/*============================================================================= Name : mouse.c Purpose : Hardware abstraction for the mouse. Created 6/26/1997 by lmoloney Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #define WIN32_LEAN_AND_MEAN #include #include "DDDFrigate.h" #include "debug.h" #include "dock.h" #include "font.h" #include "fontreg.h" #include "glinc.h" #include "globals.h" #include "GravWellGenerator.h" #include "main.h" #include "mainrgn.h" #include "mouse.h" #include "nis.h" #include "prim2d.h" #include "select.h" #include "sensors.h" #include "shipselect.h" #include "soundevent.h" #include "spaceobj.h" #include "texreg.h" #include "tweak.h" #include "types.h" #include "universe.h" #include "utility.h" #include "CommandWrap.h" #include "strings.h" #include "demo.h" #include "feflow.h" #include "researchGUI.h" #include "glcaps.h" #include "render.h" #include "tutor.h" #include "singleplayer.h" #include "glcompat.h" #include "KeyBindings.h" #include "InfoOverlay.h" #include "devstats.h" #define GLC_STORE 1 extern udword gDevcaps2; /*============================================================================= Local Type Definitions: =============================================================================*/ //flag settings #define MCF_SpecialOp 0x00000001 //has a special operation #define MCF_SpecialOpDeployed 0x00000002 //has a special operation already deployed #define MCF_Dockable 0x00000004 //can dock (big ship) #define MCF_SmallDockable 0x00000008 //can dock (small ship) #define MCF_GUICapable 0x00000010 //is associated with a GUI #define MCF_NonCombat 0x00000020 //ship is non combat ship #define MCF_SupportOverItself 0x00000040 //the mouse is over a selected repair corvette #define MCF_SingleClickSpecialActivate 0x00000080 //selection includes 1 or more single-click special activate ships #define MCF_DisableAll 0x00000100 //disable all cursor bitmaps #define MCF_DisableMovementMech 0x00000200 //disable cursors when movement pie plate is activated #define MCF_ShipSelecting 0x00001000 //ships are being selected #define MCF_BuildGUI 0x00002000 //ship opens the build manager #define MCF_SensorsGUI 0x00004000 //ship opens the sensors manager #define MCF_ResearchGUI 0x00008000 //ship opens the research manager #define MCF_SpecialAttack 0x00010000 //ship has a special attack #define MCF_SpecialSCSupport 0x00020000 //ship has a special support function for strikecraft #define MCF_SpecialSupport 0x00040000 //ship has a special support function #define MCF_SalvageOnly 0x00080000 //shiplist only contains salvage ships #define MCF_Salvage 0x00100000 //shiplist contains at least one salvage ship typedef struct { udword ship_selected; udword resource; udword flags; mouseCursor cursorover; } mouseInfoType; /*============================================================================= Data: =============================================================================*/ //we don't want the player to be able to salvage cryotrays in mission1 //so we need to include singlePlayerGameInfo extern SinglePlayerGameInfo singlePlayerGameInfo; //extern void (*mrHoldRight)(void); sdword mouseCursorXPosition, mouseCursorYPosition; uword mouseButtons; udword mouseModuleInit; rectangle mouseClipRect; bool8 mouseClip = FALSE; bool8 mouseIsVisible = TRUE; uword mouseWillBeVisible = 0; bool8 mouseDisabled = FALSE; uword mouseInsideClient = FALSE; static bool mouseGLInitialized; mouseCursor mouseCursorType = normal_mouse; udword mouseCursorMode = 0; MaxSelection mouseCursorSelect; real32 mouseDoubleClickTime = 0.0; real32 mouseDoubleClickExpire = REALlyBig; real32 mouseCursorOverDistance = REALlyBig; sdword mouseCursorOverShipType = MC_NO_SHIP; sdword mouseCursorEnemyType = -1; sdword mouseCursorEnemyPlayer = 1; real32 mouseCursorTextExpire = 0.0f; SpaceObj *mouseCursorObjPtr = NULL; SpaceObj *mouseCursorObjLast = NULL; real32 mouseCursorLastObjTime = REALlyNegative; sdword mouseCursorLastX = SDWORD_Max; sdword mouseCursorLastY = SDWORD_Max; ubyte mouseCursorOverLODs = 0; //cursor colors static color mouseCursorContentColor = MC_ContentColor; static color mouseCursorEdgeColor = MC_EdgeColor; //cursor font fonthandle mouseCursorFont = 0; //cursor bitmaps static lifheader *mouseNormalBitmap = NULL; static lifheader *mouseAddShipsBitmap = NULL; static lifheader *mouseFocusNoSelectBitmap = NULL; static lifheader *mouseMovementBitmap = NULL; static lifheader *mouseBandBoxAttackBitmap = NULL; static lifheader *mouseForceAttackBitmap = NULL; static lifheader *mouseGuardBitmap = NULL; static lifheader *mouseSpecialAttackBitmap = NULL; static lifheader *mouseSpecialOpActivateBitmap = NULL; static lifheader *mouseSpecialOpDeactivateBitmap = NULL; static lifheader *mouseGUIBitmap = NULL; static lifheader *mouseResourceBitmap = NULL; static lifheader *mouseDockingBitmap = NULL; static lifheader *mouseResearchBitmap = NULL; static lifheader *mouseSensorsBitmap = NULL; static lifheader *mouseBuildBitmap = NULL; static lifheader *mouseSalvageBitmap = NULL; static lifheader *mouseSupportBitmap = NULL; static lifheader *mouseTradersBitmap = NULL; static GLuint tex_Normal = 0; static GLuint tex_AddShips = 0; static GLuint tex_FocusNoSelect = 0; static GLuint tex_Movement = 0; static GLuint tex_BandBoxAttack = 0; static GLuint tex_ForceAttack = 0; static GLuint tex_Guard = 0; static GLuint tex_SpecialAttack = 0; static GLuint tex_SpecialOpActivate = 0; static GLuint tex_SpecialOpDeactivate = 0; static GLuint tex_GUI = 0; static GLuint tex_Resource = 0; static GLuint tex_Docking = 0; static GLuint tex_Research = 0; static GLuint tex_Sensors = 0; static GLuint tex_Build = 0; static GLuint tex_Salvage = 0; static GLuint tex_Support = 0; static GLuint tex_Traders = 0; static mouseInfoType mouseInfo = {0, 0, 0, MC_NO_SHIP}; /*============================================================================= Functions: =============================================================================*/ // ============================================================================ // Utility functions // ============================================================================ /*----------------------------------------------------------------------------- Name : mouseMirrorBitmap Description : Flips a bitmap 180 degrees Inputs : bitmap - pointer to the bitmap data width - width of the bitmap height - height of the bitmap Outputs : replaces "bitmap" with a bitmap flipped 90 degrees clockwise Return : ----------------------------------------------------------------------------*/ #define PIXEL(bm, x, y, offset, width) bm[((x) + (y)*(width))+(offset)] void mouseMirrorBitmap(udword *bitmap, sdword width, sdword height) { udword i, j; udword new_bitmap[1024]; for (i = 0; i < (udword)width; i++) { for (j = 0; j < (udword)height; j++) { PIXEL(new_bitmap, i, (height - 1) - j, 0, width) = PIXEL(bitmap, i, j, 0, width); } } memcpy(bitmap,new_bitmap,sizeof(udword)*width*height); } #undef PIXEL /*----------------------------------------------------------------------------- Name : mouseCreateGLHandle Description : creates a GL texture object for a given liff Inputs : lif - the lifheader structure of the bitmap thandle - target for the texture name Outputs : thandle contains the texture name Return : ----------------------------------------------------------------------------*/ void mouseCreateGLHandle(lifheader* lif, GLuint* thandle) { sdword y; ubyte* data; ubyte* sp; ubyte* dp; data = (ubyte*)memAlloc(4 * lif->width * lif->height, "temp mouse texture", 0); for (y = 0; y < lif->height; y++) { dp = data + 4 * lif->width * (lif->height - y - 1); sp = lif->data + 4 * lif->width * y; memcpy(dp, sp, 4 * lif->width); } if (*thandle != 0) { glDeleteTextures(1, thandle); } trClearCurrent(); glGenTextures(1, thandle); glBindTexture(GL_TEXTURE_2D, *thandle); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lif->width, lif->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); memFree(data); } // ============================================================================ // Mouse functions // ============================================================================ /*----------------------------------------------------------------------------- Name : mouseStartup Description : Start the mouse module Inputs : void Outputs : sets the mouse position by getting information from the Windows mouse system. Return : OKAY ----------------------------------------------------------------------------*/ sdword mouseStartup(void) { RECT clientRect, windowRect; POINT mousePoint; GetWindowRect(ghMainWindow, &windowRect); GetClientRect(ghMainWindow, &clientRect); //get location of window GetCursorPos(&mousePoint); //get location of Windows mouse cursor mouseCursorXPosition = mousePoint.x - windowRect.left; //compute relative coords mouseCursorYPosition = mousePoint.y - windowRect.top; mouseNormalBitmap = trLIFFileLoad(MC_NORMAL_BM, NonVolatile); mouseAddShipsBitmap = trLIFFileLoad(MC_ADD_SHIPS_BM, NonVolatile); mouseFocusNoSelectBitmap = trLIFFileLoad(MC_FOCUS_NO_SELECT_BM, NonVolatile); mouseBandBoxAttackBitmap = trLIFFileLoad(MC_BAND_BOX_ATTACK_BM, NonVolatile); mouseForceAttackBitmap = trLIFFileLoad(MC_FORCE_ATTACK_BM, NonVolatile); mouseGuardBitmap = trLIFFileLoad(MC_GUARD_BM, NonVolatile); mouseSpecialAttackBitmap = trLIFFileLoad(MC_SPECIAL_ATTACK_BM, NonVolatile); mouseSpecialOpActivateBitmap = trLIFFileLoad(MC_SPECIAL_OP_ACTIVATE_BM, NonVolatile); mouseSpecialOpDeactivateBitmap = trLIFFileLoad(MC_SPECIAL_OP_DEACTIVATE_BM, NonVolatile); mouseGUIBitmap = trLIFFileLoad(MC_GUI_BM, NonVolatile); mouseResourceBitmap = trLIFFileLoad(MC_RESOURCE_BM, NonVolatile); mouseDockingBitmap = trLIFFileLoad(MC_DOCKING_BM, NonVolatile); mouseResearchBitmap = trLIFFileLoad(MC_RESEARCH_BM, NonVolatile); mouseSensorsBitmap = trLIFFileLoad(MC_SENSORS_BM, NonVolatile); mouseBuildBitmap = trLIFFileLoad(MC_BUILD_BM, NonVolatile); mouseSalvageBitmap = trLIFFileLoad(MC_SALVAGE_BM, NonVolatile); mouseSupportBitmap = trLIFFileLoad(MC_SUPPORT_BM, NonVolatile); mouseTradersBitmap = trLIFFileLoad(MC_TRADERS_BM, NonVolatile); mouseMirrorBitmap((udword *)mouseNormalBitmap->data, mouseNormalBitmap->width, mouseNormalBitmap->height); mouseMirrorBitmap((udword *)mouseAddShipsBitmap->data, mouseAddShipsBitmap->width, mouseAddShipsBitmap->height); mouseMirrorBitmap((udword *)mouseFocusNoSelectBitmap->data, mouseFocusNoSelectBitmap->width, mouseFocusNoSelectBitmap->height); mouseMirrorBitmap((udword *)mouseBandBoxAttackBitmap->data, mouseBandBoxAttackBitmap->width, mouseBandBoxAttackBitmap->height); mouseMirrorBitmap((udword *)mouseForceAttackBitmap->data, mouseForceAttackBitmap->width, mouseForceAttackBitmap->height); mouseMirrorBitmap((udword *)mouseGuardBitmap->data, mouseGuardBitmap->width, mouseGuardBitmap->height); mouseMirrorBitmap((udword *)mouseSpecialAttackBitmap->data, mouseSpecialAttackBitmap->width, mouseSpecialAttackBitmap->height); mouseMirrorBitmap((udword *)mouseSpecialOpActivateBitmap->data, mouseSpecialOpActivateBitmap->width, mouseSpecialOpActivateBitmap->height); mouseMirrorBitmap((udword *)mouseSpecialOpDeactivateBitmap->data, mouseSpecialOpDeactivateBitmap->width, mouseSpecialOpDeactivateBitmap->height); mouseMirrorBitmap((udword *)mouseGUIBitmap->data, mouseGUIBitmap->width, mouseGUIBitmap->height); mouseMirrorBitmap((udword *)mouseResourceBitmap->data, mouseResourceBitmap->width, mouseResourceBitmap->height); mouseMirrorBitmap((udword *)mouseDockingBitmap->data, mouseDockingBitmap->width, mouseDockingBitmap->height); mouseMirrorBitmap((udword *)mouseResearchBitmap->data, mouseResearchBitmap->width, mouseResearchBitmap->height); mouseMirrorBitmap((udword *)mouseSensorsBitmap->data, mouseSensorsBitmap->width, mouseSensorsBitmap->height); mouseMirrorBitmap((udword *)mouseBuildBitmap->data, mouseBuildBitmap->width, mouseBuildBitmap->height); mouseMirrorBitmap((udword *)mouseSalvageBitmap->data, mouseSalvageBitmap->width, mouseSalvageBitmap->height); mouseMirrorBitmap((udword *)mouseSupportBitmap->data, mouseSupportBitmap->width, mouseSupportBitmap->height); mouseMirrorBitmap((udword *)mouseTradersBitmap->data, mouseTradersBitmap->width, mouseTradersBitmap->height); mouseDoubleClickTime = GetDoubleClickTime() / 1000.0f; mouseCursorFont = frFontRegister(TW_CURSORTEXT_FONT); mouseGLInitialized = FALSE; return(OKAY); } /*----------------------------------------------------------------------------- Name : mouseInitGL Description : initialize the GL texture handles for mouse bitmaps Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void mouseInitGL(void) { mouseCreateGLHandle(mouseNormalBitmap, &tex_Normal); mouseCreateGLHandle(mouseAddShipsBitmap, &tex_AddShips); mouseCreateGLHandle(mouseFocusNoSelectBitmap, &tex_FocusNoSelect); mouseCreateGLHandle(mouseBandBoxAttackBitmap, &tex_BandBoxAttack); mouseCreateGLHandle(mouseForceAttackBitmap, &tex_ForceAttack); mouseCreateGLHandle(mouseGuardBitmap, &tex_Guard); mouseCreateGLHandle(mouseSpecialAttackBitmap, &tex_SpecialAttack); mouseCreateGLHandle(mouseSpecialOpActivateBitmap, &tex_SpecialOpActivate); mouseCreateGLHandle(mouseSpecialOpDeactivateBitmap, &tex_SpecialOpDeactivate); mouseCreateGLHandle(mouseGUIBitmap, &tex_GUI); mouseCreateGLHandle(mouseResourceBitmap, &tex_Resource); mouseCreateGLHandle(mouseDockingBitmap, &tex_Docking); mouseCreateGLHandle(mouseResearchBitmap, &tex_Research); mouseCreateGLHandle(mouseSensorsBitmap, &tex_Sensors); mouseCreateGLHandle(mouseBuildBitmap, &tex_Build); mouseCreateGLHandle(mouseSalvageBitmap, &tex_Salvage); mouseCreateGLHandle(mouseSupportBitmap, &tex_Support); mouseCreateGLHandle(mouseTradersBitmap, &tex_Traders); } /*----------------------------------------------------------------------------- Name : mouseReset Description : reset mouse module (delete associated GL texture objects) Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void mouseReset(void) { if (mouseGLInitialized) { glDeleteTextures(1, &tex_Normal); glDeleteTextures(1, &tex_AddShips); glDeleteTextures(1, &tex_FocusNoSelect); glDeleteTextures(1, &tex_BandBoxAttack); glDeleteTextures(1, &tex_ForceAttack); glDeleteTextures(1, &tex_Guard); glDeleteTextures(1, &tex_SpecialAttack); glDeleteTextures(1, &tex_SpecialOpActivate); glDeleteTextures(1, &tex_SpecialOpDeactivate); glDeleteTextures(1, &tex_GUI); glDeleteTextures(1, &tex_Resource); glDeleteTextures(1, &tex_Docking); glDeleteTextures(1, &tex_Research); glDeleteTextures(1, &tex_Sensors); glDeleteTextures(1, &tex_Build); glDeleteTextures(1, &tex_Salvage); glDeleteTextures(1, &tex_Support); glDeleteTextures(1, &tex_Traders); tex_Normal = 0; tex_AddShips = 0; tex_FocusNoSelect = 0; tex_BandBoxAttack = 0; tex_ForceAttack = 0; tex_Guard = 0; tex_SpecialAttack = 0; tex_SpecialOpActivate = 0; tex_SpecialOpDeactivate = 0; tex_GUI = 0; tex_Resource = 0; tex_Docking = 0; tex_Research = 0; tex_Sensors = 0; tex_Build = 0; tex_Salvage = 0; tex_Support = 0; tex_Traders = 0; mouseGLInitialized = FALSE; } } /*----------------------------------------------------------------------------- Name : mouseShutdown Description : Close mouse module Inputs : void Outputs : not much Return : void ----------------------------------------------------------------------------*/ void mouseShutdown(void) { mouseReset(); } /*----------------------------------------------------------------------------- Name : mouseCursorHide Description : Show the cursor if it is hidden Inputs : void Outputs : sets the visibility flag to TRUE. Subsequent mouse mouseDraw() calls will not display a visible cursor. Return : void ----------------------------------------------------------------------------*/ void mouseCursorHide(void) { mouseIsVisible = FALSE; } /*----------------------------------------------------------------------------- Name : mouseCursorShow Description : Show the cursor if it is hidden Inputs : void Outputs : sets the visibility flag to TRUE. Subsequent mouse mouseDraw() calls will not display a visible cursor. Return : void ----------------------------------------------------------------------------*/ void mouseCursorShow(void) { mouseIsVisible = TRUE; } void mouseCursorDelayShow(uword delay) { mouseWillBeVisible = delay+1; } /*----------------------------------------------------------------------------- Name : mousePositionSet Description : Set new mouse position. Inputs : x, y - new location of mouse. May be clamped to the edge of the window. Outputs : Sets the Windows cursor location and the internal cursor location. Return : void ----------------------------------------------------------------------------*/ void mousePositionSet(sdword x, sdword y) { rectangle clientRect; // RECT clientRect, windowRect; POINT mousePoint; utyClientRectGet(&clientRect); //get window location // GetWindowRect(ghMainWindow, &windowRect); // GetClientRect(ghMainWindow, &clientRect); //get location of window #if MOUSE_CURSOR_CLAMP //clamp specified mouse location if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x >= clientRect.x1 - clientRect.x0) { x = clientRect.x1 - clientRect.x0 - 1; } if (y >= clientRect.y1 - clientRect.y0) { y = clientRect.y1 - clientRect.y0 - 1; } #endif mouseCursorXPosition = x; //set internal mouse location mouseCursorYPosition = y; mousePoint.x = clientRect.x0 + x; //compute Windows mouse location mousePoint.y = clientRect.y0 + y; SetCursorPos(mousePoint.x, mousePoint.y); //set Windows mouse location } /*----------------------------------------------------------------------------- Name : mouseClipToRect Description : Clips the mouse to a given rectangle. Inputs : rect - rectangle to clip to. NULL means no rectangle. Outputs : Return : ----------------------------------------------------------------------------*/ void mouseClipToRect(rectangle *rect) { if (rect == NULL) { mouseClip = FALSE; } else { mouseClip = TRUE; mouseClipRect = *rect; } } /*----------------------------------------------------------------------------- Name : mouseLDoubleClick Description : Processes a double click on the left mouse button Inputs : void Outputs : Very specific depending on the state of mouseInfo Return : TRUE if some processing has been done (overrides the processing for a single left click) FALSE if no processing was done (processing for the single left click continues) ----------------------------------------------------------------------------*/ bool mouseLDoubleClick(void) { MaxSelection tempSelection; //if a menu is up, don't do any of this // if (feStackIndex > 0) // { // if (rmGUIActive) // { // return TRUE; // } // else // { // return FALSE; // } // } //**** big chunks taken out because this function is being called // from mainrgn now. // if (bitTest(mouseCursorMode, MCM_SingleClick)) // { // if (bitTest(mouseCursorMode, MCM_DoubleClick)) // { // bitClear(mouseCursorMode, MCM_DoubleClick); // bitClear(mouseCursorMode, MCM_SingleClick); // mouseCursorSelect.numShips = 0; // } // else // { // bitSet(mouseCursorMode, MCM_DoubleClick); // mouseDoubleClickExpire = universe.totaltimeelapsed + mouseDoubleClickTime; // return FALSE; // } // } if (selSelected.numShips) { #if !MR_GUI_SINGLECLICK // if (bitTest(mouseInfo.flags, MCF_BuildGUI)) // { // tutGameMessage("Game_DoubleClickBuild"); // cmConstructionBegin(ghMainRegion,(sdword)selSelected.ShipPtr[0], 0, 0); // return TRUE; // } // else if (bitTest(mouseInfo.flags, MCF_SensorsGUI)) // { // tutGameMessage("Game_DoubleClickSensors"); // smSensorsBegin(NULL, NULL); // return TRUE; // } // else if (bitTest(mouseInfo.flags, MCF_ResearchGUI)) // { // tutGameMessage("Game_DoubleClickResearch"); // rmResearchGUIBegin(ghMainRegion,(sdword)selSelected.ShipPtr[0], 0, 0); // } // else #endif !MR_GUI_SINGLECLICK // if (ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, RepairCorvette) || // ((ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, AdvanceSupportFrigate) || // ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, Carrier)) && // (mouseCursorObjPtr && // (isShipOfClass((Ship *)mouseCursorObjPtr, CLASS_Fighter) || // isShipOfClass((Ship *)mouseCursorObjPtr, CLASS_Corvette))))) if (mouseCursorObjPtr && // if there's an object being clicked on ((isShipOfClass((Ship *)mouseCursorObjPtr, CLASS_Fighter) || // Carriers only support strikecraft isShipOfClass((Ship *)mouseCursorObjPtr, CLASS_Corvette)) && ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, Carrier)) || (ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, RepairCorvette) || ShiptypeInSelection((SelectCommand *)&mouseCursorSelect, AdvanceSupportFrigate))) { // make a backup of mouseCursorSelect tempSelection.numShips = 0; selSelectionCopy((MaxAnySelection *)&tempSelection, (MaxAnySelection *)&mouseCursorSelect); MakeShipsSpecialTargetCapable((SelectCommand *)&mouseCursorSelect,TRUE); MakeShipsNotIncludeTheseShips((SelectCommand *)&mouseCursorSelect, (SelectCommand *)&selSelected); if (mouseCursorSelect.numShips > 0) { SelectCommand sel; selSelectionCopy((MaxAnySelection *)&selSelected, (MaxAnySelection *)&mouseCursorSelect); ioUpdateShipTotals(); if (mouseCursorSelect.numShips < tempSelection.numShips) { // the selection being activated has other ships as well tutGameMessage("Game_DoubleClickSpecial"); sel.numShips = 1; sel.ShipPtr[0] = (Ship *)mouseCursorObjPtr; clWrapSpecial(&universe.mainCommandLayer, (SelectCommand *)&mouseCursorSelect, (SpecialCommand *)&sel); selSelectionCopy((MaxAnySelection *)&mouseCursorSelect, (MaxAnySelection *)&tempSelection); return FALSE; //we may not be done... } else { // the selection being activated only contains support ships mouseCursorSelect.numShips = 0; tutGameMessage("Game_DoubleClickSpecial"); sel.numShips = 1; sel.ShipPtr[0] = (Ship *)mouseCursorObjPtr; clWrapSpecial(&universe.mainCommandLayer, (SelectCommand *)&selSelected,(SpecialCommand *)&sel); return TRUE; } } bitClear(mouseCursorMode, MCM_DoubleClick); bitClear(mouseCursorMode, MCM_SingleClick); } if (bitTest(mouseInfo.flags, MCF_SpecialOp)) { MakeShipsSpecialActivateCapable((SelectCommand *)&mouseCursorSelect); if (mouseCursorSelect.numShips > 0) { selSelectionCopy((MaxAnySelection *)&selSelected, (MaxAnySelection *)&mouseCursorSelect); ioUpdateShipTotals(); mouseCursorSelect.numShips = 0; tutGameMessage("Game_DoubleClickSpecial"); clWrapSpecial(&universe.mainCommandLayer, (SelectCommand *)&selSelected,NULL); return TRUE; } bitClear(mouseCursorMode, MCM_DoubleClick); bitClear(mouseCursorMode, MCM_SingleClick); } } // else if ((mouseCursorObjPtr != NULL) && // (mouseCursorObjPtr->objtype != OBJ_ShipType)) // { // if (mouseCursorSelect.numShips > 0) // { // selSelectionCopy((MaxAnySelection *)&selSelected, // (MaxAnySelection *)&mouseCursorSelect); // mouseCursorSelect.numShips = 0; // tutGameMessage("Game_DoubleClickHarvest"); // clWrapCollectResource(&universe.mainCommandLayer, (SelectCommand *)&selSelected, (Resource*)mouseCursorObjPtr); // } // return TRUE; // } return FALSE; } /*----------------------------------------------------------------------------- Name : mouseDoubleClickCheck Description : Check to see if the double click time has expired and performs special tasks if it has Inputs : void Outputs : Very specific depending on the state of mouseInfo Return : TRUE if processing was done, FALSE if not ----------------------------------------------------------------------------*/ bool mouseDoubleClickCheck(void) { if (mouseDoubleClickExpire == 0.0) { return FALSE; } if (mouseDoubleClickExpire < universe.totaltimeelapsed) { if (bitTest(mouseCursorMode, MCM_DoubleClick)) { bitClear(mouseCursorMode, MCM_DoubleClick); bitClear(mouseCursorMode, MCM_SingleClick); mouseDoubleClickExpire = 0.0; if (mouseCursorObjPtr != NULL) { if (mouseCursorSelect.numShips > 0) { selSelectionCopy((MaxAnySelection *)&selSelected, (MaxAnySelection *)&mouseCursorSelect); mouseCursorSelect.numShips = 0; makeShipsDockCapable((SelectCommand *)&selSelected); //filter ships that can't dock clWrapDock(&universe.mainCommandLayer, (SelectCommand *)&selSelected, DOCK_AT_SPECIFIC_SHIP, (Ship *)mouseCursorObjPtr); mouseDrawType(small_docking); //may need to have "docking" as well } return TRUE; } } mouseCursorSelect.numShips = 0; mouseDoubleClickExpire = 0.0; bitClear(mouseCursorMode, MCM_SingleClick); } return FALSE; } /*----------------------------------------------------------------------------- Name : mouseLClick Description : Special processing a single click on the left mouse button Inputs : void Outputs : Very specific depending on the state of mouseInfo Return : void ----------------------------------------------------------------------------*/ void mouseLClick(void) { //if a menu is up, don't do any of this if (feStackIndex > 0) { return; } if (!bitTest(mouseCursorMode, MCM_SingleClick)) { if ((mouseCursorType == docking) || (mouseCursorType == small_docking)) { selSelectionCopy((MaxAnySelection *)&mouseCursorSelect, (MaxAnySelection *)&selSelected); bitSet(mouseCursorMode, MCM_SingleClick); mouseDoubleClickExpire = universe.totaltimeelapsed + mouseDoubleClickTime; } else if ((mouseCursorType == special_op_activate) || (mouseCursorType == special_op_deactivate)) { selSelectionCopy((MaxAnySelection *)&mouseCursorSelect, (MaxAnySelection *)&selSelected); mouseDoubleClickExpire = universe.totaltimeelapsed + mouseDoubleClickTime; } else if (mouseCursorType == support) { selSelectionCopy((MaxAnySelection *)&mouseCursorSelect, (MaxAnySelection *)&selSelected); mouseDoubleClickExpire = universe.totaltimeelapsed + mouseDoubleClickTime; } } } /*----------------------------------------------------------------------------- Name : mouseClickShipDied Description : Takes care of ships dying at inopportune times by clearing the ship from any file global selection lists or storage areas Inputs : deadship - the ship that has just died Outputs : removes the ship from mouseCursorSelect and the mouseCursorObjPtr Return : void ----------------------------------------------------------------------------*/ void mouseClickShipDied(ShipPtr deadship) { clRemoveShipFromSelection(&mouseCursorSelect, deadship); if ((mouseCursorObjPtr != NULL) && (mouseCursorObjPtr == (SpaceObj *)deadship)) { mouseCursorObjPtr = NULL; } if (mouseCursorObjLast == (SpaceObj *)deadship) { mouseCursorObjLast = NULL; } } /*----------------------------------------------------------------------------- Name : mouseDrawTriangle Description : Draws the mouse triangle on the screen Inputs : void Outputs : Draws the mouse triangle on the screen Return : void ----------------------------------------------------------------------------*/ void mouseDrawTriangle(void) { triangle mouseTri, mouseTri2; mouseTri.x0 = mouseCursorXPosition + 0; mouseTri.y0 = mouseCursorYPosition + 0; mouseTri.x1 = mouseCursorXPosition + 4; mouseTri.y1 = mouseCursorYPosition + 16; mouseTri.x2 = mouseCursorXPosition + 14; mouseTri.y2 = mouseCursorYPosition + 7; mouseTri2 = mouseTri; mouseTri2.x2++; primTriSolid2(&mouseTri2, mouseCursorContentColor); //draw mouse cursor primTriOutline2(&mouseTri, 1, mouseCursorEdgeColor); } /*----------------------------------------------------------------------------- Name : mouseInfoReset Description : Resets the mouseInfo structure Inputs : void Outputs : Resets the mouseInfo structure Return : void ----------------------------------------------------------------------------*/ void mouseInfoReset(void) { mouseInfo.ship_selected = 0; mouseInfo.resource = 0; mouseInfo.flags = 0; mouseInfo.cursorover = MC_NO_SHIP; } lifheader* mouseGetLIF(void) { switch (mouseCursorType) { case no_mouse: case rotate_camera: case zoom_camera: return NULL; case normal_mouse: case movement: return mouseNormalBitmap; case add_ships: return mouseAddShipsBitmap; case focus_no_select: return mouseFocusNoSelectBitmap; case band_box_attack: return mouseBandBoxAttackBitmap; case force_attack: return mouseForceAttackBitmap; case m_guard: return mouseGuardBitmap; case special_attack: return mouseSpecialAttackBitmap; case special_op_activate: return mouseSpecialOpActivateBitmap; case special_op_deactivate: return mouseSpecialOpDeactivateBitmap; case gui: return mouseGUIBitmap; case resource: return mouseResourceBitmap; case docking: case small_docking: return mouseDockingBitmap; case research: return mouseResearchBitmap; case sensors: return mouseSensorsBitmap; case build: return mouseBuildBitmap; case salvage: return mouseSalvageBitmap; case support: return mouseSupportBitmap; case traders: return mouseTradersBitmap; default: return NULL; } } GLubyte cursorUnderContents[4096]; sdword lastUnderWidth = 0, lastUnderHeight = 0; static sdword lastUnderX = 0, lastUnderY = 0; void mouseRestoreCursorUnder(void) { if (!feShouldSaveMouseCursor()) { return; } if (RGLtype == SWtype) { rglRestoreCursorUnder(cursorUnderContents, lastUnderWidth, lastUnderHeight, lastUnderX, lastUnderY); } #if GLC_STORE else { glcCursorUnder((ubyte*)cursorUnderContents, lastUnderWidth, lastUnderHeight, lastUnderX, lastUnderY, FALSE); } #endif } void mouseStoreCursorUnder(void) { lifheader* texture; if (!feShouldSaveMouseCursor()) { return; } texture = mouseGetLIF(); if (texture == NULL) { memset(cursorUnderContents, 0, 4096); } else { lastUnderWidth = texture->width + 2; lastUnderHeight = texture->height + 2; if (RGLtype == SWtype) { lastUnderX = mouseCursorXPosition - 1; lastUnderY = mouseCursorYPosition - 1; rglSaveCursorUnder(cursorUnderContents, lastUnderWidth, lastUnderHeight, lastUnderX, lastUnderY); } #if GLC_STORE else { lastUnderX = mouseCursorXPosition; lastUnderY = mouseCursorYPosition; glcCursorUnder((ubyte*)cursorUnderContents, lastUnderWidth, lastUnderHeight, lastUnderX, lastUnderY, TRUE); } #endif } } /*----------------------------------------------------------------------------- Name : mouseDraw Description : Update the position of the mouse by polling the system and draw it at it's new location. Inputs : void Outputs : updates mouse cursor position and button states to reflect new mouse status. Return : void Note : because this routine performs drawing operations, it should be called near the end rendering, before a buffer swap. Checks to see if the mouse is inside or outside the client area ----------------------------------------------------------------------------*/ extern regionhandle spHyperspaceRollCallScreen; #define SX primScreenToGLX #define SY primScreenToGLY void mouseDraw(void) { bool primModeOn = TRUE; lifheader *texture = NULL; GLuint thandle = 0; bool textureMouse; static mouseCursor mousehold = normal_mouse; static real32 mouseholdexpire = 0.0; if (mouseWillBeVisible > 0) { mouseWillBeVisible--; if (!mouseWillBeVisible) mouseIsVisible = TRUE; } if ((!mouseIsVisible) || (mouseDisabled)) { return; //don't draw mouse if not visible } // glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_POLYGON_BIT | GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_HINT_BIT | GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT); //rndGLStateLog("MouseDraw (start)"); if (RGLtype == SWtype) { textureMouse = FALSE; } else { textureMouse = TRUE;//!glcActive(); } if (textureMouse && !mouseGLInitialized) { mouseInitGL(); mouseGLInitialized = TRUE; } //mousePoll(); if (!primModeEnabled) { primModeOn = FALSE; primModeSetFunction2(); } glEnable(GL_BLEND); rndAdditiveBlends(FALSE); rndTextureEnvironment(RTE_Modulate); if ((mousehold != normal_mouse) && (mouseCursorType == normal_mouse)) { if (mouseholdexpire >= universe.totaltimeelapsed) { mouseCursorType = mousehold; } else //mousehold has expired { mousehold = normal_mouse; } } //if a front end screen is on (but not the hyperspace roll call screen) //all mouse settings are overridden //if the movement pieplate is on, all mouse settings except for // the focus_no_select setting is overridden if (((feStackIndex > 0) && (!spHyperspaceRollCallScreen)) || ((bitTest(mouseCursorMode, MCM_Pointmode)) && (mouseCursorType != focus_no_select))) { mouseCursorType = normal_mouse; } switch (mouseCursorType) { case no_mouse: case rotate_camera: case zoom_camera: //temporary solution goto finish; //do nothing break; case normal_mouse: case movement: texture = mouseNormalBitmap; thandle = tex_Normal; break; case add_ships: texture = mouseAddShipsBitmap; thandle = tex_AddShips; break; case focus_no_select: texture = mouseFocusNoSelectBitmap; thandle = tex_FocusNoSelect; break; case band_box_attack: texture = mouseBandBoxAttackBitmap; thandle = tex_BandBoxAttack; break; case force_attack: texture = mouseForceAttackBitmap; thandle = tex_ForceAttack; break; case m_guard: texture = mouseGuardBitmap; thandle = tex_Guard; break; case special_attack: if (mousehold == normal_mouse) { mousehold = special_attack; mouseholdexpire = universe.totaltimeelapsed + (real32)MC_MOUSEHOLDTIME; } texture = mouseSpecialAttackBitmap; thandle = tex_SpecialAttack; break; case special_op_activate: texture = mouseSpecialOpActivateBitmap; thandle = tex_SpecialOpActivate; break; case special_op_deactivate: texture = mouseSpecialOpDeactivateBitmap; thandle = tex_SpecialOpDeactivate; break; case gui: texture = mouseGUIBitmap; thandle = tex_GUI; break; case resource: texture = mouseResourceBitmap; thandle = tex_Resource; break; case docking: case small_docking: texture = mouseDockingBitmap; thandle = tex_Docking; break; case research: texture = mouseResearchBitmap; thandle = tex_Research; break; case sensors: texture = mouseSensorsBitmap; thandle = tex_Sensors; break; case build: texture = mouseBuildBitmap; thandle = tex_Build; break; case salvage: texture = mouseSalvageBitmap; thandle = tex_Salvage; break; case support: texture = mouseSupportBitmap; thandle = tex_Support; break; case traders: texture = mouseTradersBitmap; thandle = tex_Traders; break; default: break; } if (texture != NULL) { if (textureMouse) { bool texOn; trClearCurrent(); texOn = rndTextureEnable(TRUE); glBindTexture(GL_TEXTURE_2D, thandle); glColor3ub(255,255,255); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex2f(SX(mouseCursorXPosition), SY(mouseCursorYPosition)); glTexCoord2f(0.0f, 1.0f); glVertex2f(SX(mouseCursorXPosition), SY(mouseCursorYPosition + texture->height)); glTexCoord2f(1.0f, 1.0f); glVertex2f(SX(mouseCursorXPosition + texture->width), SY(mouseCursorYPosition + texture->height)); glTexCoord2f(1.0f, 0.0f); glVertex2f(SX(mouseCursorXPosition + texture->width), SY(mouseCursorYPosition)); glEnd(); rndTextureEnable(texOn); } else { glRasterPos2f(primScreenToGLX(mouseCursorXPosition), primScreenToGLY(mouseCursorYPosition + texture->height)); glDrawPixels(texture->width, texture->height, GL_RGBA, GL_UNSIGNED_BYTE, texture->data); } } else { mouseDrawTriangle(); } finish: glDisable(GL_BLEND); if (!primModeOn) { primModeClearFunction2(); } mouseCursorOverDistance = REALlyBig; mouseCursorOverShipType = MC_NO_SHIP; if (bitTest(mouseCursorMode, MCM_CursorOverObj)) { bitClear(mouseCursorMode, MCM_CursorOverObj); } else { mouseCursorObjPtr = NULL; } if (mouseCursorObjPtr != NULL) { //if the mouse is over an object mouseCursorObjLast = mouseCursorObjPtr; //remember where and when it was mouseCursorLastObjTime = universe.totaltimeelapsed; mouseCursorLastX = mouseCursorX(); mouseCursorLastY = mouseCursorY(); } //rndGLStateLog("MouseDraw (end)"); // glPopAttrib(); } #undef SX #undef SY char *tutMouseDrawMessage[] = { "Mouse_NormalMouse", "Mouse_RotateCamera", "Mouse_ZoomCamera", "Mouse_AddShips", "Mouse_FocusNoSelect", "Mouse_Movement", "Mouse_BandBoxAttack", "Mouse_ForceAttack", "Mouse_Guard", "Mouse_SpecialAttack", "Mouse_SpecialOpActivate", "Mouse_SpecialOpDeactivate", "Mouse_Gui", "Mouse_Resource", "Mouse_Derelict", "Mouse_Docking", "Mouse_SmallDocking", "Mouse_Research", "Mouse_Sensors", "Mouse_Build", "Mouse_Salvage", "Mouse_Support", "Mouse_Traders", "Mouse_EnemyShip", "Mouse_AlliedShip", }; /*----------------------------------------------------------------------------- Name : mouseDrawType Description : Sets the type of mouse cursor to be drawn Inputs : cursorType - the type of cursor to draw Outputs : Changes the global mouse cursor type variable Return : void ----------------------------------------------------------------------------*/ void mouseDrawType(mouseCursor cursorType) { //mouse messages only happen in the actual tutorial because //the overflow the message queue in the single player game if((tutorial==TUTORIAL_ONLY) && cursorType != mouseCursorType) tutGameMessage( tutMouseDrawMessage[(long)cursorType] ); mouseCursorType = cursorType; } /*----------------------------------------------------------------------------- Name : mouseCursorSet Description : sets the cursor mode for special case cursor settings Inputs : mode - the mode to set cursormode to Outputs : changes the cursormode flag Return : void ----------------------------------------------------------------------------*/ void mouseCursorSet(udword mode) { bitSet(mouseCursorMode, mode); } /*----------------------------------------------------------------------------- Name : mouseCursorClear Description : Clears the cursor mode for special case cursor settings Inputs : mode - the mode to clear Outputs : changes the cursormode flag Return : void ----------------------------------------------------------------------------*/ void mouseCursorClear(udword mode) { bitClear(mouseCursorMode, mode); } /*----------------------------------------------------------------------------- Name : mouseSelectCursorSetting Description : Gathers information about the selected ships, and ships under the mouse cursor I agree this function is ugly, but you have to consider that any number of ships can be selected at one time, and the mouse can be over any of those ships, or any other ships. This function has to take care of all of that. Poor function... overworked, underpaid, ugly, unappreciated, just not having a good life. Be kind to it... Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void mouseSelectCursorSetting(void) { sdword i; mouseInfoReset(); //if there are ships selected if (selSelected.numShips) { Ship *ship; mouseInfo.ship_selected = selSelected.numShips; //go through the selected list for (i = 0; i < selSelected.numShips; i++) { ship = selSelected.ShipPtr[i]; //count the number of resource collectors selected if (ship->shiptype == ResourceCollector) { ++mouseInfo.resource; bitSet(mouseInfo.flags, MCF_Dockable); } if (ship->staticinfo->canSingleClickSpecialActivate) { bitSet(mouseInfo.flags, MCF_SingleClickSpecialActivate); } //-- Set flags for selected ships under the cursor --// //if the cursor is over a selected ship if ((mouseCursorObjPtr != NULL) && ((Ship *)mouseCursorObjPtr == selSelected.ShipPtr[i])) { //set flags for all GUI or special op ships switch (ship->shiptype) { case Carrier: case Mothership: bitSet(mouseInfo.flags, MCF_GUICapable); bitSet(mouseInfo.flags, MCF_BuildGUI); break; case ResearchShip: bitSet(mouseInfo.flags, MCF_GUICapable); bitSet(mouseInfo.flags, MCF_ResearchGUI); break; case SensorArray: bitSet(mouseInfo.flags, MCF_GUICapable); bitSet(mouseInfo.flags, MCF_SensorsGUI); break; case CloakGenerator: case CloakedFighter: if (bitTest(ship->flags, SOF_Cloaked)) { bitSet(mouseInfo.flags, MCF_SpecialOpDeployed); } bitSet(mouseInfo.flags, MCF_SpecialOp); break; case DDDFrigate: if (((DDDFrigateSpec *)ship->ShipSpecifics)->DDDstate == 3) //DDDSTATE_ALLOUTSIDE { bitSet(mouseInfo.flags, MCF_SpecialOpDeployed); } bitSet(mouseInfo.flags, MCF_SpecialOp); break; case GravWellGenerator: if (((GravWellGeneratorSpec *)ship->ShipSpecifics)->GravFieldOn == TRUE) { bitSet(mouseInfo.flags, MCF_SpecialOpDeployed); } bitSet(mouseInfo.flags, MCF_SpecialOp); break; case MinelayerCorvette: bitSet(mouseInfo.flags, MCF_SpecialOp); break; case AdvanceSupportFrigate: case RepairCorvette: //we don't want the dock cursor to show up when //the mouse is over a selected repair corvette bitSet(mouseInfo.flags, MCF_SupportOverItself); break; } } // -- Set flags for ships that are selected but not under the cursor -- // //set flags for dockable ships if ((ship->staticinfo->shipclass == CLASS_Corvette) || (ship->staticinfo->shipclass == CLASS_Fighter)) { if (ship->shiptype != RepairCorvette) { bitSet(mouseInfo.flags, MCF_SmallDockable); } else { bitSet(mouseInfo.flags, MCF_Dockable); } } else if ((ship->staticinfo->shipclass == CLASS_Resource) || (ship->staticinfo->shipclass == CLASS_NonCombat)) { bitSet(mouseInfo.flags, MCF_NonCombat); } //set flags for special attack/support ships switch (ship->shiptype) { case MissileDestroyer: case HeavyCorvette: bitSet(mouseInfo.flags, MCF_SpecialAttack); break; case Carrier: bitSet(mouseInfo.flags, MCF_SpecialSCSupport); break; case AdvanceSupportFrigate: case RepairCorvette: bitSet(mouseInfo.flags, MCF_SpecialSupport); break; case SalCapCorvette: bitSet(mouseInfo.flags, MCF_Salvage); //if this is the first ship in the list if (i==0) { bitSet(mouseInfo.flags, MCF_SalvageOnly); } break; } //the special salvage cursor bitmap is displayed //instead of the attack bitmap if selselected only contains //salvage capture corvettes... checking for this here if (i>0 && bitTest(mouseInfo.flags, MCF_SalvageOnly)) { if (ship->shiptype != SalCapCorvette) { bitClear(mouseInfo.flags, MCF_SalvageOnly); } } } //if there isn't anything under the cursor, then the rest of this //function isn't needed if (mouseCursorOverShipType == MC_NO_SHIP) { return; } //set cursorover variable depending on the ship under cursor and //the value of certain flags. switch (mouseCursorOverShipType) { case Carrier: case Mothership: if (bitTest(mouseInfo.flags, MCF_Dockable) || bitTest(mouseInfo.flags, MCF_SmallDockable)) { mouseInfo.cursorover = docking; } else { mouseInfo.cursorover = build; } break; case ResearchShip: mouseInfo.cursorover = research; break; case SensorArray: mouseInfo.cursorover = sensors; break; case ResourceController: mouseInfo.cursorover = docking; break; case CloakGenerator: case CloakedFighter: case DDDFrigate: case GravWellGenerator: case MinelayerCorvette: mouseInfo.cursorover = special_op_activate; break; //drone is not considered as a ship in this case case Drone: mouseInfo.cursorover = MC_NO_SHIP; break; case RepairCorvette: case ResourceCollector: case AdvanceSupportFrigate: case JunkYardHQ: mouseInfo.cursorover = small_docking; break; case CryoTray: if ((singlePlayerGameInfo.currentMission != 1) && (bitTest(mouseInfo.flags, MCF_SalvageOnly))) { mouseInfo.cursorover = salvage; } break; case FloatingCity: mouseInfo.cursorover = traders; break; case MC_DERELICT: if ((mouseCursorObjPtr) && (((Derelict *)mouseCursorObjPtr)->derelicttype == HyperspaceGate)) mouseInfo.cursorover = enemy_ship; else mouseInfo.cursorover = derelict; break; case MC_RESOURCE: mouseInfo.cursorover = resource; if (mouseCursorObjPtr && (mouseCursorObjPtr->attributes & (ATTRIBUTES_KillerCollDamage|ATTRIBUTES_HeadShotKillerCollDamage))) { if (mouseInfo.resource == 0) { mouseInfo.cursorover = enemy_ship; } else { //resouce collectors can't resource killer asteroids mouseInfo.cursorover = MC_NO_SHIP; } } break; case Ghostship: case MC_ENEMY_SHIP: mouseInfo.cursorover = enemy_ship; break; case MC_ALLIED_SHIP: mouseInfo.cursorover = allied_ship; break; default: if (mouseCursorObjPtr && ((ShipPtr)mouseCursorObjPtr)->playerowner == selSelected.ShipPtr[0]->playerowner) { mouseInfo.cursorover = own_ship; } } //if a support ship is selected, and the mouse is over //a ship the support ship is capable of supporting, change //the mouse cursor if (mouseCursorObjPtr && (bitTest(mouseInfo.flags, MCF_SpecialSCSupport) && (isShipOfClass(mouseCursorObjPtr, CLASS_Fighter) || isShipOfClass(mouseCursorObjPtr, CLASS_Corvette)))) { mouseInfo.cursorover = support; } } //if there are ships being selected else if (selSelecting.numTargets) { bitSet(mouseInfo.flags, MCF_ShipSelecting); } else { if ((mouseCursorOverShipType == FloatingCity) || ((mouseCursorOverShipType == MC_ALLIED_SHIP) && (mouseCursorEnemyType == FloatingCity))) { mouseInfo.cursorover = traders; } } } /*----------------------------------------------------------------------------- Name : mouseKeyCursorSetting Description : Sets the mouse cursor depending on key states and how the mouseInfo structure is set. Inputs : voidorama (uses globals) Outputs : Calls mouseDrawType to change the mouse Draw type Return : nothing ----------------------------------------------------------------------------*/ void mouseSetCursorSetting(void) { if (!gameIsRunning) { return; } mouseDrawType(normal_mouse); //check if a double click task needs to be performed //mouse draw type will be set accordingly by this process if (mouseDoubleClickCheck()) { return; } // if the player is disabled, only a few cursor bitmaps are shown if (mrDisabled) { if (keyIsHit(ALTKEY)) { mouseDrawType(focus_no_select); return; } return; } if (!bitTest(mouseInfo.flags, MCF_DisableAll)) { if (mouseInfo.ship_selected) { //forced attack if (keyIsHit(SHIFTKEY) && keyIsHit(CONTROLKEY)) { mouseDrawType(force_attack); return; } //select multiple ships using the shift key if (keyIsHit(SHIFTKEY)) { mouseDrawType(add_ships); return; } //guard ships if ((keyIsHit(CONTROLKEY) && keyIsHit(ALTKEY)) || keyIsHit(GKEY)) { mouseDrawType(m_guard); return; } //activate/deactivate special attack if (kbCommandKeyIsHit(kbSHIP_SPECIAL)) { if (bitTest(mouseInfo.flags, MCF_SpecialAttack)) { mouseDrawType(special_attack); return; } else if (bitTest(mouseInfo.flags, MCF_SpecialSupport)) { mouseDrawType(support); return; } else if (bitTest(mouseInfo.flags, MCF_Salvage)) { mouseDrawType(salvage); return; } } //forced focus if (keyIsHit(ALTKEY)) { mouseDrawType(focus_no_select); return; } //attack if (keyIsHit(CONTROLKEY)) { if (mouseInfo.ship_selected != mouseInfo.resource) { mouseDrawType(band_box_attack); } return; } //speed things up - if cursorover isn't a special //case, don't bother going through all these if statements if (mouseInfo.cursorover == MC_NO_SHIP) { return; } // if the mouse is over the traders if (mouseInfo.cursorover == traders) { mouseDrawType(traders); } //if a dockable ship is selected and the mouse cursor is over //a ship capable of accepting dockable ships else if ((bitTest(mouseInfo.flags, MCF_Dockable)) && (mouseInfo.cursorover == docking)) { mouseDrawType(docking); } //same as above, but with small dockable ships (fighters & corvettes) else if ((bitTest(mouseInfo.flags, MCF_SmallDockable)) && (!bitTest(mouseInfo.flags, MCF_SupportOverItself)) && ((mouseInfo.cursorover == docking) || (mouseInfo.cursorover == small_docking))) { mouseDrawType(small_docking); } // if a support capable ship is selected and the mouse is over a ship else if (((mouseInfo.cursorover != enemy_ship) && (mouseInfo.cursorover != allied_ship) && (mouseInfo.cursorover != resource) && (mouseInfo.cursorover != derelict) && (mouseInfo.cursorover != traders)) && ((mouseInfo.cursorover == support) || (bitTest(mouseInfo.flags, MCF_SpecialSupport) && !bitTest(mouseInfo.flags, MCF_SupportOverItself)))) { mouseDrawType(support); } //if the mouse is over a selected ship with a special operation and that //special operation has already been deployed else if ((bitTest(mouseInfo.flags, MCF_SpecialOpDeployed)) && (mouseInfo.cursorover == special_op_activate)) { mouseDrawType(special_op_deactivate); } //if the mouse is over a selected ship with a special operation and that //special operation has no been deployed else if ((bitTest(mouseInfo.flags, MCF_SpecialOp)) && (mouseInfo.cursorover == special_op_activate)) { mouseDrawType(special_op_activate); } //if the mouse is over a selected ship that has a GUI associated with it else if ((bitTest(mouseInfo.flags, MCF_GUICapable)) && (mouseInfo.cursorover == gui)) { mouseDrawType(gui); } //if the mouse is over a selected build capable ship else if ((bitTest(mouseInfo.flags, MCF_BuildGUI)) && (mouseInfo.cursorover == build)) { mouseDrawType(build); } //if the mouse is over a selected research ship else if ((bitTest(mouseInfo.flags, MCF_ResearchGUI)) && (mouseInfo.cursorover == research)) { mouseDrawType(research); } //if the mouse is over a selected sensors array else if ((bitTest(mouseInfo.flags, MCF_SensorsGUI)) && (mouseInfo.cursorover == sensors)) { mouseDrawType(sensors); } //if a resource ship is selected and the mouse is over a resource else if ((mouseInfo.resource) && (mouseInfo.cursorover == resource)) { mouseDrawType(resource); } //if only salvage corvettes are selected and the mouse is over an enemy ship else if (bitTest(mouseInfo.flags, MCF_SalvageOnly) && ((mouseInfo.cursorover == enemy_ship) || (mouseInfo.cursorover == salvage))) { mouseDrawType(salvage); } //if a combat ship is selected and the mouse is over an enemy ship else if (!(bitTest(mouseInfo.flags, MCF_NonCombat)) && (mouseInfo.cursorover == enemy_ship)) { mouseDrawType(band_box_attack); } // else if (mouseInfo.cursorover == allied_ship) // { // mouseDrawType(gui); // } //if a singleclickspecialactivate ship is selected and the mouse is over a derelict else if (bitTest(mouseInfo.flags, MCF_SingleClickSpecialActivate) && (mouseInfo.cursorover == derelict)) { mouseDrawType(salvage); } } //if ships are being selected else if (bitTest(mouseInfo.flags, MCF_ShipSelecting) && keyIsHit(SHIFTKEY)) { mouseDrawType(add_ships); } else { //forced focus if (keyIsHit(ALTKEY)) { mouseDrawType(focus_no_select); } //if the mouse is over the trader ship else if (mouseInfo.cursorover == traders) { mouseDrawType(traders); } } } } /*----------------------------------------------------------------------------- Cursor Text Code ----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- Name : mouseCursorTextDraw Description : Draws the name of the ship type associated with mouseCursorOverShipType Inputs : void Outputs : Screen text roughly resembling the name of the ship type Return : ----------------------------------------------------------------------------*/ void mouseCursorTextDraw(void) { static sdword cursortexttype = MC_NO_SHIP; fonthandle fhSave; if ((!mrRenderMainScreen) || (!gameIsRunning) || (mrWhiteOut) || (nisIsRunning) || (keyIsHit(RMOUSE_BUTTON))) { return; } // if there's something in that cool global variable if ((mouseCursorOverShipType != MC_NO_SHIP) && (mouseCursorOverShipType != MC_RESOURCE) && (mouseCursorOverShipType != MC_DERELICT)) { cursortexttype = mouseCursorOverShipType; } else { if (mouseCursorTextExpire < universe.totaltimeelapsed) { cursortexttype = MC_NO_SHIP; } } if (cursortexttype != MC_NO_SHIP) { // display that baby! fhSave = fontMakeCurrent(mouseCursorFont); if (cursortexttype == MC_ENEMY_SHIP) { if (mouseCursorOverLODs & MOUSE_IdentifyLODMask) { //if it's been seen closely if (!singlePlayerGame) { fontPrintf(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, "%s's %s", playerNames[mouseCursorEnemyPlayer], ShipTypeToNiceStr(mouseCursorEnemyType)); } else { fontPrintf(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, ShipTypeToNiceStr(mouseCursorEnemyType)); } } else { fontPrint(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, strGetString(strEnemyShip)); } } else if (cursortexttype == MC_ALLIED_SHIP) { if (!singlePlayerGame) { fontPrintf(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, "%s's %s", playerNames[mouseCursorEnemyPlayer], ShipTypeToNiceStr(mouseCursorEnemyType)); } else { // allied ships in the single player game (defector and traders) only // display their shiptypes and not the player name fontPrint(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, ShipTypeToNiceStr(mouseCursorEnemyType)); } } else { fontPrint(TW_CURSORTEXT_X, MAIN_WindowHeight - TW_CURSORTEXT_Y, TW_CURSORTEXT_COLOR, ShipTypeToNiceStr(cursortexttype)); } fontMakeCurrent(fhSave); } } /*----------------------------------------------------------------------------- Name : mouseClipPointToRect Description : Clip an x/y coordinate to a rectangle. Inputs : x, y - position to clip rect - rectangle to clip to Outputs : clips x, y to rect Return : ----------------------------------------------------------------------------*/ void mouseClipPointToRect(sdword *x, sdword *y, rectangle *rect) { if (*x < rect->x0) { *x = rect->x0; } if (*x >= rect->x1) { *x = rect->x1 - 1; } if (*y < rect->y0) { *y = rect->y0; } if (*y >= rect->y1) { *y = rect->y1 - 1; } } /*============================================================================= Name : mousePoll Purpose : Poll current mouse location and store internally Created 7/7/1997 by lmoloney Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ void mousePoll(void) { rectangle clientRect; POINT mousePoint; if (mouseDisabled) { return; } if (demDemoPlaying) { return; } utyClientRectGet(&clientRect); //get window location GetCursorPos(&mousePoint); //get location of Windows mouse cursor mouseCursorXPosition = mousePoint.x - clientRect.x0; //compute relative coords mouseCursorYPosition = mousePoint.y - clientRect.y0; if (mouseClip) { mouseClipPointToRect(&mouseCursorXPosition, &mouseCursorYPosition, &mouseClipRect); mousePositionSet(mouseCursorXPosition, mouseCursorYPosition); } //perform client area enter/exit logic to hide/show Windows system cursor if (primPointInRectXY2(&clientRect, mousePoint.x, mousePoint.y)) { //mouse inside window's client area if (!mouseInsideClient) { //just entered region ShowCursor(FALSE); mouseInsideClient = TRUE; } } else { //else outside region if (mouseInsideClient) { //just exited region ShowCursor(TRUE); mouseInsideClient = FALSE; } } } /*----------------------------------------------------------------------------- Name : mouseDisable/mouseEnable Description : Disable and re-enable the mouse Inputs : void Outputs : Return : void ----------------------------------------------------------------------------*/ void mouseDisable(void) { mouseCursorHide(); mouseDisabled = TRUE; } void mouseEnable(void) { mouseCursorShow(); mouseDisabled = FALSE; }