OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4Script.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Functions mapped by C4Script */
19 
20 #include "C4Include.h"
21 
22 #include "C4Version.h"
23 #include "lib/C4Random.h"
24 #include "script/C4AulExec.h"
25 #include "script/C4AulDefFunc.h"
26 
27 //========================== Some Support Functions =======================================
28 
29 StdStrBuf FnStringFormat(C4PropList * _this, C4String *szFormatPar, C4Value * Pars, int ParCount)
30 {
31  int cPar=0;
32 
33  StdStrBuf StringBuf("", false);
34  const char * cpFormat = FnStringPar(szFormatPar);
35  const char * cpType;
36  char szField[20];
37  while (*cpFormat)
38  {
39  // Copy normal stuff
40  while (*cpFormat && (*cpFormat!='%'))
41  StringBuf.AppendChar(*cpFormat++);
42  // Field
43  if (*cpFormat=='%')
44  {
45  // Scan field type
46  for (cpType=cpFormat+1; *cpType && (*cpType == '+' || *cpType == '-' || *cpType == '.' || *cpType == '#' || *cpType == ' ' || Inside(*cpType,'0','9')); cpType++) {}
47  // Copy field
48  SCopy(cpFormat,szField,std::min<unsigned int>(sizeof szField - 1, cpType - cpFormat + 1));
49  // Insert field by type
50  switch (*cpType)
51  {
52  // number
53  case 'd': case 'x': case 'X':
54  {
55  if (cPar >= ParCount) throw C4AulExecError("format placeholder without parameter");
56  StringBuf.AppendFormat(szField, Pars[cPar++].getInt());
57  cpFormat+=SLen(szField);
58  break;
59  }
60  // character
61  case 'c':
62  {
63  if (cPar >= ParCount) throw C4AulExecError("format placeholder without parameter");
64  StringBuf.AppendCharacter(Pars[cPar++].getInt());
65  cpFormat+=SLen(szField);
66  break;
67  }
68  // C4ID
69  case 'i':
70  // C4Value
71  case 'v':
72  {
73  if (cPar >= ParCount) throw C4AulExecError("format placeholder without parameter");
74  StringBuf.Append(static_cast<const StdStrBuf&>(Pars[cPar++].GetDataString(10)));
75  cpFormat+=SLen(szField);
76  break;
77  }
78  // String
79  case 's':
80  {
81  // get string
82  if (cPar >= ParCount) throw C4AulExecError("format placeholder without parameter");
83  const char *szStr = "(null)";
84  if (Pars[cPar].GetData())
85  {
86  C4String * pStr = Pars[cPar].getStr();
87  if (!pStr) throw C4AulExecError("string format placeholder without string");
88  szStr = pStr->GetCStr();
89  }
90  ++cPar;
91  StringBuf.AppendFormat(szField, szStr);
92  cpFormat+=SLen(szField);
93  break;
94  }
95  case '%':
96  StringBuf.AppendChar('%');
97  cpFormat+=SLen(szField);
98  break;
99  // Undefined / Empty
100  default:
101  StringBuf.AppendChar('%');
102  cpFormat++;
103  break;
104  }
105  }
106  }
107  return StringBuf;
108 }
109 
111  C4AulFunc(Parent, pDef->Identifier), Def(pDef)
112 {
113  Parent->SetPropertyByS(Name, C4VFunction(this));
114 }
115 
116 C4AulDefFunc::~C4AulDefFunc() = default;
117 
118 C4Value C4AulDefFunc::Exec(C4PropList * p, C4Value pPars[], bool fPassErrors)
119 {
120  assert(Def->FunctionC4V);
121  return Def->FunctionC4V(p, pPars);
122 }
123 
124 //=============================== C4Script Functions ====================================
125 
126 #define MAKE_AND_RETURN_ARRAY(values) do { \
127  C4ValueArray *matrix = new C4ValueArray(sizeof(values) / sizeof(*values)); \
128  for (size_t i = 0; i < sizeof(values) / sizeof(*values); ++i) \
129  (*matrix)[i] = C4VInt(values[i]); \
130  return matrix; \
131 } while (0)
132 
133 static C4ValueArray *FnTrans_Identity(C4PropList * _this)
134 {
135  long values[] =
136  {
137  1000, 0, 0, 0,
138  0, 1000, 0, 0,
139  0, 0, 1000, 0
140  };
141  MAKE_AND_RETURN_ARRAY(values);
142 }
143 
144 static C4ValueArray *FnTrans_Translate(C4PropList * _this, long dx, long dy, long dz)
145 {
146  long values[] =
147  {
148  1000, 0, 0, dx,
149  0, 1000, 0, dy,
150  0, 0, 1000, dz
151  };
152  MAKE_AND_RETURN_ARRAY(values);
153 }
154 
155 static C4ValueArray *FnTrans_Scale(C4PropList * _this, long sx, long sy, long sz)
156 {
157  if (sy == 0 && sz == 0)
158  sy = sz = sx;
159  long values[] =
160  {
161  sx, 0, 0, 0,
162  0, sy, 0, 0,
163  0, 0, sz, 0
164  };
165  MAKE_AND_RETURN_ARRAY(values);
166 }
167 
168 static C4ValueArray *FnTrans_Rotate(C4PropList * _this, long angle, long rx, long ry, long rz)
169 {
170  long c = fixtoi(Cos(itofix(angle, 1)), 1000);
171  long s = fixtoi(Sin(itofix(angle, 1)), 1000);
172 
173  long sqrt_val = rx * rx + ry * ry + rz * rz;
174  long n = long(sqrt(double(sqrt_val)));
175  if (n * n < sqrt_val) n++;
176  else if (n * n > sqrt_val) n--;
177 
178  if (n == 0)
179  {
180  throw C4AulExecError("cannot rotate around a null vector");
181  }
182 
183  rx = (1000 * rx) / n;
184  ry = (1000 * ry) / n;
185  rz = (1000 * rz) / n;
186 
187  long values[] =
188  {
189  rx*rx*(1000-c)/1000000+c, rx*ry*(1000-c)/1000000-rz*s/1000, rx*rz*(1000-c)/1000000+ry*s/1000, 0,
190  ry*rx*(1000-c)/1000000+rz*s/1000, ry*ry*(1000-c)/1000000+c, ry*rz*(1000-c)/1000000-rx*s/1000, 0,
191  rz*rx*(1000-c)/1000000-ry*s/1000, ry*rz*(1000-c)/1000000+rx*s/1000, rz*rz*(1000-c)/1000000+c, 0
192  };
193  MAKE_AND_RETURN_ARRAY(values);
194 }
195 
196 static C4Value FnTrans_Mul(C4PropList * _this, C4Value *pars)
197 {
198  const int32_t matrixSize = 12;
199  long values[] =
200  {
201  0, 0, 0, 0,
202  0, 0, 0, 0,
203  0, 0, 0, 0
204  };
205 
206  // Read all parameters
207  bool first = true;
208  for (int32_t i = 0; i < C4AUL_MAX_Par; i++)
209  {
210  C4Value Data = *(pars++);
211  // No data given?
212  if (!Data) break;
213  C4ValueArray *factorArray = Data.getArray();
214  if (!factorArray || factorArray->GetSize() != matrixSize) continue;
215 
216  if (first)
217  {
218  first = false;
219 
220  for (int32_t c = 0; c < matrixSize; ++c)
221  values[c] = (*factorArray)[c].getInt();
222  continue;
223  }
224 
225  // multiply current matrix with new one
226  long values_rhs[matrixSize], values_result[matrixSize];
227  for (int32_t c = 0; c < matrixSize; ++c)
228  values_rhs[c] = (*factorArray)[c].getInt();
229 
230  // matrix multiplication
231  values_result[ 0] = values[0]*values_rhs[0]/1000 + values[1]*values_rhs[4]/1000 + values[ 2]*values_rhs[ 8]/1000;
232  values_result[ 1] = values[0]*values_rhs[1]/1000 + values[1]*values_rhs[5]/1000 + values[ 2]*values_rhs[ 9]/1000;
233  values_result[ 2] = values[0]*values_rhs[2]/1000 + values[1]*values_rhs[6]/1000 + values[ 2]*values_rhs[10]/1000;
234  values_result[ 3] = values[0]*values_rhs[3]/1000 + values[1]*values_rhs[7]/1000 + values[ 2]*values_rhs[11]/1000 + values[3];
235  values_result[ 4] = values[4]*values_rhs[0]/1000 + values[5]*values_rhs[4]/1000 + values[ 6]*values_rhs[ 8]/1000;
236  values_result[ 5] = values[4]*values_rhs[1]/1000 + values[5]*values_rhs[5]/1000 + values[ 6]*values_rhs[ 9]/1000;
237  values_result[ 6] = values[4]*values_rhs[2]/1000 + values[5]*values_rhs[6]/1000 + values[ 6]*values_rhs[10]/1000;
238  values_result[ 7] = values[4]*values_rhs[3]/1000 + values[5]*values_rhs[7]/1000 + values[ 6]*values_rhs[11]/1000 + values[7];
239  values_result[ 8] = values[8]*values_rhs[0]/1000 + values[9]*values_rhs[4]/1000 + values[10]*values_rhs[ 8]/1000;
240  values_result[ 9] = values[8]*values_rhs[1]/1000 + values[9]*values_rhs[5]/1000 + values[10]*values_rhs[ 9]/1000;
241  values_result[10] = values[8]*values_rhs[2]/1000 + values[9]*values_rhs[6]/1000 + values[10]*values_rhs[10]/1000;
242  values_result[11] = values[8]*values_rhs[3]/1000 + values[9]*values_rhs[7]/1000 + values[10]*values_rhs[11]/1000 + values[11];
243 
244  for (int32_t c = 0; c < matrixSize; ++c)
245  values[c] = values_result[c];
246  }
247 
248  // unlike in the other Trans_*-functions, we have to put the array into a C4Value manually here
249  C4ValueArray *matrix = new C4ValueArray(sizeof(values) / sizeof(*values));
250  for (size_t i = 0; i < sizeof(values) / sizeof(*values); ++i)
251  (*matrix)[i] = C4VInt(values[i]);
252  return C4VArray(matrix);
253 }
254 
255 #undef MAKE_AND_RETURN_ARRAY
256 
257 /* PropLists */
258 
259 static C4PropList * FnCreatePropList(C4PropList * _this, C4PropList * prototype)
260 {
261  return C4PropList::New(prototype);
262 }
263 
264 static C4Value FnGetProperty(C4PropList * _this, C4String * key, C4PropList * pObj)
265 {
266  if (!pObj) pObj = _this;
267  if (!pObj) return C4VNull;
268  if (!key) return C4VNull;
269  C4Value r;
270  pObj->GetPropertyByS(key, &r);
271  return r;
272 }
273 
274 static bool FnSetProperty(C4PropList * _this, C4String * key, const C4Value & to, C4PropList * pObj)
275 {
276  if (!pObj) pObj = _this;
277  if (!pObj) return false;
278  if (!key) return false;
279  if (pObj->IsFrozen())
280  throw C4AulExecError("proplist write: proplist is readonly");
281  pObj->SetPropertyByS(key, to);
282  return true;
283 }
284 
285 static bool FnResetProperty(C4PropList * _this, C4String * key, C4PropList * pObj)
286 {
287  if (!pObj) pObj = _this;
288  if (!pObj) return false;
289  if (!key) return false;
290  if (!pObj->HasProperty(key)) return false;
291  if (pObj->IsFrozen())
292  throw C4AulExecError("proplist write: proplist is readonly");
293  pObj->ResetProperty(key);
294  return true;
295 }
296 
297 static C4ValueArray * FnGetProperties(C4PropList * _this, C4PropList * p)
298 {
299  if (!p) p = _this;
300  if (!p) throw NeedNonGlobalContext("GetProperties");
301  C4ValueArray * r = p->GetProperties();
302  r->SortStrings();
303  return r;
304 }
305 
306 static C4PropList * FnGetPrototype(C4PropList * _this, C4PropList * p)
307 {
308  if (!p) p = _this;
309  if (!p) throw NeedNonGlobalContext("GetPrototype");
310  return p->GetPrototype();
311 }
312 
313 static void FnSetPrototype(C4PropList * _this, C4PropList * prototype, C4PropList * p)
314 {
315  if (!p) p = _this;
316  if (!p) throw NeedNonGlobalContext("GetPrototype");
317  p->SetProperty(P_Prototype, C4Value(prototype));
318 }
319 
320 static C4Value FnCall(C4PropList * _this, C4Value * Pars)
321 {
322  if (!_this) _this = ::ScriptEngine.GetPropList();
323  C4AulParSet ParSet;
324  ParSet.Copy(&Pars[1], C4AUL_MAX_Par - 1);
325  C4AulFunc * fn = Pars[0].getFunction();
326  C4String * name;
327  if (!fn)
328  {
329  name = Pars[0].getStr();
330  if (name) fn = _this->GetFunc(name);
331  }
332  if (!fn)
333  {
334  const char * s = FnStringPar(name);
335  if (s[0] == '~')
336  {
337  fn = _this->GetFunc(&s[1]);
338  if (!fn)
339  return C4Value();
340  }
341  }
342  if (!fn)
343  throw C4AulExecError(FormatString("Call: no function %s", Pars[0].GetDataString().getData()).getData());
344  return fn->Exec(_this, &ParSet, true);
345 }
346 
347 static C4String *FnGetName(C4PropList * _this, bool truename)
348 {
349  if (!_this)
350  throw NeedNonGlobalContext("GetName");
351  else if(truename)
352  return _this->IsStatic() ? _this->IsStatic()->GetParentKeyName() : nullptr;
353  else
354  return String(_this->GetName());
355 }
356 
357 /* Effects */
358 
359 static C4Value FnAddEffect(C4PropList * _this, C4String * szEffect, C4PropList * pTarget,
360  int iPrio, int iTimerInterval, C4PropList * pCmdTarget, C4Def * idCmdTarget,
361  const C4Value & Val1, const C4Value & Val2, const C4Value & Val3, const C4Value & Val4)
362 {
363  // safety
364  if (pTarget && !pTarget->Status) return C4Value();
365  if (!szEffect || !*szEffect->GetCStr() || !iPrio) return C4Value();
366  // create effect
367  C4PropList * p = pCmdTarget;
368  if (!p) p = idCmdTarget;
369  if (!p) p = ::ScriptEngine.GetPropList();
370  C4Effect * pEffect = C4Effect::New(pTarget, FnGetEffectsFor(pTarget),
371  szEffect, iPrio, iTimerInterval, p, Val1, Val2, Val3, Val4);
372  // return effect - may be 0 if the effect has been denied by another effect
373  if (!pEffect) return C4Value();
374  return C4VPropList(pEffect);
375 }
376 
377 static C4Effect * FnCreateEffect(C4PropList * _this, C4PropList * prototype, int iPrio, int iTimerInterval,
378  const C4Value & Val1, const C4Value & Val2, const C4Value & Val3, const C4Value & Val4)
379 {
380  if (!prototype || !(prototype->GetName()[0])) throw C4AulExecError("CreateEffect needs a prototype with a name");
381  if (!iPrio) throw C4AulExecError("CreateEffect needs a nonzero priority");
382  // create effect
383  C4Effect * pEffect = C4Effect::New(_this, FnGetEffectsFor(_this), prototype, iPrio, iTimerInterval,
384  Val1, Val2, Val3, Val4);
385  // return effect - may be 0 if the effect has been denied by another effect
386  return pEffect;
387 }
388 
389 static C4Effect * FnGetEffect(C4PropList * _this, C4String *psEffectName, C4PropList *pTarget, int index, int iMaxPriority)
390 {
391  const char *szEffect = FnStringPar(psEffectName);
392  // get effects
393  C4Effect *pEffect = *FnGetEffectsFor(pTarget);
394  if (!pEffect) return nullptr;
395  // name/wildcard given: find effect by name and index
396  if (szEffect && *szEffect)
397  return pEffect->Get(szEffect, index, iMaxPriority);
398  return nullptr;
399 }
400 
401 static bool FnRemoveEffect(C4PropList * _this, C4String *psEffectName, C4PropList *pTarget, C4Effect * pEffect2, bool fDoNoCalls)
402 {
403  // evaluate parameters
404  const char *szEffect = FnStringPar(psEffectName);
405  // if the user passed an effect, it can be used straight-away
406  C4Effect *pEffect = pEffect2;
407  // otherwise, the correct effect will be searched in the target's effects or in the global ones
408  if (!pEffect)
409  {
410  pEffect = *FnGetEffectsFor(pTarget);
411  // the object has no effects attached, nothing to look for
412  if (!pEffect) return false;
413  // name/wildcard given: find effect by name
414  if (szEffect && *szEffect)
415  pEffect = pEffect->Get(szEffect, 0);
416  }
417 
418  // neither passed nor found - nothing to remove!
419  if (!pEffect) return false;
420 
421  // kill it
422  if (fDoNoCalls)
423  pEffect->SetDead();
424  else
425  pEffect->Kill();
426  // done, success
427  return true;
428 }
429 
430 static C4Value FnCheckEffect(C4PropList * _this, C4String * psEffectName, C4PropList * pTarget,
431  int iPrio, int iTimerInterval,
432  const C4Value & Val1, const C4Value & Val2, const C4Value & Val3, const C4Value & Val4)
433 {
434  const char *szEffect = FnStringPar(psEffectName);
435  // safety
436  if (pTarget && !pTarget->Status) return C4Value();
437  if (!szEffect || !*szEffect) return C4Value();
438  // get effects
439  C4Effect *pEffect = *FnGetEffectsFor(pTarget);
440  if (!pEffect) return C4Value();
441  // let them check
442  C4Effect * r = pEffect->Check(szEffect, iPrio, iTimerInterval, Val1, Val2, Val3, Val4);
443  if (r == (C4Effect *)C4Fx_Effect_Deny) return C4VInt(C4Fx_Effect_Deny);
444  if (r == (C4Effect *)C4Fx_Effect_Annul) return C4VInt(C4Fx_Effect_Annul);
445  return C4VPropList(r);
446 }
447 
448 static long FnGetEffectCount(C4PropList * _this, C4String *psEffectName, C4PropList *pTarget, long iMaxPriority)
449 {
450  // evaluate parameters
451  const char *szEffect = FnStringPar(psEffectName);
452  // get effects
453  C4Effect *pEffect = *FnGetEffectsFor(pTarget);
454  if (!pEffect) return false;
455  // count effects
456  if (!*szEffect) szEffect = nullptr;
457  return pEffect->GetCount(szEffect, iMaxPriority);
458 }
459 
460 static C4Value FnEffectCall(C4PropList * _this, C4Value * Pars)
461 {
462  // evaluate parameters
463  C4PropList *pTarget = Pars[0].getPropList();
464  C4Effect * pEffect = Pars[1].getPropList() ? Pars[1].getPropList()->GetEffect() : nullptr;
465  const char *szCallFn = FnStringPar(Pars[2].getStr());
466  // safety
467  if (pTarget && !pTarget->Status) return C4Value();
468  if (!szCallFn || !*szCallFn) return C4Value();
469  if (!pEffect) return C4Value();
470  // do call
471  return pEffect->DoCall(pTarget, szCallFn, Pars[3], Pars[4], Pars[5], Pars[6], Pars[7], Pars[8], Pars[9]);
472 }
473 
474 /* Regex */
475 
476 static const long
477  Regex_CaseInsensitive = (1 << 0),
478  Regex_FirstOnly = (1 << 1);
479 
480 static std::regex_constants::syntax_option_type C4IntToSyntaxOption(long flags)
481 {
482  std::regex_constants::syntax_option_type out = std::regex::ECMAScript;
483  if (flags & Regex_CaseInsensitive)
484  out |= std::regex::icase;
485  return out;
486 }
487 
488 static std::regex_constants::match_flag_type C4IntToMatchFlag(long flags)
489 {
490  std::regex_constants::match_flag_type out = std::regex_constants::match_default;
491  if (flags & Regex_FirstOnly)
492  out |= std::regex_constants::format_first_only;
493  return out;
494 }
495 
496 static Nillable<C4String *> FnRegexReplace(C4PropList * _this, C4String *source, C4String *regex, C4String *replacement, long flags)
497 {
498  if (!source || !regex || !replacement) return C4Void();
499  try
500  {
501  std::regex re(regex->GetCStr(), C4IntToSyntaxOption(flags));
502  std::string out = std::regex_replace(source->GetCStr(), re, replacement->GetCStr(), C4IntToMatchFlag(flags));
503  return ::Strings.RegString(out.c_str());
504  }
505  catch (const std::regex_error& e)
506  {
507  throw C4AulExecError(FormatString("RegexReplace: %s", e.what()).getData());
508  }
509 }
510 
511 
512 static Nillable<C4ValueArray *> FnRegexSearch(C4PropList * _this, C4String *source, C4String *regex, long flags)
513 {
514  if (!source || !regex) return C4Void();
515  try
516  {
517  std::regex re(regex->GetCStr(), C4IntToSyntaxOption(flags));
518  C4ValueArray *out = new C4ValueArray();
519  const auto &data = source->GetData();
520  size_t pos = 0;
521  std::cmatch m;
522  long i = 0;
523  // std::regex_iterator would be the better way to do this, but is is broken in libc++ (see LLVM bug #21597).
524  while (pos <= data.getLength() && std::regex_search(data.getData() + pos, data.getData() + data.getLength(), m, re))
525  {
526  int char_pos = GetCharacterCount(std::string(data.getData(), pos + m.position()).c_str());
527  (*out)[i++] = C4VInt(char_pos);
528  if (flags & Regex_FirstOnly) break;
529  pos += m.position() + std::max<size_t>(m.length(), 1);
530  }
531  return out;
532  }
533  catch (const std::regex_error& e)
534  {
535  throw C4AulExecError(FormatString("RegexSearch: %s", e.what()).getData());
536  }
537 }
538 
539 static Nillable<C4ValueArray *> FnRegexMatch(C4PropList * _this, C4String *source, C4String *regex, long flags)
540 {
541  if (!source || !regex) return C4Void();
542  try
543  {
544  std::regex re(regex->GetCStr(), C4IntToSyntaxOption(flags));
545  C4ValueArray *out = new C4ValueArray();
546  const auto &data = source->GetData();
547  size_t pos = 0;
548  std::cmatch m;
549  long i = 0;
550  while (pos <= data.getLength() && std::regex_search(data.getData() + pos, data.getData() + data.getLength(), m, re))
551  {
552  C4ValueArray *match = new C4ValueArray(m.size());
553  long j = 0;
554  for (auto sm : m)
555  {
556  (*match)[j++] = C4VString(String(sm.str().c_str()));
557  }
558  (*out)[i++] = C4VArray(match);
559  if (flags & Regex_FirstOnly) break;
560  pos += m.position() + std::max<size_t>(m.length(), 1);
561  }
562  return out;
563  }
564  catch (const std::regex_error& e)
565  {
566  throw C4AulExecError(FormatString("RegexMatch: %s", e.what()).getData());
567  }
568 }
569 
570 static Nillable<C4ValueArray *> FnRegexSplit(C4PropList * _this, C4String *source, C4String *regex, long flags)
571 {
572  if (!source || !regex) return C4Void();
573  try
574  {
575  std::regex re(regex->GetCStr(), C4IntToSyntaxOption(flags));
576  C4ValueArray *out = new C4ValueArray();
577  const auto &data = source->GetData();
578  size_t pos = 0;
579  std::cmatch m;
580  long i = 0;
581  while (pos <= data.getLength() && std::regex_search(data.getData() + pos, data.getData() + data.getLength(), m, re))
582  {
583  // As we're advancing by one character for zero-length matches, always
584  // include at least one character here.
585  std::string substr(data.getData() + pos, std::max<size_t>(m.position(), 1));
586  (*out)[i++] = C4VString(String(substr.c_str()));
587  if (flags & Regex_FirstOnly) break;
588  pos += m.position() + std::max<size_t>(m.length(), 1);
589  }
590  if (pos <= data.getLength())
591  {
592  std::string substr(data.getData() + pos, data.getLength() - pos);
593  (*out)[i++] = C4VString(String(substr.c_str()));
594  }
595  return out;
596  }
597  catch (const std::regex_error& e)
598  {
599  throw C4AulExecError(FormatString("RegexSplit: %s", e.what()).getData());
600  }
601 }
602 
603 
604 static C4Value FnLog(C4PropList * _this, C4Value * Pars)
605 {
606  Log(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9).getData());
607  return C4VBool(true);
608 }
609 
610 static C4Value FnDebugLog(C4PropList * _this, C4Value * Pars)
611 {
612  DebugLog(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9).getData());
613  return C4VBool(true);
614 }
615 
616 static C4Value FnFormat(C4PropList * _this, C4Value * Pars)
617 {
618  return C4VString(FnStringFormat(_this, Pars[0].getStr(), &Pars[1], 9));
619 }
620 
621 // Parse a string into an integer. Returns nil if the conversion fails.
622 static Nillable<int32_t> FnParseInt(C4PropList *_this, C4String *str)
623 {
624  const char *cstr = str->GetCStr();
625  const char *end = nullptr;
626  int32_t result = StrToI32(cstr, 10, &end);
627  if (end == cstr || *end != '\0') return C4Void();
628  return result;
629 }
630 
631 static long FnAbs(C4PropList * _this, long iVal)
632 {
633  return Abs(iVal);
634 }
635 
636 static long FnSin(C4PropList * _this, long iAngle, long iRadius, long iPrec)
637 {
638  if (!iPrec) iPrec = 1;
639  // Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow
640  iAngle %= 360 * iPrec;
641  // Let itofix and fixtoi handle the division and multiplication because that can handle higher ranges
642  return fixtoi(Sin(itofix(iAngle, iPrec)), iRadius);
643 }
644 
645 static long FnCos(C4PropList * _this, long iAngle, long iRadius, long iPrec)
646 {
647  if (!iPrec) iPrec = 1;
648  iAngle %= 360 * iPrec;
649  return fixtoi(Cos(itofix(iAngle, iPrec)), iRadius);
650 }
651 
652 static long FnSqrt(C4PropList * _this, long iValue)
653 {
654  if (iValue<0) return 0;
655  long iSqrt = long(sqrt(double(iValue)));
656  if (iSqrt * iSqrt < iValue) iSqrt++;
657  if (iSqrt * iSqrt > iValue) iSqrt--;
658  return iSqrt;
659 }
660 
661 static long FnAngle(C4PropList * _this, long iX1, long iY1, long iX2, long iY2, long iPrec)
662 {
663  long iAngle;
664 
665  // Standard prec
666  if (!iPrec) iPrec = 1;
667 
668  long dx=iX2-iX1,dy=iY2-iY1;
669  if (!dx)
670  {
671  if (dy>0) return 180 * iPrec;
672  else return 0;
673  }
674  if (!dy)
675  {
676  if (dx>0) return 90 * iPrec;
677  else return 270 * iPrec;
678  }
679 
680  iAngle = static_cast<long>(180.0 * iPrec * atan2(static_cast<double>(Abs(dy)), static_cast<double>(Abs(dx))) / M_PI);
681 
682  if (iX2>iX1 )
683  {
684  if (iY2<iY1) iAngle = (90 * iPrec) - iAngle;
685  else iAngle = (90 * iPrec) + iAngle;
686  }
687  else
688  {
689  if (iY2<iY1) iAngle = (270 * iPrec) + iAngle;
690  else iAngle = (270 * iPrec) - iAngle;
691  }
692 
693  return iAngle;
694 }
695 
696 static long FnArcSin(C4PropList * _this, long iVal, long iRadius)
697 {
698  // safety
699  if (!iRadius) return 0;
700  if (iVal > iRadius) return 0;
701  // calc arcsin
702  double f1 = iVal;
703  f1 = asin(f1/iRadius)*180.0/M_PI;
704  // return rounded angle
705  return (long) floor(f1+0.5);
706 }
707 
708 static long FnArcCos(C4PropList * _this, long iVal, long iRadius)
709 {
710  // safety
711  if (!iRadius) return 0;
712  if (iVal > iRadius) return 0;
713  // calc arccos
714  double f1 = iVal;
715  f1 = acos(f1/iRadius)*180.0/M_PI;
716  // return rounded angle
717  return (long) floor(f1+0.5);
718 }
719 
720 static std::pair<Nillable<int32_t>, Nillable<int32_t>> minmax(const char *func, const C4Value &a_val, const Nillable<int32_t> &b_opt)
721 {
722  if (a_val.CheckConversion(C4V_Int))
723  {
724  int32_t a = a_val.getInt();
725  int32_t b = b_opt;
726  if (a > b)
727  std::swap(a, b);
728  return std::make_pair(a, b);
729  }
730  else if (a_val.CheckConversion(C4V_Array))
731  {
732  const C4ValueArray *a = a_val.getArray();
733  if (a->GetSize() == 0)
734  return std::make_pair(nullptr, nullptr);
735 
736  if (!a->GetItem(0).CheckConversion(C4V_Int))
737  {
738  throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but element %d of array is of type %s", func, 0, a->GetItem(0).GetTypeName()).getData());
739  }
740  int32_t min, max;
741  min = max = a->GetItem(0).getInt();
742 
743  for (int32_t i = 1; i < a->GetSize(); ++i)
744  {
745  if (!a->GetItem(i).CheckConversion(C4V_Int))
746  {
747  throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but element %d of array is of type %s", func, i, a->GetItem(i).GetTypeName()).getData());
748  }
749  int32_t value = a->GetItem(i).getInt();
750  min = std::min(min, value);
751  max = std::max(max, value);
752  }
753 
754  return std::make_pair(min, max);
755  }
756  else
757  {
758  throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but is of type %s", func, a_val.GetTypeName()).getData());
759  }
760 }
761 
762 static Nillable<int32_t> FnMin(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
763 {
764  return minmax("Min", a, b).first;
765 }
766 
767 static Nillable<int32_t> FnMax(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
768 {
769  return minmax("Max", a, b).second;
770 }
771 
772 static long FnDistance(C4PropList * _this, long iX1, long iY1, long iX2, long iY2)
773 {
774  return Distance(iX1,iY1,iX2,iY2);
775 }
776 
777 static long FnBoundBy(C4PropList * _this, long iVal, long iRange1, long iRange2)
778 {
779  return Clamp(iVal,iRange1,iRange2);
780 }
781 
782 static bool FnInside(C4PropList * _this, long iVal, long iRange1, long iRange2)
783 {
784  return Inside(iVal,iRange1,iRange2);
785 }
786 
787 static long FnRandom(C4PropList * _this, long iRange)
788 {
789  return Random(iRange);
790 }
791 
792 static int FnGetType(C4PropList * _this, const C4Value & Value)
793 {
794  // dynamic types
795  if (Value.CheckConversion(C4V_Object)) return C4V_Object;
796  if (Value.CheckConversion(C4V_Def)) return C4V_Def;
797  if (Value.CheckConversion(C4V_Effect)) return C4V_Effect;
798  // static types
799  return Value.GetType();
800 }
801 
802 static C4ValueArray * FnCreateArray(C4PropList * _this, int iSize)
803 {
804  return new C4ValueArray(iSize);
805 }
806 
807 static int FnGetLength(C4PropList * _this, const C4Value & Par)
808 {
809  // support GetLength() etc.
810  C4ValueArray * pArray = Par.getArray();
811  if (pArray)
812  return pArray->GetSize();
813  C4String * pStr = Par.getStr();
814  if (pStr)
815  return GetCharacterCount(pStr->GetData().getData());
816  throw C4AulExecError("GetLength: parameter 0 cannot be converted to string or array");
817 }
818 
819 static int FnGetIndexOf(C4PropList * _this, C4ValueArray * pArray, const C4Value & Needle)
820 {
821  // find first occurance of first parameter in array
822  // support GetIndexOf(0, x)
823  if (!pArray) return -1;
824  int32_t iSize = pArray->GetSize();
825  for (int32_t i = 0; i < iSize; ++i)
826  if (Needle.IsIdenticalTo(pArray->GetItem(i)))
827  // element found
828  return i;
829  // element not found
830  return -1;
831 }
832 
833 static bool FnDeepEqual(C4PropList * _this, const C4Value & v1, const C4Value & v2)
834 {
835  // return if v1==v2 with deep comparison on arrays and proplists
836  return v1 == v2;
837 }
838 
839 static void FnSetLength(C4PropList * _this, C4ValueArray *pArray, int iNewSize)
840 {
841  // safety
842  if (iNewSize<0 || iNewSize > C4ValueArray::MaxSize)
843  throw C4AulExecError(FormatString("SetLength: invalid array size (%d)", iNewSize).getData());
844 
845  // set new size
846  pArray->SetSize(iNewSize);
847 }
848 
849 static Nillable<long> FnGetChar(C4PropList * _this, C4String *pString, long iIndex)
850 {
851  const char *szText = FnStringPar(pString);
852  if (!szText) return C4Void();
853  // C4Strings are UTF-8 encoded, so decode to get the indicated character
854  uint32_t c = GetNextCharacter(&szText);
855  for (int i = 0; i < iIndex; ++i)
856  {
857  c = GetNextCharacter(&szText);
858  if (!c) return C4Void();
859  }
860  return c;
861 }
862 
863 static C4String *FnStringToIdentifier(C4PropList * _this, C4String *pString)
864 {
865  // Change an arbitrary string so that it becomes an identifier
866  const char *text = FnStringPar(pString);
867  if (!text) return nullptr;
868  StdStrBuf result;
869  bool had_valid = false, had_invalid = false;
870  const char *ptext = text, *t0 = text;
871  uint32_t c = GetNextCharacter(&text);
872  while (c)
873  {
874  if (isalnum(c) || c == '_')
875  {
876  // Starting with a digit? Needs to prepend a character
877  if (isdigit(c) && !had_valid)
878  {
879  result.Append("_");
880  had_invalid = true;
881  }
882  // Valid character: Append to result string if a modification had to be done
883  if (had_invalid) result.Append(ptext, text - ptext);
884  had_valid = true;
885  }
886  else
887  {
888  // Invalid character. Make sure result is created from previous valid characters
889  if (!had_invalid)
890  {
891  result.Copy(t0, ptext - t0);
892  had_invalid = true;
893  }
894  }
895  ptext = text;
896  c = GetNextCharacter(&text);
897  }
898  // Make sure no empty string is returned
899  if (!had_valid) return ::Strings.RegString("_");
900  // Return either modified string or the original if no modifications were needed
901  return had_invalid ? ::Strings.RegString(result) : pString;
902 }
903 
904 static C4Value Fneval(C4PropList * _this, C4String *strScript, bool dont_pass_errors)
905 {
906  return ::AulExec.DirectExec(_this, FnStringPar(strScript), "eval", !dont_pass_errors);
907 }
908 
909 static bool FnLocateFunc(C4PropList * _this, C4String *funcname, C4PropList * p)
910 {
911  // safety
912  if (!funcname || !funcname->GetCStr())
913  {
914  Log("No func name");
915  return false;
916  }
917  if (!p) p = _this;
918  // get function by name
919  C4AulFunc *pFunc = p->GetFunc(funcname);
920  if (!pFunc)
921  {
922  LogF("Func %s not found", funcname->GetCStr());
923  }
924  else
925  {
926  const char *szPrefix = "";
927  while (pFunc)
928  {
929  C4AulScriptFunc *pSFunc = pFunc->SFunc();
930  if (!pSFunc)
931  {
932  LogF("%s%s (engine)", szPrefix, pFunc->GetName());
933  }
934  else if (!pSFunc->pOrgScript)
935  {
936  LogF("%s%s (no owner)", szPrefix, pSFunc->GetName());
937  }
938  else
939  {
940  int32_t iLine = SGetLine(pSFunc->pOrgScript->GetScript(), pSFunc->Script);
941  LogF("%s%s (%s:%d)", szPrefix, pFunc->GetName(), pSFunc->pOrgScript->ScriptName.getData(), (int)iLine);
942  }
943  // next func in overload chain
944  pFunc = pSFunc ? pSFunc->OwnerOverloaded : nullptr;
945  szPrefix = "overloads ";
946  }
947  }
948  return true;
949 }
950 
951 static long FnModulateColor(C4PropList * _this, long iClr1, long iClr2)
952 {
953  DWORD dwClr1 = iClr1;
954  DWORD dwClr2 = iClr2;
955  // default color
956  if (!dwClr1) dwClr1 = 0xffffff;
957  // get alpha
958  long iA1=dwClr1>>24, iA2=dwClr2>>24;
959  // modulate color values; mod alpha upwards
960  DWORD r = (((dwClr1 & 0xff) * (dwClr2 & 0xff)) >> 8) | // blue
961  (((dwClr1>> 8 & 0xff) * (dwClr2>>8 & 0xff)) & 0xff00) | // green
962  (((dwClr1>>16 & 0xff) * (dwClr2>>8 & 0xff00)) & 0xff0000) | // red
963  (std::min<long>(iA1+iA2 - ((iA1*iA2)>>8), 255) << 24); // alpha
964  return r;
965 }
966 
967 static long FnWildcardMatch(C4PropList * _this, C4String *psString, C4String *psWildcard)
968 {
969  return SWildcardMatchEx(FnStringPar(psString), FnStringPar(psWildcard));
970 }
971 
972 static bool FnFatalError(C4PropList * _this, C4String *pErrorMsg)
973 {
974  throw C4AulExecError(FormatString("script: %s", pErrorMsg ? pErrorMsg->GetCStr() : "(no error)").getData());
975 }
976 
977 static bool FnStartCallTrace(C4PropList * _this)
978 {
980  return true;
981 }
982 
983 static bool FnStartScriptProfiler(C4PropList * _this, C4Def * pDef)
984 {
985  // get script to profile
986  C4ScriptHost *pScript;
987  if (pDef)
988  pScript = &pDef->Script;
989  else
990  pScript = nullptr;
991  // profile it
993  return true;
994 }
995 
996 static bool FnStopScriptProfiler(C4PropList * _this)
997 {
999  return true;
1000 }
1001 
1002 static Nillable<C4String *> FnGetConstantNameByValue(C4PropList * _this, int value, Nillable<C4String *> name_prefix, int idx)
1003 {
1004  C4String *name_prefix_s = name_prefix;
1005  // find a constant that has the specified value and prefix
1006  for (int32_t i = 0; i < ::ScriptEngine.GlobalConsts.GetAnzItems(); ++i)
1007  {
1008  if (::ScriptEngine.GlobalConsts[i].getInt() == value)
1009  {
1010  const char *const_name = ::ScriptEngine.GlobalConstNames.GetItemUnsafe(i);
1011  if (!name_prefix_s || SEqual2(const_name, name_prefix_s->GetCStr()))
1012  if (!idx--)
1013  // indexed constant found. return name minus prefix
1014  return String(const_name + (name_prefix_s ? name_prefix_s->GetData().getLength() : 0));
1015  }
1016  }
1017  // nothing found (at index)
1018  return C4Void();
1019 }
1020 
1021 static Nillable<C4String *> FnReplaceString(C4PropList * _this, C4String *source, C4String *from, C4String *to)
1022 {
1023  if (!from) return source;
1024  if (!source) return C4Void();
1025  const char *szto = to ? to->GetCStr() : "";
1026  const char *szfrom = from->GetCStr();
1027  StdStrBuf s(source->GetData(), true);
1028  if (s.Replace(szfrom, szto))
1029  {
1030  return ::Strings.RegString(s.getData());
1031  }
1032  else
1033  {
1034  return source;
1035  }
1036 }
1037 
1038 static bool FnSortArray(C4PropList * _this, C4ValueArray *pArray, bool descending)
1039 {
1040  if (!pArray) throw C4AulExecError("SortArray: no array given");
1041  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1042  // sort array by its members
1043  pArray->Sort(descending);
1044  return true;
1045 }
1046 
1047 static bool FnSortArrayByProperty(C4PropList * _this, C4ValueArray *pArray, C4String *prop_name, bool descending)
1048 {
1049  if (!pArray) throw C4AulExecError("SortArrayByProperty: no array given");
1050  if (!prop_name) throw C4AulExecError("SortArrayByProperty: no property name given");
1051  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1052  // sort array by property
1053  if (!pArray->SortByProperty(prop_name, descending)) throw C4AulExecError("SortArrayByProperty: not all array elements are proplists");
1054  return true;
1055 }
1056 
1057 static bool FnSortArrayByArrayElement(C4PropList * _this, C4ValueArray *pArray, int32_t element_index, bool descending)
1058 {
1059  if (!pArray) throw C4AulExecError("SortArrayByArrayElement: no array given");
1060  if (element_index<0) throw C4AulExecError("SortArrayByArrayElement: element index must be >=0");
1061  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1062  // sort array by array element
1063  if (!pArray->SortByArrayElement(element_index, descending)) throw C4AulExecError("SortArrayByArrayElement: not all array elements are arrays of sufficient length");
1064  return true;
1065 }
1066 
1067 static bool FnFileWrite(C4PropList * _this, int32_t file_handle, C4String *data)
1068 {
1069  // resolve file handle to user file
1070  C4AulUserFile *file = ::ScriptEngine.GetUserFile(file_handle);
1071  if (!file) throw C4AulExecError("FileWrite: invalid file handle");
1072  // prepare string to write
1073  if (!data) return false; // write nullptr? No.
1074  // write it
1075  file->Write(data->GetCStr(), data->GetData().getLength());
1076  return true;
1077 }
1078 
1079 //=========================== C4Script Function Map ===================================
1080 
1082 {
1083  { "FX_OK" ,C4V_Int, C4Fx_OK }, // generic standard behaviour for all effect callbacks
1084  { "FX_Effect_Deny" ,C4V_Int, C4Fx_Effect_Deny }, // delete effect
1085  { "FX_Effect_Annul" ,C4V_Int, C4Fx_Effect_Annul }, // delete effect, because it has annulled a countereffect
1086  { "FX_Effect_AnnulDoCalls" ,C4V_Int, C4Fx_Effect_AnnulCalls }, // delete effect, because it has annulled a countereffect; temp readd countereffect
1087  { "FX_Execute_Kill" ,C4V_Int, C4Fx_Execute_Kill }, // execute callback: Remove effect now
1088  { "FX_Stop_Deny" ,C4V_Int, C4Fx_Stop_Deny }, // deny effect removal
1089  { "FX_Start_Deny" ,C4V_Int, C4Fx_Start_Deny }, // deny effect start
1090 
1091  { "FX_Call_Normal" ,C4V_Int, C4FxCall_Normal }, // normal call; effect is being added or removed
1092  { "FX_Call_Temp" ,C4V_Int, C4FxCall_Temp }, // temp call; effect is being added or removed in responce to a lower-level effect change
1093  { "FX_Call_TempAddForRemoval" ,C4V_Int, C4FxCall_TempAddForRemoval }, // temp call; effect is being added because it had been temp removed and is now removed forever
1094  { "FX_Call_RemoveClear" ,C4V_Int, C4FxCall_RemoveClear }, // effect is being removed because object is being removed
1095  { "FX_Call_RemoveDeath" ,C4V_Int, C4FxCall_RemoveDeath }, // effect is being removed because object died - return -1 to avoid removal
1096  { "FX_Call_DmgScript" ,C4V_Int, C4FxCall_DmgScript }, // damage through script call
1097  { "FX_Call_DmgBlast" ,C4V_Int, C4FxCall_DmgBlast }, // damage through blast
1098  { "FX_Call_DmgFire" ,C4V_Int, C4FxCall_DmgFire }, // damage through fire
1099  { "FX_Call_DmgChop" ,C4V_Int, C4FxCall_DmgChop }, // damage through chopping
1100  { "FX_Call_Energy" ,C4V_Int, 32 }, // bitmask for generic energy loss
1101  { "FX_Call_EngScript" ,C4V_Int, C4FxCall_EngScript }, // energy loss through script call
1102  { "FX_Call_EngBlast" ,C4V_Int, C4FxCall_EngBlast }, // energy loss through blast
1103  { "FX_Call_EngObjHit" ,C4V_Int, C4FxCall_EngObjHit }, // energy loss through object hitting the living
1104  { "FX_Call_EngFire" ,C4V_Int, C4FxCall_EngFire }, // energy loss through fire
1105  { "FX_Call_EngBaseRefresh" ,C4V_Int, C4FxCall_EngBaseRefresh }, // energy reload in base (also by base object, but that's normally not called)
1106  { "FX_Call_EngAsphyxiation" ,C4V_Int, C4FxCall_EngAsphyxiation }, // energy loss through asphyxiaction
1107  { "FX_Call_EngCorrosion" ,C4V_Int, C4FxCall_EngCorrosion }, // energy loss through corrosion (acid)
1108  { "FX_Call_EngGetPunched" ,C4V_Int, C4FxCall_EngGetPunched }, // energy loss from punch
1109 
1110  { "Regex_CaseInsensitive" ,C4V_Int, Regex_CaseInsensitive },
1111  { "Regex_FirstOnly" ,C4V_Int, Regex_FirstOnly },
1112 
1113  { "C4V_Nil", C4V_Int, C4V_Nil},
1114  { "C4V_Int", C4V_Int, C4V_Int},
1115  { "C4V_Bool", C4V_Int, C4V_Bool},
1116  { "C4V_C4Object", C4V_Int, C4V_Object},
1117  { "C4V_Effect", C4V_Int, C4V_Effect},
1118  { "C4V_Def", C4V_Int, C4V_Def},
1119  { "C4V_String", C4V_Int, C4V_String},
1120  { "C4V_Array", C4V_Int, C4V_Array},
1121  { "C4V_Function", C4V_Int, C4V_Function},
1122  { "C4V_PropList", C4V_Int, C4V_PropList},
1123 
1124  { "C4X_Ver1", C4V_Int, C4XVER1},
1125  { "C4X_Ver2", C4V_Int, C4XVER2},
1126 
1127  { nullptr, C4V_Nil, 0}
1128 };
1129 
1131 {
1132  { "Call", true, C4V_Any, { C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnCall },
1133  { "EffectCall", true, C4V_Any, { C4V_Object ,C4V_PropList,C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnEffectCall },
1134  { "Log", true, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnLog },
1135  { "DebugLog", true, C4V_Bool, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnDebugLog },
1136  { "Format", true, C4V_String, { C4V_String ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnFormat },
1137  { "Trans_Mul", true, C4V_Array, { C4V_Array ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any ,C4V_Any}, FnTrans_Mul},
1138 
1139  { nullptr, false, C4V_Nil, { C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil ,C4V_Nil}, nullptr }
1140 };
1141 
1143 {
1144  // add all def constants (all Int)
1145  for (C4ScriptConstDef *pCDef = &C4ScriptConstMap[0]; pCDef->Identifier; pCDef++)
1146  {
1147  assert(pCDef->ValType == C4V_Int); // only int supported currently
1148  pEngine->RegisterGlobalConstant(pCDef->Identifier, C4VInt(pCDef->Data));
1149  }
1150 
1151  C4PropListStatic * p = pEngine->GetPropList();
1152  // add all def script funcs
1153  for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
1154  new C4AulDefFunc(p, pDef);
1155 #define F(f) ::AddFunc(p, #f, Fn##f)
1156  F(ParseInt);
1157  F(Abs);
1158  F(Min);
1159  F(Max);
1160  F(Sin);
1161  F(Cos);
1162  F(Sqrt);
1163  F(ArcSin);
1164  F(ArcCos);
1165  F(BoundBy);
1166  F(Inside);
1167  F(Random);
1168 
1169  F(CreateArray);
1170  F(CreatePropList);
1171  F(GetProperties);
1172  F(GetProperty);
1173  F(SetProperty);
1174  F(GetPrototype);
1175  F(SetPrototype);
1176  F(ResetProperty);
1177  F(GetName);
1178  F(AddEffect);
1179  F(CreateEffect);
1180  F(CheckEffect);
1181  F(RemoveEffect);
1182  F(GetEffect);
1183  F(GetEffectCount);
1184  F(RegexReplace);
1185  F(RegexSearch);
1186  F(RegexMatch);
1187  F(RegexSplit);
1188  F(Distance);
1189  F(Angle);
1190  F(GetChar);
1191  F(GetType);
1192  F(ModulateColor);
1193  F(WildcardMatch);
1194  F(GetLength);
1195  F(SetLength);
1196  F(GetIndexOf);
1197  F(DeepEqual);
1198  F(FatalError);
1199  F(StartCallTrace);
1200  F(StartScriptProfiler);
1201  F(StopScriptProfiler);
1202  F(SortArray);
1203  F(SortArrayByProperty);
1204  F(SortArrayByArrayElement);
1205  F(Trans_Identity);
1206  F(Trans_Translate);
1207  F(Trans_Scale);
1208  F(Trans_Rotate);
1209  F(LocateFunc);
1210  F(FileWrite);
1211  F(eval);
1212  F(StringToIdentifier);
1213  F(GetConstantNameByValue);
1214  F(ReplaceString);
1215 
1216  ::AddFunc(p, "Translate", C4AulExec::FnTranslate);
1217  ::AddFunc(p, "LogCallStack", C4AulExec::FnLogCallStack);
1218 #undef F
1219 }
virtual void ResetProperty(C4String *k)
Definition: C4PropList.cpp:969
const char * getData() const
Definition: StdBuf.h:442
StdStrBuf GetData() const
Definition: C4StringTable.h:50
void RegisterGlobalConstant(const char *szName, const C4Value &rValue)
static bool FnLogCallStack(C4PropList *_this)
Definition: C4AulExec.cpp:130
C4ScriptFnDef C4ScriptFnMap[]
Definition: C4Script.cpp:1130
void Write(const char *data, size_t data_length)
Definition: C4Aul.h:96
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:130
#define C4FxCall_RemoveDeath
Definition: C4Effect.h:46
uint32_t Random()
Definition: C4Random.cpp:43
const char * GetItemUnsafe(int32_t idx) const
Definition: C4ValueMap.h:124
C4PropListStatic * GetPropList()
Definition: C4Aul.h:151
C4String * getStr() const
Definition: C4Value.h:117
#define C4FxCall_EngFire
Definition: C4Effect.h:58
uint32_t GetNextCharacter(const char **pszString)
Definition: Standard.h:84
C4String * String(const char *str)
Definition: C4AulDefFunc.h:30
C4AulScriptEngine ScriptEngine
Definition: C4Globals.cpp:43
#define b
C4Value(* FunctionC4V)(C4PropList *_this, C4Value *)
Definition: C4AulDefFunc.h:280
int SGetLine(const char *szText, const char *cpPosition)
Definition: Standard.cpp:451
C4AulDefFunc(C4PropListStatic *Parent, C4ScriptFnDef *pDef)
Definition: C4Script.cpp:110
bool SortByArrayElement(int32_t array_idx, bool descending=false)
const char * GetName() const
Definition: C4AulFunc.h:57
C4AulFunc * GetFunc(C4PropertyName k) const
Definition: C4PropList.h:105
void SortStrings()
bool DebugLog(const char *strMessage)
Definition: C4Log.cpp:270
const char * GetCStr() const
Definition: C4StringTable.h:49
C4String * RegString(StdStrBuf String)
C4Value C4VInt(int32_t i)
Definition: C4Value.h:242
#define C4FxCall_RemoveClear
Definition: C4Effect.h:45
void SetProperty(C4PropertyName k, const C4Value &to)
Definition: C4PropList.h:120
#define C4FxCall_EngScript
Definition: C4Effect.h:55
#define C4FxCall_TempAddForRemoval
Definition: C4Effect.h:44
static void StopProfiling()
Definition: C4AulExec.cpp:972
int GetCharacterCount(const char *s)
Definition: Standard.cpp:763
C4ScriptHost * pOrgScript
virtual class C4PropListStatic * IsStatic()
Definition: C4PropList.h:85
int32_t StrToI32(const char *str, int base, const char **scan_end)
Definition: Standard.cpp:98
C4AulExec AulExec
Definition: C4AulExec.cpp:29
StdStrBuf FnStringFormat(C4PropList *_this, C4String *szFormatPar, C4Value *Pars, int ParCount)
Definition: C4Script.cpp:29
#define C4FxCall_DmgFire
Definition: C4Effect.h:51
#define a
int32_t GetCount(const char *szMask, int32_t iMaxPriority=0)
Definition: C4Effect.cpp:236
size_t SLen(const char *sptr)
Definition: Standard.h:74
C4AulUserFile * GetUserFile(int32_t handle)
void InitCoreFunctionMap(C4AulScriptEngine *pEngine)
Definition: C4Script.cpp:1142
C4AulFunc * OwnerOverloaded
C4String * GetParentKeyName()
Definition: C4PropList.h:271
C4ValueMapNames GlobalConstNames
Definition: C4Aul.h:141
#define C4Fx_Effect_Deny
Definition: C4Effect.h:32
T Clamp(T bval, T lbound, T rbound)
Definition: Standard.h:44
C4Value Exec(C4PropList *p, C4Value pPars[], bool fPassErrors=false) override
Definition: C4Script.cpp:118
#define C4FxCall_Normal
Definition: C4Effect.h:42
const C4Value & GetItem(int32_t iElem) const
Definition: C4ValueArray.h:38
void AppendFormat(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:190
ALWAYS_INLINE bool CheckConversion(C4V_Type vtToType) const
Definition: C4Value.h:189
void AppendChar(char cChar)
Definition: StdBuf.h:588
int32_t Distance(int32_t iX1, int32_t iY1, int32_t iX2, int32_t iY2)
Definition: Standard.cpp:25
#define C4Fx_Effect_AnnulCalls
Definition: C4Effect.h:34
#define MAKE_AND_RETURN_ARRAY(values)
Definition: C4Script.cpp:126
#define C4AUL_MAX_Par
Definition: C4AulFunc.h:26
#define C4FxCall_EngCorrosion
Definition: C4Effect.h:61
bool SortByProperty(C4String *prop_name, bool descending=false)
#define C4FxCall_DmgBlast
Definition: C4Effect.h:50
void Kill()
Definition: C4Effect.cpp:343
C4ScriptConstDef C4ScriptConstMap[]
Definition: C4Script.cpp:1081
~C4AulDefFunc() override
C4Effect * Check(const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
Definition: C4Effect.cpp:249
C4V_Type GetType() const
Definition: C4Value.h:161
C4StringTable Strings
Definition: C4Globals.cpp:42
const char * GetTypeName() const
Definition: C4Value.h:164
virtual bool GetPropertyByS(const C4String *k, C4Value *pResult) const
Definition: C4PropList.cpp:753
C4Value C4VPropList(C4PropList *p)
Definition: C4Value.h:245
static C4Effect * New(C4PropList *pForObj, C4Effect **ppEffectList, C4String *szName, int32_t iPrio, int32_t iTimerInterval, C4PropList *pCmdTarget, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
Definition: C4Effect.cpp:91
virtual const char * GetName() const
Definition: C4PropList.cpp:645
#define C4FxCall_DmgChop
Definition: C4Effect.h:52
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:910
void AppendCharacter(uint32_t unicodechar)
Definition: StdBuf.cpp:392
C4PropList * GetPrototype() const
Definition: C4PropList.h:81
bool SWildcardMatchEx(const char *szString, const char *szWildcard)
Definition: Standard.cpp:607
void Append(const char *pnData, size_t iChars)
Definition: StdBuf.h:519
#define C4Fx_Execute_Kill
Definition: C4Effect.h:36
void Copy(const C4Value *Pars, int ParCount)
Definition: C4AulFunc.h:37
Definition: C4Def.h:98
void SetDead()
Definition: C4Effect.cpp:205
C4Fixed itofix(int32_t x)
Definition: C4Real.h:261
void SetSize(int32_t inSize)
#define F(f)
C4Value Exec(C4PropList *p=nullptr, C4AulParSet *pPars=nullptr, bool fPassErrors=false)
Definition: C4AulFunc.h:73
static C4String * FnTranslate(C4PropList *_this, C4String *text)
Definition: C4AulExec.cpp:100
C4ValueMapData GlobalConsts
Definition: C4Aul.h:142
int Angle(int iX1, int iY1, int iX2, int iY2)
Definition: Standard.cpp:36
int32_t Status
Definition: C4PropList.h:168
C4ValueArray * getArray() const
Definition: C4Value.h:118
C4Value C4VArray(C4ValueArray *pArray)
Definition: C4Value.h:249
bool IsFrozen() const
Definition: C4PropList.h:131
static void StartProfiling(C4ScriptHost *pScript)
Definition: C4AulExec.cpp:963
int32_t GetSize() const
Definition: C4ValueArray.h:36
virtual C4Effect * GetEffect()
Definition: C4PropList.cpp:705
C4Effect * Get(const char *szName, int32_t iIndex=0, int32_t iMaxPriority=0)
Definition: C4Effect.cpp:210
void Sort(class C4SortObject &rSort)
int32_t getInt() const
Definition: C4Value.h:112
C4Value C4VBool(bool b)
Definition: C4Value.h:243
#define C4Fx_Start_Deny
Definition: C4Effect.h:39
bool HasProperty(C4String *k) const
Definition: C4PropList.h:118
const C4Value C4VNull
Definition: C4Value.cpp:30
bool IsFrozen() const
Definition: C4ValueArray.h:63
const char * Identifier
Definition: C4AulDefFunc.h:268
#define C4FxCall_Temp
Definition: C4Effect.h:43
Iterator end()
Definition: C4Gui.h:825
C4ScriptFnDef * Def
Definition: C4AulDefFunc.h:287
#define C4FxCall_EngGetPunched
Definition: C4Effect.h:63
bool WildcardMatch(const char *szWildcard, const char *szString)
Definition: StdFile.cpp:374
C4DefScriptHost Script
Definition: C4Def.h:182
int32_t GetAnzItems()
Definition: C4ValueMap.cpp:248
#define C4Fx_Effect_Annul
Definition: C4Effect.h:33
bool Log(const char *szMessage)
Definition: C4Log.cpp:192
void StartTrace()
Definition: C4AulExec.cpp:905
bool SEqual2(const char *szStr1, const char *szStr2)
Definition: Standard.cpp:176
#define C4FxCall_EngBaseRefresh
Definition: C4Effect.h:59
C4Value C4VString(C4String *pStr)
Definition: C4Value.h:246
C4Effect ** FnGetEffectsFor(C4PropList *pTarget)
#define C4FxCall_EngObjHit
Definition: C4Effect.h:57
size_t getLength() const
Definition: StdBuf.h:445
C4Value C4VFunction(C4AulFunc *pFn)
Definition: C4Value.h:250
virtual void SetPropertyByS(C4String *k, const C4Value &to)
Definition: C4PropList.cpp:948
bool IsIdenticalTo(const C4Value &cmp) const
Definition: C4Value.h:149
T Abs(T val)
Definition: Standard.h:42
C4Real Sin(const C4Real &fAngle)
Definition: C4Real.h:265
const char * Script
const char * GetScript() const
Definition: C4ScriptHost.h:52
C4Value DoCall(C4PropList *pObj, const char *szFn, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4, const C4Value &rVal5, const C4Value &rVal6, const C4Value &rVal7)
Definition: C4Effect.cpp:409
#define C4FxCall_EngBlast
Definition: C4Effect.h:56
#define C4FxCall_EngAsphyxiation
Definition: C4Effect.h:60
C4RefCntPointer< C4String > Name
Definition: C4AulFunc.h:61
#define C4Fx_Stop_Deny
Definition: C4Effect.h:38
uint32_t DWORD
virtual C4AulScriptFunc * SFunc()
Definition: C4AulFunc.h:66
int fixtoi(const C4Fixed &x)
Definition: C4Real.h:259
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:250
void AddFunc(C4PropListStatic *Parent, const char *Name, RType(*pFunc)(ThisType *, ParTypes...), bool Public=true)
Definition: C4AulDefFunc.h:260
void Copy()
Definition: StdBuf.h:467
StdCopyStrBuf ScriptName
Definition: C4ScriptHost.h:57
#define s
bool Inside(T ival, U lbound, V rbound)
Definition: Standard.h:43
C4AulFunc * getFunction() const
Definition: C4Value.h:119
#define C4FxCall_DmgScript
Definition: C4Effect.h:49
C4Real Cos(const C4Real &fAngle)
Definition: C4Real.h:266
C4Value DirectExec(C4PropList *p, const char *szScript, const char *szContext, bool fPassErrors=false, C4AulScriptContext *context=nullptr, bool parse_function=false)
Definition: C4AulExec.cpp:1013
#define C4Fx_OK
Definition: C4Effect.h:30
static C4PropList * New(C4PropList *prototype=nullptr)
Definition: C4PropList.cpp:64
int iSize
Definition: TstC4NetIO.cpp:32
StdStrBuf FormatString(const char *szFmt,...)
Definition: StdBuf.cpp:270
C4PropList * getPropList() const
Definition: C4Value.h:116