/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2007 Warzone Resurrection Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Warzone 2100 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * IntelMap.c (Intelligence Map) * * Functions for the display of the Intelligence Map * */ #include #include "lib/framework/frame.h" #include "lib/framework/strres.h" #include "lib/widget/widget.h" /* Includes direct access to render library */ #include "lib/ivis_common/piedef.h" #include "lib/ivis_common/piestate.h" #include "lib/ivis_common/rendmode.h" #include "display3d.h" #include "resource.h" #include "map.h" #include "intdisplay.h" #include "objects.h" #include "display.h" #include "design.h" #include "message.h" #include "hci.h" #include "intelmap.h" #include "mapdisplay.h" #include "lib/sound/audio.h" #include "text.h" #include "console.h" #include "research.h" #include "lib/gamelib/gtime.h" #include "loop.h" #include "lib/script/script.h" #include "scripttabs.h" #include "seqdisp.h" #include "multiplay.h" #include "lib/sound/cdaudio.h" #include "scriptextern.h" #include "csnap.h" #define NO_VIDEO // See research.txt for research entry to be displayed // By defined this we jump straight to the research entry when clicking on any button in the intelmap screen //#define DBG_RESEARCH_ENTRY (28) // Weapon research test //#define DBG_RESEARCH_ENTRY (100) // Engineering research test //#define DBG_RESEARCH_ENTRY (65) // Structure Tech //Height to view the world from in Intelligence Screen /* #define INTELMAP_VIEWHEIGHT 2250 */ /* Intelligence Map screen IDs */ //#define IDINTMAP_FORM 6000 //The intelligence map base form #define IDINTMAP_MSGFORM 6001 //The intelligence map tabbed form //#define IDINTMAP_MSGVIEW 6002 //The message 3D view for the intelligence screen #define IDINTMAP_CLOSE 6004 //The close button icon for the 3D view #define IDINTMAP_PAUSELABEL 6005 //The paused message #define IDINITMAP_TITLEVIEW 6006 //The Title view part of MSGVIEW #define IDINITMAP_PIEVIEW 6007 //The PIE view part of MSGVIEW #define IDINTMAP_FLICVIEW 6008 //The Flic View part of MSGVIEW #define IDINTMAP_TEXTVIEW 6009 //The Text area of MSGVIEW #define IDINTMAP_TITLELABEL 6010 //The title text #define IDINTMAP_SEQTEXT 6011 //Sequence subtitle text #define IDINTMAP_MSGSTART 6100 //The first button on the intelligence form #define IDINTMAP_MSGEND 6139 //The last button on the intelligence form (40 MAX) #define IDINTMAP_SEQTEXTSTART 6200 //Sequence subtitle text tabs //Proximity Messages no longer displayed in Intel Screen //#define IDINTMAP_PROXSTART 6200 //The first proximity button //#define IDINTMAP_PROXEND 6299 //The last proximity button /* Intelligence Map screen positions */ #define INTMAP_X OBJ_BACKX #define INTMAP_Y OBJ_BACKY #define INTMAP_WIDTH OBJ_BACKWIDTH #define INTMAP_HEIGHT OBJ_BACKHEIGHT #define INTMAP_LABELX RET_X #define INTMAP_LABELY 10 #define INTMAP_LABELWIDTH 60 #define INTMAP_LABELHEIGHT 20 /*tabbed message form screen positions */ #define INTMAP_MSGX OBJ_TABX #define INTMAP_MSGY OBJ_TABY #define INTMAP_MSGWIDTH OBJ_WIDTH #define INTMAP_MSGHEIGHT OBJ_HEIGHT /*3D View message form screen positions relative to INTMAP_FORM */ //#define INTMAP_VIEWX 211 //#define INTMAP_VIEWY (-260) //#define INTMAP_VIEWWIDTH MSG_BUFFER_WIDTH //#define INTMAP_VIEWHEIGHT MSG_BUFFER_HEIGHT /* Length of time the message stays on the bottom of the screen for in milliseconds */ #define INTEL_TXT_LIFE 2000 //define the 3D View sizes and positions that are required - relative to INTMAP_FORM #define INTMAP_RESEARCHX (100 + D_W) #define INTMAP_RESEARCHY (30 + D_H) #define INTMAP_RESEARCHWIDTH 440 #define INTMAP_RESEARCHHEIGHT 288 //define the 3D View sizes and positions that are required - relative to INTMAP_FORM /*#define INTMAP_MISSIONX (OBJ_BACKX) #define INTMAP_MISSIONY (46) #define INTMAP_MISSIONWIDTH (OBJ_WIDTH) #define INTMAP_MISSIONHEIGHT (215) #define INTMAP_PROXIMITYX (350) #define INTMAP_PROXIMITYY (70) #define INTMAP_PROXIMITYWIDTH (200) #define INTMAP_PROXIMITYHEIGHT (175)*/ /*dimensions for Title view section relative to IDINTMAP_MSGVIEW*/ /*dimensions for PIE view section relative to IDINTMAP_MSGVIEW*/ #define INTMAP_TITLEX 0 #define INTMAP_TITLEY 0 #define INTMAP_TITLEWIDTH INTMAP_RESEARCHWIDTH #define INTMAP_TITLEHEIGHT 18 #define INTMAP_PIEX 3 #define INTMAP_PIEY 24 //#define INTMAP_PIEWIDTH 240 //#define INTMAP_PIEHEIGHT 169 /*dimensions for FLIC view section relative to IDINTMAP_MSGVIEW*/ #define INTMAP_FLICX 245 #define INTMAP_FLICY 24 #define INTMAP_FLICWIDTH 192 #define INTMAP_FLICHEIGHT 170 /*dimensions for TEXT view section relative to IDINTMAP_MSGVIEW*/ #define INTMAP_TEXTX 0 #define INTMAP_TEXTY 200 #define INTMAP_TEXTWIDTH INTMAP_RESEARCHWIDTH #define INTMAP_TEXTHEIGHT 88 #define TEXT_XINDENT 5 #define TEXT_YINDENT 5 /*dimensions for SEQTEXT view relative to IDINTMAP_MSGVIEW*/ #define INTMAP_SEQTEXTX 0 #define INTMAP_SEQTEXTY 0 #define INTMAP_SEQTEXTWIDTH INTMAP_RESEARCHWIDTH #define INTMAP_SEQTEXTHEIGHT INTMAP_RESEARCHHEIGHT /*dimensions for SEQTEXT tab view relative to IDINTMAP_SEQTEXT*/ #define INTMAP_SEQTEXTTABX 0 #define INTMAP_SEQTEXTTABY 0 #define INTMAP_SEQTEXTTABWIDTH INTMAP_SEQTEXTWIDTH #define INTMAP_SEQTEXTTABHEIGHT INTMAP_SEQTEXTHEIGHT //position for text on full screen video #define VIDEO_TEXT_TOP_X 20 #define VIDEO_TEXT_TOP_Y 20 #define VIDEO_TEXT_BOTTOM_X 20 #define VIDEO_TEXT_BOTTOM_Y 444 #define TEXT_START_FRAME 0 #define TEXT_END_FRAME 9999 /* the widget screen */ extern W_SCREEN *psWScreen; /* Static variables ********************/ //static SDWORD viewAngle; //static SDWORD viewHeight; static UDWORD messageID; static BOOL immediateMessage = FALSE; //How many proximity messages are currently being displayed //static UDWORD numProxMsg; //flags whether to open the Intel Screen with a message static BOOL playCurrent; /* functions declarations ****************/ static BOOL intAddMessageForm(BOOL playCurrent); /*Displays the buttons used on the intelligence map */ static void intDisplayMessageButton(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours); /* displays the 3D view for the current message */ //static void intDisplayMessageView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, // UDWORD *pColours); /* Add the Proximity message buttons */ //static BOOL intAddProximityButton(MESSAGE *pMessage, UDWORD inc); /*Displays the proximity messages used on the intelligence map */ //static void intDisplayProximityButton(WIDGET *psWidget, UDWORD xOffset, // UDWORD yOffset, UDWORD *pColours); /*deal with the actual button press - proxMsg is set to true if a proximity button has been pressed*/ static void intIntelButtonPressed(BOOL proxMsg, UDWORD id); /*this sets the width and height for the Intel map surface so that it fill the appropriate sized image for the view*/ //static void setIntelBufferSize(UDWORD type); /*sets the intel map surface back to the size it was created with */ //static void resetIntelBufferSize(void); //static BOOL checkMessageOverlap(MESSAGE *psMessage, SWORD x, SWORD y); /* draws the text message in the message window - only allows for one at the moment!*/ //static void displayIntelligenceMessage(MESSAGE *psMessage); /* Remove the Message View from the Intelligence screen without animation*/ //static void intRemoveMessageViewNoAnim(BOOL animated); static void intDisplayPIEView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours); #ifndef NO_VIDEO static void intDisplayFLICView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours); #endif static void intDisplayTEXTView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours); static void addVideoText(SEQ_DISPLAY *psSeqDisplay, UDWORD sequence); static void intDisplaySeqTextView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours); static BOOL intDisplaySeqTextViewPage(VIEW_REPLAY *psViewReplay, UDWORD x0, UDWORD y0, UDWORD width, UDWORD height, BOOL render, size_t *major, size_t *minor); /*********************** VARIABLES ****************************/ // The current message being displayed MESSAGE *psCurrentMsg = NULL; // The display stats for the current messages' text TEXT_DISPLAY currentTextDisplay; #define PAUSE_DISPLAY_CONDITION (!bMultiPlayer) #define PAUSEMESSAGE_YOFFSET (0) /* Add the Intelligence Map widgets to the widget screen */ BOOL intAddIntelMap(void) { W_FORMINIT sFormInit; W_LABINIT sLabInit; BOOL Animate = TRUE; //check playCurrent with psCurrentMsg if (psCurrentMsg == NULL) { playCurrent = FALSE; } else { playCurrent = TRUE; } // Is the form already up? if(widgGetFromID(psWScreen,IDINTMAP_FORM) != NULL) { intRemoveIntelMapNoAnim(); Animate = FALSE; } else { audio_StopAll(); } cdAudio_Pause(); //add message to indicate game is paused - single player mode if(PAUSE_DISPLAY_CONDITION) { if(widgGetFromID(psWScreen,IDINTMAP_PAUSELABEL) == NULL) { memset(&sLabInit,0,sizeof(W_LABINIT)); sLabInit.id = IDINTMAP_PAUSELABEL; sLabInit.formID = 0; sLabInit.style = WLAB_PLAIN; sLabInit.x = INTMAP_LABELX; sLabInit.y = INTMAP_LABELY+PAUSEMESSAGE_YOFFSET; sLabInit.width = INTMAP_LABELWIDTH; sLabInit.height = INTMAP_LABELHEIGHT; sLabInit.pText = _("PAUSED"); sLabInit.FontID = WFont; if (!widgAddLabel(psWScreen, &sLabInit)) { return FALSE; } } } //set pause states before putting the interface up setIntelligencePauseState(); memset(&sFormInit, 0, sizeof(W_FORMINIT)); // Add the main Intelligence Map form sFormInit.formID = 0; sFormInit.id = IDINTMAP_FORM; sFormInit.style = WFORM_PLAIN; sFormInit.x = (SWORD)INTMAP_X; sFormInit.y = (SWORD)INTMAP_Y; sFormInit.width = INTMAP_WIDTH; sFormInit.height = INTMAP_HEIGHT; // If the window was closed then do open animation. if(Animate) { sFormInit.pDisplay = intOpenPlainForm; sFormInit.disableChildren = TRUE; } else { // otherwise just recreate it. sFormInit.pDisplay = intDisplayPlainForm; } //sFormInit.pDisplay = intDisplayPlainForm; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } if (!intAddMessageForm(playCurrent)) { return FALSE; } return TRUE; } /* Add the Message sub form */ static BOOL intAddMessageForm(BOOL playCurrent) { W_FORMINIT sFormInit; W_FORMINIT sBFormInit; UDWORD numButtons, i; MESSAGE *psMessage; RESEARCH *psResearch; SDWORD BufferID; /* Add the Message form */ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = IDINTMAP_FORM; sFormInit.id = IDINTMAP_MSGFORM; sFormInit.style = WFORM_TABBED; sFormInit.width = INTMAP_MSGWIDTH; sFormInit.height = INTMAP_MSGHEIGHT; sFormInit.x = INTMAP_MSGX; sFormInit.y = INTMAP_MSGY; sFormInit.majorPos = WFORM_TABTOP; sFormInit.minorPos = WFORM_TABNONE; sFormInit.majorSize = OBJ_TABWIDTH; sFormInit.majorOffset = OBJ_TABOFFSET; sFormInit.tabVertOffset = (OBJ_TABHEIGHT/2); sFormInit.tabMajorThickness = OBJ_TABHEIGHT; numButtons = 0; //numProxMsg = 0; /*work out the number of buttons */ for(psMessage = apsMessages[selectedPlayer]; psMessage; psMessage = psMessage->psNext) { //ignore proximity messages here if (psMessage->type == MSG_PROXIMITY) { //intAddProximityButton(psMessage, numProxMsg); //numProxMsg++; } else { numButtons++; } //stop adding the buttons once max has been reached if (numButtons > (IDINTMAP_MSGEND - IDINTMAP_MSGSTART)) { break; } } //set the number of tabs required sFormInit.numMajor = numForms((OBJ_BUTWIDTH + OBJ_GAP) * numButtons, (OBJ_WIDTH - OBJ_GAP)*2); //set minor tabs to 1 for (i=0; i< sFormInit.numMajor; i++) { sFormInit.aNumMinors[i] = 1; } sFormInit.pFormDisplay = intDisplayObjectForm; sFormInit.pUserData = (void*)&StandardTab; sFormInit.pTabDisplay = intDisplayTab; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } /* Add the message buttons */ memset(&sBFormInit, 0, sizeof(W_FORMINIT)); sBFormInit.formID = IDINTMAP_MSGFORM; sBFormInit.id = IDINTMAP_MSGSTART; sBFormInit.majorID = 0; sBFormInit.minorID = 0; sBFormInit.style = WFORM_CLICKABLE; sBFormInit.x = OBJ_STARTX; sBFormInit.y = OBJ_STATSTARTY; sBFormInit.width = OBJ_BUTWIDTH; sBFormInit.height = OBJ_BUTHEIGHT; ClearObjectBuffers(); //add each button messageID = 0; for(psMessage = apsMessages[selectedPlayer]; psMessage; psMessage = psMessage->psNext) { /*if (psMessage->type == MSG_TUTORIAL) { //tutorial cases should never happen ASSERT( FALSE, "Tutorial message in Intelligence screen!" ); continue; }*/ if (psMessage->type == MSG_PROXIMITY) { //ignore proximity messages here continue; } /* Set the tip and add the button */ switch (psMessage->type) { case MSG_RESEARCH: psResearch = getResearchForMsg((VIEWDATA *)psMessage->pViewData); if (psResearch) { sBFormInit.pTip = getStatName(psResearch);; } else { sBFormInit.pTip = _("Research Update"); } break; case MSG_CAMPAIGN: sBFormInit.pTip = _("Project Goals"); break; case MSG_MISSION: sBFormInit.pTip = _("Current Objective"); break; default: break; } BufferID = GetObjectBuffer(); ASSERT( BufferID >= 0,"Unable to acquire object buffer." ); RENDERBUTTON_INUSE(&ObjectBuffers[BufferID]); ObjectBuffers[BufferID].Data = (void*)psMessage; sBFormInit.pUserData = (void*)&ObjectBuffers[BufferID]; sBFormInit.pDisplay = intDisplayMessageButton; if (!widgAddForm(psWScreen, &sBFormInit)) { return FALSE; } intSetCurrentCursorPosition(&InterfaceSnap,sBFormInit.id); /* if the current message matches psSelected lock the button */ if (psMessage == psCurrentMsg) { messageID = sBFormInit.id; widgSetButtonState(psWScreen, messageID, WBUT_LOCK); widgSetTabs(psWScreen, IDINTMAP_MSGFORM, sBFormInit.majorID, 0); } /* Update the init struct for the next button */ sBFormInit.id += 1; //stop adding the buttons when at max if (sBFormInit.id > IDINTMAP_MSGEND) { break; } ASSERT( sBFormInit.id < (IDINTMAP_MSGEND+1),"Too many message buttons" ); sBFormInit.x += OBJ_BUTWIDTH + OBJ_GAP; if (sBFormInit.x + OBJ_BUTWIDTH + OBJ_GAP > INTMAP_MSGWIDTH) { sBFormInit.x = OBJ_STARTX; sBFormInit.y += OBJ_BUTHEIGHT + OBJ_GAP; } if (sBFormInit.y + OBJ_BUTHEIGHT + OBJ_GAP > INTMAP_MSGHEIGHT) { sBFormInit.y = OBJ_STATSTARTY; sBFormInit.majorID += 1; } } //check to play current message instantly if (playCurrent) { //is it a proximity message? if (psCurrentMsg->type == MSG_PROXIMITY) { //intIntelButtonPressed(TRUE, messageID); } else { intIntelButtonPressed(FALSE, messageID); } } return TRUE; } /*Add the 3D world view for the particular message (only research nmessages now) */ BOOL intAddMessageView(MESSAGE * psMessage) { W_FORMINIT sFormInit; W_BUTINIT sButInit; W_LABINIT sLabInit; BOOL Animate = TRUE; RESEARCH *psResearch; /* ASSERT( psMessage->type == MSG_RESEARCH, * "intAddMessageView: invalid message type" ); * had to comment out this check, since the 'Fast Play' tutorial triggered it * with psMessage->type=MSG_MISSION and ((VIEWDATA)*psMessage->pViewData)->type=VIEW_RPL, * but which is probably using the wrong function. - Per */ // Is the form already up? if(widgGetFromID(psWScreen,IDINTMAP_MSGVIEW) != NULL) { intRemoveMessageView(FALSE); Animate = FALSE; } /* Add the base form */ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = 0; sFormInit.id = IDINTMAP_MSGVIEW; sFormInit.style = WFORM_PLAIN; //size and position depends on the type of message - ONLY RESEARCH now sFormInit.width = INTMAP_RESEARCHWIDTH; sFormInit.height = INTMAP_RESEARCHHEIGHT; sFormInit.x = (SWORD)INTMAP_RESEARCHX; sFormInit.y = (SWORD)INTMAP_RESEARCHY; /*switch (type) { case MSG_RESEARCH: sFormInit.width = INTMAP_CAMPAIGNWIDTH; sFormInit.height = INTMAP_CAMPAIGNHEIGHT; sFormInit.x = INTMAP_CAMPAIGNX; sFormInit.y = INTMAP_CAMPAIGNY; break; //these are Full Screen FMV now case MSG_CAMPAIGN: case MSG_MISSION: //case MSG_TUTORIAL: sFormInit.width = INTMAP_MISSIONWIDTH; sFormInit.height = INTMAP_MISSIONHEIGHT; sFormInit.x = INTMAP_MISSIONX; sFormInit.y = INTMAP_MISSIONY; break; //these are no longer displayed in Intel Screen case MSG_PROXIMITY: sFormInit.width = INTMAP_PROXIMITYWIDTH; sFormInit.height = INTMAP_PROXIMITYHEIGHT; sFormInit.x = INTMAP_PROXIMITYX; sFormInit.y = INTMAP_PROXIMITYY; break; default: ASSERT( FALSE, "Unknown message type" ); return FALSE; }*/ // If the window was closed then do open animation. if(Animate) { sFormInit.pDisplay = intOpenPlainForm; sFormInit.disableChildren = TRUE; } else { // otherwise just display it. sFormInit.pDisplay = intDisplayPlainForm; } if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } /* Add the close box */ memset(&sButInit, 0, sizeof(W_BUTINIT)); sButInit.formID = IDINTMAP_MSGVIEW; sButInit.id = IDINTMAP_CLOSE; sButInit.style = WBUT_PLAIN; sButInit.x = (SWORD)(sFormInit.width - OPT_GAP - CLOSE_SIZE); sButInit.y = OPT_GAP; sButInit.width = CLOSE_SIZE; sButInit.height = CLOSE_SIZE; sButInit.pTip = _("Close"); sButInit.pDisplay = intDisplayImageHilight; sButInit.pUserData = (void*)PACKDWORD_TRI(0,IMAGE_CLOSEHILIGHT , IMAGE_CLOSE); if (!widgAddButton(psWScreen, &sButInit)) { return FALSE; } if (psMessage->type != MSG_RESEARCH && ((VIEWDATA*)psMessage->pViewData)->type == VIEW_RPL) { W_FORMINIT sTabForm; VIEW_REPLAY *psViewReplay; size_t i, cur_seq, cur_seqpage; psViewReplay = (VIEW_REPLAY *)((VIEWDATA *)psMessage->pViewData)->pData; /* Add a big tabbed text box for the subtitle text */ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.id = IDINTMAP_SEQTEXT; sFormInit.formID = IDINTMAP_MSGVIEW; sFormInit.style = WFORM_TABBED; sFormInit.x = INTMAP_SEQTEXTX; sFormInit.y = INTMAP_SEQTEXTY; sFormInit.width = INTMAP_SEQTEXTWIDTH; sFormInit.height = INTMAP_SEQTEXTHEIGHT; sFormInit.majorPos = WFORM_TABBOTTOM; sFormInit.minorPos = WFORM_TABNONE; sFormInit.majorSize = OBJ_TABWIDTH; sFormInit.majorOffset = OBJ_TABOFFSET; sFormInit.tabVertOffset = (OBJ_TABHEIGHT/2); sFormInit.tabMajorThickness = OBJ_TABHEIGHT; sFormInit.numMajor = 0; cur_seq = cur_seqpage = 0; do { sFormInit.aNumMinors[sFormInit.numMajor] = 1; sFormInit.numMajor++; } while (!intDisplaySeqTextViewPage(psViewReplay, 0, 0, sFormInit.width, sFormInit.height, FALSE, &cur_seq, &cur_seqpage)); sFormInit.pFormDisplay = intDisplayObjectForm; sFormInit.pUserData = (void*)&StandardTab; sFormInit.pTabDisplay = intDisplayTab; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } memset(&sTabForm, 0, sizeof(W_FORMINIT)); sTabForm.formID = IDINTMAP_SEQTEXT; sTabForm.id = IDINTMAP_SEQTEXTSTART; sTabForm.majorID = 0; sTabForm.minorID = 0; sTabForm.style = WFORM_PLAIN; sTabForm.x = INTMAP_SEQTEXTTABX; sTabForm.y = INTMAP_SEQTEXTTABY; sTabForm.width = INTMAP_SEQTEXTTABWIDTH; sTabForm.height = INTMAP_SEQTEXTTABHEIGHT; sTabForm.pDisplay = intDisplaySeqTextView; sTabForm.pUserData = psViewReplay; for (i = 0; i < sFormInit.numMajor; i++) { sTabForm.id = IDINTMAP_SEQTEXTSTART + i; sTabForm.majorID = i; if (!widgAddForm(psWScreen, &sTabForm)) { return FALSE; } } return TRUE; } /*Add the Title box*/ /*memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = IDINTMAP_MSGVIEW; sFormInit.id = IDINITMAP_TITLEVIEW; sFormInit.style = WFORM_PLAIN; sFormInit.x = INTMAP_TITLEX; sFormInit.y = INTMAP_TITLEY; sFormInit.width = INTMAP_TITLEWIDTH; sFormInit.height = INTMAP_TITLEHEIGHT; sFormInit.pDisplay = intDisplayPlainForm; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; }*/ /*add the Label for the title box*/ memset(&sLabInit,0,sizeof(W_LABINIT)); sLabInit.id = IDINTMAP_TITLELABEL; sLabInit.formID = IDINTMAP_MSGVIEW; sLabInit.style = WLAB_PLAIN; sLabInit.x = INTMAP_TITLEX + TEXT_XINDENT; sLabInit.y = INTMAP_TITLEY + TEXT_YINDENT; sLabInit.width = INTMAP_TITLEWIDTH; sLabInit.height = INTMAP_TITLEHEIGHT; //print research name in title bar ASSERT( psMessage->type != MSG_PROXIMITY, "intAddMessageView:Invalid message type for research" ); psResearch = getResearchForMsg((VIEWDATA *)psMessage->pViewData); ASSERT( psResearch!=NULL,"Research not found" ); //sLabInit.pText=psResearch->pName; sLabInit.pText = getStatName(psResearch); sLabInit.FontID = WFont; if (!widgAddLabel(psWScreen, &sLabInit)) { return FALSE; } /*Add the PIE box*/ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = IDINTMAP_MSGVIEW; sFormInit.id = IDINITMAP_PIEVIEW; sFormInit.style = WFORM_PLAIN; sFormInit.x = INTMAP_PIEX; sFormInit.y = INTMAP_PIEY; sFormInit.width = INTMAP_PIEWIDTH; sFormInit.height = INTMAP_PIEHEIGHT; sFormInit.pDisplay = intDisplayPIEView; sFormInit.pUserData = (void *)psMessage; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } #ifndef NO_VIDEO /*Add the Flic box */ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = IDINTMAP_MSGVIEW; sFormInit.id = IDINTMAP_FLICVIEW; sFormInit.style = WFORM_PLAIN; sFormInit.x = INTMAP_FLICX; sFormInit.y = INTMAP_FLICY; sFormInit.width = INTMAP_FLICWIDTH; sFormInit.height = INTMAP_FLICHEIGHT; sFormInit.pDisplay = intDisplayFLICView; sFormInit.pUserData = (void *)psMessage; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } #endif /*Add the text box*/ memset(&sFormInit, 0, sizeof(W_FORMINIT)); sFormInit.formID = IDINTMAP_MSGVIEW; sFormInit.id = IDINTMAP_TEXTVIEW; sFormInit.style = WFORM_PLAIN; sFormInit.x = INTMAP_TEXTX; sFormInit.y = INTMAP_TEXTY; sFormInit.width = INTMAP_TEXTWIDTH; sFormInit.height = INTMAP_TEXTHEIGHT; sFormInit.pDisplay = intDisplayTEXTView; sFormInit.pUserData = (void *)psMessage; if (!widgAddForm(psWScreen, &sFormInit)) { return FALSE; } return TRUE; } /* Process return codes from the Intelligence Map */ void intProcessIntelMap(UDWORD id) { if (id >= IDINTMAP_MSGSTART && id <= IDINTMAP_MSGEND) { intIntelButtonPressed(FALSE, id); } /*else if (id >= IDINTMAP_PROXSTART && id <= IDINTMAP_PROXEND) { intIntelButtonPressed(TRUE, id); }*/ else if (id == IDINTMAP_CLOSE) { //if close button pressed on 3D View then close the view only psCurrentMsg = NULL; //initTextDisplay(psCurrentMsg, WFont, 255); intRemoveMessageView(TRUE); } } static BOOL intDisplaySeqTextViewPage(VIEW_REPLAY *psViewReplay, UDWORD x0, UDWORD y0, UDWORD width, UDWORD height, BOOL render, size_t *cur_seq, size_t *cur_seqpage) { UDWORD x1, y1, i, linePitch, cur_y; UDWORD ty; UDWORD sequence; if (!psViewReplay) { return TRUE; /* nothing to do */ } x1 = x0 + width; y1 = y0 + height; ty = y0; iV_SetFont(WFont); /* Get the travel to the next line */ linePitch = iV_GetTextLineSize(); /* Fix for spacing.... */ linePitch += 6; ty += 3; iV_SetTextColour(PIE_TEXT_WHITE); cur_y = 0; /* add each message */ for (sequence = *cur_seq, i = *cur_seqpage; sequence < psViewReplay->numSeq; sequence++) { SEQ_DISPLAY *psSeqDisplay = &psViewReplay->pSeqList[sequence]; for (; i < psSeqDisplay->numText; i++) { if (render) { iV_DrawText(psSeqDisplay->ppTextMsg[i], x0 + TEXT_XINDENT, (ty + TEXT_YINDENT*3) + cur_y); } cur_y += linePitch; if (cur_y > height) { /* run out of room - need to make new tab */ *cur_seq = sequence; *cur_seqpage = i; return FALSE; } } i = 0; } return TRUE; /* done */ } static void intDisplaySeqTextView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_TABFORM *Form = (W_TABFORM*)psWidget; VIEW_REPLAY *psViewReplay = (VIEW_REPLAY*)Form->pUserData; size_t cur_seq, cur_seqpage; UDWORD x0, y0, page; x0 = xOffset + Form->x; y0 = yOffset + Form->y; RenderWindowFrame(&FrameNormal, x0, y0, Form->width, Form->height); /* work out where we're up to in the text */ cur_seq = cur_seqpage = 0; if(Form->style & WFORM_TABBED) { // Gerard 2007-04-07: dead code? ASSERT(FALSE,"the form is tabbed?"); for (page = 0; page < Form->majorT; page++) { intDisplaySeqTextViewPage(psViewReplay, x0, y0, Form->width, Form->height, FALSE, &cur_seq, &cur_seqpage); } } intDisplaySeqTextViewPage(psViewReplay, x0, y0, Form->width, Form->height, TRUE, &cur_seq, &cur_seqpage); } // Add all the Video Sequences for a message static void StartMessageSequences(MESSAGE *psMessage, BOOL Start) { BOOL bLoop = FALSE; // printf("start message sequence\n"); //[testing if we hit this] -Q //should never have a proximity message here if (psMessage->type == MSG_PROXIMITY) { return; } ASSERT( psMessage->pViewData != NULL, "StartMessageSequences: invalid ViewData pointer" ); if (((VIEWDATA *)psMessage->pViewData)->type == VIEW_RPL) { VIEW_REPLAY *psViewReplay; UDWORD Sequence; // Surely we don't need to set up psCurrentMsg when we pass the message into this routine ... tim // psViewReplay = (VIEW_REPLAY *)((VIEWDATA *)psCurrentMsg->pViewData)->pData; psViewReplay = (VIEW_REPLAY *)((VIEWDATA *)psMessage->pViewData)->pData; seq_ClearSeqList(); //add any sequences to the list to be played when the first one is finished for (Sequence = 0; Sequence < psViewReplay->numSeq; Sequence++) { if (psViewReplay->pSeqList[Sequence].flag == 1) { bLoop = TRUE; } else { bLoop = FALSE; } seq_AddSeqToList(psViewReplay->pSeqList[Sequence].sequenceName, psViewReplay->pSeqList[Sequence].pAudio, NULL, bLoop); // { // char String[256]; // sprintf(String,"seqadded %d of %d [%s]\n",Sequence,psViewReplay->numSeq,psViewReplay->pSeqList[Sequence].sequenceName); // prnt(1,String,0,0); // } debug( LOG_NEVER, "sequence=%d\n", Sequence ); addVideoText(&psViewReplay->pSeqList[Sequence],Sequence); } //play first full screen video if (Start==TRUE) { seq_StartNextFullScreenVideo(); } } else if (((VIEWDATA *)psMessage->pViewData)->type == VIEW_RES) { VIEW_RESEARCH *psViewReplay; //UDWORD Sequence; psViewReplay = (VIEW_RESEARCH *)((VIEWDATA *)psCurrentMsg->pViewData)->pData; seq_ClearSeqList(); seq_AddSeqToList(psViewReplay->sequenceName, psViewReplay->pAudio, NULL, FALSE); //play first full screen video if (Start==TRUE) { seq_StartNextFullScreenVideo(); } } } UDWORD ButtonPresses=0; #ifdef DBG_RESEARCH_ENTRY MESSAGE TimsMessage= { MSG_RESEARCH,NULL,NULL,FALSE,0 }; #endif /* deal with the actual button press - proxMsg is set to true if a proximity button has been pressed */ void intIntelButtonPressed(BOOL proxMsg, UDWORD id) { MESSAGE *psMessage; UDWORD currID;//, i; // char aAudioName[MAX_STR_LENGTH]; // made static to reduce stack usage. RESEARCH *psResearch; ASSERT( proxMsg != TRUE, "intIntelButtonPressed: Shouldn't be able to get a proximity message!" ); if(id == 0) { intRemoveIntelMap(); return; } /* message button has been pressed - clear the old button and messageView*/ if (messageID != 0) { widgSetButtonState(psWScreen, messageID, 0); intRemoveMessageView(FALSE); psCurrentMsg = NULL; //initTextDisplay(psCurrentMsg, WFont, 255); } /* Lock the new button */ // This means we can't click on the same movie button twice. // widgSetButtonState(psWScreen, id, WBUT_LOCK); widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK); messageID = id; //Find the message for the new button */ currID = IDINTMAP_MSGSTART; for(psMessage = apsMessages[selectedPlayer]; psMessage; psMessage = psMessage->psNext) { if (psMessage->type != MSG_PROXIMITY) { if (currID == id) { break; } currID++; } } #ifdef DBG_RESEARCH_ENTRY #warning DEBUG MESSAGE CODE ADDED ---- REMOVE BEFORE FINAL BUILD !!!!!! ButtonPresses++; if (ButtonPresses>=2) // 2nd time only !!! { psMessage=&TimsMessage; TimsMessage.pViewData= asResearch[DBG_RESEARCH_ENTRY].pViewData; } #endif //deal with the message if one if (psMessage) { //set the current message psCurrentMsg = psMessage; //initTextDisplay(psCurrentMsg, WFont, 255); //set the read flag psCurrentMsg->read = TRUE; //this is for the deaf! - done in intDisplayMessageView() /*if (psMessage->pViewData->pTextMsg) { addGameMessage(psMessage->pViewData->pTextMsg, INTEL_TXT_LIFE, TRUE); }*/ //DBPRINTF(("Dealing with a new message !!! type=%d\n",psMessage->pViewData->type); //should never have a proximity message if (psMessage->type == MSG_PROXIMITY) { return; } // If its a video sequence then play it anyway if (((VIEWDATA *)psMessage->pViewData)->type == VIEW_RPL) { if (psMessage->pViewData) { intAddMessageView(psMessage); } StartMessageSequences(psMessage,TRUE); } else if (((VIEWDATA *)psMessage->pViewData)->type == VIEW_RES) { //this must be for the blind //with forsight this information was removed from the meassage text /* if (((VIEW_RESEARCH *)((VIEWDATA *)psMessage->pViewData)->pData)->pAudio != NULL) { ASSERT( strlen(((VIEW_RESEARCH *)((VIEWDATA *)psMessage->pViewData)-> pData)->pAudio)<244,"sequence path+name greater than max string" ); strcpy(aAudioName,"sequenceaudio/"); strcat(aAudioName,((VIEW_RESEARCH *)((VIEWDATA *)psMessage-> pViewData)->pData)->pAudio); audio_PlayStream(aAudioName, AUDIO_VOL_MAX, NULL); } */ //This hack replaces it psResearch = getResearchForMsg((VIEWDATA *)psMessage->pViewData); if (psResearch != NULL) { switch(psResearch->iconID) { case IMAGE_RES_DROIDTECH: audio_PlayStream("sequenceaudio/res_droid.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_WEAPONTECH: audio_PlayStream("sequenceaudio/res_weapons.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_COMPUTERTECH: audio_PlayStream("sequenceaudio/res_com.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_POWERTECH: audio_PlayStream("sequenceaudio/res_pow.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_SYSTEMTECH: audio_PlayStream("sequenceaudio/res_systech.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_STRUCTURETECH: audio_PlayStream("sequenceaudio/res_strutech.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_CYBORGTECH: audio_PlayStream("sequenceaudio/res_droid.ogg", AUDIO_VOL_MAX, NULL); break; case IMAGE_RES_DEFENCE: audio_PlayStream("sequenceaudio/res_strutech.ogg", AUDIO_VOL_MAX, NULL); break; // default: } } //and finally for the dumb? if (psMessage->pViewData) { intAddMessageView(psMessage); } } } } static void intCleanUpIntelMap(void) { MESSAGE *psMessage, *psNext; //remove any research messages that have been read for (psMessage = apsMessages[selectedPlayer]; psMessage != NULL; psMessage = psNext) { psNext = psMessage->psNext; if (psMessage->type == MSG_RESEARCH && psMessage->read) { removeMessage(psMessage, selectedPlayer); } } resetIntelligencePauseState(); immediateMessage = FALSE; cdAudio_Resume(); // FIXME: NOT SURE IT'S CORRECT. this makes the transports come. //eventFireCallbackTrigger((TRIGGER_TYPE)CALL_VIDEO_QUIT); if (interpProcessorActive()) { debug(LOG_SCRIPT, "intCleanUpIntelMap: interpreter running, storing CALL_VIDEO_QUIT"); if(!msgStackPush(CALL_VIDEO_QUIT,-1,-1,"\0",-1,-1,NULL)) { debug(LOG_ERROR, "intCleanUpIntelMap() - msgStackPush - stack failed"); return; } } else { debug(LOG_SCRIPT, "intCleanUpIntelMap: not running"); eventFireCallbackTrigger((TRIGGER_TYPE)CALL_VIDEO_QUIT); } } /* Remove the Intelligence Map widgets from the screen */ void intRemoveIntelMap(void) { WIDGET *Widg; W_TABFORM *Form; //remove 3dView if still there Widg = widgGetFromID(psWScreen,IDINTMAP_MSGVIEW); if(Widg) { intRemoveMessageView(FALSE); } // Start the window close animation. Form = (W_TABFORM*)widgGetFromID(psWScreen,IDINTMAP_FORM); if(Form) { Form->display = intClosePlainForm; Form->disableChildren = TRUE; Form->pUserData = (void*)0; // Used to signal when the close anim has finished. } ClosingIntelMap = TRUE; //remove the text label widgDelete(psWScreen, IDINTMAP_PAUSELABEL); intCleanUpIntelMap(); } /* Remove the Intelligence Map widgets from the screen */ void intRemoveIntelMapNoAnim(void) { //UDWORD buttonID; WIDGET *Widg; //remove each proximity button /*for (buttonID = 0; buttonID < numProxMsg; buttonID++) { widgDelete(psWScreen, IDINTMAP_PROXSTART + buttonID); }*/ //remove 3dView if still there Widg = widgGetFromID(psWScreen,IDINTMAP_MSGVIEW); if(Widg) { intRemoveMessageView(FALSE); } //remove main Intelligence screen widgDelete(psWScreen, IDINTMAP_FORM); //remove the text label widgDelete(psWScreen, IDINTMAP_PAUSELABEL); intCleanUpIntelMap(); // resetIntelligencePauseState(); // // immediateMessage = FALSE; } /* Remove the Message View from the Intelligence screen */ void intRemoveMessageView(BOOL animated) { W_TABFORM *Form; VIEW_RESEARCH *psViewResearch; //remove 3dView if still there Form = (W_TABFORM*)widgGetFromID(psWScreen,IDINTMAP_MSGVIEW); if(Form) { //stop the video psViewResearch = (VIEW_RESEARCH *)Form->pUserData; seq_RenderVideoToBuffer(NULL, psViewResearch->sequenceName, gameTime2, SEQUENCE_KILL); if (animated) { widgDelete(psWScreen, IDINTMAP_CLOSE); // Start the window close animation. Form->display = intClosePlainForm; Form->disableChildren = TRUE; Form->pUserData = (void*)0; // Used to signal when the close anim has finished. ClosingMessageView = TRUE; } else { //remove without the animating close window widgDelete(psWScreen, IDINTMAP_MSGVIEW); } } } /*Displays the buttons used on the intelligence map */ void intDisplayMessageButton(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_CLICKFORM *psButton = (W_CLICKFORM*)psWidget; RENDERED_BUTTON *psBuffer = (RENDERED_BUTTON*)psButton->pUserData; MESSAGE *psMsg; BOOL Hilight = FALSE; UDWORD Down = 0, IMDType = 0, compID; SDWORD image = -1; RESEARCH *pResearch = NULL; BASE_STATS *psResGraphic = NULL; BOOL MovieButton = FALSE; OpenButtonRender((UWORD)(xOffset+psButton->x), (UWORD)(yOffset+psButton->y), psButton->width, psButton->height); Down = psButton->state & (WBUTS_DOWN | WBUTS_CLICKLOCK); Hilight = psButton->state & WBUTS_HILITE; // Get the object associated with this widget. psMsg = (MESSAGE *)psBuffer->Data; ASSERT( psMsg != NULL, "psBuffer->Data empty. Why?" ); //shouldn't have any proximity messages here... if (psMsg->type == MSG_PROXIMITY) { return; } //set the graphic for the button switch (psMsg->type) { case MSG_RESEARCH: pResearch = getResearchForMsg((VIEWDATA *)psMsg->pViewData); //IMDType = IMDTYPE_RESEARCH; //set the IMDType depending on what stat is associated with the research if (pResearch->psStat) { //we have a Stat associated with this research topic if (StatIsStructure(pResearch->psStat)) { //this defines how the button is drawn IMDType = IMDTYPE_STRUCTURESTAT; psResGraphic = pResearch->psStat; } else { compID = StatIsComponent(pResearch->psStat); if (compID != COMP_UNKNOWN) { //this defines how the button is drawn IMDType = IMDTYPE_COMPONENT; psResGraphic = pResearch->psStat; } else { ASSERT( FALSE, "intDisplayMessageButton: invalid stat" ); IMDType = IMDTYPE_RESEARCH; psResGraphic = (BASE_STATS *)pResearch; } } } else { //no Stat for this research topic so use the research topic to define what is drawn psResGraphic = (BASE_STATS *)pResearch; IMDType = IMDTYPE_RESEARCH; } break; case MSG_CAMPAIGN: image = IMAGE_INTEL_CAMPAIGN; MovieButton = TRUE; break; case MSG_MISSION: image = IMAGE_INTEL_MISSION; MovieButton = TRUE; break; default: debug( LOG_ERROR, "Unknown message type: %i", psMsg->type ); return; } //if research message if (pResearch) { if (pResearch->iconID != NO_RESEARCH_ICON) { image = pResearch->iconID; } //do we have the same icon for the top right hand corner? if (image > 0) { //RenderToButton(IntImages,(UWORD)image,pResearch,selectedPlayer,psBuffer,Down, // IMDType,TOPBUTTON); // ajl, changed from 0 to selectedPLayer RenderToButton(IntImages,(UWORD)image,psResGraphic,selectedPlayer, psBuffer,Down,IMDType,TOPBUTTON); } else { RenderToButton(NULL,0,pResearch,selectedPlayer,psBuffer,Down,IMDType,TOPBUTTON); //ajl, changed from 0 to selectedPlayer } } else //draw buttons for mission and general messages { if (image > 0) { if(MovieButton) { // draw the button with the relevant image, don't add Down to the image ID if it's // a movie button. RenderImageToButton(IntImages,(UWORD)(image),psBuffer,Down,TOPBUTTON); } else { //draw the button with the relevant image RenderImageToButton(IntImages,(UWORD)(image+Down),psBuffer,Down,TOPBUTTON); } } } CloseButtonRender(); if (Hilight) { iV_DrawImage(IntImages,IMAGE_BUT_HILITE,xOffset+psButton->x, yOffset+psButton->y); } } /* displays the PIE view for the current message */ void intDisplayPIEView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_TABFORM *Form = (W_TABFORM*)psWidget; MESSAGE *psMessage = (MESSAGE *)Form->pUserData; UDWORD x0,y0,x1,y1; VIEW_RESEARCH *psViewResearch; SWORD image = -1; RESEARCH *psResearch; //shouldn't have any proximity messages here... if (psMessage->type == MSG_PROXIMITY) { return; } if (psMessage && psMessage->pViewData) { x0 = xOffset+Form->x; y0 = yOffset+Form->y; x1 = x0 + Form->width; y1 = y0 + Form->height; //moved from after close render RenderWindowFrame(&FrameNormal,x0-1,y0-1,x1-x0+2,y1-y0+2); OpenButtonRender((UWORD)(xOffset+Form->x), (UWORD)(yOffset+Form->y), Form->width, Form->height); //OpenButtonRender(Form->x, Form->y,Form->width, Form->height); if (((VIEWDATA *)psMessage->pViewData)->type != VIEW_RES) { ASSERT( FALSE, "intDisplayPIEView: Invalid message type" ); return; } //render an object psViewResearch = (VIEW_RESEARCH *)((VIEWDATA *)psCurrentMsg->pViewData)->pData; psResearch = getResearchForMsg((VIEWDATA *)psCurrentMsg->pViewData); renderResearchToBuffer(psResearch, x0+(x1-x0)/2, y0+(y1-y0)/2); CloseButtonRender(); //draw image icon in top left of window image = (SWORD)getResearchForMsg((VIEWDATA *)psMessage->pViewData)->iconID; if (image > 0) { iV_DrawImage(IntImages,image,x0,y0); } } } #ifndef NO_VIDEO /* displays the FLIC view for the current message */ void intDisplayFLICView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_TABFORM *Form = (W_TABFORM*)psWidget; MESSAGE *psMessage = (MESSAGE *)Form->pUserData; UDWORD x0,y0,x1,y1; VIEW_RESEARCH *psViewResearch; //shouldn't have any proximity messages here... if (psMessage->type == MSG_PROXIMITY) { return; } if (psMessage && psMessage->pViewData) { OpenButtonRender((UWORD)(xOffset+Form->x), (UWORD)(yOffset+Form->y), Form->width, Form->height); x0 = xOffset+Form->x; y0 = yOffset+Form->y; x1 = x0 + Form->width; y1 = y0 + Form->height; if (((VIEWDATA *)psMessage->pViewData)->type != VIEW_RES) { ASSERT( FALSE, "intDisplayFLICView: Invalid message type" ); return; } //render a frame of the current movie psViewResearch = (VIEW_RESEARCH *)((VIEWDATA *)psCurrentMsg->pViewData)->pData; seq_RenderVideoToBuffer(NULL, psViewResearch->sequenceName, gameTime2, SEQUENCE_HOLD); //download to screen now seq_BlitBufferToScreen((SBYTE *)rendSurface.buffer, rendSurface.scantable[1], x0, y0); CloseButtonRender(); } } #endif /* displays the TEXT view for the current message */ void intDisplayTEXTView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_TABFORM *Form = (W_TABFORM*)psWidget; MESSAGE *psMessage = (MESSAGE *)Form->pUserData; UDWORD x0, y0, x1, y1, i, linePitch; UDWORD ty; x0 = xOffset+Form->x; y0 = yOffset+Form->y; x1 = x0 + Form->width; y1 = y0 + Form->height; ty = y0; RenderWindowFrame(&FrameNormal,x0,y0,x1-x0,y1-y0); if (psMessage) { iV_SetFont(WFont); /* Get the travel to the next line */ linePitch = iV_GetTextLineSize(); /* Fix for spacing.... */ linePitch+=6; ty+=3; /* Fix for spacing.... */ iV_SetTextColour(iV_PaletteNearestColour(255, 255, 255)); //add each message for (i = 0; i < ((VIEWDATA *)psMessage->pViewData)->numText; i++) { //displayIntelligenceMessage(psMessage); //check haven't run out of room first! if (i * linePitch > Form->height) { ASSERT( FALSE, "intDisplayTEXTView: Run out of room!" ); return; } //need to check the string will fit! iV_DrawText(((VIEWDATA *)psMessage->pViewData)->ppTextMsg[i], x0 + TEXT_XINDENT, (ty + TEXT_YINDENT*3) + (i * linePitch)); } } } //adds text to full screen video void addVideoText(SEQ_DISPLAY *psSeqDisplay, UDWORD sequence) { UDWORD i, x, y; if (psSeqDisplay->numText > 0) { debug( LOG_NEVER, "avt seq=%d [%s]\n", sequence, psSeqDisplay->ppTextMsg[0] ); //add each message, first at the top x = VIDEO_TEXT_TOP_X; y = VIDEO_TEXT_TOP_Y; seq_AddTextForVideo(psSeqDisplay->ppTextMsg[0], x, y, TEXT_START_FRAME, TEXT_END_FRAME, FALSE); //startframe endFrame //add each message, the rest at the bottom x = VIDEO_TEXT_BOTTOM_X; y = VIDEO_TEXT_BOTTOM_Y; i = 1; while (i < psSeqDisplay->numText) { seq_AddTextForVideo(psSeqDisplay->ppTextMsg[i], x, y, TEXT_START_FRAME, TEXT_END_FRAME, FALSE); //startframe endFrame //initialise after the first setting x = y = 0; i++; } } } /*rotate the view so looking directly down if forward = TRUE or back to previous view if forward = FALSE */ /*void intelMapView(BOOL forward) { if (forward) { //save the current viewing angle viewAngle = player.r.x; viewHeight = player.p.y; //rotate to top down view player.r.x = DEG(-90); player.p.y = INTELMAP_VIEWHEIGHT; } else { //rotate back to previous view angle player.r.x = viewAngle; player.p.y = viewHeight; } }*/ /*this sets the width and height for the Intel map surface so that it fill the appropriate sized image for the view*/ /*void setIntelBufferSize(UDWORD type) { switch (type) { case MSG_CAMPAIGN: case MSG_RESEARCH: pIntelMapSurface->width = INTMAP_CAMPAIGNWIDTH; pIntelMapSurface->height = INTMAP_CAMPAIGNHEIGHT; break; case MSG_MISSION: //case MSG_TUTORIAL: pIntelMapSurface->width = INTMAP_MISSIONWIDTH; pIntelMapSurface->height = INTMAP_MISSIONHEIGHT; break; case MSG_PROXIMITY: pIntelMapSurface->width = INTMAP_PROXIMITYWIDTH; pIntelMapSurface->height = INTMAP_PROXIMITYHEIGHT; break; default: ASSERT( FALSE, "Invalid message type" ); } } */ /*sets the intel map surface back to the size it was created with */ /*void resetIntelBufferSize(void) { pIntelMapSurface->width = MSG_BUFFER_WIDTH; pIntelMapSurface->height = MSG_BUFFER_HEIGHT; }*/ /* draws the text message in the message window - only allows for one at the moment!*/ /*void displayIntelligenceMessage(MESSAGE *psMessage) { UDWORD x1, x2, y, indent = 10; x1 = INTMAP_TEXTX; x2 = INTMAP_TEXTX + INTMAP_TEXTWIDTH; y = INTMAP_TEXTY + INTMAP_TEXTHEIGHT + indent; //size and position depends on the type of message //switch (psMessage->type) { case MSG_RESEARCH: x1 = INTMAP_RESEARCHX; x2 = INTMAP_RESEARCHX + INTMAP_RESEARCHWIDTH; y = INTMAP_RESEARCHY + INTMAP_RESEARCHHEIGHT + indent; break; case MSG_MISSION: case MSG_CAMPAIGN: //case MSG_TUTORIAL: x1 = INTMAP_MISSIONX; x2 = INTMAP_MISSIONX + INTMAP_MISSIONWIDTH; y = INTMAP_MISSIONY + INTMAP_MISSIONHEIGHT + indent;// + INTMAP_TEXTWINDOWHEIGHT;// - indent; break; case MSG_PROXIMITY: x1 = INTMAP_PROXIMITYX; x2 = INTMAP_PROXIMITYX + INTMAP_PROXIMITYWIDTH; y = INTMAP_PROXIMITYY + INTMAP_PROXIMITYHEIGHT + indent;// + INTMAP_TEXTWINDOWHEIGHT;// - indent; break; default: ASSERT( FALSE, "Unknown message type" ); } // screenSetTextColour(255,255,255); // screenTextOut(x+1,y+1,psMessage->pViewData->pTextMsg); //scrollMessage(psMessage->pViewData->pTextMsg, x2, x1, y, 5); setConsoleSizePos(x1, y, (x2-x1)); setConsolePermanence(TRUE); addConsoleMessage(psMessage->pViewData->pTextMsg, LEFT_JUSTIFY); } */ /*sets psCurrentMsg for the Intelligence screen*/ void setCurrentMsg(void) { MESSAGE *psMsg, *psLastMsg; psLastMsg = NULL; for (psMsg = apsMessages[selectedPlayer]; psMsg != NULL; psMsg = psMsg->psNext) { if (psMsg->type != MSG_PROXIMITY) { psLastMsg = psMsg; } } psCurrentMsg = psLastMsg; } //initialise the text display stats for the current message /*void initTextDisplay(MESSAGE *psMessage, UDWORD fontID, UWORD fontColour) { UDWORD width, currentLength, strLen, frames, inc; currentTextDisplay.font = fontID; currentTextDisplay.fontColour = fontColour; currentTextDisplay.startTime = 0; currentTextDisplay.text[0] = '\0'; if (psMessage == NULL || psMessage->pViewData->pTextMsg == NULL) { currentTextDisplay.totalFrames = 0; return; } //size of the text window depends on the message type switch (psMessage->type) { //case MSG_CAMPAIGN: case MSG_RESEARCH: width = INTMAP_RESEARCHWIDTH; break; //case MSG_MISSION: //case MSG_TUTORIAL: // width = INTMAP_MISSIONWIDTH; // break; //case MSG_PROXIMITY: // width = INTMAP_PROXIMITYWIDTH; // break; default: ASSERT( FALSE, "Unknown message type" ); return; } currentLength = 0; strLen = strlen(psMessage->pViewData->pTextMsg); frames = 0; currentTextDisplay.totalFrames = 0; //get the length of the text message for (inc=0; inc < strLen; inc++) { currentLength += iV_GetCharWidth(psMessage->pViewData->pTextMsg[inc]); } width += currentLength; currentLength = 0; //how long for string to completely pass along width of view for (inc=0; inc < MAX_STR_LENGTH; inc++) { if (inc < strLen) { currentLength += iV_GetCharWidth(psMessage->pViewData->pTextMsg[inc]); } else { currentLength += iV_GetCharWidth(' '); } if (currentLength > width) { break; } currentTextDisplay.totalFrames++; } currentTextDisplay.startTime = gameTime2; }*/ /* scroll the text message from right to left - aka tickertape messages */ /*void scrollMessage(char *pText, UDWORD startX, UDWORD endX, UDWORD y, UDWORD gap) { UDWORD frames, inc, strLen; SDWORD position, startChar, currentLength; UDWORD endChar, text; //work out current frame frames = 20 * (gameTime2 - currentTextDisplay.startTime)/GAME_TICKS_PER_SEC; //get the number of chars in the string strLen = strlen(pText); currentLength = 0; //work out position of the string for (inc = 0; inc < frames; inc++) { //framesMinus1 = frames - 1; if ((frames - 1 - inc) > (strLen-1)) { //add a blank for 'characters' at the end of the sentence currentLength += iV_GetCharWidth(' '); //nothing to draw so go to next inc continue; } //increment the current amount drawn currentLength += iV_GetCharWidth(pText[frames - 1 - inc]); if (((SDWORD)startX - currentLength) < (SDWORD)endX) { //ignore this character since off the scale inc--; break; } position = startX - currentLength; } startChar = frames - 1 - inc; if (startChar < 0) { startChar = 0; } endChar = frames; if (endChar > strLen) { endChar = strLen; } text = 0; for (inc = startChar; inc != endChar && inc < strLen; inc++) { currentTextDisplay.text[text++] = pText[inc]; } currentTextDisplay.text[text] = '\0'; iV_SetFont(currentTextDisplay.font); iV_SetTextColour(currentTextDisplay.fontColour); iV_DrawText(currentTextDisplay.text, position, y); //time to redo message if (frames > currentTextDisplay.totalFrames + gap) { //start again currentTextDisplay.startTime = gameTime2; } }*/ /* Process return code from the Message View for Tutorial Mode*/ /*void intProcessMessageView(UDWORD id) { if (id == IDINTMAP_CLOSE) { //if close button pressed on 3D View then close the view only psCurrentMsg = NULL; initTextDisplay(psCurrentMsg, WFont, 255); //intRemoveMessageView(); intRemoveMessageViewNoAnim(); intResetScreen(TRUE); } }*/ /* Add the Proximity message buttons */ /*BOOL intAddProximityButton(MESSAGE *pMessage, UDWORD inc) { W_FORMINIT sBFormInit; VIEW_LOCATION *pViewLocation = (VIEW_LOCATION*)pMessage->pViewData->pData; memset(&sBFormInit, 0, sizeof(W_FORMINIT)); sBFormInit.formID = 0; sBFormInit.id = IDINTMAP_PROXSTART + inc; ASSERT( sBFormInit.id < IDINTMAP_PROXEND,"Too many message buttons" ); sBFormInit.majorID = 0; sBFormInit.minorID = 0; sBFormInit.style = WFORM_CLICKABLE; //width and height is dependant on the state of the message - see intDisplayProximityButton //the x and y need to be set up each time the button is drawn - see intDisplayProximityButton sBFormInit.pDisplay = intDisplayProximityButton; //set the data for this button sBFormInit.pUserData = pMessage; if (!widgAddForm(psWScreen, &sBFormInit)) { return FALSE; } return TRUE; }*/ /*Displays the proximity messages used on the intelligence map */ /*void intDisplayProximityButton(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, UDWORD *pColours) { W_CLICKFORM *psButton = (W_CLICKFORM*)psWidget; MESSAGE *psMsg = (MESSAGE*)psButton->pUserData; PROXIMITY_DISPLAY *psProximityDisplay; BOOL Hilight = FALSE; VIEW_LOCATION *psViewLocation; UBYTE imageID; UDWORD delay = 100; (void)pColours; (void)xOffset; (void)yOffset; // Get the object associated with this widget. psMsg = (MESSAGE *)psButton->pUserData; ASSERT( psMsg->type == MSG_PROXIMITY, "Invalid message type" ); psViewLocation = (VIEW_LOCATION *)psMsg->pViewData->pData; //if not within view ignore message if (!clipXY(psViewLocation->location.x, psViewLocation->location.z)) { return; } psProximityDisplay = getProximityDisplay(psMsg); psButton->x = (SWORD)psProximityDisplay->screenX; psButton->y = (SWORD)psProximityDisplay->screenY; //get the screen coords for the message - check not 'off' the screen if (psButton->x < 0 || psButton->x > DISP_WIDTH || psButton->y < 0 || psButton->y > DISP_HEIGHT) { return; } Hilight = psButton->state & WBUTS_HILITE; //if hilighted if (Hilight) { imageID = IMAGE_INTEL_PROXHILI; psButton->width = iV_GetImageWidth(IntImages,IMAGE_INTEL_PROXHILI); psButton->height = iV_GetImageHeight(IntImages,IMAGE_INTEL_PROXHILI); } else if (psMsg->read) { //if the message is read - don't animate imageID = IMAGE_INTEL_PROXREAD; psButton->width = iV_GetImageWidth(IntImages,IMAGE_INTEL_PROXREAD); psButton->height = iV_GetImageHeight(IntImages,IMAGE_INTEL_PROXREAD); } else { //draw animated if ((GetTickCount() - psProximityDisplay->timeLastDrawn) > delay) { psProximityDisplay->strobe++; if (psProximityDisplay->strobe > 2) { psProximityDisplay->strobe = 0; } psProximityDisplay->timeLastDrawn = GetTickCount(); } imageID = (UBYTE)(IMAGE_INTEL_PROXIMITY + psProximityDisplay->strobe); psButton->width = iV_GetImageWidth(IntImages,IMAGE_INTEL_PROXIMITY); psButton->height = iV_GetImageHeight(IntImages,IMAGE_INTEL_PROXIMITY); } //adjust button x and y for width and height of button psButton->x = (SWORD)(psButton->x - psButton->width/(UWORD)2); psButton->y = (SWORD)(psButton->y - psButton->height/(UWORD)2); if (psButton->x < 0 || psButton->x > DISP_WIDTH || psButton->y < 0 || psButton->y > DISP_HEIGHT) { return; } //if there is a message 3Dview up - don't draw the proximity messages underneath if (psCurrentMsg && psCurrentMsg->pViewData) { if (!checkMessageOverlap(psCurrentMsg, psButton->x, psButton->y)) { return; } } //draw the 'button' iV_DrawImage(IntImages,imageID, psButton->x, psButton->y); }*/ /*check the x and y are within the messages 3D view if on screen */ /*BOOL checkMessageOverlap(MESSAGE *psMessage, SWORD x, SWORD y) { SWORD messageX, messageY, messageWidth, messageHeight; switch (psMessage->type) { case MSG_CAMPAIGN: case MSG_RESEARCH: messageX = INTMAP_CAMPAIGNX; messageY = INTMAP_CAMPAIGNY; messageWidth = INTMAP_CAMPAIGNWIDTH; messageHeight = INTMAP_CAMPAIGNHEIGHT; break; case MSG_MISSION: messageX = INTMAP_MISSIONX; messageY = INTMAP_MISSIONY; messageWidth = INTMAP_MISSIONWIDTH; messageHeight = INTMAP_MISSIONHEIGHT; break; case MSG_PROXIMITY: messageX = INTMAP_PROXIMITYX; messageY = INTMAP_PROXIMITYY; messageWidth = INTMAP_PROXIMITYWIDTH; messageHeight = INTMAP_PROXIMITYHEIGHT; break; default: ASSERT( FALSE, "Unknown message type" ); return FALSE; } if ((x > messageX && x < (messageX + messageWidth)) && (y > messageY && y < (messageY + messageHeight))) { return FALSE; } else { return TRUE; } }*/ /*sets which states need to be paused when the intelligence screen is up*/ void setIntelligencePauseState(void) { if (!bMultiPlayer) { gameTimeStop(); setGameUpdatePause(TRUE); if(!bInTutorial) { // Don't pause the scripts or the console if the tutorial is running. setScriptPause(TRUE); setConsolePause(TRUE); } setScrollPause(TRUE); } } /*resets the pause states */ void resetIntelligencePauseState(void) { if (!bMultiPlayer) { setGameUpdatePause(FALSE); if(!bInTutorial) { setScriptPause(FALSE); } setScrollPause(FALSE); setConsolePause(FALSE); gameTimeStart(); } } // play this message immediately, but definitely donot tell the intelligence screen to start void displayImmediateMessage(MESSAGE *psMessage) { /* This has to be changed to support a script calling a message in the intellegence screen */ #ifdef NO_VIDEO psCurrentMsg = psMessage; /* so we lied about definately not starting the intelligence screen */ addIntelScreen(); /* reset mouse cursor, since addIntelScreen() doesn't do that */ frameSetCursorFromRes(IDC_DEFAULT); /* addIntelScreen() (via addIntelMap()) actually starts * playing psCurrentMsg automatically */ return; #endif StartMessageSequences(psMessage,TRUE); } // return whether a message is immediate BOOL messageIsImmediate(void) { return immediateMessage; } /*sets the flag*/ void setMessageImmediate(BOOL state) { immediateMessage = state; }