OpenClonk
C4Material.cpp
Go to the documentation of this file.
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 /* Material definitions used by the landscape */
19 
20 #include "C4Include.h"
21 #include "landscape/C4Material.h"
22 
23 #include "c4group/C4Components.h"
24 #include "c4group/C4Group.h"
25 #include "editor/C4ToolsDlg.h" // For C4TLS_MatSky...
26 #include "game/C4Physics.h" // For GravAccel
27 #include "landscape/C4PXS.h"
28 #include "landscape/C4Texture.h"
29 #include "landscape/C4Landscape.h"
30 #include "lib/C4Random.h"
31 #include "platform/C4SoundSystem.h"
32 #include "script/C4Aul.h"
33 #include "script/C4Effect.h"
34 
35 
39 // -------------------------------------- C4MaterialReaction
40 
41 
43 
45 {
46  { "Script", &C4MaterialMap::mrfScript },
47  { "Convert", &C4MaterialMap::mrfConvert},
48  { "Poof", &C4MaterialMap::mrfPoof },
49  { "Corrode", &C4MaterialMap::mrfCorrode },
50  { "Insert", &C4MaterialMap::mrfInsert },
51  { nullptr, &C4MaterialReaction::NoReaction }
52 };
53 
54 
56 {
57  if (pComp->isDeserializer()) pScriptFunc = nullptr;
58  // compile reaction func ptr
59  StdStrBuf sReactionFuncName;
60  int32_t i=0; while (ReactionFuncMap[i].szRFName && (ReactionFuncMap[i].pFunc != pFunc)) ++i;
61  sReactionFuncName = ReactionFuncMap[i].szRFName;
62  pComp->Value(mkNamingAdapt(mkParAdapt(sReactionFuncName, StdCompiler::RCT_IdtfAllowEmpty), "Type", StdCopyStrBuf() ));
63  i=0; while (ReactionFuncMap[i].szRFName && !SEqual(ReactionFuncMap[i].szRFName, sReactionFuncName.getData())) ++i;
65  // compile the rest
68  pComp->Value(mkNamingAdapt(iExecMask, "ExecMask", ~0u ));
69  pComp->Value(mkNamingAdapt(fReverse, "Reverse", false ));
70  pComp->Value(mkNamingAdapt(fInverseSpec, "InverseSpec", false ));
71  pComp->Value(mkNamingAdapt(fInsertionCheck, "CheckSlide", true ));
72  pComp->Value(mkNamingAdapt(iDepth, "Depth", 0 ));
74  pComp->Value(mkNamingAdapt(iCorrosionRate, "CorrosionRate", 100 ));
75 }
76 
77 
78 void C4MaterialReaction::ResolveScriptFuncs(const char *szMatName)
79 {
80  // get script func for script-defined behaviour
82  {
84  if (!pScriptFunc)
85  DebugLogF(R"(Error getting function "%s" for Material reaction of "%s")", this->ScriptFunc.getData(), szMatName);
86  }
87  else
88  pScriptFunc = nullptr;
89 }
90 
91 // -------------------------------------- C4MaterialCore
92 
94 {
95  Clear();
96 }
97 
99 {
100  CustomReactionList.clear();
102  sPXSGfx.Clear();
108  *Name='\0';
110  Density = 0;
111  Friction = 0;
112  DigFree = 0;
113  BlastFree = 0;
115  Dig2ObjectRatio = 0;
116  Dig2ObjectCollect = 0;
118  Blast2ObjectRatio = 0;
119  Blast2PXSRatio = 0;
120  Instable = 0;
121  MaxAirSpeed = 0;
122  MaxSlide = 0;
123  WindDrift = 0;
124  Inflammable = 0;
125  Incendiary = 0;
126  Extinguisher = 0;
127  Corrosive = 0;
128  Corrode = 0;
129  Soil = 0;
130  Placement = 0;
131  Light = 0;
132  OverlayType = 0;
133  PXSGfxRt.Default();
134  PXSGfxSize = 0;
135  InMatConvertDepth = 0;
136  BelowTempConvert = 0;
138  AboveTempConvert = 0;
140  TempConvStrength = 0;
141  MinHeightCount = 0;
142  SplashRate=10;
143  KeepSinglePixels=false;
144  AnimationSpeed = 20;
145  LightAngle = 255;
146  for (int i = 0; i < 3; i++) {
147  LightEmit[i] = 0;
148  LightSpot[i] = 16;
149  }
150  MinShapeOverlap = 25;
151 }
152 
154 {
155  Clear();
156 }
157 
159  const char *szEntryName)
160 {
161  StdStrBuf Source;
162  if (!hGroup.LoadEntryString(szEntryName,&Source))
163  return false;
164  StdStrBuf Name = hGroup.GetFullName() + DirSep + szEntryName;
165  if (!CompileFromBuf_LogWarn<StdCompilerINIRead>(*this, Source, Name.getData()))
166  return false;
167  // adjust placement, if not specified
168  if (!Placement)
169  {
170  if (DensitySolid(Density))
171  {
172  Placement=30;
173  if (!DigFree) Placement+=20;
174  if (!BlastFree) Placement+=10;
175  }
176  else if (DensityLiquid(Density))
177  Placement=10;
178  else Placement=5;
179  }
180  return true;
181 }
182 
184 {
185  assert(pComp->hasNaming());
186  if (pComp->isDeserializer()) Clear();
187  pComp->Name("Material");
188  pComp->Value(mkNamingAdapt(toC4CStr(Name), "Name", ""));
189 
190  const StdEnumEntry<C4MaterialCoreShape> Shapes[] =
191  {
192  { "Flat", C4M_Flat },
193  { "TopFlat", C4M_TopFlat },
194  { "Smooth", C4M_Smooth },
195  { "Rough", C4M_Rough },
196  { "Octagon", C4M_Octagon },
197  { "Smoother", C4M_Smoother },
198  { nullptr, C4M_Flat }
199  };
200  pComp->Value(mkNamingAdapt(mkEnumAdaptT<uint8_t>(MapChunkType, Shapes),
201  "Shape", C4M_Flat));
202  pComp->Value(mkNamingAdapt(Density, "Density", 0));
203  pComp->Value(mkNamingAdapt(Friction, "Friction", 0));
204  pComp->Value(mkNamingAdapt(DigFree, "DigFree", 0));
205  pComp->Value(mkNamingAdapt(BlastFree, "BlastFree", 0));
206  pComp->Value(mkNamingAdapt(Blast2Object, "Blast2Object", C4ID::None));
207  pComp->Value(mkNamingAdapt(Dig2Object, "Dig2Object", C4ID::None));
208  pComp->Value(mkNamingAdapt(Dig2ObjectRatio, "Dig2ObjectRatio", 0));
209  pComp->Value(mkNamingAdapt(Dig2ObjectCollect, "Dig2ObjectCollect", 0));
210  pComp->Value(mkNamingAdapt(Blast2ObjectRatio, "Blast2ObjectRatio", 0));
211  pComp->Value(mkNamingAdapt(Blast2PXSRatio, "Blast2PXSRatio", 0));
212  pComp->Value(mkNamingAdapt(Instable, "Instable", 0));
213  pComp->Value(mkNamingAdapt(MaxAirSpeed, "MaxAirSpeed", 0));
214  pComp->Value(mkNamingAdapt(MaxSlide, "MaxSlide", 0));
215  pComp->Value(mkNamingAdapt(WindDrift, "WindDrift", 0));
216  pComp->Value(mkNamingAdapt(Inflammable, "Inflammable", 0));
217  if (pComp->isDeserializer())
218  {
219  // The value used to have a wrong spelling ("Incindiary"). If there's
220  // no "Incendiary" value, use the wrong spelling instead
221  try
222  {
223  pComp->Value(mkNamingAdapt(Incendiary, "Incendiary"));
224  }
226  {
227  delete ex;
228  pComp->Value(mkNamingAdapt(Incendiary, "Incindiary", 0));
229  }
230  }
231  else
232  {
233  // When serializing, write both spellings because some script might be
234  // calling GetMaterialVal with the wrong one
235  pComp->Value(mkNamingAdapt(Incendiary, "Incendiary"));
236  pComp->Value(mkNamingAdapt(Incendiary, "Incindiary"));
237  }
238  pComp->Value(mkNamingAdapt(Corrode, "Corrode", 0));
239  pComp->Value(mkNamingAdapt(Corrosive, "Corrosive", 0));
240  pComp->Value(mkNamingAdapt(Extinguisher, "Extinguisher", 0));
241  pComp->Value(mkNamingAdapt(Soil, "Soil", 0));
242  pComp->Value(mkNamingAdapt(Placement, "Placement", 0));
243  pComp->Value(mkNamingAdapt(Light, "Light", 0));
245  "TextureOverlay", ""));
246  pComp->Value(mkNamingAdapt(OverlayType, "OverlayType", 0));
248  "PXSGfx", ""));
249  pComp->Value(mkNamingAdapt(PXSGfxRt, "PXSGfxRt", TargetRect0));
250  pComp->Value(mkNamingAdapt(PXSGfxSize, "PXSGfxSize", PXSGfxRt.Wdt));
251  pComp->Value(mkNamingAdapt(TempConvStrength, "TempConvStrength", 0));
253  "BlastShiftTo", ""));
255  "InMatConvert", ""));
257  "InMatConvertTo", ""));
258  pComp->Value(mkNamingAdapt(InMatConvertDepth, "InMatConvertDepth", 0));
259  pComp->Value(mkNamingAdapt(AboveTempConvert, "AboveTempConvert", 0));
260  pComp->Value(mkNamingAdapt(AboveTempConvertDir, "AboveTempConvertDir", 0));
262  "AboveTempConvertTo", ""));
263  pComp->Value(mkNamingAdapt(BelowTempConvert, "BelowTempConvert", 0));
264  pComp->Value(mkNamingAdapt(BelowTempConvertDir, "BelowTempConvertDir", 0));
266  "BelowTempConvertTo", ""));
267  pComp->Value(mkNamingAdapt(MinHeightCount, "MinHeightCount", 0));
268  pComp->Value(mkNamingAdapt(SplashRate, "SplashRate", 10));
269  pComp->Value(mkNamingAdapt(KeepSinglePixels, "KeepSinglePixels", false));
270  pComp->Value(mkNamingAdapt(AnimationSpeed, "AnimationSpeed", 100));
271  pComp->Value(mkNamingAdapt(LightAngle, "LightAngle", 255));
272  pComp->Value(mkNamingAdapt(mkArrayAdaptDM(LightEmit, 0), "LightEmit"));
273  pComp->Value(mkNamingAdapt(mkArrayAdaptDM(LightSpot, 16),"LightSpot"));
274  pComp->Value(mkNamingAdapt(MinShapeOverlap, "MinShapeOverlap", 25));
275  pComp->NameEnd();
276  // material reactions
278  "Reaction", std::vector<C4MaterialReaction>()));
279 }
280 
281 
282 // -------------------------------------- C4Material
283 
285 {
286  BlastShiftTo=0;
290 }
291 
293 {
294  for (auto & i : CustomReactionList)
295  i.ResolveScriptFuncs(Name);
296 }
297 
298 
299 // -------------------------------------- C4MaterialMap
300 
301 
302 C4MaterialMap::C4MaterialMap() : DefReactConvert(&mrfConvert), DefReactPoof(&mrfPoof), DefReactCorrode(&mrfCorrode), DefReactIncinerate(&mrfIncinerate), DefReactInsert(&mrfInsert)
303 {
304  Default();
305 }
306 
307 
309 {
310  Clear();
311 }
312 
314 {
315  delete [] Map; Map=nullptr; Num=0;
316  delete [] ppReactionMap; ppReactionMap = nullptr;
317 }
318 
319 int32_t C4MaterialMap::Load(C4Group &hGroup)
320 {
321  char entryname[256+1];
322 
323  // Determine number of materials in files
324  int32_t mat_num=hGroup.EntryCount(C4CFN_MaterialFiles);
325 
326  // Allocate new map
327  C4Material *pNewMap = new C4Material [mat_num + Num];
328  if (!pNewMap) return 0;
329 
330  // Load material cores to map
331  hGroup.ResetSearch(); int32_t cnt=0;
332  while (hGroup.FindNextEntry(C4CFN_MaterialFiles,entryname))
333  {
334  if (cnt >= mat_num) {
335  Log("Internal Error: More materials loaded than expected. Make sure your material file names are unique (ignoring case).");
336  break;
337  }
338  // Load mat
339  if (!pNewMap[cnt].Load(hGroup,entryname))
340  { delete [] pNewMap; return 0; }
341  // A new material?
342  if (Get(pNewMap[cnt].Name) == MNone)
343  cnt++;
344  }
345 
346  // Take over old materials.
347  for (int32_t i = 0; i < Num; i++)
348  {
349  pNewMap[cnt+i] = Map[i];
350  }
351  delete [] Map;
352  Map = pNewMap;
353 
354  // set material number
355  Num+=cnt;
356 
357  return cnt;
358 }
359 
361 {
362  return !!hGroup.EntryCount(C4CFN_MaterialFiles);
363 }
364 
365 int32_t C4MaterialMap::Get(const char *szMaterial)
366 {
367  int32_t cnt;
368  for (cnt=0; cnt<Num; cnt++)
369  if (SEqualNoCase(szMaterial,Map[cnt].Name))
370  return cnt;
371  return MNone;
372 }
373 
374 
375 bool C4MaterialMap::CrossMapMaterials(const char* szEarthMaterial) // Called after load
376 {
377  // Check material number
379  { LogFatal(LoadResStr("IDS_PRC_TOOMANYMATS")); return false; }
380  // build reaction function map
381  delete [] ppReactionMap;
382  typedef C4MaterialReaction * C4MaterialReactionPtr;
383  ppReactionMap = new C4MaterialReactionPtr[(Num+1)*(Num+1)];
384  for (int32_t iMatPXS=-1; iMatPXS<Num; iMatPXS++)
385  {
386  C4Material *pMatPXS = (iMatPXS+1) ? Map+iMatPXS : nullptr;
387  for (int32_t iMatLS=-1; iMatLS<Num; iMatLS++)
388  {
389  C4MaterialReaction *pReaction = nullptr;
390  C4Material *pMatLS = ( iMatLS+1) ? Map+ iMatLS : nullptr;
391  // natural stuff: material conversion here?
392  if (pMatPXS && pMatPXS->sInMatConvert.getLength() && SEqualNoCase(pMatPXS->sInMatConvert.getData(), pMatLS ? pMatLS->Name : C4TLS_MatSky))
393  pReaction = &DefReactConvert;
394  // non-sky reactions
395  else if (pMatPXS && pMatLS)
396  {
397  // incindiary vs extinguisher
398  if ((pMatPXS->Incendiary && pMatLS->Extinguisher) || (pMatPXS->Extinguisher && pMatLS->Incendiary))
399  pReaction = &DefReactPoof;
400  // incindiary vs inflammable
401  else if ((pMatPXS->Incendiary && pMatLS->Inflammable) || (pMatPXS->Inflammable && pMatLS->Incendiary))
402  pReaction = &DefReactIncinerate;
403  // corrosive vs corrode
404  else if (pMatPXS->Corrosive && pMatLS->Corrode)
405  pReaction = &DefReactCorrode;
406  // liquid hitting liquid or solid: Material insertion
407  else if (DensityLiquid(MatDensity(iMatPXS)) && DensitySemiSolid(MatDensity(iMatLS)))
408  pReaction = &DefReactInsert;
409  // solid hitting solid: Material insertion
410  else if (DensitySolid(MatDensity(iMatPXS)) && DensitySolid(MatDensity(iMatLS)))
411  pReaction = &DefReactInsert;
412  }
413  // assign the function; or nullptr for no reaction
414  SetMatReaction(iMatPXS, iMatLS, pReaction);
415  }
416  }
417  // reset max shape size
419  // material-specific initialization
420  int32_t cnt;
421  for (cnt=0; cnt<Num; cnt++)
422  {
423  C4Material *pMat = Map+cnt;
424  const char *szTextureOverlay = nullptr;
425  // newgfx: init pattern
426  if (Map[cnt].sTextureOverlay.getLength())
428  {
429  szTextureOverlay = Map[cnt].sTextureOverlay.getData();
430  // backwards compatibility: if a pattern was specified although the no-pattern flag was set, overwrite that flag
431  if (Map[cnt].OverlayType & C4MatOv_None)
432  {
433  DebugLogF("Error in overlay of material %s: Flag C4MatOv_None ignored because a custom overlay (%s) was specified!", Map[cnt].Name, szTextureOverlay);
434  Map[cnt].OverlayType &= ~C4MatOv_None;
435  }
436  }
437  // default to first texture in texture map
438  int iTexMapIx;
439  if (!szTextureOverlay && (iTexMapIx = ::TextureMap.GetIndex(Map[cnt].Name, nullptr, false)))
440  szTextureOverlay = TextureMap.GetEntry(iTexMapIx)->GetTextureName();
441  // default to smooth
442  if (!szTextureOverlay)
443  szTextureOverlay = "none";
444  // search/create entry in texmap
445  Map[cnt].DefaultMatTex = ::TextureMap.GetIndex(Map[cnt].Name, szTextureOverlay, true,
446  FormatString("DefaultMatTex of mat %s", Map[cnt].Name).getData());
447  // init PXS facet
448  C4Surface * sfcTexture;
449  C4Texture * Texture;
450  if (Map[cnt].sPXSGfx.getLength())
451  if ((Texture=::TextureMap.GetTexture(Map[cnt].sPXSGfx.getData())))
452  if ((sfcTexture=Texture->Surface32))
453  Map[cnt].PXSFace.Set(sfcTexture, Map[cnt].PXSGfxRt.x, Map[cnt].PXSGfxRt.y, Map[cnt].PXSGfxRt.Wdt, Map[cnt].PXSGfxRt.Hgt);
454  // evaluate reactions for that material
455  for (auto & iRCnt : pMat->CustomReactionList)
456  {
457  C4MaterialReaction *pReact = &iRCnt;
458  if (pReact->sConvertMat.getLength()) pReact->iConvertMat = Get(pReact->sConvertMat.getData()); else pReact->iConvertMat = -1;
459  // evaluate target spec
460  int32_t tmat;
461  if (MatValid(tmat=Get(pReact->TargetSpec.getData())))
462  {
463  // single material target
464  if (pReact->fInverseSpec)
465  for (int32_t cnt2=-1; cnt2<Num; cnt2++) {
466  if (cnt2!=tmat)
467  SetMatReaction(cnt, cnt2, pReact);
468  else
469  SetMatReaction(cnt, tmat, pReact);
470  }
471  }
472  else if (SEqualNoCase(pReact->TargetSpec.getData(), "All"))
473  {
474  // add to all materials, including sky
475  if (!pReact->fInverseSpec) for (int32_t cnt2=-1; cnt2<Num; cnt2++) SetMatReaction(cnt, cnt2, pReact);
476  }
477  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Solid"))
478  {
479  // add to all solid materials
480  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
481  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (DensitySolid(Map[cnt2].Density) != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
482  }
483  else if (SEqualNoCase(pReact->TargetSpec.getData(), "SemiSolid"))
484  {
485  // add to all semisolid materials
486  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
487  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (DensitySemiSolid(Map[cnt2].Density) != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
488  }
489  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Background"))
490  {
491  // add to all BG materials, including sky
492  if (!pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
493  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Density != pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
494  }
495  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Sky"))
496  {
497  // add to sky
498  if (!pReact->fInverseSpec)
499  SetMatReaction(cnt, -1, pReact);
500  else
501  for (int32_t cnt2=0; cnt2<Num; cnt2++) SetMatReaction(cnt, cnt2, pReact);
502  }
503  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Incendiary") || SEqualNoCase(pReact->TargetSpec.getData(), "Incindiary"))
504  {
505  // add to all incendiary materials
506  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
507  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Incendiary == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
508  }
509  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Extinguisher"))
510  {
511  // add to all incendiary materials
512  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
513  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Extinguisher == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
514  }
515  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Inflammable"))
516  {
517  // add to all incendiary materials
518  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
519  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Inflammable == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
520  }
521  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Corrosive"))
522  {
523  // add to all incendiary materials
524  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
525  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Corrosive == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
526  }
527  else if (SEqualNoCase(pReact->TargetSpec.getData(), "Corrode"))
528  {
529  // add to all incendiary materials
530  if (pReact->fInverseSpec) SetMatReaction(cnt, -1, pReact);
531  for (int32_t cnt2=0; cnt2<Num; cnt2++) if (!Map[cnt2].Corrode == pReact->fInverseSpec) SetMatReaction(cnt, cnt2, pReact);
532  }
533  }
534  }
535  // second loop (DefaultMatTex is needed by GetIndexMatTex)
536  for (cnt=0; cnt<Num; cnt++)
537  {
538  if (Map[cnt].sBlastShiftTo.getLength())
539  Map[cnt].BlastShiftTo=::TextureMap.GetIndexMatTex(Map[cnt].sBlastShiftTo.getData(), nullptr, true, FormatString("BlastShiftTo of mat %s", Map[cnt].Name).getData());
540  if (Map[cnt].sInMatConvertTo.getLength())
541  Map[cnt].InMatConvertTo=Get(Map[cnt].sInMatConvertTo.getData());
542  if (Map[cnt].sBelowTempConvertTo.getLength())
543  Map[cnt].BelowTempConvertTo=::TextureMap.GetIndexMatTex(Map[cnt].sBelowTempConvertTo.getData(), nullptr, true, FormatString("BelowTempConvertTo of mat %s", Map[cnt].Name).getData());
544  if (Map[cnt].sAboveTempConvertTo.getLength())
545  Map[cnt].AboveTempConvertTo=::TextureMap.GetIndexMatTex(Map[cnt].sAboveTempConvertTo.getData(), nullptr, true, FormatString("AboveTempConvertTo of mat %s", Map[cnt].Name).getData());
546  }
547 
548  // Get hardcoded system material indices
549  const C4TexMapEntry* earth_entry = ::TextureMap.GetEntry(::TextureMap.GetIndexMatTex(szEarthMaterial));
550  if(!earth_entry)
551  { LogFatal(FormatString(R"(Earth material "%s" not found!)", szEarthMaterial).getData()); return false; }
552 
553  MVehic = Get("Vehicle"); MCVehic = Mat2PixColDefault(MVehic);
555  MTunnel = Get("Tunnel");
556  MWater = Get("Water");
557  MEarth = Get(earth_entry->GetMaterialName());
558 
559  if ((MVehic==MNone) || (MTunnel==MNone))
560  { LogFatal(LoadResStr("IDS_PRC_NOSYSMATS")); return false; }
561 
562  return true;
563 }
564 
565 
566 void C4MaterialMap::SetMatReaction(int32_t iPXSMat, int32_t iLSMat, C4MaterialReaction *pReact)
567 {
568  // evaluate reaction swap
569  if (pReact && pReact->fReverse) std::swap(iPXSMat, iLSMat);
570  // set it
571  ppReactionMap[(iLSMat+1)*(Num+1) + iPXSMat+1] = pReact;
572 }
573 
575 {
576  char *mapbuf = new char [1000];
577  mapbuf[0]=0;
578  SAppend("[Enumeration]",mapbuf); SAppend("\n",mapbuf);
579  for (int32_t cnt=0; cnt<Num; cnt++)
580  {
581  SAppend(Map[cnt].Name,mapbuf);
582  SAppend("\n",mapbuf);
583  }
584  return hGroup.Add(C4CFN_MatMap,mapbuf,SLen(mapbuf),false,true);
585 }
586 
588 {
589  // Load enumeration map (from savegame), succeed if not present
590  StdStrBuf mapbuf;
591  if (!hGroup.LoadEntryString(C4CFN_MatMap, &mapbuf)) return true;
592 
593  // Sort material array by enumeration map, fail if some missing
594  const char *csearch;
595  char cmatname[C4M_MaxName+1];
596  int32_t cmat=0;
597  if (!(csearch = SSearch(mapbuf.getData(),"[Enumeration]"))) { return false; }
598  csearch=SAdvanceSpace(csearch);
599  while (IsIdentifier(*csearch))
600  {
601  SCopyIdentifier(csearch,cmatname,C4M_MaxName);
602  if (!SortEnumeration(cmat,cmatname))
603  {
604  // Output error message!
605  return false;
606  }
607  cmat++;
608  csearch+=SLen(cmatname);
609  csearch=SAdvanceSpace(csearch);
610  }
611 
612  return true;
613 }
614 
615 bool C4MaterialMap::SortEnumeration(int32_t iMat, const char *szMatName)
616 {
617 
618  // Not enough materials loaded
619  if (iMat>=Num) return false;
620 
621  // Find requested mat
622  int32_t cmat;
623  for (cmat=iMat; cmat<Num; cmat++)
624  if (SEqual(szMatName,Map[cmat].Name))
625  break;
626  // Not found
627  if (cmat>=Num) return false;
628 
629  // already the same?
630  if (cmat == iMat) return true;
631 
632  // Move requested mat to indexed position
633  C4Material mswap;
634  mswap = Map[iMat];
635  Map[iMat] = Map[cmat];
636  Map[cmat] = mswap;
637 
638  return true;
639 }
640 
642 {
643  Num=0;
644  Map=nullptr;
645  ppReactionMap=nullptr;
647 }
648 
649 C4MaterialReaction *C4MaterialMap::GetReaction(int32_t iPXSMat, int32_t iLandscapeMat)
650 {
651  // safety
652  if (!ppReactionMap) return nullptr;
653  if (!Inside<int32_t>(iPXSMat, -1, Num-1)) return nullptr;
654  if (!Inside<int32_t>(iLandscapeMat, -1, Num-1)) return nullptr;
655  // values OK; get func!
656  return GetReactionUnsafe(iPXSMat, iLandscapeMat);
657 }
658 
659 static void Smoke(int32_t tx, int32_t ty, int32_t level)
660 {
661  // Use scripted function (global func Smoke) to create smoke
662  // Caution: This makes engine internal smoking a synced call.
663  C4AulParSet pars(tx, ty, level);
665 }
666 
667 bool mrfInsertCheck(int32_t &iX, int32_t &iY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, bool *pfPosChanged, bool no_slide = false)
668 {
669  // always manipulating pos/speed here
670  if (pfPosChanged) *pfPosChanged = true;
671 
672  // Move up by up to 3px to account for moving SolidMasks, other material insertions, etc.
673  int32_t mdens = std::min(::MaterialMap.Map[iPxsMat].Density, C4M_Solid);
674  int32_t max_upwards = 3;
675  bool was_pushed_upwards = false;
676  while (max_upwards-- && (::Landscape.GetDensity(iX, iY) >= mdens))
677  {
678  --iY;
679  was_pushed_upwards = true;
680  }
681 
682  // Rough contact? May splash
683  if (fYDir > itofix(1))
684  if (::MaterialMap.Map[iPxsMat].SplashRate && !Random(::MaterialMap.Map[iPxsMat].SplashRate))
685  {
686  fYDir = -fYDir/8;
687  fXDir = fXDir/8 + C4REAL100(Random(200) - 100);
688  if (fYDir) return false;
689  }
690 
691  // Contact: Stop
692  fYDir = -GravAccel;
693 
694  // Incendiary mats smoke on contact even before doing their slide
695  if (::MaterialMap.Map[iPxsMat].Incendiary)
696  if (!Random(25))
697  {
698  Smoke(iX, iY, 4 + Random(3));
699  }
700 
701  // Move by mat path/slide
702  int32_t iSlideX = iX, iSlideY = iY;
703 
704  if (!no_slide && ::Landscape.FindMatSlide(iSlideX,iSlideY,Sign(GravAccel),mdens,::MaterialMap.Map[iPxsMat].MaxSlide))
705  {
706  // Sliding on equal material: Move directly to optimize insertion of rain onto lakes
707  // Also move directly when shifted upwards to ensure movement on permamently moving SolidMask
708  if (iPxsMat == iLsMat || was_pushed_upwards)
709  {
710  iX = iSlideX;
711  iY = iSlideY;
712  fXDir = 0;
713  if (was_pushed_upwards)
714  {
715  // When pushed upwards and slide was found into a target position, insert directly to allow additional PXS at same location to solidify in next position in same frame
716  if (::Landscape.GetDensity(iX, iY + Sign(GravAccel)) >= mdens)
717  {
718  return true;
719  }
720  }
721  // Continue existing (and fall down next frame)
722  return false;
723  }
724  // Otherwise, just move using xdir/ydir for nice visuals when rain is moving over landscape
725  // Accelerate into the direction
726  fXDir = (fXDir * 10 + Sign(iSlideX - iX)) / 11 + C4REAL10(Random(5)-2);
727  // Slide target in range? Move there directly.
728  if (Abs(iX - iSlideX) <= Abs(fixtoi(fXDir)))
729  {
730  iX = iSlideX;
731  iY = iSlideY;
732  if (fYDir <= 0) fXDir = 0;
733  }
734  // Continue existance
735  return false;
736  }
737  // insertion OK
738  return true;
739 }
740 
741 bool mrfUserCheck(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
742 {
743  // check execution mask
744  if ((1<<evEvent) & ~pReaction->iExecMask) return false;
745  // do splash/slide check, if desired
746  if (pReaction->fInsertionCheck && evEvent == meePXSMove)
747  if (!mrfInsertCheck(iX, iY, fXDir, fYDir, iPxsMat, iLsMat, pfPosChanged))
748  return false;
749  // checks OK; reaction may be applied
750  return true;
751 }
752 
753 bool C4MaterialMap::mrfConvert(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
754 {
755  if (pReaction->fUserDefined) if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged)) return false;
756  switch (evEvent)
757  {
758  case meePXSMove: // PXS movement
759  // for hardcoded stuff: only InMatConvert is Snow in Water, which does not have any collision proc
760  if (!pReaction->fUserDefined) break;
761  // user-defined conversions may also convert upon hitting materials
762 
763  case meePXSPos: // PXS check before movement
764  {
765  // Check depth
766  int32_t iDepth = pReaction->fUserDefined ? pReaction->iDepth : ::MaterialMap.Map[iPxsMat].InMatConvertDepth;
767  if (!iDepth || GBackMat(iX, iY - iDepth) == iLsMat)
768  {
769  // Convert
770  iPxsMat = pReaction->fUserDefined ? pReaction->iConvertMat : ::MaterialMap.Map[iPxsMat].InMatConvertTo;
771  if (!MatValid(iPxsMat))
772  // Convert failure (target mat not be loaded, or target may be C4TLS_MatSky): Kill Pix
773  return true;
774  // stop movement after conversion
775  fXDir = fYDir = 0;
776  if (pfPosChanged) *pfPosChanged = true;
777  }
778  }
779  break;
780 
781  case meeMassMove: // MassMover-movement
782  // Conversion-transfer to PXS
783  ::PXS.Create(iPxsMat,itofix(iX),itofix(iY));
784  return true;
785  }
786  // not handled
787  return false;
788 }
789 
790 bool C4MaterialMap::mrfPoof(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
791 {
792  if (pReaction->fUserDefined) if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged)) return false;
793  switch (evEvent)
794  {
795  case meeMassMove: // MassMover-movement
796  case meePXSPos: // PXS check before movement: Kill both landscape and PXS mat
797  ::Landscape.ExtractMaterial(iLSPosX,iLSPosY,false);
798  if (!Random(3)) Smoke(iX,iY,3);
799  if (!Random(3)) StartSoundEffectAt("Liquids::Pshshsh", iX, iY);
800  return true;
801 
802  case meePXSMove: // PXS movement
803  // incindiary/extinguisher/corrosives are always same density proc; so do insertion check first
804  // Do not allow sliding though (e.g. water on lava).
805  if (!pReaction->fUserDefined)
806  if (!mrfInsertCheck(iX, iY, fXDir, fYDir, iPxsMat, iLsMat, pfPosChanged, true))
807  // either splash or slide prevented interaction
808  return false;
809  // Always kill both landscape and PXS mat
810  ::Landscape.ExtractMaterial(iLSPosX,iLSPosY,false);
811  if (!Random(3)) Smoke(iX,iY,3);
812  if (!Random(3)) StartSoundEffectAt("Liquids::Pshshsh", iX, iY);
813  return true;
814  }
815  // not handled
816  return false;
817 }
818 
819 bool C4MaterialMap::mrfCorrode(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
820 {
821  if (pReaction->fUserDefined) if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged)) return false;
822  switch (evEvent)
823  {
824  case meePXSPos: // PXS check before movement
825  // No corrosion - it would make acid incredibly effective
826  break;
827  case meeMassMove: // MassMover-movement
828  {
829  // evaluate corrosion percentage
830  bool fDoCorrode; int d100 = Random(100);
831  if (pReaction->fUserDefined)
832  fDoCorrode = (d100 < pReaction->iCorrosionRate);
833  else
834  fDoCorrode = (d100 < ::MaterialMap.Map[iPxsMat].Corrosive) && (d100 < ::MaterialMap.Map[iLsMat].Corrode);
835  if (fDoCorrode)
836  {
837  ::Landscape.ClearPix(iLSPosX,iLSPosY);
838  //::Landscape.CheckInstabilityRange(iLSPosX,iLSPosY); - more correct, but makes acid too effective as well
839  if (!Random(5))
840  {
841  Smoke(iX, iY, 3 + Random(3));
842  }
843  if (!Random(20)) StartSoundEffectAt("Liquids::Corrode", iX, iY);
844  return true;
845  }
846  }
847  break;
848 
849  case meePXSMove: // PXS movement
850  {
851  // corrodes to corrosives are always same density proc; so do insertion check first
852  if (!pReaction->fUserDefined)
853  if (!mrfInsertCheck(iX, iY, fXDir, fYDir, iPxsMat, iLsMat, pfPosChanged))
854  // either splash or slide prevented interaction
855  return false;
856  // evaluate corrosion percentage
857  bool fDoCorrode; int d100 = Random(100);
858  if (pReaction->fUserDefined)
859  fDoCorrode = (d100 < pReaction->iCorrosionRate);
860  else
861  fDoCorrode = (d100 < ::MaterialMap.Map[iPxsMat].Corrosive) && (d100 < ::MaterialMap.Map[iLsMat].Corrode);
862  if (fDoCorrode)
863  {
864  ::Landscape.ClearPix(iLSPosX,iLSPosY);
865  ::Landscape.CheckInstabilityRange(iLSPosX,iLSPosY);
866  if (!Random(5))
867  {
868  Smoke(iX,iY,3+Random(3));
869  }
870  if (!Random(20)) StartSoundEffectAt("Liquids::Corrode", iX, iY);
871  return true;
872  }
873  // Else: dead. Insert material here
874  ::Landscape.InsertMaterial(iPxsMat,&iX,&iY);
875  return true;
876  }
877  }
878  // not handled
879  return false;
880 }
881 
882 bool C4MaterialMap::mrfIncinerate(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
883 {
884  // not available as user reaction
885  assert(!pReaction->fUserDefined);
886  switch (evEvent)
887  {
888  case meeMassMove: // MassMover-movement
889  case meePXSPos: // PXS check before movement
890  if (::Landscape.Incinerate(iX, iY, NO_OWNER)) return true;
891  break;
892 
893  case meePXSMove: // PXS movement
894  // incinerate to inflammables are always same density proc; so do insertion check first
895  if (!mrfInsertCheck(iX, iY, fXDir, fYDir, iPxsMat, iLsMat, pfPosChanged))
896  // either splash or slide prevented interaction
897  return false;
898  // evaluate inflammation (should always succeed)
899  if (::Landscape.Incinerate(iX, iY, NO_OWNER)) return true;
900  // Else: dead. Insert material here
901  ::Landscape.InsertMaterial(iPxsMat,&iX,&iY);
902  return true;
903  }
904  // not handled
905  return false;
906 }
907 
908 bool C4MaterialMap::mrfInsert(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
909 {
910  if (pReaction->fUserDefined) if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged)) return false;
911  switch (evEvent)
912  {
913  case meePXSPos: // PXS check before movement
914  break;
915 
916  case meePXSMove: // PXS movement
917  {
918  // check for bounce/slide
919  if (!pReaction->fUserDefined)
920  if (!mrfInsertCheck(iX, iY, fXDir, fYDir, iPxsMat, iLsMat, pfPosChanged))
921  // continue existing
922  return false;
923  // Else: dead. Insert material here
924  ::Landscape.InsertMaterial(iPxsMat,&iX,&iY);
925  return true;
926  }
927 
928  case meeMassMove: // MassMover-movement
929  break;
930  }
931  // not handled
932  return false;
933 }
934 
935 bool C4MaterialMap::mrfScript(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
936 {
937  // do generic checks for user-defined reactions
938  if (!mrfUserCheck(pReaction, iX, iY, iLSPosX, iLSPosY, fXDir, fYDir, iPxsMat, iLsMat, evEvent, pfPosChanged))
939  return false;
940 
941  // check script func
942  if (!pReaction->pScriptFunc) return false;
943  // OK - let's call it!
944  // 0 1 2 3 4 5 6 7 8
945  int32_t iXDir1, iYDir1, iXDir2, iYDir2;
946  C4AulParSet pars(iX, iY, iLSPosX, iLSPosY, iXDir1 = fixtoi(fXDir, 100), iYDir1 = fixtoi(fYDir, 100), iPxsMat, iLsMat, int(evEvent));
947  if (!!pReaction->pScriptFunc->Exec(nullptr, &pars, false))
948  {
949  // PXS shall be killed!
950  return true;
951  }
952  // PXS shall exist further: write back parameters
953  iPxsMat = pars[6].getInt();
954  int32_t iX2 = pars[0].getInt(), iY2 = pars[1].getInt();
955  iXDir2 = pars[4].getInt(); iYDir2 = pars[5].getInt();
956  if (iX!=iX2 || iY!=iY2 || iXDir1!=iXDir2 || iYDir1!=iYDir2)
957  {
958  // changes to pos/speed detected
959  if (pfPosChanged) *pfPosChanged = true;
960  iX=iX2; iY=iY2;
961  fXDir = C4REAL100(iXDir2);
962  fYDir = C4REAL100(iYDir2);
963  }
964  // OK; done
965  return false;
966 }
967 
969 {
970  // update in all materials
971  for (int32_t i=0; i<Num; ++i) Map[i].UpdateScriptPointers();
972 }
973 
#define C4CFN_MatMap
Definition: C4Components.h:81
#define C4CFN_MaterialFiles
Definition: C4Components.h:169
const int C4M_MaxName
Definition: C4Constants.h:49
const int32_t C4M_Solid
Definition: C4Constants.h:172
const int32_t MNone
Definition: C4Constants.h:177
const int NO_OWNER
Definition: C4Constants.h:137
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
C4Landscape Landscape
bool DensitySolid(int32_t dens)
Definition: C4Landscape.h:196
const int32_t C4MaxMaterial
Definition: C4Landscape.h:25
bool DensitySemiSolid(int32_t dens)
Definition: C4Landscape.h:201
int32_t GBackMat(int32_t x, int32_t y)
Definition: C4Landscape.h:219
bool DensityLiquid(int32_t dens)
Definition: C4Landscape.h:206
const char * LoadResStr(const char *id)
Definition: C4Language.h:83
bool Log(const char *szMessage)
Definition: C4Log.cpp:204
bool LogFatal(const char *szMessage)
Definition: C4Log.cpp:239
bool DebugLogF(const char *strMessage ...)
Definition: C4Log.cpp:290
BYTE MCVehic
Definition: C4Material.cpp:37
int32_t MEarth
Definition: C4Material.cpp:36
const char * szRFName
Definition: C4Material.cpp:42
int32_t MWater
Definition: C4Material.cpp:36
const ReactionFuncMapEntry ReactionFuncMap[]
Definition: C4Material.cpp:44
int32_t MVehic
Definition: C4Material.cpp:36
bool mrfInsertCheck(int32_t &iX, int32_t &iY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, bool *pfPosChanged, bool no_slide=false)
Definition: C4Material.cpp:667
int32_t MTunnel
Definition: C4Material.cpp:36
C4MaterialMap MaterialMap
Definition: C4Material.cpp:974
int32_t MHalfVehic
Definition: C4Material.cpp:36
C4MaterialReactionFunc pFunc
Definition: C4Material.cpp:42
BYTE MCHalfVehic
Definition: C4Material.cpp:38
bool mrfUserCheck(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:741
Definition: C4Material.cpp:42
bool MatValid(int32_t mat)
Definition: C4Material.h:210
#define C4MatOv_None
Definition: C4Material.h:31
BYTE Mat2PixColDefault(int32_t mat)
Definition: C4Material.h:235
MaterialInteractionEvent
Definition: C4Material.h:35
@ meePXSPos
Definition: C4Material.h:36
@ meeMassMove
Definition: C4Material.h:38
@ meePXSMove
Definition: C4Material.h:37
@ C4M_Smooth
Definition: C4Material.h:75
@ C4M_Octagon
Definition: C4Material.h:77
@ C4M_TopFlat
Definition: C4Material.h:74
@ C4M_Rough
Definition: C4Material.h:76
@ C4M_Smoother
Definition: C4Material.h:78
@ C4M_Flat
Definition: C4Material.h:73
bool(* C4MaterialReactionFunc)(struct C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.h:41
int32_t MatDensity(int32_t mat)
Definition: C4Material.h:240
C4PXSSystem PXS
Definition: C4PXS.cpp:423
#define GravAccel
Definition: C4Physics.h:27
uint32_t Random()
Definition: C4Random.cpp:43
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
C4Real C4REAL100(int x)
Definition: C4Real.h:267
C4Real C4REAL10(int x)
Definition: C4Real.h:269
const C4TargetRect TargetRect0(0, 0, 0, 0, 0, 0)
@ P_Smoke
C4TextureMap TextureMap
Definition: C4Texture.cpp:576
#define C4TLS_MatSky
Definition: C4ToolsDlg.h:39
#define DirSep
uint8_t BYTE
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:369
bool IsIdentifier(char cChar)
Definition: Standard.cpp:90
const char * SAdvanceSpace(const char *szSPos)
Definition: Standard.cpp:420
bool SEqualNoCase(const char *szStr1, const char *szStr2, int iLen)
Definition: Standard.cpp:213
void SAppend(const char *szSource, char *szTarget, int iMaxL)
Definition: Standard.cpp:263
void SCopyIdentifier(const char *szSource, char *sTarget, int iMaxL)
Definition: Standard.cpp:449
int Sign(T val)
Definition: Standard.h:45
T Abs(T val)
Definition: Standard.h:42
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
size_t SLen(const char *sptr)
Definition: Standard.h:74
StdArrayDefaultAdapt< T, D > mkArrayAdaptDM(T(&array)[size], const D &rDefault)
Definition: StdAdaptors.h:392
StdSTLContainerAdapt< C > mkSTLContainerAdapt(C &rTarget, StdCompiler::Sep eSep=StdCompiler::SEP_SEP)
Definition: StdAdaptors.h:713
StdParameterAdapt< T, P > mkParAdapt(T &&rObj, P &&rPar)
Definition: StdAdaptors.h:490
StdNamingAdapt< T > mkNamingAdapt(T &&rValue, const char *szName)
Definition: StdAdaptors.h:92
#define toC4CStr(szString)
Definition: StdAdaptors.h:24
Definition: StdAdaptors.h:795
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
C4Value Exec(C4PropList *p=nullptr, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4AulFunc.h:72
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
void Set(C4Surface &rSfc)
Definition: C4Facet.cpp:459
Definition: C4Real.h:59
bool FindNextEntry(const char *wildcard, StdStrBuf *filename=nullptr, size_t *size=nullptr, bool start_at_filename=false)
Definition: C4Group.cpp:2217
int EntryCount(const char *wildcard=nullptr)
Definition: C4Group.cpp:2314
StdStrBuf GetFullName() const
Definition: C4Group.cpp:2638
bool Add(const char *filename, const char *entry_name)
Definition: C4Group.cpp:1621
bool LoadEntryString(const char *entry_name, StdStrBuf *buffer)
Definition: C4Group.cpp:2430
void ResetSearch(bool reload_contents=false)
Definition: C4Group.cpp:1316
static const C4ID None
Definition: C4Id.h:39
int32_t ExtractMaterial(int32_t fx, int32_t fy, bool distant_first)
int32_t GetDensity(int32_t x, int32_t y) const
bool FindMatSlide(int32_t &fx, int32_t &fy, int32_t ydir, int32_t mdens, int32_t mslide) const
void CheckInstabilityRange(int32_t tx, int32_t ty)
bool InsertMaterial(int32_t mat, int32_t *tx, int32_t *ty, int32_t vx=0, int32_t vy=0, bool query_only=false)
bool ClearPix(int32_t tx, int32_t ty)
bool Incinerate(int32_t x, int32_t y, int32_t cause_player)
bool KeepSinglePixels
Definition: C4Material.h:132
int32_t Friction
Definition: C4Material.h:93
StdCopyStrBuf sBelowTempConvertTo
Definition: C4Material.h:125
int32_t Incendiary
Definition: C4Material.h:107
StdCopyStrBuf sBlastShiftTo
Definition: C4Material.h:119
int32_t TempConvStrength
Definition: C4Material.h:129
C4MaterialCoreShape MapChunkType
Definition: C4Material.h:91
int32_t Corrode
Definition: C4Material.h:110
int32_t Dig2ObjectRatio
Definition: C4Material.h:97
int32_t Blast2ObjectRatio
Definition: C4Material.h:100
char Name[C4M_MaxName+1]
Definition: C4Material.h:89
int32_t Corrosive
Definition: C4Material.h:109
void CompileFunc(StdCompiler *pComp)
Definition: C4Material.cpp:183
int32_t Placement
Definition: C4Material.h:112
int32_t Soil
Definition: C4Material.h:111
C4TargetRect PXSGfxRt
Definition: C4Material.h:117
int32_t WindDrift
Definition: C4Material.h:105
std::vector< C4MaterialReaction > CustomReactionList
Definition: C4Material.h:87
StdCopyStrBuf sAboveTempConvertTo
Definition: C4Material.h:128
int32_t Density
Definition: C4Material.h:92
int32_t LightSpot[3]
Definition: C4Material.h:136
int32_t InMatConvertDepth
Definition: C4Material.h:122
int32_t Extinguisher
Definition: C4Material.h:108
int32_t MinShapeOverlap
Definition: C4Material.h:137
int32_t BlastFree
Definition: C4Material.h:95
StdCopyStrBuf sTextureOverlay
Definition: C4Material.h:114
int32_t LightEmit[3]
Definition: C4Material.h:135
int32_t DigFree
Definition: C4Material.h:94
int32_t OverlayType
Definition: C4Material.h:115
int32_t AboveTempConvertDir
Definition: C4Material.h:127
int32_t Blast2PXSRatio
Definition: C4Material.h:101
int32_t AboveTempConvert
Definition: C4Material.h:126
int32_t Inflammable
Definition: C4Material.h:106
int32_t SplashRate
Definition: C4Material.h:131
int32_t MinHeightCount
Definition: C4Material.h:130
bool Load(C4Group &hGroup, const char *szEntryName)
Definition: C4Material.cpp:158
StdCopyStrBuf sInMatConvert
Definition: C4Material.h:120
StdCopyStrBuf sPXSGfx
Definition: C4Material.h:116
int32_t Instable
Definition: C4Material.h:102
int32_t LightAngle
Definition: C4Material.h:134
int32_t MaxAirSpeed
Definition: C4Material.h:103
int32_t BelowTempConvert
Definition: C4Material.h:123
int32_t Dig2ObjectCollect
Definition: C4Material.h:98
int32_t PXSGfxSize
Definition: C4Material.h:118
StdCopyStrBuf sInMatConvertTo
Definition: C4Material.h:121
int32_t BelowTempConvertDir
Definition: C4Material.h:124
int32_t Light
Definition: C4Material.h:113
int32_t AnimationSpeed
Definition: C4Material.h:133
int32_t MaxSlide
Definition: C4Material.h:104
C4ID Blast2Object
Definition: C4Material.h:99
void UpdateScriptPointers()
Definition: C4Material.cpp:292
int32_t AboveTempConvertTo
Definition: C4Material.h:154
C4Facet PXSFace
Definition: C4Material.h:157
int32_t InMatConvertTo
Definition: C4Material.h:152
int32_t BelowTempConvertTo
Definition: C4Material.h:153
int32_t BlastShiftTo
Definition: C4Material.h:151
int32_t DefaultMatTex
Definition: C4Material.h:155
C4MaterialReaction DefReactConvert
Definition: C4Material.h:173
bool SaveEnumeration(C4Group &hGroup)
Definition: C4Material.cpp:574
C4MaterialReaction DefReactPoof
Definition: C4Material.h:173
C4MaterialReaction DefReactIncinerate
Definition: C4Material.h:173
bool HasMaterials(C4Group &hGroup) const
Definition: C4Material.cpp:360
int32_t max_shape_height
Definition: C4Material.h:171
static bool mrfPoof(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:790
C4MaterialReaction * GetReactionUnsafe(int32_t iPXSMat, int32_t iLandscapeMat)
Definition: C4Material.h:191
int32_t Num
Definition: C4Material.h:168
static bool mrfScript(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:935
bool SortEnumeration(int32_t iMat, const char *szMatName)
Definition: C4Material.cpp:615
C4Material * Map
Definition: C4Material.h:169
C4MaterialReaction * GetReaction(int32_t iPXSMat, int32_t iLandscapeMat)
Definition: C4Material.cpp:649
void SetMatReaction(int32_t iPXSMat, int32_t iLSMat, C4MaterialReaction *pReact)
Definition: C4Material.cpp:566
static bool mrfConvert(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:753
void UpdateScriptPointers()
Definition: C4Material.cpp:968
static bool mrfInsert(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:908
bool LoadEnumeration(C4Group &hGroup)
Definition: C4Material.cpp:587
static bool mrfIncinerate(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:882
C4MaterialReaction DefReactInsert
Definition: C4Material.h:173
C4MaterialReaction ** ppReactionMap
Definition: C4Material.h:170
int32_t Get(const char *szMaterial)
Definition: C4Material.cpp:365
int32_t max_shape_width
Definition: C4Material.h:171
C4MaterialReaction DefReactCorrode
Definition: C4Material.h:173
int32_t Load(C4Group &hGroup)
Definition: C4Material.cpp:319
bool CrossMapMaterials(const char *szEarthMaterial)
Definition: C4Material.cpp:375
static bool mrfCorrode(C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.cpp:819
bool Create(int32_t mat, C4Real ix, C4Real iy, C4Real ixdir=Fix0, C4Real iydir=Fix0)
Definition: C4PXS.cpp:175
C4AulFunc * GetFunc(C4PropertyName k) const
Definition: C4PropList.h:109
C4Value Call(C4PropertyName k, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4PropList.h:114
int32_t y
Definition: C4Rect.h:30
int32_t Hgt
Definition: C4Rect.h:30
int32_t Wdt
Definition: C4Rect.h:30
void Default()
Definition: C4Rect.cpp:39
Definition: C4Texture.h:49
const char * GetTextureName() const
Definition: C4Texture.h:61
const char * GetMaterialName() const
Definition: C4Texture.h:60
C4Surface * Surface32
Definition: C4Texture.h:35
int32_t GetIndex(const char *szMaterial, const char *szTexture, bool fAddIfNotExist=true, const char *szErrorIfFailed=nullptr)
Definition: C4Texture.cpp:414
int32_t GetIndexMatTex(const char *szMaterialTexture, const char *szDefaultTexture=nullptr, bool fAddIfNotExist=true, const char *szErrorIfFailed=nullptr)
Definition: C4Texture.cpp:441
const char * GetTexture(int32_t iIndex)
Definition: C4Texture.cpp:494
const C4TexMapEntry * GetEntry(int32_t iIndex) const
Definition: C4Texture.h:85
void Value(const T &rStruct)
Definition: StdCompiler.h:161
virtual void NameEnd(bool fBreak=false)
Definition: StdCompiler.h:78
virtual bool isDeserializer()
Definition: StdCompiler.h:53
@ RCT_IdtfAllowEmpty
Definition: StdCompiler.h:140
virtual bool Name(const char *szName)
Definition: StdCompiler.h:77
virtual bool hasNaming()
Definition: StdCompiler.h:58
const char * getData() const
Definition: StdBuf.h:442
void Clear()
Definition: StdBuf.h:466
size_t getLength() const
Definition: StdBuf.h:445
static bool NoReaction(struct C4MaterialReaction *pReaction, int32_t &iX, int32_t &iY, int32_t iLSPosX, int32_t iLSPosY, C4Real &fXDir, C4Real &fYDir, int32_t &iPxsMat, int32_t iLsMat, MaterialInteractionEvent evEvent, bool *pfPosChanged)
Definition: C4Material.h:45
C4MaterialReactionFunc pFunc
Definition: C4Material.h:47
StdCopyStrBuf sConvertMat
Definition: C4Material.h:57
uint32_t iExecMask
Definition: C4Material.h:52
C4AulFunc * pScriptFunc
Definition: C4Material.h:51
StdCopyStrBuf ScriptFunc
Definition: C4Material.h:50
void CompileFunc(StdCompiler *pComp)
Definition: C4Material.cpp:55
int32_t iCorrosionRate
Definition: C4Material.h:59
int32_t iConvertMat
Definition: C4Material.h:58
StdCopyStrBuf TargetSpec
Definition: C4Material.h:49
void ResolveScriptFuncs(const char *szMatName)
Definition: C4Material.cpp:78
class C4SoundInstance * StartSoundEffectAt(const char *, int32_t, int32_t, int32_t, int32_t, int32_t, class C4SoundModifier *)
Definition: stub-handle.cpp:41