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