diff --git a/src/C4Game.cpp b/src/C4Game.cpp index 905f44989..f1d6bb8ba 100644 --- a/src/C4Game.cpp +++ b/src/C4Game.cpp @@ -260,7 +260,7 @@ bool C4Game::OpenScenario() SetInitProgress(4); auto mainSection = std::make_unique(); - if (!mainSection->InitSection(ScenarioFile)) + if (!mainSection->InitFromTemplate(ScenarioFile)) { LogFatal(LoadResStr("IDS_ERR_SECTION")); return false; } @@ -2511,14 +2511,40 @@ std::int32_t C4Game::CreateSection(const char *const name) { auto section = std::make_unique(name); - if (section->InitSection(ScenarioFile)) + if (section->InitFromTemplate(ScenarioFile)) + { + const auto size = static_cast(Sections.size()); + Sections.emplace_back(std::move(section)); + + if (Sections.back()->InitMaterialTexture() + && Sections.back()->InitSecondPart() + && Sections.back()->InitThirdPart() + ) + { + return size; + } + else + { + Sections.pop_back(); + } + } + + return -1; +} + +std::int32_t C4Game::CreateEmptySection(const char *const name, const C4SLandscape &landscape) +{ + auto section = std::make_unique(name); + + if (section->InitFromEmptyLandscape(ScenarioFile, landscape)) { const auto size = static_cast(Sections.size()); Sections.emplace_back(std::move(section)); if (Sections.back()->InitMaterialTexture() && Sections.back()->InitSecondPart() - && Sections.back()->InitThirdPart()) + && Sections.back()->InitThirdPart() + ) { return size; } diff --git a/src/C4Game.h b/src/C4Game.h index b590ae747..0e33a70e8 100644 --- a/src/C4Game.h +++ b/src/C4Game.h @@ -313,6 +313,7 @@ class C4Game bool InitKeyboard(); // register main keyboard input functions std::int32_t CreateSection(const char *name); + std::int32_t CreateEmptySection(const char *name, const C4SLandscape &landscape); protected: bool InitSystem(); diff --git a/src/C4Landscape.cpp b/src/C4Landscape.cpp index 3a17f2443..642ca11df 100644 --- a/src/C4Landscape.cpp +++ b/src/C4Landscape.cpp @@ -595,7 +595,7 @@ bool C4Landscape::PostInitMap() return true; } -bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bool &rfLoaded, bool fSavegame) +void C4Landscape::PrepareInit(const bool overloadCurrent) { // set map seed, if not pre-assigned if (!MapSeed) MapSeed = Random(3133700); @@ -606,6 +606,150 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo Section.C4S.Landscape.MapWdt.Max = 10000; Section.C4S.Landscape.MapHgt.Max = 10000; + // map is like it's loaded for regular gamestart + // but it's changed and would have to be saved if a new section is loaded + fMapChanged = overloadCurrent; +} + +bool C4Landscape::FinalizeInit(bool &landscapeLoaded, C4Group *const groupForDiff) +{ + // Make pixel maps + UpdatePixMaps(); + + // progress + Game.SetInitProgress(80); + + // mark as new-style + Section.C4S.Landscape.NewStyleLandscape = 2; + + // copy noscan-var + NoScan = Section.C4S.Landscape.NoScan; + + // Scan settings + ScanSpeed = BoundBy(Width / 500, 2, 15); + + // create it + if (!Section.C4S.Landscape.ExactLandscape) + { + // map to big surface and sectionize it + // Create landscape surface + Surface32 = new C4Surface(); + Surface8 = new CSurface8(); + if (Config.Graphics.ColorAnimation && Config.Graphics.Shader) + AnimationSurface = new C4Surface(Width, Height); + if (!Surface32->Create(Width, Height, true) + || !Surface8->Create(Width, Height, true) + || (AnimationSurface && !AnimationSurface->Create(Width, Height)) + || !Mat2Pal()) + { + delete Surface8; delete Surface32; delete AnimationSurface; + Surface8 = nullptr; Surface32 = nullptr; AnimationSurface = nullptr; + return false; + } + + // Map to landscape + if (!MapToLandscape()) return false; + } + Game.SetInitProgress(87); + +#ifdef DEBUGREC + AddDbgRec(RCT_Block, "|---LS---|", 11); + AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch * Surface8->Hgt); +#endif + + // Create pixel count array + // We will use 15x17 blocks so the pixel count can't get over 255. + int32_t PixCntWidth = (Width + 16) / 17; + PixCntPitch = (Height + 14) / 15; + PixCnt = new uint8_t[PixCntWidth * PixCntPitch]; + UpdatePixCnt(C4Rect(0, 0, Width, Height)); + ClearMatCount(); + UpdateMatCnt(C4Rect(0, 0, Width, Height), true); + + // Save initial landscape + if (!SaveInitial()) + return false; + + if (groupForDiff) + { + // Load diff, if existent + ApplyDiff(*groupForDiff); + } + + // enforce first color to be transparent + Surface8->EnforceC0Transparency(); + + // after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating + // and not creating the map + Game.FixRandom(Game.Parameters.RandomSeed); + + // Success + landscapeLoaded = true; + return true; +} + +bool C4Landscape::AssignMap(CSurface8 *const map, const bool overloadCurrent, const bool loadSky, const bool savegame) +{ + // Store map size and calculate map zoom + int iWdt, iHgt; + map->GetSurfaceSize(iWdt, iHgt); + MapWidth = iWdt; MapHeight = iHgt; + MapZoom = Section.C4S.Landscape.MapZoom.Evaluate(); + + // Calculate landscape size + Width = MapZoom * MapWidth; + Height = MapZoom * MapHeight; + Width = std::max(Width, 100); + Height = std::max(Height, 100); + + // if overloading, clear current landscape (and sections, etc.) + // must clear, of course, before new sky is eventually read + if (overloadCurrent) + { + Clear(!Section.C4S.Landscape.KeepMapCreator, loadSky); + } + + // assign new map + Map = map; + + // Sky (might need to know landscape height) + if (loadSky) + { + Game.SetInitProgress(70); + if (!Sky.Init(savegame)) + { + return false; + } + } + + return true; +} + +bool C4Landscape::InitEmpty(const bool loadSky, bool &landscapeLoaded) +{ + assert(!Section.C4S.Landscape.ExactLandscape); + PrepareInit(false); + + Game.FixRandom(Game.Parameters.RandomSeed); + + std::int32_t width{0}; + std::int32_t height{0}; + + // Create map surface + Section.C4S.Landscape.GetMapSize(width, height, Game.Parameters.StartupPlayerCount); + auto map = std::make_unique(width, height); + if (!AssignMap(map.release(), false, loadSky, false)) + { + return false; + } + + return FinalizeInit(landscapeLoaded, nullptr); +} + +bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bool &rfLoaded, bool fSavegame) +{ + PrepareInit(fOverloadCurrent); + // map and landscape must be initialized with fixed random, so runtime joining clients may recreate it // with same seed // after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating @@ -615,10 +759,6 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo Game.FixRandom(Game.Parameters.RandomSeed); - // map is like it's loaded for regular gamestart - // but it's changed and would have to be saved if a new section is loaded - fMapChanged = fOverloadCurrent; - // don't change landscape mode in runtime joins bool fLandscapeModeSet = (Mode != C4LSC_Undefined); @@ -665,30 +805,9 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo AddDbgRec(RCT_Map, sfcMap->Bits, sfcMap->Pitch * sfcMap->Hgt); #endif - // Store map size and calculate map zoom - int iWdt, iHgt; - sfcMap->GetSurfaceSize(iWdt, iHgt); - MapWidth = iWdt; MapHeight = iHgt; - MapZoom = Section.C4S.Landscape.MapZoom.Evaluate(); - - // Calculate landscape size - Width = MapZoom * MapWidth; - Height = MapZoom * MapHeight; - Width = std::max(Width, 100); - Height = std::max(Height, 100); - - // if overloading, clear current landscape (and sections, etc.) - // must clear, of course, before new sky is eventually read - if (fOverloadCurrent) Clear(!Section.C4S.Landscape.KeepMapCreator, fLoadSky); - - // assign new map - Map = sfcMap; - - // Sky (might need to know landscape height) - if (fLoadSky) + if (!AssignMap(sfcMap, fOverloadCurrent, fLoadSky, fSavegame)) { - Game.SetInitProgress(70); - if (!Sky.Init(fSavegame)) return false; + return false; } } @@ -704,76 +823,7 @@ bool C4Landscape::Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bo if (!Load(hGroup, fLoadSky, fSavegame)) return false; } - // Make pixel maps - UpdatePixMaps(); - - // progress - Game.SetInitProgress(80); - - // mark as new-style - Section.C4S.Landscape.NewStyleLandscape = 2; - - // copy noscan-var - NoScan = Section.C4S.Landscape.NoScan; - - // Scan settings - ScanSpeed = BoundBy(Width / 500, 2, 15); - - // create it - if (!Section.C4S.Landscape.ExactLandscape) - { - // map to big surface and sectionize it - // Create landscape surface - Surface32 = new C4Surface(); - Surface8 = new CSurface8(); - if (Config.Graphics.ColorAnimation && Config.Graphics.Shader) - AnimationSurface = new C4Surface(Width, Height); - if (!Surface32->Create(Width, Height, true) - || !Surface8->Create(Width, Height, true) - || (AnimationSurface && !AnimationSurface->Create(Width, Height)) - || !Mat2Pal()) - { - delete Surface8; delete Surface32; delete AnimationSurface; - Surface8 = nullptr; Surface32 = nullptr; AnimationSurface = nullptr; - return false; - } - - // Map to landscape - if (!MapToLandscape()) return false; - } - Game.SetInitProgress(87); - -#ifdef DEBUGREC - AddDbgRec(RCT_Block, "|---LS---|", 11); - AddDbgRec(RCT_Ls, Surface8->Bits, Surface8->Pitch * Surface8->Hgt); -#endif - - // Create pixel count array - // We will use 15x17 blocks so the pixel count can't get over 255. - int32_t PixCntWidth = (Width + 16) / 17; - PixCntPitch = (Height + 14) / 15; - PixCnt = new uint8_t[PixCntWidth * PixCntPitch]; - UpdatePixCnt(C4Rect(0, 0, Width, Height)); - ClearMatCount(); - UpdateMatCnt(C4Rect(0, 0, Width, Height), true); - - // Save initial landscape - if (!SaveInitial()) - return false; - - // Load diff, if existent - ApplyDiff(hGroup); - - // enforce first color to be transparent - Surface8->EnforceC0Transparency(); - - // after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating - // and not creating the map - Game.FixRandom(Game.Parameters.RandomSeed); - - // Success - rfLoaded = true; - return true; + return FinalizeInit(rfLoaded, &hGroup); } bool C4Landscape::SetPix(int32_t x, int32_t y, uint8_t npix) diff --git a/src/C4Landscape.h b/src/C4Landscape.h index 36c08e03f..224e36d6e 100644 --- a/src/C4Landscape.h +++ b/src/C4Landscape.h @@ -138,6 +138,7 @@ class C4Landscape bool SaveInitial(); bool SaveTextures(C4Group &hGroup); bool Init(C4Group &hGroup, bool fOverloadCurrent, bool fLoadSky, bool &rfLoaded, bool fSavegame); + bool InitEmpty(bool loadSky, bool &landscapeLoaded); bool MapToLandscape(); bool ApplyDiff(C4Group &hGroup); bool SetMode(int32_t iMode); @@ -291,8 +292,12 @@ class C4Landscape bool MapToLandscape(CSurface8 *sfcMap, int32_t iMapX, int32_t iMapY, int32_t iMapWdt, int32_t iMapHgt, int32_t iOffsX = 0, int32_t iOffsY = 0); // zoom map segment to surface (or sector surfaces) bool GetMapColorIndex(const char *szMaterial, const char *szTexture, bool fIFT, uint8_t &rbyCol); bool SkyToLandscape(int32_t iToX, int32_t iToY, int32_t iToWdt, int32_t iToHgt, int32_t iOffX, int32_t iOffY); + void PrepareInit(bool overloadCurrent); + bool AssignMap(CSurface8 *map, bool overloadCurrent, bool loadSky, bool savegame); + bool FinalizeInit(bool &landscapeLoaded, C4Group *groupForDiff); CSurface8 *CreateMap(); // create map by landscape attributes CSurface8 *CreateMapS2(C4Group &ScenFile); // create map by def file + CSurface8 *CreateEmptyMap(std::int32_t width, std::int32_t height); bool Relight(C4Rect To); bool ApplyLighting(C4Rect To); bool UpdateAnimationSurface(C4Rect To); diff --git a/src/C4Script.cpp b/src/C4Script.cpp index 3243b87f4..31d756664 100644 --- a/src/C4Script.cpp +++ b/src/C4Script.cpp @@ -6120,14 +6120,125 @@ static void FnSetRestoreInfos(C4AulContext *ctx, C4ValueInt what) Game.RestartRestoreInfos.What = static_cast>(what); } -static C4ValueInt FnCreateSection(C4AulContext *ctx, C4String *name) +#if 0 +class C4ValueHashCompilerRead : public StdCompiler { - if (const char *const par{FnStringPar(name)}; par) +public: + typedef C4ValueHash InT; + void setInput(C4ValueHash *in) { map = in; } + + bool isCompiler() override { return true; } + bool hasNaming() override { return true; } + + NameGuard Name(const char *name) override; + void NameEnd(bool fBreak = false) override; + bool FollowName(const char *szName) override; + + void QWord(std::int64_t &rInt) override; + void QWord(std::uint64_t &rInt) override; + void DWord(std::int32_t &rInt) override; + void DWord(std::uint32_t &rInt) override; + void Word(std::int16_t &rShort) override; + void Word(std::uint16_t &rShort) override; + void Byte(std::int8_t &rByte) override; + void Boolean(bool &rBool) override; + virtual void String(char *string, std::size_t maxLength, RawCompileType type = RCT_Escaped) override; + virtual void String(std::string &str, RawCompileType type = RCT_Escaped) override; + virtual void Raw(void *data, std::size_t size, RawCompileType type = RCT_Escaped) override { - return Game.CreateSection(par); + excCorrupt("Raw not supported"); } - return -1; + +private: + C4ValueHash *map; +}; +#endif + +static C4ValueInt FnCreateSection(C4AulContext *ctx, C4Value data) +{ + if (C4String *const name{data.getStr()}; name) + { + return Game.CreateSection(name->Data.getData()); + } + else if (!data.ConvertTo(C4V_Map)) + { + throw C4AulExecError{ctx->Obj, "CreateSection(): section name or section initialization map expected"}; + } + + C4ValueHash &map{*data._getMap()}; + + C4SLandscape landscape; + landscape.Default(); + + C4String *const name{map[C4VString("Name")].getStr()}; + if (!name) + { + throw C4AulExecError{ctx->Obj, "CreateSection(): section name in initialization map expected"}; + } + + C4Value value{map[C4VString("Landscape")]}; + if (value.ConvertTo(C4V_Map)) + { + C4ValueHash &landscapeParams{*value._getMap()}; + + const auto assign = [&landscapeParams](T &field, const char *const key) + { + C4Value value{landscapeParams[C4VString(key)]}; + if (value.GetType() != C4V_Any && value.ConvertTo(C4ValueConv::Type())) + { + field = value.Get(); + } + }; + + assign(landscape.BottomOpen, "BottomOpen"); + assign(landscape.TopOpen, "TopOpen"); + assign(landscape.LeftOpen, "LeftOpen"); + assign(landscape.RightOpen, "RightOpen"); + assign(landscape.AutoScanSideOpen, "AutoScanSideOpen"); + + if (C4String *const skyDef{landscapeParams[C4VString("SkyDef")].getStr()}; skyDef) + { + const StdStrBuf &data{skyDef->Data}; + landscape.SkyDef[std::string_view{data.getData(), data.getLength()}.copy(landscape.SkyDef, std::size(landscape.SkyDef) - 1)] = '\0'; + } + + if (C4ValueArray *const skyDefFade{landscapeParams[C4VString("SkyDefFade")].getArray()}; skyDefFade) + { + for (std::size_t i{0}; i < std::size(landscape.SkyDefFade); ++i) + { + landscape.SkyDefFade[i] = skyDefFade->GetItem(static_cast(i)).getInt(); + } + } + + assign(landscape.NoSky, "NoSky"); + + const auto assignArrayToC4S = [&landscapeParams](C4SVal &field, const char *const key) + { + if (C4ValueArray *const array{landscapeParams[C4VString(key)].getArray()}; array) + { + field = { + array->GetItem(0).getInt(), + array->GetItem(1).getInt(), + array->GetItem(2).getInt(), + array->GetItem(3).getInt() + }; + } + }; + + assignArrayToC4S(landscape.Gravity, "Gravity"); + assignArrayToC4S(landscape.MapWdt, "MapWdt"); + assignArrayToC4S(landscape.MapHgt, "MapHgt"); + assignArrayToC4S(landscape.MapZoom, "MapZoom"); + assign(landscape.KeepMapCreator, "KeepMapCreator"); + assign(landscape.SkyScrollMode, "SkyScrollMode"); + landscape.NewStyleLandscape = 2; + landscape.FoWRes = CClrModAddMap::iDefResolutionX; + assign(landscape.FoWRes, "FoWRes"); + assign(landscape.ShadeMaterials, "ShadeMaterials"); + } + + return Game.CreateEmptySection(FnStringPar(name), landscape); } static C4ValueInt FnGetSectionCount(C4AulContext *ctx) diff --git a/src/C4Section.cpp b/src/C4Section.cpp index dcedf72e6..6d1115353 100644 --- a/src/C4Section.cpp +++ b/src/C4Section.cpp @@ -38,7 +38,7 @@ C4Section::C4Section() noexcept Default(); } -C4Section::C4Section(const char *const name) +C4Section::C4Section(const std::string_view name) : C4Section{} { this->name = name; @@ -66,7 +66,6 @@ void C4Section::Clear() Weather.Clear(); Landscape.Clear(); DeleteObjects(true); - Landscape.Clear(); PXS.Clear(); Material.Clear(); TextureMap.Clear(); // texture map *MUST* be cleared after the materials, because of the patterns! @@ -76,7 +75,7 @@ void C4Section::Clear() GlobalEffects = nullptr; } -bool C4Section::InitSection(C4Group &scenario) +bool C4Section::InitFromTemplate(C4Group &scenario) { C4S = Game.C4S; @@ -106,17 +105,160 @@ bool C4Section::InitSection(C4Group &scenario) return true; } +bool C4Section::InitFromEmptyLandscape(C4Group &scenario, const C4SLandscape &landscape) +{ + if (!Group.Open(scenario.GetFullName().getData())) + { + LogFatal("GROUP"); + return false; + } + + C4S = Game.C4S; + C4S.Head = Game.C4S.Head; + C4S.Definitions = Game.C4S.Definitions; + C4S.Game = Game.C4S.Game; + std::ranges::copy(Game.C4S.PlrStart, C4S.PlrStart); + C4S.Landscape = landscape; + C4S.Animals = Game.C4S.Animals; + C4S.Weather = Game.C4S.Weather; + C4S.Disasters = Game.C4S.Disasters; + C4S.Environment = Game.C4S.Environment; + + emptyLandscape = true; + return true; +} + +bool C4Section::InitMaterialTexture() +{ + // Clear old data + TextureMap.Clear(); + Material.Clear(); + + // Check for scenario local materials + bool haveSectionMaterials{Group.FindEntry(C4CFN_Material)}; + bool haveScenarioFileMaterials{!name.empty() && Game.ScenarioFile.FindEntry(C4CFN_Material)}; + + // Load all materials + auto matRes = Game.Parameters.GameRes.iterRes(NRT_Material); + bool fFirst = true, fOverloadMaterials = true, fOverloadTextures = true; + long tex_count = 0, mat_count = 0; + while (fOverloadMaterials || fOverloadTextures) + { + // Are there any scenario local materials that need to be looked at firs? + C4Group Mats; + if (haveSectionMaterials) + { + if (!Mats.OpenAsChild(&Group, C4CFN_Material)) + { + LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData()); + return false; + } + // Once only + haveSectionMaterials = false; + } + else if (haveScenarioFileMaterials) + { + if (!Mats.OpenAsChild(&Game.ScenarioFile, C4CFN_Material)) + { + LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData()); + return false; + } + + haveScenarioFileMaterials = false; + } + else + { + if (matRes == matRes.end()) break; + // Find next external material source + if (!Mats.Open(matRes->getFile())) + { + LogFatal(FormatString(LoadResStr("IDS_ERR_EXTERNALMATERIALS"), matRes->getFile(), Mats.GetError()).getData()); + return false; + } + ++matRes; + } + + // First material file? Load texture map. + bool fNewOverloadMaterials = false, fNewOverloadTextures = false; + if (fFirst) + { + long tme_count = TextureMap.LoadMap(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures); + LogF(LoadResStr("IDS_PRC_TEXMAPENTRIES"), tme_count); + // Only once + fFirst = false; + } + else + { + // Check overload-flags only + if (!C4TextureMap::LoadFlags(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures)) + fOverloadMaterials = fOverloadTextures = false; + } + + // Load textures + if (fOverloadTextures) + { + int iTexs = TextureMap.LoadTextures(Mats); + // Automatically continue search if no texture was found + if (!iTexs) fNewOverloadTextures = true; + tex_count += iTexs; + } + + // Load materials + if (fOverloadMaterials) + { + int iMats = Material.Load(Mats); + // Automatically continue search if no material was found + if (!iMats) fNewOverloadMaterials = true; + mat_count += iMats; + } + + // Set flags + fOverloadTextures = fNewOverloadTextures; + fOverloadMaterials = fNewOverloadMaterials; + } + + // Logs + LogF(LoadResStr("IDS_PRC_TEXTURES"), tex_count); + LogF(LoadResStr("IDS_PRC_MATERIALS"), mat_count); + + // Load material enumeration + if (!Material.LoadEnumeration(Group)) + { + LogFatal(LoadResStr("IDS_PRC_NOMATENUM")); return false; + } + + // Initialize texture map + TextureMap.Init(); + + // Cross map mats (after texture init, because Material-Texture-combinations are used) + Material.CrossMapMaterials(); + + // Check material number + if (Material.Num > C4MaxMaterial) + { + LogFatal(LoadResStr("IDS_PRC_TOOMANYMATS")); return false; + } + + // Enumerate materials + if (!Landscape.EnumerateMaterials()) return false; + + // get material script funcs + Material.UpdateScriptPointers(); + + return true; +} + bool C4Section::InitSecondPart() { LandscapeLoaded = false; - if (!Landscape.Init(Group, false, true, LandscapeLoaded, C4S.Head.SaveGame)) + if (!(emptyLandscape ? Landscape.InitEmpty(true, LandscapeLoaded) : Landscape.Init(Group, false, true, LandscapeLoaded, C4S.Head.SaveGame))) { LogFatal(LoadResStr("IDS_ERR_GBACK")); return false; } // the savegame flag is set if runtime data is present, in which case this is to be used - if (LandscapeLoaded && !C4S.Head.SaveGame) + if (LandscapeLoaded && (emptyLandscape || !C4S.Head.SaveGame)) { Landscape.ScenarioInit(); } @@ -241,126 +383,6 @@ bool C4Section::CheckObjectEnumeration() return true; } -bool C4Section::InitMaterialTexture() -{ - // Clear old data - TextureMap.Clear(); - Material.Clear(); - - // Check for scenario local materials - bool haveSectionMaterials{Group.FindEntry(C4CFN_Material)}; - bool haveScenarioFileMaterials{!name.empty() && Game.ScenarioFile.FindEntry(C4CFN_Material)}; - - // Load all materials - auto matRes = Game.Parameters.GameRes.iterRes(NRT_Material); - bool fFirst = true, fOverloadMaterials = true, fOverloadTextures = true; - long tex_count = 0, mat_count = 0; - while (fOverloadMaterials || fOverloadTextures) - { - // Are there any scenario local materials that need to be looked at firs? - C4Group Mats; - if (haveSectionMaterials) - { - if (!Mats.OpenAsChild(&Group, C4CFN_Material)) - { - LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData()); - return false; - } - // Once only - haveSectionMaterials = false; - } - else if (haveScenarioFileMaterials) - { - if (!Mats.OpenAsChild(&Game.ScenarioFile, C4CFN_Material)) - { - LogFatal(FormatString(LoadResStr("IDS_ERR_SCENARIOMATERIALS"), Mats.GetError()).getData()); - return false; - } - - haveScenarioFileMaterials = false; - } - else - { - if (matRes == matRes.end()) break; - // Find next external material source - if (!Mats.Open(matRes->getFile())) - { - LogFatal(FormatString(LoadResStr("IDS_ERR_EXTERNALMATERIALS"), matRes->getFile(), Mats.GetError()).getData()); - return false; - } - ++matRes; - } - - // First material file? Load texture map. - bool fNewOverloadMaterials = false, fNewOverloadTextures = false; - if (fFirst) - { - long tme_count = TextureMap.LoadMap(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures); - LogF(LoadResStr("IDS_PRC_TEXMAPENTRIES"), tme_count); - // Only once - fFirst = false; - } - else - { - // Check overload-flags only - if (!C4TextureMap::LoadFlags(Mats, C4CFN_TexMap, &fNewOverloadMaterials, &fNewOverloadTextures)) - fOverloadMaterials = fOverloadTextures = false; - } - - // Load textures - if (fOverloadTextures) - { - int iTexs = TextureMap.LoadTextures(Mats); - // Automatically continue search if no texture was found - if (!iTexs) fNewOverloadTextures = true; - tex_count += iTexs; - } - - // Load materials - if (fOverloadMaterials) - { - int iMats = Material.Load(Mats); - // Automatically continue search if no material was found - if (!iMats) fNewOverloadMaterials = true; - mat_count += iMats; - } - - // Set flags - fOverloadTextures = fNewOverloadTextures; - fOverloadMaterials = fNewOverloadMaterials; - } - - // Logs - LogF(LoadResStr("IDS_PRC_TEXTURES"), tex_count); - LogF(LoadResStr("IDS_PRC_MATERIALS"), mat_count); - - // Load material enumeration - if (!Material.LoadEnumeration(Group)) - { - LogFatal(LoadResStr("IDS_PRC_NOMATENUM")); return false; - } - - // Initialize texture map - TextureMap.Init(); - - // Cross map mats (after texture init, because Material-Texture-combinations are used) - Material.CrossMapMaterials(); - - // Check material number - if (Material.Num > C4MaxMaterial) - { - LogFatal(LoadResStr("IDS_PRC_TOOMANYMATS")); return false; - } - - // Enumerate materials - if (!Landscape.EnumerateMaterials()) return false; - - // get material script funcs - Material.UpdateScriptPointers(); - - return true; -} - static int32_t ListExpandValids(C4IDList &rlist, C4ID *idlist, int32_t maxidlist) { diff --git a/src/C4Section.h b/src/C4Section.h index f5faa2629..ebe1fa434 100644 --- a/src/C4Section.h +++ b/src/C4Section.h @@ -71,7 +71,7 @@ class C4Section public: C4Section() noexcept; - explicit C4Section(const char *name); + explicit C4Section(std::string_view name); C4Section(const C4Section &) = delete; C4Section &operator=(const C4Section &) = delete; @@ -87,13 +87,15 @@ class C4Section std::string_view GetName() const { return name; } - bool InitSection(C4Group &scenario); + bool InitFromTemplate(C4Group &scenario); + bool InitFromEmptyLandscape(C4Group &scenario, const C4SLandscape &landscape); + + bool InitMaterialTexture(); bool InitSecondPart(); bool InitThirdPart(); bool CheckObjectEnumeration(); - bool InitMaterialTexture(); private: void InitInEarth(); @@ -277,4 +279,5 @@ class C4Section private: std::string name; + bool emptyLandscape{false}; };