/*============================================================================= Name : ScenPick.c Purpose : Functionality to choose scenarios Created 10/21/1997 by lmoloney Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include #include #include "types.h" #include "debug.h" #include "file.h" #include "memory.h" #include "feflow.h" #include "utility.h" #include "font.h" #include "fontreg.h" #include "prim2d.h" #include "mouse.h" #include "scroller.h" #include "ScenPick.h" #include "texreg.h" #include "render.h" #include "bmp.h" #include "multiplayergame.h" #include "FEColour.h" #include "statscript.h" #include "subtitle.h" #include "glcompat.h" #include "strings.h" /*============================================================================= Data: =============================================================================*/ char DefaultScenario[100] = "Default"; void spScenarioWindowInit(char *name, featom *atom); void spScenarioNameDraw(featom *atom, regionhandle region); void spScenarioBitmap(featom *atom, regionhandle region); //void spScenarioBitmap(char *name, featom *atom); fecallback spCallbacks[] = { {spScenarioWindowInit, "CS_ScenarioWindowInit"}, //{spScenarioBitmap, "CS_ScenarioBitmap"}, {NULL, NULL} }; fedrawcallback spDrawCallbacks[] = { {spScenarioNameDraw, "CS_ScenarioName"}, {spScenarioBitmap, "CS_ScenarioBitmap"}, {NULL, NULL} }; listwindowhandle spScenarioListWindow = NULL; //regionhandle spScenarioBitmapWindow = NULL; char *ScenarioImagePath = "MultiPlayer\\"; lifheader *scenarioImage; udword scenarioTexture = TR_InvalidInternalHandle; sdword spTextureWidth, spTextureHeight; ubyte* spTextureData = NULL; bool spPickerStarted = FALSE; #define SCP_TEXTURE_INSET 3 spscenario *spScenarios; //list of available scenarios sdword spCurrentSelected = 0; //current scenario index, if OK is pressed sdword spNumberScenarios = 0; //number of available scenarios sdword spScenarioListLength = SCP_ScenarioListLength;//length of scenario list fonthandle spListFont, spNameFont; //fonts used for font printing color spSelectedColor = SCP_SelectedColor; //color to draw selected one at uword spTopIndex = 0; //index of what is at the top of the list uword spDisplayLength = SCP_DisplayListLength; //number of scenarios displayed at one time //text description stuff sdword spNDescriptionLines = 0; //number of text description lines char **spDescriptionLines = NULL; //the actual lines char *spDescription = NULL; //the actual description (may be chopped) fonthandle spDescriptionFont = FONT_InvalidFontHandle;//font to print in bool spDescriptionShadow = FALSE; //print with a dropshadow? color spDescriptionColor = colWhite; //print in what color? GameType *gameTypeFromDescription = NULL; static void spMissionDescriptionSet(char *directory,char *field,void *dataToFillIn); static void spDescriptionFontSet(char *directory,char *field,void *dataToFillIn); extern scriptStructEntry StaticMGInfoScriptTable[]; scriptEntry spDescriptionTweaks[] = { {"Description", spMissionDescriptionSet, NULL}, {"Font", spDescriptionFontSet, NULL}, {"Color", scriptSetRGBCB, &spDescriptionColor}, {"DropShadow", scriptSetBool8, &spDescriptionShadow}, endEntry }; scriptEntry spDescriptionTweaksFrench[] = { {"DescriptionFrench", spMissionDescriptionSet, NULL}, {"Font", spDescriptionFontSet, NULL}, {"Color", scriptSetRGBCB, &spDescriptionColor}, {"DropShadow", scriptSetBool8, &spDescriptionShadow}, endEntry }; scriptEntry spDescriptionTweaksGerman[] = { {"DescriptionGerman", spMissionDescriptionSet, NULL}, {"Font", spDescriptionFontSet, NULL}, {"Color", scriptSetRGBCB, &spDescriptionColor}, {"DropShadow", scriptSetBool8, &spDescriptionShadow}, endEntry }; scriptEntry spDescriptionTweaksSpanish[] = { {"DescriptionSpanish", spMissionDescriptionSet, NULL}, {"Font", spDescriptionFontSet, NULL}, {"Color", scriptSetRGBCB, &spDescriptionColor}, {"DropShadow", scriptSetBool8, &spDescriptionShadow}, endEntry }; scriptEntry spDescriptionTweaksItalian[] = { {"DescriptionItalian", spMissionDescriptionSet, NULL}, {"Font", spDescriptionFontSet, NULL}, {"Color", scriptSetRGBCB, &spDescriptionColor}, {"DropShadow", scriptSetBool8, &spDescriptionShadow}, endEntry }; /*============================================================================= Private functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : spScenarioItemDraw Description : Draw the list of available scenarios Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spScenarioItemDraw(rectangle *rect, listitemhandle data) { char temp[64]; sdword x, y; color c; fonthandle oldfont; spscenario *spScenario = (spscenario *)data->data; oldfont = fontMakeCurrent(spListFont); if (data->flags&UICLI_Selected) c = FEC_ListItemSelected; else c = FEC_ListItemStandard; x = rect->x0;//+MG_HorzSpacing; y = rect->y0;//+MG_VertSpacing/2; sprintf(temp,"%s",spScenario->title); fontPrint(x,y,c,temp); fontMakeCurrent(oldfont); } /*----------------------------------------------------------------------------- Name : spScenarioNameDraw Description : Draw the currently selected scenario name in screens other than the scenario picker. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spScenarioNameDraw(featom *atom, regionhandle region) { fonthandle fhSave; char scenarioName[128]; bool useDisplayName = FALSE; rectangle *r = ®ion->rect; fhSave = fontMakeCurrent(spNameFont); //select the appropriate font if (multiPlayerGame && (!GameCreator)) { if (LANGame) { if (currentScreen == MGS_Basic_Options_View) { useDisplayName = TRUE; } } else { if (WaitingForGame) { useDisplayName = TRUE; } } } if (useDisplayName) memStrncpy(scenarioName, tpGameCreated.DisplayMapName, 127); else memStrncpy(scenarioName, spScenarios[spCurrentSelected].title, 127); _strupr(scenarioName); fontPrintf(r->x0, r->y0, FEC_ListItemSelected, scenarioName); fontMakeCurrent(fhSave); } /*----------------------------------------------------------------------------- Name : spTitleFind Description : Finds the title of a mission file (on first line, in brackets) Inputs : directory, fileName - combine to form path to the file. Outputs : Allocated memory for and duplicates a string. Return : Pointer to title string. ----------------------------------------------------------------------------*/ char *spTitleFind(char *directory, char *fileName) { char string[256], fullName[_MAX_PATH]; filehandle handle; sdword status; memStrncpy(fullName, directory, _MAX_PATH - 1); strcat(fullName, fileName); strcat(fullName,"\\"); strcat(fullName, fileName); strcat(fullName,".level"); handle = fileOpen(fullName, FF_TextMode|FF_ReturnNULLOnFail); if (!handle) { return NULL; } for (;;) { status = fileLineRead(handle,string,256); if (status == FR_EndOfFile) { break; } if ((string[0] == '\n') || (string[0] == '/') || (string[0] == ';') || (string[0] == ' ')) { continue; } if (strlen(string) >= 3 && *string == '[' && string[strlen(string) - 1] == ']') { fileClose(handle); string[strlen(string) - 1] = 0; return(memStringDupe(&string[1])); } } fileClose(handle); return memStringDupe(fullName); } /*----------------------------------------------------------------------------- Name : compareScenariosCB Description : compare's the scenarios alphabetically Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ int compareScenariosCB(const void *arg1,const void *arg2) { int result; spscenario *scenario1 = (spscenario *)arg1; spscenario *scenario2 = (spscenario *)arg2; result = _stricmp(scenario1->title,scenario2->title); return result; } /*----------------------------------------------------------------------------- Name : spScenarioFind Description : Find a scenario by name Inputs : scenarioName - name of scenario to find Outputs : Return : Index of specified scenario or 0 if not found ----------------------------------------------------------------------------*/ sdword spScenarioFind(char *scenarioName) { sdword index; for (index = 0; index < spNumberScenarios; index++) { if (strstr(spScenarios[index].title, scenarioName) == spScenarios[index].title) { //if this is the default level return(index); spCurrentSelected = index; //set default scenario break; } } return(0); } /*----------------------------------------------------------------------------- Name : spTitleListLoad Description : Scans the missions directory and loads in the titles of all the mission files available. Inputs : void Outputs : Fills in spScenarios and spNumberScenarios Return : void ----------------------------------------------------------------------------*/ void spTitleListLoad(void) { #if !(defined(CGW) || defined (Downloadable) || defined(DLPublicBeta) || defined(OEM)) struct _finddata_t find; sdword handle, startHandle; #endif sdword index, numplayers; char fileName[_MAX_PATH], nameBuffer[_MAX_PATH]; #if MAIN_Password char upperNameBuffer[_MAX_PATH]; #endif char bitmapfileName[_MAX_PATH]; char *pString; char *title; filehandle scriptFile; #if defined(CGW) || defined(Downloadable) || defined(DLPublicBeta) scriptFile = fileOpen("DemoMissions.script", FF_TextMode); #else //oem has all missions! scriptFile = fileOpen("multiPlayerMissions.script", FF_TextMode); #endif dbgAssert(scriptFile != 0); while (fileLineRead(scriptFile, nameBuffer, _MAX_PATH) != FR_EndOfFile) { if (nameBuffer[0] == ';' || (nameBuffer[0] == '/' && nameBuffer[1] == '/')) { continue; } numplayers = 0; for (pString = nameBuffer; *pString != 0; pString++) { //search for a numeral character if (strchr("0123456789", *pString) != NULL) { //if this is a numeral numplayers = atoi(pString); memset(fileName, 0, _MAX_PATH); memStrncpy(fileName, nameBuffer, pString - nameBuffer + 1);//copy the start of the string memStrncpy(bitmapfileName, nameBuffer, pString - nameBuffer + 1);//copy the start of the string strcat(fileName, "%d"); //make something like: strcat(fileName, pString + 1); //'StdGame%d.level' } } if (numplayers == 0) { goto alreadyLoaded; } title = spTitleFind("MultiPlayer\\", nameBuffer); if (title == NULL) { goto alreadyLoaded; //break-continue } #if MAIN_Password if (!mainEnableSpecialMissions) { //if this is an "off-limits" mission strcpy(upperNameBuffer, title); _strupr(upperNameBuffer); if (strstr(upperNameBuffer, "ALL")) { memFree(title); goto alreadyLoaded; //break-continue } } #endif //MAIN_Password for (index = 0; index < spNumberScenarios; index++) { if (!_stricmp(spScenarios[index].fileSpec, fileName)) { //if matching file specs, // matches, but we should update max number of player if necessary if (numplayers > spScenarios[index].maxplayers) spScenarios[index].maxplayers = numplayers; if (numplayers < spScenarios[index].minplayers) spScenarios[index].minplayers = numplayers; memFree(title); goto alreadyLoaded; //break-continue } } if (spNumberScenarios >= spScenarioListLength) { spScenarioListLength += SP_ScenarioListGrowth; spScenarios = memRealloc(spScenarios, spScenarioListLength * sizeof(spscenario), "spScenarios", NonVolatile); } dbgAssert(spNumberScenarios < spScenarioListLength); spScenarios[spNumberScenarios].fileSpec = memStringDupe(fileName); spScenarios[spNumberScenarios].bitmapfileSpec = memStringDupe(bitmapfileName); spScenarios[spNumberScenarios].title = title; spScenarios[spNumberScenarios].maxplayers = numplayers; spScenarios[spNumberScenarios].minplayers = numplayers; spNumberScenarios++; alreadyLoaded:; } fileClose(scriptFile); #if !(defined(CGW) || defined (Downloadable) || defined(DLPublicBeta) || defined(OEM)) startHandle = handle = _findfirst(filePathPrepend("MultiPlayer\\*.", 0), &find); while (handle != -1) { if (find.name[0] == '.') { goto alreadyLoadedFromFileSystem; } fileName[0] = 0; numplayers = 0; for (pString = find.name; *pString != 0; pString++) { //search for a numeral character if (strchr("0123456789", *pString) != NULL) { //if this is a numeral numplayers = atoi(pString); memset(fileName, 0, _MAX_PATH); strncpy(fileName, find.name, pString - find.name);//copy the start of the string memStrncpy(bitmapfileName, find.name, pString - find.name + 1);//copy the start of the string strcat(fileName, "%d"); //make something like: strcat(fileName, pString + 1); //'StdGame%d.level' } } if (numplayers == 0) { goto alreadyLoadedFromFileSystem; } if (fileName[0] == 0) { goto alreadyLoadedFromFileSystem; } title = spTitleFind("MultiPlayer\\", find.name); if (title == NULL) { goto alreadyLoadedFromFileSystem; } #if MAIN_Password if (!mainEnableSpecialMissions) { //if this is an "off-limits" mission strcpy(upperNameBuffer, title); _strupr(upperNameBuffer); if (strstr(upperNameBuffer, "ALL")) { memFree(title); goto alreadyLoadedFromFileSystem; //break-continue } } #endif //MAIN_Password for (index = 0; index < spNumberScenarios; index++) { if (!_stricmp(spScenarios[index].fileSpec, fileName)) { //if matching file specs, // matches, but we should update max number of player if necessary if (numplayers > spScenarios[index].maxplayers) spScenarios[index].maxplayers = numplayers; if (numplayers < spScenarios[index].minplayers) spScenarios[index].minplayers = numplayers; memFree(title); goto alreadyLoadedFromFileSystem; //break-continue } } if (spNumberScenarios >= spScenarioListLength) { spScenarioListLength += SP_ScenarioListGrowth; spScenarios = memRealloc(spScenarios, spScenarioListLength * sizeof(spscenario), "spScenarios", NonVolatile); } dbgAssert(spNumberScenarios < spScenarioListLength); spScenarios[spNumberScenarios].fileSpec = memStringDupe(fileName); spScenarios[spNumberScenarios].bitmapfileSpec = memStringDupe(bitmapfileName); spScenarios[spNumberScenarios].title = title; spScenarios[spNumberScenarios].maxplayers = numplayers; spScenarios[spNumberScenarios].minplayers = numplayers; spNumberScenarios++; alreadyLoadedFromFileSystem:; handle = _findnext(startHandle, &find); } #endif //defined(CGW) || defined (Downloadable) || defined(DLPublicBeta) || defined(OEM) dbgAssert(spNumberScenarios > 0); if (spNumberScenarios > 1) { //alphabetically sort the scenario list qsort(&spScenarios[0],spNumberScenarios,sizeof(spscenario),compareScenariosCB); } //find the default scenario's index if (spCurrentSelected == 0) { //if it's not already selected spCurrentSelected = spScenarioFind(DefaultScenario); } } /*============================================================================= Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : spStartup Description : Inputs : Outputs : Registers some callbacks for buttons and user regions. Return : ----------------------------------------------------------------------------*/ void spStartup(void) { feDrawCallbackAddMultiple(spDrawCallbacks); spListFont = frFontRegister(SCP_ListFont); spNameFont = frFontRegister(SCP_NameFont); spScenarios = memAlloc(spScenarioListLength * sizeof(spscenario), "spScenarios", NonVolatile); spTitleListLoad(); if (spCurrentSelected >= spNumberScenarios) { spCurrentSelected = spScenarioFind(DefaultScenario); } } /*----------------------------------------------------------------------------- Name : spShutdown Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spShutdown(void) { sdword index; for (index = 0; index < spNumberScenarios; index++) { memFree(spScenarios[index].bitmapfileSpec); memFree(spScenarios[index].fileSpec); memFree(spScenarios[index].title); } memFree(spScenarios); } void spNewItem(void); /*----------------------------------------------------------------------------- Name : spScenarioWindowInit Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spScenarioWindowInit(char *name, featom *atom) { fonthandle oldfont; sdword index; if (FEFIRSTCALL(atom)) { oldfont = fontMakeCurrent(spListFont); spScenarioListWindow = (listwindowhandle)atom->pData; uicListWindowInit(spScenarioListWindow, NULL, // title draw, no title NULL, // title click process, no title 0/*fontHeight(" ")*2*/, // title height, no title spScenarioItemDraw, // item draw function fontHeight(" ")+SCP_VertSpacing, // item height UICLW_CanSelect|UICLW_CanHaveFocus); //spScenarioListWindow->reg.flags |= for (index = 0; index < spNumberScenarios; index++) { if (index==spCurrentSelected) uicListAddItem(spScenarioListWindow, (ubyte *)&spScenarios[index], UICLI_CanSelect|UICLI_Selected, UICLW_AddToTail); else uicListAddItem(spScenarioListWindow, (ubyte *)&spScenarios[index], UICLI_CanSelect, UICLW_AddToTail); } fontMakeCurrent(oldfont); return; } else { switch (spScenarioListWindow->message) { case CM_AcceptText: spDonePicking(NULL,NULL); break; case CM_DoubleClick: spDonePicking(NULL,NULL); break; case CM_NewItemSelected: spNewItem(); } } } /*----------------------------------------------------------------------------- Name : spScenarioPick Description : Starts the scenario picker Inputs : dest - where to store file name of destiation file. Will be "" if nothing (yet) chosen. Outputs : Starts the scenario picker screen. When chosen, the name will be stored in dest. Return : void ----------------------------------------------------------------------------*/ void spScenarioPick(char *dest) { feCallbackAddMultiple(spCallbacks); feScreenStart(ghMainRegion, SCP_ScreenName); spNewItem(); spPickerStarted = TRUE; } bool spSelectionValid(sdword candidate) { if (tpGameCreated.numPlayers + tpGameCreated.numComputers > spScenarios[candidate].maxplayers) { if (tpGameCreated.numPlayers > spScenarios[candidate].maxplayers) { return FALSE; // too many people for this map } else { // let's bump computers out for humans to join tpGameCreated.numComputers = spScenarios[candidate].maxplayers - tpGameCreated.numPlayers; // this line caused a warning in release build, numComputers is always >= 0 it is unsigned! //dbgAssert(tpGameCreated.numComputers >= 0); dbgAssert(tpGameCreated.numPlayers + tpGameCreated.numComputers <= spScenarios[candidate].maxplayers); } } return TRUE; } /*----------------------------------------------------------------------------- Name : spDescriptionDefaultsAndFreeText Description : Set text description defaults. Inputs : void Outputs : Return : void ----------------------------------------------------------------------------*/ void spDescriptionDefaultsAndFreeText(void) { if (spDescription != NULL) { //if there was a description memFree(spDescription); //kill it spDescription = NULL; memFree(spDescriptionLines); spNDescriptionLines = 0; } spDescriptionFont = FONT_InvalidFontHandle; //set printing defaults spDescriptionShadow = FALSE; spDescriptionColor = colWhite; if (gameTypeFromDescription != NULL) { memFree(gameTypeFromDescription); gameTypeFromDescription = NULL; } } /*----------------------------------------------------------------------------- Name : spDonePicking/spBackPicking // if the region is the scenario picker Description : Close the color picker and optionally specify the file path of the chosen file. Inputs : standard FE callback Outputs : DonePicking stores chosen file name in parameter to spScenarioPick Return : void ----------------------------------------------------------------------------*/ void spDonePicking(char *name, featom *atom) { sdword index; sdword spCurrentSelectedCandidate = spCurrentSelected; if (spScenarioListWindow->CurLineSelected!=NULL) { for (index = 0; index < spNumberScenarios; index++) { if (spScenarioListWindow->CurLineSelected->data == (ubyte *)&spScenarios[index]) { spCurrentSelectedCandidate = index; break; } } } if (gameTypeFromDescription != NULL) { //if there is a game type from description file mgSetGameTypeByStruct(gameTypeFromDescription); //set that game type feAllCallOnCreate(feStack[feStackIndex - 1].screen);//update buttons to reflect changes mgGameTypesOtherButtonPressed(); } spDescriptionDefaultsAndFreeText(); if (scenarioTexture != TR_InvalidInternalHandle) { //delete the preview image, if there was one trRGBTextureDelete(scenarioTexture); scenarioTexture = TR_InvalidInternalHandle; if (spTextureData != NULL) { memFree(spTextureData); spTextureData = NULL; } } if (spSelectionValid(spCurrentSelectedCandidate)) { spCurrentSelected = spCurrentSelectedCandidate; } feScreenDisappear(NULL, NULL); spPickerStarted = FALSE; } void spBackPicking(char *name, featom *atom) { spDescriptionDefaultsAndFreeText(); if (scenarioTexture != TR_InvalidInternalHandle) { //delete the preview image, if there was one trRGBTextureDelete(scenarioTexture); scenarioTexture = TR_InvalidInternalHandle; if (spTextureData != NULL) { memFree(spTextureData); spTextureData = NULL; } } feScreenDisappear(NULL, NULL); spPickerStarted = FALSE; } /*----------------------------------------------------------------------------- Name : spFindMap Description : Sets the current selected scenario to the mapname specified Inputs : Outputs : DonePicking stores chosen file name in parameter to spScenarioPick Return : void ----------------------------------------------------------------------------*/ void spFindMap(char *MapName) { sdword index; for (index = 0; index < spNumberScenarios; index++) { if (stricmp(spScenarios[index].title,MapName)==0) { spCurrentSelected = index; break; } } } /*----------------------------------------------------------------------------- Name : spFindImage Description : Attempt to find the preview image for a given scenario Inputs : scenarioFile - name of scenario Outputs : bitmapFile - name of preview.bmp file if found textFile - name of description.txt file if found Return : void ----------------------------------------------------------------------------*/ void spFindImage(char* bitmapFile, char *textFile, char *scenarioFile) { sdword i; bool foundBitmap = FALSE, foundText = FALSE; for (i = 2; i<=8; i++) { #if 0 // if 0 out because it's a bug in my bug list if (!foundBitmap) { sprintf(bitmapFile, "%s%s%c\\preview.bmp", ScenarioImagePath, scenarioFile, '0' + i); if (fileExists(bitmapFile, 0)) { //see if there is a preview bitmap in this directory foundBitmap = TRUE; } } #endif if (!foundText) { sprintf(textFile, "%s%s%c\\description.txt", ScenarioImagePath, scenarioFile, '0' + i); if (fileExists(textFile, 0)) { //see if there is a description text file in this directory foundText = TRUE; } } } if (!foundBitmap) { *bitmapFile = 0; } if (!foundText) { *textFile = 0; } } /*----------------------------------------------------------------------------- Name : spMissionDescriptionSet Description : Script-parse callback for setting description text Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ static void spMissionDescriptionSet(char *directory,char *field,void *dataToFillIn) { if (spDescription == NULL) { spDescription = memStringDupe(field); } else { spDescription = memRealloc(spDescription, strlen(spDescription) + strlen(field) + 3, "DescriptionString", 0); strcat(spDescription, "\\n"); //auto-newline strcat(spDescription, field); } } /*----------------------------------------------------------------------------- Name : spDescriptionFontSet Description : Script-parsing callback to set the font for the description text. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ static void spDescriptionFontSet(char *directory,char *field,void *dataToFillIn) { spDescriptionFont = frFontRegister(field); } /*----------------------------------------------------------------------------- Name : spNewItem Description : Called when a new item in the color picker list is selected. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spNewItem(void) { char bitmapFile[_MAX_PATH]; char descriptionFile[_MAX_PATH]; char *chopBuffer; sdword scen; rectangle textureRect; // rectangle rect = spScenarioBitmapWindow->rect; color *bmpBuffer; filehandle handle; bmpheader header; featom *atom; scen = spScenarioListWindow->CurLineSelected->position; atom = feAtomFindInScreen(feStack[feStackIndex].screen, "CS_ScenarioBitmap"); dbgAssert(atom != NULL); if (scenarioTexture != TR_InvalidInternalHandle) { //delete the old texture before creating a new one trRGBTextureDelete(scenarioTexture); scenarioTexture = TR_InvalidInternalHandle; if (spTextureData != NULL) { memFree(spTextureData); spTextureData = NULL; } } //free the previous text and set defaults spDescriptionDefaultsAndFreeText(); spFindImage(bitmapFile, descriptionFile, spScenarios[scen].bitmapfileSpec); if (strlen(bitmapFile) > 0) { handle = bmpFileOpen(&header, bitmapFile); //open the file if (handle != 0) { //if opened properly if (header.biWidth < SCP_PreviewWidthMin || header.biHeight > SCP_PreviewWidthMax) { #if SCP_VERBOSE_LEVEL >= 1 dbgMessagef("\n'%s': width of %d bad.", bitmapFile, header.biWidth); #endif bmpClose(handle); return; } else if (header.biHeight < SCP_PreviewHeightMin || header.biHeight > SCP_PreviewHeightMax) { #if SCP_VERBOSE_LEVEL >= 1 dbgMessagef("\n'%s': height of %d bad.", bitmapFile, header.biHeight); #endif bmpClose(handle); return; } //allocate the image buffer bmpBuffer = memAlloc(header.biWidth * header.biHeight * sizeof(color), "TempBMPbuffer", Pyrophoric); bmpBodyRead(bmpBuffer, handle, &header); //read in the body of the file if (header.biWidth != SCP_PreviewWidth || header.biHeight != SCP_PreviewHeight) { //if the image is the wrong size //rescale the image to the proper size bmpBuffer = trImageScale(bmpBuffer, header.biWidth, header.biHeight, SCP_PreviewWidth, SCP_PreviewHeight, TRUE); header.biWidth = SCP_PreviewWidth; //make it think we're the right size header.biHeight = SCP_PreviewHeight; } scenarioTexture = trRGBTextureCreate(bmpBuffer, header.biWidth, header.biHeight, FALSE); spTextureWidth = header.biWidth; spTextureHeight = header.biHeight; if (spTextureData != NULL) { memFree(spTextureData); } spTextureData = (ubyte*)memAlloc(4*spTextureWidth*spTextureHeight, "scenpick data", NonVolatile); memcpy(spTextureData, bmpBuffer, 4*spTextureWidth*spTextureHeight); memFree(bmpBuffer); //free the image } else { return; } } else { #if SCP_VERBOSE_LEVEL >= 1 dbgMessage("\nNo preview image found!"); #endif textureRect.x0 = atom->x + SCP_TEXTURE_INSET; textureRect.y0 = atom->y + SCP_TEXTURE_INSET; textureRect.x1 = atom->x + atom->width - SCP_TEXTURE_INSET; textureRect.y1 = atom->y + atom->height - SCP_TEXTURE_INSET; primRectSolid2(&textureRect, colBlack); } if (strlen(descriptionFile) > 0) { //if there is a description file // load in the proper description based on the language if (strCurLanguage==languageEnglish) { scriptSet(NULL, descriptionFile, spDescriptionTweaks);//load in the description text } else if (strCurLanguage==languageFrench) { scriptSet(NULL, descriptionFile, spDescriptionTweaksFrench);//load in the description text if (spDescription==NULL) { // if french isn't found load in english scriptSet(NULL, descriptionFile, spDescriptionTweaks);//load in the description text } } else if (strCurLanguage==languageGerman) { scriptSet(NULL, descriptionFile, spDescriptionTweaksGerman);//load in the description text if (spDescription==NULL) { // if german isn't found load in english scriptSet(NULL, descriptionFile, spDescriptionTweaks);//load in the description text } } else if (strCurLanguage==languageSpanish) { scriptSet(NULL, descriptionFile, spDescriptionTweaksSpanish);//load in the description text if (spDescription==NULL) { // if german isn't found load in english scriptSet(NULL, descriptionFile, spDescriptionTweaks);//load in the description text } } else if (strCurLanguage==languageItalian) { scriptSet(NULL, descriptionFile, spDescriptionTweaksItalian);//load in the description text if (spDescription==NULL) { // if german isn't found load in english scriptSet(NULL, descriptionFile, spDescriptionTweaks);//load in the description text } } if (spDescription != NULL) { //if there was real text in that file if (spDescriptionFont == FONT_InvalidFontHandle) { //make sure we have a font spDescriptionFont = frFontRegister("default.hff"); } textureRect.x0 = atom->x + SCP_TEXTURE_INSET; //and a region to print into textureRect.y0 = atom->y + SCP_TEXTURE_INSET; textureRect.x1 = atom->x + atom->width - SCP_TEXTURE_INSET; textureRect.y1 = atom->y + atom->height - SCP_TEXTURE_INSET; spDescriptionLines = memAlloc(sizeof(char *) * (textureRect.y1 - textureRect.y0), "DescLines", NonVolatile);//allocate the chopping pointers chopBuffer = memAlloc(strlen(spDescription) + textureRect.y1 - textureRect.y0, "DescChopped", NonVolatile);//allocate chop buffer spNDescriptionLines = subStringsChop(&textureRect, spDescriptionFont, strlen(spDescription), spDescription, chopBuffer, spDescriptionLines); memFree(spDescription); //free unchopped description spDescription = chopBuffer; //keep pointer to chopped description } gameTypeFromDescription = memAlloc(sizeof(GameType), "DescGameType", 0); memset(gameTypeFromDescription, 0xff, sizeof(GameType)); //flag all members as unused gameTypeFromDescription->flag = gameTypeFromDescription->flagNeeded = 0; //flag none of the flags needed scriptSetStruct(NULL, descriptionFile, StaticMGInfoScriptTable, (ubyte *)gameTypeFromDescription); } if (strlen(descriptionFile) > 0 || strlen(bitmapFile) > 0) { //if there is a description file or a bitmap if (spPickerStarted) { spScenarioBitmap(atom, (regionhandle)atom->region);//draw it/them } } } /*----------------------------------------------------------------------------- Name : spScenarioBitmap Description : Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void spScenarioBitmap(featom *atom, regionhandle region) { rectangle textureRect; sdword index, y; fonthandle oldFont; textureRect.x0 = region->rect.x0 + SCP_TEXTURE_INSET; textureRect.y0 = region->rect.y0 + SCP_TEXTURE_INSET; textureRect.x1 = region->rect.x1 - SCP_TEXTURE_INSET; textureRect.y1 = region->rect.y1 - SCP_TEXTURE_INSET; //draw the bitmap... if (scenarioTexture != TR_InvalidInternalHandle) { if (glcActive()) { glcRectSolidTexturedScaled2(&textureRect, spTextureWidth, spTextureHeight, spTextureData, NULL, TRUE); } else { trRGBTextureMakeCurrent(scenarioTexture); rndPerspectiveCorrection(FALSE); primRectSolidTextured2(&textureRect); //draw the bitmap } feStaticRectangleDraw(region); //draw a border } //draw the description text... if (spDescription != NULL) { //if there is description text dbgAssert(spDescriptionFont != FONT_InvalidFontHandle); oldFont = fontMakeCurrent(spDescriptionFont); //set the font if (spDescriptionShadow) { //optionally enable dropshadow fontShadowSet(FS_SE, colBlack); } for (index = 0, y = textureRect.y0; index < spNDescriptionLines; index++) { //draw each line dbgAssert(spDescriptionLines[index] != NULL); if (y + fontHeight(" ") >= textureRect.y1) { //if this line will extend off bottom of region break; } fontPrint(textureRect.x0, y, spDescriptionColor, spDescriptionLines[index]); y += fontHeight(" ") + 1; } fontShadowSet(FS_NONE, colBlack); fontMakeCurrent(oldFont); } }