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