OpenClonk
C4MapScriptAlgo.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2013-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Handles scripted map creation */
19 
20 #include "C4Include.h"
21 #include "landscape/C4MapScript.h"
22 #include "lib/C4Random.h"
23 
25 
26 bool C4MapScriptAlgo::GetXYProps(const C4PropList *props, C4PropertyName k, int32_t *out_xy, bool zero_defaults)
27 {
28  // Evaluate property named "k" in proplist props to store two numbers in out_xy:
29  // If props->k is a single integer, fill both numbers in out_xy with it
30  // If props->k is an array, check that it contains two numbers and store them in out_xy
31  if (!props->HasProperty(&Strings.P[k]))
32  {
33  if (zero_defaults) out_xy[0] = out_xy[1] = 0;
34  return false;
35  }
36  C4Value val; C4ValueArray *arr;
37  props->GetProperty(k, &val);
38  if ((arr = val.getArray()))
39  {
40  if (arr->GetSize() != 2)
41  throw C4AulExecError(FormatString(R"(C4MapScriptAlgo: Expected either integer or array with two integer elements in property "%s".)", Strings.P[k].GetCStr()).getData());
42  out_xy[0] = arr->GetItem(0).getInt();
43  out_xy[1] = arr->GetItem(1).getInt();
44  }
45  else
46  {
47  out_xy[0] = out_xy[1] = val.getInt();
48  }
49  return true;
50 }
51 
53 {
54  // Get MAPALGO_Layer properties
55  C4PropList *layer_pl = props->GetPropertyPropList(P_Layer);
56  if (!layer_pl || !(layer = layer_pl->GetMapScriptLayer()))
57  throw C4AulExecError(R"(C4MapScriptAlgoLayer: Expected layer in "Layer" property.)");
58 }
59 
60 bool C4MapScriptAlgoLayer::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
61 {
62  fg = layer->GetPix(x,y,0);
63  bg = layer->GetBackPix(x,y,0);
64 
65  // Evaluate MAPALGO_Layer at x,y: Just query pixel in layer. Pixels outside the layer range are zero.
66  return fg != 0 || bg != 0;
67 }
68 
70 {
71  // Get MAPALGO_RndChecker properties
72  seed = props->GetPropertyInt(P_Seed);
73  if (!seed) seed = Random(65536);
74  set_percentage = Clamp(props->GetPropertyInt(P_Ratio), 0, 100);
75  if (!set_percentage) set_percentage = 50;
76  checker_wdt = Abs(props->GetPropertyInt(P_Wdt));
77  if (!checker_wdt) checker_wdt = 10;
78  checker_hgt = Abs(props->GetPropertyInt(P_Hgt));
79  if (!checker_hgt) checker_hgt = 10;
80  C4Value is_fixed_offset_v;
81  if (props->GetProperty(P_FixedOffset, &is_fixed_offset_v))
82  is_fixed_offset = is_fixed_offset_v.getBool();
83  else
84  is_fixed_offset = false;
85 }
86 
87 // Division and modulo operators that always round downwards
88 // Both assuming b>0
89 static int32_t divD(int32_t a, int32_t b) { return a/b-(a%b<0); }
90 static int32_t modD(int32_t a, int32_t b) { return (a>=0)?a%b:b-(-a)%b; }
91 
92 // Creates a field of random numbers between 0 and scale-1. Returns the value of the field at position x,y
93 // Function should be deterministic for the same value of x,y, but should look somewhat random wrt neighbouring values of x,y
94 int32_t QuerySeededRandomField(int32_t seed, int32_t x, int32_t y, int32_t scale)
95 {
96  return modD((((seed ^ (x*214013))*214013) ^ (y*214013)), scale);
97 }
98 
99 bool C4MapScriptAlgoRndChecker::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
100 {
101  // Evaluate MAPALGO_RndChecker at x,y: Query a seeded random field scaled by checker_wdt,checker_hgt
102  if (!is_fixed_offset) { x+=seed%checker_wdt; y+=((seed*214013)%checker_hgt); }
103  x = divD(x, checker_wdt); y = divD(y, checker_hgt);
104  return QuerySeededRandomField(seed, x,y, 100) < set_percentage;
105 }
106 
108 {
109  // Get MAPALGO_Rect properties
110  rect = C4Rect(props->GetPropertyInt(P_X), props->GetPropertyInt(P_Y), props->GetPropertyInt(P_Wdt), props->GetPropertyInt(P_Hgt));
111 }
112 
113 bool C4MapScriptAlgoRect::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
114 {
115  // Evaluate MAPALGO_Rect at x,y: Return 1 for pixels contained in rect, 0 otherwise
116  return rect.Contains(x, y);
117 }
118 
120 {
121  // Get MAPALGO_Ellipse properties
122  cx = props->GetPropertyInt(P_X);
123  cy = props->GetPropertyInt(P_Y);
124  wdt = Abs(props->GetPropertyInt(P_Wdt));
125  hgt = Abs(props->GetPropertyInt(P_Hgt));
126  if (!wdt) wdt = 10;
127  if (!hgt) hgt = wdt;
128 }
129 
130 bool C4MapScriptAlgoEllipse::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
131 {
132  // Evaluate MAPALGO_Ellipse at x,y: Return 1 for pixels within ellipse, 0 otherwise
133  // warning: overflows for large values (wdt or hgt >=256)
134  // but who would draw such large ellipse anyway?
135  uint64_t dx = Abs((cx-x)*hgt), dy = Abs((cy-y)*wdt);
136  return dx*dx+dy*dy < uint64_t(wdt)*wdt*hgt*hgt;
137 }
138 
140 {
141  // Get MAPALGO_Polygon properties
142  C4Value vptx, vpty;
143  props->GetProperty(P_X, &vptx); props->GetProperty(P_Y, &vpty);
144  C4ValueArray *ptx = vptx.getArray(), *pty = vpty.getArray();
145  if (!ptx || !pty || ptx->GetSize() != pty->GetSize())
146  throw C4AulExecError(R"(C4MapScriptAlgoPolygon: Expected two equally sized int arrays in properties "X" and "Y".)");
147  poly.resize(ptx->GetSize());
148  for (int32_t i=0; i<ptx->GetSize(); ++i)
149  {
150  poly[i].x = ptx->GetItem(i).getInt();
151  poly[i].y = pty->GetItem(i).getInt();
152  }
153  wdt = props->GetPropertyInt(P_Wdt);
154  if (!wdt) wdt = 1;
155  empty = !!props->GetPropertyInt(P_Empty);
156  open = !!props->GetPropertyInt(P_Open);
157  if (open && !empty) throw C4AulExecError("C4MapScriptAlgoPolygon: Only empty polygons may be open.");
158 }
159 
160 bool C4MapScriptAlgoPolygon::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
161 {
162  // Evaluate MAPALGO_Polygon at x,y: Return 1 for pixels within the polygon or its borders, 0 otherwise
163  int32_t crossings = 0;
164  for (size_t i=0; i<poly.size(); ++i)
165  {
166  Pt pt1 = poly[i];
167  Pt pt2 = poly[(i+1)%poly.size()];
168  // check border line distance
169  int32_t pdx = pt2.x-pt1.x, pdy = pt2.y-pt1.y, dx = x-pt1.x, dy = y-pt1.y;
170  if (i!=poly.size()-1 || !open)
171  {
172  int64_t d = dx*pdy-dy*pdx;
173  int32_t lsq = (pdx*pdx+pdy*pdy);
174  if (d*d < wdt*wdt*lsq) // check distance perpendicular to line
175  {
176  if (Inside(dx*pdx+dy*pdy, 0, lsq)) // check if point lies within pt1 and pt2
177  return true; // x/y lies on this line
178  }
179  }
180  // check point distance
181  if (dx*dx+dy*dy < wdt*wdt) return true; // x/y lies close to edge point
182  // filling of polygon: point is contained if it crosses an off number of borders
183  if (!empty && (pt1.y<=y) != (pt2.y<=y)) // crossing vertically?
184  {
185  // does line pt1-pt2 intersect line (x,y)-(inf,y)?
186  crossings += (dx>dy*pdx/pdy);
187  }
188  }
189  // x/y lies inside polygon
190  return (crossings % 2)==1;
191 }
192 
194 {
195  // Get MAPALGO_Lines properties
196  lx = props->GetPropertyInt(P_X);
197  ly = props->GetPropertyInt(P_Y);
198  if (!lx && !ly) throw C4AulExecError(R"(C4MapScriptAlgoLines: Invalid direction vector. Either "X" or "Y" must be nonzero!)");
199  ox = props->GetPropertyInt(P_OffX);
200  oy = props->GetPropertyInt(P_OffY);
201  // use sync-safe distance function to calculate line width
202  int32_t l = Distance(0,0,lx,ly);
203  // default distance: double line width, so lines and gaps have same width
204  distance = props->GetPropertyInt(P_Distance);
205  if (!distance) distance = l+l; // 1+1=2
206  // cache for calculation
207  ll = int64_t(lx)*lx+int64_t(ly)*ly;
208  dl = int64_t(distance) * l;
209 }
210 
211 bool C4MapScriptAlgoLines::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
212 {
213  // Evaluate MAPALGO_Lines at x,y: Return 1 for pixels contained in lines, 0 for pixels between lines
214  int64_t ax = int64_t(x)-ox;
215  int64_t ay = int64_t(y)-oy;
216  int64_t line_pos = (ax*lx + ay*ly) % dl;
217  if (line_pos < 0) line_pos += dl;
218  return line_pos < ll;
219 }
220 
221 C4MapScriptAlgoModifier::C4MapScriptAlgoModifier(const C4PropList *props, int32_t min_ops, int32_t max_ops)
222 {
223  // Evaluate "Op" property of all algos that take another algo or layer as an operand
224  // Op may be a proplist or an array of proplists
225  C4Value vops; int32_t n; C4ValueArray temp_ops;
226  props->GetProperty(P_Op, &vops);
227  C4ValueArray *ops = vops.getArray();
228  if (!ops)
229  {
230  C4PropList *op = vops.getPropList();
231  if (op)
232  {
233  temp_ops.SetItem(0, vops);
234  ops = &temp_ops;
235  n = 1;
236  }
237  }
238  else
239  {
240  n = ops->GetSize();
241  }
242  if (!ops || n<min_ops || (max_ops && n>max_ops))
243  throw C4AulExecError(FormatString(R"(C4MapScriptAlgo: Expected between %d and %d operands in property "Op".)", (int)min_ops, (int)max_ops).getData());
244  operands.resize(n);
245  try
246  {
247  // can easily crash this by building a recursive prop list
248  // unfortunately, protecting against that is not trivial
249  for (int32_t i=0; i<n; ++i)
250  {
251  C4MapScriptAlgo *new_algo = FnParAlgo(ops->GetItem(i).getPropList());
252  if (!new_algo) throw C4AulExecError(FormatString(R"(C4MapScriptAlgo: Operand %d in property "Op" not valid.)", (int)i).getData());
253  operands[i] = new_algo;
254  }
255  }
256  catch (...)
257  {
258  Clear();
259  throw;
260  }
261 }
262 
264 {
265  // Child algos are owned by this algo, so delete them
266  for (auto & operand : operands) delete operand;
267  operands.clear();
268 }
269 
270 bool C4MapScriptAlgoAnd::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
271 {
272  // Evaluate MAPALGO_And at x,y:
273  // Return 0 if any of the operands is 0. Otherwise, returns value of last operand.
274  bool val=false;
275  for (auto operand : operands)
276  if (!(val=(*operand)(x, y, fg, bg)))
277  return false;
278  return val;
279 }
280 
281 bool C4MapScriptAlgoOr::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
282 {
283  // Evaluate MAPALGO_Or at x,y:
284  // Return first nonzero operand
285  bool val;
286  for (auto operand : operands)
287  if ((val=(*operand)(x, y, fg, bg)))
288  return val;
289  // If all operands are zero, return zero.
290  return false;
291 }
292 
293 bool C4MapScriptAlgoNot::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
294 {
295  // Evaluate MAPALGO_Not at x,y:
296  assert(operands.size()==1);
297  // Return zero if operand is set and one otherwise
298  return !(*operands[0])(x, y, fg, bg);
299 }
300 
301 bool C4MapScriptAlgoXor::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
302 {
303  // Evaluate MAPALGO_Xor at x,y:
304  assert(operands.size()==2);
305  // If exactly one of the two operands is nonzero, return it. Otherwise, return zero.
306  uint8_t fg1, bg1, fg2, bg2;
307  bool v1=(*operands[0])(x,y,fg1,bg1);
308  bool v2=(*operands[1])(x,y,fg2,bg2);
309  if ((v1 && v2) || (!v1 && !v2))
310  return false;
311  if (v1) { fg = fg1; bg = bg1; return true; }
312  fg = fg2; bg = bg2;
313  return true;
314 }
315 
317 {
318  // Get MAPALGO_Offset properties
319  ox = props->GetPropertyInt(P_OffX);
320  oy = props->GetPropertyInt(P_OffY);
321 }
322 
323 bool C4MapScriptAlgoOffset::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
324 {
325  // Evaluate MAPALGO_Offset at x,y:
326  assert(operands.size()==1);
327  // Return base layer shifted by ox,oy
328  return (*operands[0])(x-ox,y-oy, fg, bg);
329 }
330 
332 {
333  // Get MAPALGO_Scale properties
334  sx = props->GetPropertyInt(P_X);
335  sy = props->GetPropertyInt(P_Y);
336  if (!sx) sx=100;
337  if (!sy) sy=100;
338  cx = props->GetPropertyInt(P_OffX);
339  cy = props->GetPropertyInt(P_OffY);
340 }
341 
342 bool C4MapScriptAlgoScale::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
343 {
344  // Evaluate MAPALGO_Scale at x,y:
345  assert(operands.size()==1);
346  // Return base layer scaled by sx,sy percent from fixed point cx-.5,cy-.5
347  return (*operands[0])((((x-cx)*2+1)*50-sx/2)/sx+cx,(((y-cy)*2+1)*50-sy/2)/sy+cy, fg, bg);
348 }
349 
351 {
352  // Get MAPALGO_Rotate properties
353  int32_t r = props->GetPropertyInt(P_R);
354  sr=fixtoi(Sin(itofix(r)), Precision);
355  cr=fixtoi(Cos(itofix(r)), Precision);
356  ox = props->GetPropertyInt(P_OffX);
357  oy = props->GetPropertyInt(P_OffY);
358 }
359 
360 bool C4MapScriptAlgoRotate::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
361 {
362  // Evaluate MAPALGO_Rotate at x,y:
363  assert(operands.size()==1);
364  // Return base layer rotated by angle r around point ox,oy
365  x-=ox; y-=oy;
366  return (*operands[0])(x*cr/Precision-y*sr/Precision+ox,x*sr/Precision+y*cr/Precision+oy, fg, bg);
367 }
368 
370 {
371  // Get MAPALGO_Turbulence properties
372  seed = props->GetPropertyInt(P_Seed);
373  if (!seed) seed = Random(65536);
374  GetXYProps(props, P_Amplitude, amp, true);
375  GetXYProps(props, P_Scale, scale, true);
376  if (!scale[0]) scale[0] = 10;
377  if (!scale[1]) scale[1] = 10;
378  if (!amp[0] && !amp[1]) { amp[0] = amp[1] = 10; }
379  iterations = props->GetPropertyInt(P_Iterations);
380  if (!iterations) iterations = 2;
381 }
382 
383 bool C4MapScriptAlgoTurbulence::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
384 {
385  // Evaluate MAPALGO_Turbulence at x,y:
386  // move by a random offset iterations times
387  assert(operands.size()==1);
388  int32_t xy[] = {x, y};
389  for (int32_t iter=0; iter<iterations; ++iter)
390  {
391  int32_t s[2], p[2];
392  for (int dim=0; dim<2; ++dim)
393  {
394  s[dim] = divD(xy[dim], scale[dim]);
395  p[dim] = modD(xy[dim], scale[dim]);
396  }
397  int32_t a[2][2];
398  for (int dim=0; dim<2; ++dim)
399  {
400  int32_t aamp = amp[dim] / (iter+1);
401  if (!aamp) continue;
402  for (int dx=0; dx<2; ++dx) for (int dy=0; dy<2; ++dy) a[dx][dy] = QuerySeededRandomField(seed+dim, s[0]+dx, s[1]+dy, aamp) - aamp/2;
403  int32_t a_interp = a[0][0]*(scale[0]-p[0])*(scale[1]-p[1])
404  + a[1][0]*( p[0])*(scale[1]-p[1])
405  + a[0][1]*(scale[0]-p[0])*( p[1])
406  + a[1][1]*( p[0])*( p[1]);
407  xy[dim] += a_interp / (scale[0]*scale[1]);
408  }
409  }
410  return (*operands[0])(xy[0],xy[1], fg, bg);
411 }
412 
413 void C4MapScriptAlgoBorder::ResolveBorderProps(int32_t *p)
414 {
415  // Converts arrays in MAPALGO_Border properties to array of [inner border, outer border]
416  // Input: Negative values mark outer borders; positive values mark inner borders
417  int32_t inner=0, outer=0;
418  for (int32_t i=0; i<2; ++i) if (p[i]>0) inner=p[i]; else if (p[i]<0) outer=-p[i];
419  p[0] = inner; p[1] = outer;
420 }
421 
423 {
424  // Get MAPALGO_Border properties
425  int32_t wdt[2] = {0,0};
426  // Parameter Wdt fills all directions
427  int32_t n_borders = 0;
428  n_borders += GetXYProps(props, P_Wdt, wdt, false);
429  for (int32_t i=0; i<2; ++i) left[i]=top[i]=right[i]=bottom[i]=wdt[i];
430  // Individual direction parameters
431  n_borders += GetXYProps(props, P_Left, left, false);
432  n_borders += GetXYProps(props, P_Top, top, false);
433  n_borders += GetXYProps(props, P_Right, right, false);
434  n_borders += GetXYProps(props, P_Bottom, bottom, false);
435  // Resolve negative/positive values to inner/outer borders
436  ResolveBorderProps(left);
437  ResolveBorderProps(top);
438  ResolveBorderProps(right);
439  ResolveBorderProps(bottom);
440  // If nothing was specified, fill all directions with a default: Draw 1px of outer border
441  if (!n_borders)
442  {
443  left[1] = top[1] = right[1] = bottom[1] = 1;
444  }
445 }
446 
447 bool C4MapScriptAlgoBorder::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
448 {
449  // Evaluate MAPALGO_Border at x,y: Check if position is at a border of operand layer
450  // For borders inside operand layer, return the operand material. For outside borders, just return 1. For non-borders, return 0.
451  // Are we inside or outside?
452  const C4MapScriptAlgo &l = *operands[0];
453  bool inside = l(x,y,fg,bg);
454  // Check four sideways directions
455  const int32_t *ymove[] = { top, bottom }, *xmove [] ={ left, right };
456  const int32_t d[] = { -1, +1 };
457  for (int32_t dir=0; dir<2; ++dir)
458  {
459  uint8_t fake_fg, fake_bg;
460  int32_t hgt = ymove[inside!=!dir][!inside];
461  for (int32_t dy=0; dy<hgt; ++dy)
462  if (inside==!l(x,y+d[dir]*(dy+1), fake_fg, fake_bg))
463  return true;
464  int32_t wdt = xmove[inside!=!dir][!inside];
465  for (int32_t dx=0; dx<wdt; ++dx)
466  if (inside==!l(x+d[dir]*(dx+1),y, fake_fg, fake_bg))
467  return true;
468  }
469  // Not on border
470  return false;
471 }
472 
474 {
475  // Get MAPALGO_Filter properties
476  C4Value spec;
477  if (!props->GetProperty(P_Filter, &spec))
478  throw C4AulExecError("MapScriptAlgoFilter without Filter property.");
479  filter.Init(spec);
480 }
481 
482 bool C4MapScriptAlgoFilter::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const
483 {
484  // Evaluate MAPALGO_Filter at x,y:
485  // Return original color if it's marked to go through filter
486  bool col = (*operands[0])(x,y, fg, bg);
487  if (!col) fg = bg = 0;
488  return filter(fg, bg);
489 }
490 
492  : inner(inner), fg(fg), bg(bg)
493 {
494  assert(inner);
495  /* member initializers only */
496 }
497 
499  delete inner;
500 }
501 
502 bool C4MapScriptAlgoSetMaterial::operator () (int32_t x, int32_t y, uint8_t& fg, uint8_t& bg) const {
503  bool result = (*inner)(x, y, fg, bg);
504  fg = this->fg;
505  bg = this->bg;
506  return result;
507 }
508 
509 static C4MapScriptAlgo *FnParAlgoInner(C4PropList *algo_par)
510 {
511  // if algo is a layer, take that directly
512  C4MapScriptLayer *algo_layer = algo_par->GetMapScriptLayer();
513  if (algo_layer) return new C4MapScriptAlgoLayer(algo_layer);
514  // otherwise, determine by proplist parameter "algo"
515  switch (algo_par->GetPropertyInt(P_Algo))
516  {
517  case MAPALGO_Layer: return new C4MapScriptAlgoLayer(algo_par);
518  case MAPALGO_RndChecker: return new C4MapScriptAlgoRndChecker(algo_par);
519  case MAPALGO_And: return new C4MapScriptAlgoAnd(algo_par);
520  case MAPALGO_Or: return new C4MapScriptAlgoOr(algo_par);
521  case MAPALGO_Xor: return new C4MapScriptAlgoXor(algo_par);
522  case MAPALGO_Not: return new C4MapScriptAlgoNot(algo_par);
523  case MAPALGO_Offset: return new C4MapScriptAlgoOffset(algo_par);
524  case MAPALGO_Scale: return new C4MapScriptAlgoScale(algo_par);
525  case MAPALGO_Rotate: return new C4MapScriptAlgoRotate(algo_par);
526  case MAPALGO_Rect: return new C4MapScriptAlgoRect(algo_par);
527  case MAPALGO_Ellipsis: DebugLog("WARNING: MAPALGO_Ellipsis is deprecated. Use MAPALGO_Ellipse instead.");
528  /* fallthru */
529  case MAPALGO_Ellipse: return new C4MapScriptAlgoEllipse(algo_par);
530  case MAPALGO_Polygon: return new C4MapScriptAlgoPolygon(algo_par);
531  case MAPALGO_Lines: return new C4MapScriptAlgoLines(algo_par);
532  case MAPALGO_Turbulence: return new C4MapScriptAlgoTurbulence(algo_par);
533  case MAPALGO_Border: return new C4MapScriptAlgoBorder(algo_par);
534  case MAPALGO_Filter: return new C4MapScriptAlgoFilter(algo_par);
535  default:
536  throw C4AulExecError(FormatString("got invalid algo: %d", algo_par->GetPropertyInt(P_Algo)).getData());
537  }
538  return nullptr;
539 }
540 
542 {
543  // Convert script function parameter to internal C4MapScriptAlgo class. Also resolve all parameters and nested child algos.
544  if (!algo_par) return nullptr;
545 
546  C4MapScriptAlgo *inner = FnParAlgoInner(algo_par);
547 
548  // if the Material property is set, use that material:
549  C4String *material = algo_par->GetPropertyStr(P_Material);
550  if (material) { // set inner material by wrapping with SetMaterial algo.
551  uint8_t fg = 0, bg = 0;
552  if (!FnParTexCol(material, fg, bg))
553  throw C4AulExecError("Invalid Material in map script algorithm.");
554  return new C4MapScriptAlgoSetMaterial(inner, fg, bg);
555  }
556 
557  return inner; // otherwise, just return the original algo
558 }
#define s
C4StringTable Strings
Definition: C4Globals.cpp:42
bool DebugLog(const char *strMessage)
Definition: C4Log.cpp:282
#define a
#define b
bool FnParTexCol(C4String *mattex, uint8_t &fg, uint8_t &bg)
Definition: C4MapScript.cpp:48
@ MAPALGO_Layer
Definition: C4MapScript.h:70
@ MAPALGO_Border
Definition: C4MapScript.h:90
@ MAPALGO_Ellipsis
Definition: C4MapScript.h:75
@ MAPALGO_Rect
Definition: C4MapScript.h:74
@ MAPALGO_Rotate
Definition: C4MapScript.h:87
@ MAPALGO_Turbulence
Definition: C4MapScript.h:88
@ MAPALGO_Or
Definition: C4MapScript.h:81
@ MAPALGO_Filter
Definition: C4MapScript.h:91
@ MAPALGO_Lines
Definition: C4MapScript.h:77
@ MAPALGO_Not
Definition: C4MapScript.h:82
@ MAPALGO_RndChecker
Definition: C4MapScript.h:72
@ MAPALGO_And
Definition: C4MapScript.h:80
@ MAPALGO_Scale
Definition: C4MapScript.h:86
@ MAPALGO_Xor
Definition: C4MapScript.h:83
@ MAPALGO_Polygon
Definition: C4MapScript.h:76
@ MAPALGO_Ellipse
Definition: C4MapScript.h:78
@ MAPALGO_Offset
Definition: C4MapScript.h:85
C4MapScriptAlgo * FnParAlgo(C4PropList *algo_par)
int32_t QuerySeededRandomField(int32_t seed, int32_t x, int32_t y, int32_t scale)
uint32_t Random()
Definition: C4Random.cpp:43
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
C4Real Cos(const C4Real &fAngle)
Definition: C4Real.h:266
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
C4Real Sin(const C4Real &fAngle)
Definition: C4Real.h:265
C4PropertyName
@ P_Scale
@ P_Ratio
@ P_R
@ P_Wdt
@ P_Bottom
@ P_FixedOffset
@ P_Amplitude
@ P_Y
@ P_Top
@ P_Hgt
@ P_OffX
@ P_Iterations
@ P_Distance
@ P_Material
@ P_Layer
@ P_Filter
@ P_OffY
@ P_X
@ P_Seed
@ P_Open
@ P_Left
@ P_Algo
@ P_Op
@ P_Right
@ P_Empty
int32_t Distance(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2)
Definition: Standard.cpp:25
T Abs(T val)
Definition: Standard.h:42
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoBorder(const C4PropList *props)
C4MapScriptAlgoEllipse(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoFilter(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
bool GetXYProps(const C4PropList *props, C4PropertyName k, int32_t *out_xy, bool zero_defaults)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoLayer(const C4MapScriptLayer *layer)
Definition: C4MapScript.h:99
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoLines(const C4PropList *props)
C4MapScriptAlgoModifier(const C4PropList *props, int32_t min_ops=0, int32_t max_ops=0)
std::vector< C4MapScriptAlgo * > operands
Definition: C4MapScript.h:166
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoOffset(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoPolygon(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoRect(const C4PropList *props)
C4MapScriptAlgoRndChecker(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoRotate(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoScale(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoSetMaterial(C4MapScriptAlgo *inner, int fg, int bg)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
C4MapScriptAlgoTurbulence(const C4PropList *props)
bool operator()(int32_t x, int32_t y, uint8_t &fg, uint8_t &bg) const override
uint8_t GetPix(int32_t x, int32_t y, uint8_t outside_col) const
Definition: C4MapScript.h:317
uint8_t GetBackPix(int32_t x, int32_t y, uint8_t outside_col) const
Definition: C4MapScript.h:318
void Init(const C4Value &spec)
int32_t GetPropertyInt(C4PropertyName k, int32_t default_val=0) const
Definition: C4PropList.cpp:855
bool HasProperty(C4String *k) const
Definition: C4PropList.h:122
C4PropList * GetPropertyPropList(C4PropertyName k) const
Definition: C4PropList.cpp:869
C4String * GetPropertyStr(C4PropertyName k) const
Definition: C4PropList.cpp:744
virtual class C4MapScriptLayer * GetMapScriptLayer()
Definition: C4PropList.cpp:660
bool GetProperty(C4PropertyName k, C4Value *pResult) const
Definition: C4PropList.h:105
Definition: C4Rect.h:28
bool Contains(int32_t iX, int32_t iY) const
Definition: C4Rect.h:40
const char * GetCStr() const
Definition: C4StringTable.h:49
C4String P[P_LAST]
const C4Value & GetItem(int32_t iElem) const
Definition: C4ValueArray.h:38
void SetItem(int32_t iElemNr, const C4Value &Value)
int32_t GetSize() const
Definition: C4ValueArray.h:36
C4ValueArray * getArray() const
Definition: C4Value.h:118
int32_t getInt() const
Definition: C4Value.h:112
bool getBool() const
Definition: C4Value.h:113
C4PropList * getPropList() const
Definition: C4Value.h:116
const char * getData() const
Definition: StdBuf.h:442