/*============================================================================= Name : HorseRace.c Purpose : Logic for the horse race and loading chat screens. Created 6/16/1998 by ddunlop Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include #include #include "types.h" #include "globals.h" #include "glinc.h" #include "types.h" #include "Debug.h" #include "prim2d.h" #include "universe.h" #include "render.h" #include "CommandNetwork.h" #include "horserace.h" #include "region.h" #include "uicontrols.h" #include "feflow.h" #include "font.h" #include "fontreg.h" #include "prim2d.h" #include "utility.h" #include "task.h" #include "demo.h" #include "mouse.h" #include "linkedlist.h" #include "chatting.h" #include "glcaps.h" #include "nis.h" #include "multiplayergame.h" #include "etg.h" #include "file.h" #include "feReg.h" #include "interfce.h" #include "teams.h" #include "TimeoutTimer.h" #include "strings.h" #include "singleplayer.h" #include "autodownloadmap.h" #include "glcompat.h" #include "texreg.h" #include "titan.h" #include "devstats.h" #define ShouldHaveMousePtr (FALSE) extern LONGLONG utyTimerLast; extern udword gDevcaps2; /*============================================================================= defines: =============================================================================*/ #define HR_PlayerNameFont "Arial_12.hff" #define MAX_CHAT_TEXT 64 #define NUM_CHAT_LINES 10 real32 HorseRacePlayerDropoutTime = 10.0f; // tweakable color HorseRaceDropoutColor = colRGB(75,75,75); /*============================================================================= data: =============================================================================*/ extern HDC hGLDeviceContext; static rectangle hrSinglePlayerPos; static color hrSinglePlayerColor; static sdword JustInit; static sdword localbar; // Pixels and info about the background image chosen static BOOL hrBackgroundInitFrame = 0; static DWORD *hrBackgroundImage = NULL; static long hrBackgroundDirty = 0; bool hrBackgroundReinit = FALSE; static long hrBackXSize, hrBackYSize; static regionhandle hrDecRegion; HorseStatus horseracestatus; TTimer hrPlayerDropoutTimers[MAX_MULTIPLAYER_PLAYERS]; fibfileheader *hrScreensHandle = NULL; fonthandle playernamefont=0; color hrBackBarColor=HR_BackBarColor; color hrChatTextColor=HR_ChatTextColor; bool PlayersAlreadyDrawnDropped[MAX_MULTIPLAYER_PLAYERS]; textentryhandle ChatTextEntryBox = NULL; regionhandle hrBaseRegion = NULL; regionhandle hrProgressRegion = NULL; regionhandle hrChatBoxRegion = NULL; regionhandle hrAbortLoadConfirm = NULL; region horseCrapRegion = { {-1,-1,-1,-1}, //rectangle NULL, //draw function NULL, //process function NULL, NULL, //parent, child NULL, NULL, //previous, next 0, 0, //flags, status, 0, //nKeys {0}, //keys 0, #if REG_ERROR_CHECKING //userID REG_ValidationKey, //validation key #endif }; bool hrRunning=FALSE; ChatPacket chathistory[NUM_CHAT_LINES]; udword chatline=0; void horseRaceRender(void); void hrDrawPlayersProgress(featom *atom, regionhandle region); void hrDrawChatBox(featom *atom, regionhandle region); void hrChatTextEntry(char *name, featom *atom); //void hrAbortNetworkGame(char *name, featom *atom); //void hrAbortNonNetworkGame(char *name, featom *atom); void hrAbortLoadingYes(char *name, featom *atom); void hrAbortLoadingNo(char *name, featom *atom); real32 horseRaceGetPacketPercent(real32 barPercent); //HR_ChatTextEntry //extern nisheader *utyTeaserHeader; /*============================================================================= Functions =============================================================================*/ fedrawcallback hrDrawCallback[] = { {hrDrawPlayersProgress, "HR_DrawPlayersProgress" }, {hrDrawChatBox, "HR_DrawChatBox" }, {NULL, NULL} }; fecallback hrCallBack[] = { {hrChatTextEntry, "HR_ChatTextEntry" }, //{hrAbortNetworkGame, "HR_AbortNetworkGame" }, //{hrAbortNonNetworkGame, "HR_AbortNonNetworkGame" }, {hrAbortLoadingYes, "HR_AbortLoadingYes" }, {hrAbortLoadingNo, "HR_AbortLoadingNo" }, {NULL, NULL} }; void hrDirtyProgressBar() { if (hrRunning) { if (hrProgressRegion != NULL) { #ifdef DEBUG_STOMP regVerify(hrProgressRegion); #endif hrProgressRegion->status |= RSF_DrawThisFrame; } } } void hrDirtyChatBox() { if (hrRunning) { if (hrChatBoxRegion != NULL) { #ifdef DEBUG_STOMP regVerify(hrChatBoxRegion); #endif hrChatBoxRegion->status |= RSF_DrawThisFrame; } } } void hrBarDraw(rectangle *rect, color back, color fore, real32 percent) { rectangle temp; // primRectSolid2(rect, back); if (percent > 1.0) { percent = 1.0; } temp.x0 = rect->x0; temp.y0 = rect->y0; temp.x1 = rect->x0 + (sdword)((rect->x1-rect->x0)*percent); temp.y1 = rect->y1; primRectSolid2(&temp, fore); } void hrDrawPlayersProgress(featom *atom, regionhandle region) { sdword index; rectangle pos; rectangle outline; real32 percent; fonthandle currentfont; bool droppedOut; hrProgressRegion = region; pos = region->rect; // primRectSolid2(&pos, colRGBA(0, 0, 0, 64)); pos.y0+=fontHeight(" "); pos.y1=pos.y0+8; currentfont = fontMakeCurrent(playernamefont); if (multiPlayerGame) { dbgAssert(sigsNumPlayers == tpGameCreated.numPlayers); for (index=0;indexrect,colRGB(0,0,0)); feStaticRectangleDraw(region); x = region->rect.x0+10; y = region->rect.y0; for (i=0;irect.x0; sprintf(name,"%s >",tpGameCreated.playerInfo[chathistory[i].packetheader.frame].PersonalName); fontPrintf(x,y,tpGameCreated.playerInfo[chathistory[i].packetheader.frame].baseColor,"%s",name); x+=fontWidth(name)+10; //fontShadowSet(FS_E | FS_SE | FS_S); fontPrintf(x,y,hrChatTextColor,"%s",chathistory[i].message); //fontShadowSet(FS_NONE); y+= fontHeight(" "); } } fontMakeCurrent(currentfont); } void hrChooseSinglePlayerBitmap(char* pFilenameBuffer) { char fname[128], line[64]; filehandle handle; sdword x, y, width, height; sdword red, green, blue; memset(&hrSinglePlayerPos, 0, sizeof(hrSinglePlayerPos)); //image itself #if defined(OEM) if (singlePlayerGameInfo.currentMission == 5) { sprintf(fname, "SinglePlayer\\mission05_OEM\\loading.jpg"); } else #endif sprintf(fname, "SinglePlayer\\mission%02d\\loading.jpg", singlePlayerGameInfo.currentMission); if (!fileExists(fname, 0)) { pFilenameBuffer[0] = '\0'; return; } strcpy(pFilenameBuffer, fname); //image script x = 42; y = 132 + ((RGLtype == SWtype) ? 1 : 0); width = 152; height = 3; x = feResRepositionX(x); y = feResRepositionY(y); hrSinglePlayerPos.x0 = x; hrSinglePlayerPos.y0 = y; hrSinglePlayerPos.x1 = x + width; hrSinglePlayerPos.y1 = y + height; sprintf(fname, "SinglePlayer\\mission%02d\\loading.script", singlePlayerGameInfo.currentMission); if (!fileExists(fname, 0)) { hrSinglePlayerColor = colRGB(255,63,63); return; } handle = fileOpen(fname, FF_TextMode); fileLineRead(handle, line, 63); sscanf(line, "%d %d %d", &red, &green, &blue); fileClose(handle); hrSinglePlayerColor = colRGB(red, green, blue); } void hrChooseRandomBitmap(char *pFilenameBuffer) { filehandle handle; long hFind, FileCount, BigFileCount, WhichFile, Result; struct _finddata_t FindData; char BigName[512], CurDir[512], NewDir[512]; FileCount = BigFileCount = 0; GetCurrentDirectory(511, CurDir); // First, find screen shots listed in the BigFile handle = fileOpen("ScreenShots\\ShotList.script", FF_ReturnNULLOnFail | FF_TextMode); if(handle) { do { Result = fileLineRead(handle, BigName, 512); if(Result != FR_EndOfFile && Result > 0) // Found one! BigFileCount++; } while(Result != FR_EndOfFile); fileClose(handle); } // Tell the file count how many pics were in the BigFile FileCount = BigFileCount; NewDir[0] = 0; strcpy(NewDir, filePathPrepend("ScreenShots", 0)); // Switch to the screenshots directory and count the ones in there SetCurrentDirectory(NewDir); hFind = _findfirst("*.jpg", &FindData); if(hFind != -1) { do { if( ((FindData.attrib & _A_SUBDIR) == 0) && ((FindData.attrib & _A_HIDDEN) == 0) ) FileCount++; } while (_findnext(hFind, &FindData) == 0); _findclose(hFind); } // Did we find any at all? if(FileCount == 0) { pFilenameBuffer[0] = 0; SetCurrentDirectory(CurDir); return; } WhichFile = (utyTimerLast % 32777) % FileCount; if(WhichFile < BigFileCount) { // The file we want is in the bigfile script handle = fileOpen("ScreenShots\\ShotList.script", FF_ReturnNULLOnFail | FF_TextMode); if(handle) { do { Result = fileLineRead(handle, BigName, 512); if(Result != FR_EndOfFile && Result > 0) // Found one! WhichFile--; } while( (WhichFile >= 0) && (Result != FR_EndOfFile)); strcpy(pFilenameBuffer, "ScreenShots\\"); strcat(pFilenameBuffer, BigName); SetCurrentDirectory(CurDir); return; } } else { // The file we want is in the screenshots directory, so // remove BigFileCount from the file index we're looking for WhichFile -= BigFileCount; FileCount = 0; hFind = _findfirst("*.jpg", &FindData); if(hFind != -1) { do { if( ((FindData.attrib & _A_SUBDIR) == 0) && ((FindData.attrib & _A_HIDDEN) == 0) ) { if(FileCount == WhichFile) { _findclose(hFind); SetCurrentDirectory(CurDir); strcpy(pFilenameBuffer, "ScreenShots\\"); strcat(pFilenameBuffer, FindData.name); return; } else FileCount++; } } while (_findnext(hFind, &FindData) == 0); } } SetCurrentDirectory(CurDir); } typedef struct { unsigned char v[2][2]; } ColorQuad; // // Takes X & Y values normalized from 0 to 1 // returns a bilinear interpolated pixel value // unsigned char hrBilinear(ColorQuad *pQuad, double X, double Y) { float Top, Bot, Final; long FinalLong; Top = (float)pQuad->v[0][0] + ((float)pQuad->v[1][0] - (float)pQuad->v[0][0]) * X; Bot = (float)pQuad->v[0][1] + ((float)pQuad->v[1][1] - (float)pQuad->v[0][1]) * X; Final = (Top + (Bot - Top) * Y) + 0.5f; FinalLong = (long)Final; // Clamp it to 0 - 255 if(FinalLong > 255) FinalLong = (FinalLong >> 31) & 0xff; return (unsigned char)FinalLong; } unsigned long hrGetInterpPixel(unsigned char *pSrcImg, long XSize, float Xf, float Yf) { unsigned long Result, x, y, xx, yy; unsigned char *pCol; double xfrac, yfrac, xint, yint; ColorQuad r, g, b; x = (unsigned long)Xf; y = (unsigned long)Yf; xfrac = modf(Xf, &xint); yfrac = modf(Yf, &yint); for(yy=0; yy<2; yy++) { for(xx=0; xx<2; xx++) { pCol = &pSrcImg[ (((y+yy) * XSize) + x+xx) * 3 ]; r.v[xx][yy] = pCol[0]; g.v[xx][yy] = pCol[1]; b.v[xx][yy] = pCol[2]; } } Result = (unsigned long)hrBilinear(&r, xfrac, yfrac); Result |= (unsigned long)hrBilinear(&g, xfrac, yfrac) << 8; Result |= (unsigned long)hrBilinear(&b, xfrac, yfrac) << 16; Result |= 0xff000000; return Result; } long hrShipsToLoadForRace(ShipRace shiprace) { long ShipsToLoad = 0; ShipType shiptype; ShipType firstshiptype; ShipType lastshiptype; ShipStaticInfo *shipstaticinfo; firstshiptype = FirstShipTypeOfRace[shiprace]; lastshiptype = LastShipTypeOfRace[shiprace]; for (shiptype=firstshiptype;shiptype<=lastshiptype;shiptype++) { shipstaticinfo = GetShipStaticInfo(shiptype,shiprace); if( bitTest(shipstaticinfo->staticheader.infoFlags, IF_InfoNeeded) && !bitTest(shipstaticinfo->staticheader.infoFlags, IF_InfoLoaded) ) ShipsToLoad++; } return ShipsToLoad; } long hrIsBackgroundWorthLoading(void) { long ToLoad = 0; ShipRace shiprace; AsteroidType asteroidtype; DustCloudType dustcloudtype; GasCloudType gascloudtype; NebulaType nebulatype; DerelictType derelicttype; for (shiprace=0;shiprace 5); } static bool hrDrawPixelsSupported(void) { extern bool mainNoDrawPixels; if (mainNoDrawPixels) { //commandline option return FALSE; } if (mainSafeGL && (RGLtype == GLtype)) { //running in "safe mode" return FALSE; } if ((RGLtype == GLtype) && bitTest(gDevcaps2, DEVSTAT2_NO_DRAWPIXELS)) { //bit in devcaps2 return FALSE; } else if (_stricmp(GLC_VENDOR, "ati") == 0 && strstr(GLC_RENDERER, "128") != NULL) { //ATI Rage 128 return FALSE; } else if (strstr(GLC_VENDOR, "Matrox") != NULL || strstr(GLC_VENDOR, "atrox ") != NULL) { //Matrox cards return FALSE; } else { //assume support return TRUE; } } void hrInitBackground(void) { char hrImageName[512]; filehandle handle; long XSize, YSize, i; unsigned long *pDest; unsigned char *pTempImage, *pTempLine, *pRGB; float SrcX, SrcY, Scale; float IncX, IncY; long DestX, DestY; long DestXSize, DestYSize, Size, Top, Bot; JPEGDATA jp; char CurDir[512], NewDir[512]; GetCurrentDirectory(511, CurDir); hrImageName[0] = 0; if (singlePlayerGame) { hrChooseSinglePlayerBitmap(hrImageName); } else { // if(hrIsBackgroundWorthLoading()) hrChooseRandomBitmap( hrImageName ); } GetCurrentDirectory(511, NewDir); dbgAssert(stricmp(CurDir,NewDir) == 0); // Load the bitmap image handle = fileOpen(hrImageName, FF_ReturnNULLOnFail); if(handle) { memset(&jp, 0, sizeof(jp)); jp.input_file = handle; JpegInfo(&jp); fileSeek(handle, 0, SEEK_SET); XSize = jp.width; YSize = jp.height; pTempImage = (unsigned char *)memAllocAttempt((XSize+1) * (YSize+1) * 3, "BackgroundTemp", NonVolatile); if(pTempImage == NULL) return; jp.ptr = pTempImage; JpegRead(&jp); fileClose(handle); Size = XSize*3; pTempLine = (unsigned char *)malloc(Size); for(i=0; i<(YSize/2); i++) { Top = i; Bot = (YSize-1)-i; memcpy(pTempLine, pTempImage + (Size * Top), Size); memcpy(pTempImage + (Size * Top), pTempImage + (Size * Bot), Size); memcpy(pTempImage + (Size * Bot), pTempLine, Size); } free(pTempLine); // Replicate the last line to appease the filter algorithm memcpy(&pTempImage[YSize * XSize * 3], &pTempImage[(YSize-1) * XSize * 3], XSize*3); if (singlePlayerGame) { //fixed width for singleplayer game images DestXSize = 640; DestYSize = 480; hrBackgroundImage = (unsigned long*)malloc(DestXSize * DestYSize * 4); } else { if (!hrDrawPixelsSupported()) { //no DrawPixels support, must use glcompat 640x480 quilting DestXSize = 640; DestYSize = 480; hrBackgroundImage = (unsigned long*)malloc(DestXSize * DestYSize * 4); } else { Scale = 1.1f; do { Scale -= 0.1f; DestXSize = (long)((float)MAIN_WindowWidth * Scale); DestYSize = (long)((float)MAIN_WindowHeight * Scale); hrBackgroundImage = (unsigned long *)malloc(DestXSize * DestYSize * 4); } while((hrBackgroundImage == NULL) && (Scale > 0.4f)); } } //if the memory was not succesfully allocated if (hrBackgroundImage == NULL) { memFree(pTempImage); return; } // Stretch the image to fit the current display size IncX = (float)XSize / (float)DestXSize; IncY = (float)YSize / (float)DestYSize; pDest = hrBackgroundImage; if((IncX < 1.0f) && (IncY < 1.0f) && (pDest != NULL)) { SrcY = 0.0f; for(DestY = 0; DestY < DestYSize; DestY++) { SrcX = 0.0f; for(DestX = 0; DestX < DestXSize; DestX++) { pDest[DestX] = hrGetInterpPixel(pTempImage, XSize, SrcX, SrcY); SrcX += IncX; } pDest += DestXSize; SrcY += IncY; } } else if (pDest != NULL) { SrcY = 0.0f; for(DestY = 0; DestY < DestYSize; DestY++) { SrcX = 0.0f; for(DestX = 0; DestX < DestXSize; DestX++) { pRGB = &pTempImage[ (((unsigned long)SrcY * XSize) + (unsigned long)SrcX) * 3 ]; pDest[DestX] = 0xff000000 + ((unsigned long)pRGB[0]) + ((unsigned long)pRGB[1] << 8) + ((unsigned long)pRGB[2] << 16); SrcX += IncX; } SrcY += IncY; pDest += DestXSize; } } hrBackXSize = DestXSize; hrBackYSize = DestYSize; memFree(pTempImage); } } #define COORD(S,T,X,Y) \ glTexCoord2f(S, T); \ glVertex2f(primScreenToGLX(X), primScreenToGLY(Y)); void hrRectSolidTextured2(rectangle *rect) { glColor3ub(255, 255, 255); rndTextureEnvironment(RTE_Replace); rndTextureEnable(TRUE); glBegin(GL_QUADS); COORD(0.0f, 0.0f, rect->x0, rect->y0); COORD(0.0f, 1.0f, rect->x0, rect->y1 - 1); COORD(1.0f, 1.0f, rect->x1, rect->y1 - 1); COORD(1.0f, 0.0f, rect->x1, rect->y0); glEnd(); rndTextureEnable(FALSE); rndTextureEnvironment(RTE_Modulate); } #undef COORD //don't mind if this is inefficient as it only //gets called once per image anyway void hrDrawFile(char* filename, sdword x, sdword y) { udword handle; rectangle rect; lifheader* lif = trLIFFileLoad(filename, Pyrophoric); rndTextureEnable(TRUE); rndAdditiveBlends(FALSE); glEnable(GL_BLEND); glGenTextures(1, &handle); trClearCurrent(); glBindTexture(GL_TEXTURE_2D, handle); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lif->width, lif->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, lif->data); x = feResRepositionX(x); y = feResRepositionY(y); x -= lif->width >> 1; y -= lif->height >> 1; rect.x0 = x; rect.y0 = y; rect.x1 = x + lif->width; rect.y1 = y + lif->height; hrRectSolidTextured2(&rect); glDeleteTextures(1, &handle); memFree(lif); glDisable(GL_BLEND); } void hrDrawBackground(void) { real32 x, y; rndClearToBlack(); // Draw the cached background bitmap using glDrawPixels if (hrBackgroundImage) { x = -((real32)hrBackXSize / (real32)MAIN_WindowWidth); y = -((real32)hrBackYSize / (real32)MAIN_WindowHeight); rndTextureEnable(FALSE); rndLightingEnable(FALSE); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glRasterPos2f(x, y); if (hrDrawPixelsSupported()) { glDrawPixels(hrBackXSize, hrBackYSize, GL_RGBA, GL_UNSIGNED_BYTE, hrBackgroundImage); } else { glcMatrixSetup(TRUE); if (singlePlayerGame) { glcDisplayRGBABackgroundWithoutScaling((ubyte*)hrBackgroundImage); } else { glcDisplayRGBABackgroundScaled((ubyte*)hrBackgroundImage); } glcMatrixSetup(FALSE); } if (singlePlayerGame && (hrBackgroundInitFrame & 1)) { hrDrawFile("feman\\loadscreen\\ring.lif", 115, 342); hrDrawFile("feman\\loadscreen\\arrows.lif", 195, 134); } } } void hrShutdownBackground(void) { // free the memory required by the cached background bitmap if (hrBackgroundImage != NULL) { free(hrBackgroundImage); hrBackgroundImage = NULL; } hrBackgroundInitFrame = 0; hrBackgroundReinit = FALSE; } void hrAbortLoadingYes(char *name, featom *atom) { hrAbortLoadingGame = TRUE; if (multiPlayerGame) SendDroppingOutOfLoad(sigsPlayerIndex); if (hrAbortLoadConfirm) { feScreenDelete(hrAbortLoadConfirm); hrAbortLoadConfirm = NULL; } } void hrAbortLoadingNo(char *name, featom *atom) { if (hrAbortLoadConfirm) { feScreenDelete(hrAbortLoadConfirm); hrAbortLoadConfirm = NULL; } } void hrChatTextEntry(char *name, featom *atom) { char *string; ChatPacket temp; sdword width; fonthandle fhsave; char testwidth[MAX_CHATSTRING_LENGTH+40]; if (FEFIRSTCALL(atom)) { // initialize button here ChatTextEntryBox = (textentryhandle)atom->pData; uicTextEntryInit(ChatTextEntryBox,UICTE_NoLossOfFocus|UICTE_ChatTextEntry); uicTextBufferResize(ChatTextEntryBox,MAX_CHATSTRING_LENGTH-2); return; } switch (uicTextEntryMessage(atom)) { case CM_AcceptText : string = ((textentryhandle)atom->pData)->textBuffer; sendChatMessage(ALL_PLAYER_MASK^PLAYER_MASK(sigsPlayerIndex),string,(uword)sigsPlayerIndex); dbgMessagef("text entry: %s\n",string); strcpy(temp.message,string); temp.packetheader.frame = (uword)sigsPlayerIndex; hrProcessPacket((struct ChatPacket *)&temp); uicTextEntrySet(ChatTextEntryBox,"",0); break; case CM_KeyPressed : fhsave = fontMakeCurrent(((textentryhandle)atom->pData)->currentFont); //select the appropriate font sprintf(testwidth, "%s > %s", playerNames[sigsPlayerIndex], ((textentryhandle)atom->pData)->textBuffer); width = fontWidth(testwidth); fontMakeCurrent(fhsave); if (width > (atom->width-30)) { uicBackspaceCharacter((textentryhandle)atom->pData); } break; } } #if 0 void hrAbortNetworkGame(char *name, featom *atom) { hrAbortLoadingGame = TRUE; dbgAssert(multiPlayerGame); SendDroppingOutOfLoad(sigsPlayerIndex); } void hrAbortNonNetworkGame(char *name, featom *atom) { hrAbortLoadingGame = TRUE; } #endif HorseRaceBars horseBarInfo; extern bool8 etgHasBeenStarted; void horseGetNumBars(HorseRaceBars *horsebars) { sdword i; bool enablebar[MAX_POSSIBLE_NUM_BARS]; real32 totalperc; dbgAssert(horseTotalNumBars.numBars > 0); for (i=0;inumBars = 0; // now, based on enablebar[i], selectively add bars that will be loaded: for (i=0;iperc[horsebars->numBars++] = horseTotalNumBars.perc[i]; } } dbgAssert(horsebars->numBars > 0); // now renormalize percentages to 1.0 for (totalperc = 0.0f,i=0;inumBars;i++) { totalperc += horsebars->perc[i]; } dbgAssert(totalperc > 0.0f); if (totalperc != 1.0f) { for (i=0;inumBars;i++) { horsebars->perc[i] /= totalperc; } } } void horseRaceInit() { udword i; horseGetNumBars(&horseBarInfo); if (glcActive()) { (void)glcActivate(FALSE); } //initialize current bar to the 0th bar localbar=0; for(i=0;idrawFunction = ferDrawDecorative; } } void horseRaceRender() { MSG message; _asm xor eax,eax _asm mov regRenderEventIndex, eax //special-case code for double-clicks /* if (keyIsHit(LMOUSE_DOUBLE)) { keyPressUp(LMOUSE_DOUBLE); utyDoubleClick(); } if (demDemoRecording) { memcpy((ubyte *)&keyScanCode[0], (ubyte *)&keySaveScan[0], sizeof(keyScanCode));//freeze a snapshot of the key state demStateSave(); } else if (demDemoPlaying) { demStateLoad(); }*/ if (hrBackgroundReinit) { if (hrBackgroundImage != NULL) { free(hrBackgroundImage); hrBackgroundImage = NULL; } hrBackgroundReinit = FALSE; hrBackgroundDirty = (RGLtype == SWtype) ? 10000 : 3; hrBackgroundInitFrame = 0; } // Make sure the Homeworld text gets drawn on the correct frames if (hrBackgroundDirty || RGLtype == SWtype) { regRecursiveSetDirty(&horseCrapRegion); hrDecRegion = NULL; } else { regionhandle reg; // "Clean" the region with the homeworld logo // in it so it doesn't re-draw all the time reg = horseCrapRegion.child; if (reg) { reg = reg->child; } while (reg && reg->drawFunction != &ferDrawDecorative) { reg = reg->next; } if (reg) { void regNULLRenderFunction(regionhandle region); hrDecRegion = reg; reg->drawFunction = regNULLRenderFunction; } } if (TitanActive) titanPumpEngine(); Sleep(0); if (!PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE)!=0) { regProcessingRegions = TRUE; regRegionProcess(horseCrapRegion.child, 0xffffffff); regProcessingRegions = FALSE; if (ChatTextEntryBox!=NULL) { bitSet(ChatTextEntryBox->reg.status,RSF_KeyCapture); keyBufferClear(); } } else { regRegionProcess(horseCrapRegion.child, 0xffffffff); while (PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE)!=0) { if(GetMessage(&message, NULL, 0, 0)) { TranslateMessage(&message); DispatchMessage(&message); if (multiPlayerGame) { if (keyIsStuck(ESCKEY)) { keyClearSticky(ESCKEY); //clear the sticky bit if (!hrAbortLoadConfirm) { if (!hrAbortLoadingGame) // if not already aborting { hrAbortLoadConfirm = feScreenStart(&horseCrapRegion, "AbortLoadConfirm"); } } else { feScreenDelete(hrAbortLoadConfirm); hrAbortLoadConfirm = NULL; } } } regProcessingRegions = TRUE; if (hrAbortLoadConfirm!=NULL) { ; } else if (ChatTextEntryBox!=NULL) { regRegionProcess(&ChatTextEntryBox->reg, 0xffffffff); } regProcessingRegions = FALSE; } if (ChatTextEntryBox!=NULL) { bitSet(ChatTextEntryBox->reg.status,RSF_KeyCapture); keyBufferClear(); } if (TitanActive) titanPumpEngine(); Sleep(0); } } // All of the hacked stuff from the render task //glColor3ub(colRed(RND_StarColor), colGreen(RND_StarColor), colBlue(RND_StarColor)); if (ShouldHaveMousePtr) { if (feShouldSaveMouseCursor()) { if (RGLtype == SWtype) rglFeature(RGL_SAVEBUFFER_ON); } else { if (RGLtype == SWtype) rglFeature(RGL_SAVEBUFFER_OFF); rndClearToBlack(); glClear(GL_DEPTH_BUFFER_BIT); } } // primErrorMessagePrint(); //default rendering scheme is primitives on any //functions which want it off should set it back on when done // I know this looks weird, but it's correct if(hrBackgroundInitFrame == 1) hrInitBackground(); // When there's no background loaded yet, it fills the screen with black if (RGLtype == SWtype) { hrDrawBackground(); } else { if (hrBackgroundDirty) { hrDrawBackground(); } else { if (hrBackgroundImage != NULL) { free(hrBackgroundImage); hrBackgroundImage = NULL; } } } regFunctionsDraw(); //render all regions primErrorMessagePrint(); hrUncleanDecorative(); // We want the init code to be called on the 2nd pass. That way, the screen erases, // Then we incur the delay of loading the background. // For two frames -after that- we'll draw the background, // then just draw the progress bars. if(hrBackgroundDirty && hrBackgroundInitFrame) { if (hrBackgroundDirty > 0) hrBackgroundDirty--; } hrBackgroundInitFrame++; if (ShouldHaveMousePtr) { // set the cursor type, reset the variables then draw the mouse cursor mouseSelectCursorSetting(); mouseSetCursorSetting(); if (feShouldSaveMouseCursor()) { mouseStoreCursorUnder(); } mousePoll(); mouseDraw(); //draw mouse atop everything if (demDemoPlaying) { rndShamelessPlug(); } } rndFlush(); if (ShouldHaveMousePtr) { if (feShouldSaveMouseCursor()) { mouseRestoreCursorUnder(); } } primErrorMessagePrint(); } //function that returns the doctored percentage for conversion of //multiple bars to a single bar. real32 horseRaceGetPacketPercent(real32 barPercent) { real32 percent=0.0f; sdword i; for(i=0;i 1.0f) percent = 1.0f; // if(utyTeaserHeader) return TRUE; /*glClear(GL_COLOR_BUFFER_BIT); regFunctionsDraw(); //render all regions glFlush(); //ensure all draws complete*/ if (TitanActive) titanPumpEngine(); packet.packetheader.type = PACKETTYPE_HORSERACE; packet.playerindex = (uword) sigsPlayerIndex; packet.packetheader.numberOfCommands = 0; //don't need probably packet.barnum = (uword) localbar; //packet.current = (uword) localcurrent; //packet.max = (uword) localmax; packet.percent = horseRaceGetPacketPercent(percent); //render first if (lasttime == 0.0f) { horseRaceRender(); dontrenderhack = TRUE; } if (multiPlayerGame && (startingGameState == AUTODOWNLOAD_MAP) && (sigsPlayerIndex == 0)) { sendhrpackethack = TRUE; SendHorseRacePacket((ubyte *)&packet,sizeof(HorsePacket)); // always send horse race packet when autouploading map } GetSystemTime(&lp); temptime = (lp.wMilliseconds+lp.wSecond*1000.0f); if(temptime - lasttime < horseRaceRenderTime) { if(lasttime > temptime) lasttime = temptime; return FALSE; //don't return } lasttime = temptime; // if(lastper != percent) // { if (multiPlayerGame) { if (!sendhrpackethack) { if (modulusCounter <= 0) { modulusCounter = 6; } modulusCounter--; if (modulusCounter == 0) { SendHorseRacePacket((ubyte *)&packet,sizeof(HorsePacket)); } } } else { recievedHorsePacketCB((ubyte *)&packet,sizeof(HorsePacket)); } // } // lastper = percent; if (!dontrenderhack) { horseRaceRender(); } if(multiPlayerGame) { for(i=0;iplayerindex; dbgAssert(i < MAX_MULTIPLAYER_PLAYERS); if (multiPlayerGame) { titanDebug("hr: recv hrpacket from %d status %d",i,playersReadyToGo[i]); if (!playerHasDroppedOutOrQuit(i)) { TTimerReset(&hrPlayerDropoutTimers[i]); } } hrDirtyProgressBar(); horseracestatus.barnum[i] = hp->barnum; horseracestatus.percent[i] = hp->percent; }