/*============================================================================= Name : researchgui.c Purpose : logic for the research manager Created 5/27/1998 by ddunlop Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #ifndef SW_Render #include #endif #include #include #include "glinc.h" #include "main.h" #include "types.h" #include "universe.h" #include "region.h" #include "uicontrols.h" #include "feflow.h" #include "font.h" #include "fontreg.h" #include "objtypes.h" #include "texreg.h" #include "task.h" #include "mouse.h" #include "CommandLayer.h" #include "piePlate.h" #include "globals.h" #include "CommandWrap.h" #include "scroller.h" #include "soundevent.h" #include "randy.h" #include "mainrgn.h" #include "shipdefs.h" #include "prim2d.h" #include "researchapi.h" #include "researchgui.h" #include "strings.h" #include "fereg.h" #include "taskbar.h" #include "render.h" #include "fixed.h" #include "singleplayer.h" #include "tutor.h" #include "trademgr.h" #include "multiplayergame.h" #include "FEColour.h" #include "glcompat.h" #include "InfoOverlay.h" #include "commandnetwork.h" /*============================================================================= Defines: =============================================================================*/ #define RM_LabIcon "Research_icon.lif" // defines for spacing #define RM_VertSpacing (fontHeight(" ") >> 1) #define RM_HorzSpacing (fontWidth(" ")) #define RM_InfoWidth (region->rect.x1 - region->rect.x0) // defines for the headings in the tech list box #define WeaponHeading 0 #define ConstructionHeading 1 #define InterdictionHeading 2 #define SupportHeading 3 // defines for the buttons sizeing #define LB_BUTTONSIZE 45 #define LB_HALFBUTTON (LB_BUTTONSIZE/2) #define LB_BUTTONSPACE 6 #define LB_BUTTONWIDTH 25 // defines for the pregeneration of the circle data #define CIRCLE_POINTS 150 #define CIRCLE_XRADIUS 0.06875 #define CIRCLE_YRADIUS 0.09166666666667 // defines for the pulse effect #define PULSE_INC 2048 #define FIXED16_ONE 65536 #define PULSE_COLOR colRGB(200, 200, 200) // defines for the pictures LRM caching #define RM_DSINIT 0 #define RM_DSNORMAL 1 #define RM_DSDRAW 2 #define RM_DSERASE 3 #define RM_MARQUEERAD 3 #define RM_NUMMARQUEE 3 #define RM_MARQUEESPACE 7 #define RM_MARQUEE_Y_SPACE 18 #define RM_MARQUEE_HEIGHT (LB_BUTTONSIZE - (RM_MARQUEE_Y_SPACE * 2)) #define RM_MARQUEE_HALF_HEIGHT (RM_MARQUEE_HEIGHT / 2) #define RM_MARQUEERATE 3.0 #define RM_TEXTURE_INSET 3 #define RM_LAB_INSET 5 #define NUMTECHSINLIST 34 /*============================================================================= Data: =============================================================================*/ static sdword rmRenderEverythingCounter; static featom* _rmTechAtom; static regionhandle _rmTechRegion; static bool _rmTechRender = FALSE; double chop_temp; bool rmPaletted; fonthandle rmTechListFont=0; fonthandle rmTechInfoFont=0; char rmTechListFontName [RM_FontNameLength] = RM_TechListFont; char rmTechInfoFontName [RM_FontNameLength] = RM_TechInfoFont; //flag indicating loaded status of this screen fibfileheader *rmScreensHandle = NULL; regionhandle rmTechBriefRegion = NULL; regionhandle rmTechImageRegion = NULL; regionhandle rmTechListRegion = NULL; regionhandle rmBaseRegion = NULL; regionhandle rmLab1Region = NULL; regionhandle rmLab2Region = NULL; regionhandle rmLab3Region = NULL; regionhandle rmLab4Region = NULL; regionhandle rmLab5Region = NULL; regionhandle rmLab6Region = NULL; regionhandle rmConnectorRegion = NULL; regionhandle rmLabConnector1Region = NULL; regionhandle rmLabConnector2Region = NULL; regionhandle rmLabConnector3Region = NULL; regionhandle rmLabConnector4Region = NULL; regionhandle rmLabConnector5Region = NULL; regionhandle rmLabConnector6Region = NULL; listwindowhandle rmTechListWindowHandle = NULL; // callbacks for ui elements void rmSelectAll(char *string, featom *atom); void rmClearAllLabs(char *string, featom *atom); void rmClearSelectedLab(char *string, featom *atom); void rmResearchItem(char *string, featom *atom); void rmExitMenu(char *string, featom *atom); void rmTechListWindow(char *string, featom *atom); void rmExtendedInfo(char *string, featom *atom); // callbacks for user draw areas void rmLab1Draw(featom *atom, regionhandle region); void rmLab2Draw(featom *atom, regionhandle region); void rmLab3Draw(featom *atom, regionhandle region); void rmLab4Draw(featom *atom, regionhandle region); void rmLab5Draw(featom *atom, regionhandle region); void rmLab6Draw(featom *atom, regionhandle region); void rmLabConnector1Draw(featom *atom, regionhandle region); void rmLabConnector2Draw(featom *atom, regionhandle region); void rmLabConnector3Draw(featom *atom, regionhandle region); void rmLabConnector4Draw(featom *atom, regionhandle region); void rmLabConnector5Draw(featom *atom, regionhandle region); void rmLabConnector6Draw(featom *atom, regionhandle region); void rmConnectorDraw(featom *atom, regionhandle region); void rmTechBriefDraw(featom *atom, regionhandle region); void rmTechImageDraw(featom *atom, regionhandle region); fecallback rmCallback[] = { {rmSelectAll , "RM_SelectAll" }, {rmClearAllLabs , "RM_ClearAllLabs" }, {rmClearSelectedLab , "RM_ClearLab" }, {rmResearchItem , "RM_ResearchItem" }, {rmExitMenu , "RM_ExitMenu" }, {rmTechListWindow , "RM_TechListWindow" }, {rmExtendedInfo , "RM_ExtendedInfo" }, {NULL, NULL } }; fedrawcallback rmDrawCallback[] = { {rmLab1Draw, "RM_Lab1Draw" }, {rmLab2Draw, "RM_Lab2Draw" }, {rmLab3Draw, "RM_Lab3Draw" }, {rmLab4Draw, "RM_Lab4Draw" }, {rmLab5Draw, "RM_Lab5Draw" }, {rmLab6Draw, "RM_Lab6Draw" }, {rmLabConnector1Draw, "RM_LabConnector1Draw" }, {rmLabConnector2Draw, "RM_LabConnector2Draw" }, {rmLabConnector3Draw, "RM_LabConnector3Draw" }, {rmLabConnector4Draw, "RM_LabConnector4Draw" }, {rmLabConnector5Draw, "RM_LabConnector5Draw" }, {rmLabConnector6Draw, "RM_LabConnector6Draw" }, {rmConnectorDraw, "RM_ConnectorDraw" }, {rmTechBriefDraw, "RM_TechBriefDraw" }, {rmTechImageDraw, "RM_TechImageDraw" }, {NULL, NULL } }; TechPrintList PlayerTechListStatic[NUMTECHSINLIST] = { {ITEM_CLASSHEADER , 0 , WeaponHeading }, {ITEM_TECHNOLOGY , 0 , MassDrive1Kt }, {ITEM_TECHNOLOGY , 0 , Chassis1 }, {ITEM_TECHNOLOGY , 0 , FireControl }, {ITEM_TECHNOLOGY , 0 , CoolingSystems }, {ITEM_TECHNOLOGY , 0 , PlasmaWeapons }, {ITEM_TECHNOLOGY , 0 , AdvancedCoolingSystems }, {ITEM_TECHNOLOGY , 0 , AdvancedFireControl }, {ITEM_TECHNOLOGY , 0 , CloakDefenseFighter }, {ITEM_CLASSHEADER , 0 , ConstructionHeading }, {ITEM_TECHNOLOGY , 0 , MassDrive10Kt }, {ITEM_TECHNOLOGY , 0 , Chassis2 }, {ITEM_TECHNOLOGY , 0 , MediumGuns }, {ITEM_TECHNOLOGY , 0 , TargetingSystems }, {ITEM_TECHNOLOGY , 0 , MineLayerTech }, {ITEM_TECHNOLOGY , 0 , NewAlloys }, {ITEM_CLASSHEADER , 0 , InterdictionHeading }, {ITEM_TECHNOLOGY , 0 , MassDrive100Kt }, {ITEM_TECHNOLOGY , 0 , Chassis3 }, {ITEM_TECHNOLOGY , 0 , IonWeapons }, {ITEM_TECHNOLOGY , 0 , MissileWeapons }, {ITEM_TECHNOLOGY , 0 , DDDFDFGFTech }, {ITEM_TECHNOLOGY , 0 , MassDrive1Mt }, {ITEM_TECHNOLOGY , 0 , RepairTech }, {ITEM_TECHNOLOGY , 0 , HeavyGuns }, {ITEM_CLASSHEADER , 0 , SupportHeading }, {ITEM_TECHNOLOGY , 0 , ProximityDetector }, {ITEM_TECHNOLOGY , 0 , SupportRefuelTech }, {ITEM_TECHNOLOGY , 0 , AdvanceTacticalSupport }, {ITEM_TECHNOLOGY , 0 , ConstructionTech }, {ITEM_TECHNOLOGY , 0 , SensorsArrayTech }, {ITEM_TECHNOLOGY , 0 , GravityWellGeneratorTech}, {ITEM_TECHNOLOGY , 0 , CloakGeneratorTech }, {ITEM_ENDLIST , 0 , 0 } }; TechPrintList SinglePlayerR1TechList[NUMTECHSINLIST]; TechPrintList SinglePlayerR2TechList[NUMTECHSINLIST]; TechPrintList MultiPlayerR1TechList[NUMTECHSINLIST]; TechPrintList MultiPlayerR2TechList[NUMTECHSINLIST]; TechPrintList MultiPlayerCR1TechList[NUMTECHSINLIST]; TechPrintList MultiPlayerCR2TechList[NUMTECHSINLIST]; TechNames TechImageNames[]= { {"NewAlloys.lif" }, {"MassDrive1Kt.lif" }, {"CoolingSystems.lif" }, {"CloakDefenseFighter.lif" }, {"TargetingSystems.lif" }, {"PlasmaWeapons.lif" }, {"Chassis1.lif" }, {"MassDrive10Kt.lif" }, {"MediumGuns.lif" }, {"MineLayerTech.lif" }, {"Chassis2.lif" }, {"AdvancedCoolingSystems.lif" }, {"MassDrive100Kt.lif" }, {"FireControl.lif" }, {"SupportRefuelTech.lif" }, {"AdvanceTacticalSupport.lif" }, {"IonWeapons.lif" }, {"DDDFDFGFTech.lif" }, {"Chassis3.lif" }, {"MassDrive1Mt.lif" }, {"AdvancedFireControl.lif" }, {"MissileWeapons.lif" }, {"ConstructionTech.lif" }, {"HeavyGuns.lif" }, {"ProximityDetector.lif" }, {"SensorsArrayTech.lif" }, {"GravityWellGeneratorTech.lif" }, {"CloakGeneratorTech.lif" }, {"RepairTech.lif" }, {"SalvageTech.lif" }, {NULL } }; char* TechImagePaths[]= { {"ResearchGUI\\Race1\\" }, {"ResearchGUI\\Race2\\" }, {NULL } }; TechPrintList *PlayerTechList; //colors for printing selections and stuff color rmSelectionTextColor = RM_SelectionTextColor; color rmResearchingTextColor = RM_ResearchingTextColor; color rmCantResearchTextColor = RM_CantResearchTextColor; color rmStandardTextColor = RM_StandardTextColor; color rmClassHeadingTextColor = RM_ClassHeadingTextColor; color rmProgressToGoColor = RM_ProgressToGoColor; color rmProgressDoneColor0 = RM_ProgressDoneColor0; color rmProgressDoneColor1 = RM_ProgressDoneColor1; color rmLabActiveColor = RM_LabActiveColor; color rmPulseColor = RM_PulseColor; color rmNoResearchItemColor = RM_NoResearchItemColor; color rmMarqueeOnColor = RM_MarqueeOnColor; color rmMarqueeSemiOnColor = RM_MarqueeSemiOnColor; color rmMarqueeOffColor = RM_MarqueeOffColor; sdword rmCurIndex=-1; TechnologyType techinfo=-1; // is TRUE if GUI is active FALSE otherwise. bool rmGUIActive=FALSE; // List of lab buttons LabPrintList labbuttons[NUM_RESEARCHLABS]; // image variables for technology bitmap LRUPicture pictures[RM_TOTALPICS]; udword rmCurTexture = TR_InvalidInternalHandle; lifheader *rmCurTechImage = NULL; TechnologyType rmCurTechTexture = -1; sdword drawstate; udword rmLabTexture[MAX_RACES] = { TR_InvalidInternalHandle, TR_InvalidInternalHandle }; lifheader *rmLabImage[MAX_RACES] = { NULL, NULL }; // variable for marque light position real32 marqueetime=0.0; real32 marqueepos=0; bool rmExtendedInfoActive = FALSE; bool rmIoSaveState; uword researchingthistopic; bool multipleresearchersselected; ResearchTopic *multipleresearchtopic; /*============================================================================= Function Prototypes: =============================================================================*/ void rmUpdateTechList(void); sdword rmSelectAvailableTech(regionhandle region, sdword ID, udword event, udword data); sdword rmSelectTechType(regionhandle region, sdword yClicked); void SelectTechWindow(void); /*============================================================================= Functions: =============================================================================*/ void rmDirtyTechInfo() { if (rmTechBriefRegion != NULL) { #ifdef DEBUG_STOMP regVerify(rmTechBriefRegion); #endif rmTechBriefRegion->status |= RSF_DrawThisFrame; } if (rmTechImageRegion != NULL) { #ifdef DEBUG_STOMP regVerify(rmTechImageRegion); #endif rmTechImageRegion->status |= RSF_DrawThisFrame; } if (rmConnectorRegion != NULL) { #ifdef DEBUG_STOMP regVerify(rmConnectorRegion); #endif rmConnectorRegion->status |= RSF_DrawThisFrame; } } void rmDirtyTechList() { if (rmTechListRegion != NULL) { #ifdef DEBUG_STOMP regVerify(rmTechListRegion); #endif rmTechListRegion->status |= RSF_DrawThisFrame; } if (rmLab1Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab1Region); #endif rmLab1Region->status |= RSF_DrawThisFrame; } if (rmLab2Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab2Region); #endif rmLab2Region->status |= RSF_DrawThisFrame; } if (rmLab3Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab3Region); #endif rmLab3Region->status |= RSF_DrawThisFrame; } if (rmLab4Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab4Region); #endif rmLab4Region->status |= RSF_DrawThisFrame; } if (rmLab5Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab5Region); #endif rmLab5Region->status |= RSF_DrawThisFrame; } if (rmLab6Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLab6Region); #endif rmLab6Region->status |= RSF_DrawThisFrame; } if (rmLabConnector1Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector1Region); #endif rmLabConnector1Region->status |= RSF_DrawThisFrame; } if (rmLabConnector2Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector2Region); #endif rmLabConnector2Region->status |= RSF_DrawThisFrame; } if (rmLabConnector3Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector3Region); #endif rmLabConnector3Region->status |= RSF_DrawThisFrame; } if (rmLabConnector4Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector4Region); #endif rmLabConnector4Region->status |= RSF_DrawThisFrame; } if (rmLabConnector5Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector5Region); #endif rmLabConnector5Region->status |= RSF_DrawThisFrame; } if (rmLabConnector6Region != NULL) { #ifdef DEBUG_STOMP regVerify(rmLabConnector6Region); #endif rmLabConnector6Region->status |= RSF_DrawThisFrame; } } void rmSelectAll(char *string, featom *atom) { sdword index; for (index=0; indexlabstatus==LS_NORESEARCHITEM) { labbuttons[index].selected = TRUE; } } } // This function is called when a technology has just finished being researched. This is so the technology list window // can be updated. The lab highlight border is turned off. void rmClearLab(sdword labindex) { /* rmUpdateTechList(); // Regenerate list because something has just finished being researched uicListCleanUp(rmTechListWindowHandle); for (index=0;PlayerTechList[index].itemtype!=ITEM_ENDLIST; index++) { if ( (PlayerTechList[index].itemstat != STAT_CANTPRINT) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { if (PlayerTechList[index].itemtype == ITEM_CLASSHEADER) uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], 0, UICLW_AddToTail); else uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], UICLI_CanSelect, UICLW_AddToTail); } } rmTechListWindowHandle->CurLineSelected = NULL; SelectTechWindow();*/ labbuttons[labindex].selected = FALSE; } void rmClearAllLabs(char *string, featom *atom) { sdword index; for (index=0; indexlabstatus==LS_RESEARCHITEM) ) { if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchClearLab) return; if (!multiPlayerGame) { rmClearResearchlab(universe.curPlayerPtr,index); } else { clWrapResearch(RESEARCH_SUBCOMMAND_STOP, universe.curPlayerIndex, index, 0); } //labbuttons[index].selected = FALSE; halted = TRUE; } } if (halted) { speechEventFleet(COMM_F_Research_Stop, 0, universe.curPlayerIndex); } } void rmResearchItem(char *string, featom *atom) { sdword index; bool found=FALSE; TechPrintList *tech; if (rmTechListWindowHandle->CurLineSelected!=NULL) { tech = (TechPrintList*)rmTechListWindowHandle->CurLineSelected->data; if (tech->itemstat!=STAT_ALREADYHAVE) { if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchResearch) return; for (index=0; indexlabstatus==LS_NORESEARCHITEM) ) { if (!multiPlayerGame) { rmAssignPlayersLabToResearch(universe.curPlayerPtr,index,tech->itemID); } else { clWrapResearch(RESEARCH_SUBCOMMAND_START, universe.curPlayerIndex, index, tech->itemID); labbuttons[index].lab->labstatus = LS_RESEARCHITEMSOON; // LS_NORESEARCHSHIP labbuttons[index].lab->topic = NULL; } labbuttons[index].pulsepos = 0; labbuttons[index].selected = FALSE; found = TRUE; if (universe.curPlayerPtr->race == R1) { speechEventFleet(COMM_F_Research_R1_Start, tech->itemID, universe.curPlayerIndex); } else if (universe.curPlayerPtr->race == R2) { speechEventFleet(COMM_F_Research_R2_Start, tech->itemID, universe.curPlayerIndex); } } } if (found==FALSE) { index = rmFindFreeLab(universe.curPlayerPtr); if (index!=-1) { if (!multiPlayerGame) { rmAssignPlayersLabToResearch(universe.curPlayerPtr,index,tech->itemID); } else { clWrapResearch(RESEARCH_SUBCOMMAND_START, universe.curPlayerIndex, index, tech->itemID); labbuttons[index].lab->labstatus = LS_RESEARCHITEMSOON; // LS_NORESEARCHSHIP labbuttons[index].lab->topic = NULL; } if (universe.curPlayerPtr->race == R1) { speechEventFleet(COMM_F_Research_R1_Start, tech->itemID, universe.curPlayerIndex); } else if (universe.curPlayerPtr->race == R2) { speechEventFleet(COMM_F_Research_R2_Start, tech->itemID, universe.curPlayerIndex); } } } #ifdef DEBUG_STOMP regVerify((regionhandle)&rmTechListWindowHandle->reg); #endif rmTechListWindowHandle->reg.status |= RSF_DrawThisFrame; } } } void rmExitMenu(char *string, featom *atom) { rmRenderEverythingCounter = 0; // used to be this //feScreenDelete(rmBaseRegion); // whoever this caused a memory leak, should use feCurrentScreenDelete to close the current screen // if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchClose) return; feCurrentScreenDelete(); rmBaseRegion = NULL; if (rmIoSaveState) ioEnable(); // enable rendering of main game screen mrRenderMainScreen = TRUE; glcFullscreen(FALSE); /* play the exit sound */ soundEvent(NULL, UI_ManagerExit); //restart the sound of space ambient soundEvent(NULL, UI_SoundOfSpace); spUnlockout(); rmGUIActive = FALSE; rmCurTechTexture = -1; rmTechBriefRegion = NULL; rmTechImageRegion = NULL; rmTechListRegion = NULL; rmLab1Region = NULL; rmLab2Region = NULL; rmLab3Region = NULL; rmLab4Region = NULL; rmLab5Region = NULL; rmLab6Region = NULL; rmConnectorRegion = NULL; rmLabConnector1Region = NULL; rmLabConnector2Region = NULL; rmLabConnector3Region = NULL; rmLabConnector4Region = NULL; rmLabConnector5Region = NULL; rmLabConnector6Region = NULL; // enable taskbar popup window tbDisable = FALSE; techinfo = -1; } void rmCloseIfOpen() { if (rmBaseRegion) { rmExitMenu(NULL,NULL); } } /*----------------------------------------------------------------------------- Name : rmMarqueePulse Description : Inputs : LabPrintList & region info Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmMarqueePulse(LabPrintList *labprint, regionhandle region) { sdword count, index; sdword x, y; rectangle *rect = ®ion->rect; primLine2(rect->x0, rect->y0, rect->x1, rect->y0, rmStandardTextColor); primLine2(rect->x0, rect->y1, rect->x1, rect->y1, rmStandardTextColor); x = rect->x0 + RM_MARQUEESPACE; y = rect->y0 + ((rect->y1 - rect->y0) >> 1); if ((labprint->selected) && (labprint->lab->labstatus==LS_RESEARCHITEM)) { for (count=FAST_TO_INT(marqueepos),index=0;indexlabid - 1; // zero based PlayerResearchInfo *research = &universe.curPlayerPtr->researchinfo; rect.x0 = region->rect.x0 + RM_LAB_INSET; rect.y0 = region->rect.y0 + RM_LAB_INSET; rect.x1 = region->rect.x1 - RM_LAB_INSET; rect.y1 = region->rect.y1 - RM_LAB_INSET; progressRect.x0 = rect.x0; progressRect.y0 = rect.y1 - 10; progressRect.x1 = rect.x1; progressRect.y1 = rect.y1; if (labprint->selected) state = lw_focus; else state = lw_normal; ferDrawFocusWindow(region, state); switch (labprint->lab->labstatus) { case LS_NORESEARCHSHIP : primRectSolid2(&rect, colRGB(0, 0, 0)); // clear area primRectOutline2(&progressRect, 1, rmNoResearchItemColor); // draw empty progress bar break; default: case LS_NORESEARCHITEM : primRectSolid2(&rect, colRGB(0, 0, 0)); // clear area primRectOutline2(&progressRect, 1, colRGB(255, 0, 0)); // draw empty active progress bar rect.x0 += 5; rect.x1 -= 5; rect.y1 = progressRect.y0 - RM_TEXTURE_INSET; // put above the progress bar if (glcActive()) { lifheader* lif = rmLabImage[universe.curPlayerPtr->race]; glcRectSolidTexturedScaled2(&rect, lif->width, lif->height, lif->data, rmPaletted ? lif->palette : NULL, TRUE); } else { if (rmPaletted) { trPalettedTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race], rmLabImage[universe.curPlayerPtr->race]->palette); } else { trRGBTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race]); } rndPerspectiveCorrection(FALSE); primRectSolidTextured2(&rect); } break; case LS_RESEARCHITEM : primRectOutline2(&progressRect, 1, colRGB(255, 0, 0)); rect.x0 += 5; rect.x1 -= 5; rect.y1 = progressRect.y0 - RM_TEXTURE_INSET; // put above the progress bar if (glcActive()) { lifheader* lif = rmLabImage[universe.curPlayerPtr->race]; glcRectSolidTexturedScaled2(&rect, lif->width, lif->height, lif->data, rmPaletted ? lif->palette : NULL, TRUE); } else { if (rmPaletted) { trPalettedTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race], rmLabImage[universe.curPlayerPtr->race]->palette); } else { trRGBTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race]); } rndPerspectiveCorrection(FALSE); primRectSolidTextured2(&rect); } // compute progress bar length percent = (real32)((1.0 - (real32)labprint->lab->topic->timeleft/(real32)research->techstat->TimeToComplete[labprint->lab->topic->techresearch])); // Make the progress rectangle fit within the red border progressRect.x0++; progressRect.x1--; progressRect.y0++; progressRect.y1--; if (labprint->selected) { pos = ((progressRect.x1 - progressRect.x0) * labprint->pulsepos) >> 16; pos = progressRect.x0 + pos; primLine2(pos, progressRect.y0 + 1, pos, progressRect.y1 - 1, 0); if (labprint->pulsepos > FIXED16_ONE) { labprint->pulsepos = 0; } else labprint->pulsepos += PULSE_INC; pos = ((progressRect.x1 - progressRect.x0) * labprint->pulsepos) >> 16; pos = progressRect.x0 + pos; primLine2(pos, progressRect.y0 + 1, pos, progressRect.y1 - 1, PULSE_COLOR); } width = ((real32)(progressRect.x1 - progressRect.x0)) * percent; progressRect.x1 = progressRect.x0 + FAST_TO_INT(width); progressColor[0] = rmProgressDoneColor0; progressColor[1] = rmProgressDoneColor0; progressColor[2] = rmProgressDoneColor1; progressColor[3] = rmProgressDoneColor1; primRectShaded2(&progressRect, progressColor); break; case LS_RESEARCHITEMSOON : primRectSolid2(&rect, colRGB(0, 0, 0)); // clear area primRectOutline2(&progressRect, 1, colRGB(255, 0, 0)); // draw empty active progress bar rect.x0 += 5; rect.x1 -= 5; rect.y1 = progressRect.y0 - RM_TEXTURE_INSET; // put above the progress bar if (glcActive()) { lifheader* lif = rmLabImage[universe.curPlayerPtr->race]; glcRectSolidTexturedScaled2(&rect, lif->width, lif->height, lif->data, rmPaletted ? lif->palette : NULL, TRUE); } else { if (rmPaletted) { trPalettedTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race], rmLabImage[universe.curPlayerPtr->race]->palette); } else { trRGBTextureMakeCurrent(rmLabTexture[universe.curPlayerPtr->race]); } rndPerspectiveCorrection(FALSE); primRectSolidTextured2(&rect); } break; } } //update selection list void SelectTechWindow(void) { udword index; listitemhandle listitem; for (index=0;PlayerTechList[index].itemtype!=ITEM_ENDLIST; index++) { if ( (PlayerTechList[index].itemstat != STAT_CANTPRINT) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { if ((PlayerTechList[index].itemtype == ITEM_TECHNOLOGY) && (PlayerTechList[index].itemID == techinfo)) { listitem = uicListFindItemByData(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index]); uicListWindowSetCurItem(rmTechListWindowHandle, listitem); } } } /* not implemented yet listitemhandle item; Node *walk,*count; bool found=FALSE; listitemhandle iteminfo, newpos; sdword i, relativecount; walk = listwindow->listofitems.head; while (walk != NULL) { listhandle->CurLineSelected->data)->itemID CurLineSelected == item if (item == listGetStructOfNode(walk)) { found = TRUE; break; } walk = walk->next; } bitClear(rmTechListWindowHandle->CurLineSelected->flags,UICLI_Selected); listhandle->CurLineSelected = item; bitSet(rmTechListWindowHandle->CurLineSelected->flags,UICLI_Selected); */ } /*----------------------------------------------------------------------------- Name : rmSelectAvailableLab Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmSelectAvailableLab(regionhandle region, udword event, sdword labID) { sdword labindex; ResearchTopic *topic; if (event == RPE_PressLeft) { //left press (select/add job) dbgAssert(region!=NULL); #ifdef DEBUG_STOMP regVerify(region); #endif bitSet(region->status, RSF_DrawThisFrame); rmDirtyTechInfo(); if (labbuttons[labID].lab->labstatus!=LS_NORESEARCHSHIP) { if(tutorial) { char gameMessage[128]; if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchSelectLab) return; strcpy(gameMessage, "RM_LabSelect "); gameMessage[14] = '0' + labID; tutGameMessage(gameMessage); } topic = labbuttons[labID].lab->topic; if (topic != NULL) { if (multipleresearchersselected) { for (labindex=0; labindextopic == topic) { researchingthistopic++; labbuttons[labindex].selected = TRUE; } else labbuttons[labindex].selected = FALSE; } multipleresearchersselected = (researchingthistopic > 1); } techinfo = topic->techresearch; SelectTechWindow(); } else { labbuttons[labID].selected = (sword)!labbuttons[labID].selected; for (labindex=0; labindextopic != NULL) { labbuttons[labindex].selected = FALSE; /* if (labbuttons[labindex].lab->topic->techresearch==techinfo) { if (rmTechListWindowHandle->CurLineSelected!=NULL) { techinfo = PlayerTechList[((TechPrintList*)rmTechListWindowHandle->CurLineSelected->data)->itemID].itemID; } else techinfo = -1; }*/ } } techinfo = -1; uicListWindowSetCurItem(rmTechListWindowHandle, NULL); multipleresearchersselected=FALSE; } } } } /*----------------------------------------------------------------------------- Name : rmSelectLab1 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab1(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 0); return(0); } /*----------------------------------------------------------------------------- Name : rmSelectLab2 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab2(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 1); return(0); } /*----------------------------------------------------------------------------- Name : rmSelectLab3 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab3(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 2); return(0); } /*----------------------------------------------------------------------------- Name : rmSelectLab4 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab4(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 3); return(0); } /*----------------------------------------------------------------------------- Name : rmSelectLab5 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab5(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 4); return(0); } /*----------------------------------------------------------------------------- Name : rmSelectLab6 Description : processes region callback for mouse clicks Inputs : region info Outputs : none Return : void ----------------------------------------------------------------------------*/ sdword rmSelectLab6(regionhandle region, sdword ID, udword event, udword data) { rmSelectAvailableLab(region, event, 5); return(0); } /*----------------------------------------------------------------------------- Name : rmLab1Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab1Draw(featom *atom, regionhandle region) { if (rmRenderEverythingCounter > 0) { rmRenderEverythingCounter--; feRenderEverything = TRUE; } if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab1); //set new region handler function } rmLab1Region = region; rmDrawLabButton(&labbuttons[0], region); } /*----------------------------------------------------------------------------- Name : rmLab2Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab2Draw(featom *atom, regionhandle region) { if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab2); //set new region handler function } rmLab2Region = region; rmDrawLabButton(&labbuttons[1], region); } /*----------------------------------------------------------------------------- Name : rmLab3Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab3Draw(featom *atom, regionhandle region) { if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab3); //set new region handler function } rmLab3Region = region; rmDrawLabButton(&labbuttons[2], region); } /*----------------------------------------------------------------------------- Name : rmLab4Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab4Draw(featom *atom, regionhandle region) { if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab4); //set new region handler function } rmLab4Region = region; rmDrawLabButton(&labbuttons[3], region); } /*----------------------------------------------------------------------------- Name : rmLab5Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab5Draw(featom *atom, regionhandle region) { if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab5); //set new region handler function } rmLab5Region = region; rmDrawLabButton(&labbuttons[4], region); } /*----------------------------------------------------------------------------- Name : rmLab6Draw Description : draws the lab buttons along with the status of the lab. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLab6Draw(featom *atom, regionhandle region) { if (region->flags == 0 || region->flags == RPE_DrawFunctionAdded) { //if region not processed yet region->flags = RPE_PressLeft; //receive mouse presses from now on region->flags |= RPE_DrawEveryFrame; regFunctionSet(region, (regionfunction)rmSelectLab6); //set new region handler function } rmLab6Region = region; rmDrawLabButton(&labbuttons[5], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector1Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector1Draw(featom *atom, regionhandle region) { rmLabConnector1Region = region; rmMarqueePulse(&labbuttons[0], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector2Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector2Draw(featom *atom, regionhandle region) { rmLabConnector2Region = region; rmMarqueePulse(&labbuttons[1], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector3Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector3Draw(featom *atom, regionhandle region) { rmLabConnector3Region = region; rmMarqueePulse(&labbuttons[2], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector4Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector4Draw(featom *atom, regionhandle region) { rmLabConnector4Region = region; rmMarqueePulse(&labbuttons[3], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector5Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector5Draw(featom *atom, regionhandle region) { rmLabConnector5Region = region; rmMarqueePulse(&labbuttons[4], region); } /*----------------------------------------------------------------------------- Name : rmLabConnector6Draw Description : draws the lab connector between the status box and diagram. Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmLabConnector6Draw(featom *atom, regionhandle region) { rmLabConnector6Region = region; rmMarqueePulse(&labbuttons[5], region); } char *getWord(char *dest, char *source) { sdword index=strlen(dest); while ( (source[0] == ' ') || (source[0] == '-') ) { dest[index] = source[0]; dest[index+1] = 0; index++; source++; } while ( (source[0] != ' ') && (source[0] != '-') && (source[0] != 0) && (source[0] != '\n') ) { dest[index] = source[0]; dest[index+1] = 0; index++; source++; } return(source); } char *getShipBuild(char *dest) { PlayerResearchInfo *researchinfo = &universe.curPlayerPtr->researchinfo; TechStatics *techstat = researchinfo->techstat; sdword hastech = researchinfo->HasTechnology; sdword index; bool first=TRUE; for (index=0;indexTechNeededToBuildShip[index]&(hastech|TechToBit(techinfo))) == techstat->TechNeededToBuildShip[index]) { if ( (techstat->TechNeededToBuildShip[index]&hastech) != techstat->TechNeededToBuildShip[index]) { if ( ( (universe.curPlayerPtr->race == R1) && (index != DefenseFighter ) && (index != DFGFrigate ) ) | ( (universe.curPlayerPtr->race == R2) && (index != CloakedFighter ) && (index != DDDFrigate ) ) ) { if (!first) { strcat(dest,", "); } if (first) { strcat(dest,"\n\n"); strcat(dest,strGetString(strCanBuild)); strcat(dest,"\n"); } strcat(dest," "); strcat(dest,ShipTypeToNiceStr(index)); first = FALSE; } } } } return (dest); } /*----------------------------------------------------------------------------- Name : rmTechTexturePrepare Description : prepares texture for use in the research manager. Inputs : index into pictures structure. Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmTechTexturePrepare(sdword index) { if (pictures[index].techTexture == TR_InvalidInternalHandle) { pictures[index].techTexture = trPalettedTextureCreate(pictures[index].techImage->data, pictures[index].techImage->palette, pictures[index].techImage->width, pictures[index].techImage->height); rmCurTexture = pictures[index].techTexture; rmCurIndex = index; } else { trPalettedTextureMakeCurrent(pictures[index].techTexture, pictures[index].techImage->palette); rmCurTexture = pictures[index].techTexture; rmCurIndex = index; } } /*----------------------------------------------------------------------------- Name : rmExtendedInfo Description : Inputs : none Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmExtendedInfo(char *string, featom *atom) { rmExtendedInfoActive = !rmExtendedInfoActive; rmDirtyTechInfo(); } /*----------------------------------------------------------------------------- Name : rmTechInfoDraw Description : Draws technology text to the window. Inputs : region Outputs : technology info. Return : void ----------------------------------------------------------------------------*/ void rmTechInfoDraw(regionhandle region) { fonthandle currentFont; sdword x,y, width; char *pos, *oldpos; char oldline[100], line[100]; char stringtoprint[650]; bool justified, done; //rmTechInfoRegion = region; //feStaticRectangleDraw(region); //draw standard rectangle //currentFont = fontMakeCurrent(rmTechListFont); currentFont = fontMakeCurrent(rmTechInfoFont); x = region->rect.x0 + 15; y = region->rect.y0 + 5; if (techinfo != -1) { fontPrintf(x,y,FEC_ListItemStandard/*rmResearchingTextColor*/,"%s", RaceSpecificTechTypeToNiceString(techinfo, universe.curPlayerPtr->race)); y += RM_VertSpacing + fontHeight(" "); //fontMakeCurrent(rmTechInfoFont); // Bad bad design, my fault [Drew] doh! if (techinfo==DDDFDFGFTech) if (universe.curPlayerPtr->race==R1) strcpy(stringtoprint,strGetString(strR1DDDFTechinfo)); else strcpy(stringtoprint,strGetString(strR2DFGFTechinfo)); else if (techinfo==CloakDefenseFighter) if (universe.curPlayerPtr->race==R1) strcpy(stringtoprint,strGetString(strR1CloakFighterinfo)); else strcpy(stringtoprint,strGetString(strR2DefenseFighterTechinfo)); else if (universe.curPlayerPtr->race==R1) strcpy(stringtoprint,strGetString(techinfo+strTechInfoOffsetR1)); else strcpy(stringtoprint,strGetString(techinfo+strTechInfoOffsetR2)); getShipBuild(stringtoprint); pos = stringtoprint; done = FALSE; while (!done) { justified = FALSE; line[0]=0; while (!justified) { strcpy(oldline, line); oldpos = pos; pos = getWord(line, pos); if (pos[0] == '\n') { if ((width = fontWidth(line)) > RM_InfoWidth - 15) { strcpy(line, oldline); pos = oldpos; while (pos[0] == ' ') pos++; justified = TRUE; } else { justified = TRUE; pos++; while ( pos[0] == ' ' ) pos++; } } else { if ( (width=fontWidth(line)) > RM_InfoWidth - 15) { strcpy(line, oldline); pos = oldpos; while ( pos[0] == ' ' ) pos++; justified = TRUE; } if (pos[0]==0) { justified = TRUE; done = TRUE; } } } fontPrintf(x,y,rmStandardTextColor,"%s",line); y += fontHeight(" "); if (y > region->rect.y1 + fontHeight(" ")) done=TRUE; } } fontMakeCurrent(currentFont); } /*----------------------------------------------------------------------------- Name : rmTechBriefDraw Description : Inputs : region Outputs : Return : void ----------------------------------------------------------------------------*/ void rmTechBriefDraw(featom *atom, regionhandle region) { fonthandle currentFont; sdword x,y; rectangle rect; //char *pos, *oldpos; //char oldline[100], line[100]; //char stringtoprint[650]; //bool justified, done; rmTechBriefRegion = region; rect = region->rect; feStaticRectangleDraw(region); //draw standard rectangle rect.x0 += 2; rect.y0 += 2; rect.x1 -= 2; rect.y1 -= 2; primRectSolid2(&rect, atom->contentColor); currentFont = fontMakeCurrent(rmTechListFont); //currentFont = fontMakeCurrent(rmTechInfoFont); x = region->rect.x0 + 15; y = region->rect.y0 + 5; if (techinfo != -1) { fontPrintf(x,y,FEC_ListItemStandard/*rmResearchingTextColor*/,"%s",TechTypeToNiceString(techinfo)); /* y += RM_VertSpacing + fontHeight(" "); //fontMakeCurrent(rmTechInfoFont); if (universe.curPlayerPtr->race==R1) { dbgAssert(strGetString(techinfo+strTechInfoOffsetR1)!=NULL); strcpy(stringtoprint,strGetString(techinfo+strTechInfoOffsetR1)); } else { dbgAssert(strGetString(techinfo+strTechInfoOffsetR2)!=NULL); strcpy(stringtoprint,strGetString(techinfo+strTechInfoOffsetR2)); } getShipBuild(stringtoprint); pos = stringtoprint; done = FALSE; while (!done) { justified = FALSE; line[0]=0; while (!justified) { strcpy(oldline, line); oldpos = pos; pos = getWord(line, pos); if (pos[0] == '\n') { justified = TRUE; pos++; while ( pos[0] == ' ' ) pos++; } else { if ( (width=fontWidth(line)) > RM_InfoWidth - 15) { strcpy(line, oldline); pos = oldpos; while ( pos[0] == ' ' ) pos++; justified = TRUE; } if (pos[0]==0) { justified = TRUE; done = TRUE; } } } fontPrintf(x,y,rmStandardTextColor,"%s",line); y += fontHeight(" "); if (y > region->rect.y1 + fontHeight(" ")) done=TRUE; } */ } fontMakeCurrent(currentFont); } /*----------------------------------------------------------------------------- Name : rmTechImageDraw Description : Loads in, decompresses and draws the tech picture. Inputs : none Outputs : loads in rmTechImage and creates rmTechTexture Return : void ----------------------------------------------------------------------------*/ void rmTechImageDraw(featom *atom, regionhandle region) { char filename[128]; sdword index, lru; real32 time=(real32)1.0e22; bool loaded=FALSE; rectangle textureRect; rmTechImageRegion = region; feStaticRectangleDraw(region); //draw standard rectangle if (techinfo != -1) { if (techinfo != rmCurTechTexture) { for (index=0;indexrace) ) { rmTechTexturePrepare(index); rmCurTechTexture = techinfo; rmCurTechImage = pictures[lru].techImage; rmCurIndex = index; pictures[index].timestamp = universe.totaltimeelapsed; textureRect.x0 = region->rect.x0+RM_TEXTURE_INSET; textureRect.y0 = region->rect.y0+RM_TEXTURE_INSET; textureRect.x1 = region->rect.x1-RM_TEXTURE_INSET; textureRect.y1 = region->rect.y1-RM_TEXTURE_INSET; rndPerspectiveCorrection(FALSE); if (glcActive()) { glcRectSolidTextured2(&textureRect, pictures[rmCurIndex].techImage->width, pictures[rmCurIndex].techImage->height, pictures[rmCurIndex].techImage->data, pictures[rmCurIndex].techImage->palette, TRUE); } else { primRectSolidTextured2(&textureRect); } if (rmExtendedInfoActive) { primRectTranslucent2(&textureRect, colRGBA(0, 0, 0, 128)); rmTechInfoDraw(region); } return; } } // Build filename for loading texture from file strcpy(filename, TechImagePaths[universe.curPlayerPtr->race]); strcat(filename, TechTypeToString(techinfo)); strcat(filename,".lif"); // Remove oldest (least recently used) texture from memory if (pictures[lru].techImage != NULL) { memFree(pictures[lru].techImage); pictures[lru].techImage = NULL; } if (pictures[lru].techTexture != TR_InvalidInternalHandle) { trRGBTextureDelete(pictures[lru].techTexture); pictures[lru].techTexture = TR_InvalidInternalHandle; } // Load the image into LRU cache pictures[lru].techImage = trLIFFileLoad(filename, NonVolatile); dbgAssert(pictures[lru].techImage->flags & TRF_Paletted); rmTechTexturePrepare(lru); rmCurTechTexture = techinfo; rmCurTechImage = pictures[lru].techImage; pictures[lru].tech = techinfo; pictures[lru].race = universe.curPlayerPtr->race; pictures[lru].timestamp = universe.totaltimeelapsed; } else { trPalettedTextureMakeCurrent(pictures[rmCurIndex].techTexture, pictures[rmCurIndex].techImage->palette); } textureRect.x0 = region->rect.x0 + RM_TEXTURE_INSET; textureRect.y0 = region->rect.y0 + RM_TEXTURE_INSET; textureRect.x1 = region->rect.x1 - RM_TEXTURE_INSET; textureRect.y1 = region->rect.y1 - RM_TEXTURE_INSET; rndPerspectiveCorrection(FALSE); if (glcActive()) { glcRectSolidTextured2(&textureRect, pictures[rmCurIndex].techImage->width, pictures[rmCurIndex].techImage->height, pictures[rmCurIndex].techImage->data, pictures[rmCurIndex].techImage->palette, TRUE); } else { primRectSolidTextured2(&textureRect); } if (rmExtendedInfoActive) { primRectTranslucent2(&textureRect, colRGBA(0, 0, 0, 128)); rmTechInfoDraw(region); } } } /*----------------------------------------------------------------------------- Name : rmConnectorDraw Description : Draws the connector between the picture of the technology and the info. text Inputs : region Outputs : connector image Return : void ----------------------------------------------------------------------------*/ void rmConnectorDraw(featom *atom, regionhandle region) { rmConnectorRegion = region; if (techinfo != -1) { sdword centerX = region->rect.x0 + ((region->rect.x1 - region->rect.x0) / 2); primLine2(centerX, region->rect.y0, centerX, region->rect.y1, colRGB(255, 0, 0)); primCircleSolid2(centerX, region->rect.y1, 3, 16, colRGB(255, 0, 0)); } } /*----------------------------------------------------------------------------- Name : rmDrawTechListItem Description : This function draws each item in the technology list. Inputs : rectangle, and a pointer to the item handle. Outputs : Return : void ----------------------------------------------------------------------------*/ void rmDrawTechListItem(rectangle *rect, listitemhandle data) { TechPrintList *techprint=(TechPrintList *)data->data; sdword x, y; color c; Player *player=universe.curPlayerPtr; PlayerResearchInfo *research=&universe.curPlayerPtr->researchinfo; ResearchTopic *topic; TechnologyType tech; char temp[64]; real32 percent; rectangle bar; fonthandle oldfont; color progressColor[4]; x = rect->x0; y = rect->y0; oldfont = fontMakeCurrent(rmTechListFont); if (techprint->itemtype==ITEM_TECHNOLOGY) { tech = techprint->itemID; sprintf(temp, "%s", RaceSpecificTechTypeToNiceString(tech, player->race)); switch (techprint->itemstat) { case STAT_CANRESEARCH : x += RM_HorzSpacing<<2; c = FEC_ListItemStandard;//rmStandardTextColor; break; case STAT_CANTRESEARCH : x += RM_HorzSpacing<<2; c = rmCantResearchTextColor; break; case STAT_RESEARCHING : x += RM_HorzSpacing<<2; if ((topic=Researching(player,tech))!=NULL) { percent = (real32)((real32)topic->timeleft/(real32)research->techstat->TimeToComplete[tech]); bar.x0 = x-2; bar.y0 = y/*-2*/; bar.x1 = rect->x1-2; bar.y1 = y+fontHeight(" ") + 2; primRectSolid2(&bar, rmProgressToGoColor); bar.x1 -= (udword)((real32)( (rect->x1-2) - (x-2))*percent); progressColor[0] = rmProgressDoneColor0; progressColor[1] = rmProgressDoneColor0; progressColor[2] = rmProgressDoneColor1; progressColor[3] = rmProgressDoneColor1; primRectShaded2(&bar, progressColor); #ifdef DEBUG_STOMP regVerify((regionhandle)&rmTechListWindowHandle->reg); #endif rmTechListWindowHandle->reg.status |= RSF_DrawThisFrame; } c = rmResearchingTextColor; break; case STAT_ALREADYHAVE : x += RM_HorzSpacing<<2; c = FEC_ListItemInactive;//rmStandardTextColor; primCircleSolid2(x-7,y+5,3,20,rmResearchingTextColor); break; } if (bitTest(data->flags,UICLI_Selected)) { if (techprint->itemstat == STAT_RESEARCHING) { c = rmResearchingTextColor;//rmSelectionTextColor; } else { c = FEC_ListItemSelected;//rmSelectionTextColor; } } } else if ( (techprint->itemtype==ITEM_CLASSHEADER) && (techprint->itemstat==STAT_CANPRINT) ) { sprintf(temp,"%s",strGetString(techprint->itemID+strTechHeadingOffset)); c = rmClassHeadingTextColor; } fontPrintf(x,y,c,"%s",temp); fontMakeCurrent(oldfont); marqueepos += (real32)((taskTimeElapsed - marqueetime) * RM_MARQUEERATE); if (marqueepos > (real32)(RM_NUMMARQUEE / 3) + 1.0) { marqueepos -= (real32)(RM_NUMMARQUEE / 3) + 1.0; } marqueetime = taskTimeElapsed; } /*----------------------------------------------------------------------------- Name : rmTechListWindow Description : This function handle messages from the technology listwindow. Inputs : none Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmTechListWindow(char *string, featom *atom) { fonthandle oldfont; sdword index; if (FEFIRSTCALL(atom)) { oldfont = fontMakeCurrent(rmTechListFont); rmTechListWindowHandle = (listwindowhandle)atom->pData; uicListWindowInit(rmTechListWindowHandle, NULL, // title draw, no title NULL, // title click process, no title 0, // title height, no title rmDrawTechListItem, // item draw funtcion fontHeight(" ")+RM_VertSpacing, // item height UICLW_CanSelect); for (index=0;PlayerTechList[index].itemtype!=ITEM_ENDLIST; index++) { if ( (PlayerTechList[index].itemstat != STAT_CANTPRINT) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { if (PlayerTechList[index].itemtype == ITEM_CLASSHEADER) uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], 0, UICLW_AddToTail); else uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], UICLI_CanSelect, UICLW_AddToTail); } } return; } else if (FELASTCALL(atom)) { rmTechListWindowHandle = NULL; return; } switch (rmTechListWindowHandle->message) { case CM_NewItemSelected: { if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchSelectTech) return; techinfo = ((TechPrintList*)rmTechListWindowHandle->CurLineSelected->data)->itemID; rmDirtyTechInfo(); if ( ((TechPrintList*)rmTechListWindowHandle->CurLineSelected->data)->itemstat==STAT_RESEARCHING) { for (index=0; indextopic)&&(labbuttons[index].lab->topic->techresearch==techinfo)) { labbuttons[index].selected = TRUE; multipleresearchersselected++; } else labbuttons[index].selected = FALSE; multipleresearchersselected= (multipleresearchersselected>1); } } else { for (index=0; indexlabstatus == LS_RESEARCHITEM) { labbuttons[index].selected = FALSE; } } } if(tutorial) { char gameMessage[128]; strcpy(gameMessage, "RM_TechSelect_"); strcat(gameMessage, TechTypeToString(techinfo)); tutGameMessage(gameMessage); } } break; case CM_DoubleClick: if (tutorial) { tutGameMessage("RM_DoubleClick"); } rmResearchItem(NULL, NULL); break; } } /*----------------------------------------------------------------------------- Name : rmUpdateTechList Description : updates the status of the technology list. Inputs : none Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmUpdateTechList(void) { PlayerResearchInfo *research=&universe.curPlayerPtr->researchinfo; TechnologyType tech; sdword index, mask, hastech, canprint=STAT_CANTPRINT; sdword lastHeading = 0, count=0; // ubyte *data=NULL; for (index=0;PlayerTechList[index].itemtype!=ITEM_ENDLIST; index++) { if (PlayerTechList[index].itemtype==ITEM_TECHNOLOGY) { tech = PlayerTechList[index].itemID; hastech = research->HasTechnology; mask = research->techstat->TechNeededToResearch[tech]; if (TechToBit(tech)&hastech) { PlayerTechList[index].itemstat = STAT_ALREADYHAVE; } else if (Researching(universe.curPlayerPtr,tech)!=NULL) { PlayerTechList[index].itemstat = STAT_RESEARCHING; } else if (singlePlayerGame) { if ( tmTechResearchable[tech] ) { PlayerTechList[index].itemstat = STAT_CANRESEARCH; } else { PlayerTechList[index].itemstat = STAT_CANTRESEARCH; } } else { if ((hastech & mask)==mask) { PlayerTechList[index].itemstat = STAT_CANRESEARCH; } else { PlayerTechList[index].itemstat = STAT_CANTRESEARCH; } } } } for (; index >= 0; index--) { if( (PlayerTechList[index].itemtype == ITEM_TECHNOLOGY) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { canprint=STAT_CANPRINT; } else if (PlayerTechList[index].itemtype==ITEM_CLASSHEADER) { PlayerTechList[index].itemstat = (sword)canprint; canprint=STAT_CANTPRINT; } if ( (PlayerTechList[index].itemstat != STAT_CANTPRINT) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { count++; } } count--; // Regenerate list because something has just finished being researched if ( (rmTechListWindowHandle!=NULL) && (count != rmTechListWindowHandle->ListTotal)) { uicListCleanUp(rmTechListWindowHandle); for (index=0;PlayerTechList[index].itemtype!=ITEM_ENDLIST; index++) { if ( (PlayerTechList[index].itemstat != STAT_CANTPRINT) && (PlayerTechList[index].itemstat != STAT_CANTRESEARCH) ) { if (PlayerTechList[index].itemtype == ITEM_CLASSHEADER) uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], 0, UICLW_AddToTail); else uicListAddItem(rmTechListWindowHandle, (ubyte *)&PlayerTechList[index], UICLI_CanSelect, UICLW_AddToTail); } } SelectTechWindow(); rmDirtyTechList(); } if (rmTechListWindowHandle != NULL) { #ifdef DEBUG_STOMP regVerify((regionhandle)&rmTechListWindowHandle->reg); #endif rmTechListWindowHandle->reg.status |= RSF_DrawThisFrame; } rmDirtyTechList(); } /*----------------------------------------------------------------------------- Name : rmResearchBegin Description : brings up research manager GUI Inputs : standard region event handles Outputs : success fail Return : ----------------------------------------------------------------------------*/ sdword rmResearchGUIBegin(regionhandle region, sdword ID, udword event, udword data) { sdword index; if ((playPackets) || (universePause)) return 0; for(index=0; indexresearchinfo.researchlabs[index].labstatus != LS_NORESEARCHSHIP) break; } if(index == NUM_RESEARCHLABS) { // Don't have any research labs! return (0); } if((tutorial==TUTORIAL_ONLY) && !tutEnable.bResearchManager) return (0); // disable rendering of main screen mrRenderMainScreen = FALSE; glcFullscreen(TRUE); rmRenderEverythingCounter = (tutorial == TUTORIAL_ONLY) ? 4 : 0; // clear the screen rndClear(); // disable taskbar popup window tbDisable = TRUE; //mouseEnable(); //mouseCursorShow(); spLockout(SPLOCKOUT_MR); if (!rmScreensHandle) { feCallbackAddMultiple(rmCallback); //add in the callbacks feDrawCallbackAddMultiple(rmDrawCallback); rmScreensHandle = feScreensLoad(RM_FIBFile); //load in the screen } if (!singlePlayerGame) { if (bitTest(tpGameCreated.flag,MG_CarrierIsMothership)) { if (universe.curPlayerPtr->race==R1) PlayerTechList = &MultiPlayerCR1TechList[0]; else PlayerTechList = &MultiPlayerCR2TechList[0]; } else { if (universe.curPlayerPtr->race==R1) PlayerTechList = &MultiPlayerR1TechList[0]; else PlayerTechList = &MultiPlayerR2TechList[0]; } } else { if (universe.curPlayerPtr->race==R1) PlayerTechList = &SinglePlayerR1TechList[0]; else PlayerTechList = &SinglePlayerR2TechList[0]; } for (index=0;indexresearchinfo.researchlabs[index]; labbuttons[index].selected = FALSE; labbuttons[index].labid = (uword) (index+1); labbuttons[index].pulsepos = 0; } soundEventStopSFX(0.5f); /* play the intro sound */ soundEvent(NULL, UI_ManagerIntro); /* start the research ambient sound */ soundEvent(NULL, UI_ResearchManager); rmUpdateTechList(); rmIoSaveState = ioDisable(); rmBaseRegion = feScreenStart(region, RM_ResearchScreen); //add new regions as siblings of current one rmGUIActive = TRUE; tutGameMessage("Start_ResearchManager"); mouseCursorShow(); // rmExtendedInfoActive = FALSE; mouseCursorShow(); return (0); } /*----------------------------------------------------------------------------- Name : ShipsNeedTech Description : rerturns true if a ship needs the technology specified. Inputs : techstatics Outputs : TRUE/FALSE Return : bool ----------------------------------------------------------------------------*/ bool ShipsNeedTech(TechStatics *techstat, TechnologyType tech) { sdword index; for (index=0;indexTechNeededToBuildShip[index]&TechToBit(tech)) { return(TRUE); } } return(FALSE); } /*----------------------------------------------------------------------------- Name : rmSetPrintList Description : Sets the print lists for single and multiplayer after the dependancies are loaded; Inputs : none Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmSetPrintList(udword whichlist, TechStatics *techstat) { sdword index, copycount; switch (whichlist) { case RM_SPR1 : for (copycount=0,index=0;indexflags, TRF_Paletted)) { rmPaletted = TRUE; } else { rmPaletted = FALSE; } if (rmPaletted) { rmLabTexture[index] = trPalettedTextureCreate( rmLabImage[index]->data, rmLabImage[index]->palette, rmLabImage[index]->width, rmLabImage[index]->height); } else { rmLabTexture[index] = trRGBTextureCreate( (color*)rmLabImage[index]->data, rmLabImage[index]->width, rmLabImage[index]->height, TRUE); } //trPalettedTextureMakeCurrent(rmLabTexture[index], rmLabImage[index]->palette); } } rmCurTexture = TR_InvalidInternalHandle; rmCurTechImage = NULL; rmCurTechTexture = -1; rmTechListFont = frFontRegister(rmTechListFontName); rmTechInfoFont = frFontRegister(rmTechInfoFontName); } /*----------------------------------------------------------------------------- Name : rmGUIShutdown Description : shuts down the research managers GUI Inputs : none Outputs : none Return : void ----------------------------------------------------------------------------*/ void rmGUIShutdown(void) { sdword index; if (rmScreensHandle) { feScreensDelete(rmScreensHandle); rmScreensHandle = NULL; } for (index=0;index