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