Skip to content

Commit

Permalink
Refactor section initialization sequence, make FnCreateSection be abl…
Browse files Browse the repository at this point in the history
…e to create a section with an empty landscape from a map providing C4SLandscape initialization data
  • Loading branch information
Fulgen301 committed Nov 17, 2023
1 parent d32011f commit ee3a6e3
Show file tree
Hide file tree
Showing 7 changed files with 451 additions and 233 deletions.
32 changes: 29 additions & 3 deletions src/C4Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ bool C4Game::OpenScenario()
SetInitProgress(4);

auto mainSection = std::make_unique<C4Section>();
if (!mainSection->InitSection(ScenarioFile))
if (!mainSection->InitFromTemplate(ScenarioFile))
{
LogFatal(LoadResStr("IDS_ERR_SECTION")); return false;
}
Expand Down Expand Up @@ -2511,14 +2511,40 @@ std::int32_t C4Game::CreateSection(const char *const name)
{
auto section = std::make_unique<C4Section>(name);

if (section->InitSection(ScenarioFile))
if (section->InitFromTemplate(ScenarioFile))
{
const auto size = static_cast<std::int32_t>(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<C4Section>(name);

if (section->InitFromEmptyLandscape(ScenarioFile, landscape))
{
const auto size = static_cast<std::int32_t>(Sections.size());
Sections.emplace_back(std::move(section));

if (Sections.back()->InitMaterialTexture()
&& Sections.back()->InitSecondPart()
&& Sections.back()->InitThirdPart())
&& Sections.back()->InitThirdPart()
)
{
return size;
}
Expand Down
1 change: 1 addition & 0 deletions src/C4Game.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
246 changes: 148 additions & 98 deletions src/C4Landscape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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<int32_t>(Width, 100);
Height = std::max<int32_t>(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<CSurface8>(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
Expand All @@ -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);

Expand Down Expand Up @@ -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<int32_t>(Width, 100);
Height = std::max<int32_t>(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;
}
}

Expand All @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/C4Landscape.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit ee3a6e3

Please sign in to comment.