#ifdef PRECOMPILEDHEADERS #include "Tactical All.h" #else #include "builddefines.h" #include #include #include #include "sgp.h" #include "gameloop.h" #include "himage.h" #include "vobject.h" #include "sysutil.h" #include "overhead.h" #include "mousesystem.h" #include "Button System.h" #include "interface.h" #include "vsurface.h" #include "wcheck.h" #include "input.h" #include "Handle UI.h" #include "Animation Control.h" #include "Animation Data.h" #include "renderworld.h" #include "sys globals.h" #include "cursors.h" #include "radar screen.h" #include "worldman.h" #include "Font Control.h" #include "render dirty.h" #include "utilities.h" #include "interface cursors.h" #include "Sound Control.h" #include "lighting.h" #include "Interface Panels.h" #include "pathai.h" #include "vobject_blitters.h" #include "faces.h" #include "Handle UI Plan.h" #include "interface control.h" #include "interface items.h" #include "soldier profile.h" #include "MercTextBox.h" #include "soldier functions.h" #include "cursor control.h" #include "handle doors.h" #include "keys.h" #include "text.h" #include "points.h" #include "soldier macros.h" #include "game clock.h" #include "physics.h" #include "Map Screen Interface Map.h" #include "line.h" #include "Vehicles.h" #include "messageboxscreen.h" #include "gamesettings.h" #include "Squads.h" #include "message.h" #include "strategicmap.h" #include "Queen Command.h" // HEADROCK HAM 4: Included for new CTH indicator #include "weapons.h" #include "Map Screen Interface.h" // added by Flugente for SquadNames #include "environment.h" // sevenfm: needed for _KeyDown(SHIFT) #include "english.h" #endif #include "InterfaceItemImages.h" #ifdef JA2UB #include "Explosion Control.h" #include "Ja25_Tactical.h" #include "Ja25 Strategic Ai.h" #include "MapScreen Quotes.h" #include "email.h" #include "interface Dialogue.h" #include "mercs.h" #include "ub_config.h" #endif #include "connect.h" //const UINT32 INTERFACE_START_X = 0; //const UINT32 INTERFACE_START_Y = ( SCREEN_HEIGHT - INTERFACE_HEIGHT ); //const UINT32 INV_INTERFACE_START_Y = ( SCREEN_HEIGHT - INV_INTERFACE_HEIGHT ); int INTERFACE_WIDTH;// = 640; int INTERFACE_HEIGHT;// = 120; int INV_INTERFACE_HEIGHT;// = 140; int INTERFACE_START_X;// = 0; int INTERFACE_START_Y;// = ( SCREEN_HEIGHT - INTERFACE_HEIGHT ); int INV_INTERFACE_START_Y;// = ( SCREEN_HEIGHT - INV_INTERFACE_HEIGHT ); #define ARROWS_X_OFFSET 10 #define ARROWS_HEIGHT 20 #define ARROWS_WIDTH 20 #define UPARROW_Y_OFFSET -30 #define DOWNARROW_Y_OFFSET -10 #define BUTTON_PANEL_WIDTH 78 #define BUTTON_PANEL_HEIGHT 76 HIDDEN_NAMES_VALUES zHiddenNames[500]; //legion2 Jazz ENEMY_NAMES_VALUES zEnemyName[500]; ENEMY_RANK_VALUES zEnemyRank[20]; // Flugente: set this to 20, which should be way enough, as there are only 10 exp levels CIV_NAMES_VALUES zCivGroupName[NUM_CIV_GROUPS]; // Flugente: soldier profiles SOLDIER_PROFILE_VALUES zSoldierProfile[6][NUM_SOLDIER_PROFILES]; UINT16 num_found_soldier_profiles[6]; // the correct number is set on reading the xml BACKGROUND_VALUES zBackground[NUM_BACKGROUND]; // Flugente: backgrounds TAUNT_VALUES zTaunt[NUM_TAUNT]; // anv: externalised taunts BOOLEAN gfInMovementMenu = FALSE; INT32 giMenuAnchorX, giMenuAnchorY; //*ddd //#define PROG_BAR_START_Y 2 //**ddd{ //поставить дефайн в 0 если использовать большой прогресс бар //#define fSmallSizeProgressbar 1 INT32 HEIGHT_PROGRESSBAR, PROG_BAR_START_Y; //ddd} BOOLEAN gfProgBarActive = FALSE; UINT8 gubProgNumEnemies = 0; UINT8 gubProgCurEnemy = 0; UINT32 guiPORTRAITICONS; UINT32 guiASSIGNMENTICONS; // Flugente: icons for assignments //UINT32 guiPORTRAITICONS_NV; //legion //UINT32 guiPORTRAITICONS_GAS_MASK; //legion // WANNE: Additional face gear file for IMPs //UINT32 guiPORTRAITICONS_NV_IMP; //UINT32 guiPORTRAITICONS_GAS_MASK_IMP; typedef struct { UINT32 uiSurface; INT8 bCurrentMessage; UINT32 uiTimeOfLastUpdate; UINT32 uiTimeSinceLastBeep; INT8 bAnimate; INT8 bYPos; BOOLEAN fCreated; INT16 sWorldRenderX; INT16 sWorldRenderY; } TOP_MESSAGE; TOP_MESSAGE gTopMessage; BOOLEAN gfTopMessageDirty = FALSE; void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ); extern UINT16 GetAnimStateForInteraction( SOLDIERTYPE *pSoldier, BOOLEAN fDoor, UINT16 usAnimState ); MOUSE_REGION gMenuOverlayRegion; MOUSE_REGION gBottomPanalRegion; UINT16 gusOldSelectedSoldier = NOBODY; // OVerlay ID INT32 giPopupSlideMessageOverlay = -1; UINT16 gusOverlayPopupBoxWidth, gusOverlayPopupBoxHeight; MercPopUpBox gpOverrideMercBox; INT32 giUIMessageOverlay = -1; UINT16 gusUIMessageWidth, gusUIMessageHeight; MercPopUpBox gpUIMessageOverrideMercBox; UINT32 guiUIMessageTime = 0; INT32 iOverlayMessageBox = -1; INT32 iUIMessageBox = -1; UINT32 guiUIMessageTimeDelay = 0; BOOLEAN gfUseSkullIconMessage = FALSE; // Overlay callback void BlitPopupText( VIDEO_OVERLAY *pBlitter ); BOOLEAN gfPanelAllocated = FALSE; extern MOUSE_REGION gDisableRegion; extern MOUSE_REGION gUserTurnRegion; extern BOOLEAN gfUserTurnRegionActive; extern UINT8 gubSelectSMPanelToMerc; extern BOOLEAN gfIgnoreOnSelectedGuy; typedef enum { WALK_IMAGES = 0, SNEAK_IMAGES, RUN_IMAGES, CRAWL_IMAGES, LOOK_IMAGES, TALK_IMAGES, HAND_IMAGES, CANCEL_IMAGES, TARGETACTIONC_IMAGES, KNIFEACTIONC_IMAGES, AIDACTIONC_IMAGES, PUNCHACTIONC_IMAGES, BOMBACTIONC_IMAGES, OPEN_DOOR_IMAGES, EXAMINE_DOOR_IMAGES, LOCKPICK_DOOR_IMAGES, BOOT_DOOR_IMAGES, CROWBAR_DOOR_IMAGES, USE_KEY_IMAGES, USE_KEYRING_IMAGES, EXPLOSIVE_DOOR_IMAGES, TOOLKITACTIONC_IMAGES, WIRECUTACTIONC_IMAGES, NUM_ICON_IMAGES }; INT32 iIconImages[ NUM_ICON_IMAGES ]; INT32 iActionIcons[ NUM_ICONS ]; // GLOBAL INTERFACE SURFACES extern UINT32 guiRENDERBUFFER; // symbol already defined in sysutil.cpp (jonathanl) UINT32 guiINTEXT; UINT32 guiCLOSE; UINT32 guiDEAD; UINT32 guiHATCH; UINT32 guiBUTTONBORDER; UINT32 guiSILHOUETTE; UINT32 guiRADIO; UINT32 guiRADIO2; UINT32 guiCOMPANEL; UINT32 guiCOMPANELB; UINT32 guiAIMCUBES; UINT32 guiAIMBARS; UINT32 guiVEHINV; UINT32 guiBURSTACCUM; UINT32 guiITEMPOINTERHATCHES; UINT32 guiUNDERWATER; // added by Flugente UINT32 guiENEMYROLES; // added by Flugente // UI Globals MOUSE_REGION gViewportRegion; MOUSE_REGION gRadarRegion; UINT16 gsUpArrowX; UINT16 gsUpArrowY; UINT16 gsDownArrowX; UINT16 gsDownArrowY; UINT32 giUpArrowRect; UINT32 giDownArrowRect; // HEADROCK HAM 4: Rectangles for the various CTH displays. RECT MagRect; RECT AimRect; RECT ModeRect; RECT APRect; // sevenfm: additional rectangles RECT RightRect; RECT LeftRect; RECT LeftRect2; // HEADROCK HAM 4: Externed this value which tracks whether we've clicked out final aiming click yet. extern BOOLEAN gfDisplayFullCountRing; void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sWidth, INT16 sHeight, INT16 interval); void PopupDoorOpenMenu( BOOLEAN fClosingDoor ); BOOLEAN fFirstTimeInGameScreen = TRUE; BOOLEAN fInterfacePanelDirty = DIRTYLEVEL2; INT16 gsInterfaceLevel = I_GROUND_LEVEL; INT32 gsCurrentSoldierGridNo = 0; INT16 gsCurInterfacePanel = TEAM_PANEL; // LOCAL FUCTIONS void BtnPositionCallback( GUI_BUTTON *btn, INT32 reason ); void BtnMovementCallback( GUI_BUTTON *btn, INT32 reason ); void BtnDoorMenuCallback( GUI_BUTTON *btn, INT32 reason ); void MovementMenuBackregionCallback( MOUSE_REGION * pRegion, INT32 iReason ); void DoorMenuBackregionCallback( MOUSE_REGION * pRegion, INT32 iReason ); UINT32 CalcUIMessageDuration( STR16 wString ); // sevenfm: this function is needed to show cover in health bar extern void CalculateCoverForSoldier( SOLDIERTYPE* pForSoldier, const INT32& sTargetGridNo, const BOOLEAN& fRoof, INT8& bCover ); extern FLOAT Distance2D( FLOAT dDeltaX, FLOAT dDeltaY ); // Flugente: toggle display of enemy role indicators BOOLEAN gDisplayEnemyRoles = TRUE; BOOLEAN InitializeFaceGearGraphics() { VOBJECT_DESC VObjectDesc; char fileName[500]; for(UINT32 iCounter2 = 1; iCounter2 < MAXITEMS; iCounter2++ ) { VObjectDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE; #define SCSTI ".STI" if ( zNewFaceGear[iCounter2].Type > 0 ) { strcpy(fileName, zNewFaceGear[iCounter2].szFile); strcat(fileName, SCSTI); strcpy(VObjectDesc.ImageFile, fileName); CHECKF(AddVideoObject(&VObjectDesc,&zNewFaceGear[iCounter2].uiIndex)); } } for(UINT32 iCounter2 = 1; iCounter2 < MAXITEMS; iCounter2++ ) { VObjectDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE; #define SCSTI_IMP "_IMP.STI" if ( zNewFaceGear[iCounter2].Type > 0 ) { //IMP strcpy(fileName, zNewFaceGear[iCounter2].szFile); strcat(fileName, SCSTI_IMP); strcpy(VObjectDesc.ImageFile, fileName); CHECKF(AddVideoObject(&VObjectDesc,&zNewFaceGearIMP[iCounter2].uiIndex)); } } return ( TRUE ); } BOOLEAN InitializeTacticalPortraits( ) { VOBJECT_DESC VObjectDesc; VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; //CHRISL: Moved from InitializeTacticalInterface so we can reinitialize portait graphics as we need to //legion 2 jazz if (gGameSettings.fOptions[ TOPTION_SHOW_TACTICAL_FACE_ICONS ] == TRUE) { //additional face icons (legion 2) if (gGameExternalOptions.bTacticalFaceIconStyle == 0) { FilenameForBPP("INTERFACE\\portraiticons_a.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) AssertMsg(0, "Missing INTERFACE\\portraiticons_a.sti" ); } else if (gGameExternalOptions.bTacticalFaceIconStyle == 1) { FilenameForBPP("INTERFACE\\portraiticons_b.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) AssertMsg(0, "Missing INTERFACE\\portraiticons_b.sti" ); } else if (gGameExternalOptions.bTacticalFaceIconStyle == 2) { FilenameForBPP("INTERFACE\\portraiticons_c.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) AssertMsg(0, "Missing INTERFACE\\portraiticons_c.sti" ); } else if (gGameExternalOptions.bTacticalFaceIconStyle == 3) { FilenameForBPP("INTERFACE\\portraiticons_d.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) AssertMsg(0, "Missing INTERFACE\\portraiticons_d.sti" ); } } else { // JA2 classic face icons FilenameForBPP("INTERFACE\\portraiticons.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiPORTRAITICONS ) ) AssertMsg(0, "Missing INTERFACE\\portraiticons.sti" ); } // Flugente: icons for assignments FilenameForBPP("INTERFACE\\AssignmentIcons.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiASSIGNMENTICONS ) ) AssertMsg(0, "Missing INTERFACE\\AssignmentIcons.sti" ); return ( TRUE ); } BOOLEAN InitializeTacticalInterface( ) { VSURFACE_DESC vs_desc; VOBJECT_DESC VObjectDesc; //UINT32 iCounter2; // CHRISL: Setup default interface coords based on inventory system in use if((UsingNewInventorySystem() == true)) { InitNewInventorySystem(); InitializeSMPanelCoordsNew(); } else { InitOldInventorySystem(); InitializeSMPanelCoordsOld(); } //*ddd{ if( gGameExternalOptions.fSmallSizeProgressbar ) { HEIGHT_PROGRESSBAR = 7; PROG_BAR_START_Y = 0; } else{ HEIGHT_PROGRESSBAR = 20; PROG_BAR_START_Y = 2; } //*ddd} /* OK i need to initialize coords here * Isnt it cool * any questions? joker */ InitializeViewPort( ); InitializeTEAMPanelCoords( ); // Load button Interfaces iIconImages[ WALK_IMAGES ] = LoadButtonImage("INTERFACE\\newicons3.sti", -1,3,4,5,-1 ); iIconImages[ SNEAK_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 6, 7, 8, -1 ); iIconImages[ RUN_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 0, 1, 2, -1 ); iIconImages[ CRAWL_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 9, 10, 11, -1 ); iIconImages[ LOOK_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 12, 13, 14, -1 ); iIconImages[ TALK_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 21, 22, 23, -1 ); iIconImages[ HAND_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 18, 19, 20, -1 ); iIconImages[ CANCEL_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 15, 16, 17, -1 ); iIconImages[ TARGETACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 24, 25, 26, -1 ); iIconImages[ KNIFEACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 27, 28, 29, -1 ); iIconImages[ AIDACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 30, 31, 32, -1 ); iIconImages[ PUNCHACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 33, 34, 35, -1 ); iIconImages[ BOMBACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 36, 37, 38, -1 ); iIconImages[ TOOLKITACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 39, 40, 41, -1 ); iIconImages[ WIRECUTACTIONC_IMAGES ] = UseLoadedButtonImage(iIconImages[ WALK_IMAGES ], -1, 42, 43, 44, -1 ); iIconImages[ OPEN_DOOR_IMAGES ] = LoadButtonImage("INTERFACE\\door_op2.sti", -1,9,10,11,-1 ); iIconImages[ EXAMINE_DOOR_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 12, 13, 14, -1 ); iIconImages[ LOCKPICK_DOOR_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 21, 22, 23, -1 ); iIconImages[ BOOT_DOOR_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 25, 26, 27, -1 ); iIconImages[ CROWBAR_DOOR_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 0, 1, 2, -1 ); iIconImages[ USE_KEY_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 3, 4, 5, -1 ); iIconImages[ USE_KEYRING_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 6, 7, 8, -1 ); iIconImages[ EXPLOSIVE_DOOR_IMAGES ] = UseLoadedButtonImage(iIconImages[ OPEN_DOOR_IMAGES ], -1, 15, 16, 17, -1 ); // Load interface panels vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE; // failing the CHECKF after this will cause you to lose your mouse if ( GETPIXELDEPTH() == 8 ) { strcpy( vs_desc.ImageFile, "INTERFACE\\IN_TEXT_8.pcx" ); } else if ( GETPIXELDEPTH() == 16 ) { strcpy( vs_desc.ImageFile, "INTERFACE\\IN_TEXT.STI" ); } if( !AddVideoSurface( &vs_desc, &guiINTEXT ) ) AssertMsg( 0, "Missing INTERFACE\\In_text.sti"); SetVideoSurfaceTransparency( guiINTEXT, FROMRGB( 255, 0, 0 ) ); // LOAD CLOSE ANIM VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\p_close.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiCLOSE ) ) AssertMsg(0, "Missing INTERFACE\\p_close.sti" ); // LOAD DEAD ANIM VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\p_dead.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiDEAD ) ) AssertMsg(0, "Missing INTERFACE\\p_dead.sti" ); // LOAD HATCH VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\hatch.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiHATCH ) ) AssertMsg(0, "Missing INTERFACE\\hatch.sti" ); SGP_THROW_IFFALSE( RegisterItemImages(), L"Registering Item Images failed" ); // CHRISL: // LOAD INTERFACE POCKET SILHOUETTES VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\Silhouettes.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiSILHOUETTE ) ) AssertMsg(0, "Missing INTERFACE\\Silhouettes.sti" ); // LOAD INTERFACE BUTTON BORDER VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\button_frame.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiBUTTONBORDER ) ) AssertMsg(0, "Missing INTERFACE\\button_frame.sti" ); // LOAD AIM CUBES VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\aimcubes.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiAIMCUBES ) ) AssertMsg(0, "Missing INTERFACE\\aimcubes.sti" ); // LOAD AIM BARS VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\aimbars.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiAIMBARS ) ) AssertMsg(0, "Missing INTERFACE\\aimbars.sti" ); VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\inventor.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiVEHINV ) ) AssertMsg(0, "Missing INTERFACE\\inventor.sti" ); VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\burst1.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiBURSTACCUM ) ) AssertMsg(0, "Missing INTERFACE\\burst1.sti" ); // Flugente: load fish symbol (signifies that a merc is diving until someone comes up with a proper animation) VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\fish.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiUNDERWATER ) ) AssertMsg(0, "Missing INTERFACE\\fish.sti" ); // Flugente: enemy role symbols VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\RoleIcons.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiENEMYROLES ) ) AssertMsg(0, "Missing INTERFACE\\RoleIcons.sti" ); //CHRISL: Moved to seperate function so we can call seperately InitializeTacticalPortraits(); InitializeFaceGearGraphics(); /* for( iCounter2 = 1; iCounter2 < MAXITEMS; iCounter2++ ) { VObjectDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE; #define SCSTI ".STI" if ( zNewFaceGear[iCounter2].Type > 0 ) { strcpy(fileName, zNewFaceGear[iCounter2].szFile); strcat(fileName, SCSTI); strcpy(VObjectDesc.ImageFile, fileName); CHECKF(AddVideoObject(&VObjectDesc,&zNewFaceGear[iCounter2].uiIndex)); } } for( iCounter2 = 1; iCounter2 < MAXITEMS; iCounter2++ ) { VObjectDesc.fCreateFlags = VSURFACE_CREATE_FROMFILE; #define SCSTI_IMP "_IMP.STI" if ( zNewFaceGear[iCounter2].Type > 0 ) { //IMP strcpy(fileName, zNewFaceGear[iCounter2].szFile); strcat(fileName, SCSTI_IMP); strcpy(VObjectDesc.ImageFile, fileName); CHECKF(AddVideoObject(&VObjectDesc,&zNewFaceGearIMP[iCounter2].uiIndex)); } } */ // LOAD RADIO VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\radio.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiRADIO ) ) AssertMsg(0, "Missing INTERFACE\\radio.sti" ); // LOAD RADIO2 VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\radio2.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiRADIO2 ) ) AssertMsg(0, "Missing INTERFACE\\radio2.sti" ); // LOAD com panel 2 VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\communicationpopup.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiCOMPANEL ) ) AssertMsg(0, "Missing INTERFACE\\communicationpopup.sti" ); // LOAD ITEM GRIDS.... VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\itemgrid.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiITEMPOINTERHATCHES ) ) AssertMsg(0, "Missing INTERFACE\\itemgrid.sti" ); VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; FilenameForBPP("INTERFACE\\communicationpopup_2.sti", VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &guiCOMPANELB ) ) AssertMsg(0, "Missing INTERFACE\\communicationpopup_2.sti" ); // Alocate message surfaces vs_desc.fCreateFlags = VSURFACE_CREATE_DEFAULT | VSURFACE_SYSTEM_MEM_USAGE; vs_desc.usWidth = SCREEN_WIDTH; vs_desc.usHeight = 20; vs_desc.ubBitDepth = 16; CHECKF( AddVideoSurface( &vs_desc, &(gTopMessage.uiSurface) ) ); InitItemInterface( ); InitRadarScreen( ); InitTEAMSlots( ); // Init popup box images // CHECKF( LoadTextMercPopupImages( BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER ) ); return( TRUE ); } BOOLEAN ShutdownTacticalInterface( ) { ShutdownCurrentPanel( ); return( TRUE ); } BOOLEAN InitializeCurrentPanel( ) { BOOLEAN fOK = FALSE; MoveRadarScreen( ); switch( gsCurInterfacePanel ) { case SM_PANEL: // Set new viewport gsVIEWPORT_WINDOW_END_Y = INV_INTERFACE_START_Y; // Render full SetRenderFlags(RENDER_FLAG_FULL); fOK = InitializeSMPanel( ); break; case TEAM_PANEL: gsVIEWPORT_WINDOW_END_Y = INTERFACE_START_Y; // Render full SetRenderFlags(RENDER_FLAG_FULL); fOK = InitializeTEAMPanel( ); break; } // RefreshMouseRegions( ); gfPanelAllocated = TRUE; return( fOK ); } void ShutdownCurrentPanel( ) { if ( gfPanelAllocated ) { switch( gsCurInterfacePanel ) { case SM_PANEL: ShutdownSMPanel( ); break; case TEAM_PANEL: ShutdownTEAMPanel( ); break; } gfPanelAllocated = FALSE; } } void SetCurrentTacticalPanelCurrentMerc( UINT8 ubID ) { SOLDIERTYPE *pSoldier; // Disable faces SetAllAutoFacesInactive( ); if ( gsCurInterfacePanel == SM_PANEL ) { // If we are not of merc bodytype, or am an epc, and going into inv, goto another.... pSoldier = MercPtrs[ ubID ]; if ( !IS_MERC_BODY_TYPE( pSoldier ) || AM_AN_EPC( pSoldier ) ) { SetCurrentInterfacePanel( TEAM_PANEL ); } } switch( gsCurInterfacePanel ) { case SM_PANEL: //SetSMPanelCurrentMerc( ubID ); gubSelectSMPanelToMerc = ubID; break; case TEAM_PANEL: SetTEAMPanelCurrentMerc( (UINT8)gusSelectedSoldier ); break; } } void CreateCurrentTacticalPanelButtons( ) { switch( gsCurInterfacePanel ) { case SM_PANEL: CreateSMPanelButtons( /*fInterfacePanelDirty*/ ); // doesn't take parameters (jonathanl) break; case TEAM_PANEL: CreateTEAMPanelButtons( /*fInterfacePanelDirty*/ ); // doesn't take parameters (jonathanl) break; } } void SetCurrentInterfacePanel( UINT8 ubNewPanel ) { ShutdownCurrentPanel( ); // INit new panel gsCurInterfacePanel = ubNewPanel; InitializeCurrentPanel( ); } void ToggleTacticalPanels( ) { gfSwitchPanel = TRUE; gubNewPanelParam = (UINT8)gusSelectedSoldier; if ( gsCurInterfacePanel == SM_PANEL ) { gbNewPanel = TEAM_PANEL; } else { gbNewPanel = SM_PANEL; } } void RemoveCurrentTacticalPanelButtons( ) { switch( gsCurInterfacePanel ) { case SM_PANEL: RemoveSMPanelButtons( /*fInterfacePanelDirty*/ ); // doesn't take parameters (jonathanl) break; case TEAM_PANEL: RemoveTEAMPanelButtons( /*fInterfacePanelDirty*/ ); // doesn't take parameters (jonathanl) break; } } BOOLEAN IsMercPortraitVisible( UINT8 ubSoldierID ) { if ( gsCurInterfacePanel == TEAM_PANEL ) { return( TRUE ); } if ( gsCurInterfacePanel == SM_PANEL ) { if ( GetSMPanelCurrentMerc() == ubSoldierID ) { return( TRUE ); } } return( FALSE ); } void HandleInterfaceBackgrounds( ) { HandleUpDownArrowBackgrounds( ); } void PopupPositionMenu( UI_EVENT *pUIEvent ) { } void PopDownPositionMenu( ) { } void BtnPositionCallback(GUI_BUTTON *btn,INT32 reason) { } void PopupMovementMenu( UI_EVENT *pUIEvent ) { SOLDIERTYPE *pSoldier = NULL; INT32 iMenuAnchorX, iMenuAnchorY; UINT32 uiActionImages; CHAR16 zActionString[ 50 ]; BOOLEAN fDisableAction = FALSE; // Erase other menus.... EraseInterfaceMenus( TRUE ); giMenuAnchorX = gusMouseXPos - 18; giMenuAnchorY = gusMouseYPos - 18; // ATE: OK loser, let's check if we're going off the screen! if ( giMenuAnchorX < 0 ) { giMenuAnchorX = 0; } if ( giMenuAnchorY < 0 ) { giMenuAnchorY = 0; } // Create mouse region over all area to facilitate clicking to end MSYS_DefineRegion( &gMenuOverlayRegion, 0, 0 ,SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST-1, CURSOR_NORMAL, MSYS_NO_CALLBACK, MovementMenuBackregionCallback ); // Add region MSYS_AddRegion( &gMenuOverlayRegion); // OK, CHECK FOR BOUNDARIES! if ( ( giMenuAnchorX + BUTTON_PANEL_WIDTH ) > SCREEN_WIDTH ) { giMenuAnchorX = ( SCREEN_WIDTH - BUTTON_PANEL_WIDTH ); } if ( ( giMenuAnchorY + BUTTON_PANEL_HEIGHT ) > gsVIEWPORT_WINDOW_END_Y ) { giMenuAnchorY = ( gsVIEWPORT_WINDOW_END_Y - BUTTON_PANEL_HEIGHT ); } if ( gusSelectedSoldier != NOBODY ) { pSoldier = MercPtrs[ gusSelectedSoldier ]; } // Blit background! //BltVideoObjectFromIndex( FRAME_BUFFER, guiBUTTONBORDER, 0, iMenuAnchorX, iMenuAnchorY, VO_BLT_SRCTRANSPARENCY, NULL ); iMenuAnchorX = giMenuAnchorX + 9; iMenuAnchorY = giMenuAnchorY + 8; iActionIcons[ RUN_ICON ] = QuickCreateButton( iIconImages[ RUN_IMAGES ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ RUN_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } SetButtonFastHelpText( iActionIcons[ RUN_ICON ], pTacticalPopupButtonStrings[ RUN_ICON ] ); //SetButtonSavedRect( iActionIcons[ RUN_ICON ] ); ButtonList[ iActionIcons[ RUN_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( pSoldier->MercInWater( ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) ) { DisableButton( iActionIcons[ RUN_ICON ] ); } iActionIcons[ WALK_ICON ] = QuickCreateButton( iIconImages[ WALK_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ WALK_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } //SetButtonSavedRect( iActionIcons[ WALK_ICON ] ); if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { SetButtonFastHelpText( iActionIcons[ WALK_ICON ], TacticalStr[ DRIVE_POPUPTEXT ] ); } else { SetButtonFastHelpText( iActionIcons[ WALK_ICON ], pTacticalPopupButtonStrings[ WALK_ICON ] ); } ButtonList[ iActionIcons[ WALK_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) { if ( !pSoldier->CanRobotBeControlled( ) ) { DisableButton( iActionIcons[ WALK_ICON ] ); } } iActionIcons[ SNEAK_ICON ] = QuickCreateButton( iIconImages[ SNEAK_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ SNEAK_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } SetButtonFastHelpText( iActionIcons[ SNEAK_ICON ], pTacticalPopupButtonStrings[ SNEAK_ICON ] ); //SetButtonSavedRect( iActionIcons[ SNEAK_ICON ] ); ButtonList[ iActionIcons[ SNEAK_ICON ] ]->UserData[0] = (UINT32)pUIEvent; // Check if this is a valid stance, diable if not! if ( !IsValidStance( pSoldier, ANIM_CROUCH ) ) { DisableButton( iActionIcons[ SNEAK_ICON ] ); } iActionIcons[ CRAWL_ICON ] = QuickCreateButton( iIconImages[ CRAWL_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ CRAWL_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } SetButtonFastHelpText( iActionIcons[ CRAWL_ICON ], pTacticalPopupButtonStrings[ CRAWL_ICON ] ); //SetButtonSavedRect( iActionIcons[ CRAWL_ICON ] ); ButtonList[ iActionIcons[ CRAWL_ICON ] ]->UserData[0] = (UINT32)pUIEvent; // Check if this is a valid stance, diable if not! if ( !IsValidStance( pSoldier, ANIM_PRONE ) ) { DisableButton( iActionIcons[ CRAWL_ICON ] ); } iActionIcons[ LOOK_ICON ] = QuickCreateButton( iIconImages[ LOOK_IMAGES ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ LOOK_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } SetButtonFastHelpText( iActionIcons[ LOOK_ICON ], TacticalStr[ LOOK_CURSOR_POPUPTEXT ] ); //SetButtonSavedRect( iActionIcons[ LOOK_ICON ] ); ButtonList[ iActionIcons[ LOOK_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { DisableButton( iActionIcons[ LOOK_ICON ] ); } if ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) { if ( !pSoldier->CanRobotBeControlled( ) ) { DisableButton( iActionIcons[ LOOK_ICON ] ); } } if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { // Until we get mounted weapons... uiActionImages = CANCEL_IMAGES; swprintf( zActionString, TacticalStr[ NOT_APPLICABLE_POPUPTEXT ] ); fDisableAction = TRUE; } else { if ( Item[pSoldier->inv[ HANDPOS ].usItem].toolkit ) { uiActionImages = TOOLKITACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ NOT_APPLICABLE_POPUPTEXT ] ); } else if ( Item[pSoldier->inv[ HANDPOS ].usItem].wirecutters ) { uiActionImages = WIRECUTACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ NOT_APPLICABLE_POPUPTEXT ] ); } else { // Create button based on what is in our hands at the moment! switch( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass ) { case IC_PUNCH: uiActionImages = PUNCHACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ USE_HANDTOHAND_POPUPTEXT ] ); break; case IC_GUN: uiActionImages = TARGETACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ USE_FIREARM_POPUPTEXT ] ); break; case IC_BLADE: uiActionImages = KNIFEACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ USE_BLADE_POPUPTEXT ] ); break; case IC_GRENADE: case IC_BOMB: uiActionImages = BOMBACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ USE_EXPLOSIVE_POPUPTEXT ] ); break; case IC_MEDKIT: uiActionImages = AIDACTIONC_IMAGES; swprintf( zActionString, TacticalStr[ USE_MEDKIT_POPUPTEXT ] ); break; default: uiActionImages = CANCEL_IMAGES; swprintf( zActionString, TacticalStr[ NOT_APPLICABLE_POPUPTEXT ] ); fDisableAction = TRUE; break; } } } if ( AM_AN_EPC( pSoldier ) ) { fDisableAction = TRUE; } iActionIcons[ ACTIONC_ICON ] = QuickCreateButton( iIconImages[ uiActionImages ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ ACTIONC_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } //SetButtonSavedRect( iActionIcons[ ACTIONC_ICON ] ); SetButtonFastHelpText( iActionIcons[ ACTIONC_ICON ], zActionString ); ButtonList[ iActionIcons[ ACTIONC_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( fDisableAction ) { DisableButton( iActionIcons[ ACTIONC_ICON ] ); } iActionIcons[ TALK_ICON ] = QuickCreateButton( iIconImages[ TALK_IMAGES ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ TALK_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } //SetButtonSavedRect( iActionIcons[ TALK_ICON ] ); SetButtonFastHelpText( iActionIcons[ TALK_ICON ], pTacticalPopupButtonStrings[ TALK_ICON ] ); ButtonList[ iActionIcons[ TALK_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { DisableButton( iActionIcons[ TALK_ICON ] ); } iActionIcons[ HAND_ICON ] = QuickCreateButton( iIconImages[ HAND_IMAGES ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ HAND_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } //SetButtonSavedRect( iActionIcons[ HAND_ICON ] ); SetButtonFastHelpText( iActionIcons[ HAND_ICON ], pTacticalPopupButtonStrings[ HAND_ICON ] ); ButtonList[ iActionIcons[ HAND_ICON ] ]->UserData[0] = (UINT32)pUIEvent; if ( AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { DisableButton( iActionIcons[ HAND_ICON ] ); } iActionIcons[ CANCEL_ICON ] = QuickCreateButton( iIconImages[ CANCEL_IMAGES ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnMovementCallback ); if ( iActionIcons[ CANCEL_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } //SetButtonSavedRect( iActionIcons[ CANCEL_ICON ] ); SetButtonFastHelpText( iActionIcons[ CANCEL_ICON ], pTacticalPopupButtonStrings[ CANCEL_ICON ] ); ButtonList[ iActionIcons[ CANCEL_ICON ] ]->UserData[0] = (UINT32)pUIEvent; //LockTacticalInterface( ); gfInMovementMenu = TRUE; // Ignore scrolling gfIgnoreScrolling = TRUE; } void PopDownMovementMenu( ) { if ( gfInMovementMenu ) { RemoveButton( iActionIcons[ WALK_ICON ] ); RemoveButton( iActionIcons[ SNEAK_ICON ] ); RemoveButton( iActionIcons[ RUN_ICON ] ); RemoveButton( iActionIcons[ CRAWL_ICON ] ); RemoveButton( iActionIcons[ LOOK_ICON ] ); RemoveButton( iActionIcons[ ACTIONC_ICON ] ); RemoveButton( iActionIcons[ TALK_ICON ] ); RemoveButton( iActionIcons[ HAND_ICON ] ); RemoveButton( iActionIcons[ CANCEL_ICON ] ); // Turn off Ignore scrolling gfIgnoreScrolling = FALSE; // Rerender world SetRenderFlags( RENDER_FLAG_FULL ); fInterfacePanelDirty = DIRTYLEVEL2; //UnLockTacticalInterface( ); MSYS_RemoveRegion( &gMenuOverlayRegion ); } gfInMovementMenu = FALSE; } void RenderMovementMenu( ) { if ( gfInMovementMenu ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiBUTTONBORDER, 0, giMenuAnchorX, giMenuAnchorY, VO_BLT_SRCTRANSPARENCY, NULL ); // Mark buttons dirty! MarkAButtonDirty( iActionIcons[ WALK_ICON ] ); MarkAButtonDirty( iActionIcons[ SNEAK_ICON ] ); MarkAButtonDirty( iActionIcons[ RUN_ICON ] ); MarkAButtonDirty( iActionIcons[ CRAWL_ICON ] ); MarkAButtonDirty( iActionIcons[ LOOK_ICON ] ); MarkAButtonDirty( iActionIcons[ ACTIONC_ICON ] ); MarkAButtonDirty( iActionIcons[ TALK_ICON ] ); MarkAButtonDirty( iActionIcons[ HAND_ICON ] ); MarkAButtonDirty( iActionIcons[ CANCEL_ICON ] ); InvalidateRegion( giMenuAnchorX, giMenuAnchorY, giMenuAnchorX + BUTTON_PANEL_WIDTH, giMenuAnchorY + BUTTON_PANEL_HEIGHT ); } } void CancelMovementMenu( ) { // Signal end of event PopDownMovementMenu( ); guiPendingOverrideEvent = A_CHANGE_TO_MOVE; } void BtnMovementCallback(GUI_BUTTON *btn,INT32 reason) { INT32 uiBtnID; UI_EVENT *pUIEvent; if ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { btn->uiFlags |= BUTTON_CLICKED_ON; uiBtnID = btn->IDNum; pUIEvent = (UI_EVENT*)( btn->UserData[0] ); if ( uiBtnID == iActionIcons[ WALK_ICON ] ) { pUIEvent->uiParams[0] = MOVEMENT_MENU_WALK; } else if ( uiBtnID == iActionIcons[ RUN_ICON ] ) { pUIEvent->uiParams[0] = MOVEMENT_MENU_RUN; } else if ( uiBtnID == iActionIcons[ SNEAK_ICON ] ) { pUIEvent->uiParams[0] = MOVEMENT_MENU_SWAT; } else if ( uiBtnID == iActionIcons[ CRAWL_ICON ] ) { pUIEvent->uiParams[0] = MOVEMENT_MENU_PRONE; } else if ( uiBtnID == iActionIcons[ LOOK_ICON ] ) { pUIEvent->uiParams[2] = MOVEMENT_MENU_LOOK; } else if ( uiBtnID == iActionIcons[ ACTIONC_ICON ] ) { pUIEvent->uiParams[2] = MOVEMENT_MENU_ACTIONC; } else if ( uiBtnID == iActionIcons[ TALK_ICON ] ) { pUIEvent->uiParams[2] = MOVEMENT_MENU_TALK; } else if ( uiBtnID == iActionIcons[ HAND_ICON ] ) { pUIEvent->uiParams[2] = MOVEMENT_MENU_HAND; } else if ( uiBtnID == iActionIcons[ CANCEL_ICON ] ) { // Signal end of event EndMenuEvent( U_MOVEMENT_MENU ); pUIEvent->uiParams[1] = FALSE; return; } else { return; } // Signal end of event EndMenuEvent( U_MOVEMENT_MENU ); pUIEvent->uiParams[1] = TRUE; } } void HandleUpDownArrowBackgrounds( ) { static UINT32 uiOldShowUpDownArrows = ARROWS_HIDE_UP | ARROWS_HIDE_DOWN; // Check for change in mode if ( guiShowUPDownArrows != uiOldShowUpDownArrows || gfUIRefreshArrows ) { gfUIRefreshArrows = FALSE; // Hide position of new ones GetArrowsBackground( ); uiOldShowUpDownArrows = guiShowUPDownArrows; } } void RenderArrows( ) { TILE_ELEMENT TileElem; if ( guiShowUPDownArrows & ARROWS_HIDE_UP && guiShowUPDownArrows & ARROWS_HIDE_DOWN ) { return; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_BESIDE ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_G ) { TileElem = gTileDatabase[ SECONDPOINTERS1 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_Y ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_YG ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); TileElem = gTileDatabase[ SECONDPOINTERS1 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_GG ) { TileElem = gTileDatabase[ SECONDPOINTERS1 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_YY ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB ) { TileElem = gTileDatabase[ SECONDPOINTERS8 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB2 ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); TileElem = gTileDatabase[ SECONDPOINTERS8 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB3 ) { TileElem = gTileDatabase[ SECONDPOINTERS3 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); TileElem = gTileDatabase[ SECONDPOINTERS8 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsUpArrowX, gsUpArrowY + 40, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BESIDE ) { TileElem = gTileDatabase[ SECONDPOINTERS4 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_G ) { TileElem = gTileDatabase[ SECONDPOINTERS2 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_Y ) { TileElem = gTileDatabase[ SECONDPOINTERS4 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_CLIMB ) { TileElem = gTileDatabase[ SECONDPOINTERS7 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_YG ) { TileElem = gTileDatabase[ SECONDPOINTERS2 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); TileElem = gTileDatabase[ SECONDPOINTERS4 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_GG ) { TileElem = gTileDatabase[ SECONDPOINTERS2 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_YY ) { TileElem = gTileDatabase[ SECONDPOINTERS4 ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY, VO_BLT_SRCTRANSPARENCY, NULL ); BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, gsDownArrowX, gsDownArrowY + 20, VO_BLT_SRCTRANSPARENCY, NULL ); } } void EraseRenderArrows( ) { if ( giUpArrowRect != 0 ) { if ( giUpArrowRect != -1 ) { FreeBackgroundRect( giUpArrowRect ); } } giUpArrowRect = 0; if ( giDownArrowRect != 0 ) { if ( giDownArrowRect != -1 ) { FreeBackgroundRect( giDownArrowRect ); } } giDownArrowRect = 0; } void GetArrowsBackground( ) { SOLDIERTYPE *pSoldier; INT16 sMercScreenX, sMercScreenY; UINT16 sArrowHeight = ARROWS_HEIGHT, sArrowWidth = ARROWS_WIDTH; if ( guiShowUPDownArrows & ARROWS_HIDE_UP && guiShowUPDownArrows & ARROWS_HIDE_DOWN ) { return; } if ( gusSelectedSoldier != NOBODY ) { // Get selected soldier GetSoldier( &pSoldier, gusSelectedSoldier ); // Get screen position of our guy GetSoldierTRUEScreenPos( pSoldier, &sMercScreenX, &sMercScreenY ); if ( guiShowUPDownArrows & ARROWS_SHOW_UP_BESIDE ) { // Setup blt rect gsUpArrowX = sMercScreenX + ARROWS_X_OFFSET; gsUpArrowY = sMercScreenY + UPARROW_Y_OFFSET; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_G || guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_Y ) { // Setup blt rect gsUpArrowX = sMercScreenX - 10; gsUpArrowY = sMercScreenY - 50; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_YG || guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_GG || guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_YY ) { // Setup blt rect gsUpArrowX = sMercScreenX - 10; gsUpArrowY = sMercScreenY - 70; sArrowHeight = 3 * ARROWS_HEIGHT; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB ) { // Setup blt rect gsUpArrowX = sMercScreenX - 10; gsUpArrowY = sMercScreenY - 70; sArrowHeight = 2 * ARROWS_HEIGHT; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB2 ) { // Setup blt rect gsUpArrowX = sMercScreenX - 10; gsUpArrowY = sMercScreenY - 80; sArrowHeight = 3 * ARROWS_HEIGHT; } if ( guiShowUPDownArrows & ARROWS_SHOW_UP_ABOVE_CLIMB3 ) { // Setup blt rect gsUpArrowX = sMercScreenX - 10; gsUpArrowY = sMercScreenY - 900; sArrowHeight = 5 * ARROWS_HEIGHT; } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BESIDE ) { gsDownArrowX = sMercScreenX + ARROWS_X_OFFSET; gsDownArrowY = sMercScreenY + DOWNARROW_Y_OFFSET; } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_Y || guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_G ) { gsDownArrowX = sMercScreenX -10; gsDownArrowY = sMercScreenY + 10; } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_CLIMB ) { gsDownArrowX = sMercScreenX - 10; gsDownArrowY = sMercScreenY + 10; sArrowHeight = 3 * ARROWS_HEIGHT; } if ( guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_YG || guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_GG || guiShowUPDownArrows & ARROWS_SHOW_DOWN_BELOW_YY ) { gsDownArrowX = sMercScreenX -10; gsDownArrowY = sMercScreenY + 10; sArrowHeight = 3 * ARROWS_HEIGHT; } // Adjust arrows based on level if ( gsInterfaceLevel == I_ROOF_LEVEL ) { // gsDownArrowY -= ROOF_LEVEL_HEIGHT; // gsUpArrowY -= ROOF_LEVEL_HEIGHT; } //Erase prevois ones... EraseRenderArrows( ); // Register dirty rects giDownArrowRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT, NULL, gsDownArrowX, gsDownArrowY, (INT16)(gsDownArrowX + sArrowWidth), (INT16)(gsDownArrowY + sArrowHeight ) ); giUpArrowRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT, NULL, gsUpArrowX, gsUpArrowY, (INT16)(gsUpArrowX + sArrowWidth), (INT16)(gsUpArrowY + sArrowHeight ) ); } } void GetSoldierAboveGuyPositions( SOLDIERTYPE *pSoldier, INT16 *psX, INT16 *psY, BOOLEAN fRadio ) { INT16 sMercScreenX, sMercScreenY; INT16 sOffsetX, sOffsetY; UINT8 ubAnimUseHeight; INT16 sStanceOffset = 0; INT16 sTextBodyTypeYOffset = 62; // Find XY, dims, offsets GetSoldierScreenPos( pSoldier, &sMercScreenX, &sMercScreenY ); GetSoldierAnimOffsets( pSoldier, &sOffsetX, &sOffsetY ); // OK, first thing to do is subtract offsets ( because GetSoldierScreenPos adds them... ) sMercScreenX -= sOffsetX; sMercScreenY -= sOffsetY; // Adjust based on stance if ( ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_NOMOVE_MARKER) ) { ubAnimUseHeight = gAnimControl[ pSoldier->usAnimState ].ubHeight; } else { ubAnimUseHeight = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; } switch ( ubAnimUseHeight ) { case ANIM_STAND: break; case ANIM_PRONE: sStanceOffset = 25; break; case ANIM_CROUCH: sStanceOffset = 10; break; } // Adjust based on body type... switch( pSoldier->ubBodyType ) { case CROW: sStanceOffset = 30; break; case ROBOTNOWEAPON: sStanceOffset = 30; break; } //sStanceOffset -= gpWorldLevelData[ pSoldier->sGridNo ].sHeight; // Adjust based on level if ( pSoldier->pathing.bLevel == 1 && gsInterfaceLevel == 0 ) { //sStanceOffset -= ROOF_LEVEL_HEIGHT; } if ( pSoldier->pathing.bLevel == 0 && gsInterfaceLevel == 1 ) { //sStanceOffset += ROOF_LEVEL_HEIGHT; } if ( pSoldier->ubProfile != NO_PROFILE ) { if ( fRadio ) { *psX = sMercScreenX - ( 80 / 2 ) - pSoldier->sLocatorOffX; *psY = sMercScreenY - sTextBodyTypeYOffset + sStanceOffset; } else { *psX = sMercScreenX - ( 80 / 2 ) - pSoldier->sLocatorOffX; *psY = sMercScreenY - sTextBodyTypeYOffset + sStanceOffset; // OK, Check if we need to go below.... // Can do this 1) if displaying damge or 2 ) above screen // If not a radio position, adjust if we are getting hit, to be lower! // If we are getting hit, lower them! if ( pSoldier->flags.fDisplayDamage || *psY < gsVIEWPORT_WINDOW_START_Y ) { *psX = sMercScreenX - ( 80 / 2 ) - pSoldier->sLocatorOffX; *psY = sMercScreenY; } } } else { //Display Text! *psX = sMercScreenX - ( 80 / 2 ) - pSoldier->sLocatorOffX; *psY = sMercScreenY - sTextBodyTypeYOffset + sStanceOffset; } } void DrawCTHPixelToBuffer( UINT16 *pBuffer, UINT32 uiPitch, INT16 sLeft, INT16 sTop, INT16 sRight, INT16 sBottom, INT16 sPixelX, INT16 sPixelY, UINT16 usColor ) { /////////////////////////////////////////////////////////// // HEADROCK HAM 4: // // This is a specialized drawing function that's used for the CTH indicator. It makes sure that the // pixel is drawn only within the allowed region (the Tactical Viewport), and never drawn in regions // reserved for other parts of the CTH indicator. if (sPixelX < sLeft || sPixelX > sRight || sPixelY < sTop || sPixelY > (sBottom-1)) { return; } // Do not draw in other CTH rects! if ((sPixelX >= MagRect.left && sPixelX <= MagRect.right) && (sPixelY >= MagRect.top && sPixelY <= MagRect.bottom)) { return; } if ((sPixelX >= AimRect.left && sPixelX <= AimRect.right) && (sPixelY >= AimRect.top && sPixelY <= AimRect.bottom)) { return; } if ((sPixelX >= ModeRect.left && sPixelX <= ModeRect.right) && (sPixelY >= ModeRect.top && sPixelY <= ModeRect.bottom)) { return; } if ((sPixelX >= APRect.left && sPixelX <= APRect.right) && (sPixelY >= APRect.top && sPixelY <= APRect.bottom)) { return; } // sevenfm: added additional right, left rectangles if ((sPixelX >= RightRect.left && sPixelX <= RightRect.right) && (sPixelY >= RightRect.top && sPixelY <= RightRect.bottom)) { return; } if ((sPixelX >= LeftRect.left && sPixelX <= LeftRect.right) && (sPixelY >= LeftRect.top && sPixelY <= LeftRect.bottom)) { return; } if ((sPixelX >= LeftRect2.left && sPixelX <= LeftRect2.right) && (sPixelY >= LeftRect2.top && sPixelY <= LeftRect2.bottom)) { return; } pBuffer[sPixelX + uiPitch*sPixelY] = usColor; } //QUOTE_SYSTEM_STRUCT soldierTTInfo; void DrawSelectedUIAboveGuy( UINT16 usSoldierID ) { SOLDIERTYPE *pSoldier; INT16 sXPos, sYPos; INT16 sX, sY; INT32 iBack; TILE_ELEMENT TileElem; CHAR16 *pStr; CHAR16 NameStr[ MAX_ENEMY_NAMES_CHARS ]; UINT16 usGraphicToUse = THIRDPOINTERS1; BOOLEAN fRaiseName = FALSE; BOOLEAN fDoName = TRUE; UINT16 iCounter2; INT16 maxWidth = 40; // sevenfm: maximum string length (in pixels) is used to determine x coordinate for additional info GetSoldier( &pSoldier, usSoldierID ); if ( !pSoldier || (pSoldier->bVisible == -1 && !(gTacticalStatus.uiFlags&SHOW_ALL_MERCS) ) ) { return; } if (TileIsOutOfBounds(pSoldier->sGridNo)) { return; } if ( pSoldier->flags.fFlashLocator ) { if ( pSoldier->bVisible == -1 ) { pSoldier->flags.fFlashLocator = FALSE; } else { if ( TIMECOUNTERDONE( pSoldier->timeCounters.BlinkSelCounter, 80 ) ) { RESETTIMECOUNTER( pSoldier->timeCounters.BlinkSelCounter, 80 ); // pSoldier->flags.fShowLocator = !pSoldier->flags.fShowLocator; pSoldier->flags.fShowLocator = TRUE; // Update frame pSoldier->sLocatorFrame++; if ( pSoldier->sLocatorFrame == 5 ) { // Update time we do this pSoldier->flags.fFlashLocator++; pSoldier->sLocatorFrame = 0; } } //if ( TIMECOUNTERDONE( pSoldier->timeCounters.FlashSelCounter, 5000 ) ) //{ // RESETTIMECOUNTER( pSoldier->timeCounters.FlashSelCounter, 5000 ); // pSoldier->flags.fFlashLocator = FALSE; // pSoldier->flags.fShowLocator = FALSE; //} if ( pSoldier->flags.fFlashLocator == pSoldier->ubNumLocateCycles ) { pSoldier->flags.fFlashLocator = FALSE; pSoldier->flags.fShowLocator = FALSE; } //if ( pSoldier->flags.fShowLocator ) { // Render the beastie GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); // Adjust for bars! sXPos += 25; sYPos += 25; //sXPos += 15; //sYPos += 21; // Add bars //iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 55 ), (INT16)(sYPos + 80 ) ); iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos +40 ), (INT16)(sYPos + 40 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } if ( ( !pSoldier->aiData.bNeutral && ( pSoldier->bSide != gbPlayerNum ) ) ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiRADIO2, pSoldier->sLocatorFrame, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( FRAME_BUFFER, guiRADIO, pSoldier->sLocatorFrame, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); //BltVideoObjectFromIndex( FRAME_BUFFER, guiRADIO, 0, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); } } } } // Flugente: show a small animation hat signifies that a merc is underwater (hopefully temporary until someone comes up with a proper animation) else if ( pSoldier->UsesScubaGear() ) { if ( TIMECOUNTERDONE( pSoldier->timeCounters.BlinkSelCounter, 320 ) ) { RESETTIMECOUNTER( pSoldier->timeCounters.BlinkSelCounter, 320 ); // Update frame pSoldier->sLocatorFrame++; if ( pSoldier->sLocatorFrame == 5 ) { // Update time we do this pSoldier->sLocatorFrame = 0; } } if ( pSoldier->flags.fFlashLocator == pSoldier->ubNumLocateCycles ) { pSoldier->flags.fShowLocator = FALSE; } if ( gGameExternalOptions.ubShowHealthBarsOnHead ) { // Render the beastie GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); // Adjust for bars! sXPos += 25; sYPos += 25; // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos +40 ), (INT16)(sYPos + 40 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiUNDERWATER, pSoldier->sLocatorFrame, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); } } if ( gDisplayEnemyRoles && pSoldier->bTeam == ENEMY_TEAM ) { ShowSoldierRoleSymbol(pSoldier); } if ( !pSoldier->flags.fShowLocator ) { // RETURN IF MERC IS NOT SELECTED if ( gfUIHandleSelectionAboveGuy && pSoldier->ubID == gsSelectedGuy && pSoldier->ubID != gusSelectedSoldier && !gfIgnoreOnSelectedGuy ) { } else if ( pSoldier->ubID == gusSelectedSoldier && !gRubberBandActive ) { usGraphicToUse = THIRDPOINTERS2; } // show all people's names if ! //else if ( pSoldier->ubID >= 20 && pSoldier->bVisible != -1 ) //{ //} else if ( pSoldier->flags.uiStatusFlags & SOLDIER_MULTI_SELECTED ) { } else { return; } } else { if ( pSoldier->ubID == gusSelectedSoldier && !gRubberBandActive ) { usGraphicToUse = THIRDPOINTERS2; } } // If he is in the middle of a certain animation, ignore! if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_NOSHOW_MARKER ) { return; } // Donot show if we are dead if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) ) { return; } GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, FALSE ); // Display name SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); BOOLEAN bInCombat = gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT; BOOLEAN bStealth = pSoldier->bStealthMode || pSoldier->bSoldierFlagMask & ( SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER ); // sevenfm: for mercs use name color as cover indicator if( pSoldier->bTeam == OUR_TEAM && ! ( pSoldier->flags.uiStatusFlags & ( SOLDIER_VEHICLE | SOLDIER_ROBOT) ) && ( ( gGameExternalOptions.ubShowCoverIndicator == 1 && ( bInCombat || bStealth ) ) || ( gGameExternalOptions.ubShowCoverIndicator == 2 && bStealth ) ) ) { INT8 cover = 3; // MAX_COVER BOOLEAN showCover; INT32 usMapPos; INT16 color8, color16; if( GetMouseMapPos(&usMapPos) && _KeyDown(SHIFT) ) { // target tile cover CalculateCoverForSoldier( pSoldier, usMapPos, gsInterfaceLevel, cover ); showCover = CoverColorCode( cover, color8, color16 ); SetFontForeground( (UINT8)color8 ); } else { // merc's cover CalculateCoverForSoldier( pSoldier, pSoldier->sGridNo, pSoldier->pathing.bLevel, cover ); showCover = CoverColorCode( cover, color8, color16 ); SetFontForeground( (UINT8)color8 ); } } else { SetFontForeground( FONT_MCOLOR_WHITE ); } if ( pSoldier->ubProfile != NO_PROFILE || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { if ( gfUIMouseOnValidCatcher == 1 && pSoldier->ubID == gubUIValidCatcherID ) { swprintf( NameStr, TacticalStr[ CATCH_STR ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); fRaiseName = TRUE; } else if ( gfUIMouseOnValidCatcher == 3 && pSoldier->ubID == gubUIValidCatcherID ) { swprintf( NameStr, TacticalStr[ RELOAD_STR ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); fRaiseName = TRUE; } else if ( gfUIMouseOnValidCatcher == 4 && pSoldier->ubID == gubUIValidCatcherID ) { swprintf( NameStr, pMessageStrings[ MSG_PASS ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); fRaiseName = TRUE; } else if ( pSoldier->bAssignment >= ON_DUTY ) { SetFontForeground( FONT_YELLOW ); swprintf( NameStr, L"(%s)", pAssignmentStrings[ pSoldier->bAssignment ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); fRaiseName = TRUE; } else if ( pSoldier->bTeam == gbPlayerNum && pSoldier->bAssignment < ON_DUTY && pSoldier->bAssignment != CurrentSquad() && !( pSoldier->flags.uiStatusFlags & SOLDIER_MULTI_SELECTED ) ) { if ( gGameExternalOptions.fUseXMLSquadNames ) swprintf( NameStr, SquadNames[ pSoldier->bAssignment ].squadname ); else swprintf( NameStr, gzLateLocalizedString[ 34 ], ( pSoldier->bAssignment + 1 ) ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); fRaiseName = TRUE; } // If not in a squad.... if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) { if ( GetNumberInVehicle( pSoldier->bVehicleID ) == 0 ) { SetFontForeground( FONT_GRAY4 ); } } else { if ( pSoldier->bAssignment >= ON_DUTY ) { SetFontForeground( FONT_YELLOW ); } } if ( fDoName ) { if ( fRaiseName ) { //legion2 jazz if (pSoldier->ubBodyType == ROBOTNOWEAPON && pSoldier->bTeam == ENEMY_TEAM ) { swprintf( NameStr, zGrod[0] ); } else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) { swprintf( NameStr,L"???" ); } else { swprintf( NameStr, L"%s", pSoldier->name ); } //Legion if (pSoldier->ubBodyType == TANK_NE || pSoldier->ubBodyType == TANK_NW) { swprintf( NameStr, gNewVehicle[164].NewVehicleStrings ); //swprintf( NameStr, pVehicleStrings[4] ); } else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) { swprintf( NameStr,L"???" ); } else { swprintf( NameStr, L"%s", pSoldier->name ); } //------- //swprintf( NameStr, L"%s", pSoldier->name ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos - 10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else { //legion Jazz if (pSoldier->ubBodyType == ROBOTNOWEAPON && pSoldier->bTeam == ENEMY_TEAM ) { swprintf( NameStr, zGrod[0] ); } else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) { swprintf( NameStr,L"???" ); } else { swprintf( NameStr, L"%s", pSoldier->name ); } //Legion if (pSoldier->ubBodyType == TANK_NE || pSoldier->ubBodyType == TANK_NW) { //swprintf( NameStr, pVehicleStrings[4] ); swprintf( NameStr, gNewVehicle[164].NewVehicleStrings ); } else if (zHiddenNames[pSoldier->ubProfile].Hidden == TRUE) { swprintf( NameStr,L"???" ); } else { wprintf( NameStr, L"%s", pSoldier->name ); } //--------------- //swprintf( NameStr, L"%s", pSoldier->name ); FindFontCenterCoordinates( sXPos, sYPos, (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } } // if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON || RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) //new profiles by Jazz if ( gProfilesIMP[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesAIM[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || gProfilesMERC[pSoldier->ubProfile].ProfilId == pSoldier->ubProfile || RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )) { if ( gGameExternalOptions.ubShowHealthBarsOnHead ) { if( gGameExternalOptions.ubShowHealthBarsOnHead > 1 ) { INT16 interval = gGameExternalOptions.ubShowHealthBarsOnHead; //if( interval > 3 ) // interval -= 2; sXPos += 27; sYPos += 7; iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sXPos, sYPos-1, (INT16)(sXPos + 24 ), (INT16)(sYPos + 3 + interval*3 ) ); if ( iBack != -1 ) SetBackgroundRectFilled( iBack ); DrawBarsInUIBox( pSoldier, (INT16)(sXPos), (INT16)(sYPos), 20, 1, 2 ); // show AP only in turnbased combat, only during our turn if( gGameExternalOptions.ubShowHealthBarsOnHead > 2 && (gTacticalStatus.uiFlags & TURNBASED ) && (gTacticalStatus.uiFlags & INCOMBAT) && gTacticalStatus.ubCurrentTeam == OUR_TEAM) { INT16 len; swprintf( NameStr,L"%d", pSoldier->bActionPoints ); len = StringPixLength ( NameStr, TINYFONT1 ); SetFont( TINYFONT1 ); if(pSoldier->bActionPoints > APBPConstants[MIN_APS_TO_INTERRUPT]) SetFontForeground( FONT_MCOLOR_LTGRAY ); else if(pSoldier->bActionPoints > 10) SetFontForeground( FONT_YELLOW ); else SetFontForeground( FONT_MCOLOR_DKRED ); gprintfdirty( sXPos-2-len, sYPos-2, NameStr ); mprintf( sXPos-2-len, sYPos-2, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } } else { // Adjust for bars! if ( pSoldier->ubID == gusSelectedSoldier ) { sXPos += 28; sYPos += 5; } else { sXPos += 30; sYPos += 7; } // Add bars iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 34 ), (INT16)(sYPos + 11 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } TileElem = gTileDatabase[ usGraphicToUse ]; BltVideoObject( FRAME_BUFFER, TileElem.hTileSurface, TileElem.usRegionIndex, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); // Draw life, breath // Only do this when we are a vehicle but on our team if ( pSoldier->ubID == gusSelectedSoldier ) { DrawBarsInUIBox( pSoldier, (INT16)(sXPos +1), (INT16)(sYPos + 2), 16, 1, 3); } else { DrawBarsInUIBox( pSoldier, (INT16)(sXPos -1), (INT16)(sYPos ), 16, 1, 3 ); } } } } else // ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON || { // RPC_RECRUITED( pSoldier ) || AM_AN_EPC( pSoldier ) || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) ) if ( gfUIMouseOnValidCatcher == 2 && pSoldier->ubID == gubUIValidCatcherID ) { SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); swprintf( NameStr, TacticalStr[ GIVE_STR ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos + 10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else { SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_DKRED ); pStr = GetSoldierHealthString( pSoldier ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 10 ), (INT16)(80 ), 1, pStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, pStr ); mprintf( sX, sY, pStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); //----------------- if ( pSoldier->bInSector && pSoldier->ubProfile == NO_PROFILE ) { if ( pSoldier->bTeam == ENEMY_TEAM ) { // Flugente: soldier profiles if ( gGameExternalOptions.fSoldierProfiles_Enemy && pSoldier->usSoldierProfile ) { swprintf(NameStr, pSoldier->GetName()); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else if (gGameExternalOptions.fEnemyNames == TRUE && gGameExternalOptions.fEnemyRank == FALSE) { for( iCounter2 = 0; iCounter2 < 500; ++iCounter2 ) { if (zEnemyName[iCounter2].Enabled == 1) { if ( pSoldier->sSectorX == zEnemyName[iCounter2].SectorX && pSoldier->sSectorY == zEnemyName[iCounter2].SectorY ) { swprintf(NameStr, zEnemyName[iCounter2].szCurGroup); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); break; } } } } else if (gGameExternalOptions.fEnemyNames == FALSE && gGameExternalOptions.fEnemyRank == TRUE) { for( iCounter2 = 1; iCounter2 < 11; ++iCounter2 ) { if (zEnemyRank[iCounter2].Enabled == 1) { if ( zEnemyRank[iCounter2].Stats == 0 && pSoldier->stats.bExpLevel == zEnemyRank[iCounter2].ExpLevel ) { swprintf(NameStr, zEnemyRank[iCounter2].szCurRank); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); break; } } } } } // Flugente: soldier profiles else if ( pSoldier->bTeam == MILITIA_TEAM && gGameExternalOptions.fSoldierProfiles_Militia && pSoldier->usSoldierProfile ) { // get a proper chaos name swprintf(NameStr, pSoldier->GetName()); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else if (gGameExternalOptions.fCivGroupName == TRUE && pSoldier->ubCivilianGroup > 0 ) { if (zCivGroupName[pSoldier->ubCivilianGroup].Enabled == 1) { swprintf(NameStr, zCivGroupName[pSoldier->ubCivilianGroup].szCurGroup); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } } } //------------ } } } else //pSoldier->ubProfile != NO_PROFILE || ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { if ( pSoldier->pathing.bLevel != 0 ) { // Display name SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); swprintf( NameStr, gzLateLocalizedString[ 15 ] ); FindFontCenterCoordinates( sXPos, (INT16)(sYPos + 10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } pStr = GetSoldierHealthString( pSoldier ); //jones extern void SoldierTooltip(SOLDIERTYPE*); //if ( gGameExternalOptions.gfAllowSoldierToolTips ) // changed by SANDRO if ( gGameSettings.fOptions[TOPTION_ALLOW_SOLDIER_TOOLTIPS] ) SoldierTooltip(pSoldier); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_DKRED ); FindFontCenterCoordinates( sXPos, sYPos, (INT16)(80 ), 1, pStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, pStr ); mprintf( sX, sY, pStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); //----------------- if ( pSoldier->bInSector && pSoldier->ubProfile == NO_PROFILE ) { #ifdef ENABLE_ZOMBIES if ( pSoldier->IsZombie() ) { swprintf(NameStr, pSoldier->name); // Display name SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos -10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else #endif if ( pSoldier->bTeam == ENEMY_TEAM ) { // Flugente: soldier profiles if ( gGameExternalOptions.fSoldierProfiles_Enemy && pSoldier->usSoldierProfile ) { // get a proper chaos name swprintf(NameStr, pSoldier->GetName()); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } else if (gGameExternalOptions.fEnemyNames == TRUE) { for( iCounter2 = 0; iCounter2 < 500; ++iCounter2 ) { if (zEnemyName[iCounter2].Enabled == 1 ) { if ( pSoldier->sSectorX == zEnemyName[iCounter2].SectorX && pSoldier->sSectorY == zEnemyName[iCounter2].SectorY ) { swprintf(NameStr, zEnemyName[iCounter2].szCurGroup); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); break; } } } } if (gGameExternalOptions.fEnemyRank == TRUE) { for( iCounter2 = 1; iCounter2 < 11; ++iCounter2 ) { if (zEnemyRank[iCounter2].Enabled == 1) { if ( zEnemyRank[iCounter2].Stats == 0 && pSoldier->stats.bExpLevel == zEnemyRank[iCounter2].ExpLevel ) { swprintf(NameStr, zEnemyRank[iCounter2].szCurRank); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); // need to adjust sYPos because default position already occupied by the name if ( gGameExternalOptions.fSoldierProfiles_Enemy && pSoldier->usSoldierProfile || gGameExternalOptions.fEnemyNames ) FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); // use default position for text else FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); //legion2 gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); break; } } } } // show weapon name and additional info BOOLEAN showExactInfo = FALSE; INT16 height = 0; SOLDIERTYPE *pSelectedSoldier, *pTargetSoldier; pSelectedSoldier = MercPtrs[ gusSelectedSoldier ]; pTargetSoldier = pSoldier; // calc max range for exact info if ( gusSelectedSoldier != NOBODY ) showExactInfo = ShowExactInfo( pSelectedSoldier, pTargetSoldier ); // show weapon/armour/items info if ( gGameExternalOptions.fShowEnemyWeapon && gTacticalStatus.ubCurrentTeam == OUR_TEAM && pTargetSoldier->ubBodyType <= REGFEMALE ) { height = 30; SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); if( !gGameExternalOptions.fEnemyRank || !gGameExternalOptions.fEnemyNames ) height = 10; swprintf( NameStr, L"" ); GetEnemyInfoString( pSelectedSoldier, pTargetSoldier, showExactInfo, NameStr ); // print item name FindFontCenterCoordinates( sXPos, (INT16)( sYPos + height ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); maxWidth = __max( maxWidth, StringPixLength ( NameStr, TINYFONT1 ) ); } height = 0; FindFontCenterCoordinates( sXPos, (INT16)( sYPos + height ), (INT16)(80 ), 1, L"", TINYFONT1, &sX, &sY ); // show enemy health bar if( gGameExternalOptions.ubShowEnemyHealth > 1 && gTacticalStatus.ubCurrentTeam == OUR_TEAM ) { UINT8 ubLines = gGameExternalOptions.ubShowEnemyHealth - 1; INT32 iBarWidth = 24; INT32 iBarHeight; iBarHeight = 2 + 3 * ubLines - 1; sY += 10; sY -= iBarHeight; sX -= iBarWidth / 2; iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sX, sY, (INT16)(sX + iBarWidth), (INT16)(sY + iBarHeight ) ); if ( iBack != -1 ) SetBackgroundRectFilled( iBack ); DrawEnemyHealthBar( pSoldier, sX, sY, ubLines, iBarWidth - 2, iBarHeight ); } FindFontCenterCoordinates( sXPos, (INT16)( sYPos + height ), (INT16)(80 ), 1, L"", TINYFONT1, &sX, &sY ); sX-=maxWidth / 2 + StringPixLength ( L"***", TINYFONT1 ); // show additional info if( gGameExternalOptions.fShowEnemyAwareness && gTacticalStatus.ubCurrentTeam == OUR_TEAM ) { SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); // show awareness sign only when in stealth mode or disguised if( ( gusSelectedSoldier != NOBODY ) && ( MercPtrs[ gusSelectedSoldier ]->bStealthMode || MercPtrs[ gusSelectedSoldier ]->bSoldierFlagMask & ( SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER ) ) ) { if( pSoldier->aiData.bOppList[ MercPtrs[ gusSelectedSoldier ]->ubID ] == SEEN_CURRENTLY ) swprintf( NameStr, L"%s", L"<*>" ); else swprintf( NameStr, L"%s", L"<->" ); SetFontForeground( FONT_GRAY1 ); switch ( pSoldier->aiData.bAlertStatus ) { case STATUS_GREEN: // everything's OK, no suspicion SetFontForeground( FONT_GREEN ); break; case STATUS_YELLOW: // he or his friend heard something SetFontForeground( FONT_YELLOW ); break; case STATUS_RED: // has definite evidence of opponent SetFontForeground( FONT_ORANGE ); break; case STATUS_BLACK: // currently sees an active opponent SetFontForeground( FONT_DKRED ); break; } if ( showExactInfo ) { if( gGameExternalOptions.ubShowEnemyHealth > 1 ) { gprintfdirty( sX + maxWidth / 2 - 15, sY + height, NameStr ); mprintf( sX + maxWidth / 2 - 13, sY + height, NameStr ); } else { gprintfdirty( sX, sY + height, NameStr ); mprintf( sX, sY + height, NameStr ); } height += 10; } } } // show rank icon if( gGameExternalOptions.ubShowEnemyRankIcon && gTacticalStatus.ubCurrentTeam == OUR_TEAM ) //&& (!gGameExternalOptions.fEnemyNames) && (!gGameExternalOptions.fEnemyRank)) { sX = sXPos + 50; sY = sYPos + 17; if(gGameExternalOptions.fEnemyNames) sY+=10; if(gGameExternalOptions.fEnemyRank) sY+=10; iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sX, sY, (INT16)(sX + 22 ), (INT16)(sY + 14 ) ); if ( iBack != -1 ) SetBackgroundRectFilled( iBack ); DrawRankIcon( pSoldier->stats.bExpLevel, sX, sY ); } } // Flugente: soldier profiles else if ( pSoldier->bTeam == MILITIA_TEAM && gGameExternalOptions.fSoldierProfiles_Militia && pSoldier->usSoldierProfile ) { // get a proper chaos name swprintf(NameStr, pSoldier->GetName()); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); } else if (gGameExternalOptions.fCivGroupName == TRUE && pSoldier->ubCivilianGroup > 0 ) { if (zCivGroupName[pSoldier->ubCivilianGroup].Enabled == 1) { swprintf(NameStr, zCivGroupName[pSoldier->ubCivilianGroup].szCurGroup); SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_YELLOW ); //legion2 FindFontCenterCoordinates( sXPos, (INT16)( sYPos + 20 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY ); gprintfdirty( sX, sY, NameStr ); mprintf( sX, sY, NameStr ); } } } } } BOOLEAN DrawCTHIndicator() { //////////////////////////////////////////// // HEADROCK HAM 4: NCTH Indicator // // The NCTH shooting system is radically different from the old CTH, and as a result it requires a completely // new indicator to show hit-probability. The "Hit Percentage" bar we've all gotten used to in JA2 1.13 is not // doable in NCTH since the hit probability is unknown before the bullet reaches the target distance. Instead, // we use a sort of "reticle" to show the margin of error for our current shot. // // The CTH indicator is made up of several parts: // 1. Outer Circle: This circle shows the margin of error that we would have if Muzzle Accuracy was 0%. In other // words, it indicates the "worst" possible shot with the gun we're holding, given the target's distance. // This circle only gets larger or smaller if the shooter moves closer or further from the target (or // changes weapons...). // 2. Inner Circle+Crosshairs: This indicator shows the margin of error for the shot given all the bonuses from // Base CTH and extra aiming clicks. It is a visual representation of where our bullet may end up once fired. // The bullet can end up anywhere within this smaller circle. The circle gets larger or smaller as we change // the number of applied aiming clicks, add magnification bonuses from a scope, change stance, etcetera. // 3. Additional indicators: These are floating graphical and numerical indicators showing various important // data, such as how many aiming clicks we've applied (and how many we can apply), how many bullets we're // going to fire (in burst/auto mode), and how many APs it's going to cost us. These are generally just // relocation and redesign of existing indicators on the OCTH cursor. if (gCTHDisplay.MuzzleSwayPercentage < 0 || gCTHDisplay.MuzzleSwayPercentage > 99 || gCTHDisplay.FinalMagFactor < 1.0) { // Obviously Uninitialized. return 0; } INT32 iBack; // Find the shooter. SOLDIERTYPE *pSoldier; GetSoldier( &pSoldier, gusSelectedSoldier ); OBJECTTYPE* pWeapon = pSoldier->GetUsedWeapon( &pSoldier->inv[ pSoldier->ubAttackingHand ] ); // Create a Background Rect for us to draw our indicator on. With NCTH, the size and position of this rectangle // is equal exactly to the size of the tactical screen viewport. Unlike the OCTH indicator, the NCTH one can grow // so large as to fill the entire screen. INT16 sLeft = gsVIEWPORT_START_X; INT16 sTop = gsVIEWPORT_WINDOW_START_Y; INT16 sRight = gsVIEWPORT_END_X; INT16 sBottom = gsVIEWPORT_WINDOW_END_Y; iBack = RegisterBackgroundRect(BGND_FLAG_SINGLE, NULL, sLeft, sTop, sRight, sBottom); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } ///////////////////////////////////////////////////////////////////////////////////////////// // HEADROCK HAM 4: New CTH, Aperture Size // // As explained above, the most important part of the new indicator is the Aperture circle/crosshairs. // These indicate the size of the "margin of error" for our current shot. The more accurate we are, // the smaller the circle will be. // // The player uses this to determine whether the shot has a good likelyhood to hit the target. // If the circle is the same size or smaller than the target itself, then hit probability is 100%. // The larger it gets, the less hit probability there will be. When adding extra aiming clicks, // the circle gets proportionally smaller. The idea is to try to make it as small as the target // (if possible) to ensure a hit. // // Shot aperture is calculated using the CTH formula (CalcChanceToHitGun). Scopes and lasers // can help decrease the size of the aperture further. ///////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// // Define colors UINT8 ColorsRed[10] = { 255, 255, 255, 255, 255, 255, 255, 255, 173, 0 }; UINT8 ColorsGreen[10] = { 0, 50, 81, 101, 133, 174, 211, 243, 255, 255 }; // Select the color of the indicator circles UINT16 usCApertureBar; // CHRISL: Instead of shigting the color based on MuzzleSwayPercent, let's move this line and base it on the final iAperture value // Indicator changes color from red to yellow to green, based on how well the gun is aimed. //usCApertureBar = Get16BPPColor( FROMRGB( ColorsRed[gCTHDisplay.MuzzleSwayPercentage/10], ColorsGreen[gCTHDisplay.MuzzleSwayPercentage/10], 0 ) ); // Crosshair color shifts from red (longshot) to green (Accurate shot) UINT16 usCApertureBorder = Get16BPPColor( FROMRGB( 10, 10, 10 ) ); // Boundaries in dark color. ////////////////////////////////// // Calculate Aperture // Calculate the center point of the shooter, in world coordinates. FLOAT dStartX = (FLOAT) CenterX( gCTHDisplay.iShooterGridNo ); FLOAT dStartY = (FLOAT) CenterY( gCTHDisplay.iShooterGridNo ); // Calculate the center point of the target, in world coordinates. FLOAT dEndX = (FLOAT) CenterX( gCTHDisplay.iTargetGridNo ); FLOAT dEndY = (FLOAT) CenterY( gCTHDisplay.iTargetGridNo ); // Calculate a delta: the difference between the shooter and target. FLOAT dDeltaX = dEndX - dStartX; FLOAT dDeltaY = dEndY - dStartY; // Calculate the distance of the shot, using Pythagorean Theorem DOUBLE d2DDistance = Distance2D( dDeltaX, dDeltaY ); // Round it upwards. INT32 iDistance = (INT32) d2DDistance; if ( d2DDistance != iDistance ) { iDistance += 1; d2DDistance = (FLOAT) ( iDistance); } /////////////////////////////////////////////////////////// // Now we calculate the Aperture size. This is done using the same method as the shooting formula uses. // Calculate the maximum angle of any shot. DOUBLE ddMaxAngleRadians = (gGameCTHConstants.DEGREES_MAXIMUM_APERTURE * 6.283) / 360; // Calculate the size of a "normal" aperture. This is how wide a shot can go at 1x Normal Distance. FLOAT iBasicAperture = (FLOAT)((sin(ddMaxAngleRadians) * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE) * 2); // The *2 compensates for the difference between CellXY and ScreenXY // when using the reworked NCTH code we do additional calculations for iron sights and lasers if (gGameExternalOptions.fUseNewCTHCalculation) { // iron sights can get a percentage bonus to make them overall better but only when not shooting from hip if ( gCTHDisplay.ScopeMagFactor <= 1.0 && !pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) iBasicAperture = iBasicAperture * (FLOAT)( (100 - gGameCTHConstants.IRON_SIGHT_PERFORMANCE_BONUS) / 100); // laser pointers can provide a percentage bonus to base aperture if ( gCTHDisplay.iBestLaserRange > 0 && ( gGameCTHConstants.LASER_PERFORMANCE_BONUS_HIP + gGameCTHConstants.LASER_PERFORMANCE_BONUS_IRON + gGameCTHConstants.LASER_PERFORMANCE_BONUS_SCOPE != 0) ) { INT8 bLightLevel = LightTrueLevel(gCTHDisplay.iTargetGridNo, gsInterfaceLevel ); INT32 iMaxLaserRange = ( gCTHDisplay.iBestLaserRange*( 2*bLightLevel + 3*NORMAL_LIGHTLEVEL_NIGHT - 5*NORMAL_LIGHTLEVEL_DAY ) ) / ( 2 * ( NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY ) ); // laser only has effect when in range if ( iMaxLaserRange > d2DDistance ) { FLOAT fLaserBonus = 0; // which bonus do we want to apply? if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, gCTHDisplay.iTargetGridNo ) ) // shooting from hip fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_HIP; else if ( gCTHDisplay.ScopeMagFactor <= 1.0 ) // using iron sights or other 1x sights fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_IRON; else // must be using a scope fLaserBonus = gGameCTHConstants.LASER_PERFORMANCE_BONUS_SCOPE; // light level influences how easy it is to spot the laser dot on the target FLOAT fBrightnessModifier = (FLOAT)(bLightLevel) / (FLOAT)(NORMAL_LIGHTLEVEL_NIGHT); // laser fully efficient if ( gCTHDisplay.iBestLaserRange > d2DDistance ) // apply full bonus iBasicAperture = iBasicAperture * (FLOAT)( (100 - (fLaserBonus * fBrightnessModifier)) / 100); else { // beyond BestLaserRange laser bonus drops linearly to 0 FLOAT fEffectiveLaserRatio = (FLOAT)(iMaxLaserRange - d2DDistance) / (FLOAT)(iMaxLaserRange - gCTHDisplay.iBestLaserRange); // apply partial bonus iBasicAperture = iBasicAperture * (FLOAT)( (100 - (fLaserBonus * fBrightnessModifier * fEffectiveLaserRatio)) / 100); } } } } // Next, find out how large the aperture can be around the target, given range. The further the target is, the // larger the aperture can be. FLOAT iDistanceAperture = iBasicAperture * (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); /////////////////////////////////////////////////////////////// // To make things easier for us, we now calculate the Magnification Factor for this shot. A Mag Factor // is a divisor to the sway of the muzzle. It's about the same as multiplying CTH by a certain amount. // Note that both optical magnification devices (like scopes) and dot-projection devices (like lasers and // reflex sights) provide this sort of bonus. FLOAT iMagFactor = CalcMagFactor( pSoldier, pWeapon, d2DDistance, gCTHDisplay.iTargetGridNo, (UINT8)pSoldier->aiData.bAimTime ); // Get effective mag factor for this shooter. This represents his ability to use scopes. FLOAT fEffectiveMagFactor = CalcEffectiveMagFactor( pSoldier, iMagFactor ); // Next step is to apply scope/projection factor to decrease the size of the aperture. This gives us the "Max // Aperture" value - the size of the shooting circle if the gun is as unstable as possible. FLOAT iMaxAperture = iDistanceAperture / fEffectiveMagFactor; // We now use the Muzzle Sway value, calculated by the CTH formula, to decrease the size of the shot aperture. // It is used as a percentage: a 50% muzzle sway value gives a cone with half the maximum radius. A cone with // 0% Muzzle Sway is a single line with no width (meaning all shots will fly right down the center, and all will // hit the target), while a cone with 100% muzzle sway is as wide as possible. FLOAT iAperture = ( iMaxAperture * (100.0f - (FLOAT)gCTHDisplay.MuzzleSwayPercentage) / 100.0f); ///////////////////////////////////////////// // Factor in Weapon "Effective Range". UINT16 sEffRange = Weapon[Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubClassIndex].usRange + GetRangeBonus(&(pSoldier->inv[ pSoldier->ubAttackingHand ])); FLOAT iRangeRatio = __max(1.0f, (FLOAT)(d2DDistance / sEffRange)); FLOAT iDistanceRatio = (FLOAT)(d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); ///////////////////////////////////////////// // Factor in Gun Accuracy. INT16 sAccuracy = GetGunAccuracy( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ); sAccuracy = __max(0, sAccuracy); sAccuracy = __min(100, sAccuracy); FLOAT iBulletDev = (gGameCTHConstants.MAX_BULLET_DEV * (100-sAccuracy)) / 100; if( gGameCTHConstants.RANGE_EFFECTS_DEV == TRUE ) iBulletDev *= iRangeRatio; iBulletDev *= iDistanceRatio; // Since bullet dev is only affected by distance, we add it last as a flat modifier. iBasicAperture += iBulletDev; iDistanceAperture += iBulletDev; iAperture += iBulletDev; // CHRISL: Moved here so we can base the cursor color on the iAperture value UINT8 iColorCode = 0; if(iAperture < 3.0) iColorCode = 9; else if(iAperture < 6.0) iColorCode = 8; else if(iAperture < 9.0) iColorCode = 7; else if(iAperture < 12.0) iColorCode = 6; else if(iAperture < 16.0) iColorCode = 5; else if(iAperture < 20.0) iColorCode = 4; else if(iAperture < 25.0) iColorCode = 3; else if(iAperture < 30.0) iColorCode = 2; else if(iAperture < 40.0) iColorCode = 1; usCApertureBar = Get16BPPColor( FROMRGB( ColorsRed[iColorCode], ColorsGreen[iColorCode], 0 ) ); // Crosshair color shifts from red (longshot) to green (Accurate shot) /////////////////////////////////////////////////////////////////////////////////////////////////// // HEADROCK HAM 4: Calculate Screen Positions // // Aperture Size has to be translated into on-screen size. We also want to track the position of the // mouse so that our indicator moves with it like a cursor. // Z Offset is used to move the indicator up or down. It's currently set to 0 since it's not required ATM. FLOAT zOffset = 0; // Calculate the position of the mouse cursor and store it. INT16 sStartScreenX; INT16 sStartScreenY; POINT MousePos; GetCursorPos(&MousePos); ScreenToClient(ghWindow, &MousePos); // In window coords! sStartScreenX = (INT16)MousePos.x; sStartScreenY = (INT16)MousePos.y; // Define regions for the various indicators. We need to do this now because the Aperture Circles will want to // avoid being drawn within these regions, otherwise they might make them harder to see. MagRect.left = sStartScreenX-50; MagRect.top = sStartScreenY-15; MagRect.right = sStartScreenX-20; MagRect.bottom = sStartScreenY-5; APRect.left = sStartScreenX+22; APRect.top = sStartScreenY-15; APRect.right = sStartScreenX+52; APRect.bottom = sStartScreenY-5; AimRect.left = sStartScreenX-35; AimRect.top = sStartScreenY+22; AimRect.right = sStartScreenX+35; AimRect.bottom = sStartScreenY+30; ModeRect.left = sStartScreenX-28; ModeRect.top = sStartScreenY+31; ModeRect.right = sStartScreenX+28; ModeRect.bottom = sStartScreenY+41; //////////////////////////////////////////////////////////////////////////////////////// // DRAW ADDITIONAL COMPONENTS: // // We now draw additional indicators on top of the circles. There are four indicators: // // 1. AP Cost: The current AP cost for the shot has been moved from the center of the // targeting cursor to avoid obscuring the meeting point of the aperture crosshairs. // It is now displayed in the top right, together with the word "AP". // 2. MAG Factor: The current Magnification or Projection factor for the shot is displayed // in the top-left, followed by an "x". Its color indicates whether we are using the // full potential of our aiming device. // 3. Aiming Pips: The circles on the old indicator shows how many aiming clicks we've // placed into the shot. Now that the circles are used to indicate shot probability, // the aiming clicks are displayed with a series of pips below the targeting cursor // which fill up as we add levels. // 4. Bullet Count: This indicator, now below the Aiming Pips indicator, shows the number // of bullets queues up for a Burst/Autofire volley. For autofire, it starts out by // displaying grey bullets showing how many we CAN add, then fills up with colored // bullets as we add them to the volley. A "+" sign is added if space for bullets runs out. CHAR16 pStr[10]; INT16 curX = 0; INT16 curY = 0; ///////////////////////////////////////// // Load image STI UINT32 guiCTHImage; VOBJECT_DESC VObjectDesc; VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE; if(UsingNewCTHSystem() == true) FilenameForBPP("CURSORS\\CUR_CTH_NCTH.sti", VObjectDesc.ImageFile); else FilenameForBPP("CURSORS\\CUR_CTH.sti", VObjectDesc.ImageFile); CHECKF(AddVideoObject(&VObjectDesc, &guiCTHImage)); /////////////// AP COST FOR CURRENT SHOT { // Create a pointer to the Frame Buffer which we are going to draw directly into. SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); // Find coordinates, using the full string ("XX AP") swprintf( pStr, L"%d %s", gsCurrentActionPoints, gzNCTHlabels[ 1 ] ); FindFontCenterCoordinates( (INT16)APRect.left, (INT16)APRect.top, (INT16)APRect.right-(INT16)APRect.left, 10, pStr, TINYFONT1, &curX, &curY); // Find width of this string. UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); // Cut string to just the number of APs swprintf( pStr, L"%d", gsCurrentActionPoints ); // Find out how wide this string is UINT16 usWidth = StringPixLength( pStr, TINYFONT1 ); // Draw to screen gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Draw the "AP" label 4 pixels forward. SetFontForeground(FONT_MCOLOR_LTYELLOW); swprintf( pStr, L"%s", gzNCTHlabels[ 1 ] ); curX += usWidth + 4; gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Redefine area size based on total width plus a margin of 2 pixels. usTotalWidth = usTotalWidth + 6; INT16 sCenter = (INT16)((APRect.right + APRect.left) / 2); APRect.left = sCenter - (usTotalWidth / 2); APRect.right = sCenter + (usTotalWidth / 2); } // sevenfm: draw item pics DrawNCTHCursorItemPics( sStartScreenX, sStartScreenY ); /////////////// MAG FACTOR { SetFont( TINYFONT1 ); // Find coordinates, using full string ("X.X x") swprintf( pStr, L"%1.1f x", gCTHDisplay.FinalMagFactor ); FindFontCenterCoordinates( (INT16)MagRect.left, (INT16)MagRect.top, (INT16)MagRect.right-(INT16)MagRect.left, 10, pStr, TINYFONT1, &curX, &curY); // Find width of this string. UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); // Cut string to just the float swprintf( pStr, L"%1.1f", gCTHDisplay.FinalMagFactor ); // Record the width of the float UINT16 usWidth = StringPixLength( pStr, TINYFONT1 ); //////////////////////////// // We change the color of this indicator based on whether or not our optical devices are working // at full potential. Remember that scopes below their best range give out penalties! // If using a scope below its optimal range... if (gCTHDisplay.ScopeMagFactor > 1.0 && gCTHDisplay.ScopeMagFactor > gCTHDisplay.FinalMagFactor) { // If within projection range... if (gCTHDisplay.ProjectionFactor > 1.0 && gCTHDisplay.ProjectionFactor >= iDistanceRatio ) { SetFontForeground( FONT_ORANGE ); } // If only using a scope... else { SetRGBFontForeground( 255, 150, 150 ); // Bright Pink } } // If using a scope above its range, or a laser below its range else if ((gCTHDisplay.ScopeMagFactor > 1.0 && gCTHDisplay.ScopeMagFactor <= iDistanceRatio) || (gCTHDisplay.ProjectionFactor > 1.0 && gCTHDisplay.ProjectionFactor >= iDistanceRatio) ) { SetRGBFontForeground( 100,255,100 ); // True Light Green } // In all other circumstances... else { SetFontForeground( FONT_MCOLOR_WHITE ); } // Print the float gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Add an "x" 4 pixels forward. SetFontForeground( FONT_MCOLOR_LTYELLOW ); swprintf( pStr, L"x" ); curX += usWidth + 4; gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Redefine area size based on total width plus a margin of 2 pixels. usTotalWidth = usTotalWidth + 6; INT16 sCenter = (INT16)((MagRect.right + MagRect.left) / 2); MagRect.left = sCenter - (usTotalWidth / 2); MagRect.right = sCenter + (usTotalWidth / 2); } #ifdef JA2BETAVERSION /////////////// SHOT APERTURE SIZE { // Create a pointer to the Frame Buffer which we are going to draw directly into. SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); // Find coordinates, using the full string ("XX AP") swprintf( pStr, L"%3.2f", iAperture ); FindFontCenterCoordinates( (INT16)APRect.left, (INT16)APRect.top-5, (INT16)APRect.right-(INT16)APRect.left, 5, pStr, TINYFONT1, &curX, &curY); // Find width of this string. UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); // Draw to screen gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Redefine area size based on total width plus a margin of 2 pixels. usTotalWidth = usTotalWidth + 6; INT16 sCenter = (INT16)((APRect.right + APRect.left) / 2); APRect.left = sCenter - (usTotalWidth / 2); APRect.right = sCenter + (usTotalWidth / 2); } /////////////// DISTANCE APERTURE SIZE { SetFont( TINYFONT1 ); // Find coordinates, using full string ("X.X x") swprintf( pStr, L"%3.2f", iDistanceAperture ); FindFontCenterCoordinates( (INT16)MagRect.left, (INT16)MagRect.top-5, (INT16)MagRect.right-(INT16)MagRect.left, 5, pStr, TINYFONT1, &curX, &curY); // Find width of this string. UINT16 usTotalWidth = StringPixLength ( pStr, TINYFONT1 ); // Draw to screen gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); // Redefine area size based on total width plus a margin of 2 pixels. usTotalWidth = usTotalWidth + 6; INT16 sCenter = (INT16)((MagRect.right + MagRect.left) / 2); MagRect.left = sCenter - (usTotalWidth / 2); MagRect.right = sCenter + (usTotalWidth / 2); } #endif //////////////////// BURST/AUTO LABEL AND BULLETS if (pSoldier->bDoBurst) { SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); //////////////////////////////////////////////////////////////////////////////// // We need to calculate how many bullets to display, and how much space they // take, so that we can center them horizontally on the CTH indicator. // This works slightly differently for Autofire and Burst. UINT8 ubNumBullets = 0; UINT8 ubBulletWidth = 4; UINT8 ubTotalWidth = 0; UINT32 uiMaxAutofire = 0; UINT32 uiMaxBulletsToDisplay = 0; UINT32 uiSpacesToDisplay = 0; if (pSoldier->bDoAutofire) { // Number of COLORED bullets to display is the number of bullets we want to fire. ubNumBullets = pSoldier->bDoAutofire; // How many bullets are left in the gun? UINT32 uiBulletsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; if (pSoldier->IsValidSecondHandBurst()) { uiBulletsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), uiBulletsLeft ); } UINT32 uiCurBullet = uiBulletsLeft; while( uiCurBullet > 0 ) { // We work backwards from the total number of bullets left, to find out the number of bullets // that can be fired given the current number of APs left. // Store Soldier Autofire variable into a temp. We do this to fool the AP Calculation formula. UINT8 TempDoAutofire = pSoldier->bDoAutofire; pSoldier->bDoAutofire = uiCurBullet; //Get AP cost to fire this many bullets INT16 sAPCosts = CalcTotalAPsToAttack( pSoldier, gCTHDisplay.iTargetGridNo, TRUE, pSoldier->aiData.bShownAimTime); // Switch back. pSoldier->bDoAutofire = TempDoAutofire; // Have we reached a number of bullets that can be fired with the current APs? if( !uiMaxAutofire && EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) ) { // Set it. uiMaxAutofire = uiCurBullet; } //Decrement until zero. uiCurBullet--; } // Display no more than X bullets on screen! uiMaxBulletsToDisplay = __min(uiMaxAutofire, 15); // Calculate how many spaces to display. Currently, a space is displayed after every 5 bullets. uiSpacesToDisplay = (uiMaxBulletsToDisplay-1) / 5; // Calculate the total width of this display in pixels. Spaces and bullets have the same width. ubTotalWidth = ubBulletWidth * (uiMaxBulletsToDisplay + uiSpacesToDisplay); } else { // Number of COLORED bullets to display is the number of bullets we want to fire. ubNumBullets = GetShotsPerBurst( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ); // Display no more than X bullets on screen! uiMaxBulletsToDisplay = __min(ubNumBullets, 15); // Calculate how many spaces to display. Currently, a space is displayed after every 5 bullets. uiSpacesToDisplay = (uiMaxBulletsToDisplay-1) / 5; // Calculate the total width of this display in pixels. Spaces and bullets have the same width. ubTotalWidth = ubBulletWidth * (uiMaxBulletsToDisplay + uiSpacesToDisplay); } // Tracks the number of spaces we've drawn on screen so far. UINT16 usNumSpacesShown = 0; // AUTO FIRE if (pSoldier->bDoAutofire) { // Draw greyed-out bullets, indicating how many bullets CAN be added to the volley given our // current remaining APs. for (UINT8 x = 0; x < (uiMaxBulletsToDisplay); x++) { // Find starting point for drawing INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); INT16 sTop = (INT16)ModeRect.top; // If we've drawn 5,10,15,etc. bullets, add a space. if (x > 0 && x%5 == 0) { usNumSpacesShown++; } // Offset adds up the number of bullets and spaces we've already drawn. INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); // Draw a bullet here! BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 8, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); // If the number of bullets that can be fired is greater than the number of bullets we can display, // and we've just now drawn the last displayable bullet, then... if (x == uiMaxBulletsToDisplay-1 && uiMaxBulletsToDisplay < uiMaxAutofire) { // Draw a shaded plus sign at the end. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 9, sLeft + sCurOffset + ubBulletWidth, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); } } // Draw colored bullets. These show how many bullets we've set to fire with the current volley. usNumSpacesShown = 0; for (UINT8 x = 0; x < ubNumBullets; x++) { // Set start point for drawing INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); INT16 sTop = (INT16)ModeRect.top; // Calculate offset based on the number of bullets and spaces already drawn. INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); // If we're drawing more bullets than can be displayed on-screen... if (x == uiMaxBulletsToDisplay) { // Draw a colored plus sign at the end. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 10, sLeft + sCurOffset, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); // Set x to NumBullets to end the loop x = ubNumBullets; } else { // If we've drawn 5,10,15,etc. bullets, increase the number of spaces drawn. if (x > 0 && x%5 == 0) { usNumSpacesShown++; } // Recalculate offset to take any new spaces into account. INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); // Draw a colored bullet here. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 7, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } // Redefine area size based on total width plus a margin of 2 pixels. ubTotalWidth = ubTotalWidth + 6; INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); ModeRect.left = sCenter - (ubTotalWidth / 2); ModeRect.right = sCenter + (ubTotalWidth / 2); } // BURST FIRE else { // Draw colored bullets. These show how many bullets we've set to fire with the current burst. usNumSpacesShown = 0; UINT16 usTotalWidth = 0; UINT8 x; for (x = 0; x < ubNumBullets; x++) { // Set start point for drawing INT16 sLeft = (((INT16)ModeRect.left + (INT16)ModeRect.right)/2) - (ubTotalWidth/2); INT16 sTop = (INT16)ModeRect.top; // Calculate offset based on the number of bullets and spaces already drawn. INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); // If we're drawing more bullets than can be displayed on-screen... if (x == uiMaxBulletsToDisplay) { // Draw a colored plus sign at the end. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 10, sLeft + sCurOffset, sTop+2, VO_BLT_SRCTRANSPARENCY, NULL ); // Set x to NumBullets to end the loop x = ubNumBullets; usTotalWidth += 5; } else { // If we've drawn 5,10,15,etc. bullets, increase the number of spaces drawn. if (x > 0 && x%5 == 0) { usNumSpacesShown++; } // Recalculate offset to take any new spaces into account. INT16 sCurOffset = ubBulletWidth * (x+usNumSpacesShown); // Draw a colored bullet here. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 7, sLeft + sCurOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } usTotalWidth += ubBulletWidth * ((x+1)+usNumSpacesShown)+4; INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); ModeRect.left = sCenter - (ubTotalWidth / 2); ModeRect.right = sCenter + (ubTotalWidth / 2); } } /////////////// SINGLE-SHOT. else { // Draw a label that says "SINGLE" instead of bullets. SetFont( TINYFONT1 ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); swprintf( pStr, gzNCTHlabels[ 0 ] ); FindFontCenterCoordinates( (INT16)ModeRect.left, (INT16)ModeRect.top, (INT16)ModeRect.right-(INT16)ModeRect.left, 10, pStr, TINYFONT1, &curX, &curY); gprintfdirty( curX, curY, pStr ); mprintf( curX, curY, pStr); UINT16 usTotalWidth = StringPixLength( pStr, TINYFONT1 ) + 6; INT16 sCenter = (INT16)((ModeRect.right + ModeRect.left) / 2); ModeRect.left = sCenter - (usTotalWidth / 2); ModeRect.right = sCenter + (usTotalWidth / 2); } /////////////// AIM LEVELS { // Calculate number of allowed aiming levels on this gun. INT8 ubAllowedLevels = AllowedAimingLevels( pSoldier, gCTHDisplay.iTargetGridNo ); // Number of ticks to display, and the number of spaces between them. UINT8 ubNumTicks = ((ubAllowedLevels-1)*2)+1; UINT8 ubNumSpaces = ubNumTicks-1; // Width of the tick image plus (or minus) a mandatory margin. UINT8 ubAimTickWidth = 5; // Total width of the aiming display if using no extra spacing and MAXIMUM allowed aiming levels (currently 8) UINT8 ubAimMaxTotalWidth = ubAimTickWidth * ((8 * 2)-1); // Total width of the aiming display if using no extra spacing and as many levels as allowed by the gun. UINT8 ubAimPlainWidth = ubAimTickWidth * ubNumTicks; // Find the largest space width possible without exceeding the maximum width. We do this by // finding the difference between MaxTotal width and Plain width, and dividing it by the number of spaces // we've got. UINT8 ubAimFinalOffset = 0; UINT8 ubAimFinalWidth = 0; if (ubNumSpaces > 0) { UINT8 ubAimBestOffset = (ubAimMaxTotalWidth - ubAimPlainWidth) / ubNumSpaces; // Final offset is whichever is smallest - the largest width, or the width of a single tick. ubAimFinalOffset = __min(ubAimBestOffset, ubAimTickWidth); } // else leave at 0 ubAimFinalOffset += ubAimTickWidth; // Final width of the entire display, taking all ticks and spaces into account. ubAimFinalWidth = ubAimTickWidth + (ubAimFinalOffset * ubNumSpaces); // Find offset from center. UINT8 ubAimLeftOffset = ubAimFinalWidth / 2; // Find starting coordinates for this display sTop = (INT16)AimRect.top; sLeft = (INT16)((AimRect.left+AimRect.right)/2) - ubAimLeftOffset; // Draw empty ticks. for (UINT8 x = 0; x < (ubAllowedLevels*2)-1; x++) { INT16 sOffset = x * ubAimFinalOffset; if (gfDisplayFullCountRing) { if (ubAllowedLevels - abs((ubAllowedLevels-(x+1))) >= pSoldier->aiData.bShownAimTime) { // Red empty tick - unusable aim level with current AP! BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 6, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { // Orange empty tick - Used aim tick. BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 4, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } else { if (pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) && ubAllowedLevels - abs((ubAllowedLevels-(x+1))) <= GetNumberAltFireAimLevels( pSoldier, gCTHDisplay.iTargetGridNo ) ) { // yellow empty tick BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 2, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { // grey empty tick BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 0, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } } // Draw Filled Ticks if (pSoldier->aiData.bShownAimTime) { // Tick on the left INT16 sNewLeft = sLeft + (ubAimFinalOffset * (pSoldier->aiData.bShownAimTime-1)); if (gfDisplayFullCountRing) { if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } else { if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } // Tick on the right sNewLeft = sLeft + (ubAimFinalOffset * (ubNumSpaces-(pSoldier->aiData.bShownAimTime-1))); if (gfDisplayFullCountRing) { if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } else { if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } else { BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); } } } ubAimFinalWidth += 6; INT16 sCenter = (INT16)((AimRect.right + AimRect.left) / 2); AimRect.left = sCenter - (ubAimFinalWidth / 2); AimRect.right = sCenter + (ubAimFinalWidth / 2); } // Delete CTH indicator STIs from memory. DeleteVideoObjectFromIndex( guiCTHImage ); /////////////////////////////////////////////////////////////////////////////////////// // HEADROCK HAM 4: Drawing the CTH indicator to the Frame Buffer // // Early on I ran into issues concerning drawing this indicator on the screen. At first I naturally // wanted to draw it on the Cursor Buffer, the same way as the old indicator. Unfortunately, // the size of the Cursor Buffer is quite limited (~35x35 pixels) and is governed by the size of the STIs used // for the mouse cursor itself. After much trial and error, it became obvious that it was impossible to draw // a large indicator (as required by the NCTH system) directly onto the mouse buffer. // // Fortunately, I found out that it was possible to draw into the Frame Buffer instead, without leaving // graphical glitches behind. I could also dynamically define the area to draw into as I pleased. Furthermore, // I managed to make this drawing behave the same as a mouse cursor would, by having it follow the mouse // position. // // The end result is a bit of an ugly workaround: We're drawing what is essentially a mouse cursor without referring // to ANY part of the mouse cursor system (except the location of the mouse). This is the only way I could make it // work, and so far it works flawlessly. // Create a pointer to the Frame Buffer which we are going to draw directly into. UINT32 uiPitch; UINT16 *ptrBuf = (UINT16*)LockVideoSurface( FRAME_BUFFER, &uiPitch ); uiPitch >>= 1; /////////////////////////////////////////////////////////////////////////////// // Begin drawing sLeft = gsVIEWPORT_START_X; sTop = gsVIEWPORT_WINDOW_START_Y; sRight = gsVIEWPORT_END_X; sBottom = gsVIEWPORT_WINDOW_END_Y; // INT16 lastY = 0; // INT16 diffY = 0; // UINT32 uiAperture = __max(2,(UINT32)iAperture); // UINT32 uiMaxAperture = __max(2,(UINT32)iDistanceAperture); UINT32 uiApertureBarLength = 10; INT32 cnt = 0; // Vertical bias makes the circle "flatter" and "wider" in prone and crouched stance. FLOAT dVerticalBias = gGameCTHConstants.VERTICAL_BIAS; switch (gAnimControl[ pSoldier->usAnimState ].ubEndHeight) { case ANIM_STAND: dVerticalBias = 1.0; break; case ANIM_PRONE: // no change break; case ANIM_CROUCH: dVerticalBias = 1.0f + ((dVerticalBias - 1.0f) * 0.66f); break; } // Circumference tells us how many pixels to draw, hopefully. FLOAT RADIANS_IN_CIRCLE = (FLOAT)(PI * 2); INT32 Circ = 0; Circ = (INT32)((iDistanceAperture * RADIANS_IN_CIRCLE) * dVerticalBias); if(gGameSettings.fOptions[ TOPTION_CTH_CURSOR ]) { // Draw outer circle for (INT32 iCurPoint = 0; iCurPoint < Circ; iCurPoint++) { curX = (INT16)(iDistanceAperture * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); curY = (INT16)((iDistanceAperture * dVerticalBias) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); INT16 firstX = curX; INT16 firstY = curY; DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBar ); // Draw a border circle which is 1 point wider // curX = (INT16)((iDistanceAperture+1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // curY = (INT16)(((iDistanceAperture * dVerticalBias)+1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // if (curX != firstX || curY != firstY) // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); // Draw a border circle which is 1 point narrower // curX = (INT16)((iDistanceAperture-1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // curY = (INT16)(((iDistanceAperture * dVerticalBias)-1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // if (curX != firstX || curY != firstY) // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); } Circ = (INT32)((iAperture * RADIANS_IN_CIRCLE) * dVerticalBias); // Draw inner circle for (INT32 iCurPoint = 0; iCurPoint < Circ; iCurPoint++) { curX = (INT16)(iAperture * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); curY = (INT16)((iAperture * dVerticalBias) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); INT16 firstX = curX; INT16 firstY = curY; DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBar ); // Draw a border circle which is 1 point wider // curX = (INT16)((iAperture+1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // curY = (INT16)(((iAperture * dVerticalBias)+1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // if (curX != firstX || curY != firstY) // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); // Draw a border circle which is 1 point narrower // curX = (INT16)((iAperture-1) * cos((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // curY = (INT16)(((iAperture * dVerticalBias)-1) * sin((iCurPoint * RADIANS_IN_CIRCLE)/Circ)); // if (curX != firstX || curY != firstY) // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+curX, sStartScreenY+curY+(INT16)zOffset, usCApertureBorder ); } // Aperture Crosshairs for (INT16 cnt = (INT16)(iAperture); cnt <= (INT16)(iAperture + uiApertureBarLength); cnt++) { // Horizontal Aperture Crosshairs DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, sStartScreenY+(INT16)zOffset, usCApertureBar ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, sStartScreenY+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBar ); // Darker borders // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY+2)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY+2)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY-2)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY-2)+(INT16)zOffset, usCApertureBorder ); // Darker borders DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY+1)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-cnt, (sStartScreenY-1)+(INT16)zOffset, usCApertureBorder ); } for (INT16 cnt = (INT16)(iAperture * dVerticalBias); cnt <= (INT16)((iAperture * dVerticalBias) + uiApertureBarLength); cnt++) { // Vertical Aperture Crosshairs DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBar ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBar ); // Darker borders // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+2, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+2, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-2, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); // DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-2, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX+1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY+cnt)+(INT16)zOffset, usCApertureBorder ); DrawCTHPixelToBuffer( ptrBuf, uiPitch, sLeft, sTop, sRight, sBottom, sStartScreenX-1, (sStartScreenY-cnt)+(INT16)zOffset, usCApertureBorder ); } } // Unlock the Frame Buffer. UnLockVideoSurface( FRAME_BUFFER ); return (TRUE); } void RenderOverlayMessage( VIDEO_OVERLAY *pBlitter ) { // Override it! OverrideMercPopupBox( &gpOverrideMercBox ); RenderMercPopupBox( pBlitter->sX, pBlitter->sY, pBlitter->uiDestBuff ); // Set it back! ResetOverrideMercPopupBox( ); InvalidateRegion( pBlitter->sX, pBlitter->sY, pBlitter->sX + gusOverlayPopupBoxWidth, pBlitter->sY + gusOverlayPopupBoxHeight ); } void BeginOverlayMessage( UINT32 uiFont, STR16 pFontString, ... ) { va_list argptr; VIDEO_OVERLAY_DESC VideoOverlayDesc; CHAR16 SlideString[512]; va_start(argptr, pFontString); // Set up variable argument pointer vswprintf(SlideString, pFontString, argptr); // process gprintf string (get output str) va_end(argptr); // Override it! OverrideMercPopupBox( &gpOverrideMercBox ); SetPrepareMercPopupFlags( MERC_POPUP_PREPARE_FLAGS_TRANS_BACK | MERC_POPUP_PREPARE_FLAGS_MARGINS ); // Prepare text box iOverlayMessageBox = PrepareMercPopupBox( iOverlayMessageBox, BASIC_MERC_POPUP_BACKGROUND, RED_MERC_POPUP_BORDER, SlideString, 200, 50, 0, 0, &gusOverlayPopupBoxWidth, &gusOverlayPopupBoxHeight ); // Set it back! ResetOverrideMercPopupBox( ); if ( giPopupSlideMessageOverlay == -1 ) { // WDS - bug fix: VideoOverlayDesc must be initialized! - 07/16/2007 memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); // Set Overlay VideoOverlayDesc.sLeft = ( SCREEN_WIDTH - gusOverlayPopupBoxWidth ) / 2; VideoOverlayDesc.sTop = 100; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusOverlayPopupBoxWidth; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusOverlayPopupBoxHeight; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderOverlayMessage; giPopupSlideMessageOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); } } void EndOverlayMessage( ) { if ( giPopupSlideMessageOverlay != -1 ) { // DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Removing Overlay message") ); RemoveVideoOverlay( giPopupSlideMessageOverlay ); giPopupSlideMessageOverlay = -1; } } void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sWidth, INT16 sHeight, INT16 interval ) { FLOAT dWidth, dPercentage; UINT32 uiDestPitchBYTES; UINT8 *pDestBuf; INT8 bBandage; INT8 bPoisonBandage; INT16 color8; INT16 color16; // Draw new size pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); // region rysowania barow nad najemnikiem SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, ( gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y ) ); // sevenfm: draw background for alt bar if( gGameExternalOptions.ubShowHealthBarsOnHead > 1 ) { DrawBar( sXPos+2, sYPos, sWidth + 2, 1 + interval*3, COLOR_BLACK, Get16BPPColor( FROMRGB( 0, 0, 0 ) ), pDestBuf ); // draw border: light brown for stealth mode, grey for regular if(pSoldier->bStealthMode) { color8 = COLOR_BROWN; color16 = Get16BPPColor( FROMRGB( 180, 140, 20 ) ); } else{ color8 = COLOR_DKGREY; color16 = Get16BPPColor( FROMRGB( 120, 120, 120 ) ); } if ( pSoldier->ubID == gusSelectedSoldier ) { if(gbPixelDepth==16) RectangleDraw( TRUE, sXPos+1, sYPos-1, sXPos+sWidth+3, sYPos+1+interval*3, color16, pDestBuf); else RectangleDraw8( TRUE, sXPos+1, sYPos-1, sXPos+sWidth+3, sYPos+1+interval*3, color8, pDestBuf); } } // get amt bandaged bBandage = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; // get amount of poisoned bandage bPoisonBandage = pSoldier->bPoisonSum - pSoldier->bPoisonBleeding - pSoldier->bPoisonLife; // NOW DO BLEEDING if ( pSoldier->bBleeding ) { dPercentage = (FLOAT)( pSoldier->bBleeding + pSoldier->stats.bLife + bBandage )/ (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_RED, Get16BPPColor( FROMRGB( 240, 240, 20 ) ), pDestBuf ); } // poisoned bleeding if ( pSoldier->bPoisonBleeding ) { dPercentage = (FLOAT)( pSoldier->stats.bLifeMax - pSoldier->bBleeding + pSoldier->bPoisonBleeding )/ (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_GREEN, Get16BPPColor( FROMRGB( 240, 20, 240 ) ), pDestBuf ); } if( bBandage ) { dPercentage = (FLOAT)( pSoldier->stats.bLife + bBandage ) / (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_RED, Get16BPPColor( FROMRGB( 222, 132, 132 ) ), pDestBuf ); } // poisoned bandage if ( bPoisonBandage ) { dPercentage = (FLOAT)( pSoldier->stats.bLife + bPoisonBandage )/ (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_GREEN, Get16BPPColor( FROMRGB( 132, 222, 132 ) ), pDestBuf ); } dPercentage = (FLOAT)pSoldier->stats.bLife / (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_RED, Get16BPPColor( FROMRGB( 200, 0, 0 ) ), pDestBuf ); // poisoned life if ( pSoldier->bPoisonLife ) { dPercentage = (FLOAT)( pSoldier->bPoisonLife )/ (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1, (INT32)dWidth, sHeight, COLOR_GREEN, Get16BPPColor( FROMRGB( 0, 200, 0 ) ), pDestBuf ); } dPercentage = (FLOAT)( pSoldier->bBreathMax ) / (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1 + interval, (INT32)dWidth, sHeight, COLOR_BLUE, Get16BPPColor( FROMRGB( 20, 20, 150 ) ), pDestBuf ); dPercentage = (FLOAT)( pSoldier->bBreath ) / (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos + 3, sYPos + 1 + interval, (INT32)dWidth, sHeight, COLOR_BLUE, Get16BPPColor( FROMRGB( 100, 100, 220 ) ), pDestBuf ); /* // morale dPercentage = (FLOAT)pSoldier->aiData.bMorale / (FLOAT)100; dWidth = dPercentage * sWidth; if(gbPixelDepth==16) { usLineColor = Get16BPPColor( FROMRGB( 0, 250, 0 ) ); RectangleDraw( TRUE, sXPos + 1, sYPos + 7, (INT32)( sXPos + dWidth + 1 ), sYPos + 7, usLineColor, pDestBuf ); } else if(gbPixelDepth==8) { // DB Need to change this to a color from the 8-bit standard palette usLineColor = COLOR_GREEN; RectangleDraw8( TRUE, sXPos + 1, sYPos + 7, (INT32)( sXPos + dWidth + 1 ), sYPos + 7, usLineColor, pDestBuf ); } */ // draw suppression shock bar if( gGameExternalOptions.ubShowHealthBarsOnHead > 1 ) { dPercentage = (FLOAT)( __min(100, ( (FLOAT)100 * CalcEffectiveShockLevel( pSoldier ) ) / CalcSuppressionTolerance( pSoldier ) ) ) / (FLOAT)100; dWidth = dPercentage * sWidth; DrawBar( sXPos+3, sYPos+1+2*interval, (INT32)dWidth, sHeight, COLOR_ORANGE, Get16BPPColor( FROMRGB( 220, 140, 0 ) ), pDestBuf ); } /* BOOLEAN bDisguised = pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV | SOLDIER_COVERT_SOLDIER); BOOLEAN bStealth = pSoldier->bStealthMode; // draw cover indicators if( ( gGameExternalOptions.ubShowHealthBarsOnHead > 1 ) && ( (gTacticalStatus.uiFlags & TURNBASED ) && (gTacticalStatus.uiFlags & INCOMBAT) || bStealth || bDisguised ) ) { INT8 cover = 3; // MAX_COVER BOOLEAN showCover; INT32 usMapPos; if( gGameExternalOptions.ubShowCoverIndicator ==1 || ( gGameExternalOptions.ubShowCoverIndicator ==3 && (bStealth || bDisguised) ) ) { if( GetMouseMapPos(&usMapPos) && _KeyDown(SHIFT) ) { // draw target tile cover indicator CalculateCoverForSoldier( pSoldier, usMapPos, gsInterfaceLevel, cover ); showCover = CoverColorCode( cover, color8, color16 ); } else { // draw cover indicator CalculateCoverForSoldier( pSoldier, pSoldier->sGridNo, pSoldier->pathing.bLevel, cover ); showCover = CoverColorCode( cover, color8, color16 ); if ( color8 == COLOR_GREEN) showCover = FALSE; } if(showCover) DrawBar( sXPos+33, sYPos+1, 1+sHeight , (interval==3 ? 2 : 3 )*interval-1, color8, color16, pDestBuf ); } } */ UnLockVideoSurface( FRAME_BUFFER ); } void EndDeadlockMsg( ) { // Reset gridlock gfUIInDeadlock = FALSE; } void ClearInterface( ) { if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) { return; } // Stop any UI menus! if ( gCurrentUIMode == MENU_MODE ) { EndMenuEvent( guiCurrentEvent ); } if ( gfUIHandleShowMoveGrid ) { RemoveTopmost( gsUIHandleShowMoveGridLocation, FIRSTPOINTERS4 ); RemoveTopmost( gsUIHandleShowMoveGridLocation, FIRSTPOINTERS2 ); RemoveTopmost( gsUIHandleShowMoveGridLocation, FIRSTPOINTERS13 ); RemoveTopmost( gsUIHandleShowMoveGridLocation, FIRSTPOINTERS15 ); } // Remove any popup menus if ( gCurrentUIMode == GETTINGITEM_MODE ) { RemoveItemPickupMenu( ); } // Remove any popup menus if ( gCurrentUIMode == OPENDOOR_MENU_MODE ) { PopDownOpenDoorMenu( ); } // Remove UP/DOWN arrows... //EraseRenderArrows( ); // Don't render arrows this frame! guiShowUPDownArrows = ARROWS_HIDE_UP | ARROWS_HIDE_DOWN; gTintBulletCounts = FALSE; gfUIAutofireBulletCount = FALSE; ResetPhysicsTrajectoryUI( ); // Remove any paths, cursors ErasePath( FALSE ); //gfPlotNewMovement = TRUE; // Erase Interface cursors HideUICursor( ); MSYS_ChangeRegionCursor( &gViewportRegion , VIDEO_NO_CURSOR ); // Hide lock UI cursors... MSYS_ChangeRegionCursor( &gDisableRegion , VIDEO_NO_CURSOR ); MSYS_ChangeRegionCursor( &gUserTurnRegion , VIDEO_NO_CURSOR ); // Remove special thing for south arrow... if ( gsGlobalCursorYOffset == ( SCREEN_HEIGHT - gsVIEWPORT_WINDOW_END_Y ) ) { SetCurrentCursorFromDatabase( VIDEO_NO_CURSOR ); } } void RestoreInterface( ) { // Once we are done, plot path again! gfPlotNewMovement = TRUE; // OK, reset arrows too... gfUIRefreshArrows = TRUE; // SHow lock UI cursors... MSYS_ChangeRegionCursor( &gDisableRegion , CURSOR_WAIT ); MSYS_ChangeRegionCursor( &gUserTurnRegion , CURSOR_WAIT ); } void BlitPopupText( VIDEO_OVERLAY *pBlitter ) { UINT8 *pDestBuf; UINT32 uiDestPitchBYTES; BltVideoSurface( pBlitter->uiDestBuff, guiINTEXT, 0, pBlitter->pBackground->sLeft, pBlitter->pBackground->sTop, VS_BLT_FAST | VS_BLT_USECOLORKEY, NULL ); pDestBuf = LockVideoSurface( pBlitter->uiDestBuff, &uiDestPitchBYTES); SetFont( pBlitter->uiFontID ); SetFontBackground( pBlitter->ubFontBack ); SetFontForeground( pBlitter->ubFontFore ); mprintf_buffer( pDestBuf, uiDestPitchBYTES, pBlitter->uiFontID, pBlitter->sX, pBlitter->sY, pBlitter->zText ); UnLockVideoSurface( pBlitter->uiDestBuff ); } void DirtyMercPanelInterface( SOLDIERTYPE *pSoldier, UINT8 ubDirtyLevel ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DirtyMercPanelInterface")); if ( pSoldier->bTeam == gbPlayerNum ) { // ONly set to a higher level! if ( fInterfacePanelDirty < ubDirtyLevel ) { fInterfacePanelDirty = ubDirtyLevel; } } } typedef struct { SOLDIERTYPE *pSoldier; STRUCTURE *pStructure; UINT8 ubDirection; INT16 sX; INT16 sY; BOOLEAN fMenuHandled; BOOLEAN fClosingDoor; } OPENDOOR_MENU; OPENDOOR_MENU gOpenDoorMenu; BOOLEAN gfInOpenDoorMenu = FALSE; BOOLEAN InitDoorOpenMenu( SOLDIERTYPE *pSoldier, STRUCTURE *pStructure, UINT8 ubDirection, BOOLEAN fClosingDoor ) { INT16 sHeight, sWidth; INT16 sScreenX, sScreenY; // Can't bring up this menu if in autobandage mode if (gTacticalStatus.fAutoBandageMode) { return FALSE; } // Erase other menus.... EraseInterfaceMenus( TRUE ); InterruptTime(); PauseGame(); LockPauseState( 19 ); // Pause timers as well.... PauseTime( TRUE ); gOpenDoorMenu.pSoldier = pSoldier; gOpenDoorMenu.pStructure = pStructure; gOpenDoorMenu.ubDirection = ubDirection; gOpenDoorMenu.fClosingDoor = fClosingDoor; // OK, Determine position... // Center on guy // Locate to guy first..... LocateSoldier( pSoldier->ubID, FALSE ); GetSoldierAnimDims( pSoldier, &sHeight, &sWidth ); GetSoldierScreenPos( pSoldier, &sScreenX, &sScreenY ); gOpenDoorMenu.sX = sScreenX - ( ( BUTTON_PANEL_WIDTH - sWidth ) / 2 ); gOpenDoorMenu.sY = sScreenY - ( ( BUTTON_PANEL_HEIGHT - sHeight ) / 2 ); // Alrighty, cancel lock UI if we havn't done so already UnSetUIBusy( pSoldier->ubID ); // OK, CHECK FOR BOUNDARIES! if ( ( gOpenDoorMenu.sX + BUTTON_PANEL_WIDTH ) > SCREEN_WIDTH ) { gOpenDoorMenu.sX = ( SCREEN_WIDTH - BUTTON_PANEL_WIDTH ); } if ( ( gOpenDoorMenu.sY + BUTTON_PANEL_HEIGHT ) > gsVIEWPORT_WINDOW_END_Y ) { gOpenDoorMenu.sY = ( gsVIEWPORT_WINDOW_END_Y - BUTTON_PANEL_HEIGHT ); } if ( gOpenDoorMenu.sX < 0 ) { gOpenDoorMenu.sX = 0; } if ( gOpenDoorMenu.sY < 0 ) { gOpenDoorMenu.sY = 0; } gOpenDoorMenu.fMenuHandled = FALSE; guiPendingOverrideEvent = OP_OPENDOORMENU; HandleTacticalUI( ); PopupDoorOpenMenu( fClosingDoor ); return( TRUE ); } void PopupDoorOpenMenu( BOOLEAN fClosingDoor ) { INT32 iMenuAnchorX, iMenuAnchorY; CHAR16 zDisp[ 100 ]; iMenuAnchorX = gOpenDoorMenu.sX; iMenuAnchorY = gOpenDoorMenu.sY; // Blit background! //BltVideoObjectFromIndex( FRAME_BUFFER, guiBUTTONBORDER, 0, iMenuAnchorX, iMenuAnchorY, VO_BLT_SRCTRANSPARENCY, NULL ); iMenuAnchorX = gOpenDoorMenu.sX + 9; iMenuAnchorY = gOpenDoorMenu.sY + 8; // Create mouse region over all area to facilitate clicking to end MSYS_DefineRegion( &gMenuOverlayRegion, 0, 0 ,SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST-1, CURSOR_NORMAL, MSYS_NO_CALLBACK, DoorMenuBackregionCallback ); // Add region MSYS_AddRegion( &gMenuOverlayRegion); iActionIcons[ USE_KEYRING_ICON ] = QuickCreateButton( iIconImages[ USE_KEYRING_IMAGES ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ USE_KEYRING_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ USE_KEYRING_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ USE_KEYRING_ICON ], APBPConstants[AP_UNLOCK_DOOR] ); } SetButtonFastHelpText( iActionIcons[ USE_KEYRING_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_UNLOCK_DOOR], APBPConstants[BP_UNLOCK_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) { DisableButton( iActionIcons[ USE_KEYRING_ICON ] ); } // Greyout if no keys found... if ( !SoldierHasKey( gOpenDoorMenu.pSoldier, ANYKEY ) ) { DisableButton( iActionIcons[ USE_KEYRING_ICON ] ); } iActionIcons[ USE_CROWBAR_ICON ] = QuickCreateButton( iIconImages[ CROWBAR_DOOR_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ USE_CROWBAR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ USE_CROWBAR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ USE_CROWBAR_ICON ], APBPConstants[AP_USE_CROWBAR] ); } SetButtonFastHelpText( iActionIcons[ USE_CROWBAR_ICON ], zDisp ); // Greyout if no crowbar found... if ( FindUsableCrowbar ( gOpenDoorMenu.pSoldier ) == NO_SLOT || fClosingDoor ) { DisableButton( iActionIcons[ USE_CROWBAR_ICON ] ); } if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_USE_CROWBAR], APBPConstants[BP_USE_CROWBAR], FALSE ) ) { DisableButton( iActionIcons[ USE_CROWBAR_ICON ] ); } iActionIcons[ LOCKPICK_DOOR_ICON ] = QuickCreateButton( iIconImages[ LOCKPICK_DOOR_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ LOCKPICK_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ LOCKPICK_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ LOCKPICK_DOOR_ICON ], GetAPsToPicklock( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ LOCKPICK_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToPicklock( gOpenDoorMenu.pSoldier ), APBPConstants[BP_PICKLOCK], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ LOCKPICK_DOOR_ICON ] ); } // Grayout if no lockpick found.... if ( FindLocksmithKit( gOpenDoorMenu.pSoldier ) == NO_SLOT ) { DisableButton( iActionIcons[ LOCKPICK_DOOR_ICON ] ); } iActionIcons[ EXPLOSIVE_DOOR_ICON ] = QuickCreateButton( iIconImages[ EXPLOSIVE_DOOR_IMAGES ], (INT16)(iMenuAnchorX + 40 ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ EXPLOSIVE_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ EXPLOSIVE_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ EXPLOSIVE_DOOR_ICON ], GetAPsToBombDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ EXPLOSIVE_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToBombDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_EXPLODE_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ EXPLOSIVE_DOOR_ICON ] ); } // Grayout if no lock explosive found.... // For no use bomb1 until we get a special item for this if ( FindLockBomb ( gOpenDoorMenu.pSoldier ) == NO_SLOT ) { DisableButton( iActionIcons[ EXPLOSIVE_DOOR_ICON ] ); } iActionIcons[ OPEN_DOOR_ICON ] = QuickCreateButton( iIconImages[ OPEN_DOOR_IMAGES ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ OPEN_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if ( fClosingDoor ) { if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ CANCEL_ICON + 1 ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ CANCEL_ICON + 1 ], GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } } else { if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ OPEN_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ OPEN_DOOR_ICON ], GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } } SetButtonFastHelpText( iActionIcons[ OPEN_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_OPEN_DOOR], FALSE ) ) // SANDRO { DisableButton( iActionIcons[ OPEN_DOOR_ICON ] ); } // Create button based on what is in our hands at the moment! iActionIcons[ EXAMINE_DOOR_ICON ] = QuickCreateButton( iIconImages[ EXAMINE_DOOR_IMAGES ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ EXAMINE_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ EXAMINE_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ EXAMINE_DOOR_ICON ], APBPConstants[AP_EXAMINE_DOOR] ); } SetButtonFastHelpText( iActionIcons[ EXAMINE_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_EXAMINE_DOOR], APBPConstants[BP_EXAMINE_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) { DisableButton( iActionIcons[ EXAMINE_DOOR_ICON ] ); } iActionIcons[ BOOT_DOOR_ICON ] = QuickCreateButton( iIconImages[ BOOT_DOOR_IMAGES ], (INT16)(iMenuAnchorX ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ BOOT_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ BOOT_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ BOOT_DOOR_ICON ], APBPConstants[AP_BOOT_DOOR] ); } SetButtonFastHelpText( iActionIcons[ BOOT_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_BOOT_DOOR], APBPConstants[BP_BOOT_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) { DisableButton( iActionIcons[ BOOT_DOOR_ICON ] ); } iActionIcons[ UNTRAP_DOOR_ICON ] = QuickCreateButton( iIconImages[ UNTRAP_DOOR_ICON ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY + 40 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ UNTRAP_DOOR_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } if (!(gTacticalStatus.uiFlags & TURNBASED) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { swprintf( zDisp, pTacticalPopupButtonStrings[ UNTRAP_DOOR_ICON ] ); } else { swprintf( zDisp, L"%s ( %d )", pTacticalPopupButtonStrings[ UNTRAP_DOOR_ICON ], GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ) ); // SANDRO } SetButtonFastHelpText( iActionIcons[ UNTRAP_DOOR_ICON ], zDisp ); if ( !EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_UNTRAP_DOOR], FALSE ) || fClosingDoor || AM_AN_EPC( gOpenDoorMenu.pSoldier ) ) // SANDRO { DisableButton( iActionIcons[ UNTRAP_DOOR_ICON ] ); } iActionIcons[ CANCEL_ICON ] = QuickCreateButton( iIconImages[ CANCEL_IMAGES ], (INT16)(iMenuAnchorX + 20 ), (INT16)(iMenuAnchorY + 20 ), BUTTON_NO_TOGGLE, MSYS_PRIORITY_HIGHEST - 1, DEFAULT_MOVE_CALLBACK, (GUI_CALLBACK)BtnDoorMenuCallback ); if ( iActionIcons[ CANCEL_ICON ] == -1 ) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Cannot create Interface button" ); return; } SetButtonFastHelpText( iActionIcons[ CANCEL_ICON ], pTacticalPopupButtonStrings[ CANCEL_ICON ] ); //LockTacticalInterface( ); gfInOpenDoorMenu = TRUE; // Ignore scrolling gfIgnoreScrolling = TRUE; } void PopDownOpenDoorMenu( ) { if ( gfInOpenDoorMenu ) { UnLockPauseState(); UnPauseGame(); // UnPause timers as well.... PauseTime( FALSE ); RemoveButton( iActionIcons[ USE_KEYRING_ICON ] ); RemoveButton( iActionIcons[ USE_CROWBAR_ICON ] ); RemoveButton( iActionIcons[ LOCKPICK_DOOR_ICON ] ); RemoveButton( iActionIcons[ EXPLOSIVE_DOOR_ICON ] ); RemoveButton( iActionIcons[ OPEN_DOOR_ICON ] ); RemoveButton( iActionIcons[ EXAMINE_DOOR_ICON ] ); RemoveButton( iActionIcons[ BOOT_DOOR_ICON ] ); RemoveButton( iActionIcons[ UNTRAP_DOOR_ICON ] ); RemoveButton( iActionIcons[ CANCEL_ICON ] ); // Turn off Ignore scrolling gfIgnoreScrolling = FALSE; // Rerender world SetRenderFlags( RENDER_FLAG_FULL ); fInterfacePanelDirty = DIRTYLEVEL2; //UnLockTacticalInterface( ); MSYS_RemoveRegion( &gMenuOverlayRegion); } gfInOpenDoorMenu = FALSE; } void RenderOpenDoorMenu( ) { if ( gfInOpenDoorMenu ) { BltVideoObjectFromIndex( FRAME_BUFFER, guiBUTTONBORDER, 0, gOpenDoorMenu.sX, gOpenDoorMenu.sY, VO_BLT_SRCTRANSPARENCY, NULL ); // Mark buttons dirty! MarkAButtonDirty( iActionIcons[ USE_KEYRING_ICON ] ); MarkAButtonDirty( iActionIcons[ USE_CROWBAR_ICON ] ); MarkAButtonDirty( iActionIcons[ LOCKPICK_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ EXPLOSIVE_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ OPEN_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ EXAMINE_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ BOOT_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ UNTRAP_DOOR_ICON ] ); MarkAButtonDirty( iActionIcons[ CANCEL_ICON ] ); RenderButtons( ); // if game is paused, then render paused game text RenderPausedGameBox( ); InvalidateRegion( gOpenDoorMenu.sX, gOpenDoorMenu.sY, gOpenDoorMenu.sX + BUTTON_PANEL_WIDTH, gOpenDoorMenu.sY + BUTTON_PANEL_HEIGHT ); } } void CancelOpenDoorMenu( ) { // Signal end of event gOpenDoorMenu.fMenuHandled = 2; } void BtnDoorMenuCallback(GUI_BUTTON *btn,INT32 reason) { INT32 uiBtnID; if ( reason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { btn->uiFlags |= BUTTON_CLICKED_ON; uiBtnID = btn->IDNum; // Popdown menu gOpenDoorMenu.fMenuHandled = TRUE; if ( uiBtnID == iActionIcons[ CANCEL_ICON ] ) { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; #ifdef JA2UB //Handle someone trying to open the door in the tunnel gate` HandlePlayerSayingQuoteWhenFailingToOpenGateInTunnel( gOpenDoorMenu.pSoldier, FALSE ); //Ja25 UB #endif } // Switch on command.... if ( uiBtnID == iActionIcons[ OPEN_DOOR_ICON ] ) { #ifdef JA2UB //Handle someone trying to open the door in the tunnel gate` if( HandlePlayerSayingQuoteWhenFailingToOpenGateInTunnel( gOpenDoorMenu.pSoldier, TRUE ) ) //Ja25 UB { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } else { // Open door normally... // Check APs if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_OPEN_DOOR], APBPConstants[BP_OPEN_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); if ( gOpenDoorMenu.fClosingDoor ) { gOpenDoorMenu.pSoldier->ChangeSoldierState( GetAnimStateForInteraction( gOpenDoorMenu.pSoldier, TRUE, CLOSE_DOOR ), 0 , FALSE ); } else { InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_OPEN ); } } else { // OK, set cancel code! gOpenDoorMenu.fMenuHandled = 2; } } #else // Open door normally... // Check APs // SANDRO - changed APs for opening dorrs calc if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToOpenDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_OPEN_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); if ( gOpenDoorMenu.fClosingDoor ) { gOpenDoorMenu.pSoldier->ChangeSoldierState( GetAnimStateForInteraction( gOpenDoorMenu.pSoldier, TRUE, CLOSE_DOOR ), 0 , FALSE ); } else { InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_OPEN ); } } else { // OK, set cancel code! gOpenDoorMenu.fMenuHandled = 2; } #endif } if ( uiBtnID == iActionIcons[ BOOT_DOOR_ICON ] ) { // Boot door if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_BOOT_DOOR], APBPConstants[BP_BOOT_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_FORCE ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } if ( uiBtnID == iActionIcons[ USE_KEYRING_ICON ] ) { // Unlock door if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_UNLOCK_DOOR], APBPConstants[BP_UNLOCK_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_UNLOCK ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } if ( uiBtnID == iActionIcons[ LOCKPICK_DOOR_ICON ] ) { // Lockpick if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToPicklock( gOpenDoorMenu.pSoldier ), APBPConstants[BP_PICKLOCK], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_LOCKPICK ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } if ( uiBtnID == iActionIcons[ EXAMINE_DOOR_ICON ] ) { // Lockpick if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_EXAMINE_DOOR], APBPConstants[BP_EXAMINE_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_EXAMINE ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } if ( uiBtnID == iActionIcons[ EXPLOSIVE_DOOR_ICON ] ) { #ifdef JA2UB //Handle someone trying to open the door in the tunnel gate` if( HandlePlayerSayingQuoteWhenFailingToOpenGateInTunnel( gOpenDoorMenu.pSoldier, TRUE ) ) //Ja25 UB { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } else { // Explode if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_EXPLODE_DOOR], APBPConstants[BP_EXPLODE_DOOR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_EXPLODE ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } #else // Explode if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToBombDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_EXPLODE_DOOR], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_EXPLODE ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } #endif } if ( uiBtnID == iActionIcons[ UNTRAP_DOOR_ICON ] ) { // Explode if ( EnoughPoints( gOpenDoorMenu.pSoldier, GetAPsToUntrapDoor( gOpenDoorMenu.pSoldier ), APBPConstants[BP_UNTRAP_DOOR], FALSE ) ) // SANDRO { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_UNTRAP ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } if ( uiBtnID == iActionIcons[ USE_CROWBAR_ICON ] ) { #ifdef JA2UB //Handle someone trying to open the door in the tunnel gate` if( HandlePlayerSayingQuoteWhenFailingToOpenGateInTunnel( gOpenDoorMenu.pSoldier, TRUE ) ) //JA25 UB { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } else { // Explode if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_USE_CROWBAR], APBPConstants[BP_USE_CROWBAR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_CROWBAR ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } } #else // Explode if ( EnoughPoints( gOpenDoorMenu.pSoldier, APBPConstants[AP_USE_CROWBAR], APBPConstants[BP_USE_CROWBAR], FALSE ) ) { // Set UI SetUIBusy( (UINT8)gOpenDoorMenu.pSoldier->ubID ); InteractWithClosedDoor( gOpenDoorMenu.pSoldier, HANDLE_DOOR_CROWBAR ); } else { // OK, set cancle code! gOpenDoorMenu.fMenuHandled = 2; } #endif } HandleOpenDoorMenu( ); } } BOOLEAN HandleOpenDoorMenu( ) { if ( gOpenDoorMenu.fMenuHandled ) { PopDownOpenDoorMenu( ); return( gOpenDoorMenu.fMenuHandled ); } return( FALSE ); } void RenderUIMessage( VIDEO_OVERLAY *pBlitter ) { // Shade area first... ShadowVideoSurfaceRect( pBlitter->uiDestBuff, pBlitter->sX, pBlitter->sY, pBlitter->sX + gusUIMessageWidth - 2, pBlitter->sY + gusUIMessageHeight - 2 ); RenderMercPopUpBoxFromIndex( iUIMessageBox, pBlitter->sX, pBlitter->sY, pBlitter->uiDestBuff ); InvalidateRegion( pBlitter->sX, pBlitter->sY, pBlitter->sX + gusUIMessageWidth, pBlitter->sY + gusUIMessageHeight ); } void InternalBeginUIMessage( BOOLEAN fUseSkullIcon, STR16 pFontString, ... ) { va_list argptr; VIDEO_OVERLAY_DESC VideoOverlayDesc; CHAR16 MsgString[512]; va_start(argptr, pFontString); // Set up variable argument pointer vswprintf(MsgString, pFontString, argptr); // process gprintf string (get output str) va_end(argptr); guiUIMessageTime = GetJA2Clock( ); guiUIMessageTimeDelay = CalcUIMessageDuration(MsgString); // Override it! OverrideMercPopupBox( &gpUIMessageOverrideMercBox ); //SetPrepareMercPopupFlags( MERC_POPUP_PREPARE_FLAGS_TRANS_BACK | MERC_POPUP_PREPARE_FLAGS_MARGINS ); if ( fUseSkullIcon ) { SetPrepareMercPopupFlags( MERC_POPUP_PREPARE_FLAGS_MARGINS | MERC_POPUP_PREPARE_FLAGS_SKULLICON ); } else { SetPrepareMercPopupFlags( MERC_POPUP_PREPARE_FLAGS_MARGINS | MERC_POPUP_PREPARE_FLAGS_STOPICON ); } // Prepare text box iUIMessageBox = PrepareMercPopupBox( iUIMessageBox ,BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, MsgString, 200, 10, 0, 0, &gusUIMessageWidth, &gusUIMessageHeight ); // Set it back! ResetOverrideMercPopupBox( ); if ( giUIMessageOverlay != -1 ) { RemoveVideoOverlay( giUIMessageOverlay ); giUIMessageOverlay = -1; } if ( giUIMessageOverlay == -1 ) { memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) ); // Set Overlay VideoOverlayDesc.sLeft = ( SCREEN_WIDTH - gusUIMessageWidth ) / 2; VideoOverlayDesc.sTop = 150; VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusUIMessageWidth; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusUIMessageHeight; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderUIMessage; giUIMessageOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); } gfUseSkullIconMessage = fUseSkullIcon; } void BeginUIMessage( STR16 pFontString, ... ) { va_list argptr; CHAR16 MsgString[512]; va_start(argptr, pFontString); // Set up variable argument pointer vswprintf(MsgString, pFontString, argptr); // process gprintf string (get output str) va_end(argptr); InternalBeginUIMessage( FALSE, MsgString ); } void BeginMapUIMessage( UINT8 ubPosition, STR16 pFontString, ... ) { va_list argptr; VIDEO_OVERLAY_DESC VideoOverlayDesc; CHAR16 MsgString[512]; memset( &VideoOverlayDesc, 0, sizeof( VideoOverlayDesc ) ); va_start(argptr, pFontString); // Set up variable argument pointer vswprintf(MsgString, pFontString, argptr); // process gprintf string (get output str) va_end(argptr); guiUIMessageTime = GetJA2Clock( ); guiUIMessageTimeDelay = CalcUIMessageDuration(MsgString); // Override it! OverrideMercPopupBox( &gpUIMessageOverrideMercBox ); SetPrepareMercPopupFlags( MERC_POPUP_PREPARE_FLAGS_TRANS_BACK | MERC_POPUP_PREPARE_FLAGS_MARGINS ); // Prepare text box iUIMessageBox = PrepareMercPopupBox( iUIMessageBox ,BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, MsgString, 200, 10, 0, 0, &gusUIMessageWidth, &gusUIMessageHeight ); // Set it back! ResetOverrideMercPopupBox( ); if ( giUIMessageOverlay == -1 ) { // WDS - bug fix: VideoOverlayDesc must be initialized! - 07/16/2007 memset( &VideoOverlayDesc, 0, sizeof( VIDEO_OVERLAY_DESC ) ); // Set Overlay VideoOverlayDesc.sLeft = 20 + MAP_VIEW_START_X + ( MAP_VIEW_WIDTH - gusUIMessageWidth ) / 2; VideoOverlayDesc.sTop = MAP_VIEW_START_Y + ( MAP_VIEW_HEIGHT - gusUIMessageHeight ) / 2; if( ubPosition == MSG_MAP_UI_POSITION_UPPER ) { VideoOverlayDesc.sTop -= 100; } else if ( ubPosition == MSG_MAP_UI_POSITION_LOWER ) { VideoOverlayDesc.sTop += 100; } VideoOverlayDesc.sRight = VideoOverlayDesc.sLeft + gusUIMessageWidth; VideoOverlayDesc.sBottom = VideoOverlayDesc.sTop + gusUIMessageHeight; VideoOverlayDesc.sX = VideoOverlayDesc.sLeft; VideoOverlayDesc.sY = VideoOverlayDesc.sTop; VideoOverlayDesc.BltCallback = RenderUIMessage; giUIMessageOverlay = RegisterVideoOverlay( 0, &VideoOverlayDesc ); } } void EndUIMessage( ) { UINT32 uiClock = GetJA2Clock(); if ( giUIMessageOverlay != -1 ) { if ( gfUseSkullIconMessage ) { if ( ( uiClock - guiUIMessageTime ) < 300 ) { return; } } // DebugMsg( TOPIC_JA2, DBG_LEVEL_0, String( "Removing Overlay message") ); RemoveVideoOverlay( giUIMessageOverlay ); // Remove popup as well.... if ( iUIMessageBox != -1 ) { RemoveMercPopupBoxFromIndex( iUIMessageBox ); iUIMessageBox = -1; } giUIMessageOverlay = -1; } //iUIMessageBox = -1; } #define PLAYER_TEAM_TIMER_INTTERUPT_GRACE ( 15000 / PLAYER_TEAM_TIMER_SEC_PER_TICKS ) #define PLAYER_TEAM_TIMER_GRACE_PERIOD 1000 //#define PLAYER_TEAM_TIMER_SEC_PER_TICKS 100 int PLAYER_TEAM_TIMER_SEC_PER_TICKS = 100;//hayden #define PLAYER_TEAM_TIMER_TICKS_PER_OK_MERC ( 15000 / PLAYER_TEAM_TIMER_SEC_PER_TICKS ) #define PLAYER_TEAM_TIMER_TICKS_PER_NOTOK_MERC ( 5000 / PLAYER_TEAM_TIMER_SEC_PER_TICKS ) #define PLAYER_TEAM_TIMER_TICKS_FROM_END_TO_START_BEEP ( (5000 / PLAYER_TEAM_TIMER_SEC_PER_TICKS)*1.15 ) #define PLAYER_TEAM_TIMER_TIME_BETWEEN_BEEPS ( 500 ) #define PLAYER_TEAM_TIMER_TICKS_PER_ENEMY ( 2000 / PLAYER_TEAM_TIMER_SEC_PER_TICKS ) BOOLEAN AddTopMessage( UINT8 ubType, STR16 pzString ) { UINT32 cnt; BOOLEAN fFound = FALSE; // Set time of last update gTopMessage.uiTimeOfLastUpdate = GetJA2Clock( ); // Set flag to animate down... //gTopMessage.bAnimate = -1; //gTopMessage.bYPos = 2; gTopMessage.bAnimate = 0; gTopMessage.bYPos = 20; gTopMessage.fCreated = TRUE; fFound = TRUE; cnt = 0; // WANNE: Disabled AI count on turnbar, because it shows different count on clients /* if(is_networked && gTacticalStatus.ubCurrentTeam == 1 && ubType == COMPUTER_TURN_MESSAGE){ //add ai count to turn bar - haydent swprintf( pzString, MPClientMessage[80], NumEnemyInSector()); } */ if ( fFound ) { gTopMessage.bCurrentMessage = (INT8)cnt; gTacticalStatus.ubTopMessageType = ubType; gTacticalStatus.fInTopMessage = TRUE; // Copy string wcsncpy( gTacticalStatus.zTopMessageString, pzString, 19 ); CreateTopMessage( gTopMessage.uiSurface, ubType, pzString ); return( TRUE ); } return( FALSE ); } void CreateTopMessage( UINT32 uiSurface, UINT8 ubType, STR16 psString ) { UINT32 uiBAR, uiPLAYERBAR = 0, uiINTBAR = 0; VOBJECT_DESC VObjectDesc; INT16 sX, sY; INT32 cnt2; INT16 sBarX = 0; UINT32 uiBarToUseInUpDate=0; BOOLEAN fDoLimitBar = FALSE; FLOAT dNumStepsPerEnemy, dLength, dCurSize; INT16 iProgBarLength; STR fn; memset( &VObjectDesc, 0, sizeof( VObjectDesc ) ); VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE; if (iResolution >= _640x480 && iResolution < _800x600) { iProgBarLength = 640 - 13; if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\rect_Thin.sti"; else fn = "INTERFACE\\rect.sti"; } else if (iResolution < _1024x768) { iProgBarLength = 800 - 13; if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\rect_800x600Thin.sti"; else fn = "INTERFACE\\rect_800x600.sti"; } else { iProgBarLength = 1024 - 13; if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\rect_1024x768Thin.sti"; else fn = "INTERFACE\\rect_1024x768.sti"; } FilenameForBPP(fn, VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &uiBAR ) ) { sprintf(fn, "Missing %s", fn); AssertMsg(0, fn ); } if (iResolution >= _640x480 && iResolution < _800x600) { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebargreen_Thin.sti"; else fn = "INTERFACE\\timebargreen.sti"; } else if (iResolution < _1024x768) { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebargreen_800x600Thin.sti"; else fn = "INTERFACE\\timebargreen_800x600.sti"; } else { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebargreen_1024x768Thin.sti"; else fn = "INTERFACE\\timebargreen_1024x768.sti"; } FilenameForBPP(fn, VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &uiPLAYERBAR ) ) { sprintf(fn, "Missing %s", fn); AssertMsg(0, fn ); } if (iResolution >= _640x480 && iResolution < _800x600) { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebaryellow_Thin.sti"; else fn = "INTERFACE\\timebaryellow.sti"; } else if (iResolution < _1024x768) { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebaryellow_800x600Thin.sti"; else fn = "INTERFACE\\timebaryellow_800x600.sti"; } else { if (gGameExternalOptions.fSmallSizeProgressbar) fn = "INTERFACE\\timebaryellow_1024x768Thin.sti"; else fn = "INTERFACE\\timebaryellow_1024x768.sti"; } FilenameForBPP(fn, VObjectDesc.ImageFile); if( !AddVideoObject( &VObjectDesc, &uiINTBAR ) ) { sprintf(fn, "Missing %s", fn); AssertMsg(0, fn ); } SetFontDestBuffer( uiSurface , 0, 0, SCREEN_WIDTH , HEIGHT_PROGRESSBAR, FALSE ); SetFont( TINYFONT1 ); switch( ubType ) { case COMPUTER_TURN_MESSAGE: case COMPUTER_INTERRUPT_MESSAGE: case MILITIA_INTERRUPT_MESSAGE: case AIR_RAID_TURN_MESSAGE: // Render rect into surface BltVideoObjectFromIndex( uiSurface, uiBAR, 0, xResOffset, 0, VO_BLT_SRCTRANSPARENCY, NULL ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); uiBarToUseInUpDate = uiBAR; fDoLimitBar = TRUE; break; case PLAYER_INTERRUPT_MESSAGE: // Render rect into surface BltVideoObjectFromIndex( uiSurface, uiINTBAR, 0, xResOffset, 0, VO_BLT_SRCTRANSPARENCY, NULL ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); SetFontShadow( NO_SHADOW ); uiBarToUseInUpDate = uiINTBAR; break; case PLAYER_TURN_MESSAGE: // Render rect into surface BltVideoObjectFromIndex( uiSurface, uiPLAYERBAR, 0, xResOffset, 0, VO_BLT_SRCTRANSPARENCY, NULL ); SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_WHITE ); SetFontShadow( NO_SHADOW ); uiBarToUseInUpDate = uiPLAYERBAR; break; } if ( gGameOptions.fTurnTimeLimit ) { if ( ubType == PLAYER_TURN_MESSAGE || ubType == PLAYER_INTERRUPT_MESSAGE ) { fDoLimitBar = TRUE; } } if ( fDoLimitBar ) { dNumStepsPerEnemy = (FLOAT)( (FLOAT)iProgBarLength / (FLOAT)gTacticalStatus.usTactialTurnLimitMax ); // Render end peice sBarX = (SCREEN_WIDTH - xResSize) / 2 + 5; BltVideoObjectFromIndex( uiSurface, uiBarToUseInUpDate, 1, sBarX, PROG_BAR_START_Y, VO_BLT_SRCTRANSPARENCY, NULL ); // Determine Length dLength = ( gTacticalStatus.usTactialTurnLimitCounter ) * dNumStepsPerEnemy; dCurSize = 0; cnt2 = 0; while( dCurSize < dLength ) { sBarX++; // Check sBarX, ( just as a precaution ) if ( sBarX > SCREEN_WIDTH - 1 ) { break; } BltVideoObjectFromIndex( uiSurface, uiBarToUseInUpDate, (INT16)( 2 + cnt2 ), sBarX, PROG_BAR_START_Y, VO_BLT_SRCTRANSPARENCY, NULL ); dCurSize++; cnt2++; if ( cnt2 == 10 ) { cnt2 = 0; } } // Do end... if ( gTacticalStatus.usTactialTurnLimitCounter == gTacticalStatus.usTactialTurnLimitMax ) { sBarX++; BltVideoObjectFromIndex( uiSurface, uiBarToUseInUpDate, (INT16)( 2 + cnt2 ), sBarX, PROG_BAR_START_Y, VO_BLT_SRCTRANSPARENCY, NULL ); sBarX++; BltVideoObjectFromIndex( uiSurface, uiBarToUseInUpDate, (INT16)( 12 ), sBarX, PROG_BAR_START_Y, VO_BLT_SRCTRANSPARENCY, NULL ); } } // Delete rect DeleteVideoObjectFromIndex( uiBAR ); DeleteVideoObjectFromIndex( uiINTBAR ); DeleteVideoObjectFromIndex( uiPLAYERBAR ); // Draw text.... if(gGameExternalOptions.fSmallSizeProgressbar) FindFontCenterCoordinates( SCREEN_WIDTH/2, 2, 1, 1, psString, TINYFONT1, &sX, &sY ); else FindFontCenterCoordinates( SCREEN_WIDTH/2, 7, 1, 1, psString, TINYFONT1, &sX, &sY ); mprintf( sX, sY, psString ); // Change back... SetFontDestBuffer( FRAME_BUFFER , 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE ); // Done! SetFontShadow( DEFAULT_SHADOW ); gfTopMessageDirty = TRUE; } void TurnExpiredCallBack( UINT8 bExitValue ) { // End turn... UIHandleEndTurn( NULL ); } void CheckForAndHandleEndPlayerTimeLimit( ) { if ( gTacticalStatus.fInTopMessage ) { if ( gGameOptions.fTurnTimeLimit ) { if ( gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE || gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE ) { if ( gTacticalStatus.usTactialTurnLimitCounter == ( gTacticalStatus.usTactialTurnLimitMax - 1 ) ) { // ATE: increase this so that we don't go into here again... gTacticalStatus.usTactialTurnLimitCounter++; // OK, set message that time limit has expired.... //DoMessageBox( MSG_BOX_BASIC_STYLE, L"Turn has Expired!", GAME_SCREEN, ( UINT8 )MSG_BOX_FLAG_OK, TurnExpiredCallBack, NULL ); // End turn... UIHandleEndTurn( NULL ); } } } } } void HandleTopMessages( ) { //UINT32 uiTime; blt_vs_fx BltFx; // OK, is out current count > 0 ? if ( gTacticalStatus.fInTopMessage ) { //gfTopMessageDirty = TRUE; // ATE: If we are told to go into top message, but we have not // initialized it yet... // This is mostly for loading saved games..... if ( !gTopMessage.fCreated ) { gfTopMessageDirty = TRUE; AddTopMessage( gTacticalStatus.ubTopMessageType, gTacticalStatus.zTopMessageString ); } if ( gTacticalStatus.ubTopMessageType == COMPUTER_TURN_MESSAGE || gTacticalStatus.ubTopMessageType == COMPUTER_INTERRUPT_MESSAGE || gTacticalStatus.ubTopMessageType == MILITIA_INTERRUPT_MESSAGE || gTacticalStatus.ubTopMessageType == AIR_RAID_TURN_MESSAGE ) { // OK, update timer..... if ( TIMECOUNTERDONE( giTimerTeamTurnUpdate, PLAYER_TEAM_TIMER_SEC_PER_TICKS ) ) { RESETTIMECOUNTER( giTimerTeamTurnUpdate, PLAYER_TEAM_TIMER_SEC_PER_TICKS ); if(!is_networked)//hayden - stop clients from updating enemy progress bar... //could have another param in here when get coop going { // Update counter.... if ( gTacticalStatus.usTactialTurnLimitCounter < gTacticalStatus.usTactialTurnLimitMax ) { gTacticalStatus.usTactialTurnLimitCounter++; } // Check if we have reach limit... if ( gTacticalStatus.usTactialTurnLimitCounter >= ( ( gubProgCurEnemy ) * PLAYER_TEAM_TIMER_TICKS_PER_ENEMY ) ) { gTacticalStatus.usTactialTurnLimitCounter = ( ( gubProgCurEnemy ) * PLAYER_TEAM_TIMER_TICKS_PER_ENEMY ); } } CreateTopMessage( gTopMessage.uiSurface, gTacticalStatus.ubTopMessageType, gTacticalStatus.zTopMessageString ); } } else if ( gGameOptions.fTurnTimeLimit ) { if ( gTacticalStatus.ubTopMessageType == PLAYER_TURN_MESSAGE || gTacticalStatus.ubTopMessageType == PLAYER_INTERRUPT_MESSAGE ) { if ( !gfUserTurnRegionActive && !AreWeInAUIMenu() ) { // Check Grace period... if ( ( GetJA2Clock( ) - gTacticalStatus.uiTactialTurnLimitClock ) > PLAYER_TEAM_TIMER_GRACE_PERIOD ) { gTacticalStatus.uiTactialTurnLimitClock = 0; if ( TIMECOUNTERDONE( giTimerTeamTurnUpdate, PLAYER_TEAM_TIMER_SEC_PER_TICKS ) ) { RESETTIMECOUNTER( giTimerTeamTurnUpdate, PLAYER_TEAM_TIMER_SEC_PER_TICKS ); if ( gTacticalStatus.fTactialTurnLimitStartedBeep ) { if ( ( GetJA2Clock( ) - gTopMessage.uiTimeSinceLastBeep ) > PLAYER_TEAM_TIMER_TIME_BETWEEN_BEEPS ) { gTopMessage.uiTimeSinceLastBeep = GetJA2Clock( ); // Start sample.... PlayJA2SampleFromFile( "SOUNDS\\TURN_NEAR_END.WAV", RATE_11025, HIGHVOLUME, 1 , MIDDLEPAN ); } } // OK, have we gone past the time to if ( !gTacticalStatus.fTactialTurnLimitStartedBeep && ( gTacticalStatus.usTactialTurnLimitMax - gTacticalStatus.usTactialTurnLimitCounter ) < PLAYER_TEAM_TIMER_TICKS_FROM_END_TO_START_BEEP ) { gTacticalStatus.fTactialTurnLimitStartedBeep = TRUE; gTopMessage.uiTimeSinceLastBeep = GetJA2Clock( ); } // Update counter.... if ( gTacticalStatus.usTactialTurnLimitCounter < gTacticalStatus.usTactialTurnLimitMax ) { gTacticalStatus.usTactialTurnLimitCounter++; } CreateTopMessage( gTopMessage.uiSurface, gTacticalStatus.ubTopMessageType, gTacticalStatus.zTopMessageString ); // Have we reached max? if ( gTacticalStatus.usTactialTurnLimitCounter == ( gTacticalStatus.usTactialTurnLimitMax - 1) ) { // IF we are not in lock ui mode.... CheckForAndHandleEndPlayerTimeLimit( ); } } } } } } // Set redner viewport value //* ddd gsVIEWPORT_WINDOW_START_Y = 20; gsVIEWPORT_WINDOW_START_Y = HEIGHT_PROGRESSBAR; // Check if we have scrolled... if ( gTopMessage.sWorldRenderX != gsRenderCenterX || gTopMessage.sWorldRenderY != gsRenderCenterY ) { gfTopMessageDirty = TRUE; } if ( gfTopMessageDirty ) { gTopMessage.sWorldRenderX = gsRenderCenterX; gTopMessage.sWorldRenderY = gsRenderCenterY; // Redner! BltFx.SrcRect.iLeft = 0; //* ddd BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; if(gGameExternalOptions.fSmallSizeProgressbar) BltFx.SrcRect.iTop = 0; else BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; BltFx.SrcRect.iRight = SCREEN_WIDTH ; //*ddd BltFx.SrcRect.iBottom = 20; BltFx.SrcRect.iBottom = HEIGHT_PROGRESSBAR; BltVideoSurface( FRAME_BUFFER, gTopMessage.uiSurface, 0, 0, 0, VS_BLT_SRCSUBRECT, &BltFx ); // Save to save buffer.... BltFx.SrcRect.iLeft = 0; //* ddd BltFx.SrcRect.iTop = 0; if(gGameExternalOptions.fSmallSizeProgressbar) BltFx.SrcRect.iTop = 0; else BltFx.SrcRect.iTop = 20 - gTopMessage.bYPos; BltFx.SrcRect.iRight = SCREEN_WIDTH; //*ddd BltFx.SrcRect.iBottom = 20; BltFx.SrcRect.iBottom = HEIGHT_PROGRESSBAR; BltVideoSurface( guiSAVEBUFFER, FRAME_BUFFER, 0, 0, 0, VS_BLT_SRCSUBRECT, &BltFx ); //*ddd InvalidateRegion( 0, 0, SCREEN_WIDTH, 20 ); InvalidateRegion( 0, 0, SCREEN_WIDTH, HEIGHT_PROGRESSBAR ); gfTopMessageDirty = FALSE; } } else { // Set redner viewport value gsVIEWPORT_WINDOW_START_Y = 0; } } void EndTopMessage( ) { // blt_vs_fx BltFx; // OK, end the topmost message! if ( gTacticalStatus.fInTopMessage ) { // Are we the last? //if ( gTopMessage.bCurrentMessage == 1 ) { // We are.... // Re-render our strip and then copy to the save buffer... gsVIEWPORT_WINDOW_START_Y = 0; gTacticalStatus.fInTopMessage = FALSE; SetRenderFlags( RENDER_FLAG_FULL ); //RenderStaticWorldRect( 0, 0, 640, 20, TRUE ); //gsVIEWPORT_WINDOW_START_Y = 20; // Copy into save buffer... //BltFx.SrcRect.iLeft = 0; //BltFx.SrcRect.iTop = 0; //BltFx.SrcRect.iRight = 640; //BltFx.SrcRect.iBottom = 20; //BltVideoSurface( guiSAVEBUFFER, FRAME_BUFFER, 0, // 0, 0, // VS_BLT_SRCSUBRECT, &BltFx ); } //else //{ // Render to save buffer // CreateTopMessage( guiSAVEBUFFER, gTopMessageTypes[ 0 ], gzTopMessageStrings[ 0 ] ); //} // Animate up... //gTopMessage.bAnimate = 1; // Set time of last update //gTopMessage.uiTimeOfLastUpdate = GetJA2Clock( ) + 150; // Handle first frame now... // HandleTopMessages( ); } } BOOLEAN InTopMessageBarAnimation( ) { if ( gTacticalStatus.fInTopMessage ) { if ( gTopMessage.bAnimate != 0 ) { HandleTopMessages( ); return( TRUE ); } } return( FALSE ); } void PauseRT( BOOLEAN fPause ) { //StopMercAnimation( fPause ); if ( fPause ) { // PauseGame( ); } else { // UnPauseGame( ); } } void InitEnemyUIBar( UINT8 ubNumEnemies, UINT8 ubDoneEnemies ) { // OK, set value gubProgNumEnemies = ubNumEnemies + ubDoneEnemies; gubProgCurEnemy = ubDoneEnemies; gfProgBarActive = TRUE; gTacticalStatus.usTactialTurnLimitCounter = ubDoneEnemies * PLAYER_TEAM_TIMER_TICKS_PER_ENEMY; gTacticalStatus.usTactialTurnLimitMax = ( (ubNumEnemies + ubDoneEnemies) * PLAYER_TEAM_TIMER_TICKS_PER_ENEMY ); } void UpdateEnemyUIBar( ) { // Are we active? if ( gfProgBarActive ) { // OK, update team limit counter.... gTacticalStatus.usTactialTurnLimitCounter = ( gubProgCurEnemy * PLAYER_TEAM_TIMER_TICKS_PER_ENEMY ); gubProgCurEnemy++; } // Do we have an active enemy bar? if ( gTacticalStatus.fInTopMessage ) { if ( gTacticalStatus.ubTopMessageType == COMPUTER_TURN_MESSAGE ) { // Update message! CreateTopMessage( gTopMessage.uiSurface, COMPUTER_TURN_MESSAGE, gTacticalStatus.zTopMessageString ); } } } void InitPlayerUIBar( BOOLEAN fInterrupt ) { SOLDIERTYPE *pTeamSoldier; INT32 cnt = 0; INT8 bNumOK = 0, bNumNotOK = 0; if ( !gGameOptions.fTurnTimeLimit ) { if ( fInterrupt == TRUE ) { AddTopMessage( PLAYER_INTERRUPT_MESSAGE, Message[STR_INTERRUPT] ); } else { //EndTopMessage(); AddTopMessage( PLAYER_TURN_MESSAGE, TeamTurnString[0] ); } return; } if (is_networked) gTacticalStatus.usTactialTurnLimitMax = 0;//hayden , cheap hack, always calc time... // OK, calculate time.... if ( !fInterrupt || gTacticalStatus.usTactialTurnLimitMax == 0 ) { gTacticalStatus.usTactialTurnLimitCounter = 0; // IF IT'S THE SELECTED GUY, MAKE ANOTHER SELECTED! cnt = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; // look for all mercs on the same team, for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; cnt++,pTeamSoldier++) { // Are we active and in sector..... if ( pTeamSoldier->bActive && pTeamSoldier->bInSector ) { if ( pTeamSoldier->stats.bLife < OKLIFE ) { bNumNotOK++; } else { bNumOK++; } } } gTacticalStatus.usTactialTurnLimitMax = ( bNumOK * PLAYER_TEAM_TIMER_TICKS_PER_OK_MERC ) + ( bNumNotOK * PLAYER_TEAM_TIMER_TICKS_PER_NOTOK_MERC ); } else { if ( gTacticalStatus.usTactialTurnLimitCounter > PLAYER_TEAM_TIMER_INTTERUPT_GRACE ) { gTacticalStatus.usTactialTurnLimitCounter -= PLAYER_TEAM_TIMER_INTTERUPT_GRACE; } } gTacticalStatus.uiTactialTurnLimitClock = 0; gTacticalStatus.fTactialTurnLimitStartedBeep = FALSE; // RESET COIUNTER... RESETTIMECOUNTER( giTimerTeamTurnUpdate, PLAYER_TEAM_TIMER_SEC_PER_TICKS ); // OK, set value if ( fInterrupt != TRUE ) { AddTopMessage( PLAYER_TURN_MESSAGE, TeamTurnString[0] ); } else { AddTopMessage( PLAYER_INTERRUPT_MESSAGE, Message[STR_INTERRUPT] ); } } void MovementMenuBackregionCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if ( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { CancelMovementMenu( ); } } void DoorMenuBackregionCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if ( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) { CancelOpenDoorMenu( ); } } STR16 GetSoldierHealthString( SOLDIERTYPE *pSoldier ) { // sevenfm: show enemy health as text only when SHOW_ENEMY_HEALTH = 1 if ( ( gGameExternalOptions.ubShowEnemyHealth != 1 ) && (pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == CREATURE_TEAM)) { return L""; } else { // Flugente: display if we are a prisoner of war if ( pSoldier->bSoldierFlagMask & SOLDIER_POW ) return zHealthStr[ 7 ]; INT32 cnt, cntStart; if( pSoldier->stats.bLife == pSoldier->stats.bLifeMax ) { cntStart = 4; } else { cntStart = 0; } //Show health on others......... for ( cnt = cntStart; cnt < 6; cnt ++ ) { if ( pSoldier->stats.bLife < bHealthStrRanges[ cnt ] ) { break; } } return zHealthStr[ cnt ]; } } typedef struct { INT8 bHeight; INT8 bPower; INT32 sGridNo; UINT8 ubLevel; SOLDIERTYPE *pSoldier; BOOLEAN fShowHeight; BOOLEAN fShowPower; BOOLEAN fActiveHeightBar; BOOLEAN fActivePowerBar; BOOLEAN fAtEndHeight; INT32 sTargetGridNo; FLOAT dInitialForce; FLOAT dForce; FLOAT dDegrees; FLOAT dMaxForce; UINT8 ubPowerIndex; } AIMCUBE_UI_DATA; static BOOLEAN gfInAimCubeUI = FALSE; static AIMCUBE_UI_DATA gCubeUIData; #define GET_CUBES_HEIGHT_FROM_UIHEIGHT( h ) ( 32 + ( h * 64 ) ) void CalculateAimCubeUIPhysics( ) { UINT8 ubHeight; ubHeight = GET_CUBES_HEIGHT_FROM_UIHEIGHT( gCubeUIData.bHeight ); if ( gCubeUIData.fActiveHeightBar ) { // OK, determine which power to use..... // TODO this: take force / max force * 10.... gCubeUIData.ubPowerIndex = (UINT8)( gCubeUIData.dForce / gCubeUIData.dMaxForce * 10 ); } if ( gCubeUIData.fActivePowerBar ) { gCubeUIData.dForce = ( gCubeUIData.dMaxForce * ( (FLOAT)gCubeUIData.ubPowerIndex / (FLOAT)10 ) ); // Limit to the max force... if ( gCubeUIData.dForce > gCubeUIData.dMaxForce ) { gCubeUIData.dForce = gCubeUIData.dMaxForce; } gCubeUIData.dDegrees = (FLOAT)CalculateLaunchItemAngle( gCubeUIData.pSoldier, gCubeUIData.sGridNo, ubHeight, gCubeUIData.dForce, &(gCubeUIData.pSoldier->inv[ HANDPOS ] ), &(gCubeUIData.sTargetGridNo ) ); } } INT32 GetInAimCubeUIGridNo( ) { return( gCubeUIData.sGridNo ); } BOOLEAN InAimCubeUI( ) { return( gfInAimCubeUI ); } BOOLEAN AimCubeUIClick( ) { if ( !gfInAimCubeUI ) { return( FALSE ); } // If we have clicked, and we are only on height, continue with power if ( gCubeUIData.fActiveHeightBar && gCubeUIData.bHeight != 0 ) { gCubeUIData.fShowPower = TRUE; gCubeUIData.fActiveHeightBar = FALSE; gCubeUIData.fActivePowerBar = TRUE; return( FALSE ); } else { return( TRUE ); } } void BeginAimCubeUI( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 ubLevel, UINT8 bStartPower, INT8 bStartHeight ) { gfInAimCubeUI = TRUE; gCubeUIData.sGridNo = sGridNo; gCubeUIData.ubLevel = ubLevel; gCubeUIData.pSoldier = pSoldier; gCubeUIData.bPower = bStartPower; gCubeUIData.bHeight = bStartHeight; gCubeUIData.fShowHeight = TRUE; gCubeUIData.fShowPower = FALSE; gCubeUIData.fActivePowerBar = FALSE; gCubeUIData.fActiveHeightBar = TRUE; gCubeUIData.fAtEndHeight = FALSE; gCubeUIData.dDegrees = (float)PI/4; // Calculate Iniital force.... CalculateAimCubeUIPhysics( ); } void EndAimCubeUI( ) { gfInAimCubeUI = FALSE; } void IncrementAimCubeUI( ) { if ( gCubeUIData.fActiveHeightBar ) { // Cycle the last height yellow once if ( gCubeUIData.bHeight == 3 ) { if ( gCubeUIData.fAtEndHeight ) { gCubeUIData.bHeight = 0; gCubeUIData.fAtEndHeight = 0; } else { gCubeUIData.fAtEndHeight = TRUE; } } else { gCubeUIData.bHeight++; } CalculateAimCubeUIPhysics( ); } if ( gCubeUIData.fActivePowerBar ) { if ( gCubeUIData.ubPowerIndex == 10 ) { UINT8 ubHeight; ubHeight = GET_CUBES_HEIGHT_FROM_UIHEIGHT( gCubeUIData.bHeight ); // Start back to basic7 gCubeUIData.dDegrees = (FLOAT)(PI/4); gCubeUIData.dInitialForce = gCubeUIData.dForce; // OK, determine which power to use..... // TODO this: take force / max force * 10.... gCubeUIData.ubPowerIndex = (UINT8)( gCubeUIData.dForce / gCubeUIData.dMaxForce * 10 ); } // Cycle the last height yellow once gCubeUIData.ubPowerIndex++; CalculateAimCubeUIPhysics( ); } } void SetupAimCubeAI( ) { if ( gfInAimCubeUI ) { AddTopmostToHead( gCubeUIData.sTargetGridNo, FIRSTPOINTERS2 ); gpWorldLevelData[ gCubeUIData.sTargetGridNo ].pTopmostHead->ubShadeLevel=DEFAULT_SHADE_LEVEL; gpWorldLevelData[ gCubeUIData.sTargetGridNo ].pTopmostHead->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; //AddTopmostToHead( gCubeUIData.sGridNo, FIRSTPOINTERS2 ); //gpWorldLevelData[ gCubeUIData.sGridNo ].pTopmostHead->ubShadeLevel=DEFAULT_SHADE_LEVEL; //gpWorldLevelData[ gCubeUIData.sGridNo ].pTopmostHead->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; } } void ResetAimCubeAI( ) { if ( gfInAimCubeUI ) { RemoveTopmost( gCubeUIData.sTargetGridNo, FIRSTPOINTERS2 ); //RemoveTopmost( gCubeUIData.sGridNo, FIRSTPOINTERS2 ); } } void RenderAimCubeUI( ) { INT16 sScreenX = 0, sScreenY = 0; INT32 cnt; INT16 sBarHeight; INT32 iBack; INT8 bGraphicNum; if ( gfInAimCubeUI ) { // OK, given height if ( gCubeUIData.fShowHeight ) { // Determine screen location.... GetGridNoScreenPos( gCubeUIData.sGridNo, gCubeUIData.ubLevel, &sScreenX, &sScreenY ); // Save background iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sScreenX, (INT16)(sScreenY - 70 ), (INT16)(sScreenX + 40 ), (INT16)(sScreenY + 50 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } sBarHeight = 0; bGraphicNum = 0; if ( gCubeUIData.bHeight == 3 && gCubeUIData.fAtEndHeight ) { bGraphicNum = 1; } // Do first level.... BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); sBarHeight -= 3; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); // Loop through height..... for ( cnt = 1; cnt <= gCubeUIData.bHeight; cnt++ ) { sBarHeight -= 3; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); sBarHeight -= 3; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); sBarHeight -= 3; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); sBarHeight -= 3; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMCUBES, bGraphicNum, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); } } if ( gCubeUIData.fShowPower ) { sBarHeight = -50; BltVideoObjectFromIndex( FRAME_BUFFER, guiAIMBARS, gCubeUIData.ubPowerIndex, sScreenX, ( sScreenY + sBarHeight ), VO_BLT_SRCTRANSPARENCY, NULL ); } } } void GetLaunchItemParamsFromUI( ) { } static BOOLEAN gfDisplayPhysicsUI = FALSE; static INT32 gsPhysicsImpactPointGridNo; static INT8 gbPhysicsImpactPointLevel; static BOOLEAN gfBadPhysicsCTGT = FALSE; void BeginPhysicsTrajectoryUI( INT32 sGridNo, INT8 bLevel, BOOLEAN fBadCTGT ) { gfDisplayPhysicsUI = TRUE; gsPhysicsImpactPointGridNo = sGridNo; gbPhysicsImpactPointLevel = bLevel; gfBadPhysicsCTGT = fBadCTGT; } void EndPhysicsTrajectoryUI( ) { gfDisplayPhysicsUI = FALSE; } void SetupPhysicsTrajectoryUI( ) { if ( gfDisplayPhysicsUI && gfUIHandlePhysicsTrajectory ) { if ( gbPhysicsImpactPointLevel == 0 ) { if ( gfBadPhysicsCTGT ) { AddTopmostToHead( gsPhysicsImpactPointGridNo, FIRSTPOINTERS12 ); } else { AddTopmostToHead( gsPhysicsImpactPointGridNo, FIRSTPOINTERS8 ); } gpWorldLevelData[ gsPhysicsImpactPointGridNo ].pTopmostHead->ubShadeLevel=DEFAULT_SHADE_LEVEL; gpWorldLevelData[ gsPhysicsImpactPointGridNo ].pTopmostHead->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; } else { if ( gfBadPhysicsCTGT ) { AddOnRoofToHead( gsPhysicsImpactPointGridNo, FIRSTPOINTERS12 ); } else { AddOnRoofToHead( gsPhysicsImpactPointGridNo, FIRSTPOINTERS8 ); } gpWorldLevelData[ gsPhysicsImpactPointGridNo ].pOnRoofHead->ubShadeLevel=DEFAULT_SHADE_LEVEL; gpWorldLevelData[ gsPhysicsImpactPointGridNo ].pOnRoofHead->ubNaturalShadeLevel=DEFAULT_SHADE_LEVEL; } } } void ResetPhysicsTrajectoryUI( ) { if ( gfDisplayPhysicsUI ) { RemoveTopmost( gsPhysicsImpactPointGridNo, FIRSTPOINTERS8 ); RemoveTopmost( gsPhysicsImpactPointGridNo, FIRSTPOINTERS12 ); RemoveOnRoof( gsPhysicsImpactPointGridNo, FIRSTPOINTERS8 ); RemoveOnRoof( gsPhysicsImpactPointGridNo, FIRSTPOINTERS12 ); } } void DirtyTopMessage( ) { gTopMessage.fCreated = FALSE; } UINT32 CalcUIMessageDuration( STR16 wString ) { // base + X per letter return( 1000 + 50 * wcslen( wString ) ); } BOOLEAN gfMultipurposeLocatorOn = FALSE; UINT32 guiMultiPurposeLocatorLastUpdate; INT8 gbMultiPurposeLocatorFrame; INT32 gsMultiPurposeLocatorGridNo; INT8 gbMultiPurposeLocatorLevel; INT8 gbMultiPurposeLocatorCycles; void BeginMultiPurposeLocator( INT32 sGridNo, INT8 bLevel, BOOLEAN fSlideTo ) { guiMultiPurposeLocatorLastUpdate = 0; gbMultiPurposeLocatorCycles = 0; gbMultiPurposeLocatorFrame = 0; gfMultipurposeLocatorOn = TRUE; gsMultiPurposeLocatorGridNo = sGridNo; gbMultiPurposeLocatorLevel = bLevel; if ( fSlideTo ) { // FIRST CHECK IF WE ARE ON SCREEN if ( GridNoOnScreen( sGridNo ) ) { return; } // sGridNo here for DG compatibility gTacticalStatus.sSlideTarget = sGridNo; gTacticalStatus.sSlideReason = NOBODY; // Plot new path! gfPlotNewMovement = TRUE; } } void HandleMultiPurposeLocator( ) { UINT32 uiClock; if ( !gfMultipurposeLocatorOn ) { return; } // Update radio locator uiClock = GetJA2Clock( ); // Update frame values! if ( ( uiClock - guiMultiPurposeLocatorLastUpdate ) > 80 ) { guiMultiPurposeLocatorLastUpdate = uiClock; // Update frame gbMultiPurposeLocatorFrame++; if ( gbMultiPurposeLocatorFrame == 5 ) { gbMultiPurposeLocatorFrame = 0; gbMultiPurposeLocatorCycles++; } if ( gbMultiPurposeLocatorCycles == 8 ) { gfMultipurposeLocatorOn = FALSE; } } } void RenderTopmostMultiPurposeLocator( ) { FLOAT dOffsetX, dOffsetY; FLOAT dTempX_S, dTempY_S; INT16 sX, sY, sXPos, sYPos; INT32 iBack; if ( !gfMultipurposeLocatorOn ) { return; } ConvertGridNoToCenterCellXY( gsMultiPurposeLocatorGridNo, &sX, &sY ); dOffsetX = (FLOAT)( sX - gsRenderCenterX ); dOffsetY = (FLOAT)( sY - gsRenderCenterY ); // Calculate guy's position FloatFromCellToScreenCoordinates( dOffsetX, dOffsetY, &dTempX_S, &dTempY_S ); sXPos = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) + (INT16)dTempX_S; sYPos = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + (INT16)dTempY_S - gpWorldLevelData[ gsMultiPurposeLocatorGridNo ].sHeight; // Adjust for offset position on screen sXPos -= gsRenderWorldOffsetX; sYPos -= gsRenderWorldOffsetY; // Adjust for render height sYPos += gsRenderHeight; // Adjust for level height if ( gbMultiPurposeLocatorLevel ) { sYPos -= ROOF_LEVEL_HEIGHT; } // Center circle! sXPos -= 20; sYPos -= 20; iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos +40 ), (INT16)(sYPos + 40 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiRADIO, gbMultiPurposeLocatorFrame, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL ); } void DrawBar( INT32 x, INT32 y, INT32 width, INT32 height, UINT16 color8, UINT16 color16, UINT8 *pDestBuf ) { if( width > 0 ) { for( INT32 i=0; i < height; i++ ) { if(gbPixelDepth==16) LineDraw( TRUE, x, y+i, x+width-1, y+i, color16, pDestBuf ); else if(gbPixelDepth==8) LineDraw8( TRUE, x, y+i, x+width-1, y+i, color8, pDestBuf ); } } } BOOLEAN CoverColorCode( INT8 cover, INT16 &color8, INT16 &color16 ){ BOOLEAN showCover = TRUE; switch(cover) { case 0: //color8 = COLOR_RED; color8 = FONT_MCOLOR_RED; color16 = Get16BPPColor( FROMRGB( 220, 0, 0 ) ); break; case 1: color8 = COLOR_ORANGE; color16 = Get16BPPColor( FROMRGB( 220, 140, 0 ) ); break; case 2: color8 = COLOR_YELLOW; color16 = Get16BPPColor( FROMRGB( 220, 220, 0 ) ); break; case 3: color8 = COLOR_GREEN; color16 = Get16BPPColor( FROMRGB( 0, 200, 0 ) ); break; default: showCover = FALSE; } return showCover; } void DrawRankIcon( INT8 rank, INT32 baseX, INT32 baseY ) { UINT32 uiDestPitchBYTES; UINT8 *pDestBuf; INT16 color8; INT16 color16; pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, ( gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y ) ); if(rank<6) { color8 = FONT_DKGREEN; color16 = Get16BPPColor( FROMRGB( 20, 60, 20 ) ); //color8 = FONT_ORANGE; //color16 = Get16BPPColor( FROMRGB( 160, 80, 0 ) ); } else { color8 = FONT_DKRED; color16 = Get16BPPColor( FROMRGB( 60, 20, 20 ) ); } DrawBar( baseX+2, baseY+2, 7, 8, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+10, baseX+7, baseY+10, color8, color16, pDestBuf ); DrawLine( baseX+4, baseY+11, baseX+6, baseY+11, color8, color16, pDestBuf ); if(rank<6) { color8 = COLOR_GREEN; color16 = Get16BPPColor( FROMRGB( 20, 80, 20 ) ); //color8 = FONT_YELLOW; //color16 = Get16BPPColor( FROMRGB( 200, 120, 00 ) ); } else { color8 = COLOR_RED; color16 = Get16BPPColor( FROMRGB( 120, 20, 20 ) ); } DrawLine( baseX+2, baseY+1, baseX+8, baseY+1, color8, color16, pDestBuf ); DrawLine( baseX+1, baseY+2, baseX+1, baseY+9, color8, color16, pDestBuf ); DrawLine( baseX+9, baseY+2, baseX+9, baseY+9, color8, color16, pDestBuf ); DrawLine( baseX+1, baseY+9, baseX+4, baseY+12, color8, color16, pDestBuf ); DrawLine( baseX+4, baseY+12, baseX+6, baseY+12, color8, color16, pDestBuf ); DrawLine( baseX+6, baseY+12, baseX+9, baseY+9, color8, color16, pDestBuf ); if(rank<6) { //color8 = FONT_DKGREEN; //color16 = Get16BPPColor( FROMRGB( 0, 40, 0 ) ); //color8 = COLOR_LTGREY; //color16 = Get16BPPColor( FROMRGB( 120, 120, 120 ) ); color8 = COLOR_YELLOW; color16 = Get16BPPColor( FROMRGB( 200, 200, 200 ) ); } else { color8 = FONT_ORANGE; color16 = Get16BPPColor( FROMRGB( 220, 140, 20 ) ); } switch( rank ) { case 1: DrawLine( baseX+3, baseY+6, baseX+7, baseY+6, color8, color16, pDestBuf ); break; case 2: DrawLine( baseX+3, baseY+5, baseX+7, baseY+5, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+7, baseX+7, baseY+7, color8, color16, pDestBuf ); break; case 3: DrawLine( baseX+3, baseY+4, baseX+7, baseY+4, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+6, baseX+7, baseY+6, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+8, baseX+7, baseY+8, color8, color16, pDestBuf ); break; case 4: DrawLine( baseX+3, baseY+5, baseX+5, baseY+8, color8, color16, pDestBuf ); DrawLine( baseX+5, baseY+8, baseX+7, baseY+5, color8, color16, pDestBuf ); break; case 5: DrawLine( baseX+3, baseY+4, baseX+7, baseY+4, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+6, baseX+5, baseY+9, color8, color16, pDestBuf ); DrawLine( baseX+5, baseY+9, baseX+7, baseY+6, color8, color16, pDestBuf ); break; case 6: DrawLine( baseX+5, baseY+4, baseX+5, baseY+8, color8, color16, pDestBuf ); break; case 7: DrawLine( baseX+4, baseY+4, baseX+4, baseY+8, color8, color16, pDestBuf ); DrawLine( baseX+6, baseY+4, baseX+6, baseY+8, color8, color16, pDestBuf ); break; case 8: DrawLine( baseX+5, baseY+4, baseX+5, baseY+8, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+4, baseX+3, baseY+8, color8, color16, pDestBuf ); DrawLine( baseX+7, baseY+4, baseX+7, baseY+8, color8, color16, pDestBuf ); break; case 9: DrawLine( baseX+2, baseY+6, baseX+8, baseY+6, color8, color16, pDestBuf ); DrawLine( baseX+5, baseY+3, baseX+5, baseY+9, color8, color16, pDestBuf ); DrawLine( baseX+3, baseY+4, baseX+7, baseY+8, color8, color16, pDestBuf ); DrawLine( baseX+7, baseY+4, baseX+3, baseY+8, color8, color16, pDestBuf ); } UnLockVideoSurface( FRAME_BUFFER ); } void DrawItemPic(INVTYPE *pItem, INT16 sX, INT16 sY ) { UINT16 usGraphicNum; usGraphicNum = g_bUsePngItemImages ? 0 : pItem->ubGraphicNum; HVOBJECT hVObject; ETRLEObject *pTrav; GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) ); pTrav = &(hVObject->pETRLEObject[ usGraphicNum ] ); BltVideoObjectOutlineFromIndex( FRAME_BUFFER, GetInterfaceGraphicForItem( pItem ), usGraphicNum, sX - pTrav->sOffsetX, sY - pTrav->sOffsetY, Get16BPPColor( FROMRGB( 255, 255, 255 ) ), FALSE ); } void GetItemDimensions( INVTYPE *pItem, INT16 &sWidth, INT16 &sHeight ) { HVOBJECT hVObject; ETRLEObject *pTrav; UINT16 usGraphicNum; usGraphicNum = g_bUsePngItemImages ? 0 : pItem->ubGraphicNum; GetVideoObject( &hVObject, GetInterfaceGraphicForItem( pItem ) ); pTrav = &(hVObject->pETRLEObject[ usGraphicNum ] ); sWidth = (UINT32)(pTrav->usWidth); sHeight = (UINT32)(pTrav->usHeight); } BOOLEAN ShowExactInfo( SOLDIERTYPE* pSoldier, SOLDIERTYPE* pTargetSoldier ) { INT32 range; INT32 maxExactWeaponDistance; if( pTargetSoldier->bVisible == -1 ) return FALSE; range = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, pTargetSoldier->sGridNo ) / 10; // visible distance maxExactWeaponDistance = (INT32)( pSoldier->GetMaxDistanceVisible( pTargetSoldier->sGridNo, 0, CALC_FROM_WANTED_DIR) ) / 2 ; // apply experience level factor maxExactWeaponDistance = (INT32)( maxExactWeaponDistance * ( 1 + FLOAT( EffectiveExpLevel( pSoldier ) ) / 10.0f ) ); if ( maxExactWeaponDistance >= range ) return TRUE; return FALSE; } void DrawNCTHCursorItemPics( INT16 sStartScreenX, INT16 sStartScreenY ) { // find target soldier SOLDIERTYPE *pSoldier; SOLDIERTYPE *pTargetSoldier; INT32 usItemID = 0; INT16 sX, sY, sWidth, sHeight; INT16 sXOffset = 0; GetSoldier( &pSoldier, gusSelectedSoldier ); GetSoldier( &pTargetSoldier, gusUIFullTargetID ); // zero rects RightRect.left = 0; RightRect.top = 0; RightRect.right = 0; RightRect.bottom = 0; LeftRect.left = 0; LeftRect.top = 0; LeftRect.right = 0; LeftRect.bottom = 0; LeftRect2.left = 0; LeftRect2.top = 0; LeftRect2.right = 0; LeftRect2.bottom = 0; if( gGameExternalOptions.ubAdditionalNCTHCursorInfo && gfUIBodyHitLocation && pSoldier->ubBodyType <= REGFEMALE && _KeyDown( ALT ) && ShowExactInfo( pSoldier, pTargetSoldier) ) { // show armour switch( pSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: if( pTargetSoldier->inv[HELMETPOS].exists() ) usItemID = pTargetSoldier->inv[HELMETPOS].usItem; break; case AIM_SHOT_TORSO: if( pTargetSoldier->inv[VESTPOS].exists() ) usItemID = pTargetSoldier->inv[VESTPOS].usItem; break; case AIM_SHOT_LEGS: if( pTargetSoldier->inv[LEGPOS].exists() ) usItemID = pTargetSoldier->inv[LEGPOS].usItem; break; } if( usItemID ) { sX = sStartScreenX+25; sY = sStartScreenY-3; DrawItemPic( &(Item[ usItemID ] ), sX, sY ); GetItemDimensions( &(Item[ usItemID ]), sWidth, sHeight ); RightRect.left = sX; RightRect.top = sY; RightRect.right = sX + sWidth; RightRect.bottom = sY + sHeight; } if( gGameExternalOptions.ubAdditionalNCTHCursorInfo > 1 ) { // show item in hands if( pSoldier->bAimShotLocation == AIM_SHOT_TORSO ) { if( pTargetSoldier->inv[HANDPOS].exists() ) { usItemID = pTargetSoldier->inv[HANDPOS].usItem; GetItemDimensions( &(Item[ usItemID ]), sWidth, sHeight ); if( sWidth > 30 ) sXOffset = 10; sX = sStartScreenX - 25 - sWidth + sXOffset; sY = sStartScreenY - 3; DrawItemPic(&(Item[ usItemID ] ), sX, sY ); LeftRect.left = sX; LeftRect.top = sY; LeftRect.right = sX + sWidth; LeftRect.bottom = sY + sHeight; } } // show items in head slots else if( pSoldier->bAimShotLocation == AIM_SHOT_HEAD ) { if( pTargetSoldier->inv[HEAD2POS].exists() ) { usItemID = pTargetSoldier->inv[HEAD2POS].usItem; GetItemDimensions( &(Item[ usItemID ]), sWidth, sHeight ); sX = sStartScreenX - 25 - sWidth; sY = sStartScreenY - 3; DrawItemPic(&(Item[ usItemID ] ), sX, sY ); LeftRect.left = sX; LeftRect.top = sY; LeftRect.right = sX + sWidth; LeftRect.bottom = sY + sHeight; } if( pTargetSoldier->inv[HEAD1POS].exists() ) { usItemID = pTargetSoldier->inv[HEAD1POS].usItem; GetItemDimensions( &(Item[ usItemID ]), sWidth, sHeight ); sX = sStartScreenX - 25 - sWidth; sY = sStartScreenY - 3; if( pTargetSoldier->inv[HEAD2POS].exists() ) sX -= LeftRect.right - LeftRect.left; DrawItemPic(&(Item[ usItemID ] ), sX, sY ); LeftRect2.left = sX; LeftRect2.top = sY; LeftRect2.right = sX + sWidth; LeftRect2.bottom = sY + sHeight; } } } } } void GetEnemyInfoString( SOLDIERTYPE* pSelectedSoldier, SOLDIERTYPE* pTargetSoldier, BOOLEAN showExactInfo, CHAR16 *NameStr ) { UINT16 usItemID; // if ALT pressed - show armour instead of weapon if( gfUIBodyHitLocation && _KeyDown( ALT ) ) { SetFontForeground( FONT_YELLOW ); // show armour usItemID = 0; switch( pSelectedSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: if( pTargetSoldier->inv[HELMETPOS].exists() ) usItemID = pTargetSoldier->inv[HELMETPOS].usItem; break; case AIM_SHOT_TORSO: if( pTargetSoldier->inv[VESTPOS].exists() ) usItemID = pTargetSoldier->inv[VESTPOS].usItem; break; case AIM_SHOT_LEGS: if( pTargetSoldier->inv[LEGPOS].exists() ) usItemID = pTargetSoldier->inv[LEGPOS].usItem; break; } if( usItemID ) { if( showExactInfo && gGameExternalOptions.fShowEnemyExtendedInfo ) { // in range, show exact armour name swprintf( NameStr, L"%s", ItemNames[ usItemID ] ); } else { // show general armour type switch( pSelectedSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_HELMET] ); break; case AIM_SHOT_TORSO: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_VEST] ); break; case AIM_SHOT_LEGS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_LEGGINGS] ); break; } } } } else { if( gfUIBodyHitLocation && pSelectedSoldier->bAimShotLocation == AIM_SHOT_HEAD ) { // show face items SetFontForeground( FONT_ORANGE ); if( pTargetSoldier->inv[HEAD1POS].exists() ) { if(gGameExternalOptions.fShowEnemyExtendedInfo) { // show exact name wcscat( NameStr, ItemNames[ pTargetSoldier->inv[HEAD1POS].usItem ] ); } else { // show general name if( Item[pTargetSoldier->inv[HEAD1POS].usItem].gasmask ) wcscat( NameStr, L"Mask" ); else if( Item[pTargetSoldier->inv[HEAD1POS].usItem].nightvisionrangebonus || Item[pTargetSoldier->inv[HEAD1POS].usItem].cavevisionrangebonus ) wcscat( NameStr, L"NVG" ); } } if( pTargetSoldier->inv[HEAD2POS].exists() ) { if( pTargetSoldier->inv[HEAD1POS].exists() ) wcscat( NameStr, L", " ); if(gGameExternalOptions.fShowEnemyExtendedInfo) { // show exact name wcscat( NameStr, ItemNames[ pTargetSoldier->inv[HEAD2POS].usItem ] ); } else { // show general name if( Item[pTargetSoldier->inv[HEAD1POS].usItem].gasmask ) wcscat( NameStr, L"Mask" ); else if( Item[pTargetSoldier->inv[HEAD1POS].usItem].nightvisionrangebonus || Item[pTargetSoldier->inv[HEAD1POS].usItem].cavevisionrangebonus ) wcscat( NameStr, L"NVG" ); } } } else { // show weapon SetFontForeground( FONT_ORANGE ); if ( WeaponInHand( pTargetSoldier ) ) { if ( showExactInfo ) { swprintf( NameStr, L"%s", ItemNames[ pTargetSoldier->inv[ HANDPOS ].usItem ] ); } else { // display general weapon class switch( Weapon[pTargetSoldier->inv[ HANDPOS ].usItem].ubWeaponClass ) { case HANDGUNCLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_HANDGUN] ); break; case SMGCLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_SMG] ); break; case RIFLECLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_RIFLE] ); break; case MGCLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_MG] ); break; case SHOTGUNCLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_SHOTGUN] ); break; case KNIFECLASS: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_KNIFE] ); break; default: swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_HEAVY_WEAPON] ); break; } } } else { if( showExactInfo ) { if( pTargetSoldier->inv[ HANDPOS ].usItem ) swprintf( NameStr, L"%s", Item[ pTargetSoldier->inv[ HANDPOS ].usItem ].szItemName ); else swprintf( NameStr, L"%s", gzTooltipStrings[STR_TT_NO_WEAPON] ); } else { if( pTargetSoldier->inv[ HANDPOS ].usItem ) swprintf( NameStr, L"%s", L"Item" ); else swprintf( NameStr, L"%s", L"" ); } } } } } void DrawLine( INT32 x1, INT32 y1, INT32 x2, INT32 y2, UINT16 color8, UINT16 color16, UINT8 *pDestBuf ) { if(gbPixelDepth==16) LineDraw( TRUE, x1, y1, x2, y2, color16, pDestBuf); else LineDraw8( TRUE, x1, y1, x2, y2, color8, pDestBuf); } void DrawEnemyHealthBar( SOLDIERTYPE* pSoldier, INT32 sX, INT32 sY, UINT8 ubLines, INT32 iBarWidth, INT32 iBarHeight ) { FLOAT dWidth, dPercentage; UINT32 uiDestPitchBYTES; UINT8 *pDestBuf; INT32 sHeight = 2; pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES ); SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, gsVIEWPORT_WINDOW_START_Y, SCREEN_WIDTH, ( gsVIEWPORT_WINDOW_END_Y - gsVIEWPORT_WINDOW_START_Y ) ); // sevenfm: draw background DrawBar( sX, sY, iBarWidth + 2, iBarHeight, COLOR_BLACK, Get16BPPColor( FROMRGB( 0, 0, 0 ) ), pDestBuf ); // draw health if(ubLines > 0) { dPercentage = (FLOAT)pSoldier->stats.bLife / (FLOAT) pSoldier->stats.bLifeMax; dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); DrawBar( sX + 1, sY + 1, (INT32)dWidth, sHeight, COLOR_RED, Get16BPPColor( FROMRGB( 200, 0, 0 ) ), pDestBuf ); } // draw ap if(ubLines > 1) { if( pSoldier->bActionPoints >0 ) { //dPercentage = (FLOAT)pSoldier->bActionPoints / (FLOAT) ( pSoldier->bActionPoints + pSoldier->ubAPsLostToSuppression + pSoldier->u); dPercentage = (FLOAT)pSoldier->bActionPoints / (FLOAT) ( pSoldier->bInitialActionPoints); dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); //DrawBar( sX + 1, sY + 1 + (sHeight+1), (INT32)dWidth, sHeight, COLOR_BLUE, Get16BPPColor( FROMRGB( 20, 20, 220 ) ), pDestBuf ); DrawBar( sX + 1, sY + 1 + (sHeight+1), (INT32)dWidth, sHeight, COLOR_PURPLE, Get16BPPColor( FROMRGB( 110, 30, 210 ) ), pDestBuf ); } else { dPercentage = (FLOAT)pSoldier->bActionPoints / (FLOAT) ( APBPConstants[AP_MIN_LIMIT] ); dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); DrawBar( sX + 1, sY + 1 + (sHeight+1), (INT32)dWidth, sHeight, COLOR_LTGREY, Get16BPPColor( FROMRGB( 140, 140, 140 ) ), pDestBuf ); } } // draw suppression shock if( ubLines > 2 ) { dPercentage = (FLOAT)( __min(100, ( (FLOAT)100 * CalcEffectiveShockLevel( pSoldier ) ) / CalcSuppressionTolerance( pSoldier ) ) ) / (FLOAT)100; dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); DrawBar( sX+1, sY + 1 + 2*(sHeight+1), (INT32)dWidth, sHeight, COLOR_ORANGE, Get16BPPColor( FROMRGB( 200, 120, 0 ) ), pDestBuf ); } // draw morale if( ubLines > 3 ) { dPercentage = (FLOAT)( pSoldier->aiData.bAIMorale ) / (FLOAT)( MORALE_FEARLESS ); //dPercentage = (FLOAT)( pSoldier->aiData.bMorale ) / (FLOAT)( 100 ); dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); DrawBar( sX+1, sY + 1 + 3*(sHeight+1), (INT32)dWidth, sHeight, COLOR_GREEN, Get16BPPColor( FROMRGB( 0, 140, 0 ) ), pDestBuf ); } // draw BP if( ubLines > 4 ) { dPercentage = (FLOAT)( pSoldier->bBreath ) / (FLOAT)( pSoldier->bBreathMax ); dWidth = dPercentage * iBarWidth; dWidth = __min (dWidth, iBarWidth); DrawBar( sX+1, sY + 1 + 4*(sHeight+1), (INT32)dWidth, sHeight, COLOR_BLUE, Get16BPPColor( FROMRGB( 0, 0, 200 ) ), pDestBuf ); } UnLockVideoSurface( FRAME_BUFFER ); } // Flugente: show enemy role BOOLEAN ShowSoldierRoleSymbol(SOLDIERTYPE* pSoldier) { // this only works on enemy soldiers if ( pSoldier->bTeam != ENEMY_TEAM ) return false; if ( pSoldier->usSkillCounter[SOLDIER_COUNTER_ROLE_OBSERVED] < gGameExternalOptions.usTurnsToUncover ) return false; INT16 sXPos = 0; INT16 sYPos = 0; INT32 iBack = 0; GetSoldierAboveGuyPositions( pSoldier, &sXPos, &sYPos, TRUE ); // Adjust for bars! sXPos += 50; sYPos += 25; // is this guy an officer? if ( pSoldier->bSoldierFlagMask & SOLDIER_ENEMY_OFFICER ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 0, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } // is this guy radio operator with a radio? if ( pSoldier->CanUseRadio(false) ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 3, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } // is this guy a doctor? we do not check for medical gear, as we would not have that information from a glance if ( HAS_SKILL_TRAIT( pSoldier, DOCTOR_NT) ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 1, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } // is this guy a sniper? Just check for the gun, trait is not necessary if ( pSoldier->HasSniper() ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 2, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } // is this guy a mortar guy? Just check for the gun, trait is not necessary if ( pSoldier->HasMortar() ) { // Add bars iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos + 20 ), (INT16)(sYPos + 20 ) ); if ( iBack != -1 ) { SetBackgroundRectFilled( iBack ); } BltVideoObjectFromIndex( FRAME_BUFFER, guiENEMYROLES, 4, sXPos, sYPos, VO_BLT_TRANSSHADOW, NULL ); sYPos += 20; } return true; }