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 static long FnAbs(C4PropList * _this, long iVal)
621 {
622  return Abs(iVal);
623 }
624 
625 static long FnSin(C4PropList * _this, long iAngle, long iRadius, long iPrec)
626 {
627  if (!iPrec) iPrec = 1;
628  // Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow
629  iAngle %= 360 * iPrec;
630  // Let itofix and fixtoi handle the division and multiplication because that can handle higher ranges
631  return fixtoi(Sin(itofix(iAngle, iPrec)), iRadius);
632 }
633 
634 static long FnCos(C4PropList * _this, long iAngle, long iRadius, long iPrec)
635 {
636  if (!iPrec) iPrec = 1;
637  iAngle %= 360 * iPrec;
638  return fixtoi(Cos(itofix(iAngle, iPrec)), iRadius);
639 }
640 
641 static long FnSqrt(C4PropList * _this, long iValue)
642 {
643  if (iValue<0) return 0;
644  long iSqrt = long(sqrt(double(iValue)));
645  if (iSqrt * iSqrt < iValue) iSqrt++;
646  if (iSqrt * iSqrt > iValue) iSqrt--;
647  return iSqrt;
648 }
649 
650 static long FnAngle(C4PropList * _this, long iX1, long iY1, long iX2, long iY2, long iPrec)
651 {
652  long iAngle;
653 
654  // Standard prec
655  if (!iPrec) iPrec = 1;
656 
657  long dx=iX2-iX1,dy=iY2-iY1;
658  if (!dx)
659  {
660  if (dy>0) return 180 * iPrec;
661  else return 0;
662  }
663  if (!dy)
664  {
665  if (dx>0) return 90 * iPrec;
666  else return 270 * iPrec;
667  }
668 
669  iAngle = static_cast<long>(180.0 * iPrec * atan2(static_cast<double>(Abs(dy)), static_cast<double>(Abs(dx))) / M_PI);
670 
671  if (iX2>iX1 )
672  {
673  if (iY2<iY1) iAngle = (90 * iPrec) - iAngle;
674  else iAngle = (90 * iPrec) + iAngle;
675  }
676  else
677  {
678  if (iY2<iY1) iAngle = (270 * iPrec) + iAngle;
679  else iAngle = (270 * iPrec) - iAngle;
680  }
681 
682  return iAngle;
683 }
684 
685 static long FnArcSin(C4PropList * _this, long iVal, long iRadius)
686 {
687  // safety
688  if (!iRadius) return 0;
689  if (iVal > iRadius) return 0;
690  // calc arcsin
691  double f1 = iVal;
692  f1 = asin(f1/iRadius)*180.0/M_PI;
693  // return rounded angle
694  return (long) floor(f1+0.5);
695 }
696 
697 static long FnArcCos(C4PropList * _this, long iVal, long iRadius)
698 {
699  // safety
700  if (!iRadius) return 0;
701  if (iVal > iRadius) return 0;
702  // calc arccos
703  double f1 = iVal;
704  f1 = acos(f1/iRadius)*180.0/M_PI;
705  // return rounded angle
706  return (long) floor(f1+0.5);
707 }
708 
709 static std::pair<Nillable<int32_t>, Nillable<int32_t>> minmax(const char *func, const C4Value &a_val, const Nillable<int32_t> &b_opt)
710 {
711  if (a_val.CheckConversion(C4V_Int))
712  {
713  int32_t a = a_val.getInt();
714  int32_t b = b_opt;
715  if (a > b)
716  std::swap(a, b);
717  return std::make_pair(a, b);
718  }
719  else if (a_val.CheckConversion(C4V_Array))
720  {
721  const C4ValueArray *a = a_val.getArray();
722  if (a->GetSize() == 0)
723  return std::make_pair(nullptr, nullptr);
724 
725  if (!a->GetItem(0).CheckConversion(C4V_Int))
726  {
727  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());
728  }
729  int32_t min, max;
730  min = max = a->GetItem(0).getInt();
731 
732  for (int32_t i = 1; i < a->GetSize(); ++i)
733  {
734  if (!a->GetItem(i).CheckConversion(C4V_Int))
735  {
736  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());
737  }
738  int32_t value = a->GetItem(i).getInt();
739  min = std::min(min, value);
740  max = std::max(max, value);
741  }
742 
743  return std::make_pair(min, max);
744  }
745  else
746  {
747  throw C4AulExecError(FormatString("%s: argument 1 must be int or array-of-int, but is of type %s", func, a_val.GetTypeName()).getData());
748  }
749 }
750 
751 static Nillable<int32_t> FnMin(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
752 {
753  return minmax("Min", a, b).first;
754 }
755 
756 static Nillable<int32_t> FnMax(C4PropList * _this, const C4Value &a, Nillable<int32_t> b)
757 {
758  return minmax("Max", a, b).second;
759 }
760 
761 static long FnDistance(C4PropList * _this, long iX1, long iY1, long iX2, long iY2)
762 {
763  return Distance(iX1,iY1,iX2,iY2);
764 }
765 
766 static long FnBoundBy(C4PropList * _this, long iVal, long iRange1, long iRange2)
767 {
768  return Clamp(iVal,iRange1,iRange2);
769 }
770 
771 static bool FnInside(C4PropList * _this, long iVal, long iRange1, long iRange2)
772 {
773  return Inside(iVal,iRange1,iRange2);
774 }
775 
776 static long FnRandom(C4PropList * _this, long iRange)
777 {
778  return Random(iRange);
779 }
780 
781 static int FnGetType(C4PropList * _this, const C4Value & Value)
782 {
783  // dynamic types
784  if (Value.CheckConversion(C4V_Object)) return C4V_Object;
785  if (Value.CheckConversion(C4V_Def)) return C4V_Def;
786  if (Value.CheckConversion(C4V_Effect)) return C4V_Effect;
787  // static types
788  return Value.GetType();
789 }
790 
791 static C4ValueArray * FnCreateArray(C4PropList * _this, int iSize)
792 {
793  return new C4ValueArray(iSize);
794 }
795 
796 static int FnGetLength(C4PropList * _this, const C4Value & Par)
797 {
798  // support GetLength() etc.
799  C4ValueArray * pArray = Par.getArray();
800  if (pArray)
801  return pArray->GetSize();
802  C4String * pStr = Par.getStr();
803  if (pStr)
804  return GetCharacterCount(pStr->GetData().getData());
805  throw C4AulExecError("GetLength: parameter 0 cannot be converted to string or array");
806 }
807 
808 static int FnGetIndexOf(C4PropList * _this, C4ValueArray * pArray, const C4Value & Needle)
809 {
810  // find first occurance of first parameter in array
811  // support GetIndexOf(0, x)
812  if (!pArray) return -1;
813  int32_t iSize = pArray->GetSize();
814  for (int32_t i = 0; i < iSize; ++i)
815  if (Needle.IsIdenticalTo(pArray->GetItem(i)))
816  // element found
817  return i;
818  // element not found
819  return -1;
820 }
821 
822 static bool FnDeepEqual(C4PropList * _this, const C4Value & v1, const C4Value & v2)
823 {
824  // return if v1==v2 with deep comparison on arrays and proplists
825  return v1 == v2;
826 }
827 
828 static void FnSetLength(C4PropList * _this, C4ValueArray *pArray, int iNewSize)
829 {
830  // safety
831  if (iNewSize<0 || iNewSize > C4ValueArray::MaxSize)
832  throw C4AulExecError(FormatString("SetLength: invalid array size (%d)", iNewSize).getData());
833 
834  // set new size
835  pArray->SetSize(iNewSize);
836 }
837 
838 static Nillable<long> FnGetChar(C4PropList * _this, C4String *pString, long iIndex)
839 {
840  const char *szText = FnStringPar(pString);
841  if (!szText) return C4Void();
842  // C4Strings are UTF-8 encoded, so decode to get the indicated character
843  uint32_t c = GetNextCharacter(&szText);
844  for (int i = 0; i < iIndex; ++i)
845  {
846  c = GetNextCharacter(&szText);
847  if (!c) return C4Void();
848  }
849  return c;
850 }
851 
852 static C4String *FnStringToIdentifier(C4PropList * _this, C4String *pString)
853 {
854  // Change an arbitrary string so that it becomes an identifier
855  const char *text = FnStringPar(pString);
856  if (!text) return nullptr;
857  StdStrBuf result;
858  bool had_valid = false, had_invalid = false;
859  const char *ptext = text, *t0 = text;
860  uint32_t c = GetNextCharacter(&text);
861  while (c)
862  {
863  if (isalnum(c) || c == '_')
864  {
865  // Starting with a digit? Needs to prepend a character
866  if (isdigit(c) && !had_valid)
867  {
868  result.Append("_");
869  had_invalid = true;
870  }
871  // Valid character: Append to result string if a modification had to be done
872  if (had_invalid) result.Append(ptext, text - ptext);
873  had_valid = true;
874  }
875  else
876  {
877  // Invalid character. Make sure result is created from previous valid characters
878  if (!had_invalid)
879  {
880  result.Copy(t0, ptext - t0);
881  had_invalid = true;
882  }
883  }
884  ptext = text;
885  c = GetNextCharacter(&text);
886  }
887  // Make sure no empty string is returned
888  if (!had_valid) return ::Strings.RegString("_");
889  // Return either modified string or the original if no modifications were needed
890  return had_invalid ? ::Strings.RegString(result) : pString;
891 }
892 
893 static C4Value Fneval(C4PropList * _this, C4String *strScript, bool dont_pass_errors)
894 {
895  return ::AulExec.DirectExec(_this, FnStringPar(strScript), "eval", !dont_pass_errors);
896 }
897 
898 static bool FnLocateFunc(C4PropList * _this, C4String *funcname, C4PropList * p)
899 {
900  // safety
901  if (!funcname || !funcname->GetCStr())
902  {
903  Log("No func name");
904  return false;
905  }
906  if (!p) p = _this;
907  // get function by name
908  C4AulFunc *pFunc = p->GetFunc(funcname);
909  if (!pFunc)
910  {
911  LogF("Func %s not found", funcname->GetCStr());
912  }
913  else
914  {
915  const char *szPrefix = "";
916  while (pFunc)
917  {
918  C4AulScriptFunc *pSFunc = pFunc->SFunc();
919  if (!pSFunc)
920  {
921  LogF("%s%s (engine)", szPrefix, pFunc->GetName());
922  }
923  else if (!pSFunc->pOrgScript)
924  {
925  LogF("%s%s (no owner)", szPrefix, pSFunc->GetName());
926  }
927  else
928  {
929  int32_t iLine = SGetLine(pSFunc->pOrgScript->GetScript(), pSFunc->Script);
930  LogF("%s%s (%s:%d)", szPrefix, pFunc->GetName(), pSFunc->pOrgScript->ScriptName.getData(), (int)iLine);
931  }
932  // next func in overload chain
933  pFunc = pSFunc ? pSFunc->OwnerOverloaded : nullptr;
934  szPrefix = "overloads ";
935  }
936  }
937  return true;
938 }
939 
940 static long FnModulateColor(C4PropList * _this, long iClr1, long iClr2)
941 {
942  DWORD dwClr1 = iClr1;
943  DWORD dwClr2 = iClr2;
944  // default color
945  if (!dwClr1) dwClr1 = 0xffffff;
946  // get alpha
947  long iA1=dwClr1>>24, iA2=dwClr2>>24;
948  // modulate color values; mod alpha upwards
949  DWORD r = (((dwClr1 & 0xff) * (dwClr2 & 0xff)) >> 8) | // blue
950  (((dwClr1>> 8 & 0xff) * (dwClr2>>8 & 0xff)) & 0xff00) | // green
951  (((dwClr1>>16 & 0xff) * (dwClr2>>8 & 0xff00)) & 0xff0000) | // red
952  (std::min<long>(iA1+iA2 - ((iA1*iA2)>>8), 255) << 24); // alpha
953  return r;
954 }
955 
956 static long FnWildcardMatch(C4PropList * _this, C4String *psString, C4String *psWildcard)
957 {
958  return SWildcardMatchEx(FnStringPar(psString), FnStringPar(psWildcard));
959 }
960 
961 static bool FnFatalError(C4PropList * _this, C4String *pErrorMsg)
962 {
963  throw C4AulExecError(FormatString("script: %s", pErrorMsg ? pErrorMsg->GetCStr() : "(no error)").getData());
964 }
965 
966 static bool FnStartCallTrace(C4PropList * _this)
967 {
969  return true;
970 }
971 
972 static bool FnStartScriptProfiler(C4PropList * _this, C4Def * pDef)
973 {
974  // get script to profile
975  C4ScriptHost *pScript;
976  if (pDef)
977  pScript = &pDef->Script;
978  else
979  pScript = nullptr;
980  // profile it
982  return true;
983 }
984 
985 static bool FnStopScriptProfiler(C4PropList * _this)
986 {
988  return true;
989 }
990 
991 static Nillable<C4String *> FnGetConstantNameByValue(C4PropList * _this, int value, Nillable<C4String *> name_prefix, int idx)
992 {
993  C4String *name_prefix_s = name_prefix;
994  // find a constant that has the specified value and prefix
995  for (int32_t i = 0; i < ::ScriptEngine.GlobalConsts.GetAnzItems(); ++i)
996  {
997  if (::ScriptEngine.GlobalConsts[i].getInt() == value)
998  {
999  const char *const_name = ::ScriptEngine.GlobalConstNames.GetItemUnsafe(i);
1000  if (!name_prefix_s || SEqual2(const_name, name_prefix_s->GetCStr()))
1001  if (!idx--)
1002  // indexed constant found. return name minus prefix
1003  return String(const_name + (name_prefix_s ? name_prefix_s->GetData().getLength() : 0));
1004  }
1005  }
1006  // nothing found (at index)
1007  return C4Void();
1008 }
1009 
1010 static Nillable<C4String *> FnReplaceString(C4PropList * _this, C4String *source, C4String *from, C4String *to)
1011 {
1012  if (!from) return source;
1013  if (!source) return C4Void();
1014  const char *szto = to ? to->GetCStr() : "";
1015  const char *szfrom = from->GetCStr();
1016  StdStrBuf s(source->GetData(), true);
1017  if (s.Replace(szfrom, szto))
1018  {
1019  return ::Strings.RegString(s.getData());
1020  }
1021  else
1022  {
1023  return source;
1024  }
1025 }
1026 
1027 static bool FnSortArray(C4PropList * _this, C4ValueArray *pArray, bool descending)
1028 {
1029  if (!pArray) throw C4AulExecError("SortArray: no array given");
1030  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1031  // sort array by its members
1032  pArray->Sort(descending);
1033  return true;
1034 }
1035 
1036 static bool FnSortArrayByProperty(C4PropList * _this, C4ValueArray *pArray, C4String *prop_name, bool descending)
1037 {
1038  if (!pArray) throw C4AulExecError("SortArrayByProperty: no array given");
1039  if (!prop_name) throw C4AulExecError("SortArrayByProperty: no property name given");
1040  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1041  // sort array by property
1042  if (!pArray->SortByProperty(prop_name, descending)) throw C4AulExecError("SortArrayByProperty: not all array elements are proplists");
1043  return true;
1044 }
1045 
1046 static bool FnSortArrayByArrayElement(C4PropList * _this, C4ValueArray *pArray, int32_t element_index, bool descending)
1047 {
1048  if (!pArray) throw C4AulExecError("SortArrayByArrayElement: no array given");
1049  if (element_index<0) throw C4AulExecError("SortArrayByArrayElement: element index must be >=0");
1050  if (pArray->IsFrozen()) throw C4AulExecError("array sort: array is readonly");
1051  // sort array by array element
1052  if (!pArray->SortByArrayElement(element_index, descending)) throw C4AulExecError("SortArrayByArrayElement: not all array elements are arrays of sufficient length");
1053  return true;
1054 }
1055 
1056 static bool FnFileWrite(C4PropList * _this, int32_t file_handle, C4String *data)
1057 {
1058  // resolve file handle to user file
1059  C4AulUserFile *file = ::ScriptEngine.GetUserFile(file_handle);
1060  if (!file) throw C4AulExecError("FileWrite: invalid file handle");
1061  // prepare string to write
1062  if (!data) return false; // write nullptr? No.
1063  // write it
1064  file->Write(data->GetCStr(), data->GetData().getLength());
1065  return true;
1066 }
1067 
1068 //=========================== C4Script Function Map ===================================
1069 
1071 {
1072  { "FX_OK" ,C4V_Int, C4Fx_OK }, // generic standard behaviour for all effect callbacks
1073  { "FX_Effect_Deny" ,C4V_Int, C4Fx_Effect_Deny }, // delete effect
1074  { "FX_Effect_Annul" ,C4V_Int, C4Fx_Effect_Annul }, // delete effect, because it has annulled a countereffect
1075  { "FX_Effect_AnnulDoCalls" ,C4V_Int, C4Fx_Effect_AnnulCalls }, // delete effect, because it has annulled a countereffect; temp readd countereffect
1076  { "FX_Execute_Kill" ,C4V_Int, C4Fx_Execute_Kill }, // execute callback: Remove effect now
1077  { "FX_Stop_Deny" ,C4V_Int, C4Fx_Stop_Deny }, // deny effect removal
1078  { "FX_Start_Deny" ,C4V_Int, C4Fx_Start_Deny }, // deny effect start
1079 
1080  { "FX_Call_Normal" ,C4V_Int, C4FxCall_Normal }, // normal call; effect is being added or removed
1081  { "FX_Call_Temp" ,C4V_Int, C4FxCall_Temp }, // temp call; effect is being added or removed in responce to a lower-level effect change
1082  { "FX_Call_TempAddForRemoval" ,C4V_Int, C4FxCall_TempAddForRemoval }, // temp call; effect is being added because it had been temp removed and is now removed forever
1083  { "FX_Call_RemoveClear" ,C4V_Int, C4FxCall_RemoveClear }, // effect is being removed because object is being removed
1084  { "FX_Call_RemoveDeath" ,C4V_Int, C4FxCall_RemoveDeath }, // effect is being removed because object died - return -1 to avoid removal
1085  { "FX_Call_DmgScript" ,C4V_Int, C4FxCall_DmgScript }, // damage through script call
1086  { "FX_Call_DmgBlast" ,C4V_Int, C4FxCall_DmgBlast }, // damage through blast
1087  { "FX_Call_DmgFire" ,C4V_Int, C4FxCall_DmgFire }, // damage through fire
1088  { "FX_Call_DmgChop" ,C4V_Int, C4FxCall_DmgChop }, // damage through chopping
1089  { "FX_Call_Energy" ,C4V_Int, 32 }, // bitmask for generic energy loss
1090  { "FX_Call_EngScript" ,C4V_Int, C4FxCall_EngScript }, // energy loss through script call
1091  { "FX_Call_EngBlast" ,C4V_Int, C4FxCall_EngBlast }, // energy loss through blast
1092  { "FX_Call_EngObjHit" ,C4V_Int, C4FxCall_EngObjHit }, // energy loss through object hitting the living
1093  { "FX_Call_EngFire" ,C4V_Int, C4FxCall_EngFire }, // energy loss through fire
1094  { "FX_Call_EngBaseRefresh" ,C4V_Int, C4FxCall_EngBaseRefresh }, // energy reload in base (also by base object, but that's normally not called)
1095  { "FX_Call_EngAsphyxiation" ,C4V_Int, C4FxCall_EngAsphyxiation }, // energy loss through asphyxiaction
1096  { "FX_Call_EngCorrosion" ,C4V_Int, C4FxCall_EngCorrosion }, // energy loss through corrosion (acid)
1097  { "FX_Call_EngGetPunched" ,C4V_Int, C4FxCall_EngGetPunched }, // energy loss from punch
1098 
1099  { "Regex_CaseInsensitive" ,C4V_Int, Regex_CaseInsensitive },
1100  { "Regex_FirstOnly" ,C4V_Int, Regex_FirstOnly },
1101 
1102  { "C4V_Nil", C4V_Int, C4V_Nil},
1103  { "C4V_Int", C4V_Int, C4V_Int},
1104  { "C4V_Bool", C4V_Int, C4V_Bool},
1105  { "C4V_C4Object", C4V_Int, C4V_Object},
1106  { "C4V_Effect", C4V_Int, C4V_Effect},
1107  { "C4V_Def", C4V_Int, C4V_Def},
1108  { "C4V_String", C4V_Int, C4V_String},
1109  { "C4V_Array", C4V_Int, C4V_Array},
1110  { "C4V_Function", C4V_Int, C4V_Function},
1111  { "C4V_PropList", C4V_Int, C4V_PropList},
1112 
1113  { "C4X_Ver1", C4V_Int, C4XVER1},
1114  { "C4X_Ver2", C4V_Int, C4XVER2},
1115 
1116  { nullptr, C4V_Nil, 0}
1117 };
1118 
1120 {
1121  { "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 },
1122  { "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 },
1123  { "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 },
1124  { "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 },
1125  { "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 },
1126  { "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},
1127 
1128  { 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 }
1129 };
1130 
1132 {
1133  // add all def constants (all Int)
1134  for (C4ScriptConstDef *pCDef = &C4ScriptConstMap[0]; pCDef->Identifier; pCDef++)
1135  {
1136  assert(pCDef->ValType == C4V_Int); // only int supported currently
1137  pEngine->RegisterGlobalConstant(pCDef->Identifier, C4VInt(pCDef->Data));
1138  }
1139 
1140  C4PropListStatic * p = pEngine->GetPropList();
1141  // add all def script funcs
1142  for (C4ScriptFnDef *pDef = &C4ScriptFnMap[0]; pDef->Identifier; pDef++)
1143  new C4AulDefFunc(p, pDef);
1144 #define F(f) ::AddFunc(p, #f, Fn##f)
1145  F(Abs);
1146  F(Min);
1147  F(Max);
1148  F(Sin);
1149  F(Cos);
1150  F(Sqrt);
1151  F(ArcSin);
1152  F(ArcCos);
1153  F(BoundBy);
1154  F(Inside);
1155  F(Random);
1156 
1157  F(CreateArray);
1158  F(CreatePropList);
1159  F(GetProperties);
1160  F(GetProperty);
1161  F(SetProperty);
1162  F(GetPrototype);
1163  F(SetPrototype);
1164  F(ResetProperty);
1165  F(GetName);
1166  F(AddEffect);
1167  F(CreateEffect);
1168  F(CheckEffect);
1169  F(RemoveEffect);
1170  F(GetEffect);
1171  F(GetEffectCount);
1172  F(RegexReplace);
1173  F(RegexSearch);
1174  F(RegexMatch);
1175  F(RegexSplit);
1176  F(Distance);
1177  F(Angle);
1178  F(GetChar);
1179  F(GetType);
1180  F(ModulateColor);
1181  F(WildcardMatch);
1182  F(GetLength);
1183  F(SetLength);
1184  F(GetIndexOf);
1185  F(DeepEqual);
1186  F(FatalError);
1187  F(StartCallTrace);
1188  F(StartScriptProfiler);
1189  F(StopScriptProfiler);
1190  F(SortArray);
1191  F(SortArrayByProperty);
1192  F(SortArrayByArrayElement);
1193  F(Trans_Identity);
1194  F(Trans_Translate);
1195  F(Trans_Scale);
1196  F(Trans_Rotate);
1197  F(LocateFunc);
1198  F(FileWrite);
1199  F(eval);
1200  F(StringToIdentifier);
1201  F(GetConstantNameByValue);
1202  F(ReplaceString);
1203 
1204  ::AddFunc(p, "Translate", C4AulExec::FnTranslate);
1205  ::AddFunc(p, "LogCallStack", C4AulExec::FnLogCallStack);
1206 #undef F
1207 }
virtual void ResetProperty(C4String *k)
Definition: C4PropList.cpp:928
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:1119
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:122
#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:443
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:978
int GetCharacterCount(const char *s)
Definition: Standard.cpp:771
C4ScriptHost * pOrgScript
virtual class C4PropListStatic * IsStatic()
Definition: C4PropList.h:87
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:1131
C4AulFunc * OwnerOverloaded
C4String * GetParentKeyName()
Definition: C4PropList.h:272
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:1070
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:712
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:604
#define C4FxCall_DmgChop
Definition: C4Effect.h:52
virtual C4ValueArray * GetProperties() const
Definition: C4PropList.cpp:869
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:599
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:169
C4ValueArray * getArray() const
Definition: C4Value.h:118
C4Value C4VArray(C4ValueArray *pArray)
Definition: C4Value.h:249
bool IsFrozen() const
Definition: C4PropList.h:132
static void StartProfiling(C4ScriptHost *pScript)
Definition: C4AulExec.cpp:969
int32_t GetSize() const
Definition: C4ValueArray.h:36
virtual C4Effect * GetEffect()
Definition: C4PropList.cpp:664
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
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:911
bool SEqual2(const char *szStr1, const char *szStr2)
Definition: Standard.cpp:168
#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:907
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:1020
#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