1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Object definition */
19 
20 #include "C4Include.h"
21 #include "C4ForbidLibraryCompilation.h"
22 #include "object/C4Def.h"
23 
24 #include "c4group/C4Components.h"
25 #include "graphics/C4Draw.h"
26 #include "graphics/C4DrawGL.h"
27 #include "graphics/C4GraphicsResource.h"
28 #include "graphics/CSurface8.h"
29 #include "landscape/C4Particles.h"
30 #include "landscape/C4SolidMask.h"
31 #include "lib/StdColors.h"
32 #include "lib/StdMeshLoader.h"
33 #include "object/C4Object.h"
34 #include "platform/C4FileMonitor.h"
35 #include "platform/C4SoundSystem.h"
36 #include "player/C4RankSystem.h"
37 
38 // Helper class to load additional resources required for meshes from
39 // a C4Group.
40 class C4DefAdditionalResourcesLoader: public StdMeshMaterialLoader
41 {
42 public:
C4DefAdditionalResourcesLoader(C4Group & hGroup)43 	C4DefAdditionalResourcesLoader(C4Group& hGroup): Group(hGroup) {}
44 
LoadTexture(const char * filename)45 	C4Surface* LoadTexture(const char* filename) override
46 	{
47 		if (!Group.AccessEntry(filename)) return nullptr;
48 		C4Surface* surface = new C4Surface;
49 		// Suppress error message here, StdMeshMaterial loader
50 		// will show one.
51 		if (!surface->Read(Group, GetExtension(filename), C4SF_MipMap))
52 			{ delete surface; surface = nullptr; }
53 		return surface;
54 	}
55 
LoadShaderCode(const char * filename)56 	StdStrBuf LoadShaderCode(const char* filename) override
57 	{
58 		StdStrBuf ret;
59 		if (!Group.LoadEntryString(filename, &ret)) return StdStrBuf();
60 		return ret;
61 	}
62 
AddShaderSlices(C4Shader & shader,int ssc)63 	void AddShaderSlices(C4Shader& shader, int ssc) override
64 	{
65 #ifndef USE_CONSOLE
66 		// Add mesh-independent slices
67 		shader.AddDefine("OPENCLONK");
68 		shader.AddDefine("OC_MESH");
69 
70 		if (ssc & C4SSC_MOD2) shader.AddDefine("OC_CLRMOD_MOD2");
71 		if (ssc & C4SSC_LIGHT) shader.AddDefine("OC_DYNAMIC_LIGHT");
72 
73 		// Note these are never set for meshes at the moment:
74 		if (ssc & C4SSC_BASE) shader.AddDefine("OC_HAVE_BASE");
75 		if (ssc & C4SSC_OVERLAY) shader.AddDefine("OC_HAVE_OVERLAY");
76 
77 		shader.LoadFragmentSlices(&::GraphicsResource.Files, "CommonShader.glsl");
78 		shader.LoadFragmentSlices(&::GraphicsResource.Files, "ObjectShader.glsl");
79 
80 		// Categories for script shaders.
81 		shader.SetScriptCategories({"Common", "Object"});
82 #endif
83 	}
84 
85 private:
86 	C4Group& Group;
87 };
88 
89 
90 
DefaultDefCore()91 void C4Def::DefaultDefCore()
92 {
93 	rC4XVer[0]=rC4XVer[1]=0;
94 	RequireDef.Clear();
95 	Shape.Default();
96 	Entrance.Default();
97 	Collection.Default();
98 	PictureRect.Default();
99 	SolidMask.Default();
100 	TopFace.Default();
101 	BurnTurnTo=C4ID::None;
102 	GrowthType=0;
103 	CrewMember=0;
104 	NativeCrew=0;
105 	Mass=0;
106 	Value=0;
107 	Exclusive=0;
108 	Category=0;
109 	Constructable=0;
110 	Rotateable=0;
111 	RotatedEntrance=0;
112 	Float=0;
113 	ColorByOwner=0;
114 	NoHorizontalMove=0;
115 	LiftTop=0;
116 	GrabPutGet=0;
117 	UprightAttach=0;
118 	Line=0;
119 	LineIntersect=0;
120 	IncompleteActivity=0;
121 	Oversize=0;
122 	Fragile=0;
123 	NoPushEnter=0;
124 	Projectile=0;
125 	VehicleControl=0;
126 	Pathfinder=0;
127 	NoMassFromContents=0;
128 	MoveToRange=0;
129 	NoStabilize=0;
130 	ClosedContainer=0;
131 	SilentCommands=0;
132 	TemporaryCrew=0;
133 	BlitMode=C4D_Blit_Normal;
134 	NoBreath=0;
135 	ConSizeOff=0;
136 	NoGet=0;
137 	NoTransferZones=0;
138 	HideInCreator = false;
139 }
140 
LoadDefCore(C4Group & hGroup)141 bool C4Def::LoadDefCore(C4Group &hGroup)
142 {
143 	StdStrBuf Source;
144 	if (hGroup.LoadEntryString(C4CFN_DefCore,&Source))
145 	{
146 		StdStrBuf Name = hGroup.GetFullName() + (const StdStrBuf &)FormatString("%cDefCore.txt", DirectorySeparator);
147 		if (!Compile(Source.getData(), Name.getData()))
148 			return false;
149 		Source.Clear();
150 
151 		// Check mass
152 		if (Mass < 0)
153 		{
154 			DebugLogF("WARNING: Def %s (%s) at %s has invalid mass!", GetName(), id.ToString(), hGroup.GetFullName().getData());
155 			Mass = 0;
156 		}
157 
158 		return true;
159 	}
160 	return false;
161 }
162 
Save(C4Group & hGroup)163 bool C4Def::Save(C4Group &hGroup)
164 {
165 	StdStrBuf Out;
166 	if (! Decompile(&Out, FormatString("%s::DefCore.txt", id.ToString()).getData()) )
167 		return false;
168 	return hGroup.Add(C4CFN_DefCore,Out,false,true);
169 }
170 
Compile(const char * szSource,const char * szName)171 bool C4Def::Compile(const char *szSource, const char *szName)
172 {
173 	return CompileFromBuf_LogWarn<StdCompilerINIRead>(mkNamingAdapt(*this, "DefCore"), StdStrBuf(szSource), szName);
174 }
175 
Decompile(StdStrBuf * pOut,const char * szName)176 bool C4Def::Decompile(StdStrBuf *pOut, const char *szName)
177 {
178 	return DecompileToBuf_Log<StdCompilerINIWrite>(mkNamingAdapt(*this, "DefCore"), pOut, szName);
179 }
180 
CompileFunc(StdCompiler * pComp)181 void C4Def::CompileFunc(StdCompiler *pComp)
182 {
183 
184 	pComp->Value(mkNamingAdapt(id,                "id",                 C4ID::None          ));
185 	pComp->Value(mkNamingAdapt(toC4CArr(rC4XVer),             "Version"                               ));
186 	pComp->Value(mkNamingAdapt(mkParAdapt(RequireDef, false), "RequireDef",         C4IDList()        ));
187 
188 	const StdBitfieldEntry<int32_t> Categories[] =
189 	{
190 
191 		{ "C4D_None",                     C4D_None                },
192 		{ "C4D_StaticBack",               C4D_StaticBack          },
193 		{ "C4D_Structure",                C4D_Structure           },
194 		{ "C4D_Vehicle",                  C4D_Vehicle             },
195 		{ "C4D_Living",                   C4D_Living              },
196 		{ "C4D_Object",                   C4D_Object              },
197 
198 		{ "C4D_Goal",                     C4D_Goal                },
199 		{ "C4D_Rule",                     C4D_Rule                },
200 		{ "C4D_Environment",              C4D_Environment         },
201 
202 		{ "C4D_Background",               C4D_Background          },
203 		{ "C4D_Parallax",                 C4D_Parallax            },
204 		{ "C4D_MouseSelect",              C4D_MouseSelect         },
205 		{ "C4D_Foreground",               C4D_Foreground          },
206 		{ "C4D_MouseIgnore",              C4D_MouseIgnore         },
207 		{ "C4D_IgnoreFoW",                C4D_IgnoreFoW           },
208 
209 		{ nullptr,                           0                       }
210 	};
211 
212 	pComp->Value(mkNamingAdapt(mkBitfieldAdapt<int32_t>(Category, Categories),
213 	                           "Category",           0             ));
214 
215 	pComp->Value(mkParAdapt(Shape, static_cast<C4Shape*>(nullptr)));
216 	pComp->Value(mkNamingAdapt(Value,                         "Value",              0                 ));
217 	pComp->Value(mkNamingAdapt(Mass,                          "Mass",               0                 ));
218 	pComp->Value(mkNamingAdapt(SolidMask,                     "SolidMask",          TargetRect0       ));
219 	pComp->Value(mkNamingAdapt(TopFace,                       "TopFace",            TargetRect0       ));
220 	pComp->Value(mkNamingAdapt(PictureRect,                   "Picture",            Rect0             ));
221 	pComp->Value(mkNamingAdapt(Entrance,                      "Entrance",           Rect0             ));
222 	pComp->Value(mkNamingAdapt(Collection,                    "Collection",         Rect0             ));
223 	pComp->Value(mkNamingAdapt(Exclusive,                     "Exclusive",          0                 ));
224 	pComp->Value(mkNamingAdapt(Line,                          "Line",               0                 ));
225 	// <Newton> undocumented, but obsolete? I don't understand the sense of this value.
226 	pComp->Value(mkNamingAdapt(LineIntersect,                 "LineIntersect",      0                 ));
227 	pComp->Value(mkNamingAdapt(CrewMember,                    "CrewMember",         0                 ));
228 	pComp->Value(mkNamingAdapt(NativeCrew,                    "NoStandardCrew",     0                 ));
229 	pComp->Value(mkNamingAdapt(Constructable,                 "Construction",       0                 ));
230 
231 	const StdBitfieldEntry<int32_t> GrabPutGetTypes[] =
232 	{
233 
234 		{ "C4D_GrabGet"            ,C4D_Grab_Get},
235 		{ "C4D_GrabPut"            ,C4D_Grab_Put},
236 
237 		{ nullptr,                     0}
238 	};
239 
240 	pComp->Value(mkNamingAdapt(mkBitfieldAdapt(GrabPutGet, GrabPutGetTypes),
241 	                           "GrabPutGet",         0                 ));
242 
243 	pComp->Value(mkNamingAdapt(Rotateable,                    "Rotate",             0                 ));
244 	pComp->Value(mkNamingAdapt(RotatedEntrance,               "RotatedEntrance",    0                 ));
245 	pComp->Value(mkNamingAdapt(Float,                         "Float",              0                 ));
246 	pComp->Value(mkNamingAdapt(ColorByOwner,                  "ColorByOwner",       0                 ));
247 	pComp->Value(mkNamingAdapt(NoHorizontalMove,              "HorizontalFix",      0                 ));
248 	pComp->Value(mkNamingAdapt(LiftTop,                       "LiftTop",            0                 ));
249 	pComp->Value(mkNamingAdapt(UprightAttach,                 "UprightAttach",      0                 ));
250 	pComp->Value(mkNamingAdapt(GrowthType,                    "StretchGrowth",      0                 ));
251 	pComp->Value(mkNamingAdapt(IncompleteActivity,            "IncompleteActivity", 0                 ));
252 	pComp->Value(mkNamingAdapt(Oversize,                      "Oversize",           0                 ));
253 	// <Newton> Fragile and Projectile are kinda obsolete.
254 	// Only used at one point in the command system. Should rather be solved with properties if at all
255 	pComp->Value(mkNamingAdapt(Fragile,                       "Fragile",            0                 ));
256 	pComp->Value(mkNamingAdapt(Projectile,                    "Projectile",         0                 ));
257 
258 	pComp->Value(mkNamingAdapt(NoPushEnter,                   "NoPushEnter",        0                 ));
259 	pComp->Value(mkNamingAdapt(VehicleControl,                "VehicleControl",     0                 ));
260 	pComp->Value(mkNamingAdapt(Pathfinder,                    "Pathfinder",         0                 ));
261 	pComp->Value(mkNamingAdapt(MoveToRange,                   "MoveToRange",        0                 ));
262 	pComp->Value(mkNamingAdapt(NoMassFromContents,            "NoMassFromContents", 0                 ));
263 	pComp->Value(mkNamingAdapt(NoStabilize,                   "NoStabilize",        0                 ));
264 	pComp->Value(mkNamingAdapt(ClosedContainer,               "ClosedContainer",    0                 ));
265 	pComp->Value(mkNamingAdapt(SilentCommands,                "SilentCommands",     0                 ));
266 	pComp->Value(mkNamingAdapt(TemporaryCrew,                 "TemporaryCrew",      0                 ));
267 	pComp->Value(mkNamingAdapt(BlitMode,                      "BlitMode",           C4D_Blit_Normal   ));
268 	pComp->Value(mkNamingAdapt(NoBreath,                      "NoBreath",           0                 ));
269 	pComp->Value(mkNamingAdapt(ConSizeOff,                    "ConSizeOff",         0                 ));
270 	pComp->Value(mkNamingAdapt(NoGet,                         "NoGet",              0                 ));
271 	pComp->Value(mkNamingAdapt(NoTransferZones,               "NoTransferZones",    0                 ));
272 
273 	const StdBitfieldEntry<int32_t> AllowPictureStackModes[] =
274 	{
275 
276 		{ "APS_Color",      APS_Color    },
277 		{ "APS_Graphics",   APS_Graphics },
278 		{ "APS_Name",       APS_Name     },
279 		{ "APS_Overlay",    APS_Overlay  },
280 		{ nullptr,             0            }
281 	};
282 
283 	pComp->Value(mkNamingAdapt(mkBitfieldAdapt<int32_t>(AllowPictureStack, AllowPictureStackModes),		//undocumented
284 	                           "AllowPictureStack",   0                ));
285 	pComp->Value(mkNamingAdapt(HideInCreator, "HideInCreator", false));
286 }
287 
288 //-------------------------------- C4Def -------------------------------------------------------
289 
C4Def()290 C4Def::C4Def(): Script(), C4PropListStatic(ScriptEngine.GetPropList(), nullptr, nullptr)
291 {
292 	Script.SetDef(this);
293 	assert(ScriptEngine.GetPropList());
294 	Graphics.pDef = this;
295 	Default();
296 }
297 
Default()298 void C4Def::Default()
299 {
300 	DefaultDefCore();
301 	Next=nullptr;
302 	Temporary=false;
303 	Filename[0]=0;
304 	Creation=0;
305 	Count=0;
306 	MainFace.Set(nullptr,0,0,0,0);
307 	Script.Clear();
308 	StringTable.Clear();
309 	pClonkNames=nullptr;
310 	pRankNames=nullptr;
311 	pRankSymbols=nullptr;
312 	fClonkNamesOwned = fRankNamesOwned = fRankSymbolsOwned = false;
313 	iNumRankSymbols=1;
314 	pSolidMask = nullptr;
315 }
316 
~C4Def()317 C4Def::~C4Def()
318 {
319 	Clear();
320 }
321 
Clear()322 void C4Def::Clear()
323 {
324 	Script.Clear();
325 	C4PropList::Clear();
326 
327 	Graphics.Clear();
328 
329 	StringTable.Clear();
330 	if (pClonkNames && fClonkNamesOwned) delete pClonkNames; pClonkNames=nullptr;
331 	if (pRankNames && fRankNamesOwned) delete pRankNames; pRankNames=nullptr;
332 	if (pRankSymbols && fRankSymbolsOwned) delete pRankSymbols; pRankSymbols=nullptr;
333 	fClonkNamesOwned = fRankNamesOwned = fRankSymbolsOwned = false;
334 	delete pSolidMask; pSolidMask = nullptr;
335 }
336 
Load(C4Group & hGroup,StdMeshSkeletonLoader & loader,DWORD dwLoadWhat,const char * szLanguage,C4SoundSystem * pSoundSystem,C4DefGraphicsPtrBackup * gfx_backup)337 bool C4Def::Load(C4Group &hGroup,
338 	StdMeshSkeletonLoader &loader,
339 	DWORD dwLoadWhat,
340 	const char *szLanguage,
341 	C4SoundSystem *pSoundSystem,
342 	C4DefGraphicsPtrBackup *gfx_backup
343 	)
344 {
345 	bool AddFileMonitoring = false;
346 	if (Game.pFileMonitor && !SEqual(hGroup.GetFullName().getData(),Filename) && !hGroup.IsPacked())
347 		AddFileMonitoring = true;
348 
349 	// Store filename
350 	SCopy(hGroup.GetFullName().getData(),Filename);
351 
352 	// Verbose log filename
353 	if (Config.Graphics.VerboseObjectLoading>=3)
354 		Log(hGroup.GetFullName().getData());
355 
356 	if (AddFileMonitoring) Game.pFileMonitor->AddDirectory(Filename);
357 
358 	// Pre-read all images and shader stuff because they ar eaccessed in unpredictable order during loading
359 	hGroup.PreCacheEntries(C4CFN_ShaderFiles);
360 	hGroup.PreCacheEntries(C4CFN_ImageFiles);
361 
362 	LoadMeshMaterials(hGroup, gfx_backup);
363 	bool fSuccess = LoadParticleDef(hGroup);
364 
365 	// Read DefCore
366 	if (fSuccess) fSuccess = LoadDefCore(hGroup);
367 
368 	// Skip def: don't even read sounds!
369 	if (fSuccess && Game.C4S.Definitions.SkipDefs.GetIDCount(id, 1)) return false;
370 
371 	// Read sounds, even if not a valid def (for pure ocd sound folders)
372 	if (dwLoadWhat & C4D_Load_Sounds) LoadSounds(hGroup, pSoundSystem);
373 
374 	// cancel if not a valid definition
375 	if (!fSuccess) return false;
376 
377 	// Read and parse SolidMask bitmap
378 	if (!LoadSolidMask(hGroup)) return false;
379 
380 	// Read surface bitmap, meshes, skeletons
381 	if ((dwLoadWhat & C4D_Load_Bitmap) && !LoadGraphics(hGroup, loader)) return false;
382 
383 	// Read string table
384 	C4Language::LoadComponentHost(&StringTable, hGroup, C4CFN_ScriptStringTbl, szLanguage);
385 
386 	// Register ID with script engine
387 	::ScriptEngine.RegisterGlobalConstant(id.ToString(), C4VPropList(this));
388 	ParentKeyName = ::Strings.RegString(id.ToString());
389 
390 	// Read script
391 	if (dwLoadWhat & C4D_Load_Script) LoadScript(hGroup, szLanguage);
392 
393 	// Read clonknames
394 	if (dwLoadWhat & C4D_Load_ClonkNames) LoadClonkNames(hGroup, pClonkNames, szLanguage);
395 
396 	// Read clonkranks
397 	if (dwLoadWhat & C4D_Load_RankNames) LoadRankNames(hGroup, szLanguage);
398 
399 	// Read rankfaces
400 	if (dwLoadWhat & C4D_Load_RankFaces) LoadRankFaces(hGroup);
401 
402 	// Temporary flag
403 	if (dwLoadWhat & C4D_Load_Temporary) Temporary=true;
404 
405 	return true;
406 }
407 
LoadMeshMaterials(C4Group & hGroup,C4DefGraphicsPtrBackup * gfx_backup)408 void C4Def::LoadMeshMaterials(C4Group &hGroup, C4DefGraphicsPtrBackup *gfx_backup)
409 {
410 	// Load all mesh materials from this folder
411 	C4DefAdditionalResourcesLoader loader(hGroup);
412 	hGroup.ResetSearch();
413 	char MaterialFilename[_MAX_PATH + 1]; *MaterialFilename = 0;
414 
415 	for (const auto &mat : mesh_materials)
416 	{
417 		::MeshMaterialManager.Remove(mat, &gfx_backup->GetUpdater());
418 	}
419 	mesh_materials.clear();
420 	while (hGroup.FindNextEntry(C4CFN_DefMaterials, MaterialFilename, nullptr, !!*MaterialFilename))
421 	{
422 		StdStrBuf material;
423 		if (hGroup.LoadEntryString(MaterialFilename, &material))
424 		{
425 			try
426 			{
427 				StdStrBuf buf;
428 				buf.Copy(hGroup.GetName());
429 				buf.Append("/"); buf.Append(MaterialFilename);
430 				auto new_materials = ::MeshMaterialManager.Parse(material.getData(), buf.getData(), loader);
431 				mesh_materials.insert(new_materials.begin(), new_materials.end());
432 			}
433 			catch (const StdMeshMaterialError& ex)
434 			{
435 				DebugLogF("Failed to read material script: %s", ex.what());
436 			}
437 		}
438 	}
439 }
440 
LoadParticleDef(C4Group & hGroup)441 bool C4Def::LoadParticleDef(C4Group &hGroup)
442 {
443 	bool fSuccess = true;
444 	// particle def?
445 	if (hGroup.AccessEntry(C4CFN_ParticleCore))
446 	{
447 		// def loading not successful; abort after reading sounds
448 		fSuccess = false;
449 		// create new particle def
450 		C4ParticleDef *pParticleDef = new C4ParticleDef();
451 		// load it
452 		if (!pParticleDef->Load(hGroup))
453 		{
454 			// not successful :( - destroy it again
455 			delete pParticleDef;
456 		}
457 		// done
458 	}
459 	return fSuccess;
460 }
461 
LoadSolidMask(C4Group & hGroup)462 bool C4Def::LoadSolidMask(C4Group &hGroup)
463 {
464 	if (hGroup.FindEntry(C4CFN_SolidMask))
465 	{
466 		pSolidMask = C4SolidMask::LoadMaskFromFile(hGroup, C4CFN_SolidMask);
467 		if (!pSolidMask)
468 		{
469 			DebugLogF("  Error loading SolidMask of %s (%s)", hGroup.GetFullName().getData(), id.ToString());
470 			return false;
471 		}
472 		// check SolidMask size
473 		if (SolidMask.x<0 || SolidMask.y<0 || SolidMask.x + SolidMask.Wdt>pSolidMask->Wdt || SolidMask.y + SolidMask.Hgt>pSolidMask->Hgt) SolidMask.Default();
474 	}
475 	else if (SolidMask.Wdt)
476 	{
477 		// Warning in case someone wants to define SolidMasks the old way (in the main graphics file)
478 		DebugLogF("WARNING: Definition %s (%s) defines SolidMask in DefCore but has no SolidMask file!", hGroup.GetFullName().getData(), id.ToString());
479 		SolidMask.Default();
480 	}
481 
482 	return true;
483 }
484 
LoadGraphics(C4Group & hGroup,StdMeshSkeletonLoader & loader)485 bool C4Def::LoadGraphics(C4Group &hGroup, StdMeshSkeletonLoader &loader)
486 {
487 	// Try to load graphics
488 	// No fail on error - just have an object without graphics.
489 	Graphics.Load(hGroup, loader, !!ColorByOwner);
490 
491 	if (Graphics.Type == C4DefGraphics::TYPE_Bitmap)
492 	{
493 		// Bitmap post-load settings
494 		if (Graphics.GetBitmap())
495 		{
496 			// Set MainFace (unassigned bitmap: will be set by GetMainFace())
497 			MainFace.Set(nullptr, 0, 0, Shape.Wdt, Shape.Hgt);
498 		}
499 
500 		// Adjust picture rect
501 		if ((PictureRect.Wdt == 0) || (PictureRect.Hgt == 0))
502 			PictureRect.Set(0, 0, Shape.Wdt*Graphics.Bmp.Bitmap->Scale, Shape.Hgt*Graphics.Bmp.Bitmap->Scale);
503 
504 		// validate TopFace
505 		if (TopFace.x<0 || TopFace.y<0 || TopFace.x + TopFace.Wdt>Graphics.Bmp.Bitmap->Wdt || TopFace.y + TopFace.Hgt>Graphics.Bmp.Bitmap->Hgt)
506 		{
507 			TopFace.Default();
508 			// warn in debug mode
509 			DebugLogF("invalid TopFace in %s (%s)", GetName(), id.ToString());
510 		}
511 	}
512 	else
513 	{
514 		TopFace.Default();
515 	}
516 
517 	return true;
518 }
519 
LoadScript(C4Group & hGroup,const char * szLanguage)520 void C4Def::LoadScript(C4Group &hGroup, const char* szLanguage)
521 {
522 	// reg script to engine
523 	Script.Reg2List(&::ScriptEngine);
524 	// Load script
525 	Script.Load(hGroup, C4CFN_Script, szLanguage, &StringTable);
526 }
527 
LoadClonkNames(C4Group & hGroup,C4ComponentHost * pClonkNames,const char * szLanguage)528 void C4Def::LoadClonkNames(C4Group &hGroup, C4ComponentHost* pClonkNames, const char* szLanguage)
529 {
530 	// clear any previous
531 	if (pClonkNames) delete pClonkNames; pClonkNames = nullptr;
532 	if (hGroup.FindEntry(C4CFN_ClonkNameFiles))
533 	{
534 		// create new
535 		pClonkNames = new C4ComponentHost();
536 		if (!C4Language::LoadComponentHost(pClonkNames, hGroup, C4CFN_ClonkNames, szLanguage))
537 		{
538 			delete pClonkNames; pClonkNames = nullptr;
539 		}
540 		else
541 			fClonkNamesOwned = true;
542 	}
543 }
544 
LoadRankNames(C4Group & hGroup,const char * szLanguage)545 void C4Def::LoadRankNames(C4Group &hGroup, const char* szLanguage)
546 {
547 	// clear any previous
548 	if (pRankNames) delete pRankNames; pRankNames = nullptr;
549 	if (hGroup.FindEntry(C4CFN_RankNameFiles))
550 	{
551 		// create new
552 		pRankNames = new C4RankSystem();
553 		// load from group
554 		if (!pRankNames->Load(hGroup, C4CFN_RankNames, 1000, szLanguage))
555 		{
556 			delete pRankNames; pRankNames = nullptr;
557 		}
558 		else
559 			fRankNamesOwned = true;
560 	}
561 }
562 
LoadRankFaces(C4Group & hGroup)563 void C4Def::LoadRankFaces(C4Group &hGroup)
564 {
565 	// clear any previous
566 	if (pRankSymbols) delete pRankSymbols; pRankSymbols = nullptr;
567 	// load new
568 	if (hGroup.AccessEntry(C4CFN_RankFacesPNG))
569 	{
570 		pRankSymbols = new C4FacetSurface();
571 		if (!pRankSymbols->GetFace().ReadPNG(hGroup, false)) { delete pRankSymbols; pRankSymbols = nullptr; }
572 	}
573 	// set size
574 	if (pRankSymbols)
575 	{
576 		pRankSymbols->Set(&pRankSymbols->GetFace(), 0, 0, pRankSymbols->GetFace().Hgt, pRankSymbols->GetFace().Hgt);
577 		int32_t Q; pRankSymbols->GetPhaseNum(iNumRankSymbols, Q);
578 		if (!iNumRankSymbols) { delete pRankSymbols; pRankSymbols = nullptr; }
579 		else
580 		{
581 			if (pRankNames)
582 			{
583 				// if extended rank names are defined, subtract those from the symbol count. The last symbols are used as overlay
584 				iNumRankSymbols = std::max<int32_t>(1, iNumRankSymbols - pRankNames->GetExtendedRankNum());
585 			}
586 			fRankSymbolsOwned = true;
587 		}
588 	}
589 }
590 
LoadSounds(C4Group & hGroup,C4SoundSystem * pSoundSystem)591 void C4Def::LoadSounds(C4Group &hGroup, C4SoundSystem* pSoundSystem)
592 {
593 	if (pSoundSystem)
594 		pSoundSystem->LoadEffects(hGroup, (id == C4ID::None) ? nullptr : id.ToString(), true);
595 }
596 
Draw(C4Facet & cgo,bool fSelected,DWORD iColor,C4Object * pObj,int32_t iPhaseX,int32_t iPhaseY,C4DrawTransform * trans,const char * graphicsName)597 void C4Def::Draw(C4Facet &cgo, bool fSelected, DWORD iColor, C4Object *pObj, int32_t iPhaseX, int32_t iPhaseY, C4DrawTransform* trans, const char *graphicsName)
598 {
599 	if(fSelected)
600 		pDraw->DrawBoxDw(cgo.Surface, cgo.X, cgo.Y, cgo.X + cgo.Wdt - 1, cgo.Y + cgo.Hgt - 1, C4RGB(0xca, 0, 0));
601 
602 	C4DefGraphics* graphics = pObj ? pObj->GetGraphics() : &Graphics;
603 	if (graphicsName)
604 	{
605 		C4DefGraphics *other = graphics->Get(graphicsName);
606 		if (other) graphics = other;
607 	}
608 	graphics->Draw(cgo, iColor, pObj, iPhaseX, iPhaseY, trans);
609 }
610 
GetValue(C4Object * pInBase,int32_t iBuyPlayer)611 int32_t C4Def::GetValue(C4Object *pInBase, int32_t iBuyPlayer)
612 {
613 	C4Value r = Call(PSF_CalcDefValue, &C4AulParSet(pInBase, iBuyPlayer));
614 	int32_t iValue = Value;
615 	if (r != C4VNull)
616 		iValue = r.getInt();
617 	// do any adjustments based on where the item is bought
618 	if (pInBase)
619 	{
620 		r = pInBase->Call(PSF_CalcBuyValue, &C4AulParSet(this, iValue));
621 		if (r != C4VNull)
622 			iValue = r.getInt();
623 	}
624 	return iValue;
625 }
626 
Synchronize()627 void C4Def::Synchronize()
628 {
629 }
630 
IncludeDefinition(C4Def * pIncludeDef)631 void C4Def::IncludeDefinition(C4Def *pIncludeDef)
632 {
633 	// inherited rank infos and clonk names, if this definition doesn't have its own
634 	if (!fClonkNamesOwned) pClonkNames = pIncludeDef->pClonkNames;
635 	if (!fRankNamesOwned) pRankNames = pIncludeDef->pRankNames;
636 	if (!fRankSymbolsOwned) { pRankSymbols = pIncludeDef->pRankSymbols; iNumRankSymbols = pIncludeDef->iNumRankSymbols; }
637 }
638 
ResetIncludeDependencies()639 void C4Def::ResetIncludeDependencies()
640 {
641 	// clear all pointers into foreign defs
642 	if (!fClonkNamesOwned) pClonkNames = nullptr;
643 	if (!fRankNamesOwned) pRankNames = nullptr;
644 	if (!fRankSymbolsOwned) { pRankSymbols = nullptr; iNumRankSymbols = 0; }
645 }
646 
GetActionByName(const char * actname)647 C4PropList *C4Def::GetActionByName(const char *actname)
648 {
649 	if (!actname) return nullptr;
650 	C4String * actname_str = Strings.RegString(actname);
651 	actname_str->IncRef();
652 	C4PropList *r = GetActionByName(actname_str);
653 	actname_str->DecRef();
654 	return r;
655 }
656 
GetActionByName(C4String * actname)657 C4PropList *C4Def::GetActionByName(C4String *actname)
658 {
659 	assert(actname);
660 	// If we get the null string or ActIdle by name, return nullptr action
661 	if (!actname || actname == &Strings.P[P_Idle]) return nullptr;
662 	// otherwise, query actmap
663 	C4Value ActMap; GetProperty(P_ActMap, &ActMap);
664 	if (!ActMap.getPropList()) return nullptr;
665 	C4Value Action; ActMap.getPropList()->GetPropertyByS(actname, &Action);
666 	if (!Action.getPropList()) return nullptr;
667 	return Action.getPropList();
668 }
669