forked from Mirrors/openclonk
767 lines
27 KiB
C++
767 lines
27 KiB
C++
/*
|
|
* OpenClonk, http://www.openclonk.org
|
|
*
|
|
* Copyright (c) 1998-2000, 2007 Matthes Bender
|
|
* Copyright (c) 2002, 2004-2008 Sven Eberhardt
|
|
* Copyright (c) 2004-2005 Peter Wortmann
|
|
* Copyright (c) 2006 Günther Brammer
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
*
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
* to OpenClonk.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
* See isc_license.txt for full license and disclaimer.
|
|
*
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
* See clonk_trademark_license.txt for full license.
|
|
*/
|
|
|
|
/* Core component of a scenario file */
|
|
|
|
#include <C4Include.h>
|
|
#include <C4Scenario.h>
|
|
#include <C4InputValidation.h>
|
|
|
|
#ifndef BIG_C4INCLUDE
|
|
#include <C4Random.h>
|
|
#include <C4Group.h>
|
|
#include <C4Components.h>
|
|
#include <C4Game.h>
|
|
#endif
|
|
|
|
#if defined(C4FRONTEND) || defined (C4GROUP)
|
|
#include "C4CompilerWrapper.h"
|
|
#endif
|
|
|
|
//==================================== C4SVal ==============================================
|
|
|
|
C4SVal::C4SVal(int32_t std, int32_t rnd, int32_t min, int32_t max)
|
|
: Std(std), Rnd(rnd), Min(min), Max(max)
|
|
{
|
|
}
|
|
|
|
void C4SVal::Set(int32_t std, int32_t rnd, int32_t min, int32_t max)
|
|
{
|
|
Std=std; Rnd=rnd; Min=min; Max=max;
|
|
}
|
|
|
|
int32_t C4SVal::Evaluate()
|
|
{
|
|
return BoundBy(Std+Random(2*Rnd+1)-Rnd,Min,Max);
|
|
}
|
|
|
|
void C4SVal::Default()
|
|
{
|
|
Set();
|
|
}
|
|
|
|
void C4SVal::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkDefaultAdapt(Std, 0));
|
|
if (!pComp->Seperator()) return;
|
|
pComp->Value(mkDefaultAdapt(Rnd, 0));
|
|
if (!pComp->Seperator()) return;
|
|
pComp->Value(mkDefaultAdapt(Min, 0));
|
|
if (!pComp->Seperator()) return;
|
|
pComp->Value(mkDefaultAdapt(Max, 100));
|
|
}
|
|
|
|
//================================ C4Scenario ==========================================
|
|
|
|
C4Scenario::C4Scenario()
|
|
{
|
|
Default();
|
|
}
|
|
|
|
void C4Scenario::Default()
|
|
{
|
|
int32_t cnt;
|
|
Head.Default();
|
|
Definitions.Default();
|
|
Game.Default();
|
|
for (cnt=0; cnt<C4S_MaxPlayer; cnt++) PlrStart[cnt].Default();
|
|
Landscape.Default();
|
|
Animals.Default();
|
|
Weather.Default();
|
|
Disasters.Default();
|
|
Game.Realism.Default();
|
|
Environment.Default();
|
|
}
|
|
|
|
BOOL C4Scenario::Load(C4Group &hGroup, bool fLoadSection)
|
|
{
|
|
char *pSource;
|
|
// Load
|
|
if (!hGroup.LoadEntry(C4CFN_ScenarioCore,&pSource,NULL,1)) return FALSE;
|
|
// Compile
|
|
if (!Compile(pSource, fLoadSection)) { delete [] pSource; return FALSE; }
|
|
delete [] pSource;
|
|
// Convert
|
|
Game.ConvertGoals(Game.Realism);
|
|
// Success
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL C4Scenario::Save(C4Group &hGroup, bool fSaveSection)
|
|
{
|
|
char *Buffer; int32_t BufferSize;
|
|
if (!Decompile(&Buffer,&BufferSize, fSaveSection))
|
|
return FALSE;
|
|
if (!hGroup.Add(C4CFN_ScenarioCore,Buffer,BufferSize,FALSE,TRUE))
|
|
{ StdBuf Buf; Buf.Take(Buffer, BufferSize); return FALSE; }
|
|
return TRUE;
|
|
}
|
|
|
|
void C4Scenario::CompileFunc(StdCompiler *pComp, bool fSection)
|
|
{
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(Head, fSection), "Head"));
|
|
if (!fSection) pComp->Value(mkNamingAdapt(Definitions, "Definitions"));
|
|
pComp->Value(mkNamingAdapt(mkParAdapt(Game, fSection), "Game"));
|
|
for(int32_t i = 0; i < C4S_MaxPlayer; i++)
|
|
pComp->Value(mkNamingAdapt(PlrStart[i], FormatString("Player%d", i+1).getData()));
|
|
pComp->Value(mkNamingAdapt(Landscape, "Landscape"));
|
|
pComp->Value(mkNamingAdapt(Animals, "Animals"));
|
|
pComp->Value(mkNamingAdapt(Weather, "Weather"));
|
|
pComp->Value(mkNamingAdapt(Disasters, "Disasters"));
|
|
pComp->Value(mkNamingAdapt(Environment, "Environment"));
|
|
}
|
|
|
|
int32_t C4Scenario::GetMinPlayer()
|
|
{
|
|
// MinPlayer is specified.
|
|
if (Head.MinPlayer != 0)
|
|
return Head.MinPlayer;
|
|
// Melee? Need at least two.
|
|
if (Game.IsMelee())
|
|
return 2;
|
|
// Otherwise/unknown: need at least one.
|
|
return 1;
|
|
}
|
|
|
|
void C4SDefinitions::Default()
|
|
{
|
|
LocalOnly=AllowUserChange=FALSE;
|
|
ZeroMem(Definition,sizeof (Definition));
|
|
SkipDefs.Default();
|
|
}
|
|
|
|
const int32_t C4S_MaxPlayerDefault = 12;
|
|
|
|
void C4SHead::Default()
|
|
{
|
|
Origin.Clear();
|
|
ZeroMem(this,sizeof (C4SHead));
|
|
Icon=18;
|
|
MaxPlayer=MaxPlayerLeague=C4S_MaxPlayerDefault;
|
|
MinPlayer=0; // auto-determine by mode
|
|
SCopy("Default Title",Title,C4MaxTitle);
|
|
}
|
|
|
|
void C4SHead::CompileFunc(StdCompiler *pComp, bool fSection)
|
|
{
|
|
if (!fSection)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Icon, "Icon", 18));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Title), "Title", "Default Title"));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Loader), "Loader", ""));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Font), "Font", ""));
|
|
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(C4XVer,0), "Version" ));
|
|
pComp->Value(mkNamingAdapt(Difficulty, "Difficulty", 0));
|
|
pComp->Value(mkNamingAdapt(EnableUnregisteredAccess, "Access", FALSE));
|
|
pComp->Value(mkNamingAdapt(MaxPlayer, "MaxPlayer", C4S_MaxPlayerDefault));
|
|
pComp->Value(mkNamingAdapt(MaxPlayerLeague, "MaxPlayerLeague", MaxPlayer));
|
|
pComp->Value(mkNamingAdapt(MinPlayer, "MinPlayer", 0));
|
|
pComp->Value(mkNamingAdapt(SaveGame, "SaveGame", FALSE));
|
|
pComp->Value(mkNamingAdapt(Replay, "Replay", FALSE));
|
|
pComp->Value(mkNamingAdapt(Film, "Film", FALSE));
|
|
pComp->Value(mkNamingAdapt(DisableMouse, "DisableMouse", FALSE));
|
|
pComp->Value(mkNamingAdapt(IgnoreSyncChecks, "IgnoreSyncChecks", FALSE));
|
|
pComp->Value(mkNamingAdapt(StartupPlayerCount, "StartupPlayerCount", 0));
|
|
}
|
|
pComp->Value(mkNamingAdapt(NoInitialize, "NoInitialize", FALSE));
|
|
pComp->Value(mkNamingAdapt(RandomSeed, "RandomSeed", 0));
|
|
if (!fSection)
|
|
{
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Engine), "Engine", ""));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(MissionAccess), "MissionAccess", ""));
|
|
pComp->Value(mkNamingAdapt(NetworkGame, "NetworkGame", false));
|
|
pComp->Value(mkNamingAdapt(NetworkRuntimeJoin, "NetworkRuntimeJoin", false));
|
|
pComp->Value(mkNamingAdapt(ForcedGfxMode, "ForcedGfxMode", 0));
|
|
pComp->Value(mkNamingAdapt(ForcedFairCrew, "ForcedNoCrew", 0));
|
|
pComp->Value(mkNamingAdapt(FairCrewStrength, "DefCrewStrength", 0));
|
|
pComp->Value(mkNamingAdapt(mkStrValAdapt(mkParAdapt(Origin, StdCompiler::RCT_All), C4InVal::VAL_SubPathFilename), "Origin", StdCopyStrBuf()));
|
|
// windows needs backslashes in Origin; other systems use forward slashes
|
|
if (pComp->isCompiler()) Origin.ReplaceChar(AltDirectorySeparator, DirectorySeparator);
|
|
}
|
|
}
|
|
|
|
void C4SGame::Default()
|
|
{
|
|
Elimination=C4S_EliminateCrew;
|
|
ValueGain=0;
|
|
CreateObjects.Clear();
|
|
ClearObjects.Clear();
|
|
ClearMaterial.Clear();
|
|
Mode=C4S_Cooperative;
|
|
CooperativeGoal=C4S_NoGoal;
|
|
EnableRemoveFlag=0;
|
|
Goals.Clear();
|
|
Rules.Clear();
|
|
FoWColor=0;
|
|
}
|
|
|
|
void C4SGame::CompileFunc(StdCompiler *pComp, bool fSection)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Mode, "Mode", C4S_Cooperative));
|
|
pComp->Value(mkNamingAdapt(Elimination, "Elimination", C4S_EliminateCrew));
|
|
pComp->Value(mkNamingAdapt(CooperativeGoal, "CooperativeGoal", C4S_NoGoal));
|
|
pComp->Value(mkNamingAdapt(CreateObjects, "CreateObjects", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(ClearObjects, "ClearObjects", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(ClearMaterial, "ClearMaterials", C4NameList()));
|
|
pComp->Value(mkNamingAdapt(ValueGain, "ValueGain", 0));
|
|
pComp->Value(mkNamingAdapt(EnableRemoveFlag, "EnableRemoveFlag", FALSE));
|
|
pComp->Value(mkNamingAdapt(Realism.ConstructionNeedsMaterial, "StructNeedMaterial", FALSE));
|
|
pComp->Value(mkNamingAdapt(Realism.StructuresNeedEnergy, "StructNeedEnergy", TRUE));
|
|
if (!fSection)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Realism.ValueOverloads, "ValueOverloads", C4IDList()));
|
|
}
|
|
pComp->Value(mkNamingAdapt(mkRuntimeValueAdapt(Realism.LandscapePushPull), "LandscapePushPull", FALSE));
|
|
pComp->Value(mkNamingAdapt(mkRuntimeValueAdapt(Realism.LandscapeInsertThrust), "LandscapeInsertThrust",TRUE));
|
|
|
|
const StdBitfieldEntry<int32_t> BaseFunctionalities[] = {
|
|
{ "BASEFUNC_AutoSellContents", BASEFUNC_AutoSellContents },
|
|
{ "BASEFUNC_RegenerateEnergy", BASEFUNC_RegenerateEnergy },
|
|
{ "BASEFUNC_Buy", BASEFUNC_Buy },
|
|
{ "BASEFUNC_Sell", BASEFUNC_Sell },
|
|
{ "BASEFUNC_RejectEntrance", BASEFUNC_RejectEntrance },
|
|
{ "BASEFUNC_Extinguish", BASEFUNC_Extinguish },
|
|
{ "BASEFUNC_Default", BASEFUNC_Default },
|
|
{ NULL, 0 } };
|
|
|
|
pComp->Value(mkNamingAdapt(mkRuntimeValueAdapt(mkBitfieldAdapt<int32_t>(Realism.BaseFunctionality, BaseFunctionalities)), "BaseFunctionality", BASEFUNC_Default));
|
|
pComp->Value(mkNamingAdapt(mkRuntimeValueAdapt(Realism.BaseRegenerateEnergyPrice), "BaseRegenerateEnergyPrice",BASE_RegenerateEnergyPrice));
|
|
pComp->Value(mkNamingAdapt(Goals, "Goals", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(Rules, "Rules", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(FoWColor, "FoWColor", 0u));
|
|
}
|
|
|
|
void C4SGame::ClearCooperativeGoals()
|
|
{
|
|
ValueGain=0;
|
|
CreateObjects.Clear();
|
|
ClearObjects.Clear();
|
|
ClearMaterial.Clear();
|
|
}
|
|
|
|
void C4SPlrStart::Default()
|
|
{
|
|
NativeCrew=C4ID_None;
|
|
Crew.Set(1,0,1,10);
|
|
Wealth.Set(0,0,0,250);
|
|
Position[0]=Position[1]=-1;
|
|
EnforcePosition=0;
|
|
ReadyCrew.Default();
|
|
ReadyBase.Default();
|
|
ReadyVehic.Default();
|
|
ReadyMaterial.Default();
|
|
BuildKnowledge.Default();
|
|
HomeBaseMaterial.Default();
|
|
HomeBaseProduction.Default();
|
|
Magic.Default();
|
|
}
|
|
|
|
bool C4SPlrStart::EquipmentEqual(C4SPlrStart &rhs)
|
|
{
|
|
return *this == rhs;
|
|
}
|
|
|
|
bool C4SPlrStart::operator==(const C4SPlrStart& rhs)
|
|
{
|
|
return (NativeCrew==rhs.NativeCrew)
|
|
&& (Crew == rhs.Crew)
|
|
&& (Wealth == rhs.Wealth)
|
|
&& (ReadyCrew == rhs.ReadyCrew)
|
|
&& (ReadyBase == rhs.ReadyBase)
|
|
&& (ReadyVehic == rhs.ReadyVehic)
|
|
&& (ReadyMaterial == rhs.ReadyMaterial)
|
|
&& (BuildKnowledge == rhs.BuildKnowledge)
|
|
&& (HomeBaseMaterial == rhs.HomeBaseMaterial)
|
|
&& (HomeBaseProduction == rhs.HomeBaseProduction)
|
|
&& (Magic == rhs.Magic);
|
|
}
|
|
|
|
void C4SPlrStart::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(mkC4IDAdapt(NativeCrew), "StandardCrew", C4ID_None));
|
|
pComp->Value(mkNamingAdapt(Crew, "Clonks", C4SVal(1, 0, 1, 10), true));
|
|
pComp->Value(mkNamingAdapt(Wealth, "Wealth", C4SVal(0, 0, 0,250), true));
|
|
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(Position,-1), "Position" ));
|
|
pComp->Value(mkNamingAdapt(EnforcePosition, "EnforcePosition", 0));
|
|
pComp->Value(mkNamingAdapt(ReadyCrew, "Crew", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(ReadyBase, "Buildings", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(ReadyVehic, "Vehicles", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(ReadyMaterial, "Material", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(BuildKnowledge, "Knowledge", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(HomeBaseMaterial, "HomeBaseMaterial", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(HomeBaseProduction, "HomeBaseProduction", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(Magic, "Magic", C4IDList()));
|
|
}
|
|
|
|
void C4SLandscape::Default()
|
|
{
|
|
BottomOpen=0; TopOpen=1;
|
|
LeftOpen=0; RightOpen=0;
|
|
AutoScanSideOpen=1;
|
|
SkyDef[0]=0;
|
|
NoSky=0;
|
|
for (int32_t cnt=0; cnt<6; cnt++) SkyDefFade[cnt]=0;
|
|
VegLevel.Set(50,30,0,100);
|
|
Vegetation.Default();
|
|
InEarthLevel.Set(50,0,0,100);
|
|
InEarth.Default();
|
|
MapWdt.Set(100,0,64,250);
|
|
MapHgt.Set(50,0,40,250);
|
|
MapZoom.Set(10,0,5,15);
|
|
Amplitude.Set(0,0);
|
|
Phase.Set(50);
|
|
Period.Set(15);
|
|
Random.Set(0);
|
|
LiquidLevel.Default();
|
|
MapPlayerExtend=0;
|
|
Layers.Clear();
|
|
SCopy("Earth",Material,C4M_MaxName);
|
|
SCopy("Water",Liquid,C4M_MaxName);
|
|
ExactLandscape=0;
|
|
Gravity.Set(100,0,10,200);
|
|
NoScan=0;
|
|
KeepMapCreator=0;
|
|
SkyScrollMode=0;
|
|
NewStyleLandscape=0;
|
|
FoWRes=CClrModAddMap::DefResolutionX;
|
|
}
|
|
|
|
void C4SLandscape::GetMapSize(int32_t &rWdt, int32_t &rHgt, int32_t iPlayerNum)
|
|
{
|
|
rWdt = MapWdt.Evaluate();
|
|
rHgt = MapHgt.Evaluate();
|
|
iPlayerNum = Max<int32_t>( iPlayerNum, 1 );
|
|
if (MapPlayerExtend)
|
|
rWdt = Min(rWdt * Min(iPlayerNum, C4S_MaxMapPlayerExtend), MapWdt.Max);
|
|
}
|
|
|
|
void C4SLandscape::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(ExactLandscape, "ExactLandscape", FALSE));
|
|
pComp->Value(mkNamingAdapt(Vegetation, "Vegetation", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(VegLevel, "VegetationLevel", C4SVal(50,30,0,100), true));
|
|
pComp->Value(mkNamingAdapt(InEarth, "InEarth", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(InEarthLevel, "InEarthLevel", C4SVal(50,0,0,100), true));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(SkyDef), "Sky", ""));
|
|
pComp->Value(mkNamingAdapt(mkArrayAdaptDM(SkyDefFade,0),"SkyFade" ));
|
|
pComp->Value(mkNamingAdapt(NoSky, "NoSky", FALSE));
|
|
pComp->Value(mkNamingAdapt(BottomOpen, "BottomOpen", FALSE));
|
|
pComp->Value(mkNamingAdapt(TopOpen, "TopOpen", TRUE));
|
|
pComp->Value(mkNamingAdapt(LeftOpen, "LeftOpen", 0));
|
|
pComp->Value(mkNamingAdapt(RightOpen, "RightOpen", 0));
|
|
pComp->Value(mkNamingAdapt(AutoScanSideOpen, "AutoScanSideOpen", TRUE));
|
|
pComp->Value(mkNamingAdapt(MapWdt, "MapWidth", C4SVal(100,0,64,250), true));
|
|
pComp->Value(mkNamingAdapt(MapHgt, "MapHeight", C4SVal(50,0,40,250), true));
|
|
pComp->Value(mkNamingAdapt(MapZoom, "MapZoom", C4SVal(10,0,5,15), true));
|
|
pComp->Value(mkNamingAdapt(Amplitude, "Amplitude", C4SVal(0)));
|
|
pComp->Value(mkNamingAdapt(Phase, "Phase", C4SVal(50)));
|
|
pComp->Value(mkNamingAdapt(Period, "Period", C4SVal(15)));
|
|
pComp->Value(mkNamingAdapt(Random, "Random", C4SVal(0)));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Material),"Material", "Earth"));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Liquid), "Liquid", "Water"));
|
|
pComp->Value(mkNamingAdapt(LiquidLevel, "LiquidLevel", C4SVal()));
|
|
pComp->Value(mkNamingAdapt(MapPlayerExtend, "MapPlayerExtend", 0));
|
|
pComp->Value(mkNamingAdapt(Layers, "Layers", C4NameList()));
|
|
pComp->Value(mkNamingAdapt(Gravity, "Gravity", C4SVal(100,0,10,200), true));
|
|
pComp->Value(mkNamingAdapt(NoScan, "NoScan", FALSE));
|
|
pComp->Value(mkNamingAdapt(KeepMapCreator, "KeepMapCreator", FALSE));
|
|
pComp->Value(mkNamingAdapt(SkyScrollMode, "SkyScrollMode", 0));
|
|
pComp->Value(mkNamingAdapt(NewStyleLandscape, "NewStyleLandscape", FALSE));
|
|
pComp->Value(mkNamingAdapt(FoWRes, "FoWRes", static_cast<int32_t>(CClrModAddMap::DefResolutionX)));
|
|
}
|
|
|
|
void C4SWeather::Default()
|
|
{
|
|
Climate.Set(50,10);
|
|
StartSeason.Set(50,50);
|
|
YearSpeed.Set(50);
|
|
Rain.Default(); Lightning.Default(); Wind.Set(0,70,-100,+100);
|
|
SCopy("Water",Precipitation,C4M_MaxName);
|
|
NoGamma=1;
|
|
}
|
|
|
|
void C4SWeather::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Climate, "Climate", C4SVal(50,10), true));
|
|
pComp->Value(mkNamingAdapt(StartSeason, "StartSeason", C4SVal(50,50), true));
|
|
pComp->Value(mkNamingAdapt(YearSpeed, "YearSpeed", C4SVal(50)));
|
|
pComp->Value(mkNamingAdapt(Rain, "Rain", C4SVal()));
|
|
pComp->Value(mkNamingAdapt(Wind, "Wind", C4SVal(0,70,-100,+100), true));
|
|
pComp->Value(mkNamingAdapt(Lightning, "Lightning", C4SVal()));
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Precipitation),"Precipitation", "Water"));
|
|
pComp->Value(mkNamingAdapt(NoGamma, "NoGamma", TRUE));
|
|
}
|
|
|
|
void C4SAnimals::Default()
|
|
{
|
|
FreeLife.Clear();
|
|
EarthNest.Clear();
|
|
}
|
|
|
|
void C4SAnimals::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(FreeLife, "Animal", C4IDList()));
|
|
pComp->Value(mkNamingAdapt(EarthNest, "Nest", C4IDList()));
|
|
}
|
|
|
|
void C4SEnvironment::Default()
|
|
{
|
|
Objects.Clear();
|
|
}
|
|
|
|
void C4SEnvironment::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Objects, "Objects", C4IDList()));
|
|
}
|
|
|
|
void C4SRealism::Default()
|
|
{
|
|
ConstructionNeedsMaterial=0;
|
|
StructuresNeedEnergy=1;
|
|
LandscapePushPull=0;
|
|
LandscapeInsertThrust=0;
|
|
ValueOverloads.Default();
|
|
BaseFunctionality = BASEFUNC_Default;
|
|
BaseRegenerateEnergyPrice = BASE_RegenerateEnergyPrice;
|
|
}
|
|
|
|
void C4SDisasters::Default()
|
|
{
|
|
Volcano.Default();
|
|
Earthquake.Default();
|
|
Meteorite.Default();
|
|
}
|
|
|
|
void C4SDisasters::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(Meteorite, "Meteorite", C4SVal()));
|
|
pComp->Value(mkNamingAdapt(Volcano, "Volcano", C4SVal()));
|
|
pComp->Value(mkNamingAdapt(Earthquake, "Earthquake", C4SVal()));
|
|
}
|
|
|
|
BOOL C4Scenario::Compile(const char *szSource, bool fLoadSection)
|
|
{
|
|
if (!fLoadSection) Default();
|
|
return CompileFromBuf_LogWarn<StdCompilerINIRead>(mkParAdapt(*this, fLoadSection), StdStrBuf(szSource), C4CFN_ScenarioCore);
|
|
}
|
|
|
|
BOOL C4Scenario::Decompile(char **ppOutput, int32_t *ipSize, bool fSaveSection)
|
|
{
|
|
try
|
|
{
|
|
// Decompile
|
|
StdStrBuf Buf = DecompileToBuf<StdCompilerINIWrite>(mkParAdapt(*this, fSaveSection));
|
|
// Return
|
|
*ppOutput = Buf.GrabPointer();
|
|
*ipSize = Buf.getSize();
|
|
}
|
|
catch(StdCompiler::Exception *)
|
|
{ return FALSE; }
|
|
return TRUE;
|
|
}
|
|
|
|
void C4Scenario::Clear()
|
|
{
|
|
|
|
}
|
|
|
|
void C4Scenario::SetExactLandscape()
|
|
{
|
|
if (Landscape.ExactLandscape) return;
|
|
//int32_t iMapZoom = Landscape.MapZoom.Std;
|
|
// Set landscape
|
|
Landscape.ExactLandscape = 1;
|
|
/*FIXME: warum ist das auskommentiert?
|
|
// - because Map and Landscape are handled differently in NET2 (Map.bmp vs Landscape.bmp), and the zoomed Map.bmp may be used
|
|
// to reconstruct the textures on the Landscape.bmp in case of e.g. runtime joins. In this sense, C4S.Landscape.ExactLandscape
|
|
// only marks that the landscape.bmp is an exact one, and there may or may not be an accompanying Map.bmp
|
|
Landscape.MapZoom.Set(1,0,1,1);
|
|
// Zoom player starting positions
|
|
for (int32_t cnt=0; cnt<C4S_MaxPlayer; cnt++)
|
|
{
|
|
if (PlrStart[cnt].PositionX >= -1)
|
|
PlrStart[cnt].PositionX = PlrStart[cnt].PositionX * iMapZoom;
|
|
if (PlrStart[cnt].PositionY >= -1)
|
|
PlrStart[cnt].PositionY = PlrStart[cnt].PositionY * iMapZoom;
|
|
}
|
|
*/
|
|
}
|
|
|
|
bool C4SDefinitions::GetModules(StdStrBuf *psOutModules) const
|
|
{
|
|
// Local only
|
|
if (LocalOnly) { psOutModules->Copy(""); return TRUE; }
|
|
// Scan for any valid entries
|
|
bool fSpecified = false;
|
|
int32_t cnt=0;
|
|
for (; cnt<C4S_MaxDefinitions; cnt++)
|
|
if (Definition[cnt][0])
|
|
fSpecified = true;
|
|
// No valid entries
|
|
if (!fSpecified) return false;
|
|
// Compose entry list
|
|
psOutModules->Copy("");
|
|
for (cnt=0; cnt<C4S_MaxDefinitions; cnt++)
|
|
if (Definition[cnt][0])
|
|
{
|
|
if (psOutModules->getLength()) psOutModules->AppendChar(';');
|
|
psOutModules->Append(Definition[cnt]);
|
|
}
|
|
// Done
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void C4SDefinitions::SetModules(const char *szList, const char *szRelativeToPath, const char *szRelativeToPath2)
|
|
{
|
|
int32_t cnt;
|
|
|
|
// Empty list: local only
|
|
if (!SModuleCount(szList))
|
|
{
|
|
LocalOnly=TRUE;
|
|
for (cnt=0; cnt<C4S_MaxDefinitions; cnt++) Definition[cnt][0]=0;
|
|
return;
|
|
}
|
|
|
|
// Set list
|
|
LocalOnly=FALSE;
|
|
for (cnt=0; cnt<C4S_MaxDefinitions; cnt++)
|
|
{
|
|
SGetModule(szList,cnt,Definition[cnt],_MAX_PATH);
|
|
// Make relative path
|
|
if (szRelativeToPath && *szRelativeToPath)
|
|
if (SEqualNoCase(Definition[cnt],szRelativeToPath,SLen(szRelativeToPath)))
|
|
SCopy(Definition[cnt]+SLen(szRelativeToPath),Definition[cnt]);
|
|
if (szRelativeToPath2 && *szRelativeToPath2)
|
|
if (SEqualNoCase(Definition[cnt],szRelativeToPath2,SLen(szRelativeToPath2)))
|
|
SCopy(Definition[cnt]+SLen(szRelativeToPath2),Definition[cnt]);
|
|
}
|
|
|
|
}
|
|
|
|
BOOL C4SDefinitions::AssertModules(const char *szPath, char *sMissing)
|
|
{
|
|
// Local only
|
|
if (LocalOnly) return TRUE;
|
|
|
|
// Check all listed modules for availability
|
|
BOOL fAllAvailable=TRUE;
|
|
char szModule[_MAX_PATH+1];
|
|
if (sMissing) sMissing[0]=0;
|
|
// Check all definition files
|
|
for (int32_t cnt=0; cnt<C4S_MaxDefinitions; cnt++)
|
|
if (Definition[cnt][0])
|
|
{
|
|
// Compose filename using path specified by caller
|
|
szModule[0]=0;
|
|
if (szPath) SCopy(szPath,szModule); if (szModule[0]) AppendBackslash(szModule);
|
|
SAppend(Definition[cnt],szModule);
|
|
// Missing
|
|
if (!C4Group_IsGroup(szModule))
|
|
{
|
|
// Add to list
|
|
if (sMissing) { SNewSegment(sMissing,", "); SAppend(Definition[cnt],sMissing); }
|
|
fAllAvailable=FALSE;
|
|
}
|
|
}
|
|
|
|
return fAllAvailable;
|
|
}
|
|
|
|
void C4SDefinitions::CompileFunc(StdCompiler *pComp)
|
|
{
|
|
pComp->Value(mkNamingAdapt(LocalOnly, "LocalOnly", FALSE));
|
|
pComp->Value(mkNamingAdapt(AllowUserChange, "AllowUserChange", FALSE));
|
|
for(int32_t i = 0; i < C4S_MaxDefinitions; i++)
|
|
pComp->Value(mkNamingAdapt(mkStringAdaptMA(Definition[i]), FormatString("Definition%i", i+1).getData(), ""));
|
|
pComp->Value(mkNamingAdapt(SkipDefs, "SkipDefs", C4IDList()));
|
|
}
|
|
|
|
void C4SGame::ConvertGoals(C4SRealism &rRealism)
|
|
{
|
|
|
|
// Convert mode to goals
|
|
switch (Mode)
|
|
{
|
|
case C4S_Melee: Goals.SetIDCount(C4Id("MELE"),1,TRUE); ClearOldGoals(); break;
|
|
case C4S_MeleeTeamwork: Goals.SetIDCount(C4Id("MELE"),1,TRUE); ClearOldGoals(); break;
|
|
}
|
|
Mode=0;
|
|
|
|
// Convert goals (master selection)
|
|
switch (CooperativeGoal)
|
|
{
|
|
case C4S_Goldmine: Goals.SetIDCount(C4Id("GLDM"),1,TRUE); ClearOldGoals(); break;
|
|
case C4S_Monsterkill: Goals.SetIDCount(C4Id("MNTK"),1,TRUE); ClearOldGoals(); break;
|
|
case C4S_ValueGain: Goals.SetIDCount(C4Id("VALG"),Max(ValueGain/100,1),TRUE); ClearOldGoals(); break;
|
|
}
|
|
CooperativeGoal=0;
|
|
// CreateObjects,ClearObjects,ClearMaterials are still valid but invisible
|
|
|
|
// Convert realism to rules
|
|
if (rRealism.ConstructionNeedsMaterial) Rules.SetIDCount(C4Id("CNMT"),1,TRUE); rRealism.ConstructionNeedsMaterial=0;
|
|
if (rRealism.StructuresNeedEnergy) Rules.SetIDCount(C4Id("ENRG"),1,TRUE); rRealism.StructuresNeedEnergy=0;
|
|
|
|
// Convert rules
|
|
if (EnableRemoveFlag) Rules.SetIDCount(C4Id("FGRV"),1,TRUE); EnableRemoveFlag=0;
|
|
|
|
// Convert eliminiation to rules
|
|
switch (Elimination)
|
|
{
|
|
case C4S_KillTheCaptain: Rules.SetIDCount(C4Id("KILC"),1,TRUE); break;
|
|
case C4S_CaptureTheFlag: Rules.SetIDCount(C4Id("CTFL"),1,TRUE); break;
|
|
}
|
|
Elimination=1; // unconvertible default crew elimination
|
|
|
|
// CaptureTheFlag requires FlagRemoveable
|
|
if (Rules.GetIDCount(C4Id("CTFL"))) Rules.SetIDCount(C4Id("FGRV"),1,TRUE);
|
|
|
|
}
|
|
|
|
void C4SGame::ClearOldGoals()
|
|
{
|
|
CreateObjects.Clear(); ClearObjects.Clear(); ClearMaterial.Clear();
|
|
ValueGain=0;
|
|
}
|
|
|
|
BOOL C4SGame::IsMelee()
|
|
{
|
|
return (Goals.GetIDCount(C4Id("MELE")) || Goals.GetIDCount(C4Id("MEL2")));
|
|
}
|
|
|
|
|
|
|
|
|
|
// scenario sections
|
|
|
|
const char *C4ScenSect_Main = "main";
|
|
|
|
C4ScenarioSection::C4ScenarioSection(char *szName)
|
|
{
|
|
// copy name
|
|
if (szName && !SEqualNoCase(szName, C4ScenSect_Main) && *szName)
|
|
{
|
|
this->szName = new char[strlen(szName)+1];
|
|
SCopy(szName, this->szName);
|
|
}
|
|
else
|
|
this->szName = const_cast<char *>(C4ScenSect_Main);
|
|
// zero fields
|
|
szTempFilename = szFilename = 0;
|
|
fModified = false;
|
|
// link into main list
|
|
pNext = Game.pScenarioSections;
|
|
Game.pScenarioSections = this;
|
|
}
|
|
|
|
C4ScenarioSection::~C4ScenarioSection()
|
|
{
|
|
// del following scenario sections
|
|
while (pNext)
|
|
{
|
|
C4ScenarioSection *pDel = pNext;
|
|
pNext = pNext->pNext;
|
|
pDel->pNext = NULL;
|
|
delete pDel;
|
|
}
|
|
// del temp file
|
|
if (szTempFilename)
|
|
{
|
|
EraseItem(szTempFilename);
|
|
delete szTempFilename;
|
|
}
|
|
// del filename if assigned
|
|
if (szFilename) delete szFilename;
|
|
// del name if owned
|
|
if (szName != C4ScenSect_Main) delete szName;
|
|
}
|
|
|
|
bool C4ScenarioSection::ScenarioLoad(char *szFilename)
|
|
{
|
|
// safety
|
|
if (this->szFilename || !szFilename) return false;
|
|
// store name
|
|
this->szFilename = new char[strlen(szFilename)+1];
|
|
SCopy(szFilename, this->szFilename, _MAX_FNAME);
|
|
// extract if it's not an open folder
|
|
if (Game.ScenarioFile.IsPacked()) if (!EnsureTempStore(true, true)) return false;
|
|
// donce, success
|
|
return true;
|
|
}
|
|
|
|
C4Group *C4ScenarioSection::GetGroupfile(C4Group &rGrp)
|
|
{
|
|
// check temp filename
|
|
if (szTempFilename) if (rGrp.Open(szTempFilename)) return &rGrp; else return NULL;
|
|
// check filename within scenario
|
|
if (szFilename) if (rGrp.OpenAsChild(&Game.ScenarioFile, szFilename)) return &rGrp; else return NULL;
|
|
// unmodified main section: return main group
|
|
if (SEqualNoCase(szName, C4ScenSect_Main)) return &Game.ScenarioFile;
|
|
// failure
|
|
return NULL;
|
|
}
|
|
|
|
bool C4ScenarioSection::EnsureTempStore(bool fExtractLandscape, bool fExtractObjects)
|
|
{
|
|
// if it's temp store already, don't do anything
|
|
if (szTempFilename) return true;
|
|
// make temp filename
|
|
char *szTmp = const_cast<char *>(Config.AtTempPath(szFilename ? GetFilename(szFilename) : szName));
|
|
MakeTempFilename(szTmp);
|
|
// main section: extract section files from main scenario group (create group as open dir)
|
|
if (!szFilename)
|
|
{
|
|
if (!CreateDirectory(szTmp, NULL)) return false;
|
|
C4Group hGroup;
|
|
if (!hGroup.Open(szTmp, TRUE)) { EraseItem(szTmp); return false; }
|
|
// extract all desired section files
|
|
Game.ScenarioFile.ResetSearch();
|
|
char fn[_MAX_FNAME+1]; *fn=0;
|
|
while (Game.ScenarioFile.FindNextEntry(C4FLS_Section, fn))
|
|
if (fExtractLandscape || !WildcardMatch(C4FLS_SectionLandscape, fn))
|
|
if (fExtractObjects || !WildcardMatch(C4FLS_SectionObjects, fn))
|
|
Game.ScenarioFile.ExtractEntry(fn, szTmp);
|
|
hGroup.Close();
|
|
}
|
|
else
|
|
{
|
|
// subsection: simply extract section from main group
|
|
if (!Game.ScenarioFile.ExtractEntry(szFilename, szTmp)) return false;
|
|
// delete undesired landscape/object files
|
|
if (!fExtractLandscape || !fExtractObjects)
|
|
{
|
|
C4Group hGroup;
|
|
if (hGroup.Open(szFilename))
|
|
{
|
|
if (!fExtractLandscape) hGroup.Delete(C4FLS_SectionLandscape);
|
|
if (!fExtractObjects) hGroup.Delete(C4FLS_SectionObjects);
|
|
}
|
|
}
|
|
}
|
|
// copy temp filename
|
|
szTempFilename = new char[strlen(szTmp)+1];
|
|
SCopy(szTmp, szTempFilename, _MAX_PATH);
|
|
// done, success
|
|
return true;
|
|
}
|
|
|