C4SoundEffect *C4SoundSystem::GetEffect(const char *szSndName) { C4SoundEffect *pSfx; char szName[C4MaxSoundName + 4 + 1]; int32_t iNumber; // Evaluate sound name SCopy(szSndName, szName, C4MaxSoundName); // Default extension DefaultExtension(szName, "wav"); // Convert old style '*' wildcard to correct '?' wildcard // For sound effects, '*' is supposed to match single digits only SReplaceChar(szName, '*', '?'); // Sound with a wildcard: determine number of available matches if (SCharCount('?', szName)) { // Search global sound file if (!(iNumber = SoundFile.EntryCount(szName))) // Search scenario local files if (!(iNumber = Game.ScenarioFile.EntryCount(szName))) // Search bank loaded sounds if (!(iNumber = EffectInBank(szName))) // None found: failure return NULL; // Insert index to name iNumber = BoundBy(1 + SafeRandom(iNumber), 1, 9); SReplaceChar(szName, '?', '0' + iNumber); } // Find requested sound effect in bank for (pSfx = FirstSound; pSfx; pSfx = pSfx->Next) if (SEqualNoCase(szName, pSfx->Name)) break; // Sound not in bank, try add if (!pSfx) if (!(pSfx = AddEffect(szName))) return NULL; return pSfx; }
void C4Language::LoadInfos(C4Group &hGroup) { char strEntry[_MAX_FNAME + 1]; char *strTable; // Look for language string tables hGroup.ResetSearch(); while (hGroup.FindNextEntry(C4CFN_Language, strEntry)) // For now, we will only load info on the first string table found for a given // language code as there is currently no handling for selecting different string tables // of the same code - the system always loads the first string table found for a given code if (!FindInfo(GetFilenameOnly(strEntry) + SLen(GetFilenameOnly(strEntry)) - 2)) // Load language string table if (hGroup.LoadEntry(strEntry, &strTable, 0, 1)) { // New language info C4LanguageInfo *pInfo = new C4LanguageInfo; // Get language code by entry name SCopy(GetFilenameOnly(strEntry) + SLen(GetFilenameOnly(strEntry)) - 2, pInfo->Code, 2); SCapitalize(pInfo->Code); // Get language name, info, fallback from table CopyResStr("IDS_LANG_NAME", strTable, pInfo->Name); CopyResStr("IDS_LANG_INFO", strTable, pInfo->Info); CopyResStr("IDS_LANG_FALLBACK", strTable, pInfo->Fallback); // Safety: pipe character is not allowed in any language info string SReplaceChar(pInfo->Name, '|', ' '); SReplaceChar(pInfo->Info, '|', ' '); SReplaceChar(pInfo->Fallback, '|', ' '); // Delete table delete [] strTable; // Add info to list pInfo->Next = Infos; Infos = pInfo; } }
int32_t C4TextureMap::LoadTextures(C4Group &hGroup, C4Group* OverloadFile) { int32_t texnum=0; #ifdef C4ENGINE // overload: load from other file if (OverloadFile) texnum+=LoadTextures(*OverloadFile); char texname[256+1]; C4Surface *ctex; size_t binlen; // newgfx: load PNG-textures first hGroup.ResetSearch(); while (hGroup.AccessNextEntry(C4CFN_PNGFiles,&binlen,texname)) { // check if it already exists in the map SReplaceChar(texname,'.',0); if (GetTexture(texname)) continue; SAppend(".png", texname); // load if (ctex=GroupReadSurfacePNG(hGroup)) { SReplaceChar(texname,'.',0); if (AddTexture(texname,ctex)) texnum++; else delete ctex; } } // Load all bitmap files from group hGroup.ResetSearch(); CSurface8 *ctex8; while (hGroup.AccessNextEntry(C4CFN_BitmapFiles,&binlen,texname)) { // check if it already exists in the map SReplaceChar(texname,'.',0); if (GetTexture(texname)) continue; SAppend(".bmp", texname); if (ctex8=GroupReadSurface8(hGroup)) { ctex8->AllowColor(0,2,TRUE); SReplaceChar(texname,'.',0); if (AddTexture(texname,ctex8)) texnum++; else delete ctex; } } #endif return texnum; }
void C4Application::QuitGame() { // reinit desired? Do restart if (UseStartupDialog || NextMission) { // backup last start params bool fWasNetworkActive = Game.NetworkActive; // stop game Game.Clear(); Game.Default(); AppState = C4AS_PreInit; // if a next mission is desired, set to start it if (NextMission) { SCopy(NextMission.getData(), Game.ScenarioFilename, _MAX_PATH); SReplaceChar( Game.ScenarioFilename, '\\', DirSep[0]); // linux/mac: make sure we are using forward slashes #ifdef NETWORK Game.fLobby = Game.NetworkActive = fWasNetworkActive; #endif Game.fObserve = false; Game.Record = !!Config.General.Record; NextMission.Clear(); } } else { Quit(); } }
int32_t C4TextureMap::LoadMap(C4Group &hGroup, const char *szEntryName, BOOL *pOverloadMaterials, BOOL *pOverloadTextures) { char *bpMap; char szLine[100+1]; int32_t cnt, iIndex, iTextures = 0; // Load text file into memory if (!hGroup.LoadEntry(szEntryName,&bpMap,NULL,1)) return 0; // Scan text buffer lines for (cnt=0; SCopySegment(bpMap,cnt,szLine,0x0A,100); cnt++) if ( (szLine[0]!='#') && (SCharCount('=',szLine)==1) ) { SReplaceChar(szLine,0x0D,0x00); if (Inside<int32_t>( iIndex = strtol(szLine,NULL,10), 0, C4M_MaxTexIndex-1 )) { const char *szMapping = szLine+SCharPos('=',szLine)+1; StdStrBuf Material, Texture; Material.CopyUntil(szMapping, '-'); Texture.Copy(SSearch(szMapping, "-")); if (AddEntry(iIndex, Material.getData(), Texture.getData())) iTextures++; } } else { if (SEqual2(szLine, "OverloadMaterials")) { fOverloadMaterials = TRUE; if(pOverloadMaterials) *pOverloadMaterials = TRUE; } if (SEqual2(szLine, "OverloadTextures")) { fOverloadTextures = TRUE; if(pOverloadTextures) *pOverloadTextures = TRUE; } } // Delete buffer, return entry count delete [] bpMap; fEntriesAdded=false; return iTextures; }
void C4ObjectInfoCore::Default(C4ID n_id, C4DefList *pDefs, const char *cpNames) { // Def C4Def *pDef=NULL; if (pDefs) pDef = pDefs->ID2Def(n_id); // Defaults id=n_id; Participation=1; Rank=0; Experience=0; Rounds=0; DeathCount=0; Birthday=0; TotalPlayingTime=0; SCopy("Clonk",Name,C4MaxName); SCopy("Clonk",TypeName,C4MaxName); sRankName.Copy("Clonk"); sNextRankName.Clear(); NextRankExp=0; DeathMessage[0]='\0'; *PortraitFile=0; Age=0; ExtraData.Reset(); // Type if (pDef) SCopy(pDef->GetName(),TypeName,C4MaxName); // Name if (cpNames) { // Name file reference if (SSearchNoCase(cpNames,C4CFN_Names)) SCopy(GetAName(cpNames),Name,C4MaxName); // Name list else { SCopySegment(cpNames,Random(SCharCount(0x0A,cpNames)),Name,0x0A,C4MaxName+1); SClearFrontBack(Name); SReplaceChar(Name,0x0D,0x00); } if (!Name[0]) SCopy("Clonk",Name,C4MaxName); } #ifdef C4ENGINE if (pDefs) UpdateCustomRanks(pDefs); #endif // Physical Physical.Default(); if (pDef) Physical = pDef->Physical; Physical.PromotionUpdate(Rank); // Old format }
C4MenuItem::C4MenuItem(C4Menu *pMenu, int32_t iIndex, const char *szCaption, const char *szCommand, int32_t iCount, C4Object *pObject, const char *szInfoCaption, C4ID idID, const char *szCommand2, bool fOwnValue, int32_t iValue, int32_t iStyle, bool fIsSelectable) : C4GUI::Element(), Count(iCount), id(idID), Object(pObject), pSymbolObj(NULL), pSymbolGraphics(NULL), dwSymbolClr(0u), fOwnValue(fOwnValue), iValue(iValue), fSelected(false), iStyle(iStyle), pMenu(pMenu), iIndex(iIndex), IsSelectable(fIsSelectable), TextDisplayProgress(-1) { *Caption=*Command=*Command2=*InfoCaption=0; Symbol.Default(); SCopy(szCaption,Caption,C4MaxTitle); SCopy(szCommand,Command,_MAX_FNAME+30); SCopy(szCommand2,Command2,_MAX_FNAME+30); SCopy(szInfoCaption,InfoCaption,C4MaxTitle); // some info caption corrections SReplaceChar(InfoCaption, 10, ' '); SReplaceChar(InfoCaption, 13, '|'); SetToolTip(InfoCaption); }
void C4Application::SetNextMission(const char *szMissionFilename) { // set next mission if any is desired if (szMissionFilename) { NextMission.Copy(szMissionFilename); // scenarios tend to use the wrong slash SReplaceChar(NextMission.getMData(), AltDirectorySeparator, DirectorySeparator); } else NextMission.Clear(); }
C4SoundInstance *C4SoundSystem::FindInstance(const char *szSndName, C4Object *pObj) { char szName[C4MaxSoundName + 4 + 1]; // Evaluate sound name (see GetEffect) SCopy(szSndName, szName, C4MaxSoundName); DefaultExtension(szName, "wav"); SReplaceChar(szName, '*', '?'); // Find an effect with a matching instance for (C4SoundEffect *csfx = FirstSound; csfx; csfx = csfx->Next) if (WildcardMatch(szName, csfx->Name)) { C4SoundInstance *pInst = csfx->GetInstance(pObj); if (pInst) return pInst; } return NULL; }
void C4ObjectInfoCore::Default(C4ID n_id, C4DefList *pDefs, const char *cpNames) { // Def C4Def *pDef=NULL; if (pDefs) pDef = pDefs->ID2Def(n_id); // Defaults id=n_id; Participation=1; Rank=0; Experience=0; Rounds=0; DeathCount=0; Birthday=0; TotalPlayingTime=0; SCopy("Clonk",Name,C4MaxName); SCopy("Clonk",TypeName,C4MaxName); sRankName.Copy("Clonk"); sNextRankName.Clear(); NextRankExp=0; DeathMessage[0]='\0'; Age=0; ExtraData.Reset(); // Type if (pDef) SCopy(pDef->GetName(),TypeName,C4MaxName); // Name if (cpNames) { SCopySegment(cpNames,Random(SCharCount(0x0A,cpNames)),Name,0x0A,C4MaxName+1); SClearFrontBack(Name); SReplaceChar(Name,0x0D,0x00); if (!Name[0]) SCopy("Clonk",Name,C4MaxName); } if (pDefs) UpdateCustomRanks(pDefs); }
BOOL C4ComponentHost::Load(const char *szName, C4GroupSet &hGroupSet, const char *szFilename, const char *szLanguage) { // Clear any old stuff Clear(); // Store name & filename SCopy(szName, Name); SCopy(szFilename, Filename); // Load component - try all segmented filenames char strEntry[_MAX_FNAME + 1], strEntryWithLanguage[_MAX_FNAME + 1]; for (int iFilename = 0; SCopySegment(Filename, iFilename, strEntry, '|', _MAX_FNAME); iFilename++) { // Try to insert all language codes provided into the filename char strCode[3] = ""; for (int iLang = 0; SCopySegment(szLanguage ? szLanguage : "", iLang, strCode, ',', 2); iLang++) { // Insert language code sprintf(strEntryWithLanguage, strEntry, strCode); if (hGroupSet.LoadEntryString(strEntryWithLanguage, Data)) { if (pConfig->General.fUTF8) Data.EnsureUnicode(); // Store actual filename C4Group *pGroup = hGroupSet.FindEntry(strEntryWithLanguage); pGroup->FindEntry(strEntryWithLanguage, Filename); CopyFilePathFromGroup(*pGroup); // Got it return TRUE; } // Couldn't insert language code anyway - no point in trying other // languages if (!SSearch(strEntry, "%s")) break; } } // Truncate any additional segments from stored filename SReplaceChar(Filename, '|', 0); // skip full path (unknown) FilePath[0] = 0; // Not loaded return FALSE; }
void C4Application::ParseCommandLine(int argc, char * argv[]) { StdStrBuf CmdLine("Command line:"); for(int i = 0; i < argc; ++i) { CmdLine.Append(" "); CmdLine.Append(argv[i]); } Log(CmdLine.getData()); ClearCommandLine(); Game.NetworkActive = false; isEditor = 2; int c; while (1) { static struct option long_options[] = { // option, w/ argument?, set directly, set to... {"editor", no_argument, &isEditor, 1}, {"fullscreen", no_argument, &isEditor, 0}, {"debugwait", no_argument, &Game.DebugWait, 1}, {"update", no_argument, &CheckForUpdates, 1}, {"noruntimejoin", no_argument, &Config.Network.NoRuntimeJoin, 1}, {"runtimejoin", no_argument, &Config.Network.NoRuntimeJoin, 0}, {"noleague", no_argument, &Config.Network.LeagueServerSignUp, 0}, {"league", no_argument, &Config.Network.LeagueServerSignUp, 1}, {"nosignup", no_argument, &Config.Network.MasterServerSignUp, 0}, {"signup", no_argument, &Config.Network.MasterServerSignUp, 1}, {"debugrecread", required_argument, 0, 'K'}, {"debugrecwrite", required_argument, 0, 'w'}, {"client", required_argument, 0, 'c'}, {"host", no_argument, 0, 'h'}, {"debughost", required_argument, 0, 'H'}, {"debugpass", required_argument, 0, 'P'}, {"debug", required_argument, 0, 'D'}, {"data", required_argument, 0, 'd'}, {"startup", required_argument, 0, 's'}, {"stream", required_argument, 0, 'e'}, {"recdump", required_argument, 0, 'R'}, {"comment", required_argument, 0, 'm'}, {"pass", required_argument, 0, 'p'}, {"udpport", required_argument, 0, 'u'}, {"tcpport", required_argument, 0, 't'}, {"join", required_argument, 0, 'j'}, {"language", required_argument, 0, 'L'}, {"scenpar", required_argument, 0, 'S'}, {"observe", no_argument, 0, 'o'}, {"nonetwork", no_argument, 0, 'N'}, {"network", no_argument, 0, 'n'}, {"record", no_argument, 0, 'r'}, {"lobby", required_argument, 0, 'l'}, {"debug-opengl", no_argument, &Config.Graphics.DebugOpenGL, 1}, {0, 0, 0, 0} }; int option_index = 0; c = getopt_long (argc, argv, "abc:d:f:", long_options, &option_index); // no more options if (c == -1) break; switch (c) { case 0: // Signup if (SEqualNoCase(long_options[option_index].name, "signup")) { Game.NetworkActive = true; } // League if (SEqualNoCase(long_options[option_index].name, "league")) { Game.NetworkActive = true; Config.Network.MasterServerSignUp = true; } break; // Lobby case 'l': Game.fLobby = true; // lobby timeout specified? (e.g. --lobby=120) if (optarg) { Game.iLobbyTimeout = atoi(optarg); if (Game.iLobbyTimeout < 0) Game.iLobbyTimeout = 0; } break; case 'o': Game.fObserve = true; break; // Direct join case 'j': Game.NetworkActive = true; SCopy(optarg, Game.DirectJoinAddress, _MAX_PATH); break; case 'K': if (optarg && optarg[0]) { LogF("Reading from DebugRec file '%s'", optarg); SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH); } else Log("Reading DebugRec from CtrlRec file in scenario record"); Config.General.DebugRec = 1; Config.General.DebugRecWrite = 0; break; case 'w': if (optarg && optarg[0]) { LogF("Writing to DebugRec file '%s'", optarg); SCopy(optarg, Config.General.DebugRecExternalFile, _MAX_PATH); } else Log("Writing DebugRec to CtrlRec file in scenario record"); Config.General.DebugRec = 1; Config.General.DebugRecWrite = 1; break; case 'r': Game.Record = true; break; case 'n': Game.NetworkActive = true; break; case 'N': Game.NetworkActive = false; break; // Language override by parameter case 'L': SCopy(optarg, Config.General.LanguageEx, CFG_MaxString); // port overrides case 't': Config.Network.PortTCP = atoi(optarg); break; case 'u': Config.Network.PortUDP = atoi(optarg); break; // network game password case 'p': Network.SetPassword(optarg); break; // network game comment case 'm': Config.Network.Comment.CopyValidated(optarg); break; // record dump case 'R': Game.RecordDumpFile.Copy(optarg); break; // record stream case 'e': Game.RecordStream.Copy(optarg); break; // startup start screen case 's': C4Startup::SetStartScreen(optarg); break; // additional read-only data path case 'd': Reloc.AddPath(optarg); break; // debug options case 'D': Game.DebugPort = atoi(optarg); break; case 'P': Game.DebugPassword = optarg; break; case 'H': Game.DebugHost = optarg; break; // set custom scenario parameter by command line case 'S': { StdStrBuf sopt, soptval; sopt.Copy(optarg); int32_t val=1; if (sopt.SplitAtChar('=', &soptval)) val=atoi(soptval.getData()); Game.StartupScenarioParameters.SetValue(sopt.getData(), val, false); } break; // debug configs case 'h': Game.NetworkActive = true; Game.fLobby = true; Config.Network.PortTCP = 11112; Config.Network.PortUDP = 11113; Config.Network.MasterServerSignUp = Config.Network.LeagueServerSignUp = false; break; case 'c': Game.NetworkActive = true; SCopy("localhost", Game.DirectJoinAddress, _MAX_PATH); Game.fLobby = true; Config.Network.PortTCP = 11112 + 2*(atoi(optarg)+1); Config.Network.PortUDP = 11113 + 2*(atoi(optarg)+1); break; case '?': /* getopt_long already printed an error message. */ break; default: assert(!"unexpected getopt_long return value"); } } if (!Config.Network.MasterServerSignUp) Config.Network.LeagueServerSignUp = false; if (Game.fObserve || Game.fLobby) Game.NetworkActive = true; while (optind < argc) { char * szParameter = argv[optind++]; { // Strip trailing / that result from tab-completing unpacked c4groups int iLen = SLen(szParameter); if (iLen > 5 && szParameter[iLen-1] == '/' && szParameter[iLen-5] == '.' && szParameter[iLen-4] == 'o' && szParameter[iLen-3] == 'c') { szParameter[iLen-1] = '\0'; } } // Scenario file if (SEqualNoCase(GetExtension(szParameter),"ocs")) { if(IsGlobalPath(szParameter)) Game.SetScenarioFilename(szParameter); else Game.SetScenarioFilename((std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str()); continue; } if (SEqualNoCase(GetFilename(szParameter),"scenario.txt")) { Game.SetScenarioFilename(szParameter); continue; } // Player file if (SEqualNoCase(GetExtension(szParameter),"ocp")) { if(IsGlobalPath(szParameter)) SAddModule(Game.PlayerFilenames, szParameter); else SAddModule(Game.PlayerFilenames, (std::string(GetWorkingDirectory()) + DirSep + szParameter).c_str()); continue; } // Definition file if (SEqualNoCase(GetExtension(szParameter),"ocd")) { SAddModule(Game.DefinitionFilenames,szParameter); continue; } // Key file if (SEqualNoCase(GetExtension(szParameter),"c4k")) { Application.IncomingKeyfile.Copy(szParameter); continue; } // Update file if (SEqualNoCase(GetExtension(szParameter),"ocu")) { Application.IncomingUpdate.Copy(szParameter); continue; } // record stream if (SEqualNoCase(GetExtension(szParameter),"c4r")) { Game.RecordStream.Copy(szParameter); } // Direct join by URL if (SEqual2NoCase(szParameter, "clonk:")) { // Store address SCopy(szParameter + 6, Game.DirectJoinAddress, _MAX_PATH); SClearFrontBack(Game.DirectJoinAddress, '/'); // Special case: if the target address is "update" then this is used for update initiation by url if (SEqualNoCase(Game.DirectJoinAddress, "update")) { Application.CheckForUpdates = true; Game.DirectJoinAddress[0] = 0; continue; } // Self-enable network Game.NetworkActive = true; continue; } } #ifdef _WIN32 // Clean up some forward/backward slach confusion since many internal OC file functions cannot handle both SReplaceChar(Game.ScenarioFilename, AltDirectorySeparator, DirectorySeparator); SReplaceChar(Game.PlayerFilenames, AltDirectorySeparator, DirectorySeparator); SReplaceChar(Game.DefinitionFilenames, AltDirectorySeparator, DirectorySeparator); Application.IncomingKeyfile.ReplaceChar(AltDirectorySeparator, DirectorySeparator); Application.IncomingUpdate.ReplaceChar(AltDirectorySeparator, DirectorySeparator); Game.RecordStream.ReplaceChar(AltDirectorySeparator, DirectorySeparator); #endif // Default to editor if scenario given, player mode otherwise if (isEditor == 2) isEditor = !!*Game.ScenarioFilename && !Config.General.OpenScenarioInGameMode; // record? Game.Record = Game.Record || (Config.Network.LeagueServerSignUp && Game.NetworkActive); // startup dialog required? QuitAfterGame = !isEditor && Game.HasScenario(); }
BOOL C4ComponentHost::LoadAppend(const char *szName, C4Group &hGroup, const char *szFilename, const char *szLanguage) { Clear(); // Store name & filename SCopy(szName, Name); SCopy(szFilename, Filename); // Load component (segmented filename) char str1[_MAX_FNAME + 1], str2[_MAX_FNAME + 1]; int iFileCnt = 0, iFileSizeSum = 0; int cseg, clseg; for (cseg = 0; SCopySegment(Filename, cseg, str1, '|', _MAX_FNAME); cseg++) { char szLang[3] = ""; for (clseg = 0; SCopySegment(szLanguage ? szLanguage : "", clseg, szLang, ',', 2); clseg++) { sprintf(str2, str1, szLang); // Check existance size_t iFileSize; if (hGroup.FindEntry(str2, NULL, &iFileSize)) { iFileCnt++; iFileSizeSum += 1 + iFileSize; break; } if (!SSearch(str1, "%s")) break; } } // No matching files found? if (!iFileCnt) return FALSE; // Allocate memory Data.SetLength(iFileSizeSum); // Search files to read contents char *pPos = Data.getMData(); *pPos = 0; for (cseg = 0; SCopySegment(Filename, cseg, str1, '|', _MAX_FNAME); cseg++) { char szLang[3] = ""; for (clseg = 0; SCopySegment(szLanguage ? szLanguage : "", clseg, szLang, ',', 2); clseg++) { sprintf(str2, str1, szLang); // Load data char *pTemp; if (hGroup.LoadEntry(str2, &pTemp, NULL, 1)) { *pPos++ = '\n'; SCopy(pTemp, pPos, Data.getPtr(Data.getLength()) - pPos); pPos += SLen(pPos); delete[] pTemp; break; } delete[] pTemp; if (!SSearch(str1, "%s")) break; } } SReplaceChar(Filename, '|', 0); CopyFilePathFromGroup(hGroup); return !!iFileCnt; }
bool C4Sky::Init(bool fSavegame) { int32_t skylistn; // reset scrolling pos+speed // not in savegame, because it will have been loaded from game data there if (!fSavegame) { x=y=xdir=ydir=0; ParX=ParY=10; ParallaxMode=0; } // Check for sky bitmap in scenario file Surface = new C4Surface(); bool loaded = !!Surface->LoadAny(Game.ScenarioFile,C4CFN_Sky,true,true, C4SF_Tileable | C4SF_MipMap); // Else, evaluate scenario core landscape sky default list if (!loaded) { // Scan list sections SReplaceChar(Game.C4S.Landscape.SkyDef,',',';'); // modifying the C4S here...! skylistn=SCharCount(';',Game.C4S.Landscape.SkyDef)+1; char str[402]; SCopySegment(Game.C4S.Landscape.SkyDef,SeededRandom(Game.RandomSeed,skylistn),str,';'); SClearFrontBack(str); // Sky tile specified, try load if (*str && !SEqual(str,"Default")) { // Check for sky tile in scenario file loaded = !!Surface->LoadAny(Game.ScenarioFile,str,true,true, C4SF_Tileable | C4SF_MipMap); if (!loaded) { loaded = !!Surface->LoadAny(::GraphicsResource.Files, str, true, false, C4SF_Tileable | C4SF_MipMap); } } } if (loaded) { // surface loaded, store first color index FadeClr1=FadeClr2=0xffffffff; // set parallax scroll mode switch (Game.C4S.Landscape.SkyScrollMode) { case 0: // default: no scrolling break; case 1: // go with the wind in xdir, and do some parallax scrolling in ydir ParallaxMode=C4SkyPM_Wind; ParY=20; break; case 2: // parallax in both directions ParX=ParY=20; break; } } // Else, try creating default Surface if (!loaded) { SetFadePalette(Game.C4S.Landscape.SkyDefFade); delete Surface; Surface = 0; } // Load sky shaders: regular sprite shaders with OC_SKY define const char* const SkyDefines[] = { "OC_SKY", NULL }; if (!pDraw->PrepareSpriteShader(Shader, "Sky", Surface ? C4SSC_BASE : 0, &::GraphicsResource.Files, SkyDefines, NULL)) return false; if (!pDraw->PrepareSpriteShader(ShaderLight, "SkyLight", (Surface ? C4SSC_BASE : 0) | C4SSC_LIGHT, &::GraphicsResource.Files, SkyDefines, NULL)) return false; // no sky - using fade in newgfx if (!Surface) return true; // Store size if (Surface) { int iWdt,iHgt; if (Surface->GetSurfaceSize(iWdt, iHgt)) { Width = iWdt; Height = iHgt; } } // Success return true; }