OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4MapCreatorS2.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // complex dynamic landscape creator
17 
18 #include "C4Include.h"
20 
21 #include "control/C4Record.h"
22 #include "graphics/CSurface8.h"
23 #include "landscape/C4Material.h"
24 #include "landscape/C4Texture.h"
25 #include "lib/C4Random.h"
26 #include "script/C4ScriptHost.h"
27 
28 namespace {
29  // node attribute entry for SetField search
31  {
32  C4MCV_None,
33  C4MCV_Integer,
34  C4MCV_Percent,
35  C4MCV_Pixels,
36  C4MCV_Material,
37  C4MCV_Texture,
38  C4MCV_Algorithm,
39  C4MCV_Boolean,
40  C4MCV_Zoom,
41  C4MCV_ScriptFunc
42  };
43 
44  template<typename T>
45  class MemberAdapter {
46  public:
47  typedef char (T::*OffsetType);
48 
49  MemberAdapter(T& object, OffsetType offset)
50  : Object(object), Offset(offset)
51  {
52  }
53 
54  template<typename U>
55  U& As()
56  {
57  typedef U (T::*TargetPtrType);
58  return Object.*reinterpret_cast<TargetPtrType>(Offset);
59  }
60 
61  private:
62  T& Object;
63  OffsetType Offset;
64  };
65 
66  typedef MemberAdapter<C4MCOverlay>::OffsetType C4MCOverlayOffsetType;
67 
68  struct C4MCNodeAttr
69  {
70  const char* Name; // name of field
71  C4MCValueType Type; // type of field
72  C4MCOverlayOffsetType Offset; // offset of field in overlay MCOverlay-class
73  };
74 
75  extern C4MCNodeAttr C4MCOvrlMap[];
76 }
77 
78 /* --- C4MCCallbackArray --- */
79 
81 {
82  // store fn
83  pSF = pSFunc;
84  // zero fields
85  pMap=nullptr; pNext=nullptr;
86  // store and add in map creator
87  if ((this->pMapCreator=pMapCreator))
88  pMapCreator->CallbackArrays.Add(this);
89  // done
90 }
91 
93 {
94  // clear map, if present
95  if (pMap) delete [] pMap;
96 }
97 
98 void C4MCCallbackArray::EnablePixel(int32_t iX, int32_t iY)
99 {
100  // array not yet created? then do that now!
101  if (!pMap)
102  {
103  // safety
104  if (!pMapCreator) return;
105  // get current map size
106  C4MCMap *pCurrMap = pMapCreator->pCurrentMap;
107  if (!pCurrMap) return;
108  iWdt = pCurrMap->Wdt; iHgt = pCurrMap->Hgt;
109  // create bitmap
110  int32_t iSize=(iWdt*iHgt+7)/8;
111  pMap = new BYTE[iSize];
112  memset(pMap, 0, iSize);
113  // done
114  }
115  // safety: do not set outside map!
116  if (iX<0 || iY<0 || iX>=iWdt || iY>=iHgt) return;
117  // set in map
118  int32_t iIndex = iX + iY*iWdt;
119  pMap[iIndex/8] |= 1<<(iIndex%8);
120  // done
121 }
122 
123 void C4MCCallbackArray::Execute(int32_t iMapZoom)
124 {
125  // safety
126  if (!pSF || !pMap) return;
127  // pre-create parset
128  C4AulParSet Pars(0, 0, iMapZoom);
129  // call all funcs
130  int32_t iIndex=iWdt*iHgt;
131  while (iIndex--)
132  if (pMap[iIndex/8]&(1<<(iIndex%8)))
133  {
134  // set pars
135  Pars[0] = C4VInt((iIndex%iWdt) * iMapZoom - (iMapZoom/2));
136  Pars[1] = C4VInt((iIndex/iWdt) * iMapZoom - (iMapZoom/2));
137  // call
138  pSF->Exec(nullptr, &Pars);
139  }
140  // done
141 }
142 
143 
144 
145 /* --- C4MCCallbackArrayList --- */
146 
148 {
149  // add to end
150  if (pFirst)
151  {
152  C4MCCallbackArray *pLast = pFirst;
153  while (pLast->pNext) pLast=pLast->pNext;
154  pLast->pNext=pNewArray;
155  }
156  else pFirst=pNewArray;
157 }
158 
160 {
161  // remove all arrays
162  C4MCCallbackArray *pArray, *pNext=pFirst;
163  while ((pArray=pNext))
164  {
165  pNext=pArray->pNext;
166  delete pArray;
167  }
168  // zero first-field
169  pFirst=nullptr;
170 }
171 
172 void C4MCCallbackArrayList::Execute(int32_t iMapZoom)
173 {
174  // execute all arrays
175  for (C4MCCallbackArray *pArray = pFirst; pArray; pArray=pArray->pNext)
176  pArray->Execute(iMapZoom);
177 }
178 
179 
180 
181 
182 /* --- C4MCNode --- */
183 
185 {
186  // reg to owner
187  Reg2Owner(pOwner);
188  // no name
189  *Name=0;
190 }
191 
192 C4MCNode::C4MCNode(C4MCParser* pParser, C4MCNode *pOwner, C4MCNode &rTemplate, bool fClone)
193 {
194  // Make sure the template is not used recursively within itself
195  for(C4MCNode* pParent = pOwner; pParent != nullptr; pParent = pParent->Owner)
196  if(pParent == &rTemplate)
197  throw C4MCParserErr(pParser, C4MCErr_NoRecTemplate, rTemplate.Name);
198  // set owner and stuff
199  Reg2Owner(pOwner);
200  // copy children from template
201  for (C4MCNode *pChild=rTemplate.Child0; pChild; pChild=pChild->Next)
202  pChild->clone(pParser, this);
203  // no name
204  *Name=0;
205 }
206 
208 {
209  // clear
210  Clear();
211  // remove from list
212  if (Prev) Prev->Next = Next; else if (Owner) Owner->Child0 = Next;
213  if (Next) Next->Prev = Prev; else if (Owner) Owner->ChildL = Prev;
214 }
215 
217 {
218  // init list
219  Child0=ChildL=nullptr;
220  // owner?
221  if ((Owner=pOwner))
222  {
223  // link into it
224  if ((Prev = Owner->ChildL))
225  Prev->Next = this;
226  else
227  Owner->Child0 = this;
228  Owner->ChildL = this;
229  MapCreator=pOwner->MapCreator;
230  }
231  else
232  {
233  Prev=nullptr;
234  MapCreator=nullptr;
235  }
236  // we're always last entry
237  Next=nullptr;
238 }
239 
241 {
242  // delete all children; they'll unreg themselves
243  while (Child0) delete Child0;
244 }
245 
247 {
248  for (C4MCNode *pOwnr=Owner; pOwnr; pOwnr=pOwnr->Owner)
249  if (C4MCOverlay *pOwnrOvrl=pOwnr->Overlay())
250  return pOwnrOvrl;
251  // no overlay-owner
252  return nullptr;
253 }
254 
255 C4MCNode *C4MCNode::GetNodeByName(const char *szName)
256 {
257  // search local list (backwards: last node has highest priority)
258  for (C4MCNode *pChild=ChildL; pChild; pChild=pChild->Prev)
259  // name match?
260  if (SEqual(pChild->Name, szName))
261  // yeah, success!
262  return pChild;
263  // search owner, if present
264  if (Owner) return Owner->GetNodeByName(szName);
265  // nothing found
266  return nullptr;
267 }
268 
269 bool C4MCNode::SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
270 {
271  // no fields in base class
272  return false;
273 }
274 
275 int32_t C4MCNode::IntPar(C4MCParser *pParser, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
276 {
277  // check if int32_t
278  if (ValType == MCT_INT || ValType == MCT_PERCENT || ValType == MCT_PX)
279  return iVal;
280  throw C4MCParserErr(pParser, C4MCErr_FieldValInvalid, szSVal);
281 }
282 
283 const char *C4MCNode::StrPar(C4MCParser *pParser, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
284 {
285  // check if identifier
286  if (ValType != MCT_IDTF)
287  throw C4MCParserErr(pParser, C4MCErr_FieldValInvalid, szSVal);
288  return szSVal;
289 }
290 
291 #define IntPar IntPar(pParser, szSVal, iVal, ValType) // shortcut for checked int32_t param
292 #define StrPar StrPar(pParser, szSVal, iVal, ValType) // shortcut for checked str param
293 
295 {
296  // evaluate ourselves
297  Evaluate();
298  // evaluate children
299  for (C4MCNode *pChild=Child0; pChild; pChild=pChild->Next)
300  pChild->ReEvaluate();
301 }
302 
303 
304 // overlay
305 
307 {
308  // zero members
309  X=Y=Wdt=Hgt=OffX=OffY=0;
310  Material=MNone;
311  *Texture=0;
312  Op=MCT_NONE;
313  MatClr=0;
314  MatClrBkg=0;
315  Algorithm=nullptr;
316  Sub=false;
317  ZoomX=ZoomY=0;
318  FixedSeed=Seed=0;
319 // Alpha=Beta=0;
322  pEvaluateFunc=pDrawFunc=nullptr;
323 }
324 
325 C4MCOverlay::C4MCOverlay(C4MCParser* pParser, C4MCNode *pOwner, C4MCOverlay &rTemplate, bool fClone) : C4MCNode(pParser, pOwner, rTemplate, fClone)
326 {
327  // copy fields
328  X=rTemplate.X; Y=rTemplate.Y; Wdt=rTemplate.Wdt; Hgt=rTemplate.Hgt;
329  RX=rTemplate.RX; RY=rTemplate.RY; RWdt=rTemplate.RWdt; RHgt=rTemplate.RHgt;
330  OffX=rTemplate.OffX; OffY=rTemplate.OffY; ROffX=rTemplate.ROffX; ROffY=rTemplate.ROffY;
331  Material=rTemplate.Material;
332  SCopy(rTemplate.Texture, Texture, C4MaxName);
333  Algorithm=rTemplate.Algorithm;
334  Sub=rTemplate.Sub;
335  ZoomX=rTemplate.ZoomX; ZoomY=rTemplate.ZoomY;
336  MatClr=rTemplate.MatClr;
337  MatClrBkg=rTemplate.MatClrBkg;
338  Seed=rTemplate.Seed;
339  Alpha=rTemplate.Alpha; Beta=rTemplate.Beta; Turbulence=rTemplate.Turbulence; Lambda=rTemplate.Lambda;
340  Rotate=rTemplate.Rotate;
341  Invert=rTemplate.Invert; LooseBounds=rTemplate.LooseBounds; Group=rTemplate.Group; Mask=rTemplate.Mask;
342  FixedSeed=rTemplate.FixedSeed;
343  pEvaluateFunc=rTemplate.pEvaluateFunc;
344  pDrawFunc=rTemplate.pDrawFunc;
345  // zero non-template-fields
346  if (fClone) Op=rTemplate.Op; else Op=MCT_NONE;
347 }
348 
350 {
351  // default algo
353  // no mat (sky) default
354  Material=MNone;
355  *Texture=0;
356  // but if mat is set, assume it sub
357  Sub=true;
358  // full size
359  OffX=OffY=X=Y=0;
360  ROffX.Set(0,true); ROffY.Set(0,true); RX.Set(0,true); RY.Set(0,true);
362  RWdt.Set(C4MC_SizeRes,true); RHgt.Set(C4MC_SizeRes,true);
363  // def zoom
365  // def values
366  Alpha.Set(0,false); Beta.Set(0,false); Turbulence=Lambda=Rotate=0; Invert=LooseBounds=Group=Mask=false;
367  FixedSeed=0;
368  // script funcs
369  pEvaluateFunc=pDrawFunc=nullptr;
370 }
371 
372 bool C4MCOverlay::SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
373 {
374  int32_t iMat; C4MCAlgorithm *pAlgo;
375  // inherited fields
376  if (C4MCNode::SetField(pParser, szField, szSVal, iVal, ValType)) return true;
377  //local fields
378  for (C4MCNodeAttr *pAttr=&C4MCOvrlMap[0]; *pAttr->Name; pAttr++)
379  if (SEqual(szField, pAttr->Name))
380  {
381  // field was found, get offset to store in
382  MemberAdapter<C4MCOverlay> Target(*this, pAttr->Offset);
383  // store according to field type
384  switch (pAttr->Type)
385  {
386  case C4MCV_Integer:
387  // simply store
388  Target.As<int32_t>() = IntPar;
389  break;
390  case C4MCV_Percent:
391  Target.As<int_bool>().Set(IntPar, ValType == MCT_PERCENT || ValType == MCT_INT);
392  break;
393  case C4MCV_Pixels:
394  Target.As<int_bool>().Set(IntPar, ValType == MCT_PERCENT);
395  break;
396  case C4MCV_Material:
397  // get material by string
398  iMat = MapCreator->MatMap->Get(StrPar);
399  // check validity
400  if (iMat == MNone) throw C4MCParserErr(pParser, C4MCErr_MatNotFound, StrPar);
401  // store
402  Target.As<int32_t>() = iMat;
403  break;
404  case C4MCV_Texture:
405  // check validity
407  throw C4MCParserErr(pParser, C4MCErr_TexNotFound, StrPar);
408  // store
409  SCopy(StrPar, Target.As<char [C4M_MaxName + 1]>(), C4M_MaxName);
410  break;
411  case C4MCV_Algorithm:
412  // get algo
413  pAlgo=GetAlgo(StrPar);
414  // check validity
415  if (!pAlgo) throw C4MCParserErr(pParser, C4MCErr_AlgoNotFound, StrPar);
416  // store
417  Target.As<C4MCAlgorithm *>()=pAlgo;
418  break;
419  case C4MCV_Boolean:
420  // store whether value is not zero
421  Target.As<bool>()=IntPar!=0;
422  break;
423  case C4MCV_Zoom:
424  // store calculated zoom
425  Target.As<int32_t>()=Clamp<int32_t>(C4MC_ZoomRes-IntPar,1,C4MC_ZoomRes*2);
426  break;
427  case C4MCV_ScriptFunc:
428  {
429  // get script func of main script
431  if (!pSFunc) throw C4MCParserErr(pParser, C4MCErr_SFuncNotFound, StrPar);
432  // add to main
433  Target.As<C4MCCallbackArray*>() = new C4MCCallbackArray(pSFunc, MapCreator);
434  }
435  default:
436  // TODO
437  break;
438  }
439  // done
440  return true;
441  }
442  // nothing found :(
443  return false;
444 }
445 
447 {
448  // search map
449  for (C4MCAlgorithm *pAlgo = &C4MCAlgoMap[0]; pAlgo->Function; pAlgo++)
450  // check name
451  if (SEqual(pAlgo->Identifier, szName))
452  // success!
453  return pAlgo;
454  // nothing found
455  return nullptr;
456 }
457 
459 {
460  // inherited
462  // get mat color
463  if (Inside<int32_t>(Material,0,MapCreator->MatMap->Num-1))
464  {
466  if(MatClr == 0 || !Sub)
467  MatClrBkg = 0;
468  else
470  }
471  else
472  {
473  MatClr=0;
474  MatClrBkg=0;
475  }
476 
477  // calc size
478  if (Owner)
479  {
480  C4MCOverlay *pOwnrOvrl;
481  if ((pOwnrOvrl=OwnerOverlay()))
482  {
483  int32_t iOwnerWdt=pOwnrOvrl->Wdt; int32_t iOwnerHgt=pOwnrOvrl->Hgt;
484  X = RX.Evaluate(iOwnerWdt) + pOwnrOvrl->X;
485  Y = RY.Evaluate(iOwnerHgt) + pOwnrOvrl->Y;
486  Wdt = RWdt.Evaluate(iOwnerWdt);
487  Hgt = RHgt.Evaluate(iOwnerHgt);
488  OffX = ROffX.Evaluate(iOwnerWdt);
489  OffY = ROffY.Evaluate(iOwnerHgt);
490  }
491  }
492  // calc seed
493  if (!(Seed=FixedSeed))
494  {
495  int32_t r1=Random(32768);
496  int32_t r2=Random(65536);
497  Seed=(r1<<16) | r2;
498  }
499 }
500 
502 {
503  // run backwards until nullptr, non-overlay or overlay without operator is found
504  C4MCOverlay *pOvrl=this;
505  C4MCOverlay *pPrevO;
506  while (pOvrl->Prev)
507  {
508  if (!(pPrevO=pOvrl->Prev->Overlay())) break;
509  if (pPrevO->Op == MCT_NONE) break;
510  pOvrl=pPrevO;
511  }
512  // done
513  return pOvrl;
514 }
515 
516 bool C4MCOverlay::CheckMask(int32_t iX, int32_t iY)
517 {
518  // bounds match?
519  if (!LooseBounds) if (iX<X || iY<Y || iX>=X+Wdt || iY>=Y+Hgt) return false;
520  if (Config.General.DebugRec)
521  {
522  C4RCTrf rc;
523  rc.x=iX; rc.y=iY; rc.Rotate=Rotate; rc.Turbulence=Turbulence;
524  AddDbgRec(RCT_MCT1, &rc, sizeof(rc));
525  }
526  C4Real dX=itofix(iX); C4Real dY=itofix(iY);
527  // apply turbulence
528  if (Turbulence)
529  {
530  const C4Real Rad2Grad = itofix(3754936, 65536);
531  int32_t j=3;
532  for (int32_t i=10; i<=Turbulence; i*=10)
533  {
534  int32_t Seed2; Seed2=Seed;
535  for (int32_t l=0; l<Lambda+1; ++l)
536  {
537  for (C4Real d=itofix(2); d<6; d+=C4REAL10(15))
538  {
539  dX += Sin(((dX / 7 + itofix(Seed2) / ZoomX + dY) / j + d) * Rad2Grad) * j / 2;
540  dY += Cos(((dY / 7 + itofix(Seed2) / ZoomY + dX) / j - d) * Rad2Grad) * j / 2;
541  }
542  Seed2 = (Seed * (Seed2<<3) + 0x4465) & 0xffff;
543  }
544  j+=3;
545  }
546  }
547  // apply rotation
548  if (Rotate)
549  {
550  C4Real dXo(dX), dYo(dY);
551  dX = dXo*Cos(itofix(Rotate)) - dYo*Sin(itofix(Rotate));
552  dY = dYo*Cos(itofix(Rotate)) + dXo*Sin(itofix(Rotate));
553  }
554  if (Rotate || Turbulence)
555  { iX=fixtoi(dX, ZoomX); iY=fixtoi(dY, ZoomY); }
556  else
557  { iX*=ZoomX; iY*=ZoomY; }
558  if (Config.General.DebugRec)
559  {
560  C4RCPos rc2;
561  rc2.x=iX; rc2.y=iY;
562  AddDbgRec(RCT_MCT2, &rc2, sizeof(rc2));
563  }
564  // apply offset
565  iX-=OffX*ZoomX; iY-=OffY*ZoomY;
566  // check bounds, if loose
567  if (LooseBounds) if (iX<X*ZoomX || iY<Y*ZoomY || iX>=(X+Wdt)*ZoomX || iY>=(Y+Hgt)*ZoomY) return Invert;
568  // query algorithm
569  return (Algorithm->Function) (this, iX, iY)^Invert;
570 }
571 
572 bool C4MCOverlay::RenderPix(int32_t iX, int32_t iY, BYTE &rPix, BYTE &rPixBkg, C4MCTokenType eLastOp, bool fLastSet, bool fDraw, C4MCOverlay **ppPixelSetOverlay)
573 {
574  // algo match?
575  bool SetThis=CheckMask(iX, iY);
576  bool DoSet;
577  // exec last op
578  switch (eLastOp)
579  {
580  case MCT_AND: // and
581  DoSet=SetThis&&fLastSet;
582  break;
583  case MCT_OR: // or
584  DoSet=SetThis||fLastSet;
585  break;
586  case MCT_XOR: // xor
587  DoSet=SetThis^fLastSet;
588  break;
589  default: // no op
590  DoSet=SetThis;
591  break;
592  }
593 
594  // set pix to local value and exec children, if no operator is following
595  if ((DoSet && fDraw && Op == MCT_NONE) || Group)
596  {
597  // groups don't set a pixel value, if they're associated with an operator
598  fDraw &= !Group || (Op == MCT_NONE);
599  if (fDraw && DoSet && !Mask)
600  {
601  rPix=MatClr;
602  rPixBkg=MatClrBkg;
603  if (ppPixelSetOverlay) *ppPixelSetOverlay = this;
604  }
605  bool fLastSetC=false; eLastOp=MCT_NONE;
606  // evaluate children overlays, if this was painted, too
607  for (C4MCNode *pChild=Child0; pChild; pChild=pChild->Next)
608  if (C4MCOverlay *pOvrl=pChild->Overlay())
609  {
610  fLastSetC=pOvrl->RenderPix(iX, iY, rPix, rPixBkg, eLastOp, fLastSetC, fDraw, ppPixelSetOverlay);
611  if (Group && (pOvrl->Op == MCT_NONE))
612  DoSet |= fLastSetC;
613  eLastOp=pOvrl->Op;
614  }
615  // add evaluation-callback
616  if (pEvaluateFunc && DoSet && fDraw) pEvaluateFunc->EnablePixel(iX, iY);
617  }
618  // done
619  return DoSet;
620 }
621 
622 bool C4MCOverlay::PeekPix(int32_t iX, int32_t iY)
623 {
624  // start with this one
625  C4MCOverlay *pOvrl=this; bool fLastSetC=false; C4MCTokenType eLastOp=MCT_NONE; BYTE Crap;
626  // loop through op chain
627  while (true)
628  {
629  fLastSetC=pOvrl->RenderPix(iX, iY, Crap, Crap, eLastOp, fLastSetC, false);
630  eLastOp=pOvrl->Op;
631  if (!pOvrl->Op) break;
632  // must be another overlay, since there's an operator
633  // hopefully, the preparser will catch all the other crap
634  pOvrl=pOvrl->Next->Overlay();
635  }
636  // return result
637  return fLastSetC;
638 }
639 
640 // point
641 
643 {
644  // zero members
645  X=Y=0;
646 }
647 
648 C4MCPoint::C4MCPoint(C4MCParser* pParser, C4MCNode *pOwner, C4MCPoint &rTemplate, bool fClone) : C4MCNode(pParser, pOwner, rTemplate, fClone)
649 {
650  // copy fields
651  X=rTemplate.X; Y=rTemplate.Y;
652  RX=rTemplate.RX; RY=rTemplate.RY;
653 }
654 
656 {
657  X=Y=0;
658 }
659 
660 bool C4MCPoint::SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
661 {
662  // only explicit %/px
663  if (ValType == MCT_INT) return false;
664  if (SEqual (szField, "x"))
665  {
666  RX.Set(IntPar, ValType == MCT_PERCENT);
667  return true;
668  }
669  else if (SEqual (szField, "y"))
670  {
671  RY.Set(IntPar, ValType == MCT_PERCENT);
672  return true;
673  }
674  return false;
675 }
676 
678 {
679  // inherited
681  // get mat color
682  // calc size
683  if (Owner)
684  {
685  C4MCOverlay *pOwnrOvrl;
686  if ((pOwnrOvrl=OwnerOverlay()))
687  {
688  X = RX.Evaluate(pOwnrOvrl->Wdt) + pOwnrOvrl->X;
689  Y = RY.Evaluate(pOwnrOvrl->Hgt) + pOwnrOvrl->Y;
690  }
691  }
692 }
693 
694 // map
695 
697 {
698 
699 }
700 
701 C4MCMap::C4MCMap(C4MCParser* pParser, C4MCNode *pOwner, C4MCMap &rTemplate, bool fClone) : C4MCOverlay(pParser, pOwner, rTemplate, fClone)
702 {
703 
704 }
705 
707 {
708  // inherited
710  // size by landscape def
712 }
713 
714 bool C4MCMap::RenderTo(BYTE *pToBuf, BYTE *pToBufBkg, int32_t iPitch)
715 {
716  // set current render target
717  if (MapCreator) MapCreator->pCurrentMap=this;
718  // draw pixel by pixel
719  for (int32_t iY=0; iY<Hgt; iY++)
720  {
721  for (int32_t iX=0; iX<Wdt; iX++)
722  {
723  // default to sky
724  BYTE dummyPix;
725  *pToBuf=0;
726  if (pToBufBkg) *pToBufBkg=0;
727  // render pixel value
728  C4MCOverlay *pRenderedOverlay = nullptr;
729  RenderPix(iX, iY, *pToBuf, pToBufBkg ? *pToBufBkg : dummyPix, MCT_NONE, false, true, &pRenderedOverlay);
730  // add draw-callback for rendered overlay
731  if (pRenderedOverlay)
732  if (pRenderedOverlay->pDrawFunc)
733  pRenderedOverlay->pDrawFunc->EnablePixel(iX, iY);
734  // next pixel
735  pToBuf++;
736  if (pToBufBkg) pToBufBkg++;
737  }
738  // next line
739  pToBuf+=iPitch-Wdt;
740  if (pToBufBkg) pToBufBkg+=iPitch-Wdt;
741  }
742  // reset render target
743  if (MapCreator) MapCreator->pCurrentMap=nullptr;
744  // success
745  return true;
746 }
747 
748 void C4MCMap::SetSize(int32_t iWdt, int32_t iHgt)
749 {
750  // store new size
751  Wdt=iWdt; Hgt=iHgt;
752  // update relative values
754 }
755 
756 
757 // map creator
758 
759 C4MapCreatorS2::C4MapCreatorS2(C4SLandscape *pLandscape, C4TextureMap *pTexMap, C4MaterialMap *pMatMap, int iPlayerCount) : C4MCNode(nullptr)
760 {
761  // me r b creator
762  MapCreator=this;
763  // store members
764  Landscape=pLandscape; TexMap=pTexMap; MatMap=pMatMap;
765  PlayerCount=iPlayerCount;
766  // set engine field for default stuff
767  DefaultMap.MapCreator=this;
770  // default to landscape settings
771  Default();
772 }
773 
775 {
776  // clear fields
777  Clear();
778 }
779 
781 {
782  // default templates
786  pCurrentMap=nullptr;
787 }
788 
790 {
791  // clear nodes
792  C4MCNode::Clear();
793  // clear callbacks
795  // defaults templates
796  Default();
797 }
798 
799 bool C4MapCreatorS2::ReadFile(const char *szFilename, C4Group *pGrp)
800 {
801  // create parser and read file
802  try
803  {
804  C4MCParser(this).ParseFile(szFilename, pGrp);
805  }
806  catch (C4MCParserErr err)
807  {
808  err.show();
809  return false;
810  }
811  // success
812  return true;
813 }
814 
815 bool C4MapCreatorS2::ReadScript(const char *szScript)
816 {
817  // create parser and read
818  try
819  {
820  C4MCParser(this).Parse(szScript);
821  }
822  catch (C4MCParserErr err)
823  {
824  err.show();
825  return false;
826  }
827  // success
828  return true;
829 }
830 
831 C4MCMap *C4MapCreatorS2::GetMap(const char *szMapName)
832 {
833  C4MCMap *pMap=nullptr; C4MCNode *pNode;
834  // get map
835  if (szMapName && *szMapName)
836  {
837  // by name...
838  if ((pNode = GetNodeByName(szMapName)))
839  if (pNode->Type() == MCN_Map)
840  pMap = (C4MCMap *) pNode;
841  }
842  else
843  {
844  // or simply last map entry
845  for (pNode = ChildL; pNode; pNode=pNode->Prev)
846  if (pNode->Type() == MCN_Map)
847  {
848  pMap = (C4MCMap *) pNode;
849  break;
850  }
851  }
852  return pMap;
853 }
854 
855 bool C4MapCreatorS2::Render(const char *szMapName, CSurface8*& sfcMap, CSurface8*& sfcMapBkg)
856 {
857  assert(sfcMap == nullptr);
858  assert(sfcMapBkg == nullptr);
859 
860  // get map
861  C4MCMap *pMap=GetMap(szMapName);
862  if (!pMap) return false;
863 
864  // get size
865  int32_t sfcWdt, sfcHgt;
866  sfcWdt=pMap->Wdt; sfcHgt=pMap->Hgt;
867  if (!sfcWdt || !sfcHgt) return false;
868 
869  // create surfaces
870  sfcMap = new CSurface8(sfcWdt, sfcHgt);
871  sfcMapBkg = new CSurface8(sfcWdt, sfcHgt);
872  assert(sfcMap->Pitch == sfcMapBkg->Pitch);
873 
874  // render map to surface
875  pMap->RenderTo(sfcMap->Bits, sfcMapBkg->Bits, sfcMap->Pitch);
876 
877  // success
878  return true;
879 }
880 
881 static inline void DWordAlign(int &val)
882 {
883  if (val%4) { val>>=2; val<<=2; val+=4; }
884 }
885 
886 BYTE *C4MapCreatorS2::RenderBuf(const char *szMapName, int32_t &sfcWdt, int32_t &sfcHgt)
887 {
888  // get map
889  C4MCMap *pMap=GetMap(szMapName);
890  if (!pMap) return nullptr;
891 
892  // get size
893  sfcWdt=pMap->Wdt; sfcHgt=pMap->Hgt;
894  if (!sfcWdt || !sfcHgt) return nullptr;
895  int dwSfcWdt = sfcWdt;
896  DWordAlign(dwSfcWdt);
897  sfcWdt = dwSfcWdt;
898 
899  // create buffer
900  BYTE *buf=new BYTE[sfcWdt*sfcHgt];
901 
902  // render and return it
903  pMap->RenderTo(buf, nullptr, sfcWdt);
904  return buf;
905 }
906 
907 C4MCParserErr::C4MCParserErr(C4MCParser *pParser, const char *szMsg)
908 {
909  // create error message
910  sprintf(Msg, "%s: %s (%d)", pParser->Filename, szMsg, pParser->BPos ? SGetLine(pParser->BPos, pParser->CPos) : 0);
911 }
912 
913 C4MCParserErr::C4MCParserErr(C4MCParser *pParser, const char *szMsg, const char *szPar)
914 {
915  char Buf[C4MaxMessage];
916  // create error message
917  sprintf(Buf, szMsg, szPar);
918  sprintf(Msg, "%s: %s (%d)", pParser->Filename, Buf, pParser->BPos ? SGetLine(pParser->BPos, pParser->CPos) : 0);
919 }
920 
922 {
923  // log error
924  Log(Msg);
925 }
926 
927 
928 // parser
929 
931 {
932  // store map creator
933  MapCreator=pMapCreator;
934  // reset some fields
935  Code=nullptr; BPos = nullptr; CPos=nullptr; *Filename=0;
936 }
937 
939 {
940  // clean up
941  Clear();
942 }
943 
945 {
946  // clear code if present
947  if (Code) delete [] Code; Code=nullptr; BPos = nullptr; CPos=nullptr;
948  // reset filename
949  *Filename=0;
950 }
951 
952 bool C4MCParser::AdvanceSpaces()
953 {
954  char C, C2 = (char) 0;
955  // defaultly, not in comment
956  int32_t InComment = 0; // 0/1/2 = no comment/line comment/multi line comment
957  // don't go past end
958  while ((C = *CPos))
959  {
960  // loop until out of comment and non-whitespace is found
961  switch (InComment)
962  {
963  case 0:
964  if (C == '/')
965  {
966  CPos++;
967  switch (*CPos)
968  {
969  case '/': InComment = 1; break;
970  case '*': InComment = 2; break;
971  default: CPos--; return true;
972  }
973  }
974  else if ((BYTE) C > 32) return true;
975  break;
976  case 1:
977  if (((BYTE) C == 13) || ((BYTE) C == 10)) InComment = 0;
978  break;
979  case 2:
980  if ((C == '/') && (C2 == '*')) InComment = 0;
981  break;
982  }
983  // next char; store prev
984  CPos++; C2 = C;
985  }
986  // end of code reached; return false
987  return false;
988 }
989 
990 bool C4MCParser::GetNextToken()
991 {
992  // move to start of token
993  if (!AdvanceSpaces()) { CurrToken=MCT_EOF; return false; }
994  // store offset
995  const char *CPos0 = CPos;
996  int32_t Len = 0;
997  // token get state
998  enum TokenGetState
999  {
1000  TGS_None, // just started
1001  TGS_Ident, // getting identifier
1002  TGS_Int, // getting integer
1003  TGS_Dir // getting directive
1004  };
1005  TokenGetState State = TGS_None;
1006 
1007  // loop until finished
1008  while (true)
1009  {
1010  // get char
1011  char C = *CPos;
1012 
1013  switch (State)
1014  {
1015  case TGS_None:
1016  // get token type by first char
1017  // +/- are operators
1018  if ((((C >= '0') && (C <= '9')) || (C == '+') || (C == '-')))
1019  State = TGS_Int; // integer by +, -, 0-9
1020  else if (C == '#') State = TGS_Dir; // directive by "#"
1021  else if (C == ';') {CPos++; CurrToken=MCT_SCOLON; return true; } // ";"
1022  else if (C == '=') {CPos++; CurrToken=MCT_EQ; return true; } // "="
1023  else if (C == '{') {CPos++; CurrToken=MCT_BLOPEN; return true; } // "{"
1024  else if (C == '}') {CPos++; CurrToken=MCT_BLCLOSE; return true; } // "}"
1025  else if (C == '&') {CPos++; CurrToken=MCT_AND; return true; } // "&"
1026  else if (C == '|') {CPos++; CurrToken=MCT_OR; return true; } // "|"
1027  else if (C == '^') {CPos++; CurrToken=MCT_XOR; return true; } // "^"
1028  else if (C >= '@') State = TGS_Ident; // identifier by all non-special chars
1029  else
1030  {
1031  // unrecognized char
1032  CPos++;
1033  throw C4MCParserErr(this, "unexpected character found");
1034  }
1035  break;
1036 
1037  case TGS_Ident: // ident and directive: parse until non ident-char is found
1038  case TGS_Dir:
1039  if (((C < '0') || (C > '9')) && ((C < 'a') || (C > 'z')) && ((C < 'A') || (C > 'Z')) && (C != '_'))
1040  {
1041  // return ident/directive
1042  Len = std::min<int32_t>(Len, C4MaxName);
1043  SCopy(CPos0, CurrTokenIdtf, Len);
1044  if (State==TGS_Ident) CurrToken=MCT_IDTF; else CurrToken=MCT_DIR;
1045  return true;
1046  }
1047  break;
1048 
1049  case TGS_Int: // integer: parse until non-number is found
1050  if ((C < '0') || (C > '9'))
1051  {
1052  // return integer
1053  Len = std::min<int32_t>(Len, C4MaxName);
1054  CurrToken=MCT_INT;
1055  // check for "-"
1056  if (Len == 1 && *CPos0 == '-')
1057  {
1058  CurrToken = MCT_RANGE;
1059  return true;
1060  }
1061  else if ('%' == C) { CPos++; CurrToken=MCT_PERCENT; } // "%"
1062  else if ('p' == C)
1063  {
1064  // p or px
1065  ++CPos;
1066  if ('x' == *CPos) ++CPos;
1067  CurrToken=MCT_PX;
1068  }
1069  SCopy(CPos0, CurrTokenIdtf, Len);
1070  // it's not, so return the int32_t
1071  sscanf(CurrTokenIdtf, "%d", &CurrTokenVal);
1072  return true;
1073  }
1074  break;
1075 
1076  }
1077  // next char
1078  CPos++; Len++;
1079  }
1080 
1081 }
1082 
1083 static void PrintNodeTree(C4MCNode *pNode, int depth)
1084 {
1085  for (int i = 0; i < depth; ++i)
1086  printf(" ");
1087  switch (pNode->Type())
1088  {
1089  case MCN_Node: printf("Node %s\n", pNode->Name); break;
1090  case MCN_Overlay: printf("Overlay %s\n", pNode->Name); break;
1091  case MCN_Point: printf("Point %s\n", pNode->Name); break;
1092  case MCN_Map: printf("Map %s\n", pNode->Name); break;
1093  }
1094  for (C4MCNode * pChild = pNode->Child0; pChild; pChild = pChild->Next)
1095  PrintNodeTree(pChild, depth + 1);
1096 }
1097 
1098 void C4MCParser::ParseTo(C4MCNode *pToNode)
1099 {
1100  C4MCNode *pNewNode=nullptr; // new node
1101  bool Done=false; // finished?
1102  C4MCNodeType LastOperand = C4MCNodeType(-1); // last first operand of operator
1103  char FieldName[C4MaxName];// buffer for current field to access
1104  C4MCNode *pCpyNode; // node to copy from
1105  // current state
1106  enum ParseState
1107  {
1108  PS_NONE, // just started
1109  PS_KEYWD1, // got block-opening keyword (map, overlay etc.)
1110  PS_KEYWD1N, // got name for block
1111  PS_AFTERNODE, // node has been parsed; expect ; or operator
1112  PS_GOTOP, // got operator
1113  PS_GOTIDTF, // got identifier, expect '=', ';' or '{'; identifier remains in CurrTokenIdtf
1114  PS_GOTOPIDTF, // got identifier after operator; accept ';' or '{' only
1115  PS_SETFIELD // accept field value; field is stored in FieldName
1116  };
1117  ParseState State = PS_NONE;
1118  // parse until end of file (or block)
1119  while (GetNextToken())
1120  {
1121  switch (State)
1122  {
1123  case PS_NONE:
1124  case PS_GOTOP:
1125  switch (CurrToken)
1126  {
1127  case MCT_DIR:
1128  // top level needed
1129  if (!pToNode->GlobalScope())
1130  throw C4MCParserErr(this, C4MCErr_NoDirGlobal);
1131  // no directives so far
1132  throw C4MCParserErr(this, C4MCErr_UnknownDir, CurrTokenIdtf);
1133  break;
1134  case MCT_IDTF:
1135  // identifier: check keywords
1136  if (SEqual(CurrTokenIdtf, C4MC_Overlay))
1137  {
1138  // overlay: create overlay node, using default template
1139  pNewNode = new C4MCOverlay(this, pToNode, MapCreator->DefaultOverlay, false);
1140  State=PS_KEYWD1;
1141  }
1142  else if (SEqual(CurrTokenIdtf, C4MC_Point) && !pToNode->GetNodeByName(CurrTokenIdtf))
1143  {
1144  // only in overlays
1145  if (!pToNode->Overlay())
1146  throw C4MCParserErr(this, C4MCErr_PointOnlyOvl);
1147  // create point node, using default template
1148  pNewNode = new C4MCPoint(this, pToNode, MapCreator->DefaultPoint, false);
1149  State=PS_KEYWD1;
1150  }
1151  else if (SEqual(CurrTokenIdtf, C4MC_Map))
1152  {
1153  // map: check top level
1154  if (!pToNode->GlobalScope())
1155  throw C4MCParserErr(this, C4MCErr_MapNoGlobal);
1156  // create map node, using default template
1157  pNewNode = new C4MCMap(this, pToNode, MapCreator->DefaultMap, false);
1158  State=PS_KEYWD1;
1159  }
1160  else
1161  {
1162  // so this is either a field-set or a defined node
1163  // '=', ';' or '{' may follow, none of these will clear the CurrTokenIdtf
1164  // so safely assume it preserved and just update the state
1165  if (State==PS_GOTOP) State=PS_GOTOPIDTF; else State=PS_GOTIDTF;
1166  }
1167  // operator: check type
1168  if (State == PS_GOTOP && pNewNode)
1169  if (LastOperand != pNewNode->Type())
1170  throw C4MCParserErr(this, C4MCErr_OpTypeErr);
1171  break;
1172  case MCT_BLCLOSE:
1173  case MCT_EOF:
1174  // block done
1175  Done=true;
1176  break;
1177  default:
1178  // we don't like that
1179  throw C4MCParserErr(this, C4MCErr_IdtfExp);
1180  break;
1181  }
1182  break;
1183  case PS_KEYWD1:
1184  if (CurrToken==MCT_IDTF)
1185  {
1186  // name the current node
1187  SCopy(CurrTokenIdtf, pNewNode->Name, C4MaxName);
1188  State=PS_KEYWD1N;
1189  break;
1190  }
1191  else if (pToNode->GlobalScope())
1192  {
1193  // disallow unnamed nodes in global scope
1194  throw C4MCParserErr(this, C4MCErr_UnnamedNoGlbl);
1195  }
1196  // in local scope, allow unnamed; so continue
1197  case PS_KEYWD1N:
1198  // do expect a block opening
1199  if (CurrToken!=MCT_BLOPEN)
1200  throw C4MCParserErr(this, C4MCErr_BlOpenExp);
1201  // parse new node
1202  ParseTo(pNewNode);
1203  // check file end
1204  if (CurrToken==MCT_EOF)
1205  throw C4MCParserErr(this, C4MCErr_EOF);
1206  // reset state
1207  State=PS_AFTERNODE;
1208  break;
1209  case PS_GOTIDTF:
1210  case PS_GOTOPIDTF:
1211  switch (CurrToken)
1212  {
1213  case MCT_EQ:
1214  // so it's a field set
1215  // not after operators
1216  if (State==PS_GOTOPIDTF)
1217  throw C4MCParserErr(this, C4MCErr_Obj2Exp);
1218  // store field name
1219  SCopy(CurrTokenIdtf, FieldName, C4MaxName);
1220  // update state to accept value
1221  State=PS_SETFIELD;
1222  break;
1223  case MCT_BLOPEN:
1224  case MCT_SCOLON:
1225  case MCT_AND: case MCT_OR: case MCT_XOR:
1226  // so it's a node copy
1227  // local scope only
1228  if (pToNode->GlobalScope())
1229  throw C4MCParserErr(this, C4MCErr_ReinstNoGlobal, CurrTokenIdtf);
1230  // get the node
1231  pCpyNode=pToNode->GetNodeByName(CurrTokenIdtf);
1232  if (!pCpyNode)
1233  throw C4MCParserErr(this, C4MCErr_UnknownObj, CurrTokenIdtf);
1234  // create the copy
1235  switch (pCpyNode->Type())
1236  {
1237  case MCN_Overlay:
1238  // create overlay
1239  pNewNode=new C4MCOverlay(this, pToNode, *((C4MCOverlay *) pCpyNode), false);
1240  break;
1241  case MCN_Map:
1242  // maps not allowed
1243  if (pCpyNode->Type() == MCN_Map)
1244  throw C4MCParserErr(this, C4MCErr_MapNoGlobal, CurrTokenIdtf);
1245  break;
1246  default:
1247  // huh?
1248  throw C4MCParserErr(this, C4MCErr_ReinstUnknown, CurrTokenIdtf);
1249  break;
1250  }
1251  // check type for operators
1252  if (State==PS_GOTOPIDTF)
1253  if (LastOperand != pNewNode->Type())
1254  throw C4MCParserErr(this, C4MCErr_OpTypeErr);
1255  // further overloads?
1256  if (CurrToken==MCT_BLOPEN)
1257  {
1258  // parse new node
1259  ParseTo(pNewNode);
1260  // get next token, as we'll simply fall through to PS_AFTERNODE
1261  GetNextToken();
1262  // check file end
1263  if (CurrToken==MCT_EOF)
1264  throw C4MCParserErr(this, C4MCErr_EOF);
1265  }
1266  // reset state
1267  State=PS_AFTERNODE;
1268  break;
1269 
1270  default:
1272  break;
1273  }
1274  // fall through to next case, if it was a named node reinstanciation
1275  if (State != PS_AFTERNODE) break;
1276  case PS_AFTERNODE:
1277  // expect operator or semicolon
1278  switch (CurrToken)
1279  {
1280  case MCT_SCOLON:
1281  // reset state
1282  State=PS_NONE;
1283  break;
1284  case MCT_AND:
1285  case MCT_OR:
1286  case MCT_XOR:
1287  // operator: not in global scope
1288  if (pToNode->GlobalScope())
1289  throw C4MCParserErr(this, C4MCErr_OpsNoGlobal);
1290  // set operator
1291  if (!pNewNode->SetOp(CurrToken))
1292  throw C4MCParserErr(this, "';' expected");
1293  LastOperand=pNewNode->Type();
1294  // update state
1295  State=PS_GOTOP;
1296  break;
1297  default:
1298  throw C4MCParserErr(this, C4MCErr_SColonOrOpExp);
1299  break;
1300  }
1301  // node done
1302  // evaluate node and children, if this is top-level
1303  // we mustn't evaluate everything immediately, because parents must be evaluated first!
1304  if (pToNode->GlobalScope()) pNewNode->ReEvaluate();
1305  pNewNode=nullptr;
1306  break;
1307  case PS_SETFIELD:
1308  ParseValue (pToNode, FieldName);
1309  /*// set field: accept integer constants and identifiers
1310  switch (CurrToken)
1311  {
1312  case MCT_IDTF:
1313  // reset value field
1314  CurrTokenVal=0;
1315  case MCT_INT:
1316  break;
1317  default:
1318  throw C4MCParserErr(this, C4MCErr_FieldConstExp, CurrTokenIdtf);
1319  break;
1320  }
1321  // set field
1322  if (!pToNode->SetField(this, FieldName, CurrTokenIdtf, CurrTokenVal, CurrToken))
1323  // field not found
1324  throw C4MCParserErr(this, C4MCErr_Field404, FieldName);
1325  // now, the one and only thing to get is a semicolon
1326  if (!GetNextToken())
1327  throw C4MCParserErr(this, C4MCErr_EOF);
1328  if (CurrToken != MCT_SCOLON)
1329  throw C4MCParserErr(this, C4MCErr_SColonExp);*/
1330  // reset state
1331  State=PS_NONE;
1332  break;
1333  }
1334  // don't get another token!
1335  if (Done) break;
1336  }
1337  // end of file expected?
1338  if (State != PS_NONE)
1339  {
1340  if (State == PS_GOTOP)
1341  throw C4MCParserErr(this, C4MCErr_Obj2Exp);
1342  else
1343  throw C4MCParserErr(this, C4MCErr_EOF);
1344  }
1345 }
1346 
1347 void C4MCParser::ParseValue(C4MCNode *pToNode, const char *szFieldName)
1348 {
1349  int32_t Value;
1350  C4MCTokenType Type;
1351  switch (CurrToken)
1352  {
1353  case MCT_IDTF:
1354  {
1355  // set field
1356  if (!pToNode->SetField(this, szFieldName, CurrTokenIdtf, 0, CurrToken))
1357  // field not found
1358  throw C4MCParserErr(this, C4MCErr_Field404, szFieldName);
1359  if (!GetNextToken())
1360  throw C4MCParserErr(this, C4MCErr_EOF);
1361  break;
1362  }
1363  case MCT_INT:
1364  case MCT_PX:
1365  case MCT_PERCENT:
1366  {
1367  Value = CurrTokenVal;
1368  Type = CurrToken;
1369  if (!GetNextToken())
1370  throw C4MCParserErr(this, C4MCErr_EOF);
1371  // range
1372  if (MCT_RANGE == CurrToken)
1373  {
1374  // Get the second value
1375  if (!GetNextToken())
1376  throw C4MCParserErr(this, C4MCErr_EOF);
1377  if (MCT_INT == CurrToken || MCT_PX == CurrToken || MCT_PERCENT == CurrToken)
1378  {
1379  Value += Random (CurrTokenVal - Value);
1380  }
1381  else
1382  throw C4MCParserErr(this, C4MCErr_FieldConstExp, CurrTokenIdtf);
1383  Type = CurrToken;
1384  if (!GetNextToken())
1385  throw C4MCParserErr(this, C4MCErr_EOF);
1386  }
1387  if (!pToNode->SetField(this, szFieldName, CurrTokenIdtf, Value, Type))
1388  // field not found
1389  throw C4MCParserErr(this, C4MCErr_Field404, szFieldName);
1390  break;
1391  }
1392  default:
1393  {
1394  throw C4MCParserErr(this, C4MCErr_FieldConstExp, CurrTokenIdtf);
1395  }
1396  }
1397 
1398  // now, the one and only thing to get is a semicolon
1399  if (CurrToken != MCT_SCOLON)
1400  throw C4MCParserErr(this, C4MCErr_SColonExp);
1401 
1402 
1403  /*
1404  // set field: accept integer constants and identifiers
1405  switch (CurrToken)
1406  {
1407  case MCT_IDTF:
1408  // reset value field
1409  CurrTokenVal=0;
1410  // set field
1411  if (!pToNode->SetField(this, szFieldName, CurrTokenIdtf, CurrTokenVal, CurrToken))
1412  // field not found
1413  throw C4MCParserErr(this, C4MCErr_Field404, szFieldName);
1414  break;
1415  case MCT_INT:
1416  Value1 = CurrTokenVal;
1417  while (GetNextToken ())
1418  {
1419  switch (CurrToken)
1420  {
1421  case MCT_SCOLON:
1422  // set field
1423  if (!pToNode->SetField(this, szFieldName, CurrTokenIdtf, Value1, MCT_INT))
1424  // field not found
1425  throw C4MCParserErr(this, C4MCErr_Field404, szFieldName);
1426  return;
1427  break;
1428  case MCT_RANGE:
1429  break;
1430  case MCT_INT:
1431  Value2 = CurrTokenVal;
1432  Value1 += Random (Value2 - Value1);
1433  break;
1434  default:
1435  throw C4MCParserErr(this, C4MCErr_SColonExp);
1436  break;
1437  }
1438  }
1439  break;
1440  default:
1441  throw C4MCParserErr(this, C4MCErr_FieldConstExp, CurrTokenIdtf);
1442  break;
1443  }
1444  // now, the one and only thing to get is a semicolon
1445  if (!GetNextToken())
1446  throw C4MCParserErr(this, C4MCErr_EOF);
1447  if (CurrToken != MCT_SCOLON)
1448  throw C4MCParserErr(this, C4MCErr_SColonExp);*/
1449 }
1450 
1451 void C4MCParser::ParseFile(const char *szFilename, C4Group *pGrp)
1452 {
1453  size_t iSize; // file size
1454 
1455  // clear any old data
1456  Clear();
1457  // store filename
1458  SCopy(szFilename, Filename, C4MaxName);
1459  // check group
1460  if (!pGrp) throw C4MCParserErr(this, C4MCErr_NoGroup);
1461  // get file
1462  if (!pGrp->AccessEntry(szFilename, &iSize))
1463  // 404
1464  throw C4MCParserErr(this, C4MCErr_404);
1465  // file is empty?
1466  if (!iSize) return;
1467  // alloc mem
1468  Code = new char[iSize+1];
1469  // read file
1470  pGrp->Read((void *) Code, iSize);
1471  Code[iSize]=0;
1472  // parse it
1473  BPos=Code;
1474  CPos=Code;
1475  ParseTo(MapCreator);
1476  if (false) PrintNodeTree(MapCreator, 0);
1477  // free code
1478  // on errors, this will be done be destructor
1479  Clear();
1480 }
1481 
1482 void C4MCParser::Parse(const char *szScript)
1483 {
1484  // clear any old data
1485  Clear();
1486  // parse it
1487  BPos=szScript;
1488  CPos=szScript;
1489  ParseTo(MapCreator);
1490  if (false) PrintNodeTree(MapCreator, 0);
1491  // free code
1492  // on errors, this will be done be destructor
1493  Clear();
1494 
1495 }
1496 
1497 void C4MCParser::ParseMemFile(const char *szScript, const char *szFilename)
1498 {
1499  // clear any old data
1500  Clear();
1501  // store filename
1502  SCopy(szFilename, Filename, C4MaxName);
1503  // parse it
1504  BPos=szScript;
1505  CPos=szScript;
1506  ParseTo(MapCreator);
1507  // on errors, this will be done be destructor
1508  Clear();
1509 }
1510 
1511 
1512 // algorithms ---------------------
1513 
1514 // helper func
1515 bool PreparePeek(C4MCOverlay **ppOvrl, int32_t &iX, int32_t &iY, C4MCOverlay **ppTopOvrl)
1516 {
1517  // zoom out
1518  iX/=(*ppOvrl)->ZoomX; iY/=(*ppOvrl)->ZoomY;
1519  // get owning overlay
1520  C4MCOverlay *pOvrl2=(*ppOvrl)->OwnerOverlay();
1521  if (!pOvrl2) return false;
1522  // get uppermost overlay
1523  C4MCOverlay *pNextOvrl;
1524  for (*ppTopOvrl=pOvrl2; (pNextOvrl=(*ppTopOvrl)->OwnerOverlay()); *ppTopOvrl=pNextOvrl) {}
1525  // get first of operator-chain
1526  pOvrl2=pOvrl2->FirstOfChain();
1527  // set new overlay
1528  *ppOvrl=pOvrl2;
1529  // success
1530  return true;
1531 }
1532 
1533 #define a pOvrl->Alpha
1534 #define b pOvrl->Beta
1535 #define s pOvrl->Seed
1536 #define z C4MC_ZoomRes
1537 #define z2 (C4MC_ZoomRes*C4MC_ZoomRes)
1538 
1539 bool AlgoSolid(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1540 {
1541  // solid always solid :)
1542  return true;
1543 }
1544 
1545 bool AlgoRandom(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1546 {
1547  // totally random
1548  return !((((s ^ (iX<<2) ^ (iY<<5))^((s>>16)+1+iX+(iY<<2)))/17)%(a.Evaluate(C4MC_SizeRes)+2));
1549 }
1550 
1551 bool AlgoChecker(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1552 {
1553  // checkers with size of 10
1554  return !(((iX/(z*10))%2)^((iY/(z*10))%2));
1555 }
1556 
1557 bool AlgoBozo(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1558 {
1559  // do some bozo stuff - keep it regular here, since it may be modified by turbulence
1560  int32_t iXC=(iX/10+s+(iY/80))%(z*2)-z;
1561  int32_t iYC=(iY/10+s+(iX/80))%(z*2)-z;
1562  int32_t id=Abs(iXC*iYC); // ((iSeed^iX^iY)%z)
1563  return id > z2*(a.Evaluate(C4MC_SizeRes)+10)/50;
1564 }
1565 
1566 bool AlgoSin(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1567 {
1568  // a sine curve where bottom is filled
1569  return iY > fixtoi((Sin(itofix(iX/z*10))+1)*z*10);
1570 }
1571 
1572 bool AlgoBoxes(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1573 {
1574  // For percents instead of Pixels
1575  int32_t pxb = b.Evaluate(pOvrl->Wdt);
1576  int32_t pxa = a.Evaluate(pOvrl->Wdt);
1577  // return whether inside box
1578  return Abs(iX+(s%4738))%(pxb*z+1)<pxa*z+1 && Abs(iY+(s/4738))%(pxb*z+1)<pxa*z+1;
1579 }
1580 
1581 bool AlgoRndChecker(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1582 {
1583  // randomly set squares with size of 10
1584  return AlgoRandom(pOvrl, iX/(z*10), iY/(z*10));
1585 }
1586 
1587 bool AlgoLines(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1588 {
1589  // For percents instead of Pixels
1590  int32_t pxb = b.Evaluate(pOvrl->Wdt);
1591  int32_t pxa = a.Evaluate(pOvrl->Wdt);
1592  // return whether inside line
1593  return Abs(iX+(s%4738))%(pxb*z+1)<pxa*z+1;
1594 }
1595 
1596 bool AlgoBorder(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1597 {
1598  C4MCOverlay *pTopOvrl;
1599  // get params before, since pOvrl will be changed by PreparePeek
1600  int32_t la=a.Evaluate(pOvrl->Wdt); int32_t lb=b.Evaluate(pOvrl->Hgt);
1601  // prepare a pixel peek from owner
1602  if (!PreparePeek(&pOvrl, iX, iY, &pTopOvrl)) return false;
1603  // query a/b pixels in x/y-directions
1604  for (int32_t x=iX-la; x<=iX+la; x++) if (pTopOvrl->InBounds(x, iY)) if (!pOvrl->PeekPix(x, iY)) return true;
1605  for (int32_t y=iY-lb; y<=iY+lb; y++) if (pTopOvrl->InBounds(iX, y)) if (!pOvrl->PeekPix(iX, y)) return true;
1606  // nothing found
1607  return false;
1608 }
1609 
1610 bool AlgoMandel(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1611 {
1612  // how many iterations?
1613  uint32_t iMandelIter = a.Evaluate(C4MC_SizeRes) != 0 ? a.Evaluate(C4MC_SizeRes) : 1000;
1614  if (iMandelIter < 10) iMandelIter = 10;
1615  // calc c & ci values
1616  double c = ((double) iX / z / pOvrl->Wdt - .5 * ((double) pOvrl->ZoomX / z)) * 4;
1617  double ci = ((double) iY / z / pOvrl->Hgt - .5 * ((double) pOvrl->ZoomY / z)) * 4;
1618  // create _z & _zi
1619  double _z = c, _zi = ci;
1620  double xz;
1621  uint32_t i;
1622  for (i=0; i<iMandelIter; i++)
1623  {
1624  xz = _z * _z - _zi * _zi;
1625  _zi = 2 * _z * _zi + ci;
1626  _z = xz + c;
1627  if (_z * _z + _zi * _zi > 4) break;
1628  }
1629  return !(i<iMandelIter);
1630 }
1631 
1632 bool AlgoGradient(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1633 {
1634  return (std::abs((iX^(iY*3)) * 2531011L) % 214013L) % z > iX / pOvrl->Wdt;
1635 }
1636 
1637 bool AlgoScript(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1638 {
1639  C4AulParSet Pars(iX, iY, pOvrl->Alpha.Evaluate(C4MC_SizeRes), pOvrl->Beta.Evaluate(C4MC_SizeRes));
1640  return ::GameScript.Call(FormatString("ScriptAlgo%s", pOvrl->Name).getData(), &Pars).getBool();
1641 }
1642 
1643 bool AlgoRndAll(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1644 {
1645  // return by seed and params; ignore pos
1646  return s%100<a.Evaluate(C4MC_SizeRes);
1647 }
1648 
1649 bool AlgoPolygon(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
1650 {
1651  // Wo do not support empty polygons.
1652  if (!pOvrl -> ChildL) return false;
1653  int32_t uX = 0; // last point before current point
1654  int32_t uY = 0; // with uY != iY
1655  int32_t cX, cY; // current point
1656  int32_t lX = 0; // x of really last point before current point
1657  int32_t count = 0;
1658  bool ignore = false;
1659  int32_t zX; //Where edge intersects with line
1660  C4MCNode *pChild, *pStartChild;
1661  //get a point with uY!=iY, or anyone
1662  for (pChild = pOvrl -> ChildL; pChild->Prev; pChild = pChild->Prev)
1663  if (pChild->Type() == MCN_Point)
1664  {
1665  uX = ((C4MCPoint*) pChild) -> X * 100;
1666  lX = uX;
1667  uY = ((C4MCPoint*) pChild) -> Y * 100;
1668  if (iY != uY) break;
1669  }
1670  pStartChild = pChild -> Next;
1671  if (!pStartChild) pStartChild = pOvrl->Child0;
1672  if (!pStartChild) return false;
1673  for (pChild = pStartChild; ; pChild=pChild -> Next)
1674  {
1675  if (!pChild) pChild = pOvrl->Child0;
1676  if (pChild->Type() == MCN_Point)
1677  {
1678  cX = ((C4MCPoint*) pChild) -> X * 100;
1679  cY = ((C4MCPoint*) pChild) -> Y * 100;
1680  //If looking at line
1681  if (ignore)
1682  {
1683  //if C is on line
1684  if (cY == iY)
1685  {
1686  //if I is on edge
1687  if (((lX < iX) == (iX < cX)) || (cX == iX)) return true;
1688  }
1689  else
1690  {
1691  //if edge intersects line
1692  if ((uY < iY) == (iY < cY) && (lX >= iX)) count++;
1693  ignore = false;
1694  uX = cX;
1695  uY = cY;
1696  }
1697  }
1698  //if looking at ray
1699  else
1700  {
1701  //If point C lays on ray
1702  if (cY == iY)
1703  {
1704  //are I and C the same points?
1705  if (cX == iX) return true;
1706  //skip this point for now
1707  ignore = true;
1708  }
1709  else
1710  {
1711  //if edge intersects line
1712  if ((uY < iY) == (iY <= cY))
1713  {
1714  //and edge intersects ray, because both points are right of iX
1715  if (iX < std::min (uX, cX))
1716  {
1717  count++;
1718  }
1719  //or one is right of I
1720  else if (iX <= std::max (uX, cX))
1721  {
1722  //and edge intersects with ray
1723  if (iX < (zX = ((cX - uX) * (iY - uY) / (cY - uY)) + uX)) count++;
1724  //if I lays on CU
1725  if (zX == iX) return true;
1726  }
1727  }
1728  uX = cX;
1729  uY = cY;
1730  }
1731  }
1732  lX = cX;
1733  }
1734  if (pChild -> Next == pStartChild) break;
1735  if (!pChild -> Next) if (pStartChild == pOvrl->Child0) break;
1736  }
1737  //if edge has changed side of ray uneven times
1738  if ((count & 1) > 0) return true; else return false;
1739 }
1740 
1741 #undef a
1742 #undef b
1743 #undef s
1744 #undef z
1745 #undef z2
1746 
1748 {
1749  { "solid", &AlgoSolid },
1750  { "random", &AlgoRandom },
1751  { "checker", &AlgoChecker },
1752  { "bozo", &AlgoBozo },
1753  { "sin", &AlgoSin },
1754  { "boxes", &AlgoBoxes },
1755  { "rndchecker", &AlgoRndChecker },
1756  { "lines", &AlgoLines },
1757  { "border", &AlgoBorder },
1758  { "mandel", &AlgoMandel },
1759  { "gradient", &AlgoGradient },
1760  { "script", &AlgoScript },
1761  { "rndall", &AlgoRndAll },
1762  { "poly", &AlgoPolygon },
1763  { "", nullptr }
1764 };
1765 
1766 #define offsC4MCOvrl(x) reinterpret_cast<C4MCOverlayOffsetType>(&C4MCOverlay::x)
1767 
1768 namespace {
1769  C4MCNodeAttr C4MCOvrlMap[] =
1770  {
1771  { "x", C4MCV_Percent, offsC4MCOvrl(RX) },
1772  { "y", C4MCV_Percent, offsC4MCOvrl(RY) },
1773  { "wdt", C4MCV_Percent, offsC4MCOvrl(RWdt) },
1774  { "hgt", C4MCV_Percent, offsC4MCOvrl(RHgt) },
1775  { "ox", C4MCV_Percent, offsC4MCOvrl(ROffX) },
1776  { "oy", C4MCV_Percent, offsC4MCOvrl(ROffY) },
1777  { "mat", C4MCV_Material, offsC4MCOvrl(Material) },
1778  { "tex", C4MCV_Texture, offsC4MCOvrl(Texture) },
1779  { "algo", C4MCV_Algorithm, offsC4MCOvrl(Algorithm) },
1780  { "sub", C4MCV_Boolean, offsC4MCOvrl(Sub) },
1781  { "zoomX", C4MCV_Zoom, offsC4MCOvrl(ZoomX) },
1782  { "zoomY", C4MCV_Zoom, offsC4MCOvrl(ZoomY) },
1783  { "a", C4MCV_Pixels, offsC4MCOvrl(Alpha) },
1784  { "b", C4MCV_Pixels, offsC4MCOvrl(Beta) },
1785  { "turbulence", C4MCV_Integer, offsC4MCOvrl(Turbulence) },
1786  { "lambda", C4MCV_Integer, offsC4MCOvrl(Lambda) },
1787  { "rotate", C4MCV_Integer, offsC4MCOvrl(Rotate) },
1788  { "seed", C4MCV_Integer, offsC4MCOvrl(FixedSeed) },
1789  { "invert", C4MCV_Boolean, offsC4MCOvrl(Invert) },
1790  { "loosebounds", C4MCV_Boolean, offsC4MCOvrl(LooseBounds) },
1791  { "grp", C4MCV_Boolean, offsC4MCOvrl(Group) },
1792  { "mask", C4MCV_Boolean, offsC4MCOvrl(Mask) },
1793  { "evalFn", C4MCV_ScriptFunc, offsC4MCOvrl(pEvaluateFunc) },
1794  { "drawFn", C4MCV_ScriptFunc, offsC4MCOvrl(pDrawFunc) },
1795  { "", C4MCV_None, nullptr }
1796  };
1797 }
const char * getData() const
Definition: StdBuf.h:442
int_bool ROffY
#define C4MCErr_UnnamedNoGlbl
#define C4MC_ZoomRes
C4MaterialMap * MatMap
void Execute(int32_t iMapZoom)
bool SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType) override
C4Config Config
Definition: C4Config.cpp:833
int x
Definition: C4Record.h:180
bool AlgoSolid(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
#define z
#define C4MCErr_ReinstUnknown
C4MCOverlay * OwnerOverlay()
C4SLandscape * Landscape
uint32_t Random()
Definition: C4Random.cpp:43
const char * StrPar(C4MCParser *pParser, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
#define C4MCErr_404
bool AlgoRndChecker(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
C4MCNode * GetNodeByName(const char *szName)
#define C4MCErr_NoDirGlobal
#define C4MCErr_FieldConstExp
C4MCAlgorithm * GetAlgo(const char *szName)
friend class C4MCParserErr
C4GameScriptHost GameScript
#define C4MC_Point
bool AccessEntry(const char *szWildCard, size_t *iSize=nullptr, char *sFileName=nullptr, bool NeedsToBeAGroup=false)
Definition: C4Group.cpp:1695
#define C4MCErr_Obj2Exp
#define b
C4ConfigGeneral General
Definition: C4Config.h:251
bool ReadFile(const char *szFilename, C4Group *pGrp)
#define sprintf
Definition: Standard.h:164
#define C4MCErr_MapNoGlobal
C4MCPoint(C4MCNode *pOwner=nullptr)
int SGetLine(const char *szText, const char *cpPosition)
Definition: Standard.cpp:473
C4MCOverlay DefaultOverlay
C4AulFunc * GetFunc(C4PropertyName k) const
Definition: C4PropList.h:105
#define C4MCErr_PointOnlyOvl
void GetMapSize(int32_t &rWdt, int32_t &rHgt, int32_t iPlayerNum)
Definition: C4Scenario.cpp:317
C4Value Call(const char *szFunction, C4AulParSet *pPars=nullptr, bool fPassError=false)
C4Material * Map
Definition: C4Material.h:169
#define C4MC_SizeRes
void ParseFile(const char *szFilename, C4Group *pGrp)
C4Value C4VInt(int32_t i)
Definition: C4Value.h:242
BYTE * Bits
Definition: CSurface8.h:30
char Name[C4MaxName]
#define C4MCErr_EOF
#define C4MCErr_UnknownObj
int32_t Turbulence
C4MCOverlay * Overlay() override
C4MCParser(C4MapCreatorS2 *pMapCreator)
bool AlgoRandom(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
int_bool RHgt
uint8_t BYTE
bool AlgoPolygon(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
#define z2
C4MCCallbackArray * pDrawFunc
int y
Definition: C4Record.h:180
C4TextureMap * TexMap
virtual bool GlobalScope()
#define a
char Msg[C4MaxMessage]
#define s
bool AlgoScript(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
bool SEqual(const char *szStr1, const char *szStr2)
Definition: Standard.h:93
int32_t MTunnel
Definition: C4Material.cpp:36
#define C4MCErr_BlOpenExp
C4MCTokenType Op
void Evaluate() override
bool RenderPix(int32_t iX, int32_t iY, BYTE &rPix, BYTE &rPixBkg, C4MCTokenType eLastOp=MCT_NONE, bool fLastSet=false, bool fDraw=true, C4MCOverlay **ppPixelSetOverlay=nullptr)
#define C4MCErr_UnknownDir
Definition: C4Real.h:58
int Rotate
Definition: C4Record.h:180
const int C4M_MaxName
Definition: C4Constants.h:49
virtual void Evaluate()
int_bool ROffX
#define C4MCErr_MatNotFound
bool CheckMask(int32_t iX, int32_t iY)
#define C4MCErr_ReinstNoGlobal
bool CheckTexture(const char *szTexture)
Definition: C4Texture.cpp:485
bool RenderTo(BYTE *pToBuf, BYTE *pToBufBkg, int32_t iPitch)
C4MCPoint DefaultPoint
bool ReadScript(const char *szScript)
virtual C4MCNodeType Type()
const int32_t MNone
Definition: C4Constants.h:177
C4MCNode * Child0
int Turbulence
Definition: C4Record.h:180
C4MCCallbackArrayList CallbackArrays
C4MCNode * ChildL
C4MCNode * Owner
C4Real C4REAL10(int x)
Definition: C4Real.h:269
char Name[C4M_MaxName+1]
Definition: C4Material.h:89
void Evaluate() override
int Pitch
Definition: CSurface8.h:28
bool AlgoBozo(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
int y
Definition: C4Record.h:185
C4MCCallbackArray * pNext
#define C4MCErr_SColonExp
C4MCMap * GetMap(const char *szMapName)
C4Value ScenPropList
Definition: C4ScriptHost.h:163
bool PreparePeek(C4MCOverlay **ppOvrl, int32_t &iX, int32_t &iY, C4MCOverlay **ppTopOvrl)
C4MCNode(C4MCNode *pOwner=nullptr)
int_bool RWdt
void Parse(const char *szScript)
C4MCMap(C4MCNode *pOwner=nullptr)
void AddDbgRec(C4RecordChunkType eType, const void *pData, int iSize)
Definition: C4Record.cpp:32
const unsigned int C4MaxName
int32_t FixedSeed
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
bool PeekPix(int32_t iX, int32_t iY)
C4Value Exec(C4PropList *p=nullptr, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4AulFunc.h:72
bool AlgoBorder(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
void Add(C4MCCallbackArray *pNewArray)
int_bool RY
#define C4MCErr_Field404
#define C4MCErr_TexNotFound
void Reg2Owner(C4MCNode *pOwner)
void Execute(int32_t iMapZoom)
int32_t Num
Definition: C4Material.h:168
C4MCNode * Next
C4MCNodeType
int_bool Beta
virtual bool SetOp(C4MCTokenType eOp)
C4MCOverlay(C4MCNode *pOwner=nullptr)
C4MCCallbackArray * pEvaluateFunc
#define C4MC_Map
bool InBounds(int32_t iX, int32_t iY)
bool Render(const char *szMapName, CSurface8 *&sfcMap, CSurface8 *&sfcMapBkg)
bool AlgoChecker(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
#define C4MC_DefAlgo
#define C4MCErr_SColonOrOpExp
bool SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType) override
BYTE * RenderBuf(const char *szMapName, int32_t &sfcWdt, int32_t &sfcHgt)
#define C4MCErr_FieldValInvalid
C4MCCallbackArray * pFirst
int32_t Lambda
C4MapCreatorS2 * pMapCreator
friend class C4MCParser
virtual C4MCOverlay * Overlay()
#define C4MCErr_AlgoNotFound
C4Object * Object(C4PropList *_this)
Definition: C4AulDefFunc.h:34
void Default()
virtual bool SetField(C4MCParser *pParser, const char *szField, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
#define C4MCErr_NoRecTemplate
#define C4MCErr_IdtfExp
bool AlgoGradient(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
C4MCAlgorithm C4MCAlgoMap[]
C4MCParserErr(C4MCParser *pParser, const char *szMsg)
int32_t Get(const char *szMaterial)
Definition: C4Material.cpp:361
int32_t Rotate
C4MCMap * pCurrentMap
bool AlgoSin(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
bool(* Function)(C4MCOverlay *, int32_t, int32_t)
~C4MapCreatorS2() override
int32_t IntPar(C4MCParser *pParser, const char *szSVal, int32_t iVal, C4MCTokenType ValType)
C4MapCreatorS2(C4SLandscape *pLandscape, C4TextureMap *pTexMap, C4MaterialMap *pMatMap, int iPlayerCount)
C4MCTokenType
int_bool Alpha
#define C4MC_Overlay
bool AlgoBoxes(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
void ParseMemFile(const char *szScript, const char *szFilename)
void ReEvaluate()
#define offsC4MCOvrl(x)
C4MCValueType
bool Log(const char *szMessage)
Definition: C4Log.cpp:192
C4MCCallbackArray(C4AulFunc *pSFunc, C4MapCreatorS2 *pMapCreator)
BYTE Mat2PixColDefault(int32_t mat)
Definition: C4Material.h:235
#define C4MCErr_NoGroup
bool AlgoRndAll(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
bool AlgoMandel(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
C4MCOverlay * FirstOfChain()
void Set(int32_t value, bool percent)
int32_t DebugRec
Definition: C4Config.h:60
int32_t Evaluate(int32_t relative_to)
#define X(sdl, oc)
int_bool RX
C4MCAlgorithm * Algorithm
char Texture[C4M_MaxName+1]
virtual ~C4MCNode()
T Abs(T val)
Definition: Standard.h:42
C4Real Sin(const C4Real &fAngle)
Definition: C4Real.h:265
C4PropList * _getPropList() const
Definition: C4Value.h:129
C4MCNode * Prev
const int C4MaxMessage
Definition: C4Constants.h:28
int32_t GetIndexMatTex(const char *szMaterialTexture, const char *szDefaultTexture=nullptr, bool fAddIfNotExist=true, const char *szErrorIfFailed=nullptr)
Definition: C4Texture.cpp:441
void EnablePixel(int32_t iX, int32_t iY)
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
#define C4MCErr_EqSColonBlOpenExp
#define C4MCErr_OpsNoGlobal
C4MapCreatorS2 * MapCreator
int x
Definition: C4Record.h:185
#define C4MCErr_OpTypeErr
C4Real Cos(const C4Real &fAngle)
Definition: C4Real.h:266
void SetSize(int32_t iWdt, int32_t iHgt)
#define C4MCErr_SFuncNotFound
bool AlgoLines(C4MCOverlay *pOvrl, int32_t iX, int32_t iY)
int32_t Material
int iSize
Definition: TstC4NetIO.cpp:32
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
bool Read(void *pBuffer, size_t iSize) override
Definition: C4Group.cpp:1125