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