| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (C) 1998-2000, Matthes Bender (RedWolf Design) |
| 5 | * Copyright (c) 2017, The OpenClonk Team and contributors |
| 6 | * Copyright (c) 2017-2022, The LegacyClonk 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 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */ |
| 19 | |
| 20 | /* Functions mapped by C4Script */ |
| 21 | |
| 22 | #include <C4Include.h> |
| 23 | #include <C4Script.h> |
| 24 | #include <C4Version.h> |
| 25 | |
| 26 | #include <C4Application.h> |
| 27 | #include <C4Object.h> |
| 28 | #include <C4ObjectInfo.h> |
| 29 | #include <C4ObjectCom.h> |
| 30 | #include <C4Random.h> |
| 31 | #include <C4Command.h> |
| 32 | #include <C4Console.h> |
| 33 | #include <C4Viewport.h> |
| 34 | #include <C4Wrappers.h> |
| 35 | #include <C4ObjectInfoList.h> |
| 36 | #include <C4Player.h> |
| 37 | #include <C4ObjectMenu.h> |
| 38 | #include <C4ValueHash.h> |
| 39 | #include <C4NetworkRestartInfos.h> |
| 40 | #include <C4SoundSystem.h> |
| 41 | |
| 42 | #include <array> |
| 43 | #include <cinttypes> |
| 44 | #include <numbers> |
| 45 | #include <optional> |
| 46 | #include <type_traits> |
| 47 | #include <utility> |
| 48 | |
| 49 | #ifndef _WIN32 |
| 50 | #include <sys/time.h> |
| 51 | #endif |
| 52 | |
| 53 | // Some Support Functions |
| 54 | |
| 55 | static void Warn(C4Object *const obj, const std::string_view message) |
| 56 | { |
| 57 | C4AulExecError{obj, message}.show(); |
| 58 | } |
| 59 | |
| 60 | template<typename... Args> |
| 61 | static void StrictError(C4AulContext *const context, C4AulScriptStrict errorSince, const std::format_string<Args...> message, Args &&... args) |
| 62 | { |
| 63 | const auto strictness = context->Caller ? context->Caller->Func->Owner->Strict : C4AulScriptStrict::NONSTRICT; |
| 64 | |
| 65 | const std::string result{std::format(message, std::forward<Args>(args)...)}; |
| 66 | if (strictness < errorSince) |
| 67 | { |
| 68 | Warn(obj: context->Obj, message: result); |
| 69 | } |
| 70 | else |
| 71 | { |
| 72 | throw C4AulExecError{context->Obj, result}; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | const C4ValueInt MaxFnStringParLen = 500; |
| 77 | |
| 78 | inline const static char *FnStringPar(const C4String *const pString) |
| 79 | { |
| 80 | return pString ? pString->Data.getData() : "" ; |
| 81 | } |
| 82 | |
| 83 | inline C4String *String(const char *str) |
| 84 | { |
| 85 | return str ? new C4String((str), &Game.ScriptEngine.Strings) : nullptr; |
| 86 | } |
| 87 | |
| 88 | inline C4String *String(StdStrBuf &&str) |
| 89 | { |
| 90 | return str ? new C4String(std::forward<StdStrBuf>(t&: str), &Game.ScriptEngine.Strings) : nullptr; |
| 91 | } |
| 92 | |
| 93 | static std::string FnStringFormat(C4AulContext *cthr, const char *szFormatPar, C4Value *Par0 = nullptr, C4Value *Par1 = nullptr, C4Value *Par2 = nullptr, C4Value *Par3 = nullptr, |
| 94 | C4Value *Par4 = nullptr, C4Value *Par5 = nullptr, C4Value *Par6 = nullptr, C4Value *Par7 = nullptr, C4Value *Par8 = nullptr, C4Value *Par9 = nullptr) |
| 95 | { |
| 96 | C4Value *Par[11]; |
| 97 | Par[0] = Par0; Par[1] = Par1; Par[2] = Par2; Par[3] = Par3; Par[4] = Par4; |
| 98 | Par[5] = Par5; Par[6] = Par6; Par[7] = Par7; Par[8] = Par8; Par[9] = Par9; |
| 99 | Par[10] = nullptr; |
| 100 | int cPar = 0; |
| 101 | |
| 102 | std::string stringBuf; |
| 103 | const char *cpFormat = szFormatPar; |
| 104 | const char *cpType; |
| 105 | char szField[MaxFnStringParLen + 1]; |
| 106 | while (*cpFormat) |
| 107 | { |
| 108 | // Copy normal stuff |
| 109 | while (*cpFormat && (*cpFormat != '%')) |
| 110 | stringBuf += *cpFormat++; |
| 111 | // Field |
| 112 | if (*cpFormat == '%') |
| 113 | { |
| 114 | // Scan field type |
| 115 | for (cpType = cpFormat + 1; *cpType && (*cpType == '.' || Inside(ival: *cpType, lbound: '0', rbound: '9')); cpType++); |
| 116 | // Copy field |
| 117 | SCopy(szSource: cpFormat, sTarget: szField, iMaxL: std::min<unsigned int>(a: sizeof(szField) - 1, b: cpType - cpFormat + 1)); |
| 118 | // Insert field by type |
| 119 | switch (*cpType) |
| 120 | { |
| 121 | // number |
| 122 | case 'd': case 'x': case 'X': case 'c': |
| 123 | { |
| 124 | if (!Par[cPar]) throw C4AulExecError(cthr->Obj, "format placeholder without parameter" ); |
| 125 | stringBuf += fmt::sprintf(fmt: szField, args: Par[cPar++]->getInt()); |
| 126 | cpFormat += SLen(sptr: szField); |
| 127 | break; |
| 128 | } |
| 129 | // C4ID |
| 130 | case 'i': |
| 131 | { |
| 132 | if (!Par[cPar]) throw C4AulExecError(cthr->Obj, "format placeholder without parameter" ); |
| 133 | C4ID id = Par[cPar++]->getC4ID(); |
| 134 | stringBuf += C4IdText(id); |
| 135 | cpFormat += SLen(sptr: szField); |
| 136 | break; |
| 137 | } |
| 138 | // C4Value |
| 139 | case 'v': |
| 140 | { |
| 141 | if (!Par[cPar]) throw C4AulExecError(cthr->Obj, "format placeholder without parameter" ); |
| 142 | if (!Par[cPar]->_getRaw() && !cthr->CalledWithStrictNil()) |
| 143 | { |
| 144 | stringBuf += '0'; |
| 145 | } |
| 146 | else |
| 147 | { |
| 148 | stringBuf += Par[cPar++]->GetDataString(); |
| 149 | } |
| 150 | cpFormat += SLen(sptr: szField); |
| 151 | break; |
| 152 | } |
| 153 | // String |
| 154 | case 's': |
| 155 | { |
| 156 | // get string |
| 157 | if (!Par[cPar]) throw C4AulExecError(cthr->Obj, "format placeholder without parameter" ); |
| 158 | const char *szStr = "(null)" ; |
| 159 | if (Par[cPar]->GetData()) |
| 160 | { |
| 161 | C4String *pStr = Par[cPar++]->getStr(); |
| 162 | if (!pStr) throw C4AulExecError(cthr->Obj, "string format placeholder without string" ); |
| 163 | szStr = pStr->Data.getData(); |
| 164 | } |
| 165 | stringBuf += fmt::sprintf(fmt: szField, args: szStr); |
| 166 | cpFormat += SLen(sptr: szField); |
| 167 | break; |
| 168 | } |
| 169 | case '%': |
| 170 | stringBuf += '%'; |
| 171 | cpFormat += SLen(sptr: szField); |
| 172 | break; |
| 173 | // Undefined / Empty |
| 174 | default: |
| 175 | stringBuf += '%'; |
| 176 | cpFormat++; |
| 177 | break; |
| 178 | } |
| 179 | } |
| 180 | } |
| 181 | return stringBuf; |
| 182 | } |
| 183 | |
| 184 | bool CheckEnergyNeedChain(C4Object *pObj, C4ObjectList &rEnergyChainChecked) |
| 185 | { |
| 186 | if (!pObj) return false; |
| 187 | |
| 188 | // No recursion, flag check |
| 189 | if (rEnergyChainChecked.GetLink(pObj)) return false; |
| 190 | rEnergyChainChecked.Add(nObj: pObj, eSort: C4ObjectList::stNone); |
| 191 | |
| 192 | // This object needs energy |
| 193 | if (pObj->Def->LineConnect & C4D_Power_Consumer) |
| 194 | if (pObj->NeedEnergy) |
| 195 | return true; |
| 196 | |
| 197 | // Check all power line connected structures |
| 198 | C4Object *cline; C4ObjectLink *clnk; |
| 199 | for (clnk = Game.Objects.First; clnk && (cline = clnk->Obj); clnk = clnk->Next) |
| 200 | if (cline->Status) if (cline->Def->id == C4ID_PowerLine) |
| 201 | if (cline->Action.Target == pObj) |
| 202 | if (CheckEnergyNeedChain(pObj: cline->Action.Target2, rEnergyChainChecked)) |
| 203 | return true; |
| 204 | |
| 205 | return false; |
| 206 | } |
| 207 | |
| 208 | uint32_t StringBitEval(const char *str) |
| 209 | { |
| 210 | uint32_t rval = 0; |
| 211 | for (int cpos = 0; str && str[cpos]; cpos++) |
| 212 | if ((str[cpos] != '_') && (str[cpos] != ' ')) |
| 213 | rval += 1 << cpos; |
| 214 | return rval; |
| 215 | } |
| 216 | |
| 217 | // C4Script Functions |
| 218 | |
| 219 | static C4Object *Fn_this(C4AulContext *cthr) |
| 220 | { |
| 221 | return cthr->Obj; |
| 222 | } |
| 223 | |
| 224 | static C4ValueInt Fn_goto(C4AulContext *cthr, C4ValueInt iCounter) |
| 225 | { |
| 226 | Game.Script.Counter = iCounter; |
| 227 | return iCounter; |
| 228 | } |
| 229 | |
| 230 | static bool FnChangeDef(C4AulContext *cthr, C4ID to_id, C4Object *pObj) |
| 231 | { |
| 232 | if (!pObj) pObj = cthr->Obj; |
| 233 | if (!pObj) return false; |
| 234 | return pObj->ChangeDef(idNew: to_id); |
| 235 | } |
| 236 | |
| 237 | static bool FnExplode(C4AulContext *cthr, C4ValueInt iLevel, C4Object *pObj, C4ID idEffect, C4String *szEffect) |
| 238 | { |
| 239 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 240 | pObj->Explode(iLevel, idEffect, szEffect: FnStringPar(pString: szEffect)); |
| 241 | return true; |
| 242 | } |
| 243 | |
| 244 | static bool FnIncinerate(C4AulContext *cthr, C4Object *pObj) |
| 245 | { |
| 246 | if (!pObj) pObj = cthr->Obj; |
| 247 | if (!pObj) return false; |
| 248 | C4ValueInt iCausedBy = NO_OWNER; |
| 249 | if (cthr->Obj) iCausedBy = cthr->Obj->Controller; |
| 250 | return pObj->Incinerate(iCausedBy); |
| 251 | } |
| 252 | |
| 253 | static bool FnIncinerateLandscape(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY) |
| 254 | { |
| 255 | if (cthr->Obj) |
| 256 | { |
| 257 | iX += cthr->Obj->x; |
| 258 | iY += cthr->Obj->y; |
| 259 | } |
| 260 | return Game.Landscape.Incinerate(x: iX, y: iY); |
| 261 | } |
| 262 | |
| 263 | static bool FnExtinguish(C4AulContext *cthr, C4Object *pObj) |
| 264 | { |
| 265 | if (!pObj) pObj = cthr->Obj; |
| 266 | if (!pObj) return false; |
| 267 | // extinguish all fires |
| 268 | return pObj->Extinguish(iFireNumber: 0); |
| 269 | } |
| 270 | |
| 271 | static bool FnSetSolidMask(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4ValueInt iTX, C4ValueInt iTY, C4Object *pObj) |
| 272 | { |
| 273 | if (!pObj) pObj = cthr->Obj; |
| 274 | if (!pObj) return false; |
| 275 | pObj->SetSolidMask(iX, iY, iWdt, iHgt, iTX, iTY); |
| 276 | return true; |
| 277 | } |
| 278 | |
| 279 | static void FnSetGravity(C4AulContext *cthr, C4ValueInt iGravity) |
| 280 | { |
| 281 | Game.Landscape.Gravity = itofix(x: BoundBy<C4ValueInt>(bval: iGravity, lbound: -300, rbound: 300)) / 500; |
| 282 | } |
| 283 | |
| 284 | static C4ValueInt FnGetGravity(C4AulContext *cthr) |
| 285 | { |
| 286 | return fixtoi(x: Game.Landscape.Gravity * 500); |
| 287 | } |
| 288 | |
| 289 | template<int N> |
| 290 | static void DeathAnnounceMessageHelper(C4Object *const obj, const int n) |
| 291 | { |
| 292 | if (N == n) |
| 293 | { |
| 294 | GameMsgObject(szText: LoadResStr(id: static_cast<C4ResStrTableKey>(std::to_underlying(value: C4ResStrTableKey::IDS_OBJ_DEATH1) + N), args: obj->GetName()).c_str(), pTarget: obj); |
| 295 | } |
| 296 | else if constexpr (N > 0) |
| 297 | { |
| 298 | DeathAnnounceMessageHelper<N - 1>(obj, n); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | static bool FnDeathAnnounce(C4AulContext *cthr) |
| 303 | { |
| 304 | static constexpr int MaxDeathMsg{7}; |
| 305 | if (!cthr->Obj) return false; |
| 306 | if (Game.C4S.Head.Film) return true; |
| 307 | // Check if crew member has an own death message |
| 308 | if (cthr->Obj->Info && *(cthr->Obj->Info->DeathMessage)) |
| 309 | { |
| 310 | GameMsgObject(szText: cthr->Obj->Info->DeathMessage, pTarget: cthr->Obj); |
| 311 | } |
| 312 | else |
| 313 | { |
| 314 | DeathAnnounceMessageHelper<MaxDeathMsg - 1>(obj: cthr->Obj, n: SafeRandom(range: MaxDeathMsg)); |
| 315 | } |
| 316 | return true; |
| 317 | } |
| 318 | |
| 319 | static bool FnGrabContents(C4AulContext *cthr, C4Object *from, C4Object *pTo) |
| 320 | { |
| 321 | if (!pTo && !(pTo = cthr->Obj)) return false; |
| 322 | if (!from) return false; |
| 323 | if (pTo == from) return false; |
| 324 | pTo->GrabContents(pFrom: from); |
| 325 | return true; |
| 326 | } |
| 327 | |
| 328 | static bool FnPunch(C4AulContext *cthr, C4Object *target, C4ValueInt punch) |
| 329 | { |
| 330 | if (!cthr->Obj) return false; |
| 331 | return ObjectComPunch(cObj: cthr->Obj, pTarget: target, iPunch: punch); |
| 332 | } |
| 333 | |
| 334 | static bool FnKill(C4AulContext *cthr, C4Object *pObj, bool fForced) |
| 335 | { |
| 336 | if (!pObj) pObj = cthr->Obj; |
| 337 | if (!pObj) return false; |
| 338 | if (!pObj->GetAlive()) return false; |
| 339 | // Trace kills by player-owned objects |
| 340 | // Do not trace for NO_OWNER, because that would include e.g. the Suicide-rule |
| 341 | if (cthr->Obj && ValidPlr(plr: cthr->Obj->Controller)) pObj->UpdatLastEnergyLossCause(iNewCausePlr: cthr->Obj->Controller); |
| 342 | // Do the kill |
| 343 | pObj->AssignDeath(fForced); |
| 344 | return true; |
| 345 | } |
| 346 | |
| 347 | static bool FnFling(C4AulContext *cthr, C4Object *pObj, C4ValueInt iXDir, C4ValueInt iYDir, C4ValueInt iPrec, bool fAddSpeed) |
| 348 | { |
| 349 | if (!pObj) return false; |
| 350 | if (!iPrec) iPrec = 1; |
| 351 | pObj->Fling(txdir: itofix(x: iXDir, prec: iPrec), tydir: itofix(x: iYDir, prec: iPrec), fAddSpeed, byPlayer: cthr->Obj ? cthr->Obj->Controller : NO_OWNER); |
| 352 | // unstick from ground, because Fling command may be issued in an Action-callback, |
| 353 | // where attach-values have already been determined for that frame |
| 354 | pObj->Action.t_attach = 0; |
| 355 | return true; |
| 356 | } |
| 357 | |
| 358 | static bool FnJump(C4AulContext *cthr, C4Object *pObj) |
| 359 | { |
| 360 | if (!pObj) pObj = cthr->Obj; |
| 361 | if (!pObj) return false; |
| 362 | return ObjectComJump(cObj: pObj); |
| 363 | } |
| 364 | |
| 365 | static bool FnEnter(C4AulContext *cthr, C4Object *pTarget, C4Object *pObj) |
| 366 | { |
| 367 | if (!pObj) pObj = cthr->Obj; |
| 368 | if (!pObj) return false; |
| 369 | return pObj->Enter(pTarget); |
| 370 | } |
| 371 | |
| 372 | static bool FnExit(C4AulContext *cthr, C4Object *pObj, C4ValueInt tx, C4ValueInt ty, C4ValueInt tr, C4ValueInt txdir, C4ValueInt tydir, C4ValueInt trdir) |
| 373 | { |
| 374 | if (!pObj) pObj = cthr->Obj; |
| 375 | if (!pObj) return false; |
| 376 | if (cthr->Obj) |
| 377 | { |
| 378 | tx += cthr->Obj->x; |
| 379 | ty += cthr->Obj->y; |
| 380 | } |
| 381 | if (tr == -1) tr = Random(iRange: 360); |
| 382 | ObjectComCancelAttach(cObj: pObj); |
| 383 | return pObj->Exit(iX: tx, |
| 384 | iY: ty + pObj->Shape.y, |
| 385 | iR: tr, |
| 386 | iXDir: itofix(x: txdir), iYDir: itofix(x: tydir), |
| 387 | iRDir: itofix(x: trdir) / 10); |
| 388 | } |
| 389 | |
| 390 | static bool FnCollect(C4AulContext *cthr, C4Object *pItem, C4Object * pCollector) |
| 391 | { |
| 392 | // local call / safety |
| 393 | if (!pCollector) pCollector = cthr->Obj; |
| 394 | if (!pItem || !pCollector) return false; |
| 395 | // Script function Collect ignores NoCollectDelay |
| 396 | int32_t iOldNoCollectDelay = pCollector->NoCollectDelay; |
| 397 | if (iOldNoCollectDelay) |
| 398 | { |
| 399 | pCollector->NoCollectDelay = 0; |
| 400 | pCollector->UpdateOCF(); |
| 401 | } |
| 402 | |
| 403 | bool success = false; |
| 404 | // check OCF of collector (MaxCarry) |
| 405 | if (pCollector->OCF & OCF_Collection) |
| 406 | // collect |
| 407 | success = pCollector->Collect(pObj: pItem); |
| 408 | // restore NoCollectDelay |
| 409 | if (iOldNoCollectDelay > pCollector->NoCollectDelay) pCollector->NoCollectDelay = iOldNoCollectDelay; |
| 410 | // failure |
| 411 | return success; |
| 412 | } |
| 413 | |
| 414 | static bool FnSplit2Components(C4AulContext *cthr, C4Object *pObj) |
| 415 | { |
| 416 | C4Object *pThing, *pNew, *pContainer; |
| 417 | size_t cnt, cnt2; |
| 418 | // Pointer required |
| 419 | if (!pObj) pObj = cthr->Obj; |
| 420 | if (!pObj) return false; |
| 421 | // Store container |
| 422 | pContainer = pObj->Contained; |
| 423 | // Contents: exit / transfer to container |
| 424 | while (pThing = pObj->Contents.GetObject()) |
| 425 | if (pContainer) pThing->Enter(pTarget: pContainer); |
| 426 | else pThing->Exit(iX: pThing->x, iY: pThing->y); |
| 427 | // Destroy the object, create its components |
| 428 | C4IDList ObjComponents; |
| 429 | pObj->Def->GetComponents(pOutList: &ObjComponents, pObjInstance: pObj, pBuilder: cthr->Obj); |
| 430 | if (pObj->Contained) pObj->Exit(iX: pObj->x, iY: pObj->y); |
| 431 | for (cnt = 0; ObjComponents.GetID(index: cnt); cnt++) |
| 432 | { |
| 433 | for (cnt2 = 0; cnt2 < ObjComponents.GetCount(index: cnt); cnt2++) |
| 434 | { |
| 435 | // force argument evaluation order |
| 436 | const auto r4 = itofix(x: Rnd3()); |
| 437 | const auto r3 = itofix(x: Rnd3()); |
| 438 | const auto r2 = itofix(x: Rnd3()); |
| 439 | const auto r1 = Random(iRange: 360); |
| 440 | if (pNew = Game.CreateObject(type: ObjComponents.GetID(index: cnt), |
| 441 | pCreator: pObj, |
| 442 | owner: pObj->Owner, |
| 443 | x: pObj->x, y: pObj->y, |
| 444 | r: r1, xdir: r2, ydir: r3, rdir: r4)) |
| 445 | { |
| 446 | if (pObj->GetOnFire()) pNew->Incinerate(iCausedBy: pObj->Owner); |
| 447 | if (pContainer) pNew->Enter(pTarget: pContainer); |
| 448 | } |
| 449 | } |
| 450 | } |
| 451 | pObj->AssignRemoval(); |
| 452 | return true; |
| 453 | } |
| 454 | |
| 455 | static bool FnRemoveObject(C4AulContext *cthr, C4Object *pObj, bool fEjectContents) |
| 456 | { |
| 457 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 458 | pObj->AssignRemoval(fExitContents: fEjectContents); |
| 459 | return true; |
| 460 | } |
| 461 | |
| 462 | static bool FnSetPosition(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4Object *pObj, bool fCheckBounds) |
| 463 | { |
| 464 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 465 | |
| 466 | if (fCheckBounds) |
| 467 | { |
| 468 | // BoundsCheck takes ref to int32_t and not to C4ValueInt |
| 469 | int32_t i_x = iX, i_y = iY; |
| 470 | pObj->BoundsCheck(ctcox&: i_x, ctcoy&: i_y); |
| 471 | iX = i_x; iY = i_y; |
| 472 | } |
| 473 | pObj->ForcePosition(tx: iX, ty: iY); |
| 474 | // update liquid |
| 475 | pObj->UpdateInLiquid(); |
| 476 | return true; |
| 477 | } |
| 478 | |
| 479 | static bool FnDoCon(C4AulContext *cthr, C4ValueInt iChange, C4Object *pObj) // in percent |
| 480 | { |
| 481 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 482 | pObj->DoCon(iChange: FullCon * iChange / 100); |
| 483 | return true; |
| 484 | } |
| 485 | |
| 486 | static C4ValueInt FnGetCon(C4AulContext *cthr, C4Object *pObj) // in percent |
| 487 | { |
| 488 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 489 | return 100 * pObj->GetCon() / FullCon; |
| 490 | } |
| 491 | |
| 492 | static bool FnDoEnergy(C4AulContext *cthr, C4ValueInt iChange, C4Object *pObj, bool fExact, C4ValueInt iEngType, C4ValueInt iCausedByPlusOne) |
| 493 | { |
| 494 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 495 | if (!iEngType) iEngType = C4FxCall_EngScript; |
| 496 | C4ValueInt iCausedBy = iCausedByPlusOne - 1; if (!iCausedByPlusOne && cthr->Obj) iCausedBy = cthr->Obj->Controller; |
| 497 | pObj->DoEnergy(iChange, fExact: !!fExact, iCause: iEngType, iCausedByPlr: iCausedBy); |
| 498 | return true; |
| 499 | } |
| 500 | |
| 501 | static bool FnDoBreath(C4AulContext *cthr, C4ValueInt iChange, C4Object *pObj) |
| 502 | { |
| 503 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 504 | pObj->DoBreath(iChange); |
| 505 | return true; |
| 506 | } |
| 507 | |
| 508 | static bool FnDoDamage(C4AulContext *cthr, C4ValueInt iChange, C4Object *pObj, C4ValueInt iDmgType, C4ValueInt iCausedByPlusOne) |
| 509 | { |
| 510 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 511 | C4ValueInt iCausedBy = iCausedByPlusOne - 1; if (!iCausedByPlusOne && cthr->Obj) iCausedBy = cthr->Obj->Controller; |
| 512 | if (!iDmgType) iDmgType = C4FxCall_DmgScript; |
| 513 | pObj->DoDamage(iLevel: iChange, iCausedByPlr: iCausedBy, iCause: iDmgType); |
| 514 | return true; |
| 515 | } |
| 516 | |
| 517 | static bool FnDoMagicEnergy(C4AulContext *cthr, C4ValueInt iChange, C4Object *pObj, bool fAllowPartial) |
| 518 | { |
| 519 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 520 | // Physical modification factor |
| 521 | iChange *= MagicPhysicalFactor; |
| 522 | // Maximum load |
| 523 | if (iChange > 0) |
| 524 | if (pObj->MagicEnergy + iChange > pObj->GetPhysical()->Magic) |
| 525 | { |
| 526 | if (!fAllowPartial) return false; |
| 527 | iChange = pObj->GetPhysical()->Magic - pObj->MagicEnergy; |
| 528 | if (!iChange) return false; |
| 529 | // partial change to max allowed |
| 530 | } |
| 531 | // Insufficient load |
| 532 | if (iChange < 0) |
| 533 | if (pObj->MagicEnergy + iChange < 0) |
| 534 | { |
| 535 | if (!fAllowPartial) return false; |
| 536 | iChange = -pObj->MagicEnergy; |
| 537 | if (!iChange) return false; |
| 538 | // partial change to zero allowed |
| 539 | } |
| 540 | // Change energy level |
| 541 | pObj->MagicEnergy = BoundBy<C4ValueInt>(bval: pObj->MagicEnergy + iChange, lbound: 0, rbound: pObj->GetPhysical()->Magic); |
| 542 | pObj->ViewEnergy = C4ViewDelay; |
| 543 | return true; |
| 544 | } |
| 545 | |
| 546 | static C4ValueInt FnGetMagicEnergy(C4AulContext *cthr, C4Object *pObj) |
| 547 | { |
| 548 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 549 | return pObj->MagicEnergy / MagicPhysicalFactor; |
| 550 | } |
| 551 | |
| 552 | const int32_t PHYS_Current = 0, |
| 553 | PHYS_Permanent = 1, |
| 554 | PHYS_Temporary = 2, |
| 555 | PHYS_StackTemporary = 3; |
| 556 | |
| 557 | static bool FnSetPhysical(C4AulContext *cthr, C4String *szPhysical, C4ValueInt iValue, C4ValueInt iMode, C4Object *pObj) |
| 558 | { |
| 559 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 560 | // Get physical offset |
| 561 | C4PhysicalInfo::Offset off; |
| 562 | if (!C4PhysicalInfo::GetOffsetByName(szPhysicalName: FnStringPar(pString: szPhysical), pmpiOut: &off)) return false; |
| 563 | // Set by mode |
| 564 | switch (iMode) |
| 565 | { |
| 566 | // Currently active physical |
| 567 | case PHYS_Current: |
| 568 | // Info objects or temporary mode only |
| 569 | if (!pObj->PhysicalTemporary) if (!pObj->Info || Game.Parameters.UseFairCrew) return false; |
| 570 | // Set physical |
| 571 | pObj->GetPhysical()->*off = iValue; |
| 572 | return true; |
| 573 | // Permanent physical |
| 574 | case PHYS_Permanent: |
| 575 | // Info objects only |
| 576 | if (!pObj->Info) return false; |
| 577 | // In fair crew mode, changing the permanent physicals is only allowed via TrainPhysical |
| 578 | // Otherwise, stuff like SetPhysical(..., GetPhysical(...)+1, ...) would screw up the crew in fair crew mode |
| 579 | if (Game.Parameters.UseFairCrew) return false; |
| 580 | // Set physical |
| 581 | pObj->Info->Physical.*off = iValue; |
| 582 | return true; |
| 583 | // Temporary physical |
| 584 | case PHYS_Temporary: |
| 585 | case PHYS_StackTemporary: |
| 586 | // Automatically switch to temporary mode |
| 587 | if (!pObj->PhysicalTemporary) |
| 588 | { |
| 589 | pObj->TemporaryPhysical = *(pObj->GetPhysical()); |
| 590 | pObj->PhysicalTemporary = true; |
| 591 | } |
| 592 | // if old value is to be remembered, register the change |
| 593 | if (iMode == PHYS_StackTemporary) |
| 594 | pObj->TemporaryPhysical.RegisterChange(mpiOffset: off); |
| 595 | // Set physical |
| 596 | pObj->TemporaryPhysical.*off = iValue; |
| 597 | return true; |
| 598 | } |
| 599 | // Invalid mode |
| 600 | return false; |
| 601 | } |
| 602 | |
| 603 | static bool FnTrainPhysical(C4AulContext *cthr, C4String *szPhysical, C4ValueInt iTrainBy, C4ValueInt iMaxTrain, C4Object *pObj) |
| 604 | { |
| 605 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 606 | // Get physical offset |
| 607 | C4PhysicalInfo::Offset off; |
| 608 | if (!C4PhysicalInfo::GetOffsetByName(szPhysicalName: FnStringPar(pString: szPhysical), pmpiOut: &off)) return false; |
| 609 | // train it |
| 610 | return !!pObj->TrainPhysical(mpiOffset: off, iTrainBy, iMaxTrain); |
| 611 | } |
| 612 | |
| 613 | static bool FnResetPhysical(C4AulContext *cthr, C4Object *pObj, C4String *sPhysical) |
| 614 | { |
| 615 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 616 | const char *szPhysical = FnStringPar(pString: sPhysical); |
| 617 | |
| 618 | // Reset to permanent physical |
| 619 | if (!pObj->PhysicalTemporary) return false; |
| 620 | |
| 621 | // reset specified physical only? |
| 622 | if (szPhysical && *szPhysical) |
| 623 | { |
| 624 | C4PhysicalInfo::Offset off; |
| 625 | if (!C4PhysicalInfo::GetOffsetByName(szPhysicalName: szPhysical, pmpiOut: &off)) return false; |
| 626 | if (!pObj->TemporaryPhysical.ResetPhysical(mpiOffset: off)) return false; |
| 627 | // if other physical changes remain, do not reset complete physicals |
| 628 | if (pObj->TemporaryPhysical.HasChanges(pRefPhysical: pObj->GetPhysical(fPermanent: true))) return true; |
| 629 | } |
| 630 | |
| 631 | // actual reset of temp physicals |
| 632 | pObj->PhysicalTemporary = false; |
| 633 | pObj->TemporaryPhysical.Default(); |
| 634 | |
| 635 | return true; |
| 636 | } |
| 637 | |
| 638 | static std::optional<C4ValueInt> FnGetPhysical(C4AulContext *cthr, C4String *szPhysical, C4ValueInt iMode, C4Object *pObj, C4ID idDef) |
| 639 | { |
| 640 | // Get physical offset |
| 641 | C4PhysicalInfo::Offset off; |
| 642 | if (!C4PhysicalInfo::GetOffsetByName(szPhysicalName: FnStringPar(pString: szPhysical), pmpiOut: &off)) return {}; |
| 643 | // no object given? |
| 644 | if (!pObj) |
| 645 | { |
| 646 | // def given? |
| 647 | if (idDef) |
| 648 | { |
| 649 | // get def |
| 650 | C4Def *pDef = Game.Defs.ID2Def(id: idDef); if (!pDef) return {}; |
| 651 | // return physical value |
| 652 | return {pDef->Physical.*off}; |
| 653 | } |
| 654 | // local call? |
| 655 | pObj = cthr->Obj; if (!pObj) return {}; |
| 656 | } |
| 657 | |
| 658 | // Get by mode |
| 659 | switch (iMode) |
| 660 | { |
| 661 | // Currently active physical |
| 662 | case PHYS_Current: |
| 663 | // Get physical |
| 664 | return {pObj->GetPhysical()->*off}; |
| 665 | // Permanent physical |
| 666 | case PHYS_Permanent: |
| 667 | // Info objects only |
| 668 | if (!pObj->Info) return {}; |
| 669 | // In fair crew mode, scripts may not read permanent physical values - fallback to fair def physical instead! |
| 670 | if (Game.Parameters.UseFairCrew) |
| 671 | if (pObj->Info->pDef) |
| 672 | return {pObj->Info->pDef->GetFairCrewPhysicals()->*off}; |
| 673 | else |
| 674 | return {pObj->Def->GetFairCrewPhysicals()->*off}; |
| 675 | // Get physical |
| 676 | return {pObj->Info->Physical.*off}; |
| 677 | // Temporary physical |
| 678 | case PHYS_Temporary: |
| 679 | // Info objects only |
| 680 | if (!pObj->Info) return {}; |
| 681 | // Only if in temporary mode |
| 682 | if (!pObj->PhysicalTemporary) return {}; |
| 683 | // Get physical |
| 684 | return {pObj->TemporaryPhysical.*off}; |
| 685 | } |
| 686 | // Invalid mode |
| 687 | return {}; |
| 688 | } |
| 689 | |
| 690 | static bool FnSetEntrance(C4AulContext *cthr, bool enabled, C4Object *pObj) |
| 691 | { |
| 692 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 693 | pObj->EntranceStatus = enabled; |
| 694 | return true; |
| 695 | } |
| 696 | |
| 697 | static bool FnSetXDir(C4AulContext *cthr, C4ValueInt nxdir, C4Object *pObj, C4ValueInt iPrec) |
| 698 | { |
| 699 | // safety |
| 700 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 701 | // precision (default 10.0) |
| 702 | if (!iPrec) iPrec = 10; |
| 703 | // update xdir |
| 704 | pObj->xdir = itofix(x: nxdir, prec: iPrec); |
| 705 | pObj->Mobile = 1; |
| 706 | // success |
| 707 | return true; |
| 708 | } |
| 709 | |
| 710 | static bool FnSetRDir(C4AulContext *cthr, C4ValueInt nrdir, C4Object *pObj, C4ValueInt iPrec) |
| 711 | { |
| 712 | // safety |
| 713 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 714 | // precision (default 10.0) |
| 715 | if (!iPrec) iPrec = 10; |
| 716 | // update rdir |
| 717 | pObj->rdir = itofix(x: nrdir, prec: iPrec); |
| 718 | pObj->Mobile = 1; |
| 719 | // success |
| 720 | return true; |
| 721 | } |
| 722 | |
| 723 | static bool FnSetYDir(C4AulContext *cthr, C4ValueInt nydir, C4Object *pObj, C4ValueInt iPrec) |
| 724 | { |
| 725 | // safety |
| 726 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 727 | // precision (default 10.0) |
| 728 | if (!iPrec) iPrec = 10; |
| 729 | // update ydir |
| 730 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 731 | pObj->ydir = itofix(x: nydir, prec: iPrec); |
| 732 | pObj->Mobile = 1; |
| 733 | // success |
| 734 | return true; |
| 735 | } |
| 736 | |
| 737 | static bool FnSetR(C4AulContext *cthr, C4ValueInt nr, C4Object *pObj) |
| 738 | { |
| 739 | // safety |
| 740 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 741 | // set rotation |
| 742 | pObj->SetRotation(nr); |
| 743 | // success |
| 744 | return true; |
| 745 | } |
| 746 | |
| 747 | static bool FnSetAction(C4AulContext *cthr, C4String *szAction, |
| 748 | C4Object *pTarget, C4Object *pTarget2, bool fDirect) |
| 749 | { |
| 750 | if (!cthr->Obj) return false; |
| 751 | if (!szAction) return false; |
| 752 | return !!cthr->Obj->SetActionByName(szActName: FnStringPar(pString: szAction), pTarget, pTarget2, |
| 753 | iCalls: C4Object::SAC_StartCall | C4Object::SAC_AbortCall, fForce: !!fDirect); |
| 754 | } |
| 755 | |
| 756 | static bool FnSetBridgeActionData(C4AulContext *cthr, C4ValueInt iBridgeLength, bool fMoveClonk, bool fWall, C4ValueInt iBridgeMaterial, C4Object *pObj) |
| 757 | { |
| 758 | if (!pObj) pObj = cthr->Obj; if (!pObj || !pObj->Status) return false; |
| 759 | // action must be BRIDGE |
| 760 | if (pObj->Action.Act <= ActIdle) return false; |
| 761 | if (pObj->Def->ActMap[pObj->Action.Act].Procedure != DFA_BRIDGE) return false; |
| 762 | // set data |
| 763 | pObj->Action.SetBridgeData(iBridgeTime: iBridgeLength, fMoveClonk, fWall, iBridgeMaterial); |
| 764 | return true; |
| 765 | } |
| 766 | |
| 767 | static bool FnSetActionData(C4AulContext *cthr, C4ValueInt iData, C4Object *pObj) |
| 768 | { |
| 769 | if (!pObj) pObj = cthr->Obj; if (!pObj || !pObj->Status) return false; |
| 770 | // bridge: Convert from old style |
| 771 | if ((pObj->Action.Act > ActIdle) && (pObj->Def->ActMap[pObj->Action.Act].Procedure == DFA_BRIDGE)) |
| 772 | return FnSetBridgeActionData(cthr, iBridgeLength: 0, fMoveClonk: false, fWall: false, iBridgeMaterial: iData, pObj); |
| 773 | // attach: check for valid vertex indices |
| 774 | if ((pObj->Action.Act > ActIdle) && (pObj->Def->ActMap[pObj->Action.Act].Procedure == DFA_ATTACH)) // Fixed Action.Act check here... matthes |
| 775 | if (((iData & 255) >= C4D_MaxVertex) || ((iData >> 8) >= C4D_MaxVertex)) |
| 776 | return false; |
| 777 | // set data |
| 778 | pObj->Action.Data = iData; |
| 779 | return true; |
| 780 | } |
| 781 | |
| 782 | static bool FnObjectSetAction(C4AulContext *cthr, C4Object *pObj, C4String *szAction, |
| 783 | C4Object *pTarget, C4Object *pTarget2, bool fDirect) |
| 784 | { |
| 785 | if (!szAction || !pObj) return false; |
| 786 | // regular action change |
| 787 | return !!pObj->SetActionByName(szActName: FnStringPar(pString: szAction), pTarget, pTarget2, |
| 788 | iCalls: C4Object::SAC_StartCall | C4Object::SAC_AbortCall, fForce: !!fDirect); |
| 789 | } |
| 790 | |
| 791 | static bool FnSetComDir(C4AulContext *cthr, C4ValueInt ncomdir, C4Object *pObj) |
| 792 | { |
| 793 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 794 | pObj->Action.ComDir = ncomdir; |
| 795 | return true; |
| 796 | } |
| 797 | |
| 798 | static bool FnSetDir(C4AulContext *cthr, C4ValueInt ndir, C4Object *pObj) |
| 799 | { |
| 800 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 801 | pObj->SetDir(ndir); |
| 802 | return true; |
| 803 | } |
| 804 | |
| 805 | static bool FnSetCategory(C4AulContext *cthr, C4ValueInt iCategory, C4Object *pObj) |
| 806 | { |
| 807 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 808 | if (!(iCategory & C4D_SortLimit)) iCategory |= (pObj->Category & C4D_SortLimit); |
| 809 | pObj->SetCategory(iCategory); |
| 810 | return true; |
| 811 | } |
| 812 | |
| 813 | static bool FnSetAlive(C4AulContext *cthr, bool nalv, C4Object *pObj) |
| 814 | { |
| 815 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 816 | pObj->SetAlive(nalv); |
| 817 | return true; |
| 818 | } |
| 819 | |
| 820 | static bool FnSetOwner(C4AulContext *cthr, C4ValueInt iOwner, C4Object *pObj) |
| 821 | { |
| 822 | // Object safety |
| 823 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 824 | // Set owner |
| 825 | return !!pObj->SetOwner(iOwner); |
| 826 | } |
| 827 | |
| 828 | static bool FnSetPhase(C4AulContext *cthr, C4ValueInt iVal, C4Object *pObj) |
| 829 | { |
| 830 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 831 | return !!pObj->SetPhase(iVal); |
| 832 | } |
| 833 | |
| 834 | static bool FnExecuteCommand(C4AulContext *cthr, C4Object *pObj) |
| 835 | { |
| 836 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 837 | return !!pObj->ExecuteCommand(); |
| 838 | } |
| 839 | |
| 840 | static bool FnSetCommand(C4AulContext *cthr, C4Object *pObj, C4String *szCommand, C4Object *pTarget, C4Value Tx, C4ValueInt iTy, C4Object *pTarget2, C4Value data, C4ValueInt iRetries) |
| 841 | { |
| 842 | // Object |
| 843 | if (!pObj) pObj = cthr->Obj; |
| 844 | if (!pObj || !szCommand) return false; |
| 845 | // Command |
| 846 | C4ValueInt iCommand = CommandByName(szCommand: FnStringPar(pString: szCommand)); |
| 847 | if (!iCommand) |
| 848 | { |
| 849 | pObj->ClearCommands(); |
| 850 | return false; |
| 851 | } |
| 852 | // Special: convert iData to szText |
| 853 | const char *szText = nullptr; |
| 854 | int32_t iData = 0; |
| 855 | if (iCommand == C4CMD_Call) |
| 856 | { |
| 857 | szText = FnStringPar(pString: data.getStr()); |
| 858 | } |
| 859 | else |
| 860 | { |
| 861 | iData = data.getIntOrID(); |
| 862 | Tx.ConvertTo(vtToType: C4V_Int); |
| 863 | } |
| 864 | // Set |
| 865 | pObj->SetCommand(iCommand, pTarget, iTx: Tx, iTy, pTarget2, fControl: false, iData, iRetries, szText); |
| 866 | // Success |
| 867 | return true; |
| 868 | } |
| 869 | |
| 870 | static bool FnAddCommand(C4AulContext *cthr, C4Object *pObj, C4String *szCommand, C4Object *pTarget, C4Value Tx, C4ValueInt iTy, C4Object *pTarget2, C4ValueInt iUpdateInterval, C4Value data, C4ValueInt iRetries, C4ValueInt iBaseMode) |
| 871 | { |
| 872 | // Object |
| 873 | if (!pObj) pObj = cthr->Obj; |
| 874 | if (!pObj || !szCommand) return false; |
| 875 | // Command |
| 876 | C4ValueInt iCommand = CommandByName(szCommand: FnStringPar(pString: szCommand)); |
| 877 | if (!iCommand) return false; |
| 878 | // Special: convert iData to szText |
| 879 | const char *szText = nullptr; |
| 880 | int32_t iData = 0; |
| 881 | if (iCommand == C4CMD_Call) |
| 882 | { |
| 883 | szText = FnStringPar(pString: data.getStr()); |
| 884 | } |
| 885 | else |
| 886 | { |
| 887 | iData = data.getIntOrID(); |
| 888 | Tx.ConvertTo(vtToType: C4V_Int); |
| 889 | } |
| 890 | // Add |
| 891 | return pObj->AddCommand(iCommand, pTarget, iTx: Tx, iTy, iUpdateInterval, pTarget2, fInitEvaluation: true, iData, fAppend: false, iRetries, szText, iBaseMode); |
| 892 | } |
| 893 | |
| 894 | static bool FnAppendCommand(C4AulContext *cthr, C4Object *pObj, C4String *szCommand, C4Object *pTarget, C4Value Tx, C4ValueInt iTy, C4Object *pTarget2, C4ValueInt iUpdateInterval, C4Value Data, C4ValueInt iRetries, C4ValueInt iBaseMode) |
| 895 | { |
| 896 | // Object |
| 897 | if (!pObj) pObj = cthr->Obj; |
| 898 | if (!pObj || !szCommand) return false; |
| 899 | // Command |
| 900 | C4ValueInt iCommand = CommandByName(szCommand: FnStringPar(pString: szCommand)); |
| 901 | if (!iCommand) return false; |
| 902 | // Special: convert iData to szText |
| 903 | const char *szText = nullptr; |
| 904 | int32_t iData = 0; |
| 905 | if (iCommand == C4CMD_Call) |
| 906 | { |
| 907 | szText = FnStringPar(pString: Data.getStr()); |
| 908 | } |
| 909 | else |
| 910 | { |
| 911 | iData = Data.getIntOrID(); |
| 912 | Tx.ConvertTo(vtToType: C4V_Int); |
| 913 | } |
| 914 | // Add |
| 915 | return pObj->AddCommand(iCommand, pTarget, iTx: Tx, iTy, iUpdateInterval, pTarget2, fInitEvaluation: true, iData, fAppend: true, iRetries, szText, iBaseMode); |
| 916 | } |
| 917 | |
| 918 | static C4Value FnGetCommand(C4AulContext *cthr, C4Object *pObj, C4ValueInt iElement, C4ValueInt iCommandNum) |
| 919 | { |
| 920 | if (!pObj) pObj = cthr->Obj; |
| 921 | if (!pObj) return C4VNull; |
| 922 | C4Command *Command = pObj->Command; |
| 923 | // Move through list to Command iCommandNum |
| 924 | while (Command && iCommandNum--) Command = Command->Next; |
| 925 | // Object has no command or iCommandNum was to high or < 0 |
| 926 | if (!Command) return C4VNull; |
| 927 | // Return command element |
| 928 | switch (iElement) |
| 929 | { |
| 930 | case 0: // Name |
| 931 | return C4VString(strString: CommandName(iCommand: Command->Command)); |
| 932 | case 1: // Target |
| 933 | return C4VObj(pObj: Command->Target); |
| 934 | case 2: // Tx |
| 935 | return Command->Tx; |
| 936 | case 3: // Ty |
| 937 | return C4VInt(iVal: Command->Ty); |
| 938 | case 4: // Target2 |
| 939 | return C4VObj(pObj: Command->Target2); |
| 940 | case 5: // Data |
| 941 | return C4Value(Command->Data, C4V_Any); |
| 942 | } |
| 943 | // Undefined element |
| 944 | return C4VNull; |
| 945 | } |
| 946 | |
| 947 | static bool FnFinishCommand(C4AulContext *cthr, C4Object *pObj, bool fSuccess, C4ValueInt iCommandNum) |
| 948 | { |
| 949 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 950 | C4Command *Command = pObj->Command; |
| 951 | // Move through list to Command iCommandNum |
| 952 | while (Command && iCommandNum--) Command = Command->Next; |
| 953 | // Object has no command or iCommandNum was to high or < 0 |
| 954 | if (!Command) return false; |
| 955 | if (!fSuccess) ++(Command->Failures); |
| 956 | else Command->Finished = true; |
| 957 | return true; |
| 958 | } |
| 959 | |
| 960 | static bool FnPlayerObjectCommand(C4AulContext *cthr, C4ValueInt iPlr, C4String *szCommand, C4Object *pTarget, C4Value Tx, C4ValueInt iTy, C4Object *pTarget2, C4Value data) |
| 961 | { |
| 962 | // Player |
| 963 | if (!ValidPlr(plr: iPlr) || !szCommand) return false; |
| 964 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 965 | // Command |
| 966 | C4ValueInt iCommand = CommandByName(szCommand: FnStringPar(pString: szCommand)); |
| 967 | if (!iCommand) return false; |
| 968 | |
| 969 | std::int32_t iData{0}; |
| 970 | const std::int32_t iTx{Tx.getInt()}; |
| 971 | if (iCommand == C4CMD_Call) |
| 972 | { |
| 973 | StrictError(context: cthr, errorSince: C4AulScriptStrict::STRICT3, message: "PlayerObjectCommand: Command \"Call\" not supported" ); |
| 974 | } |
| 975 | else |
| 976 | { |
| 977 | iData = data.getIntOrID(); |
| 978 | } |
| 979 | // Set |
| 980 | pPlr->ObjectCommand(iCommand, pTarget, iTx, iTy, pTarget2, iData, iAddMode: C4P_Command_Set); |
| 981 | // Success |
| 982 | return true; |
| 983 | } |
| 984 | |
| 985 | static C4String *FnGetAction(C4AulContext *cthr, C4Object *pObj) |
| 986 | { |
| 987 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 988 | if (pObj->Action.Act <= ActIdle) return String(str: "Idle" ); |
| 989 | return String(str: pObj->Def->ActMap[pObj->Action.Act].Name); |
| 990 | } |
| 991 | |
| 992 | static C4String *FnGetName(C4AulContext *cthr, C4Object *pObj, C4ID idDef) |
| 993 | { |
| 994 | // Def name |
| 995 | C4Def *pDef; |
| 996 | if (idDef) |
| 997 | { |
| 998 | pDef = C4Id2Def(id: idDef); |
| 999 | if (pDef) return String(str: pDef->GetName()); |
| 1000 | return nullptr; |
| 1001 | } |
| 1002 | // Object name |
| 1003 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1004 | return String(str: pObj->GetName()); |
| 1005 | } |
| 1006 | |
| 1007 | static bool FnSetName(C4AulContext *cthr, C4String *pNewName, C4Object *pObj, C4ID idDef, bool fSetInInfo, bool fMakeValidIfExists) |
| 1008 | { |
| 1009 | // safety |
| 1010 | if (fSetInInfo && idDef) return false; |
| 1011 | |
| 1012 | // Def name |
| 1013 | C4Def *pDef; |
| 1014 | |
| 1015 | if (idDef) |
| 1016 | if (pDef = C4Id2Def(id: idDef)) |
| 1017 | pDef->Name.Copy(pnData: FnStringPar(pString: pNewName)); |
| 1018 | else |
| 1019 | return false; |
| 1020 | else |
| 1021 | { |
| 1022 | // Object name |
| 1023 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1024 | if (fSetInInfo) |
| 1025 | { |
| 1026 | // setting name in info |
| 1027 | C4ObjectInfo *pInfo = pObj->Info; |
| 1028 | if (!pInfo) return false; |
| 1029 | const char *szName = pNewName->Data.getData(); |
| 1030 | // empty names are bad; e.g., could cause problems in savegames |
| 1031 | if (!szName || !*szName) return false; |
| 1032 | // name must not be too C4ValueInt |
| 1033 | if (SLen(sptr: szName) > C4MaxName) return false; |
| 1034 | // any change at all? |
| 1035 | if (SEqual(szStr1: szName, szStr2: pInfo->Name)) return true; |
| 1036 | // make sure names in info list aren't duplicated |
| 1037 | // querying owner info list here isn't 100% accurate, as infos might have been stolen by other players |
| 1038 | // however, there is no good way to track the original list ATM |
| 1039 | C4ObjectInfoList *pInfoList = nullptr; |
| 1040 | C4Player *pOwner = Game.Players.Get(iPlayer: pObj->Owner); |
| 1041 | if (pOwner) pInfoList = &pOwner->CrewInfoList; |
| 1042 | char NameBuf[C4MaxName + 1]; |
| 1043 | if (pInfoList) if (pInfoList->NameExists(szName)) |
| 1044 | { |
| 1045 | if (!fMakeValidIfExists) return false; |
| 1046 | SCopy(szSource: szName, sTarget: NameBuf, iMaxL: C4MaxName); |
| 1047 | pInfoList->MakeValidName(sName: NameBuf); |
| 1048 | szName = NameBuf; |
| 1049 | } |
| 1050 | SCopy(szSource: szName, sTarget: pInfo->Name, iMaxL: C4MaxName); |
| 1051 | pObj->SetName(); // make sure object uses info name |
| 1052 | } |
| 1053 | else |
| 1054 | { |
| 1055 | if (!pNewName) pObj->SetName(); |
| 1056 | else pObj->SetName(pNewName->Data.getData()); |
| 1057 | } |
| 1058 | } |
| 1059 | return true; |
| 1060 | } |
| 1061 | |
| 1062 | static C4String *FnGetDesc(C4AulContext *cthr, C4Object *pObj, C4ID idDef) |
| 1063 | { |
| 1064 | C4Def *pDef; |
| 1065 | // find def |
| 1066 | if (!pObj && !idDef) pObj = cthr->Obj; |
| 1067 | if (pObj) |
| 1068 | pDef = pObj->Def; |
| 1069 | else |
| 1070 | pDef = Game.Defs.ID2Def(id: idDef); |
| 1071 | // nothing found? |
| 1072 | if (!pDef) return nullptr; |
| 1073 | // return desc |
| 1074 | return String(str: pDef->GetDesc()); |
| 1075 | } |
| 1076 | |
| 1077 | static C4String *FnGetPlayerName(C4AulContext *cthr, C4ValueInt iPlayer) |
| 1078 | { |
| 1079 | if (!ValidPlr(plr: iPlayer)) return nullptr; |
| 1080 | return String(str: Game.Players.Get(iPlayer)->GetName()); |
| 1081 | } |
| 1082 | |
| 1083 | static C4String *FnGetTaggedPlayerName(C4AulContext *cthr, C4ValueInt iPlayer) |
| 1084 | { |
| 1085 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 1086 | if (!pPlr) return nullptr; |
| 1087 | uint32_t dwClr = pPlr->ColorDw; C4GUI::MakeColorReadableOnBlack(rdwClr&: dwClr); |
| 1088 | static char szFnFormatBuf[1024 + 1]; |
| 1089 | FormatWithNull(buf&: szFnFormatBuf, fmt: "<c {:x}>{}</c>" , args: dwClr & 0xffffff, args: pPlr->GetName()); |
| 1090 | return String(str: szFnFormatBuf); |
| 1091 | } |
| 1092 | |
| 1093 | static std::optional<C4ValueInt> FnGetPlayerType(C4AulContext *cthr, C4ValueInt iPlayer) |
| 1094 | { |
| 1095 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 1096 | if (!pPlr) return {}; |
| 1097 | return {pPlr->GetType()}; |
| 1098 | } |
| 1099 | |
| 1100 | static C4Object *FnGetActionTarget(C4AulContext *cthr, C4ValueInt target_index, C4Object *pObj) |
| 1101 | { |
| 1102 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1103 | if (target_index == 0) return pObj->Action.Target; |
| 1104 | if (target_index == 1) return pObj->Action.Target2; |
| 1105 | return nullptr; |
| 1106 | } |
| 1107 | |
| 1108 | static bool FnSetActionTargets(C4AulContext *cthr, C4Object *pTarget1, C4Object *pTarget2, C4Object *pObj) |
| 1109 | { |
| 1110 | // safety |
| 1111 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1112 | // set targets |
| 1113 | pObj->Action.Target = pTarget1; |
| 1114 | pObj->Action.Target2 = pTarget2; |
| 1115 | return true; |
| 1116 | } |
| 1117 | |
| 1118 | static std::optional<C4ValueInt> FnGetDir(C4AulContext *cthr, C4Object *pObj) |
| 1119 | { |
| 1120 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1121 | return {pObj->Action.Dir}; |
| 1122 | } |
| 1123 | |
| 1124 | static std::optional<C4ValueInt> FnGetEntrance(C4AulContext *cthr, C4Object *pObj) |
| 1125 | { |
| 1126 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1127 | return {pObj->EntranceStatus}; |
| 1128 | } |
| 1129 | |
| 1130 | static std::optional<C4ValueInt> FnGetPhase(C4AulContext *cthr, C4Object *pObj) |
| 1131 | { |
| 1132 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1133 | return {pObj->Action.Phase}; |
| 1134 | } |
| 1135 | |
| 1136 | static std::optional<C4ValueInt> FnGetEnergy(C4AulContext *cthr, C4Object *pObj) |
| 1137 | { |
| 1138 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1139 | return {100 * pObj->Energy / C4MaxPhysical}; |
| 1140 | } |
| 1141 | |
| 1142 | static std::optional<C4ValueInt> FnGetBreath(C4AulContext *cthr, C4Object *pObj) |
| 1143 | { |
| 1144 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1145 | return {100 * pObj->Breath / C4MaxPhysical}; |
| 1146 | } |
| 1147 | |
| 1148 | static std::optional<C4ValueInt> FnGetMass(C4AulContext *cthr, C4Object *pObj, C4ID idDef) |
| 1149 | { |
| 1150 | if (idDef) |
| 1151 | { |
| 1152 | C4Def *pDef = Game.Defs.ID2Def(id: idDef); |
| 1153 | if (!pDef) return {}; |
| 1154 | return pDef->Mass; |
| 1155 | } |
| 1156 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1157 | return {pObj->Mass}; |
| 1158 | } |
| 1159 | |
| 1160 | static std::optional<C4ValueInt> FnGetRDir(C4AulContext *cthr, C4Object *pObj, C4ValueInt iPrec) |
| 1161 | { |
| 1162 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1163 | if (!iPrec) iPrec = 10; |
| 1164 | return {fixtoi(x: pObj->rdir, prec: iPrec)}; |
| 1165 | } |
| 1166 | |
| 1167 | static std::optional<C4ValueInt> FnGetXDir(C4AulContext *cthr, C4Object *pObj, C4ValueInt iPrec) |
| 1168 | { |
| 1169 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1170 | if (!iPrec) iPrec = 10; |
| 1171 | return {fixtoi(x: pObj->xdir, prec: iPrec)}; |
| 1172 | } |
| 1173 | |
| 1174 | static std::optional<C4ValueInt> FnGetYDir(C4AulContext *cthr, C4Object *pObj, C4ValueInt iPrec) |
| 1175 | { |
| 1176 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1177 | if (!iPrec) iPrec = 10; |
| 1178 | return {fixtoi(x: pObj->ydir, prec: iPrec)}; |
| 1179 | } |
| 1180 | |
| 1181 | static std::optional<C4ValueInt> FnGetR(C4AulContext *cthr, C4Object *pObj) |
| 1182 | { |
| 1183 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1184 | // Adjust range |
| 1185 | C4ValueInt iR = pObj->r; |
| 1186 | while (iR > 180) iR -= 360; |
| 1187 | while (iR < -180) iR += 360; |
| 1188 | return {iR}; |
| 1189 | } |
| 1190 | |
| 1191 | static std::optional<C4ValueInt> FnGetComDir(C4AulContext *cthr, C4Object *pObj) |
| 1192 | { |
| 1193 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1194 | return {pObj->Action.ComDir}; |
| 1195 | } |
| 1196 | |
| 1197 | static std::optional<C4ValueInt> FnGetX(C4AulContext *cthr, C4Object *pObj) |
| 1198 | { |
| 1199 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1200 | return {pObj->x}; |
| 1201 | } |
| 1202 | |
| 1203 | static std::optional<C4ValueInt> FnGetVertexNum(C4AulContext *cthr, C4Object *pObj) |
| 1204 | { |
| 1205 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1206 | return {pObj->Shape.VtxNum}; |
| 1207 | } |
| 1208 | |
| 1209 | static const C4ValueInt VTX_X = 0, // vertex data indices |
| 1210 | VTX_Y = 1, |
| 1211 | VTX_CNAT = 2, |
| 1212 | VTX_Friction = 3, |
| 1213 | VTX_SetPermanent = 1, |
| 1214 | VTX_SetPermanentUpd = 2; |
| 1215 | |
| 1216 | static std::optional<C4ValueInt> FnGetVertex(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt iValueToGet, C4Object *pObj) |
| 1217 | { |
| 1218 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1219 | if (pObj->Shape.VtxNum < 1) return {}; |
| 1220 | iIndex = std::min<C4ValueInt>(a: iIndex, b: pObj->Shape.VtxNum - 1); |
| 1221 | switch (iValueToGet) |
| 1222 | { |
| 1223 | case VTX_X: return {pObj->Shape.VtxX[iIndex]}; break; |
| 1224 | case VTX_Y: return {pObj->Shape.VtxY[iIndex]}; break; |
| 1225 | case VTX_CNAT: return {pObj->Shape.VtxCNAT[iIndex]}; break; |
| 1226 | case VTX_Friction: return {pObj->Shape.VtxFriction[iIndex]}; break; |
| 1227 | default: |
| 1228 | // old-style behaviour for any value != 0 (normally not used) |
| 1229 | DebugLog(fmt: "GetVertex: Unknown vertex attribute: {}; getting VtxY" , args&: iValueToGet); |
| 1230 | return {pObj->Shape.VtxY[iIndex]}; |
| 1231 | break; |
| 1232 | } |
| 1233 | // impossible mayhem! |
| 1234 | return {}; |
| 1235 | } |
| 1236 | |
| 1237 | static bool FnSetVertex(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt iValueToSet, C4ValueInt iValue, C4Object *pObj, C4ValueInt iOwnVertexMode) |
| 1238 | { |
| 1239 | // local call / safety |
| 1240 | if (!pObj) pObj = cthr->Obj; if (!pObj || !pObj->Status) return false; |
| 1241 | // own vertex mode? |
| 1242 | if (iOwnVertexMode) |
| 1243 | { |
| 1244 | // enter own custom vertex mode if not already set |
| 1245 | if (!pObj->fOwnVertices) |
| 1246 | { |
| 1247 | pObj->Shape.CreateOwnOriginalCopy(rFrom&: pObj->Def->Shape); |
| 1248 | pObj->fOwnVertices = 1; |
| 1249 | } |
| 1250 | // set vertices at end of buffer |
| 1251 | iIndex += C4D_VertexCpyPos; |
| 1252 | } |
| 1253 | // range check |
| 1254 | if (!Inside<C4ValueInt>(ival: iIndex, lbound: 0, rbound: C4D_MaxVertex - 1)) return false; |
| 1255 | // set desired value |
| 1256 | switch (iValueToSet) |
| 1257 | { |
| 1258 | case VTX_X: pObj->Shape.VtxX[iIndex] = iValue; break; |
| 1259 | case VTX_Y: pObj->Shape.VtxY[iIndex] = iValue; break; |
| 1260 | case VTX_CNAT: pObj->Shape.VtxCNAT[iIndex] = iValue; break; |
| 1261 | case VTX_Friction: pObj->Shape.VtxFriction[iIndex] = iValue; break; |
| 1262 | default: |
| 1263 | // old-style behaviour for any value != 0 (normally not used) |
| 1264 | pObj->Shape.VtxY[iIndex] = iValue; |
| 1265 | DebugLog(fmt: "SetVertex: Unknown vertex attribute: {}; setting VtxY" , args&: iValueToSet); |
| 1266 | break; |
| 1267 | } |
| 1268 | // vertex update desired? |
| 1269 | if (iOwnVertexMode == VTX_SetPermanentUpd) pObj->UpdateShape(bUpdateVertices: true); |
| 1270 | return true; |
| 1271 | } |
| 1272 | |
| 1273 | static bool FnAddVertex(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4Object *pObj) |
| 1274 | { |
| 1275 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1276 | return !!pObj->Shape.AddVertex(iX, iY); |
| 1277 | } |
| 1278 | |
| 1279 | static bool FnRemoveVertex(C4AulContext *cthr, C4ValueInt iIndex, C4Object *pObj) |
| 1280 | { |
| 1281 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1282 | return !!pObj->Shape.RemoveVertex(iPos: iIndex); |
| 1283 | } |
| 1284 | |
| 1285 | static bool FnSetContactDensity(C4AulContext *cthr, C4ValueInt iDensity, C4Object *pObj) |
| 1286 | { |
| 1287 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1288 | pObj->Shape.ContactDensity = iDensity; |
| 1289 | return true; |
| 1290 | } |
| 1291 | |
| 1292 | static std::optional<C4ValueInt> FnGetY(C4AulContext *cthr, C4Object *pObj) |
| 1293 | { |
| 1294 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1295 | return {pObj->y}; |
| 1296 | } |
| 1297 | |
| 1298 | static std::optional<C4ValueInt> FnGetAlive(C4AulContext *cthr, C4Object *pObj) |
| 1299 | { |
| 1300 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1301 | return pObj->GetAlive(); |
| 1302 | } |
| 1303 | |
| 1304 | static C4ValueInt FnGetOwner(C4AulContext *cthr, C4Object *pObj) |
| 1305 | { |
| 1306 | if (!pObj) pObj = cthr->Obj; if (!pObj) return NO_OWNER; |
| 1307 | return pObj->Owner; |
| 1308 | } |
| 1309 | |
| 1310 | static std::optional<C4ValueInt> FnCrewMember(C4AulContext *cthr, C4Object *pObj) |
| 1311 | { |
| 1312 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1313 | return pObj->Def->CrewMember; |
| 1314 | } |
| 1315 | |
| 1316 | static C4ValueInt FnGetController(C4AulContext *cthr, C4Object *pObj) |
| 1317 | { |
| 1318 | if (!pObj) pObj = cthr->Obj; if (!pObj) return NO_OWNER; |
| 1319 | return pObj->Controller; |
| 1320 | } |
| 1321 | |
| 1322 | static bool FnSetController(C4AulContext *cthr, C4ValueInt iNewController, C4Object *pObj) |
| 1323 | { |
| 1324 | // validate player |
| 1325 | if (iNewController != NO_OWNER && !ValidPlr(plr: iNewController)) return false; |
| 1326 | // Object safety |
| 1327 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1328 | // Set controller |
| 1329 | pObj->Controller = iNewController; |
| 1330 | return true; |
| 1331 | } |
| 1332 | |
| 1333 | static C4ValueInt FnGetKiller(C4AulContext *cthr, C4Object *pObj) |
| 1334 | { |
| 1335 | if (!pObj) pObj = cthr->Obj; if (!pObj) return NO_OWNER; |
| 1336 | return pObj->LastEnergyLossCausePlayer; |
| 1337 | } |
| 1338 | |
| 1339 | static bool FnSetKiller(C4AulContext *cthr, C4ValueInt iNewKiller, C4Object *pObj) |
| 1340 | { |
| 1341 | // validate player |
| 1342 | if (iNewKiller != NO_OWNER && !ValidPlr(plr: iNewKiller)) return false; |
| 1343 | // object safety |
| 1344 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1345 | // set killer as last energy loss cause |
| 1346 | pObj->LastEnergyLossCausePlayer = iNewKiller; |
| 1347 | return true; |
| 1348 | } |
| 1349 | |
| 1350 | static std::optional<C4ValueInt> FnGetCategory(C4AulContext *cthr, C4Object *pObj, C4ID idDef) |
| 1351 | { |
| 1352 | // Def category |
| 1353 | C4Def *pDef; |
| 1354 | if (idDef) if (pDef = C4Id2Def(id: idDef)) return {pDef->Category}; |
| 1355 | // Object category |
| 1356 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1357 | return {pObj->Category}; |
| 1358 | } |
| 1359 | |
| 1360 | static std::optional<C4ValueInt> FnGetOCF(C4AulContext *cthr, C4Object *pObj) |
| 1361 | { |
| 1362 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1363 | return {pObj->OCF}; |
| 1364 | } |
| 1365 | |
| 1366 | static std::optional<C4ValueInt> FnGetDamage(C4AulContext *cthr, C4Object *pObj) |
| 1367 | { |
| 1368 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1369 | return {pObj->Damage}; |
| 1370 | } |
| 1371 | |
| 1372 | static std::optional<C4ValueInt> FnGetValue(C4AulContext *cthr, C4Object *pObj, C4ID idDef, C4Object *pInBase, C4ValueInt iForPlayer) |
| 1373 | { |
| 1374 | // Def value |
| 1375 | C4Def *pDef; |
| 1376 | if (idDef) |
| 1377 | // return Def value or 0 if def unloaded |
| 1378 | if (pDef = C4Id2Def(id: idDef)) return pDef->GetValue(pInBase, iBuyPlayer: iForPlayer); else return {}; |
| 1379 | // Object value |
| 1380 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1381 | return {pObj->GetValue(pInBase, iForPlayer)}; |
| 1382 | } |
| 1383 | |
| 1384 | static std::optional<C4ValueInt> FnGetRank(C4AulContext *cthr, C4Object *pObj) |
| 1385 | { |
| 1386 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1387 | if (!pObj->Info) return {}; |
| 1388 | return {pObj->Info->Rank}; |
| 1389 | } |
| 1390 | |
| 1391 | static std::optional<C4ValueInt> FnValue(C4AulContext *cthr, C4ID id) |
| 1392 | { |
| 1393 | C4Def *pDef = C4Id2Def(id); |
| 1394 | if (pDef) return {pDef->Value}; |
| 1395 | return {}; |
| 1396 | } |
| 1397 | |
| 1398 | static std::optional<C4ValueInt> FnGetActTime(C4AulContext *cthr, C4Object *pObj) |
| 1399 | { |
| 1400 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1401 | return {pObj->Action.Time}; |
| 1402 | } |
| 1403 | |
| 1404 | static C4ID FnGetID(C4AulContext *cthr, C4Object *pObj) |
| 1405 | { |
| 1406 | C4Def *pDef = pObj ? pObj->Def : cthr->Def; |
| 1407 | if (!pDef) return 0; |
| 1408 | // return id of object |
| 1409 | return pDef->id; |
| 1410 | } |
| 1411 | |
| 1412 | static C4ValueInt FnGetBase(C4AulContext *cthr, C4Object *pObj) |
| 1413 | { |
| 1414 | if (!pObj) pObj = cthr->Obj; if (!pObj) return -1; |
| 1415 | return pObj->Base; |
| 1416 | } |
| 1417 | |
| 1418 | static C4ID (C4AulContext *cthr, C4Object *pObj) |
| 1419 | { |
| 1420 | if (!pObj) pObj = cthr->Obj; if (!pObj) return C4ID(-1); |
| 1421 | if (pObj->Menu && pObj->Menu->IsActive()) |
| 1422 | return pObj->Menu->GetIdentification(); |
| 1423 | return C4MN_None; |
| 1424 | } |
| 1425 | |
| 1426 | static bool (C4AulContext *cthr, C4ID iSymbol, C4Object *, C4Object *pCommandObj, |
| 1427 | C4ValueInt , C4String *szCaption, C4ValueInt , |
| 1428 | C4ValueInt iStyle, bool fPermanent, C4ID ) |
| 1429 | { |
| 1430 | if (!pMenuObj) { pMenuObj = cthr->Obj; if (!pMenuObj) return false; } |
| 1431 | if (!pCommandObj) pCommandObj = cthr->Obj; |
| 1432 | if (pCommandObj) |
| 1433 | { |
| 1434 | // object menu: Validate object |
| 1435 | if (!pCommandObj->Status) return false; |
| 1436 | } |
| 1437 | else |
| 1438 | { |
| 1439 | // scenario script callback: No command object OK |
| 1440 | } |
| 1441 | |
| 1442 | // Create symbol |
| 1443 | C4Def *pDef; |
| 1444 | C4FacetExSurface fctSymbol; |
| 1445 | fctSymbol.Create(iWdt: C4SymbolSize, iHgt: C4SymbolSize); |
| 1446 | if (pDef = C4Id2Def(id: iSymbol)) pDef->Draw(cgo&: fctSymbol); |
| 1447 | |
| 1448 | // Clear any old menu, init new menu |
| 1449 | if (!pMenuObj->CloseMenu(fForce: false)) return false; |
| 1450 | if (!pMenuObj->Menu) pMenuObj->Menu = new C4ObjectMenu; else pMenuObj->Menu->ClearItems(fResetSelection: true); |
| 1451 | pMenuObj->Menu->Init(fctSymbol, szEmpty: FnStringPar(pString: szCaption), pObject: pCommandObj, iExtra, iExtraData, iId: idMenuID ? idMenuID : iSymbol, iStyle, fUserMenu: true); |
| 1452 | |
| 1453 | // Set permanent |
| 1454 | pMenuObj->Menu->SetPermanent(fPermanent); |
| 1455 | |
| 1456 | return true; |
| 1457 | } |
| 1458 | |
| 1459 | const C4ValueInt C4MN_Add_ImgRank = 1, |
| 1460 | C4MN_Add_ImgIndexed = 2, |
| 1461 | C4MN_Add_ImgObjRank = 3, |
| 1462 | C4MN_Add_ImgObject = 4, |
| 1463 | C4MN_Add_ImgTextSpec = 5, |
| 1464 | C4MN_Add_ImgColor = 6, |
| 1465 | C4MN_Add_ImgIndexedColor = 7, |
| 1466 | C4MN_Add_MaxImage = 127, // mask for param which decides what to draw as the menu symbol |
| 1467 | C4MN_Add_PassValue = 128, |
| 1468 | C4MN_Add_ForceCount = 256, |
| 1469 | C4MN_Add_ForceNoDesc = 512; |
| 1470 | |
| 1471 | static bool (C4AulContext *cthr, C4String *szCaption, C4String *szCommand, C4ID idItem, C4Object *, C4ValueInt iCount, C4Value Parameter, C4String *szInfoCaption, C4ValueInt , C4Value XPar, C4Value XPar2) |
| 1472 | { |
| 1473 | if (!pMenuObj) pMenuObj = cthr->Obj; |
| 1474 | if (!pMenuObj) return false; |
| 1475 | if (!pMenuObj->Menu) return false; |
| 1476 | |
| 1477 | char caption[256 + 1]; |
| 1478 | char parameter[256 + 1]; |
| 1479 | char dummy[256 + 1]; |
| 1480 | std::string command; |
| 1481 | std::string command2; |
| 1482 | char infocaption[C4MaxTitle + 1]; |
| 1483 | |
| 1484 | // get needed symbol size |
| 1485 | const auto iSymbolSize = pMenuObj->Menu->GetSymbolSize(); |
| 1486 | |
| 1487 | // Check specified def |
| 1488 | C4Def *pDef = C4Id2Def(id: idItem); |
| 1489 | if (!pDef) pDef = pMenuObj->Def; |
| 1490 | |
| 1491 | // Compose caption with def name |
| 1492 | if (szCaption) |
| 1493 | { |
| 1494 | const char *s = FnStringPar(pString: szCaption); |
| 1495 | const char *sep = strstr(haystack: s, needle: "%s" ); |
| 1496 | if (sep) |
| 1497 | { |
| 1498 | strncpy(dest: caption, src: s, n: std::min<intptr_t>(a: sep - s, b: 256)); |
| 1499 | caption[std::min<intptr_t>(a: sep - s, b: 256)] = 0; |
| 1500 | strncat(dest: caption, src: pDef->GetName(), n: 256); |
| 1501 | strncat(dest: caption, src: sep + 2, n: 256); |
| 1502 | } |
| 1503 | else |
| 1504 | { |
| 1505 | strncpy(dest: caption, src: s, n: 256); |
| 1506 | caption[256] = 0; |
| 1507 | } |
| 1508 | } |
| 1509 | else |
| 1510 | caption[0] = 0; |
| 1511 | |
| 1512 | // create string to include type-information in command |
| 1513 | switch (Parameter.GetType()) |
| 1514 | { |
| 1515 | case C4V_Int: |
| 1516 | FormatWithNull(buf&: parameter, fmt: "{}" , args: Parameter.getInt()); |
| 1517 | break; |
| 1518 | case C4V_Bool: |
| 1519 | SCopy(szSource: Parameter.getBool() ? "true" : "false" , sTarget: parameter); |
| 1520 | break; |
| 1521 | case C4V_C4ID: |
| 1522 | FormatWithNull(buf&: parameter, fmt: "{}" , args: C4IdText(id: Parameter.getC4ID())); |
| 1523 | break; |
| 1524 | case C4V_C4Object: |
| 1525 | FormatWithNull(buf&: parameter, fmt: "Object({})" , args&: Parameter.getObj()->Number); |
| 1526 | break; |
| 1527 | case C4V_String: |
| 1528 | // note this breaks if there is '"' in the string. |
| 1529 | parameter[0] = '"'; |
| 1530 | SCopy(szSource: Parameter.getStr()->Data.getData(), sTarget: parameter + 1, iMaxL: sizeof(parameter) - 3); |
| 1531 | SAppendChar(cChar: '"', szStr: parameter); |
| 1532 | break; |
| 1533 | case C4V_Any: |
| 1534 | FormatWithNull(buf&: parameter, fmt: "CastAny({})" , args: Parameter._getRaw()); |
| 1535 | break; |
| 1536 | case C4V_Array: |
| 1537 | // Arrays were never allowed, so tell the scripter |
| 1538 | throw C4AulExecError(cthr->Obj, "array as parameter to AddMenuItem" ); |
| 1539 | case C4V_Map: |
| 1540 | // Maps are not allowed either |
| 1541 | throw C4AulExecError(cthr->Obj, "map as parameter to AddMenuItem" ); |
| 1542 | default: |
| 1543 | return false; |
| 1544 | } |
| 1545 | |
| 1546 | // own value |
| 1547 | bool fOwnValue = false; C4ValueInt iValue = 0; |
| 1548 | if (iExtra & C4MN_Add_PassValue) |
| 1549 | { |
| 1550 | fOwnValue = true; |
| 1551 | iValue = XPar2.getInt(); |
| 1552 | } |
| 1553 | |
| 1554 | // New Style: native script command |
| 1555 | int i = 0; |
| 1556 | for (; i < SLen(sptr: FnStringPar(pString: szCommand)); i++) |
| 1557 | if (!IsIdentifier(cChar: FnStringPar(pString: szCommand)[i])) |
| 1558 | break; |
| 1559 | if (i < SLen(sptr: FnStringPar(pString: szCommand))) |
| 1560 | { |
| 1561 | // Search for "%d" an replace it by "%s" for insertion of formatted parameter |
| 1562 | SCopy(szSource: FnStringPar(pString: szCommand), sTarget: dummy, iMaxL: 256); |
| 1563 | char *pFound = const_cast<char *>(SSearch(szString: dummy, szIndex: "%d" )); |
| 1564 | if (pFound != nullptr) |
| 1565 | *(pFound - 1) = 's'; |
| 1566 | // Compose left-click command |
| 1567 | command = fmt::sprintf(fmt: dummy, args: parameter, args: 0); |
| 1568 | command2 = fmt::sprintf(fmt: dummy, args: parameter, args: 1); |
| 1569 | } |
| 1570 | |
| 1571 | // Old style: function name with id and parameter |
| 1572 | else |
| 1573 | { |
| 1574 | const char *szScriptCom = FnStringPar(pString: szCommand); |
| 1575 | if (szScriptCom && *szScriptCom) |
| 1576 | { |
| 1577 | if (iExtra & C4MN_Add_PassValue) |
| 1578 | { |
| 1579 | // with value |
| 1580 | command = std::format(fmt: "{}({},{},0,{})" , args&: szScriptCom, args: C4IdText(id: idItem), args: +parameter, args&: iValue); |
| 1581 | command2 = std::format(fmt: "{}({},{},1,{})" , args&: szScriptCom, args: C4IdText(id: idItem), args: +parameter, args&: iValue); |
| 1582 | } |
| 1583 | else |
| 1584 | { |
| 1585 | // without value |
| 1586 | command = std::format(fmt: "{}({},{})" , args&: szScriptCom, args: C4IdText(id: idItem), args: +parameter); |
| 1587 | command2 = std::format(fmt: "{}({},{},1)" , args&: szScriptCom, args: C4IdText(id: idItem), args: +parameter); |
| 1588 | } |
| 1589 | } |
| 1590 | else |
| 1591 | { |
| 1592 | // no command |
| 1593 | } |
| 1594 | } |
| 1595 | |
| 1596 | // Info caption |
| 1597 | SCopy(szSource: FnStringPar(pString: szInfoCaption), sTarget: infocaption, iMaxL: C4MaxTitle); |
| 1598 | // Default info caption by def desc |
| 1599 | if (!infocaption[0] && !(iExtra & C4MN_Add_ForceNoDesc)) SCopy(szSource: pDef->GetDesc(), sTarget: infocaption, iMaxL: C4MaxTitle); |
| 1600 | |
| 1601 | // Create symbol |
| 1602 | C4FacetExSurface fctSymbol; |
| 1603 | switch (iExtra & C4MN_Add_MaxImage) |
| 1604 | { |
| 1605 | case C4MN_Add_ImgRank: |
| 1606 | { |
| 1607 | // symbol by rank |
| 1608 | C4FacetEx *pfctRankSym = &Game.GraphicsResource.fctRank; |
| 1609 | int32_t iRankSymNum = Game.GraphicsResource.iNumRanks; |
| 1610 | if (pDef && pDef->pRankSymbols) |
| 1611 | { |
| 1612 | pfctRankSym = pDef->pRankSymbols; |
| 1613 | iRankSymNum = pDef->iNumRankSymbols; |
| 1614 | } |
| 1615 | C4RankSystem::DrawRankSymbol(fctSymbol: &fctSymbol, iRank: iCount, pfctRankSymbols: pfctRankSym, iRankSymbolCount: iRankSymNum, fOwnSurface: true); |
| 1616 | iCount = 0; |
| 1617 | break; |
| 1618 | } |
| 1619 | case C4MN_Add_ImgIndexed: |
| 1620 | // use indexed facet |
| 1621 | pDef->Picture2Facet(cgo&: fctSymbol, color: 0, xPhase: XPar.getInt()); |
| 1622 | break; |
| 1623 | case C4MN_Add_ImgObjRank: |
| 1624 | { |
| 1625 | // draw current gfx of XPar_C4V including rank |
| 1626 | if (XPar.GetType() != C4V_C4Object) return false; |
| 1627 | C4Object *pGfxObj = XPar.getObj(); |
| 1628 | if (pGfxObj && pGfxObj->Status) |
| 1629 | { |
| 1630 | // create graphics |
| 1631 | // get rank gfx |
| 1632 | C4FacetEx *pRankRes = &Game.GraphicsResource.fctRank; |
| 1633 | C4ValueInt iRankCnt = Game.GraphicsResource.iNumRanks; |
| 1634 | C4Def *pDef = pGfxObj->Def; |
| 1635 | if (pDef->pRankSymbols) |
| 1636 | { |
| 1637 | pRankRes = pDef->pRankSymbols; |
| 1638 | iRankCnt = pDef->iNumRankSymbols; |
| 1639 | } |
| 1640 | // context menu |
| 1641 | C4Facet fctRank; |
| 1642 | if (pMenuObj->Menu->IsContextMenu()) |
| 1643 | { |
| 1644 | // context menu entry: left object gfx |
| 1645 | C4ValueInt C4MN_SymbolSize = pMenuObj->Menu->GetItemHeight(); |
| 1646 | fctSymbol.Create(iWdt: C4MN_SymbolSize * 2, iHgt: C4MN_SymbolSize); |
| 1647 | fctSymbol.Wdt = C4MN_SymbolSize; |
| 1648 | pGfxObj->Def->Draw(cgo&: fctSymbol, fSelected: false, iColor: pGfxObj->Color, pObj: pGfxObj); |
| 1649 | // right of it the rank |
| 1650 | fctRank = fctSymbol; |
| 1651 | fctRank.X = C4MN_SymbolSize; |
| 1652 | fctSymbol.Wdt *= 2; |
| 1653 | } |
| 1654 | else |
| 1655 | { |
| 1656 | // regular menu: draw object picture |
| 1657 | fctSymbol.Create(iWdt: iSymbolSize, iHgt: iSymbolSize); |
| 1658 | pGfxObj->Def->Draw(cgo&: fctSymbol, fSelected: false, iColor: pGfxObj->Color, pObj: pGfxObj); |
| 1659 | // rank at top-right corner |
| 1660 | fctRank = fctSymbol; |
| 1661 | fctRank.X = fctRank.Wdt - pRankRes->Wdt; |
| 1662 | fctRank.Wdt = pRankRes->Wdt; |
| 1663 | fctRank.Hgt = pRankRes->Hgt; |
| 1664 | } |
| 1665 | // draw rank |
| 1666 | if (pGfxObj->Info) |
| 1667 | { |
| 1668 | C4Facet fctBackup = static_cast<const C4Facet &>(fctSymbol); |
| 1669 | fctSymbol.Set(fctRank); |
| 1670 | C4RankSystem::DrawRankSymbol(fctSymbol: &fctSymbol, iRank: pGfxObj->Info->Rank, pfctRankSymbols: pRankRes, iRankSymbolCount: iRankCnt, fOwnSurface: true); |
| 1671 | fctSymbol.Set(fctBackup); |
| 1672 | } |
| 1673 | } |
| 1674 | } |
| 1675 | break; |
| 1676 | case C4MN_Add_ImgObject: |
| 1677 | { |
| 1678 | // draw object picture |
| 1679 | if (XPar.GetType() != C4V_C4Object) return false; |
| 1680 | C4Object *pGfxObj = XPar.getObj(); |
| 1681 | fctSymbol.Wdt = fctSymbol.Hgt = iSymbolSize; |
| 1682 | pGfxObj->Picture2Facet(cgo&: fctSymbol); |
| 1683 | } |
| 1684 | break; |
| 1685 | |
| 1686 | case C4MN_Add_ImgTextSpec: |
| 1687 | { |
| 1688 | C4FacetExSurface fctSymSpec; |
| 1689 | uint32_t dwClr = XPar.getInt(); |
| 1690 | if (!szCaption || !Game.DrawTextSpecImage(fctTarget&: fctSymSpec, szSpec: caption, dwClr: dwClr ? dwClr : 0xff)) |
| 1691 | return false; |
| 1692 | fctSymbol.Create(iWdt: iSymbolSize, iHgt: iSymbolSize); |
| 1693 | fctSymSpec.Draw(cgo&: fctSymbol, fAspect: true); |
| 1694 | *caption = '\0'; |
| 1695 | } |
| 1696 | break; |
| 1697 | |
| 1698 | case C4MN_Add_ImgColor: |
| 1699 | // set colored def facet |
| 1700 | pDef->Picture2Facet(cgo&: fctSymbol, color: XPar.getInt()); |
| 1701 | break; |
| 1702 | |
| 1703 | case C4MN_Add_ImgIndexedColor: |
| 1704 | if (iExtra & C4MN_Add_PassValue) |
| 1705 | { |
| 1706 | throw C4AulExecError{cthr->Obj, "AddMenuItem: C4MN_Add_ImgIndexedColor can not be used together with C4MN_Add_PassValue!" }; |
| 1707 | } |
| 1708 | pDef->Picture2Facet(cgo&: fctSymbol, color: XPar2.getInt(), xPhase: XPar.getInt()); |
| 1709 | break; |
| 1710 | |
| 1711 | default: |
| 1712 | // default: by def, if it is not specifically NONE |
| 1713 | if (idItem != C4Id(str: "NONE" )) |
| 1714 | { |
| 1715 | pDef->Picture2Facet(cgo&: fctSymbol); |
| 1716 | } |
| 1717 | else |
| 1718 | { |
| 1719 | // otherwise: Clear symbol! |
| 1720 | } |
| 1721 | break; |
| 1722 | } |
| 1723 | |
| 1724 | // Convert default zero count to no count |
| 1725 | if (iCount == 0 && !(iExtra & C4MN_Add_ForceCount)) iCount = C4MN_Item_NoCount; |
| 1726 | |
| 1727 | // menuitems without commands are never selectable |
| 1728 | bool fIsSelectable = !command.empty(); |
| 1729 | |
| 1730 | // Add menu item |
| 1731 | pMenuObj->Menu->Add(szCaption: caption, fctSymbol, szCommand: command.c_str(), iCount, pObject: nullptr, szInfoCaption: infocaption, idID: idItem, szCommand2: command2.c_str(), fOwnValue, iValue, fIsSelectable); |
| 1732 | |
| 1733 | return true; |
| 1734 | } |
| 1735 | |
| 1736 | static bool (C4AulContext *cthr, C4ValueInt iItem, C4Object *) |
| 1737 | { |
| 1738 | if (!pMenuObj) pMenuObj = cthr->Obj; if (!pMenuObj) return false; |
| 1739 | if (!pMenuObj->Menu) return false; |
| 1740 | return !!pMenuObj->Menu->SetSelection(iSelection: iItem, fAdjustPosition: false, fDoCalls: true); |
| 1741 | } |
| 1742 | |
| 1743 | static bool (C4AulContext *cthr, C4ID idNewDeco, C4Object *) |
| 1744 | { |
| 1745 | if (!pMenuObj || !pMenuObj->Menu) return false; |
| 1746 | C4GUI::FrameDecoration *pNewDeco = new C4GUI::FrameDecoration(); |
| 1747 | if (!pNewDeco->SetByDef(idNewDeco)) |
| 1748 | { |
| 1749 | delete pNewDeco; |
| 1750 | return false; |
| 1751 | } |
| 1752 | pMenuObj->Menu->SetFrameDeco(pNewDeco); |
| 1753 | return true; |
| 1754 | } |
| 1755 | |
| 1756 | static bool (C4AulContext *cthr, C4ValueInt iNewProgress, C4Object *) |
| 1757 | { |
| 1758 | if (!pMenuObj || !pMenuObj->Menu) return false; |
| 1759 | return pMenuObj->Menu->SetTextProgress(iToProgress: iNewProgress, fAdd: false); |
| 1760 | } |
| 1761 | |
| 1762 | // Check / Status |
| 1763 | |
| 1764 | static C4Object *FnContained(C4AulContext *cthr, C4Object *pObj) |
| 1765 | { |
| 1766 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1767 | return pObj->Contained; |
| 1768 | } |
| 1769 | |
| 1770 | static C4Object *FnContents(C4AulContext *cthr, C4ValueInt index, C4Object *pObj, bool returnAttached) |
| 1771 | { |
| 1772 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1773 | // Special: objects attaching to another object |
| 1774 | // cannot be accessed by FnContents, unless returnAttached is true |
| 1775 | C4Object *cobj; |
| 1776 | while (cobj = pObj->Contents.GetObject(Index: index)) |
| 1777 | { |
| 1778 | if (cobj->GetProcedure() != DFA_ATTACH || returnAttached) return cobj; |
| 1779 | index++; |
| 1780 | } |
| 1781 | return nullptr; |
| 1782 | } |
| 1783 | |
| 1784 | static bool FnShiftContents(C4AulContext *cthr, C4Object *pObj, bool fShiftBack, C4ID idTarget, bool fDoCalls) |
| 1785 | { |
| 1786 | // local call/safety |
| 1787 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 1788 | // regular shift |
| 1789 | if (!idTarget) return !!pObj->ShiftContents(fShiftBack, fDoCalls); |
| 1790 | // check if ID is present within target |
| 1791 | C4Object *pNewFront = pObj->Contents.Find(id: idTarget); |
| 1792 | if (!pNewFront) return false; |
| 1793 | // select it |
| 1794 | pObj->DirectComContents(pTarget: pNewFront, fDoCalls); |
| 1795 | // done, success |
| 1796 | return true; |
| 1797 | } |
| 1798 | |
| 1799 | static C4Object *FnScrollContents(C4AulContext *cthr, C4Object *pObj) |
| 1800 | { |
| 1801 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1802 | |
| 1803 | C4Object *pMove = pObj->Contents.GetObject(); |
| 1804 | if (pMove) |
| 1805 | { |
| 1806 | pObj->Contents.Remove(pObj: pMove); |
| 1807 | pObj->Contents.Add(nObj: pMove, eSort: C4ObjectList::stNone); |
| 1808 | } |
| 1809 | |
| 1810 | return pObj->Contents.GetObject(); |
| 1811 | } |
| 1812 | |
| 1813 | static std::optional<C4ValueInt> FnContentsCount(C4AulContext *cthr, C4ID id, C4Object *pObj) |
| 1814 | { |
| 1815 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1816 | return {pObj->Contents.ObjectCount(id)}; |
| 1817 | } |
| 1818 | |
| 1819 | static C4Object *FnFindContents(C4AulContext *cthr, C4ID c_id, C4Object *pObj) |
| 1820 | { |
| 1821 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1822 | return pObj->Contents.Find(id: c_id); |
| 1823 | } |
| 1824 | |
| 1825 | static C4Object *FnFindOtherContents(C4AulContext *cthr, C4ID c_id, C4Object *pObj) |
| 1826 | { |
| 1827 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1828 | return pObj->Contents.FindOther(id: c_id); |
| 1829 | } |
| 1830 | |
| 1831 | static std::optional<bool> FnActIdle(C4AulContext *cthr, C4Object *pObj) |
| 1832 | { |
| 1833 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1834 | if (pObj->Action.Act == ActIdle) return {true}; |
| 1835 | return {false}; |
| 1836 | } |
| 1837 | |
| 1838 | static std::optional<bool> FnCheckEnergyNeedChain(C4AulContext *cthr, C4Object *pObj) |
| 1839 | { |
| 1840 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1841 | C4ObjectList EnergyChainChecked; |
| 1842 | return {CheckEnergyNeedChain(pObj, rEnergyChainChecked&: EnergyChainChecked)}; |
| 1843 | } |
| 1844 | |
| 1845 | static std::optional<bool> FnEnergyCheck(C4AulContext *cthr, C4ValueInt energy, C4Object *pObj) |
| 1846 | { |
| 1847 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1848 | if (!(Game.Rules & C4RULE_StructuresNeedEnergy) |
| 1849 | || (pObj->Energy >= energy) |
| 1850 | || !(pObj->Def->LineConnect & C4D_Power_Consumer)) |
| 1851 | { |
| 1852 | pObj->NeedEnergy = 0; return {true}; |
| 1853 | } |
| 1854 | pObj->NeedEnergy = 1; |
| 1855 | return {false}; |
| 1856 | } |
| 1857 | |
| 1858 | static std::optional<bool> FnStuck(C4AulContext *cthr, C4Object *pObj) |
| 1859 | { |
| 1860 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1861 | return {!!pObj->Shape.CheckContact(cx: pObj->x, cy: pObj->y)}; |
| 1862 | } |
| 1863 | |
| 1864 | static std::optional<bool> FnInLiquid(C4AulContext *cthr, C4Object *pObj) |
| 1865 | { |
| 1866 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1867 | return {pObj->InLiquid}; |
| 1868 | } |
| 1869 | |
| 1870 | static std::optional<bool> FnOnFire(C4AulContext *cthr, C4Object *pObj) |
| 1871 | { |
| 1872 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 1873 | if (pObj->GetOnFire()) return {true}; |
| 1874 | // check for effect |
| 1875 | if (!pObj->pEffects) return {false}; |
| 1876 | return {!!pObj->pEffects->Get(C4Fx_AnyFire)}; |
| 1877 | } |
| 1878 | |
| 1879 | static std::optional<bool> FnComponentAll(C4AulContext *cthr, C4Object *pObj, C4ID c_id) |
| 1880 | { |
| 1881 | C4ValueInt cnt; |
| 1882 | if (!pObj) return {}; |
| 1883 | C4IDList Components; |
| 1884 | pObj->Def->GetComponents(pOutList: &Components, pObjInstance: pObj, pBuilder: cthr->Obj); |
| 1885 | for (cnt = 0; Components.GetID(index: cnt); cnt++) |
| 1886 | if (Components.GetID(index: cnt) != c_id) |
| 1887 | if (Components.GetCount(index: cnt) > 0) |
| 1888 | return {false}; |
| 1889 | return {true}; |
| 1890 | } |
| 1891 | |
| 1892 | static C4Object *FnCreateObject(C4AulContext *cthr, |
| 1893 | C4ID id, C4ValueInt iXOffset, C4ValueInt iYOffset, C4ValueInt iOwner) |
| 1894 | { |
| 1895 | if (cthr->Obj) // Local object calls override |
| 1896 | { |
| 1897 | iXOffset += cthr->Obj->x; |
| 1898 | iYOffset += cthr->Obj->y; |
| 1899 | if (!cthr->Caller || cthr->Caller->Func->Owner->Strict == C4AulScriptStrict::NONSTRICT) |
| 1900 | iOwner = cthr->Obj->Owner; |
| 1901 | } |
| 1902 | |
| 1903 | C4Object *pNewObj = Game.CreateObject(type: id, pCreator: cthr->Obj, owner: iOwner, x: iXOffset, y: iYOffset); |
| 1904 | |
| 1905 | // Set initial controller to creating controller, so more complicated cause-effect-chains can be traced back to the causing player |
| 1906 | if (pNewObj && cthr->Obj && cthr->Obj->Controller > NO_OWNER) pNewObj->Controller = cthr->Obj->Controller; |
| 1907 | |
| 1908 | return pNewObj; |
| 1909 | } |
| 1910 | |
| 1911 | static C4Object *FnCreateConstruction(C4AulContext *cthr, |
| 1912 | C4ID id, C4ValueInt iXOffset, C4ValueInt iYOffset, C4ValueInt iOwner, |
| 1913 | C4ValueInt iCompletion, bool fTerrain, bool fCheckSite) |
| 1914 | { |
| 1915 | // Local object calls override position offset, owner |
| 1916 | if (cthr->Obj) |
| 1917 | { |
| 1918 | iXOffset += cthr->Obj->x; |
| 1919 | iYOffset += cthr->Obj->y; |
| 1920 | if (!cthr->Caller || cthr->Caller->Func->Owner->Strict == C4AulScriptStrict::NONSTRICT) |
| 1921 | iOwner = cthr->Obj->Owner; |
| 1922 | } |
| 1923 | |
| 1924 | // Check site |
| 1925 | if (fCheckSite) |
| 1926 | if (!ConstructionCheck(id, iX: iXOffset, iY: iYOffset, pByObj: cthr->Obj)) |
| 1927 | return nullptr; |
| 1928 | |
| 1929 | // Create site object |
| 1930 | C4Object *pNewObj = Game.CreateObjectConstruction(type: id, pCreator: cthr->Obj, owner: iOwner, ctx: iXOffset, bty: iYOffset, con: iCompletion * FullCon / 100, terrain: fTerrain); |
| 1931 | |
| 1932 | // Set initial controller to creating controller, so more complicated cause-effect-chains can be traced back to the causing player |
| 1933 | if (pNewObj && cthr->Obj && cthr->Obj->Controller > NO_OWNER) pNewObj->Controller = cthr->Obj->Controller; |
| 1934 | |
| 1935 | return pNewObj; |
| 1936 | } |
| 1937 | |
| 1938 | static C4Object *FnCreateContents(C4AulContext *cthr, C4ID c_id, C4Object *pObj, C4ValueInt iCount) |
| 1939 | { |
| 1940 | // local call / safety |
| 1941 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1942 | // default amount parameter |
| 1943 | if (!iCount) ++iCount; |
| 1944 | // create objects |
| 1945 | C4Object *pNewObj = nullptr; |
| 1946 | while (iCount-- > 0) pNewObj = pObj->CreateContents(n_id: c_id); |
| 1947 | // controller will automatically be set upon entrance |
| 1948 | // return last created |
| 1949 | return pNewObj; |
| 1950 | } |
| 1951 | |
| 1952 | static C4Object *FnComposeContents(C4AulContext *cthr, C4ID c_id, C4Object *pObj) |
| 1953 | { |
| 1954 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 1955 | return pObj->ComposeContents(id: c_id); |
| 1956 | } |
| 1957 | |
| 1958 | static std::optional<bool> FnFindConstructionSite(C4AulContext *cthr, C4ID id, C4ValueInt iVarX, C4ValueInt iVarY) |
| 1959 | { |
| 1960 | // Get def (Old-style implementation (fixed)...) |
| 1961 | C4Def *pDef; |
| 1962 | if (!(pDef = C4Id2Def(id))) return {}; |
| 1963 | // Var indices out of range |
| 1964 | if (!Inside<C4ValueInt>(ival: iVarX, lbound: 0, C4AUL_MAX_Par - 1) || !Inside<C4ValueInt>(ival: iVarY, lbound: 0, C4AUL_MAX_Par - 1)) return {}; |
| 1965 | // Get thread vars |
| 1966 | if (!cthr->Caller) return {}; |
| 1967 | C4Value &V1 = cthr->Caller->NumVars[iVarX]; |
| 1968 | C4Value &V2 = cthr->Caller->NumVars[iVarY]; |
| 1969 | // Construction check at starting position |
| 1970 | if (ConstructionCheck(id, iX: V1.getInt(), iY: V2.getInt())) |
| 1971 | return {true}; |
| 1972 | // Search for real |
| 1973 | int32_t v1 = V1.getInt(), v2 = V2.getInt(); |
| 1974 | bool result = !!FindConSiteSpot(rx&: v1, ry&: v2, |
| 1975 | wdt: pDef->Shape.Wdt, hgt: pDef->Shape.Hgt, |
| 1976 | category: pDef->Category, |
| 1977 | hrange: 20); |
| 1978 | V1 = C4VInt(iVal: v1); V2 = C4VInt(iVal: v2); |
| 1979 | return {result}; |
| 1980 | } |
| 1981 | |
| 1982 | static C4Object *FnFindBase(C4AulContext *cthr, C4ValueInt iOwner, C4ValueInt iIndex) |
| 1983 | { |
| 1984 | if (!ValidPlr(plr: iOwner)) return nullptr; |
| 1985 | return Game.FindBase(iPlayer: iOwner, iIndex); |
| 1986 | } |
| 1987 | |
| 1988 | C4FindObject *CreateCriterionsFromPars(const C4Value *pPars, C4FindObject **pFOs, C4SortObject **pSOs) |
| 1989 | { |
| 1990 | int i, iCnt = 0, iSortCnt = 0; |
| 1991 | // Read all parameters |
| 1992 | for (i = 0; i < C4AUL_MAX_Par; i++) |
| 1993 | { |
| 1994 | const C4Value &Data = pPars[i].GetRefVal(); |
| 1995 | // No data given? |
| 1996 | if (!Data) break; |
| 1997 | // Construct |
| 1998 | C4SortObject *pSO = nullptr; |
| 1999 | C4FindObject *pFO = C4FindObject::CreateByValue(Data, ppSortObj: pSOs ? &pSO : nullptr); |
| 2000 | // Add FindObject |
| 2001 | if (pFO) |
| 2002 | { |
| 2003 | pFOs[iCnt++] = pFO; |
| 2004 | } |
| 2005 | // Add SortObject |
| 2006 | if (pSO) |
| 2007 | { |
| 2008 | pSOs[iSortCnt++] = pSO; |
| 2009 | } |
| 2010 | } |
| 2011 | // No criterions? |
| 2012 | if (!iCnt) |
| 2013 | { |
| 2014 | for (i = 0; i < iSortCnt; ++i) delete pSOs[i]; |
| 2015 | return nullptr; |
| 2016 | } |
| 2017 | // create sort criterion |
| 2018 | C4SortObject *pSO = nullptr; |
| 2019 | if (iSortCnt) |
| 2020 | { |
| 2021 | if (iSortCnt == 1) |
| 2022 | pSO = pSOs[0]; |
| 2023 | else |
| 2024 | pSO = new C4SortObjectMultiple(iSortCnt, pSOs, false); |
| 2025 | } |
| 2026 | // Create search object |
| 2027 | C4FindObject *pFO; |
| 2028 | if (iCnt == 1) |
| 2029 | pFO = pFOs[0]; |
| 2030 | else |
| 2031 | pFO = new C4FindObjectAnd(iCnt, pFOs, false); |
| 2032 | if (pSO) pFO->SetSort(pSO); |
| 2033 | return pFO; |
| 2034 | } |
| 2035 | |
| 2036 | static C4Value FnObjectCount2(C4AulContext *cthr, const C4Value *pPars) |
| 2037 | { |
| 2038 | // Create FindObject-structure |
| 2039 | C4FindObject *pFOs[C4AUL_MAX_Par]; |
| 2040 | C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, pSOs: nullptr); |
| 2041 | // Error? |
| 2042 | if (!pFO) |
| 2043 | throw C4AulExecError(cthr->Obj, "ObjectCount: No valid search criterions supplied!" ); |
| 2044 | // Search |
| 2045 | int32_t iCnt = pFO->Count(Objs: Game.Objects, Sct: Game.Objects.Sectors); |
| 2046 | // Free |
| 2047 | delete pFO; |
| 2048 | // Return |
| 2049 | return C4VInt(iVal: iCnt); |
| 2050 | } |
| 2051 | |
| 2052 | static C4Value FnFindObject2(C4AulContext *cthr, const C4Value *pPars) |
| 2053 | { |
| 2054 | // Create FindObject-structure |
| 2055 | C4FindObject *pFOs[C4AUL_MAX_Par]; |
| 2056 | C4SortObject *pSOs[C4AUL_MAX_Par]; |
| 2057 | C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, pSOs); |
| 2058 | // Error? |
| 2059 | if (!pFO) |
| 2060 | throw C4AulExecError(cthr->Obj, "FindObject: No valid search criterions supplied!" ); |
| 2061 | // Search |
| 2062 | C4Object *pObj = pFO->Find(Objs: Game.Objects, Sct: Game.Objects.Sectors); |
| 2063 | // Free |
| 2064 | delete pFO; |
| 2065 | // Return |
| 2066 | return C4VObj(pObj); |
| 2067 | } |
| 2068 | |
| 2069 | static C4Value FnFindObjects(C4AulContext *cthr, const C4Value *pPars) |
| 2070 | { |
| 2071 | // Create FindObject-structure |
| 2072 | C4FindObject *pFOs[C4AUL_MAX_Par]; |
| 2073 | C4SortObject *pSOs[C4AUL_MAX_Par]; |
| 2074 | C4FindObject *pFO = CreateCriterionsFromPars(pPars, pFOs, pSOs); |
| 2075 | // Error? |
| 2076 | if (!pFO) |
| 2077 | throw C4AulExecError(cthr->Obj, "FindObjects: No valid search criterions supplied!" ); |
| 2078 | // Search |
| 2079 | C4ValueArray *pResult = pFO->FindMany(Objs: Game.Objects, Sct: Game.Objects.Sectors); |
| 2080 | // Free |
| 2081 | delete pFO; |
| 2082 | // Return |
| 2083 | return C4VArray(pArray: pResult); |
| 2084 | } |
| 2085 | |
| 2086 | static C4ValueInt FnObjectCount(C4AulContext *cthr, C4ID id, C4ValueInt x, C4ValueInt y, C4ValueInt wdt, C4ValueInt hgt, C4ValueInt dwOCF, C4String *szAction, C4Object *pActionTarget, C4Value vContainer, C4ValueInt iOwner) |
| 2087 | { |
| 2088 | // Local call adjust coordinates |
| 2089 | if (cthr->Obj && (x || y || wdt || hgt)) // if not default full range |
| 2090 | { |
| 2091 | x += cthr->Obj->x; |
| 2092 | y += cthr->Obj->y; |
| 2093 | } |
| 2094 | // Adjust default ocf |
| 2095 | if (dwOCF == 0) dwOCF = OCF_All; |
| 2096 | // Adjust default owner |
| 2097 | if (iOwner == 0) iOwner = ANY_OWNER; // imcomplete useless implementation |
| 2098 | // NO_CONTAINER/ANY_CONTAINER |
| 2099 | C4Object *pContainer = vContainer.getObj(); |
| 2100 | if (vContainer.getInt() == NO_CONTAINER) |
| 2101 | pContainer = reinterpret_cast<C4Object *>(NO_CONTAINER); |
| 2102 | if (vContainer.getInt() == ANY_CONTAINER) |
| 2103 | pContainer = reinterpret_cast<C4Object *>(ANY_CONTAINER); |
| 2104 | // Find object |
| 2105 | return Game.ObjectCount(id, x, y, wdt, hgt, ocf: dwOCF, |
| 2106 | szAction: FnStringPar(pString: szAction), pActionTarget, |
| 2107 | pExclude: cthr->Obj, // Local calls exclude self |
| 2108 | pContainer, |
| 2109 | iOwner); |
| 2110 | } |
| 2111 | |
| 2112 | static C4Object *FnFindObject(C4AulContext *cthr, C4ID id, C4ValueInt x, C4ValueInt y, C4ValueInt wdt, C4ValueInt hgt, C4ValueInt dwOCF, C4String *szAction, C4Object *pActionTarget, C4Value vContainer, C4Object *pFindNext) |
| 2113 | { |
| 2114 | // Local call adjust coordinates |
| 2115 | if (cthr->Obj) |
| 2116 | if (x || y || wdt || hgt) // if not default full range |
| 2117 | { |
| 2118 | x += cthr->Obj->x; y += cthr->Obj->y; |
| 2119 | } |
| 2120 | // Adjust default ocf |
| 2121 | if (dwOCF == 0) dwOCF = OCF_All; |
| 2122 | // NO_CONTAINER/ANY_CONTAINER |
| 2123 | C4Object *pContainer = vContainer.getObj(); |
| 2124 | if (vContainer.getInt() == NO_CONTAINER) |
| 2125 | pContainer = reinterpret_cast<C4Object *>(NO_CONTAINER); |
| 2126 | if (vContainer.getInt() == ANY_CONTAINER) |
| 2127 | pContainer = reinterpret_cast<C4Object *>(ANY_CONTAINER); |
| 2128 | // Find object |
| 2129 | return Game.FindObject(id, iX: x, iY: y, iWdt: wdt, iHgt: hgt, ocf: dwOCF, |
| 2130 | szAction: FnStringPar(pString: szAction), pActionTarget, |
| 2131 | pExclude: cthr->Obj, // Local calls exclude self |
| 2132 | pContainer, |
| 2133 | iOwner: ANY_OWNER, |
| 2134 | pFindNext); |
| 2135 | } |
| 2136 | |
| 2137 | static C4Object *FnFindObjectOwner(C4AulContext *cthr, |
| 2138 | C4ID id, |
| 2139 | C4ValueInt iOwner, |
| 2140 | C4ValueInt x, C4ValueInt y, C4ValueInt wdt, C4ValueInt hgt, |
| 2141 | C4ValueInt dwOCF, |
| 2142 | C4String *szAction, C4Object *pActionTarget, |
| 2143 | C4Object *pFindNext) |
| 2144 | { |
| 2145 | // invalid owner? |
| 2146 | if (!ValidPlr(plr: iOwner) && iOwner != NO_OWNER) return nullptr; |
| 2147 | // Local call adjust coordinates |
| 2148 | if (cthr->Obj) |
| 2149 | if (x || y || wdt || hgt) // if not default full range |
| 2150 | { |
| 2151 | x += cthr->Obj->x; y += cthr->Obj->y; |
| 2152 | } |
| 2153 | // Adjust default ocf |
| 2154 | if (dwOCF == 0) dwOCF = OCF_All; |
| 2155 | // Find object |
| 2156 | return Game.FindObject(id, iX: x, iY: y, iWdt: wdt, iHgt: hgt, ocf: dwOCF, |
| 2157 | szAction: FnStringPar(pString: szAction), pActionTarget, |
| 2158 | pExclude: cthr->Obj, // Local calls exclude self |
| 2159 | pContainer: nullptr, |
| 2160 | iOwner, |
| 2161 | pFindNext); |
| 2162 | } |
| 2163 | |
| 2164 | static bool FnMakeCrewMember(C4AulContext *cthr, C4Object *pObj, C4ValueInt iPlayer) |
| 2165 | { |
| 2166 | if (!ValidPlr(plr: iPlayer)) return false; |
| 2167 | return !!Game.Players.Get(iPlayer)->MakeCrewMember(pObj); |
| 2168 | } |
| 2169 | |
| 2170 | static bool FnGrabObjectInfo(C4AulContext *cthr, C4Object *pFrom, C4Object *pTo) |
| 2171 | { |
| 2172 | // local call, safety |
| 2173 | if (!pFrom) return false; if (!pTo) { pTo = cthr->Obj; if (!pTo) return false; } |
| 2174 | // grab info |
| 2175 | return !!pTo->GrabInfo(pFrom); |
| 2176 | } |
| 2177 | |
| 2178 | static bool FnFlameConsumeMaterial(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2179 | { |
| 2180 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2181 | C4ValueInt mat = GBackMat(x, y); |
| 2182 | if (!MatValid(mat)) return false; |
| 2183 | if (!Game.Material.Map[mat].Inflammable) return false; |
| 2184 | if (Game.Landscape.ExtractMaterial(fx: x, fy: y) == MNone) return false; |
| 2185 | return true; |
| 2186 | } |
| 2187 | |
| 2188 | static void FnSmoke(C4AulContext *cthr, C4ValueInt tx, C4ValueInt ty, C4ValueInt level, C4ValueInt dwClr) |
| 2189 | { |
| 2190 | if (cthr->Obj) { tx += cthr->Obj->x; ty += cthr->Obj->y; } |
| 2191 | Smoke(tx, ty, level, dwClr); |
| 2192 | } |
| 2193 | |
| 2194 | static void FnBubble(C4AulContext *cthr, C4ValueInt tx, C4ValueInt ty) |
| 2195 | { |
| 2196 | if (cthr->Obj) { tx += cthr->Obj->x; ty += cthr->Obj->y; } |
| 2197 | BubbleOut(tx, ty); |
| 2198 | } |
| 2199 | |
| 2200 | static C4ValueInt (C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2201 | { |
| 2202 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2203 | if (!GBackLiquid(x, y)) return MNone; |
| 2204 | return Game.Landscape.ExtractMaterial(fx: x, fy: y); |
| 2205 | } |
| 2206 | |
| 2207 | static bool FnInsertMaterial(C4AulContext *cthr, C4ValueInt mat, C4ValueInt x, C4ValueInt y, C4ValueInt vx, C4ValueInt vy) |
| 2208 | { |
| 2209 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2210 | return !!Game.Landscape.InsertMaterial(mat, tx: x, ty: y, vx, vy); |
| 2211 | } |
| 2212 | |
| 2213 | static C4ValueInt FnGetMaterialCount(C4AulContext *cthr, C4ValueInt iMaterial, bool fReal) |
| 2214 | { |
| 2215 | if (!MatValid(mat: iMaterial)) return -1; |
| 2216 | if (fReal || !Game.Material.Map[iMaterial].MinHeightCount) |
| 2217 | return Game.Landscape.MatCount[iMaterial]; |
| 2218 | else |
| 2219 | return Game.Landscape.EffectiveMatCount[iMaterial]; |
| 2220 | } |
| 2221 | |
| 2222 | static C4ValueInt FnGetMaterial(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2223 | { |
| 2224 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2225 | return GBackMat(x, y); |
| 2226 | } |
| 2227 | |
| 2228 | static C4String *FnGetTexture(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2229 | { |
| 2230 | // Get texture |
| 2231 | int32_t iTex = PixCol2Tex(GBackPix(x, y)); |
| 2232 | if (!iTex) return nullptr; |
| 2233 | // Get material-texture mapping |
| 2234 | const C4TexMapEntry *pTex = Game.TextureMap.GetEntry(iIndex: iTex); |
| 2235 | if (!pTex) return nullptr; |
| 2236 | // Return tex name |
| 2237 | return String(str: pTex->GetTextureName()); |
| 2238 | } |
| 2239 | |
| 2240 | static bool FnGBackSolid(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2241 | { |
| 2242 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2243 | return GBackSolid(x, y); |
| 2244 | } |
| 2245 | |
| 2246 | static bool FnGBackSemiSolid(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2247 | { |
| 2248 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2249 | return GBackSemiSolid(x, y); |
| 2250 | } |
| 2251 | |
| 2252 | static bool FnGBackLiquid(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2253 | { |
| 2254 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2255 | return GBackLiquid(x, y); |
| 2256 | } |
| 2257 | |
| 2258 | static bool FnGBackSky(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 2259 | { |
| 2260 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2261 | return !GBackIFT(x, y); |
| 2262 | } |
| 2263 | |
| 2264 | static C4ValueInt (C4AulContext *cthr, C4ValueInt x, C4ValueInt y, C4ValueInt mat, C4ValueInt amount) |
| 2265 | { |
| 2266 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 2267 | C4ValueInt = 0; for (; extracted < amount; extracted++) |
| 2268 | { |
| 2269 | if (GBackMat(x, y) != mat) return extracted; |
| 2270 | if (Game.Landscape.ExtractMaterial(fx: x, fy: y) != mat) return extracted; |
| 2271 | } |
| 2272 | return extracted; |
| 2273 | } |
| 2274 | |
| 2275 | static void FnBlastObjects(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iLevel, C4Object *pInObj, C4ValueInt iCausedByPlusOne) |
| 2276 | { |
| 2277 | C4ValueInt iCausedBy = iCausedByPlusOne - 1; if (!iCausedByPlusOne && cthr->Obj) iCausedBy = cthr->Obj->Controller; |
| 2278 | Game.BlastObjects(tx: iX, ty: iY, level: iLevel, inobj: pInObj, iCausedBy, pByObj: cthr->Obj); |
| 2279 | } |
| 2280 | |
| 2281 | static bool FnBlastObject(C4AulContext *cthr, C4ValueInt iLevel, C4Object *pObj, C4ValueInt iCausedByPlusOne) |
| 2282 | { |
| 2283 | C4ValueInt iCausedBy = iCausedByPlusOne - 1; if (!iCausedByPlusOne && cthr->Obj) iCausedBy = cthr->Obj->Controller; |
| 2284 | if (!pObj) if (!(pObj = cthr->Obj)) return false; |
| 2285 | if (!pObj->Status) return false; |
| 2286 | pObj->Blast(iLevel, iCausedBy); |
| 2287 | return true; |
| 2288 | } |
| 2289 | |
| 2290 | static void FnBlastFree(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iLevel, C4ValueInt iCausedByPlusOne) |
| 2291 | { |
| 2292 | C4ValueInt iCausedBy = iCausedByPlusOne - 1; |
| 2293 | if (!iCausedByPlusOne && cthr->Obj) |
| 2294 | { |
| 2295 | iCausedBy = cthr->Obj->Controller; |
| 2296 | iX += cthr->Obj->x; |
| 2297 | iY += cthr->Obj->y; |
| 2298 | } |
| 2299 | C4ValueInt grade = BoundBy<C4ValueInt>(bval: (iLevel / 10) - 1, lbound: 1, rbound: 3); |
| 2300 | Game.Landscape.BlastFree(tx: iX, ty: iY, rad: iLevel, grade, iByPlayer: iCausedBy); |
| 2301 | } |
| 2302 | |
| 2303 | static bool FnSound(C4AulContext *cthr, C4String *szSound, bool fGlobal, C4Object *pObj, C4ValueInt iLevel, C4ValueInt iAtPlayer, C4ValueInt iLoop, bool fMultiple, C4ValueInt iCustomFalloffDistance) |
| 2304 | { |
| 2305 | // play here? |
| 2306 | if (iAtPlayer) |
| 2307 | { |
| 2308 | // get player to play at |
| 2309 | C4Player *pPlr = Game.Players.Get(iPlayer: iAtPlayer - 1); |
| 2310 | // not existent? fail |
| 2311 | if (!pPlr) return false; |
| 2312 | // network client: don't play here |
| 2313 | // return true for network sync |
| 2314 | if (!pPlr->LocalControl && !Game.GraphicsSystem.GetViewport(iPlayer: iAtPlayer - 1)) return true; |
| 2315 | } |
| 2316 | // even less than nothing? |
| 2317 | if (iLevel < 0) return true; |
| 2318 | // default sound level |
| 2319 | if (!iLevel || iLevel > 100) |
| 2320 | iLevel = 100; |
| 2321 | // target object |
| 2322 | if (fGlobal) pObj = nullptr; else if (!pObj) pObj = cthr->Obj; |
| 2323 | // already playing? |
| 2324 | if (iLoop >= 0 && !fMultiple && IsSoundPlaying(name: FnStringPar(pString: szSound), obj: pObj)) |
| 2325 | return true; |
| 2326 | // try to play effect |
| 2327 | if (iLoop >= 0) |
| 2328 | StartSoundEffect(name: FnStringPar(pString: szSound), loop: !!iLoop, volume: iLevel, obj: pObj, falloffDistance: iCustomFalloffDistance); |
| 2329 | else |
| 2330 | StopSoundEffect(name: FnStringPar(pString: szSound), obj: pObj); |
| 2331 | // always return true (network safety!) |
| 2332 | return true; |
| 2333 | } |
| 2334 | |
| 2335 | static void FnMusic(C4AulContext *cthr, C4String *szSongname, bool fLoop) |
| 2336 | { |
| 2337 | if (!szSongname) |
| 2338 | { |
| 2339 | Game.IsMusicEnabled = false; |
| 2340 | Application.MusicSystem->Stop(); |
| 2341 | } |
| 2342 | else |
| 2343 | { |
| 2344 | Game.IsMusicEnabled = true; |
| 2345 | Application.MusicSystem->Play(songname: FnStringPar(pString: szSongname), loop: fLoop); |
| 2346 | } |
| 2347 | } |
| 2348 | |
| 2349 | static C4ValueInt FnMusicLevel(C4AulContext *cthr, C4ValueInt iLevel) |
| 2350 | { |
| 2351 | Game.SetMusicLevel(iLevel); |
| 2352 | return Game.iMusicLevel; |
| 2353 | } |
| 2354 | |
| 2355 | static std::optional<C4ValueInt> FnSetPlayList(C4AulContext *cth, C4String *szPlayList, bool fRestartMusic) |
| 2356 | { |
| 2357 | C4ValueInt iFilesInPlayList = Application.MusicSystem->SetPlayList(FnStringPar(pString: szPlayList)); |
| 2358 | Game.PlayList.Copy(pnData: FnStringPar(pString: szPlayList)); |
| 2359 | if (fRestartMusic) Application.MusicSystem->Play(); |
| 2360 | if (Game.Control.SyncMode()) return {}; |
| 2361 | return {iFilesInPlayList}; |
| 2362 | } |
| 2363 | |
| 2364 | static void FnSoundLevel(C4AulContext *cthr, C4String *szSound, C4ValueInt iLevel, C4Object *pObj) |
| 2365 | { |
| 2366 | SoundLevel(name: FnStringPar(pString: szSound), obj: pObj, iLevel); |
| 2367 | } |
| 2368 | |
| 2369 | static bool FnGameOver(C4AulContext *cthr, C4ValueInt iGameOverValue /* provided for future compatibility */) |
| 2370 | { |
| 2371 | return !!Game.DoGameOver(); |
| 2372 | } |
| 2373 | |
| 2374 | static bool FnGainMissionAccess(C4AulContext *cthr, C4String *szPassword) |
| 2375 | { |
| 2376 | if (SLen(sptr: Config.General.MissionAccess) + SLen(sptr: FnStringPar(pString: szPassword)) + 3 > CFG_MaxString) return false; |
| 2377 | SAddModule(szList: Config.General.MissionAccess, szModule: FnStringPar(pString: szPassword)); |
| 2378 | return true; |
| 2379 | } |
| 2380 | |
| 2381 | static void FnLog(C4AulContext *cthr, C4String *szMessage, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7, C4Value iPar8) |
| 2382 | { |
| 2383 | LogNTr(message: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7, Par8: &iPar8)); |
| 2384 | } |
| 2385 | |
| 2386 | static void FnDebugLog(C4AulContext *cthr, C4String *szMessage, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7, C4Value iPar8) |
| 2387 | { |
| 2388 | DebugLog(message: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7, Par8: &iPar8)); |
| 2389 | } |
| 2390 | |
| 2391 | static C4String *FnFormat(C4AulContext *cthr, C4String *szFormat, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7, C4Value iPar8) |
| 2392 | { |
| 2393 | return String(str: StdStrBuf{FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szFormat), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7, Par8: &iPar8).c_str()}); |
| 2394 | } |
| 2395 | |
| 2396 | static C4ID FnC4Id(C4AulContext *cthr, C4String *szID) |
| 2397 | { |
| 2398 | return C4Id(str: FnStringPar(pString: szID)); |
| 2399 | } |
| 2400 | |
| 2401 | static bool FnPlayerMessage(C4AulContext *cthr, C4ValueInt iPlayer, C4String *szMessage, C4Object *pObj, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6) |
| 2402 | { |
| 2403 | char buf[MaxFnStringParLen + 1]; |
| 2404 | if (!szMessage) return false; |
| 2405 | |
| 2406 | // Speech |
| 2407 | bool fSpoken = false; |
| 2408 | if (SCopySegment(fstr: FnStringPar(pString: szMessage), segn: 1, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2409 | if (StartSoundEffect(name: buf, loop: false, volume: 100, obj: pObj ? pObj : cthr->Obj)) |
| 2410 | fSpoken = true; |
| 2411 | |
| 2412 | // Text |
| 2413 | if (!fSpoken) |
| 2414 | if (SCopySegment(fstr: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6).c_str(), segn: 0, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2415 | if (pObj) GameMsgObjectPlayer(szText: buf, pTarget: pObj, iPlayer); |
| 2416 | else GameMsgPlayer(szText: buf, iPlayer); |
| 2417 | |
| 2418 | return true; |
| 2419 | } |
| 2420 | |
| 2421 | static bool FnMessage(C4AulContext *cthr, C4String *szMessage, C4Object *pObj, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7) |
| 2422 | { |
| 2423 | char buf[MaxFnStringParLen + 1]; |
| 2424 | if (!szMessage) return false; |
| 2425 | |
| 2426 | // Speech |
| 2427 | bool fSpoken = false; |
| 2428 | if (SCopySegment(fstr: FnStringPar(pString: szMessage), segn: 1, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2429 | if (StartSoundEffect(name: buf, loop: false, volume: 100, obj: cthr->Obj)) |
| 2430 | fSpoken = true; |
| 2431 | |
| 2432 | // Text |
| 2433 | if (!fSpoken) |
| 2434 | if (SCopySegment(fstr: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7).c_str(), segn: 0, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2435 | if (pObj) GameMsgObject(szText: buf, pTarget: pObj); |
| 2436 | else GameMsgGlobal(szText: buf); |
| 2437 | |
| 2438 | return true; |
| 2439 | } |
| 2440 | |
| 2441 | static bool FnAddMessage(C4AulContext *cthr, C4String *szMessage, C4Object *pObj, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7) |
| 2442 | { |
| 2443 | if (!szMessage) return false; |
| 2444 | |
| 2445 | if (pObj) Game.Messages.Append(iType: C4GM_Target, szText: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7).c_str(), pTarget: pObj, iPlayer: NO_OWNER, iX: 0, iY: 0, bCol: FWhite); |
| 2446 | else Game.Messages.Append(iType: C4GM_Global, szText: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7).c_str(), pTarget: nullptr, iPlayer: ANY_OWNER, iX: 0, iY: 0, bCol: FWhite); |
| 2447 | |
| 2448 | return true; |
| 2449 | } |
| 2450 | |
| 2451 | static bool FnPlrMessage(C4AulContext *cthr, C4String *szMessage, C4ValueInt iPlr, C4Value iPar0, C4Value iPar1, C4Value iPar2, C4Value iPar3, C4Value iPar4, C4Value iPar5, C4Value iPar6, C4Value iPar7) |
| 2452 | { |
| 2453 | char buf[MaxFnStringParLen + 1]; |
| 2454 | if (!szMessage) return false; |
| 2455 | |
| 2456 | // Speech |
| 2457 | bool fSpoken = false; |
| 2458 | if (SCopySegment(fstr: FnStringPar(pString: szMessage), segn: 1, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2459 | if (StartSoundEffect(name: buf, loop: false, volume: 100, obj: cthr->Obj)) |
| 2460 | fSpoken = true; |
| 2461 | |
| 2462 | // Text |
| 2463 | if (!fSpoken) |
| 2464 | if (SCopySegment(fstr: FnStringFormat(cthr, szFormatPar: FnStringPar(pString: szMessage), Par0: &iPar0, Par1: &iPar1, Par2: &iPar2, Par3: &iPar3, Par4: &iPar4, Par5: &iPar5, Par6: &iPar6, Par7: &iPar7).c_str(), segn: 0, tstr: buf, sepa: '$', iMaxL: MaxFnStringParLen)) |
| 2465 | if (ValidPlr(plr: iPlr)) GameMsgPlayer(szText: buf, iPlayer: iPlr); |
| 2466 | else GameMsgGlobal(szText: buf); |
| 2467 | |
| 2468 | return true; |
| 2469 | } |
| 2470 | |
| 2471 | static void FnScriptGo(C4AulContext *cthr, bool go) |
| 2472 | { |
| 2473 | Game.Script.Go = !!go; |
| 2474 | } |
| 2475 | |
| 2476 | static void FnCastPXS(C4AulContext *cthr, C4String *mat_name, C4ValueInt amt, C4ValueInt level, C4ValueInt tx, C4ValueInt ty) |
| 2477 | { |
| 2478 | if (cthr->Obj) { tx += cthr->Obj->x; ty += cthr->Obj->y; } |
| 2479 | Game.PXS.Cast(mat: Game.Material.Get(szMaterial: FnStringPar(pString: mat_name)), num: amt, tx, ty, level); |
| 2480 | } |
| 2481 | |
| 2482 | static void FnCastObjects(C4AulContext *cthr, C4ID id, C4ValueInt amt, C4ValueInt level, C4ValueInt tx, C4ValueInt ty) |
| 2483 | { |
| 2484 | if (cthr->Obj) { tx += cthr->Obj->x; ty += cthr->Obj->y; } |
| 2485 | Game.CastObjects(id, pCreator: cthr->Obj, num: amt, level, tx, ty, iOwner: cthr->Obj ? cthr->Obj->Owner : NO_OWNER, iController: cthr->Obj ? cthr->Obj->Controller : NO_OWNER); |
| 2486 | } |
| 2487 | |
| 2488 | static C4ValueInt FnMaterial(C4AulContext *cthr, C4String *mat_name) |
| 2489 | { |
| 2490 | return Game.Material.Get(szMaterial: FnStringPar(pString: mat_name)); |
| 2491 | } |
| 2492 | |
| 2493 | C4Object *FnPlaceVegetation(C4AulContext *cthr, C4ID id, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4ValueInt iGrowth) |
| 2494 | { |
| 2495 | // Local call: relative coordinates |
| 2496 | if (cthr->Obj) { iX += cthr->Obj->x; iY += cthr->Obj->y; } |
| 2497 | // Place vegetation |
| 2498 | return Game.PlaceVegetation(id, iX, iY, iWdt, iHgt, iGrowth); |
| 2499 | } |
| 2500 | |
| 2501 | C4Object *FnPlaceAnimal(C4AulContext *cthr, C4ID id) |
| 2502 | { |
| 2503 | return Game.PlaceAnimal(idAnimal: id); |
| 2504 | } |
| 2505 | |
| 2506 | static void FnDrawVolcanoBranch(C4AulContext *cthr, C4ValueInt mat, C4ValueInt fx, C4ValueInt fy, C4ValueInt tx, C4ValueInt ty, C4ValueInt size) |
| 2507 | { |
| 2508 | C4ValueInt cx, cx2, cy; |
| 2509 | for (cy = ty; cy < fy; cy++) |
| 2510 | { |
| 2511 | cx = fx + (tx - fx) * (cy - fy) / (ty - fy); |
| 2512 | for (cx2 = cx - size / 2; cx2 < cx + size / 2; cx2++) |
| 2513 | SBackPix(x: cx2, y: cy, npix: Mat2PixColDefault(mat) + GBackIFT(x: cx2, y: cy)); |
| 2514 | } |
| 2515 | } |
| 2516 | |
| 2517 | static bool FnHostile(C4AulContext *cthr, C4ValueInt iPlr1, C4ValueInt iPlr2, bool fCheckOneWayOnly) |
| 2518 | { |
| 2519 | if (fCheckOneWayOnly) |
| 2520 | { |
| 2521 | return Game.Players.HostilityDeclared(iPlayer1: iPlr1, iPlayer2: iPlr2); |
| 2522 | } |
| 2523 | else |
| 2524 | return !!Hostile(plr1: iPlr1, plr2: iPlr2); |
| 2525 | } |
| 2526 | |
| 2527 | static bool FnSetHostility(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iPlr2, bool fHostile, bool fSilent, bool fNoCalls) |
| 2528 | { |
| 2529 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2530 | if (!pPlr) return false; |
| 2531 | // do rejection test first |
| 2532 | if (!fNoCalls) |
| 2533 | { |
| 2534 | if (Game.Script.GRBroadcast(PSF_RejectHostilityChange, pPars: {C4VInt(iVal: iPlr), C4VInt(iVal: iPlr2), C4VBool(fVal: fHostile)}, fPassError: true, fRejectTest: true)) |
| 2535 | return false; |
| 2536 | } |
| 2537 | // OK; set hostility |
| 2538 | bool fOldHostility = Game.Players.HostilityDeclared(iPlayer1: iPlr, iPlayer2: iPlr2); |
| 2539 | if (!pPlr->SetHostility(iOpponent: iPlr2, iHostility: fHostile, fSilent)) return false; |
| 2540 | // calls afterwards |
| 2541 | Game.Script.GRBroadcast(PSF_OnHostilityChange, pPars: {C4VInt(iVal: iPlr), C4VInt(iVal: iPlr2), C4VBool(fVal: fHostile), C4VBool(fVal: fOldHostility)}, fPassError: true); |
| 2542 | return true; |
| 2543 | } |
| 2544 | |
| 2545 | static bool FnSetPlrView(C4AulContext *cthr, C4ValueInt iPlr, C4Object *tobj) |
| 2546 | { |
| 2547 | if (!ValidPlr(plr: iPlr)) return false; |
| 2548 | Game.Players.Get(iPlayer: iPlr)->SetViewMode(iMode: C4PVM_Target, pTarget: tobj); |
| 2549 | return true; |
| 2550 | } |
| 2551 | |
| 2552 | static bool FnSetPlrShowControl(C4AulContext *cthr, C4ValueInt iPlr, C4String *defstring) |
| 2553 | { |
| 2554 | if (!ValidPlr(plr: iPlr)) return false; |
| 2555 | Game.Players.Get(iPlayer: iPlr)->ShowControl = StringBitEval(str: FnStringPar(pString: defstring)); |
| 2556 | return true; |
| 2557 | } |
| 2558 | |
| 2559 | static bool FnSetPlrShowCommand(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iCom) |
| 2560 | { |
| 2561 | if (!ValidPlr(plr: iPlr)) return false; |
| 2562 | Game.Players.Get(iPlayer: iPlr)->FlashCom = iCom; |
| 2563 | if (!Config.Graphics.ShowCommands) Config.Graphics.ShowCommands = true; |
| 2564 | return true; |
| 2565 | } |
| 2566 | |
| 2567 | static bool FnSetPlrShowControlPos(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt pos) |
| 2568 | { |
| 2569 | if (!ValidPlr(plr: iPlr)) return false; |
| 2570 | Game.Players.Get(iPlayer: iPlr)->ShowControlPos = pos; |
| 2571 | return true; |
| 2572 | } |
| 2573 | |
| 2574 | static C4String *FnGetPlrControlName(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iCon, bool fShort) |
| 2575 | { |
| 2576 | return String(str: PlrControlKeyName(iPlayer: iPlr, iControl: iCon, fShort).c_str()); |
| 2577 | } |
| 2578 | |
| 2579 | static C4ValueInt FnGetPlrJumpAndRunControl(C4AulContext *cthr, C4ValueInt iPlr) |
| 2580 | { |
| 2581 | C4Player *plr = Game.Players.Get(iPlayer: iPlr); |
| 2582 | return plr ? plr->ControlStyle : -1; |
| 2583 | } |
| 2584 | |
| 2585 | static C4ValueInt FnGetPlrViewMode(C4AulContext *cthr, C4ValueInt iPlr) |
| 2586 | { |
| 2587 | if (!ValidPlr(plr: iPlr)) return -1; |
| 2588 | if (Game.Control.SyncMode()) return -1; |
| 2589 | return Game.Players.Get(iPlayer: iPlr)->ViewMode; |
| 2590 | } |
| 2591 | |
| 2592 | static C4Object *FnGetPlrView(C4AulContext *cthr, C4ValueInt iPlr) |
| 2593 | { |
| 2594 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2595 | if (!pPlr || pPlr->ViewMode != C4PVM_Target) return nullptr; |
| 2596 | return pPlr->ViewTarget; |
| 2597 | } |
| 2598 | |
| 2599 | static bool FnDoHomebaseMaterial(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iChange) |
| 2600 | { |
| 2601 | // validity check |
| 2602 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2603 | if (!pPlr) return false; |
| 2604 | C4Def *pDef = C4Id2Def(id); |
| 2605 | if (!pDef) return false; |
| 2606 | // add to material |
| 2607 | C4ValueInt iLastcount = pPlr->HomeBaseMaterial.GetIDCount(id); |
| 2608 | if (!pPlr->HomeBaseMaterial.SetIDCount(id, count: iLastcount + iChange, addNewID: true)) return false; |
| 2609 | if (Game.Rules & C4RULE_TeamHombase) pPlr->SyncHomebaseMaterialToTeam(); |
| 2610 | return true; |
| 2611 | } |
| 2612 | |
| 2613 | static bool FnDoHomebaseProduction(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iChange) |
| 2614 | { |
| 2615 | // validity check |
| 2616 | if (!ValidPlr(plr: iPlr)) return false; |
| 2617 | C4Def *pDef = C4Id2Def(id); |
| 2618 | if (!pDef) return false; |
| 2619 | // add to material |
| 2620 | C4ValueInt iLastcount = Game.Players.Get(iPlayer: iPlr)->HomeBaseProduction.GetIDCount(id); |
| 2621 | return Game.Players.Get(iPlayer: iPlr)->HomeBaseProduction.SetIDCount(id, count: iLastcount + iChange, addNewID: true); |
| 2622 | } |
| 2623 | |
| 2624 | static std::optional<C4ValueInt> FnGetPlrDownDouble(C4AulContext *cthr, C4ValueInt iPlr) |
| 2625 | { |
| 2626 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2627 | return Game.Players.Get(iPlayer: iPlr)->LastComDownDouble; |
| 2628 | } |
| 2629 | |
| 2630 | static bool FnClearLastPlrCom(C4AulContext *cthr, C4ValueInt iPlr) |
| 2631 | { |
| 2632 | // get player |
| 2633 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2634 | if (!pPlr) return false; |
| 2635 | // reset last coms |
| 2636 | pPlr->LastCom = COM_None; |
| 2637 | pPlr->LastComDownDouble = 0; |
| 2638 | // done, success |
| 2639 | return true; |
| 2640 | } |
| 2641 | |
| 2642 | static bool FnSetPlrKnowledge(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, bool fRemove) |
| 2643 | { |
| 2644 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2645 | if (!pPlr) return false; |
| 2646 | if (fRemove) |
| 2647 | { |
| 2648 | C4ValueInt iIndex = pPlr->Knowledge.GetIndex(id); |
| 2649 | if (iIndex < 0) return false; |
| 2650 | return pPlr->Knowledge.DeleteItem(iIndex); |
| 2651 | } |
| 2652 | else |
| 2653 | { |
| 2654 | if (!C4Id2Def(id)) return false; |
| 2655 | return pPlr->Knowledge.SetIDCount(id, count: 1, addNewID: true); |
| 2656 | } |
| 2657 | } |
| 2658 | |
| 2659 | static bool FnSetComponent(C4AulContext *cthr, C4ID idComponent, C4ValueInt iCount, C4Object *pObj) |
| 2660 | { |
| 2661 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 2662 | return pObj->Component.SetIDCount(id: idComponent, count: iCount, addNewID: true); |
| 2663 | } |
| 2664 | |
| 2665 | static C4Value FnGetPlrKnowledge(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iIndex, C4ValueInt dwCategory) |
| 2666 | { |
| 2667 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 2668 | // Search by id, check if available, return bool |
| 2669 | if (id) return C4VBool(fVal: Game.Players.Get(iPlayer: iPlr)->Knowledge.GetIDCount(id, zeroDefVal: 1) != 0); |
| 2670 | // Search indexed item of given category, return C4ID |
| 2671 | return C4VID(idVal: Game.Players.Get(iPlayer: iPlr)->Knowledge.GetID(rDefs&: Game.Defs, dwCategory, index: iIndex)); |
| 2672 | } |
| 2673 | |
| 2674 | static C4ID FnGetDefinition(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt dwCategory) |
| 2675 | { |
| 2676 | C4Def *pDef; |
| 2677 | // Default: all categories |
| 2678 | if (!dwCategory) dwCategory = C4D_All; |
| 2679 | // Get def |
| 2680 | if (!(pDef = Game.Defs.GetDef(index: iIndex, category: dwCategory))) return C4ID_None; |
| 2681 | // Return id |
| 2682 | return pDef->id; |
| 2683 | } |
| 2684 | |
| 2685 | static C4Value FnGetComponent(C4AulContext *cthr, C4ID idComponent, C4ValueInt iIndex, C4Object *pObj, C4ID idDef) |
| 2686 | { |
| 2687 | // Def component - as seen by scope object as builder |
| 2688 | if (idDef) |
| 2689 | { |
| 2690 | // Get def |
| 2691 | C4Def *pDef = C4Id2Def(id: idDef); |
| 2692 | if (!pDef) return C4VNull; |
| 2693 | // Component count |
| 2694 | if (idComponent) return C4VInt(iVal: pDef->GetComponentCount(idComponent, pBuilder: cthr->Obj)); |
| 2695 | // Indexed component |
| 2696 | return C4VID(idVal: pDef->GetIndexedComponent(idx: iIndex, pBuilder: cthr->Obj)); |
| 2697 | } |
| 2698 | // Object component |
| 2699 | else |
| 2700 | { |
| 2701 | // Get object |
| 2702 | if (!pObj) pObj = cthr->Obj; |
| 2703 | if (!pObj) return C4VNull; |
| 2704 | // Component count |
| 2705 | if (idComponent) return C4VInt(iVal: pObj->Component.GetIDCount(id: idComponent)); |
| 2706 | // Indexed component |
| 2707 | return C4VID(idVal: pObj->Component.GetID(index: iIndex)); |
| 2708 | } |
| 2709 | } |
| 2710 | |
| 2711 | static C4Value FnGetHomebaseMaterial(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iIndex, C4ValueInt dwCategory) |
| 2712 | { |
| 2713 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 2714 | // Search by id, return available count |
| 2715 | if (id) return C4VInt(iVal: Game.Players.Get(iPlayer: iPlr)->HomeBaseMaterial.GetIDCount(id)); |
| 2716 | // Search indexed item of given category, return C4ID |
| 2717 | return C4VID(idVal: Game.Players.Get(iPlayer: iPlr)->HomeBaseMaterial.GetID(rDefs&: Game.Defs, dwCategory, index: iIndex)); |
| 2718 | } |
| 2719 | |
| 2720 | static C4Value FnGetHomebaseProduction(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iIndex, C4ValueInt dwCategory) |
| 2721 | { |
| 2722 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 2723 | // Search by id, return available count |
| 2724 | if (id) return C4VInt(iVal: Game.Players.Get(iPlayer: iPlr)->HomeBaseProduction.GetIDCount(id)); |
| 2725 | // Search indexed item of given category, return C4ID |
| 2726 | return C4VID(idVal: Game.Players.Get(iPlayer: iPlr)->HomeBaseProduction.GetID(rDefs&: Game.Defs, dwCategory, index: iIndex)); |
| 2727 | } |
| 2728 | |
| 2729 | static C4ValueInt FnSetPlrMagic(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, bool fRemove) |
| 2730 | { |
| 2731 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2732 | if (!pPlr) return false; |
| 2733 | if (fRemove) |
| 2734 | { |
| 2735 | C4ValueInt iIndex = pPlr->Magic.GetIndex(id); |
| 2736 | if (iIndex < 0) return false; |
| 2737 | return pPlr->Magic.DeleteItem(iIndex); |
| 2738 | } |
| 2739 | else |
| 2740 | { |
| 2741 | if (!C4Id2Def(id)) return false; |
| 2742 | return pPlr->Magic.SetIDCount(id, count: 1, addNewID: true); |
| 2743 | } |
| 2744 | } |
| 2745 | |
| 2746 | static C4Value FnGetPlrMagic(C4AulContext *cthr, C4ValueInt iPlr, C4ID id, C4ValueInt iIndex) |
| 2747 | { |
| 2748 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 2749 | // Search by id, check if available, return bool |
| 2750 | if (id) return C4VBool(fVal: Game.Players.Get(iPlayer: iPlr)->Magic.GetIDCount(id, zeroDefVal: 1) != 0); |
| 2751 | // Search indexed item of given category, return C4ID |
| 2752 | return C4VID(idVal: Game.Players.Get(iPlayer: iPlr)->Magic.GetID(rDefs&: Game.Defs, dwCategory: C4D_Magic, index: iIndex)); |
| 2753 | } |
| 2754 | |
| 2755 | static std::optional<C4ValueInt> FnGetWealth(C4AulContext *cthr, C4ValueInt iPlr) |
| 2756 | { |
| 2757 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2758 | return {Game.Players.Get(iPlayer: iPlr)->Wealth}; |
| 2759 | } |
| 2760 | |
| 2761 | static bool FnSetWealth(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iValue) |
| 2762 | { |
| 2763 | if (!ValidPlr(plr: iPlr)) return false; |
| 2764 | Game.Players.Get(iPlayer: iPlr)->Wealth = BoundBy<C4ValueInt>(bval: iValue, lbound: 0, rbound: 100000); |
| 2765 | return true; |
| 2766 | } |
| 2767 | |
| 2768 | static C4ValueInt FnDoScore(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iChange) |
| 2769 | { |
| 2770 | if (!ValidPlr(plr: iPlr)) return false; |
| 2771 | return Game.Players.Get(iPlayer: iPlr)->DoPoints(iChange); |
| 2772 | } |
| 2773 | |
| 2774 | static std::optional<C4ValueInt> FnGetPlrValue(C4AulContext *cthr, C4ValueInt iPlr) |
| 2775 | { |
| 2776 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2777 | return {Game.Players.Get(iPlayer: iPlr)->Value}; |
| 2778 | } |
| 2779 | |
| 2780 | static std::optional<C4ValueInt> FnGetPlrValueGain(C4AulContext *cthr, C4ValueInt iPlr) |
| 2781 | { |
| 2782 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2783 | return {Game.Players.Get(iPlayer: iPlr)->ValueGain}; |
| 2784 | } |
| 2785 | |
| 2786 | static std::optional<C4ValueInt> FnGetScore(C4AulContext *cthr, C4ValueInt iPlr) |
| 2787 | { |
| 2788 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2789 | return {Game.Players.Get(iPlayer: iPlr)->Points}; |
| 2790 | } |
| 2791 | |
| 2792 | static C4Object *FnGetHiRank(C4AulContext *cthr, C4ValueInt iPlr) |
| 2793 | { |
| 2794 | if (!ValidPlr(plr: iPlr)) return nullptr; |
| 2795 | return Game.Players.Get(iPlayer: iPlr)->GetHiRankActiveCrew(fSelectedOnly: false); |
| 2796 | } |
| 2797 | |
| 2798 | static C4Object *FnGetCrew(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt index) |
| 2799 | { |
| 2800 | if (!ValidPlr(plr: iPlr)) return nullptr; |
| 2801 | return Game.Players.Get(iPlayer: iPlr)->Crew.GetObject(Index: index); |
| 2802 | } |
| 2803 | |
| 2804 | static std::optional<C4ValueInt> FnGetCrewCount(C4AulContext *cthr, C4ValueInt iPlr) |
| 2805 | { |
| 2806 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2807 | return {Game.Players.Get(iPlayer: iPlr)->Crew.ObjectCount()}; |
| 2808 | } |
| 2809 | |
| 2810 | static C4ValueInt FnGetPlayerCount(C4AulContext *cthr, C4ValueInt iType) |
| 2811 | { |
| 2812 | if (!iType) |
| 2813 | return Game.Players.GetCount(); |
| 2814 | else |
| 2815 | return Game.Players.GetCount(eType: static_cast<C4PlayerType>(iType)); |
| 2816 | } |
| 2817 | |
| 2818 | static C4ValueInt FnGetPlayerByIndex(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt iType) |
| 2819 | { |
| 2820 | C4Player *pPlayer; |
| 2821 | if (iType) |
| 2822 | pPlayer = Game.Players.GetByIndex(iIndex, eType: static_cast<C4PlayerType>(iType)); |
| 2823 | else |
| 2824 | pPlayer = Game.Players.GetByIndex(iIndex); |
| 2825 | if (!pPlayer) return NO_OWNER; |
| 2826 | return pPlayer->Number; |
| 2827 | } |
| 2828 | |
| 2829 | static C4ValueInt FnEliminatePlayer(C4AulContext *cthr, C4ValueInt iPlr, bool fRemoveDirect) |
| 2830 | { |
| 2831 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2832 | if (!pPlr) return false; |
| 2833 | // direct removal? |
| 2834 | if (fRemoveDirect) |
| 2835 | { |
| 2836 | // do direct removal (no fate) |
| 2837 | if (Game.Control.isCtrlHost()) Game.Players.CtrlRemove(iPlayer: iPlr, fDisonnected: false); |
| 2838 | return true; |
| 2839 | } |
| 2840 | else |
| 2841 | { |
| 2842 | // do regular elimination |
| 2843 | if (pPlr->Eliminated) return false; |
| 2844 | pPlr->Eliminate(); |
| 2845 | } |
| 2846 | return true; |
| 2847 | } |
| 2848 | |
| 2849 | static bool FnSurrenderPlayer(C4AulContext *cthr, C4ValueInt iPlr) |
| 2850 | { |
| 2851 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2852 | if (!pPlr) return false; |
| 2853 | if (pPlr->Eliminated) return false; |
| 2854 | pPlr->Surrender(); |
| 2855 | return true; |
| 2856 | } |
| 2857 | |
| 2858 | static bool FnSetLeaguePerformance(C4AulContext *cthr, C4ValueInt iScore, C4ValueInt idPlayer) |
| 2859 | { |
| 2860 | if (!Game.Parameters.isLeague()) return false; |
| 2861 | if (idPlayer && !Game.PlayerInfos.GetPlayerInfoByID(id: idPlayer)) return false; |
| 2862 | Game.RoundResults.SetLeaguePerformance(iNewPerf: iScore, idPlayer); |
| 2863 | return true; |
| 2864 | } |
| 2865 | |
| 2866 | static bool FnSetLeagueProgressData(C4AulContext *cthr, C4String *pNewData, C4ValueInt idPlayer) |
| 2867 | { |
| 2868 | if (!Game.Parameters.League.getLength()) return false; |
| 2869 | C4PlayerInfo *info = Game.PlayerInfos.GetPlayerInfoByID(id: idPlayer); |
| 2870 | if (!info) return false; |
| 2871 | info->SetLeagueProgressData(pNewData ? pNewData->Data.getData() : nullptr); |
| 2872 | return true; |
| 2873 | } |
| 2874 | |
| 2875 | static C4String *FnGetLeagueProgressData(C4AulContext *cthr, C4ValueInt idPlayer) |
| 2876 | { |
| 2877 | if (!Game.Parameters.League.getLength()) return nullptr; |
| 2878 | C4PlayerInfo *info = Game.PlayerInfos.GetPlayerInfoByID(id: idPlayer); |
| 2879 | if (!info) return nullptr; |
| 2880 | return String(str: info->GetLeagueProgressData()); |
| 2881 | } |
| 2882 | |
| 2883 | static const int32_t CSPF_FixedAttributes = 1 << 0, |
| 2884 | CSPF_NoScenarioInit = 1 << 1, |
| 2885 | CSPF_NoEliminationCheck = 1 << 2, |
| 2886 | CSPF_Invisible = 1 << 3; |
| 2887 | |
| 2888 | static bool FnCreateScriptPlayer(C4AulContext *cthr, C4String *szName, C4ValueInt dwColor, C4ValueInt idTeam, C4ValueInt dwFlags, C4ID ) |
| 2889 | { |
| 2890 | // safety |
| 2891 | if (!szName || !szName->Data.getLength()) return false; |
| 2892 | // this script command puts a new script player info into the list |
| 2893 | // the actual join will be delayed and synchronized via queue |
| 2894 | // processed by control host only - clients/replay/etc. will perform the join via queue |
| 2895 | if (!Game.Control.isCtrlHost()) return true; |
| 2896 | C4PlayerInfo *pScriptPlrInfo = new C4PlayerInfo(); |
| 2897 | uint32_t dwInfoFlags = 0u; |
| 2898 | if (dwFlags & CSPF_FixedAttributes) dwInfoFlags |= C4PlayerInfo::PIF_AttributesFixed; |
| 2899 | if (dwFlags & CSPF_NoScenarioInit) dwInfoFlags |= C4PlayerInfo::PIF_NoScenarioInit; |
| 2900 | if (dwFlags & CSPF_NoEliminationCheck) dwInfoFlags |= C4PlayerInfo::PIF_NoEliminationCheck; |
| 2901 | if (dwFlags & CSPF_Invisible) dwInfoFlags |= C4PlayerInfo::PIF_Invisible; |
| 2902 | pScriptPlrInfo->SetAsScriptPlayer(szName: szName->Data.getData(), dwColor, dwFlags: dwInfoFlags, idExtra); |
| 2903 | pScriptPlrInfo->SetTeam(idTeam); |
| 2904 | C4ClientPlayerInfos JoinPkt(nullptr, true, pScriptPlrInfo); |
| 2905 | // add to queue! |
| 2906 | Game.PlayerInfos.DoPlayerInfoUpdate(pUpdate: &JoinPkt); |
| 2907 | // always successful for sync reasons |
| 2908 | return true; |
| 2909 | } |
| 2910 | |
| 2911 | static C4Object *FnGetCursor(C4AulContext *cthr, C4ValueInt iPlr, C4ValueInt iIndex) |
| 2912 | { |
| 2913 | // get player |
| 2914 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2915 | // invalid player? |
| 2916 | if (!pPlr) return nullptr; |
| 2917 | // first index is always the cursor |
| 2918 | if (!iIndex) return pPlr->Cursor; |
| 2919 | // iterate through selected crew for iIndex times |
| 2920 | // status needs not be checked, as dead objects are never in Crew list |
| 2921 | C4Object *pCrew; |
| 2922 | for (C4ObjectLink *pLnk = pPlr->Crew.First; pLnk; pLnk = pLnk->Next) |
| 2923 | // get crew object |
| 2924 | if (pCrew = pLnk->Obj) |
| 2925 | // is it selected? |
| 2926 | if (pCrew->Select) |
| 2927 | // is it not the cursor? (which is always first) |
| 2928 | if (pCrew != pPlr->Cursor) |
| 2929 | // enough searched? |
| 2930 | if (!--iIndex) |
| 2931 | // return it |
| 2932 | return pCrew; |
| 2933 | // nothing found at that index |
| 2934 | return nullptr; |
| 2935 | } |
| 2936 | |
| 2937 | static C4Object *FnGetViewCursor(C4AulContext *cthr, C4ValueInt iPlr) |
| 2938 | { |
| 2939 | // get player |
| 2940 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2941 | // get viewcursor |
| 2942 | return pPlr ? pPlr->ViewCursor.Object() : nullptr; |
| 2943 | } |
| 2944 | |
| 2945 | static C4Object *FnGetCaptain(C4AulContext *cthr, C4ValueInt iPlr) |
| 2946 | { |
| 2947 | if (!ValidPlr(plr: iPlr)) return nullptr; |
| 2948 | return Game.Players.Get(iPlayer: iPlr)->Captain; |
| 2949 | } |
| 2950 | |
| 2951 | static bool FnSetCursor(C4AulContext *cthr, C4ValueInt iPlr, C4Object *pObj, bool fNoSelectMark, bool fNoSelectArrow, bool fNoSelectCrew) |
| 2952 | { |
| 2953 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2954 | if (!pPlr || (pObj && !pObj->Status)) return false; |
| 2955 | pPlr->SetCursor(pObj, fSelectFlash: !fNoSelectMark, fSelectArrow: !fNoSelectArrow); |
| 2956 | if (!fNoSelectCrew) pPlr->SelectCrew(pObj, fSelect: true); |
| 2957 | return true; |
| 2958 | } |
| 2959 | |
| 2960 | static bool FnSetViewCursor(C4AulContext *cthr, C4ValueInt iPlr, C4Object *pObj) |
| 2961 | { |
| 2962 | // get player |
| 2963 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2964 | // invalid player? |
| 2965 | if (!pPlr) return false; |
| 2966 | // set viewcursor |
| 2967 | pPlr->ViewCursor = pObj; |
| 2968 | return true; |
| 2969 | } |
| 2970 | |
| 2971 | static bool FnSelectCrew(C4AulContext *cthr, C4ValueInt iPlr, C4Object *pObj, bool fSelect, bool fNoCursorAdjust) |
| 2972 | { |
| 2973 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2974 | if (!pPlr || !pObj) return false; |
| 2975 | if (fNoCursorAdjust) |
| 2976 | { |
| 2977 | if (fSelect) pObj->DoSelect(); else pObj->UnSelect(); |
| 2978 | } |
| 2979 | else |
| 2980 | pPlr->SelectCrew(pObj, fSelect); |
| 2981 | return true; |
| 2982 | } |
| 2983 | |
| 2984 | static std::optional<C4ValueInt> FnGetSelectCount(C4AulContext *cthr, C4ValueInt iPlr) |
| 2985 | { |
| 2986 | if (!ValidPlr(plr: iPlr)) return {}; |
| 2987 | return {Game.Players.Get(iPlayer: iPlr)->SelectCount}; |
| 2988 | } |
| 2989 | |
| 2990 | static C4ValueInt FnSetCrewStatus(C4AulContext *cthr, C4ValueInt iPlr, bool fInCrew, C4Object *pObj) |
| 2991 | { |
| 2992 | // validate player |
| 2993 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 2994 | if (!pPlr) return false; |
| 2995 | // validate object / local call |
| 2996 | if (!pObj) if (!(pObj = cthr->Obj)) return false; |
| 2997 | // set crew status |
| 2998 | return pPlr->SetObjectCrewStatus(pCrew: pObj, fNewStatus: fInCrew); |
| 2999 | } |
| 3000 | |
| 3001 | static C4ValueInt FnGetWind(C4AulContext *cthr, C4ValueInt x, C4ValueInt y, bool fGlobal) |
| 3002 | { |
| 3003 | // global wind |
| 3004 | if (fGlobal) return Game.Weather.Wind; |
| 3005 | // local wind |
| 3006 | if (cthr->Obj) { x += cthr->Obj->x; y += cthr->Obj->y; } |
| 3007 | return Game.Weather.GetWind(x, y); |
| 3008 | } |
| 3009 | |
| 3010 | static void FnSetWind(C4AulContext *cthr, C4ValueInt iWind) |
| 3011 | { |
| 3012 | Game.Weather.SetWind(iWind); |
| 3013 | } |
| 3014 | |
| 3015 | static void FnSetTemperature(C4AulContext *cthr, C4ValueInt iTemperature) |
| 3016 | { |
| 3017 | Game.Weather.SetTemperature(iTemperature); |
| 3018 | } |
| 3019 | |
| 3020 | static C4ValueInt FnGetTemperature(C4AulContext *cthr) |
| 3021 | { |
| 3022 | return Game.Weather.GetTemperature(); |
| 3023 | } |
| 3024 | |
| 3025 | static void FnSetSeason(C4AulContext *cthr, C4ValueInt iSeason) |
| 3026 | { |
| 3027 | Game.Weather.SetSeason(iSeason); |
| 3028 | } |
| 3029 | |
| 3030 | static C4ValueInt FnGetSeason(C4AulContext *cthr) |
| 3031 | { |
| 3032 | return Game.Weather.GetSeason(); |
| 3033 | } |
| 3034 | |
| 3035 | static void FnSetClimate(C4AulContext *cthr, C4ValueInt iClimate) |
| 3036 | { |
| 3037 | Game.Weather.SetClimate(iClimate); |
| 3038 | } |
| 3039 | |
| 3040 | static C4ValueInt FnGetClimate(C4AulContext *cthr) |
| 3041 | { |
| 3042 | return Game.Weather.GetClimate(); |
| 3043 | } |
| 3044 | |
| 3045 | static void FnSetSkyFade(C4AulContext *cthr, C4ValueInt iFromRed, C4ValueInt iFromGreen, C4ValueInt iFromBlue, C4ValueInt iToRed, C4ValueInt iToGreen, C4ValueInt iToBlue) |
| 3046 | { |
| 3047 | // newgfx: set modulation |
| 3048 | uint32_t dwBack, dwMod = GetClrModulation(src: Game.Landscape.Sky.FadeClr1, C4RGB(iFromRed, iFromGreen, iFromBlue), back&: dwBack); |
| 3049 | Game.Landscape.Sky.SetModulation(dwWithClr: dwMod, dwBackClr: dwBack); |
| 3050 | } |
| 3051 | |
| 3052 | static void FnSetSkyColor(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt iRed, C4ValueInt iGreen, C4ValueInt iBlue) |
| 3053 | { |
| 3054 | // set first index only |
| 3055 | if (iIndex) return; |
| 3056 | // get color difference |
| 3057 | uint32_t dwBack, dwMod = GetClrModulation(src: Game.Landscape.Sky.FadeClr1, C4RGB(iRed, iGreen, iBlue), back&: dwBack); |
| 3058 | Game.Landscape.Sky.SetModulation(dwWithClr: dwMod, dwBackClr: dwBack); |
| 3059 | // success |
| 3060 | } |
| 3061 | |
| 3062 | static C4ValueInt FnGetSkyColor(C4AulContext *cthr, C4ValueInt iIndex, C4ValueInt iRGB) |
| 3063 | { |
| 3064 | // relict from OldGfx |
| 3065 | if (iIndex || !Inside<C4ValueInt>(ival: iRGB, lbound: 0, rbound: 2)) return 0; |
| 3066 | uint32_t dwClr = Game.Landscape.Sky.FadeClr1; |
| 3067 | BltAlpha(dst&: dwClr, src: Game.Landscape.Sky.FadeClr2 | ((iIndex * 0xff / 19) << 24)); |
| 3068 | switch (iRGB) |
| 3069 | { |
| 3070 | case 0: return (dwClr >> 16) & 0xff; |
| 3071 | case 1: return (dwClr >> 8) & 0xff; |
| 3072 | case 2: return dwClr & 0xff; |
| 3073 | default: return 0; |
| 3074 | } |
| 3075 | } |
| 3076 | |
| 3077 | static C4ValueInt FnLandscapeWidth(C4AulContext *cthr) |
| 3078 | { |
| 3079 | return GBackWdt; |
| 3080 | } |
| 3081 | |
| 3082 | static C4ValueInt FnLandscapeHeight(C4AulContext *cthr) |
| 3083 | { |
| 3084 | return GBackHgt; |
| 3085 | } |
| 3086 | |
| 3087 | static C4ValueInt FnLaunchLightning(C4AulContext *cthr, C4ValueInt x, C4ValueInt y, C4ValueInt xdir, C4ValueInt xrange, C4ValueInt ydir, C4ValueInt yrange, bool fDoGamma) |
| 3088 | { |
| 3089 | return Game.Weather.LaunchLightning(x, y, xdir, xrange, ydir, yrange, fDoGamma); |
| 3090 | } |
| 3091 | |
| 3092 | static C4ValueInt FnLaunchVolcano(C4AulContext *cthr, C4ValueInt x) |
| 3093 | { |
| 3094 | return Game.Weather.LaunchVolcano( |
| 3095 | mat: Game.Material.Get(szMaterial: "Lava" ), |
| 3096 | x, GBackHgt - 1, |
| 3097 | size: BoundBy(bval: 15 * GBackHgt / 500 + Random(iRange: 10), lbound: 10, rbound: 60)); |
| 3098 | } |
| 3099 | |
| 3100 | static void FnLaunchEarthquake(C4AulContext *cthr, C4ValueInt x, C4ValueInt y) |
| 3101 | { |
| 3102 | Game.Weather.LaunchEarthquake(iX: x, iY: y); |
| 3103 | } |
| 3104 | |
| 3105 | static void FnShakeFree(C4AulContext *cthr, C4ValueInt x, C4ValueInt y, C4ValueInt rad) |
| 3106 | { |
| 3107 | Game.Landscape.ShakeFree(tx: x, ty: y, rad); |
| 3108 | } |
| 3109 | |
| 3110 | static void FnShakeObjects(C4AulContext *cthr, C4ValueInt x, C4ValueInt y, C4ValueInt rad) |
| 3111 | { |
| 3112 | Game.ShakeObjects(tx: x, ry: y, range: rad, iCausedBy: cthr->Obj ? cthr->Obj->Controller : NO_OWNER); |
| 3113 | } |
| 3114 | |
| 3115 | static void FnDigFree(C4AulContext *cthr, C4ValueInt x, C4ValueInt y, C4ValueInt rad, bool fRequest) |
| 3116 | { |
| 3117 | Game.Landscape.DigFree(tx: x, ty: y, rad, fRequest, pByObj: cthr->Obj); |
| 3118 | } |
| 3119 | |
| 3120 | static void FnDigFreeRect(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, bool fRequest) |
| 3121 | { |
| 3122 | Game.Landscape.DigFreeRect(tx: iX, ty: iY, wdt: iWdt, hgt: iHgt, fRequest, pByObj: cthr->Obj); |
| 3123 | } |
| 3124 | |
| 3125 | static void FnFreeRect(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4ValueInt iFreeDensity) |
| 3126 | { |
| 3127 | if (iFreeDensity) |
| 3128 | Game.Landscape.ClearRectDensity(iTx: iX, iTy: iY, iWdt, iHgt, iOfDensity: iFreeDensity); |
| 3129 | else |
| 3130 | Game.Landscape.ClearRect(iTx: iX, iTy: iY, iWdt, iHgt); |
| 3131 | } |
| 3132 | |
| 3133 | static bool FnPathFree(C4AulContext *cthr, C4ValueInt X1, C4ValueInt Y1, C4ValueInt X2, C4ValueInt Y2) |
| 3134 | { |
| 3135 | return !!PathFree(x1: X1, y1: Y1, x2: X2, y2: Y2); |
| 3136 | } |
| 3137 | |
| 3138 | static bool FnPathFree2(C4AulContext *cthr, C4Value *X1, C4Value *Y1, C4ValueInt X2, C4ValueInt Y2) |
| 3139 | { |
| 3140 | int32_t x = -1, y = -1; |
| 3141 | // Do not use getInt on the references, because it destroys them. |
| 3142 | bool r = PathFree(x1: X1->GetRefVal().getInt(), y1: Y1->GetRefVal().getInt(), x2: X2, y2: Y2, ix: &x, iy: &y); |
| 3143 | if (!r) |
| 3144 | { |
| 3145 | *X1 = C4VInt(iVal: x); |
| 3146 | *Y1 = C4VInt(iVal: y); |
| 3147 | } |
| 3148 | return r; |
| 3149 | } |
| 3150 | |
| 3151 | static C4ValueInt FnSetTransferZone(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4Object *pObj) |
| 3152 | { |
| 3153 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3154 | iX += pObj->x; iY += pObj->y; |
| 3155 | return Game.TransferZones.Set(iX, iY, iWdt, iHgt, pObj); |
| 3156 | } |
| 3157 | |
| 3158 | static bool FnNot(C4AulContext *cthr, bool fCondition) |
| 3159 | { |
| 3160 | return !fCondition; |
| 3161 | } |
| 3162 | |
| 3163 | static bool FnOr(C4AulContext *cthr, bool fCon1, bool fCon2, bool fCon3, bool fCon4, bool fCon5) |
| 3164 | { |
| 3165 | return (fCon1 || fCon2 || fCon3 || fCon4 || fCon5); |
| 3166 | } |
| 3167 | |
| 3168 | static bool FnAnd(C4AulContext *cthr, bool fCon1, bool fCon2) |
| 3169 | { |
| 3170 | return (fCon1 && fCon2); |
| 3171 | } |
| 3172 | |
| 3173 | static C4ValueInt FnBitAnd(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3174 | { |
| 3175 | return (iVal1 & iVal2); |
| 3176 | } |
| 3177 | |
| 3178 | static bool FnEqual(C4AulContext *cthr, C4Value Val1, C4Value Val2) |
| 3179 | { |
| 3180 | return Val1.GetData() == Val2.GetData(); |
| 3181 | } |
| 3182 | |
| 3183 | static C4ValueInt FnLessThan(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3184 | { |
| 3185 | return (iVal1 < iVal2); |
| 3186 | } |
| 3187 | |
| 3188 | static C4ValueInt FnGreaterThan(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3189 | { |
| 3190 | return (iVal1 > iVal2); |
| 3191 | } |
| 3192 | |
| 3193 | static C4ValueInt FnSum(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2, C4ValueInt iVal3, C4ValueInt iVal4) |
| 3194 | { |
| 3195 | return (iVal1 + iVal2 + iVal3 + iVal4); |
| 3196 | } |
| 3197 | |
| 3198 | static C4ValueInt FnSub(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2, C4ValueInt iVal3, C4ValueInt iVal4) |
| 3199 | { |
| 3200 | return (iVal1 - iVal2 - iVal3 - iVal4); |
| 3201 | } |
| 3202 | |
| 3203 | static C4ValueInt FnAbs(C4AulContext *cthr, C4ValueInt iVal) |
| 3204 | { |
| 3205 | return Abs(val: iVal); |
| 3206 | } |
| 3207 | |
| 3208 | static C4ValueInt FnMul(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3209 | { |
| 3210 | return (iVal1 * iVal2); |
| 3211 | } |
| 3212 | |
| 3213 | static C4ValueInt FnDiv(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3214 | { |
| 3215 | if (!iVal2) return 0; |
| 3216 | return (iVal1 / iVal2); |
| 3217 | } |
| 3218 | |
| 3219 | static C4ValueInt FnMod(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3220 | { |
| 3221 | if (!iVal2) return 0; |
| 3222 | return (iVal1 % iVal2); |
| 3223 | } |
| 3224 | |
| 3225 | static C4ValueInt FnPow(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3226 | { |
| 3227 | return Pow(base: iVal1, exponent: iVal2); |
| 3228 | } |
| 3229 | |
| 3230 | static C4ValueInt FnSin(C4AulContext *cthr, C4ValueInt iAngle, C4ValueInt iRadius, C4ValueInt iPrec) |
| 3231 | { |
| 3232 | if (!iPrec) iPrec = 1; |
| 3233 | // Precalculate the modulo operation so the C4Fixed argument to Sin does not overflow |
| 3234 | iAngle %= 360 * iPrec; |
| 3235 | // Let itofix and fixtoi handle the division and multiplication because that can handle higher ranges |
| 3236 | return fixtoi(x: Sin(fAngle: itofix(x: iAngle, prec: iPrec)), prec: iRadius); |
| 3237 | } |
| 3238 | |
| 3239 | static C4ValueInt FnCos(C4AulContext *cthr, C4ValueInt iAngle, C4ValueInt iRadius, C4ValueInt iPrec) |
| 3240 | { |
| 3241 | if (!iPrec) iPrec = 1; |
| 3242 | iAngle %= 360 * iPrec; |
| 3243 | return fixtoi(x: Cos(fAngle: itofix(x: iAngle, prec: iPrec)), prec: iRadius); |
| 3244 | } |
| 3245 | |
| 3246 | static C4ValueInt FnSqrt(C4AulContext *cthr, C4ValueInt iValue) |
| 3247 | { |
| 3248 | if (iValue < 0) return 0; |
| 3249 | C4ValueInt iSqrt = C4ValueInt(sqrt(x: double(iValue))); |
| 3250 | if (iSqrt * iSqrt < iValue) iSqrt++; |
| 3251 | if (iSqrt * iSqrt > iValue) iSqrt--; |
| 3252 | return iSqrt; |
| 3253 | } |
| 3254 | |
| 3255 | static C4ValueInt FnAngle(C4AulContext *cthr, C4ValueInt iX1, C4ValueInt iY1, C4ValueInt iX2, C4ValueInt iY2, C4ValueInt iPrec) |
| 3256 | { |
| 3257 | C4ValueInt iAngle; |
| 3258 | |
| 3259 | // Standard prec |
| 3260 | if (!iPrec) iPrec = 1; |
| 3261 | |
| 3262 | C4ValueInt dx = iX2 - iX1, dy = iY2 - iY1; |
| 3263 | if (!dx) if (dy > 0) return 180 * iPrec; else return 0; |
| 3264 | if (!dy) if (dx > 0) return 90 * iPrec; else return 270 * iPrec; |
| 3265 | |
| 3266 | iAngle = static_cast<C4ValueInt>(180.0 * iPrec * atan2(y: static_cast<double>(Abs(val: dy)), x: static_cast<double>(Abs(val: dx))) * std::numbers::inv_pi); |
| 3267 | |
| 3268 | if (iX2 > iX1) |
| 3269 | { |
| 3270 | if (iY2 < iY1) iAngle = (90 * iPrec) - iAngle; |
| 3271 | else iAngle = (90 * iPrec) + iAngle; |
| 3272 | } |
| 3273 | else |
| 3274 | { |
| 3275 | if (iY2 < iY1) iAngle = (270 * iPrec) + iAngle; |
| 3276 | else iAngle = (270 * iPrec) - iAngle; |
| 3277 | } |
| 3278 | |
| 3279 | return iAngle; |
| 3280 | } |
| 3281 | |
| 3282 | static C4ValueInt FnArcSin(C4AulContext *cthr, C4ValueInt iVal, C4ValueInt iRadius) |
| 3283 | { |
| 3284 | // safety |
| 3285 | if (!iRadius) return 0; |
| 3286 | if (iVal > iRadius) return 0; |
| 3287 | // calc arcsin |
| 3288 | double f1 = iVal; |
| 3289 | f1 = asin(x: f1 / iRadius) * 180.0 * std::numbers::inv_pi; |
| 3290 | // return rounded angle |
| 3291 | return static_cast<C4ValueInt>(floor(x: f1 + 0.5)); |
| 3292 | } |
| 3293 | |
| 3294 | static C4ValueInt FnArcCos(C4AulContext *cthr, C4ValueInt iVal, C4ValueInt iRadius) |
| 3295 | { |
| 3296 | // safety |
| 3297 | if (!iRadius) return 0; |
| 3298 | if (iVal > iRadius) return 0; |
| 3299 | // calc arccos |
| 3300 | double f1 = iVal; |
| 3301 | f1 = acos(x: f1 / iRadius) * 180.0 * std::numbers::inv_pi; |
| 3302 | // return rounded angle |
| 3303 | return static_cast<C4ValueInt>(floor(x: f1 + 0.5)); |
| 3304 | } |
| 3305 | |
| 3306 | static C4ValueInt FnMin(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3307 | { |
| 3308 | return (std::min)(a: iVal1, b: iVal2); |
| 3309 | } |
| 3310 | |
| 3311 | static C4ValueInt FnMax(C4AulContext *cthr, C4ValueInt iVal1, C4ValueInt iVal2) |
| 3312 | { |
| 3313 | return (std::max)(a: iVal1, b: iVal2); |
| 3314 | } |
| 3315 | |
| 3316 | static C4ValueInt FnDistance(C4AulContext *cthr, C4ValueInt iX1, C4ValueInt iY1, C4ValueInt iX2, C4ValueInt iY2) |
| 3317 | { |
| 3318 | return Distance(iX1, iY1, iX2, iY2); |
| 3319 | } |
| 3320 | |
| 3321 | static std::optional<C4ValueInt> FnObjectDistance(C4AulContext *cthr, C4Object *pObj2, C4Object *pObj) |
| 3322 | { |
| 3323 | if (!pObj) pObj = cthr->Obj; if (!pObj || !pObj2) return {}; |
| 3324 | return {Distance(iX1: pObj->x, iY1: pObj->y, iX2: pObj2->x, iY2: pObj2->y)}; |
| 3325 | } |
| 3326 | |
| 3327 | static std::optional<C4ValueInt> FnObjectNumber(C4AulContext *cthr, C4Object *pObj) |
| 3328 | { |
| 3329 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 3330 | return {pObj->Number}; |
| 3331 | } |
| 3332 | |
| 3333 | static C4Object *FnObject(C4AulContext *cthr, C4ValueInt iNumber) |
| 3334 | { |
| 3335 | return Game.Objects.SafeObjectPointer(iNumber); |
| 3336 | } |
| 3337 | |
| 3338 | static C4ValueInt FnShowInfo(C4AulContext *cthr, C4Object *pObj) |
| 3339 | { |
| 3340 | if (!cthr->Obj) return false; |
| 3341 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3342 | return cthr->Obj->ActivateMenu(iMenu: C4MN_Info, iMenuSelect: 0, iMenuData: 0, iMenuPosition: 0, pTarget: pObj); |
| 3343 | } |
| 3344 | |
| 3345 | static C4ValueInt FnBoundBy(C4AulContext *cthr, C4ValueInt iVal, C4ValueInt iRange1, C4ValueInt iRange2) |
| 3346 | { |
| 3347 | return BoundBy(bval: iVal, lbound: iRange1, rbound: iRange2); |
| 3348 | } |
| 3349 | |
| 3350 | static bool FnInside(C4AulContext *cthr, C4ValueInt iVal, C4ValueInt iRange1, C4ValueInt iRange2) |
| 3351 | { |
| 3352 | return Inside(ival: iVal, lbound: iRange1, rbound: iRange2); |
| 3353 | } |
| 3354 | |
| 3355 | static C4ValueInt FnSEqual(C4AulContext *cthr, C4String *szString1, C4String *szString2) |
| 3356 | { |
| 3357 | if (szString1 == szString2) return true; |
| 3358 | return SEqual(szStr1: FnStringPar(pString: szString1), szStr2: FnStringPar(pString: szString2)); |
| 3359 | } |
| 3360 | |
| 3361 | static C4ValueInt FnRandom(C4AulContext *cthr, C4ValueInt iRange) |
| 3362 | { |
| 3363 | return Random(iRange); |
| 3364 | } |
| 3365 | |
| 3366 | static C4ValueInt FnAsyncRandom(C4AulContext *cthr, C4ValueInt iRange) |
| 3367 | { |
| 3368 | return SafeRandom(range: iRange); |
| 3369 | } |
| 3370 | |
| 3371 | static C4Value FnSetVar(C4AulContext *cthr, C4ValueInt iVarIndex, C4Value iValue) |
| 3372 | { |
| 3373 | if (!cthr->Caller) return C4VNull; |
| 3374 | cthr->Caller->NumVars[iVarIndex] = iValue; |
| 3375 | return iValue; |
| 3376 | } |
| 3377 | |
| 3378 | static C4Value FnIncVar(C4AulContext *cthr, C4ValueInt iVarIndex) |
| 3379 | { |
| 3380 | if (!cthr->Caller) return C4VNull; |
| 3381 | return ++cthr->Caller->NumVars[iVarIndex]; |
| 3382 | } |
| 3383 | |
| 3384 | static C4Value FnDecVar(C4AulContext *cthr, C4ValueInt iVarIndex) |
| 3385 | { |
| 3386 | if (!cthr->Caller) return C4VNull; |
| 3387 | return --cthr->Caller->NumVars[iVarIndex]; |
| 3388 | } |
| 3389 | |
| 3390 | static C4Value FnVar(C4AulContext *cthr, C4ValueInt iVarIndex) |
| 3391 | { |
| 3392 | if (!cthr->Caller) return C4VNull; |
| 3393 | // Referenz zurückgeben |
| 3394 | return cthr->Caller->NumVars[iVarIndex].GetRef(); |
| 3395 | } |
| 3396 | |
| 3397 | static C4Value FnSetGlobal(C4AulContext *cthr, C4ValueInt iVarIndex, C4Value iValue) |
| 3398 | { |
| 3399 | Game.ScriptEngine.Global[iVarIndex] = iValue; |
| 3400 | return iValue; |
| 3401 | } |
| 3402 | |
| 3403 | static C4Value FnGlobal(C4AulContext *cthr, C4ValueInt iVarIndex) |
| 3404 | { |
| 3405 | return Game.ScriptEngine.Global[iVarIndex].GetRef(); |
| 3406 | } |
| 3407 | |
| 3408 | static C4Value FnSetLocal(C4AulContext *cthr, C4ValueInt iVarIndex, C4Value iValue, C4Object *pObj) |
| 3409 | { |
| 3410 | if (!pObj) pObj = cthr->Obj; |
| 3411 | if (!pObj) return C4VFalse; |
| 3412 | pObj->Local[iVarIndex] = iValue; |
| 3413 | return iValue; |
| 3414 | } |
| 3415 | |
| 3416 | static C4Value FnLocal(C4AulContext *cthr, C4ValueInt iIndex, C4Object *pObj) |
| 3417 | { |
| 3418 | if (!pObj) pObj = cthr->Obj; |
| 3419 | if (!pObj) return C4VNull; |
| 3420 | if (iIndex < 0) return C4VNull; |
| 3421 | return pObj->Local[iIndex].GetRef(); |
| 3422 | } |
| 3423 | |
| 3424 | static C4Value FnCall(C4AulContext *cthr, C4String *szFunction, |
| 3425 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3426 | C4Value par5, C4Value par6, C4Value par7, C4Value par8) |
| 3427 | { |
| 3428 | if (!szFunction || !cthr->Obj) return C4VNull; |
| 3429 | C4AulParSet Pars; |
| 3430 | Copy2ParSet9(Pars, par); |
| 3431 | return cthr->Obj->Call(szFunctionCall: FnStringPar(pString: szFunction), pPars: Pars, fPassError: true, convertNilToIntBool: !cthr->CalledWithStrictNil()); |
| 3432 | } |
| 3433 | |
| 3434 | static C4Value FnObjectCall(C4AulContext *cthr, |
| 3435 | C4Object *pObj, C4String *szFunction, |
| 3436 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3437 | C4Value par5, C4Value par6, C4Value par7) |
| 3438 | { |
| 3439 | if (!pObj || !szFunction) return C4VNull; |
| 3440 | if (!pObj->Def) return C4VNull; |
| 3441 | // get func |
| 3442 | C4AulFunc *f; |
| 3443 | if (!(f = pObj->Def->Script.GetSFunc(pIdtf: FnStringPar(pString: szFunction), AccNeeded: AA_PUBLIC, fFailSafe: true))) return C4VNull; |
| 3444 | // copy pars |
| 3445 | C4AulParSet Pars; |
| 3446 | Copy2ParSet8(Pars, par); |
| 3447 | // exec |
| 3448 | return f->Exec(pObj, pPars: Pars, fPassErrors: true, nonStrict3WarnConversionOnly: true, convertNilToIntBool: !cthr->CalledWithStrictNil()); |
| 3449 | } |
| 3450 | |
| 3451 | static C4Value FnDefinitionCall(C4AulContext *cthr, |
| 3452 | C4ID idID, C4String *szFunction, |
| 3453 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3454 | C4Value par5, C4Value par6, C4Value par7) |
| 3455 | { |
| 3456 | if (!idID || !szFunction) return C4VNull; |
| 3457 | // Make failsafe |
| 3458 | char szFunc2[C4AUL_MAX_Identifier + 1]; |
| 3459 | FormatWithNull(buf&: szFunc2, fmt: "~{}" , args: FnStringPar(pString: szFunction)); |
| 3460 | // Get definition |
| 3461 | C4Def *pDef; |
| 3462 | if (!(pDef = C4Id2Def(id: idID))) return C4VNull; |
| 3463 | // copy parameters |
| 3464 | C4AulParSet Pars; |
| 3465 | Copy2ParSet8(Pars, par); |
| 3466 | // Call |
| 3467 | return pDef->Script.Call(szFunction: szFunc2, pPars: Pars, fPassError: true, convertNilToIntBool: !cthr->CalledWithStrictNil()); |
| 3468 | } |
| 3469 | |
| 3470 | static C4Value FnGameCall(C4AulContext *cthr, |
| 3471 | C4String *szFunction, |
| 3472 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3473 | C4Value par5, C4Value par6, C4Value par7, C4Value par8) |
| 3474 | { |
| 3475 | if (!szFunction) return C4VNull; |
| 3476 | // Make failsafe |
| 3477 | char szFunc2[C4AUL_MAX_Identifier + 1]; |
| 3478 | FormatWithNull(buf&: szFunc2, fmt: "~{}" , args: FnStringPar(pString: szFunction)); |
| 3479 | // copy parameters |
| 3480 | C4AulParSet Pars; |
| 3481 | Copy2ParSet9(Pars, par); |
| 3482 | // Call |
| 3483 | return Game.Script.Call(szFunction: szFunc2, pPars: Pars, fPassError: true, convertNilToIntBool: !cthr->CalledWithStrictNil()); |
| 3484 | } |
| 3485 | |
| 3486 | static C4Value FnGameCallEx(C4AulContext *cthr, |
| 3487 | C4String *szFunction, |
| 3488 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3489 | C4Value par5, C4Value par6, C4Value par7, C4Value par8) |
| 3490 | { |
| 3491 | if (!szFunction) return C4VNull; |
| 3492 | // Make failsafe |
| 3493 | char szFunc2[C4AUL_MAX_Identifier + 1]; |
| 3494 | FormatWithNull(buf&: szFunc2, fmt: "~{}" , args: FnStringPar(pString: szFunction)); |
| 3495 | // copy parameters |
| 3496 | C4AulParSet Pars; |
| 3497 | Copy2ParSet9(Pars, par); |
| 3498 | // Call |
| 3499 | return Game.Script.GRBroadcast(szFunction: szFunc2, pPars: Pars, fPassError: true, fRejectTest: false, convertNilToIntBool: !cthr->CalledWithStrictNil()); |
| 3500 | } |
| 3501 | |
| 3502 | static C4Value FnProtectedCall(C4AulContext *cthr, |
| 3503 | C4Object *pObj, C4String *szFunction, |
| 3504 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3505 | C4Value par5, C4Value par6, C4Value par7) |
| 3506 | { |
| 3507 | if (!pObj || !szFunction) return C4VNull; |
| 3508 | if (!pObj->Def) return C4VNull; |
| 3509 | // get func |
| 3510 | C4AulScriptFunc *f; |
| 3511 | if (!(f = pObj->Def->Script.GetSFunc(pIdtf: FnStringPar(pString: szFunction), AccNeeded: AA_PROTECTED, fFailSafe: true))) return C4VNull; |
| 3512 | // copy parameters |
| 3513 | C4AulParSet Pars; |
| 3514 | Copy2ParSet8(Pars, par); |
| 3515 | // exec |
| 3516 | return f->Exec(pObj, pPars: Pars, fPassErrors: true, nonStrict3WarnConversionOnly: !cthr->CalledWithStrictNil()); |
| 3517 | } |
| 3518 | |
| 3519 | static C4Value FnPrivateCall(C4AulContext *cthr, |
| 3520 | C4Object *pObj, C4String *szFunction, |
| 3521 | C4Value par0, C4Value par1, C4Value par2, C4Value par3, C4Value par4, |
| 3522 | C4Value par5, C4Value par6, C4Value par7) |
| 3523 | { |
| 3524 | if (!pObj || !szFunction) return C4VNull; |
| 3525 | if (!pObj->Def) return C4VNull; |
| 3526 | // get func |
| 3527 | C4AulScriptFunc *f; |
| 3528 | if (!(f = pObj->Def->Script.GetSFunc(pIdtf: FnStringPar(pString: szFunction), AccNeeded: AA_PRIVATE, fFailSafe: true))) return C4VNull; |
| 3529 | // copy parameters |
| 3530 | C4AulParSet Pars; |
| 3531 | Copy2ParSet8(Pars, par); |
| 3532 | // exec |
| 3533 | return f->Exec(pObj, pPars: Pars, fPassErrors: true, nonStrict3WarnConversionOnly: !cthr->CalledWithStrictNil()); |
| 3534 | } |
| 3535 | |
| 3536 | static C4Object *FnEditCursor(C4AulContext *cth) |
| 3537 | { |
| 3538 | if (Game.Control.SyncMode()) return nullptr; |
| 3539 | return Console.EditCursor.GetTarget(); |
| 3540 | } |
| 3541 | |
| 3542 | static void FnResort(C4AulContext *cthr, C4Object *pObj) |
| 3543 | { |
| 3544 | if (!pObj) pObj = cthr->Obj; |
| 3545 | // Resort single object |
| 3546 | if (pObj) |
| 3547 | pObj->Resort(); |
| 3548 | // Resort object list |
| 3549 | else |
| 3550 | Game.Objects.SortByCategory(); |
| 3551 | } |
| 3552 | |
| 3553 | static bool FnIsNetwork(C4AulContext *cthr) { return Game.Parameters.IsNetworkGame; } |
| 3554 | |
| 3555 | static C4String *FnGetLeague(C4AulContext *cthr, C4ValueInt idx) |
| 3556 | { |
| 3557 | // get indexed league |
| 3558 | StdStrBuf sIdxLeague; |
| 3559 | if (!Game.Parameters.League.GetSection(idx, psOutSection: &sIdxLeague)) return nullptr; |
| 3560 | return String(str: sIdxLeague.getData()); |
| 3561 | } |
| 3562 | |
| 3563 | static std::optional<bool> FnTestMessageBoard(C4AulContext *cthr, C4ValueInt iForPlr, bool fTestIfInUse) |
| 3564 | { |
| 3565 | // multi-query-MessageBoard is always available if the player is valid =) |
| 3566 | // (but it won't do anything in developer mode...) |
| 3567 | C4Player *pPlr = Game.Players.Get(iPlayer: iForPlr); |
| 3568 | if (!pPlr) return {}; |
| 3569 | if (!fTestIfInUse) return {true}; |
| 3570 | // single query only if no query is scheduled |
| 3571 | return {pPlr->HasMessageBoardQuery()}; |
| 3572 | } |
| 3573 | |
| 3574 | static bool FnCallMessageBoard(C4AulContext *cthr, C4Object *pObj, bool fUpperCase, C4String *szQueryString, C4ValueInt iForPlr) |
| 3575 | { |
| 3576 | if (!pObj) pObj = cthr->Obj; |
| 3577 | if (pObj && !pObj->Status) return false; |
| 3578 | // check player |
| 3579 | C4Player *pPlr = Game.Players.Get(iPlayer: iForPlr); |
| 3580 | if (!pPlr) return false; |
| 3581 | // remove any previous |
| 3582 | pPlr->CallMessageBoard(pForObj: pObj, sQueryString: StdStrBuf::MakeRef(str: FnStringPar(pString: szQueryString)), fUppercase: !!fUpperCase); |
| 3583 | return true; |
| 3584 | } |
| 3585 | |
| 3586 | static bool FnAbortMessageBoard(C4AulContext *cthr, C4Object *pObj, C4ValueInt iForPlr) |
| 3587 | { |
| 3588 | if (!pObj) pObj = cthr->Obj; |
| 3589 | // check player |
| 3590 | C4Player *pPlr = Game.Players.Get(iPlayer: iForPlr); |
| 3591 | if (!pPlr) return false; |
| 3592 | // close TypeIn if active |
| 3593 | Game.MessageInput.AbortMsgBoardQuery(pObj, iPlr: iForPlr); |
| 3594 | // abort for it |
| 3595 | return pPlr->RemoveMessageBoardQuery(pForObj: pObj); |
| 3596 | } |
| 3597 | |
| 3598 | static bool FnOnMessageBoardAnswer(C4AulContext *cthr, C4Object *pObj, C4ValueInt iForPlr, C4String *szAnswerString) |
| 3599 | { |
| 3600 | // remove query |
| 3601 | // fail if query doesn't exist to prevent any doubled answers |
| 3602 | C4Player *pPlr = Game.Players.Get(iPlayer: iForPlr); |
| 3603 | if (!pPlr) return false; |
| 3604 | if (!pPlr->RemoveMessageBoardQuery(pForObj: pObj)) return false; |
| 3605 | // if no answer string is provided, the user did not answer anything |
| 3606 | // just remove the query |
| 3607 | if (!szAnswerString || !szAnswerString->Data.getData()) return true; |
| 3608 | // get script |
| 3609 | C4ScriptHost *scr; |
| 3610 | if (pObj) scr = &pObj->Def->Script; else scr = &Game.Script; |
| 3611 | // exec func |
| 3612 | return static_cast<bool>(scr->ObjectCall(pCaller: nullptr, pObj, PSF_InputCallback, pPars: {C4VString(strString: FnStringPar(pString: szAnswerString)), C4VInt(iVal: iForPlr)}, fPassError: true)); |
| 3613 | } |
| 3614 | |
| 3615 | static C4ValueInt FnScriptCounter(C4AulContext *cthr) |
| 3616 | { |
| 3617 | return Game.Script.Counter; |
| 3618 | } |
| 3619 | |
| 3620 | static C4ValueInt FnSetMass(C4AulContext *cthr, C4ValueInt iValue, C4Object *pObj) |
| 3621 | { |
| 3622 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3623 | pObj->OwnMass = iValue - pObj->Def->Mass; |
| 3624 | pObj->UpdateMass(); |
| 3625 | return true; |
| 3626 | } |
| 3627 | |
| 3628 | static C4ValueInt FnGetColor(C4AulContext *cthr, C4Object *pObj) |
| 3629 | { |
| 3630 | // oldgfx |
| 3631 | return 0; |
| 3632 | } |
| 3633 | |
| 3634 | static C4ValueInt FnSetColor(C4AulContext *cthr, C4ValueInt iValue, C4Object *pObj) |
| 3635 | { |
| 3636 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3637 | if (!Inside<C4ValueInt>(ival: iValue, lbound: 0, rbound: C4MaxColor - 1)) return false; |
| 3638 | iValue = Application.DDraw->Pal.GetClr(byCol: FColors[FPlayer + iValue]); |
| 3639 | pObj->Color = iValue; |
| 3640 | pObj->UpdateGraphics(fGraphicsChanged: false); |
| 3641 | pObj->UpdateFace(bUpdateShape: false); |
| 3642 | return true; |
| 3643 | } |
| 3644 | |
| 3645 | static std::optional<C4ValueInt> FnGetColorDw(C4AulContext *cthr, C4Object *pObj) |
| 3646 | { |
| 3647 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 3648 | return {pObj->Color}; |
| 3649 | } |
| 3650 | |
| 3651 | static std::optional<C4ValueInt> FnGetPlrColorDw(C4AulContext *cthr, C4ValueInt iPlr) |
| 3652 | { |
| 3653 | // get player |
| 3654 | C4Player *pPlr = Game.Players.Get(iPlayer: iPlr); |
| 3655 | // safety |
| 3656 | if (!pPlr) return {}; |
| 3657 | // return player color |
| 3658 | return {pPlr->ColorDw}; |
| 3659 | } |
| 3660 | |
| 3661 | static bool FnSetColorDw(C4AulContext *cthr, C4ValueInt iValue, C4Object *pObj) |
| 3662 | { |
| 3663 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3664 | pObj->Color = iValue; |
| 3665 | pObj->UpdateGraphics(fGraphicsChanged: false); |
| 3666 | pObj->UpdateFace(bUpdateShape: false); |
| 3667 | return true; |
| 3668 | } |
| 3669 | |
| 3670 | static C4ValueInt FnSetFoW(C4AulContext *cthr, bool fEnabled, C4ValueInt iPlr) |
| 3671 | { |
| 3672 | // safety |
| 3673 | if (!ValidPlr(plr: iPlr)) return false; |
| 3674 | // set enabled |
| 3675 | Game.Players.Get(iPlayer: iPlr)->SetFoW(!!fEnabled); |
| 3676 | // success |
| 3677 | return true; |
| 3678 | } |
| 3679 | |
| 3680 | static C4ValueInt FnSetPlrViewRange(C4AulContext *cthr, C4ValueInt iRange, C4Object *pObj, bool fExact) |
| 3681 | { |
| 3682 | // local/safety |
| 3683 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3684 | // backwards compatibility for low ranges |
| 3685 | if (!fExact && iRange < 128 && iRange > 0) iRange = 128; |
| 3686 | // set range |
| 3687 | pObj->SetPlrViewRange(iRange); |
| 3688 | // success |
| 3689 | return true; |
| 3690 | } |
| 3691 | |
| 3692 | static C4ValueInt FnGetMaxPlayer(C4AulContext *cthr) |
| 3693 | { |
| 3694 | return Game.Parameters.MaxPlayers; |
| 3695 | } |
| 3696 | |
| 3697 | static C4ValueInt FnSetMaxPlayer(C4AulContext *cthr, C4ValueInt iTo) |
| 3698 | { |
| 3699 | // think positive! :) |
| 3700 | if (iTo < 0) return false; |
| 3701 | // script functions don't need to pass ControlQueue! |
| 3702 | Game.Parameters.MaxPlayers = iTo; |
| 3703 | // success |
| 3704 | return true; |
| 3705 | } |
| 3706 | |
| 3707 | static C4ValueInt FnSetPicture(C4AulContext *cthr, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4Object *pObj) |
| 3708 | { |
| 3709 | // local/safety |
| 3710 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3711 | // set new picture rect |
| 3712 | pObj->PictureRect.Set(iX, iY, iWdt, iHgt); |
| 3713 | // success |
| 3714 | return true; |
| 3715 | } |
| 3716 | |
| 3717 | static C4String *FnGetProcedure(C4AulContext *cthr, C4Object *pObj) |
| 3718 | { |
| 3719 | // local/safety |
| 3720 | if (!pObj) pObj = cthr->Obj; if (!pObj) return nullptr; |
| 3721 | // no action? |
| 3722 | if (pObj->Action.Act <= ActIdle) return nullptr; |
| 3723 | // get proc |
| 3724 | C4ValueInt iProc = pObj->Def->ActMap[pObj->Action.Act].Procedure; |
| 3725 | // NONE? |
| 3726 | if (iProc <= DFA_NONE) return nullptr; |
| 3727 | // return procedure name |
| 3728 | return String(str: ProcedureName[iProc]); |
| 3729 | } |
| 3730 | |
| 3731 | static C4Object *FnBuy(C4AulContext *cthr, C4ID idBuyObj, C4ValueInt iForPlr, C4ValueInt iPayPlr, C4Object *pToBase, bool fShowErrors) |
| 3732 | { |
| 3733 | // safety |
| 3734 | if (!ValidPlr(plr: iForPlr) || !ValidPlr(plr: iPayPlr)) return nullptr; |
| 3735 | // buy |
| 3736 | C4Object *pThing; |
| 3737 | if (!(pThing = Game.Players.Get(iPlayer: iPayPlr)->Buy(id: idBuyObj, fShowErrors, iForPlr, pBuyObj: pToBase ? pToBase : cthr->Obj))) return nullptr; |
| 3738 | // enter object, if supplied |
| 3739 | if (pToBase) |
| 3740 | { |
| 3741 | pThing->Enter(pTarget: pToBase, fCalls: true); |
| 3742 | } |
| 3743 | else |
| 3744 | { |
| 3745 | // no target object? get local pos |
| 3746 | if (cthr->Obj) pThing->ForcePosition(tx: cthr->Obj->x, ty: cthr->Obj->y); |
| 3747 | } |
| 3748 | // done |
| 3749 | return pThing; |
| 3750 | } |
| 3751 | |
| 3752 | static bool FnSell(C4AulContext *cthr, C4ValueInt iToPlr, C4Object *pObj) |
| 3753 | { |
| 3754 | // local/safety |
| 3755 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3756 | if (!ValidPlr(plr: iToPlr)) return false; |
| 3757 | // sell |
| 3758 | return Game.Players.Get(iPlayer: iToPlr)->Sell2Home(tobj: pObj); |
| 3759 | } |
| 3760 | |
| 3761 | // ** additional funcs for references/type info |
| 3762 | |
| 3763 | static C4Value FnSet(C4AulContext *cthr, C4Value *Dest, C4Value Src) |
| 3764 | { |
| 3765 | *Dest = Src; |
| 3766 | return *Dest; |
| 3767 | } |
| 3768 | |
| 3769 | static C4Value FnInc(C4AulContext *cthr, C4Value *Value, C4Value Diff) |
| 3770 | { |
| 3771 | if (!Value->GetRefVal().ConvertTo(vtToType: C4V_Int)) |
| 3772 | return C4VNull; |
| 3773 | |
| 3774 | *Value += Diff.getInt(); |
| 3775 | |
| 3776 | return *Value; |
| 3777 | } |
| 3778 | |
| 3779 | static C4Value FnDec(C4AulContext *cthr, C4Value *Value, C4Value Diff) |
| 3780 | { |
| 3781 | if (!Value->GetRefVal().ConvertTo(vtToType: C4V_Int)) |
| 3782 | return C4VNull; |
| 3783 | |
| 3784 | *Value -= Diff.getInt(); |
| 3785 | |
| 3786 | return *Value; |
| 3787 | } |
| 3788 | |
| 3789 | static bool FnIsRef(C4AulContext *cthr, C4Value Value) |
| 3790 | { |
| 3791 | return Value.IsRef(); |
| 3792 | } |
| 3793 | |
| 3794 | static C4ValueInt FnGetType(C4AulContext *cthr, C4Value Value) |
| 3795 | { |
| 3796 | if (!Value._getBool() && cthr->Caller && !cthr->CalledWithStrictNil()) return C4V_Any; |
| 3797 | return Value.GetType(); |
| 3798 | } |
| 3799 | |
| 3800 | static C4ValueArray *FnCreateArray(C4AulContext *cthr, C4ValueInt iSize) |
| 3801 | { |
| 3802 | return new C4ValueArray(iSize); |
| 3803 | } |
| 3804 | |
| 3805 | static std::optional<C4ValueInt> FnGetLength(C4AulContext *cthr, C4Value pPar) |
| 3806 | { |
| 3807 | // support GetLength() etc. |
| 3808 | if (!pPar) return {}; |
| 3809 | if (auto map = pPar.getMap()) |
| 3810 | return {map->size()}; |
| 3811 | C4ValueArray *pArray = pPar.getArray(); |
| 3812 | if (pArray) |
| 3813 | return {pArray->GetSize()}; |
| 3814 | C4String *pStr = pPar.getStr(); |
| 3815 | if (pStr) |
| 3816 | return {pStr->Data.getLength()}; |
| 3817 | throw C4AulExecError(cthr->Obj, "func \"GetLength\" par 0 cannot be converted to string or array or map" ); |
| 3818 | } |
| 3819 | |
| 3820 | static C4ValueInt FnGetIndexOf(C4AulContext *cthr, C4Value searchVal, C4ValueArray *pArray) |
| 3821 | { |
| 3822 | // find first occurance of first parameter in array |
| 3823 | // support GetIndexOf(x, 0) |
| 3824 | if (!pArray) return -1; |
| 3825 | // find the element by comparing data only - this may result in bogus results if an object ptr array is searched for an int |
| 3826 | // however, that's rather unlikely and strange scripting style |
| 3827 | int32_t iSize = pArray->GetSize(); |
| 3828 | |
| 3829 | if (!cthr->Caller || cthr->Caller->Func->pOrgScript->Strict >= C4AulScriptStrict::STRICT2) |
| 3830 | { |
| 3831 | auto strict = cthr->Caller->Func->pOrgScript->Strict; |
| 3832 | const auto &val = searchVal.GetRefVal(); |
| 3833 | for (int32_t i = 0; i < iSize; ++i) |
| 3834 | if (val.Equals(other: pArray->GetItem(index: i), strict)) |
| 3835 | // element found |
| 3836 | return i; |
| 3837 | } |
| 3838 | else |
| 3839 | { |
| 3840 | const auto cmp = searchVal._getRaw(); |
| 3841 | for (int32_t i = 0; i < iSize; ++i) |
| 3842 | if (cmp == pArray->GetItem(index: i)._getRaw()) |
| 3843 | // element found |
| 3844 | return i; |
| 3845 | } |
| 3846 | // element not found |
| 3847 | return -1; |
| 3848 | } |
| 3849 | |
| 3850 | static void FnSetLength(C4AulContext *cthr, C4Value *pArrayRef, C4ValueInt iNewSize) |
| 3851 | { |
| 3852 | // safety |
| 3853 | if (iNewSize < 0 || iNewSize > C4ValueList::MaxSize) |
| 3854 | throw C4AulExecError(cthr->Obj, std::format(fmt: "SetLength: invalid array size ({})" , args&: iNewSize)); |
| 3855 | |
| 3856 | // set new size |
| 3857 | pArrayRef->SetArrayLength(size: iNewSize, cthr); |
| 3858 | } |
| 3859 | |
| 3860 | static bool FnSetVisibility(C4AulContext *cthr, C4ValueInt iVisibility, C4Object *pObj) |
| 3861 | { |
| 3862 | // local call/safety |
| 3863 | if (!pObj) pObj = cthr->Obj; |
| 3864 | if (!pObj) return false; |
| 3865 | |
| 3866 | pObj->Visibility = iVisibility; |
| 3867 | |
| 3868 | return true; |
| 3869 | } |
| 3870 | |
| 3871 | static std::optional<C4ValueInt> FnGetVisibility(C4AulContext *cthr, C4Object *pObj) |
| 3872 | { |
| 3873 | if (!pObj) pObj = cthr->Obj; |
| 3874 | if (!pObj) return {}; |
| 3875 | |
| 3876 | return {pObj->Visibility}; |
| 3877 | } |
| 3878 | |
| 3879 | static bool FnSetClrModulation(C4AulContext *cthr, C4ValueInt dwClr, C4Object *pObj, C4ValueInt iOverlayID) |
| 3880 | { |
| 3881 | // local call/safety |
| 3882 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 3883 | // overlay? |
| 3884 | if (iOverlayID) |
| 3885 | { |
| 3886 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 3887 | if (!pOverlay) |
| 3888 | { |
| 3889 | DebugLog(level: spdlog::level::err, fmt: "SetClrModulation: Overlay {} not defined for object {} ({})" , args: static_cast<int>(iOverlayID), args: static_cast<int>(pObj->Number), args: pObj->GetName()); |
| 3890 | return false; |
| 3891 | } |
| 3892 | pOverlay->SetClrModulation(dwClr); |
| 3893 | } |
| 3894 | else |
| 3895 | { |
| 3896 | // set it |
| 3897 | pObj->ColorMod = dwClr; |
| 3898 | } |
| 3899 | // success |
| 3900 | return true; |
| 3901 | } |
| 3902 | |
| 3903 | static std::optional<C4ValueInt> FnGetClrModulation(C4AulContext *cthr, C4Object *pObj, C4ValueInt iOverlayID) |
| 3904 | { |
| 3905 | // local call/safety |
| 3906 | if (!pObj) pObj = cthr->Obj; if (!pObj) return {}; |
| 3907 | // overlay? |
| 3908 | if (iOverlayID) |
| 3909 | { |
| 3910 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 3911 | if (!pOverlay) |
| 3912 | { |
| 3913 | DebugLog(level: spdlog::level::err, fmt: "GetClrModulation: Overlay {} not defined for object {} ({})" , args: static_cast<int>(iOverlayID), args: static_cast<int>(pObj->Number), args: pObj->GetName()); |
| 3914 | return {}; |
| 3915 | } |
| 3916 | return {pOverlay->GetClrModulation()}; |
| 3917 | } |
| 3918 | else |
| 3919 | // get it |
| 3920 | return {pObj->ColorMod}; |
| 3921 | } |
| 3922 | |
| 3923 | static bool FnGetMissionAccess(C4AulContext *cthr, C4String *strMissionAccess) |
| 3924 | { |
| 3925 | // safety |
| 3926 | if (!strMissionAccess) return false; |
| 3927 | |
| 3928 | // non-sync mode: warn |
| 3929 | if (Game.Control.SyncMode()) |
| 3930 | LogNTr(level: spdlog::level::warn, message: "using GetMissionAccess may cause desyncs when playing records!" ); |
| 3931 | |
| 3932 | return SIsModule(szList: Config.General.MissionAccess, szString: FnStringPar(pString: strMissionAccess)); |
| 3933 | } |
| 3934 | |
| 3935 | // Helper to read or write a value from/to a structure. Must be two |
| 3936 | class C4ValueCompiler : public StdCompiler |
| 3937 | { |
| 3938 | public: |
| 3939 | C4ValueCompiler(const char **pszNames, int iNameCnt, int iEntryNr) |
| 3940 | : pszNames(pszNames), iNameCnt(iNameCnt), iEntryNr(iEntryNr) {} |
| 3941 | |
| 3942 | virtual bool isCompiler() override { return false; } |
| 3943 | virtual bool hasNaming() override { return true; } |
| 3944 | virtual bool isVerbose() override { return false; } |
| 3945 | |
| 3946 | virtual NameGuard Name(const char *szName) override |
| 3947 | { |
| 3948 | // match possible? (no match yet / continued match) |
| 3949 | if (!iMatchStart || haveCurrentMatch()) |
| 3950 | // already got all names? |
| 3951 | if (!haveCompleteMatch()) |
| 3952 | // check name |
| 3953 | if (SEqual(szStr1: pszNames[iMatchCount], szStr2: szName)) |
| 3954 | { |
| 3955 | // got match |
| 3956 | if (!iMatchCount) iMatchStart = iDepth + 1; |
| 3957 | iMatchCount++; |
| 3958 | } |
| 3959 | iDepth++; |
| 3960 | return {this, true}; |
| 3961 | } |
| 3962 | |
| 3963 | virtual bool Default(const char *szName) override |
| 3964 | { |
| 3965 | // Always process values even if they are default! |
| 3966 | return false; |
| 3967 | } |
| 3968 | |
| 3969 | virtual void NameEnd(bool fBreak = false) override |
| 3970 | { |
| 3971 | // end of matched name section? |
| 3972 | if (haveCurrentMatch()) |
| 3973 | { |
| 3974 | iMatchCount--; |
| 3975 | if (!iMatchCount) iMatchStart = 0; |
| 3976 | } |
| 3977 | iDepth--; |
| 3978 | } |
| 3979 | |
| 3980 | virtual void Begin() override |
| 3981 | { |
| 3982 | // set up |
| 3983 | iDepth = iMatchStart = iMatchCount = 0; |
| 3984 | } |
| 3985 | |
| 3986 | protected: |
| 3987 | // value function forward to be overwritten by get or set compiler |
| 3988 | virtual void ProcessInt(int32_t &rInt) = 0; |
| 3989 | virtual void ProcessBool(bool &rBool) = 0; |
| 3990 | virtual void ProcessChar(char &rChar) = 0; |
| 3991 | virtual void ProcessString(char *szString, size_t iMaxLength, bool fIsID) = 0; |
| 3992 | virtual void ProcessString(std::string &str, bool isID) = 0; |
| 3993 | |
| 3994 | public: |
| 3995 | // value functions |
| 3996 | virtual void QWord(int64_t &rInt) override { if (haveCompleteMatch()) if (!iEntryNr--) { auto i = static_cast<int32_t>(rInt); ProcessInt(rInt&: i); rInt = i; } } |
| 3997 | virtual void QWord(uint64_t &rInt) override { if (haveCompleteMatch()) if (!iEntryNr--) { auto i = static_cast<int32_t>(rInt); ProcessInt(rInt&: i); rInt = i; } } |
| 3998 | virtual void DWord(int32_t &rInt) override { if (haveCompleteMatch()) if (!iEntryNr--) ProcessInt(rInt); } |
| 3999 | virtual void DWord(uint32_t &rInt) override { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i = rInt; ProcessInt(rInt&: i); rInt = i; } } |
| 4000 | virtual void Word(int16_t &rShort) override { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i = rShort; ProcessInt(rInt&: i); rShort = i; } } |
| 4001 | virtual void Word(uint16_t &rShort) override { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i = rShort; ProcessInt(rInt&: i); rShort = i; } } |
| 4002 | virtual void Byte(int8_t &rByte) override { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i = rByte; ProcessInt(rInt&: i); rByte = i; } } |
| 4003 | virtual void Byte(uint8_t &rByte) override { if (haveCompleteMatch()) if (!iEntryNr--) { int32_t i = rByte; ProcessInt(rInt&: i); rByte = i; } } |
| 4004 | virtual void Boolean(bool &rBool) override { if (haveCompleteMatch()) if (!iEntryNr--) ProcessBool(rBool); } |
| 4005 | virtual void Character(char &rChar) override { if (haveCompleteMatch()) if (!iEntryNr--) ProcessChar(rChar); } |
| 4006 | |
| 4007 | // The C4ID-Adaptor will set RCT_ID for it's strings (see C4Id.h), so we don't have to guess the type. |
| 4008 | virtual void String(char *szString, size_t iMaxLength, RawCompileType eType) override |
| 4009 | { |
| 4010 | if (haveCompleteMatch()) if (!iEntryNr--) ProcessString(szString, iMaxLength, fIsID: eType == StdCompiler::RCT_ID); |
| 4011 | } |
| 4012 | virtual void String(std::string &str, RawCompileType type) override |
| 4013 | { |
| 4014 | if (haveCompleteMatch()) if (!iEntryNr--) ProcessString(str, isID: type == StdCompiler::RCT_ID); |
| 4015 | } |
| 4016 | virtual void Raw(void *pData, size_t iSize, RawCompileType eType = RCT_Escaped) override |
| 4017 | { |
| 4018 | /* C4Script can't handle this */ |
| 4019 | } |
| 4020 | |
| 4021 | private: |
| 4022 | // Name(s) of the entry to read |
| 4023 | const char **pszNames; |
| 4024 | int iNameCnt; |
| 4025 | // Number of the element that is to be read |
| 4026 | int iEntryNr; |
| 4027 | |
| 4028 | // current depth |
| 4029 | int iDepth; |
| 4030 | // match start (where did the first name match?), |
| 4031 | // match count (how many names did match, from that point?) |
| 4032 | int iMatchStart, iMatchCount; |
| 4033 | |
| 4034 | private: |
| 4035 | // match active? |
| 4036 | bool haveCurrentMatch() const { return iDepth + 1 == iMatchStart + iMatchCount; } |
| 4037 | // match complete? |
| 4038 | bool haveCompleteMatch() const { return haveCurrentMatch() && iMatchCount == iNameCnt; } |
| 4039 | }; |
| 4040 | |
| 4041 | class C4ValueGetCompiler : public C4ValueCompiler |
| 4042 | { |
| 4043 | private: |
| 4044 | // Result |
| 4045 | C4Value Res; |
| 4046 | |
| 4047 | public: |
| 4048 | C4ValueGetCompiler(const char **pszNames, int iNameCnt, int iEntryNr) |
| 4049 | : C4ValueCompiler(pszNames, iNameCnt, iEntryNr) {} |
| 4050 | |
| 4051 | // Result-getter |
| 4052 | const C4Value &getResult() const { return Res; } |
| 4053 | |
| 4054 | protected: |
| 4055 | // get values as C4Value |
| 4056 | virtual void ProcessInt(int32_t &rInt) override { Res = C4VInt(iVal: rInt); } |
| 4057 | virtual void ProcessBool(bool &rBool) override { Res = C4VBool(fVal: rBool); } |
| 4058 | virtual void ProcessChar(char &rChar) override { Res = C4VString(strString: std::format(fmt: "{}" , args&: rChar).c_str()); } |
| 4059 | |
| 4060 | virtual void ProcessString(char *szString, size_t iMaxLength, bool fIsID) override |
| 4061 | { |
| 4062 | Res = (fIsID ? C4VID(idVal: C4Id(str: szString)) : C4VString(strString: szString)); |
| 4063 | } |
| 4064 | virtual void ProcessString(std::string &str, bool fIsID) override |
| 4065 | { |
| 4066 | Res = (fIsID ? C4VID(idVal: C4Id(str: str.c_str())) : C4VString(strString: str.c_str())); |
| 4067 | } |
| 4068 | }; |
| 4069 | |
| 4070 | class C4ValueSetCompiler : public C4ValueCompiler |
| 4071 | { |
| 4072 | private: |
| 4073 | C4Value Val; // value to which the setting should be set |
| 4074 | bool fSuccess; // set if the value could be set successfully |
| 4075 | int32_t iRuntimeWriteAllowed; // if >0, runtime writing of values is allowed |
| 4076 | |
| 4077 | public: |
| 4078 | C4ValueSetCompiler(const char **pszNames, int iNameCnt, int iEntryNr, const C4Value &rSetVal) |
| 4079 | : C4ValueCompiler(pszNames, iNameCnt, iEntryNr), Val(rSetVal), fSuccess(false), iRuntimeWriteAllowed(0) {} |
| 4080 | |
| 4081 | // Query successful setting |
| 4082 | bool getSuccess() const { return fSuccess; } |
| 4083 | |
| 4084 | virtual void setRuntimeWritesAllowed(int32_t iChange) override { iRuntimeWriteAllowed += iChange; } |
| 4085 | |
| 4086 | protected: |
| 4087 | // set values as C4Value, only if type matches or is convertible |
| 4088 | virtual void ProcessInt(int32_t &rInt) override { if (iRuntimeWriteAllowed > 0 && Val.ConvertTo(vtToType: C4V_Int)) { rInt = Val.getInt(); fSuccess = true; } } |
| 4089 | virtual void ProcessBool(bool &rBool) override { if (iRuntimeWriteAllowed > 0 && Val.ConvertTo(vtToType: C4V_Bool)) { rBool = Val.getBool(); fSuccess = true; } } |
| 4090 | virtual void ProcessChar(char &rChar) override { C4String *s; if (iRuntimeWriteAllowed > 0 && (s = Val.getStr())) { rChar = s->Data.getData() ? *s->Data.getData() : 0; fSuccess = true; } } |
| 4091 | |
| 4092 | virtual void ProcessString(char *szString, size_t iMaxLength, bool fIsID) override |
| 4093 | { |
| 4094 | if (iRuntimeWriteAllowed <= 0 || !Val.ConvertTo(vtToType: fIsID ? C4V_C4ID : C4V_String)) return; |
| 4095 | if (fIsID) |
| 4096 | { |
| 4097 | assert(iMaxLength >= 4); // fields that should carry an ID are guaranteed to have a buffer that's large enough |
| 4098 | GetC4IdText(id: Val.getC4ID(), sBuf: szString); |
| 4099 | } |
| 4100 | else |
| 4101 | { |
| 4102 | C4String *s = Val.getStr(); if (!s) return; |
| 4103 | StdStrBuf &rsBuf = s->Data; |
| 4104 | if (rsBuf.getData()) SCopy(szSource: rsBuf.getData(), sTarget: szString, iMaxL: iMaxLength); else *szString = 0; |
| 4105 | } |
| 4106 | fSuccess = true; |
| 4107 | } |
| 4108 | |
| 4109 | virtual void ProcessString(std::string &str, bool isID) override |
| 4110 | { |
| 4111 | if (iRuntimeWriteAllowed <= 0 || !Val.ConvertTo(vtToType: isID ? C4V_C4ID : C4V_String)) return; |
| 4112 | if (isID) |
| 4113 | { |
| 4114 | assert(str.size() >= 4); // fields that should carry an ID are guaranteed to have a buffer that's large enough |
| 4115 | char buf[5]; |
| 4116 | GetC4IdText(id: Val.getC4ID(), sBuf: buf); |
| 4117 | str = buf; |
| 4118 | } |
| 4119 | else |
| 4120 | { |
| 4121 | C4String *s = Val.getStr(); if (!s) return; |
| 4122 | str = s->Data.getData(); |
| 4123 | } |
| 4124 | fSuccess = true; |
| 4125 | } |
| 4126 | }; |
| 4127 | |
| 4128 | // Use the compiler to find a named value in a structure |
| 4129 | template <class T> |
| 4130 | C4Value GetValByStdCompiler(const char *strEntry, const char *strSection, int iEntryNr, const T &rFrom) |
| 4131 | { |
| 4132 | // Set up name array, create compiler |
| 4133 | const char *szNames[2] = { strSection ? strSection : strEntry, strSection ? strEntry : nullptr }; |
| 4134 | C4ValueGetCompiler Comp(szNames, strSection ? 2 : 1, iEntryNr); |
| 4135 | |
| 4136 | // Compile |
| 4137 | try |
| 4138 | { |
| 4139 | Comp.Decompile(rFrom); |
| 4140 | return Comp.getResult(); |
| 4141 | } |
| 4142 | // Should not happen, catch it anyway. |
| 4143 | catch (const StdCompiler::Exception &) |
| 4144 | { |
| 4145 | return C4VNull; |
| 4146 | } |
| 4147 | } |
| 4148 | |
| 4149 | // Use the compiler to set a named value in a structure |
| 4150 | template <class T> |
| 4151 | bool SetValByStdCompiler(const char *strEntry, const char *strSection, int iEntryNr, const T &rTo, const C4Value &rvNewVal) |
| 4152 | { |
| 4153 | // Set up name array, create compiler |
| 4154 | const char *szNames[2] = { strSection ? strSection : strEntry, strSection ? strEntry : nullptr }; |
| 4155 | C4ValueSetCompiler Comp(szNames, strSection ? 2 : 1, iEntryNr, rvNewVal); |
| 4156 | |
| 4157 | // Compile |
| 4158 | try |
| 4159 | { |
| 4160 | Comp.Decompile(rTo); |
| 4161 | return Comp.getSuccess(); |
| 4162 | } |
| 4163 | // Should not happen, catch it anyway. |
| 4164 | catch (const StdCompiler::Exception &) |
| 4165 | { |
| 4166 | return false; |
| 4167 | } |
| 4168 | } |
| 4169 | |
| 4170 | static C4Value FnGetDefCoreVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4ID idDef, C4ValueInt iEntryNr) |
| 4171 | { |
| 4172 | const char *strSection = FnStringPar(pString: section); |
| 4173 | if (strSection && !*strSection) strSection = nullptr; |
| 4174 | |
| 4175 | if (!idDef && cthr->Def) idDef = cthr->Def->id; |
| 4176 | if (!idDef) return C4VNull; |
| 4177 | |
| 4178 | C4Def *pDef = C4Id2Def(id: idDef); |
| 4179 | if (!pDef) return C4VNull; |
| 4180 | |
| 4181 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: mkNamingAdapt(rValue&: *pDef, szName: "DefCore" )); |
| 4182 | } |
| 4183 | |
| 4184 | static C4Value FnGetObjectVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4Object *pObj, C4ValueInt iEntryNr) |
| 4185 | { |
| 4186 | const char *strSection = FnStringPar(pString: section); |
| 4187 | if (!*strSection) strSection = nullptr; |
| 4188 | |
| 4189 | if (!pObj) pObj = cthr->Obj; |
| 4190 | if (!pObj) return C4VNull; |
| 4191 | |
| 4192 | // get value |
| 4193 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: mkNamingAdapt(rValue&: *pObj, szName: "Object" )); |
| 4194 | } |
| 4195 | |
| 4196 | static C4Value FnGetObjectInfoCoreVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4Object *pObj, C4ValueInt iEntryNr) |
| 4197 | { |
| 4198 | const char *strSection = FnStringPar(pString: section); |
| 4199 | if (strSection && !*strSection) strSection = nullptr; |
| 4200 | |
| 4201 | if (!pObj) pObj = cthr->Obj; |
| 4202 | if (!pObj) return C4VNull; |
| 4203 | |
| 4204 | // get obj info |
| 4205 | C4ObjectInfo *pObjInfo = pObj->Info; |
| 4206 | |
| 4207 | if (!pObjInfo) return C4VNull; |
| 4208 | |
| 4209 | // get obj info core |
| 4210 | C4ObjectInfoCore *pObjInfoCore = static_cast<C4ObjectInfoCore *>(pObjInfo); |
| 4211 | |
| 4212 | // get value |
| 4213 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: mkNamingAdapt(rValue&: *pObjInfoCore, szName: "ObjectInfo" )); |
| 4214 | } |
| 4215 | |
| 4216 | static C4Value FnGetActMapVal(C4AulContext *cthr, C4String *strEntry, C4String *action, C4ID idDef, C4ValueInt iEntryNr) |
| 4217 | { |
| 4218 | if (!idDef && cthr->Def) idDef = cthr->Def->id; |
| 4219 | if (!idDef) return C4VNull; |
| 4220 | |
| 4221 | C4Def *pDef = C4Id2Def(id: idDef); |
| 4222 | |
| 4223 | if (!pDef) return C4VNull; |
| 4224 | |
| 4225 | C4ActionDef *pAct = pDef->ActMap; |
| 4226 | |
| 4227 | if (!pAct) return C4VNull; |
| 4228 | |
| 4229 | const char *strAction = FnStringPar(pString: action); |
| 4230 | C4ValueInt iAct; |
| 4231 | for (iAct = 0; iAct < pDef->ActNum; iAct++, pAct++) |
| 4232 | if (SEqual(szStr1: pAct->Name, szStr2: strAction)) |
| 4233 | break; |
| 4234 | |
| 4235 | // not found? |
| 4236 | if (iAct >= pDef->ActNum) |
| 4237 | return C4VNull; |
| 4238 | |
| 4239 | // get value |
| 4240 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection: nullptr, iEntryNr, rFrom: *pAct); |
| 4241 | } |
| 4242 | |
| 4243 | static C4Value FnGetScenarioVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4ValueInt iEntryNr) |
| 4244 | { |
| 4245 | const char *strSection = FnStringPar(pString: section); |
| 4246 | if (strSection && !*strSection) strSection = nullptr; |
| 4247 | |
| 4248 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: mkParAdapt(rObj&: Game.C4S, rPar: false)); |
| 4249 | } |
| 4250 | |
| 4251 | static C4Value FnGetPlayerVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4ValueInt iPlr, C4ValueInt iEntryNr) |
| 4252 | { |
| 4253 | const char *strSection = FnStringPar(pString: section); |
| 4254 | if (strSection && !*strSection) strSection = nullptr; |
| 4255 | |
| 4256 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 4257 | |
| 4258 | // get player |
| 4259 | C4Player *pPlayer = Game.Players.Get(iPlayer: iPlr); |
| 4260 | |
| 4261 | // get value |
| 4262 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: mkNamingAdapt(rValue&: *pPlayer, szName: "Player" )); |
| 4263 | } |
| 4264 | |
| 4265 | static C4Value FnGetPlayerInfoCoreVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4ValueInt iPlr, C4ValueInt iEntryNr) |
| 4266 | { |
| 4267 | const char *strSection = FnStringPar(pString: section); |
| 4268 | if (strSection && !*strSection) strSection = nullptr; |
| 4269 | |
| 4270 | if (!ValidPlr(plr: iPlr)) return C4VNull; |
| 4271 | |
| 4272 | // get player |
| 4273 | C4Player *pPlayer = Game.Players.Get(iPlayer: iPlr); |
| 4274 | |
| 4275 | // get plr info core |
| 4276 | C4PlayerInfoCore *pPlayerInfoCore = static_cast<C4PlayerInfoCore *>(pPlayer); |
| 4277 | |
| 4278 | // get value |
| 4279 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection, iEntryNr, rFrom: *pPlayerInfoCore); |
| 4280 | } |
| 4281 | |
| 4282 | static C4Value FnGetMaterialVal(C4AulContext *cthr, C4String *strEntry, C4String *section, C4ValueInt iMat, C4ValueInt iEntryNr) |
| 4283 | { |
| 4284 | const char *strSection = FnStringPar(pString: section); |
| 4285 | if (strSection && !*strSection) strSection = nullptr; |
| 4286 | |
| 4287 | if (iMat < 0 || iMat >= Game.Material.Num) return C4VNull; |
| 4288 | |
| 4289 | // get material |
| 4290 | C4Material *pMaterial = &Game.Material.Map[iMat]; |
| 4291 | |
| 4292 | // get plr info core |
| 4293 | C4MaterialCore *pMaterialCore = static_cast<C4MaterialCore *>(pMaterial); |
| 4294 | |
| 4295 | // material core implicates section "Material" |
| 4296 | if (!SEqual(szStr1: strSection, szStr2: "Material" )) return C4VNull; |
| 4297 | |
| 4298 | // get value |
| 4299 | return GetValByStdCompiler(strEntry: FnStringPar(pString: strEntry), strSection: nullptr, iEntryNr, rFrom: *pMaterialCore); |
| 4300 | } |
| 4301 | |
| 4302 | static bool (C4AulContext *cthr, C4Object *pObj) |
| 4303 | { |
| 4304 | if (!pObj) pObj = cthr->Obj; |
| 4305 | if (!pObj) return false; |
| 4306 | return pObj->CloseMenu(fForce: true); |
| 4307 | } |
| 4308 | |
| 4309 | static C4ValueInt (C4AulContext *cthr, C4Object *pObj) |
| 4310 | { |
| 4311 | if (!pObj) pObj = cthr->Obj; |
| 4312 | if (!pObj) return -1; |
| 4313 | if (!pObj->Menu || !pObj->Menu->IsActive()) return -1; |
| 4314 | return pObj->Menu->GetSelection(); |
| 4315 | } |
| 4316 | |
| 4317 | static bool FnResortObjects(C4AulContext *cthr, C4String *szFunc, C4ValueInt Category) |
| 4318 | { |
| 4319 | // safety |
| 4320 | if (!szFunc) return false; |
| 4321 | if (!cthr->Caller) return false; |
| 4322 | // default category |
| 4323 | if (!Category) Category = C4D_SortLimit; |
| 4324 | // get function |
| 4325 | C4AulFunc *pFn = cthr->Caller->Func->GetLocalSFunc(szIdtf: FnStringPar(pString: szFunc)); |
| 4326 | if (!pFn) |
| 4327 | throw C4AulExecError(cthr->Obj, std::format(fmt: "ResortObjects: Resort function {} not found" , args: FnStringPar(pString: szFunc))); |
| 4328 | // create object resort |
| 4329 | C4ObjResort *pObjRes = new C4ObjResort(); |
| 4330 | pObjRes->Category = Category; |
| 4331 | pObjRes->OrderFunc = pFn; |
| 4332 | // insert into game resort proc list |
| 4333 | pObjRes->Next = Game.Objects.ResortProc; |
| 4334 | Game.Objects.ResortProc = pObjRes; |
| 4335 | // success, so far |
| 4336 | return true; |
| 4337 | } |
| 4338 | |
| 4339 | static bool FnResortObject(C4AulContext *cthr, C4String *szFunc, C4Object *pObj) |
| 4340 | { |
| 4341 | // safety |
| 4342 | if (!szFunc) return false; |
| 4343 | if (!cthr->Caller) return false; |
| 4344 | if (!pObj) if (!(pObj = cthr->Obj)) return false; |
| 4345 | // get function |
| 4346 | C4AulFunc *pFn = cthr->Caller->Func->GetLocalSFunc(szIdtf: FnStringPar(pString: szFunc)); |
| 4347 | if (!pFn) |
| 4348 | throw C4AulExecError(cthr->Obj, std::format(fmt: "ResortObjects: Resort function {} not found" , args: FnStringPar(pString: szFunc))); |
| 4349 | // create object resort |
| 4350 | C4ObjResort *pObjRes = new C4ObjResort(); |
| 4351 | pObjRes->OrderFunc = pFn; |
| 4352 | pObjRes->pSortObj = pObj; |
| 4353 | // insert into game resort proc list |
| 4354 | pObjRes->Next = Game.Objects.ResortProc; |
| 4355 | Game.Objects.ResortProc = pObjRes; |
| 4356 | // success, so far |
| 4357 | return true; |
| 4358 | } |
| 4359 | |
| 4360 | static std::optional<C4ValueInt> FnGetChar(C4AulContext *cthr, C4String *pString, C4ValueInt iIndex) |
| 4361 | { |
| 4362 | const char *szText = FnStringPar(pString); |
| 4363 | if (!szText) return {}; |
| 4364 | // loop and check for end of string |
| 4365 | for (C4ValueInt i = 0; i < iIndex; i++, szText++) |
| 4366 | if (!*szText) return 0; |
| 4367 | // return indiced character value |
| 4368 | return static_cast<unsigned char>(*szText); |
| 4369 | } |
| 4370 | |
| 4371 | static bool FnSetGraphics(C4AulContext *pCtx, C4String *pGfxName, C4Object *pObj, C4ID idSrcGfx, C4ValueInt iOverlayID, C4ValueInt iOverlayMode, C4String *pAction, C4ValueInt dwBlitMode, C4Object *pOverlayObject) |
| 4372 | { |
| 4373 | // safety |
| 4374 | if (!pObj) if (!(pObj = pCtx->Obj)) return false; |
| 4375 | if (!pObj->Status) return false; |
| 4376 | // get def for source graphics |
| 4377 | C4Def *pSrcDef = nullptr; |
| 4378 | if (idSrcGfx) if (!(pSrcDef = C4Id2Def(id: idSrcGfx))) return false; |
| 4379 | // setting overlay? |
| 4380 | if (iOverlayID) |
| 4381 | { |
| 4382 | // any overlays must be positive for now |
| 4383 | if (iOverlayID < 0) { LogNTr(level: spdlog::level::err, message: "SetGraphics: Background overlays not implemented!" ); return false; } |
| 4384 | // deleting overlay? |
| 4385 | C4DefGraphics *pGrp; |
| 4386 | if (iOverlayMode == C4GraphicsOverlay::MODE_Object) |
| 4387 | { |
| 4388 | if (!pOverlayObject) return pObj->RemoveGraphicsOverlay(iOverlayID); |
| 4389 | } |
| 4390 | else |
| 4391 | { |
| 4392 | if (!pSrcDef) return pObj->RemoveGraphicsOverlay(iOverlayID); |
| 4393 | pGrp = pSrcDef->Graphics.Get(szGrpName: FnStringPar(pString: pGfxName)); |
| 4394 | if (!pGrp) return false; |
| 4395 | } |
| 4396 | // adding/setting |
| 4397 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: true); |
| 4398 | switch (iOverlayMode) |
| 4399 | { |
| 4400 | case C4GraphicsOverlay::MODE_Base: |
| 4401 | pOverlay->SetAsBase(pBaseGfx: pGrp, dwBMode: dwBlitMode); |
| 4402 | break; |
| 4403 | |
| 4404 | case C4GraphicsOverlay::MODE_Action: |
| 4405 | pOverlay->SetAsAction(pBaseGfx: pGrp, szAction: FnStringPar(pString: pAction), dwBMode: dwBlitMode); |
| 4406 | break; |
| 4407 | |
| 4408 | case C4GraphicsOverlay::MODE_IngamePicture: |
| 4409 | pOverlay->SetAsIngamePicture(pBaseGfx: pGrp, dwBMode: dwBlitMode); |
| 4410 | break; |
| 4411 | |
| 4412 | case C4GraphicsOverlay::MODE_Picture: |
| 4413 | pOverlay->SetAsPicture(pBaseGfx: pGrp, dwBMode: dwBlitMode); |
| 4414 | break; |
| 4415 | |
| 4416 | case C4GraphicsOverlay::MODE_Object: |
| 4417 | if (pOverlayObject && !pOverlayObject->Status) pOverlayObject = nullptr; |
| 4418 | pOverlay->SetAsObject(pOverlayObj: pOverlayObject, dwBMode: dwBlitMode); |
| 4419 | break; |
| 4420 | |
| 4421 | case C4GraphicsOverlay::MODE_ExtraGraphics: |
| 4422 | pOverlay->SetAsExtraGraphics(pGfx: pGrp, dwBMode: dwBlitMode); |
| 4423 | break; |
| 4424 | |
| 4425 | default: |
| 4426 | DebugLog(message: "SetGraphics: Invalid overlay mode" ); |
| 4427 | pOverlay->SetAsBase(pBaseGfx: nullptr, dwBMode: 0); // make invalid, so it will be removed |
| 4428 | break; |
| 4429 | } |
| 4430 | // remove if invalid |
| 4431 | if (!pOverlay->IsValid(pForObj: pObj)) |
| 4432 | { |
| 4433 | pObj->RemoveGraphicsOverlay(iOverlayID); |
| 4434 | return false; |
| 4435 | } |
| 4436 | // Okay, valid overlay set! |
| 4437 | return true; |
| 4438 | } |
| 4439 | // no overlay: Base graphics |
| 4440 | // set graphics - pSrcDef==nullptr defaults to pObj->pDef |
| 4441 | return pObj->SetGraphics(szGraphicsName: FnStringPar(pString: pGfxName), pSourceDef: pSrcDef); |
| 4442 | } |
| 4443 | |
| 4444 | static std::optional<C4ValueInt> FnGetDefBottom(C4AulContext *cthr, C4Object *pObj) |
| 4445 | { |
| 4446 | if (!pObj) if (!(pObj = cthr->Obj)) return {}; |
| 4447 | return pObj->y + pObj->Def->Shape.y + pObj->Def->Shape.Hgt; |
| 4448 | } |
| 4449 | |
| 4450 | static bool FnSetMaterialColor(C4AulContext *cthr, C4ValueInt iMat, C4ValueInt iClr1R, C4ValueInt iClr1G, C4ValueInt iClr1B, C4ValueInt iClr2R, C4ValueInt iClr2G, C4ValueInt iClr2B, C4ValueInt iClr3R, C4ValueInt iClr3G, C4ValueInt iClr3B) |
| 4451 | { |
| 4452 | // get mat |
| 4453 | if (!MatValid(mat: iMat)) return false; |
| 4454 | C4Material *pMat = &Game.Material.Map[iMat]; |
| 4455 | // newgfx: emulate by landscape modulation - enlightment not allowed... |
| 4456 | uint32_t dwBack, dwMod = GetClrModulation(C4RGB(pMat->Color[0], pMat->Color[1], pMat->Color[2]), C4RGB(iClr1R, iClr1G, iClr1B), back&: dwBack); |
| 4457 | dwMod &= 0xffffff; |
| 4458 | if (!dwMod) dwMod = 1; |
| 4459 | if (dwMod == 0xffffff) dwMod = 0; |
| 4460 | Game.Landscape.SetModulation(dwMod); |
| 4461 | // done |
| 4462 | return true; |
| 4463 | } |
| 4464 | |
| 4465 | static std::optional<C4ValueInt> FnGetMaterialColor(C4AulContext *cthr, C4ValueInt iMat, C4ValueInt iNum, C4ValueInt iChannel) |
| 4466 | { |
| 4467 | // get mat |
| 4468 | if (!MatValid(mat: iMat)) return {}; |
| 4469 | C4Material *pMat = &Game.Material.Map[iMat]; |
| 4470 | // get color |
| 4471 | return pMat->Color[iNum * 3 + iChannel]; |
| 4472 | } |
| 4473 | |
| 4474 | static C4String *FnMaterialName(C4AulContext *cthr, C4ValueInt iMat) |
| 4475 | { |
| 4476 | // mat valid? |
| 4477 | if (!MatValid(mat: iMat)) return nullptr; |
| 4478 | // return mat name |
| 4479 | return String(str: Game.Material.Map[iMat].Name); |
| 4480 | } |
| 4481 | |
| 4482 | static bool (C4AulContext *cthr, C4ValueInt iCols, C4ValueInt iRows, C4Object *pObj) |
| 4483 | { |
| 4484 | // get object |
| 4485 | if (!pObj) pObj = cthr->Obj; if (!pObj) return false; |
| 4486 | // get menu |
| 4487 | C4Menu *pMnu = pObj->Menu; |
| 4488 | if (!pMnu || !pMnu->IsActive()) return false; |
| 4489 | pMnu->SetSize(iToWdt: BoundBy<C4ValueInt>(bval: iCols, lbound: 0, rbound: 50), iToHgt: BoundBy<C4ValueInt>(bval: iRows, lbound: 0, rbound: 50)); |
| 4490 | return true; |
| 4491 | } |
| 4492 | |
| 4493 | static C4String *FnGetNeededMatStr(C4AulContext *cthr, C4Object *pObj) |
| 4494 | { |
| 4495 | // local/safety |
| 4496 | if (!pObj) if (!(pObj = cthr->Obj)) return nullptr; |
| 4497 | return String(str: pObj->GetNeededMatStr(pBuilder: cthr->Obj).c_str()); |
| 4498 | } |
| 4499 | |
| 4500 | static C4Value FnEval(C4AulContext *cthr, C4String *strScript) |
| 4501 | { |
| 4502 | // execute script in the same object |
| 4503 | C4AulScriptStrict Strict = C4AulScriptStrict::MAXSTRICT; |
| 4504 | if (cthr->Caller) |
| 4505 | Strict = cthr->Caller->Func->pOrgScript->Strict; |
| 4506 | if (cthr->Obj) |
| 4507 | return cthr->Obj->Def->Script.DirectExec(pObj: cthr->Obj, szScript: FnStringPar(pString: strScript), szContext: "eval" , fPassErrors: true, Strict); |
| 4508 | else if (cthr->Def) |
| 4509 | return cthr->Def->Script.DirectExec(pObj: nullptr, szScript: FnStringPar(pString: strScript), szContext: "eval" , fPassErrors: true, Strict); |
| 4510 | else |
| 4511 | return Game.Script.DirectExec(pObj: nullptr, szScript: FnStringPar(pString: strScript), szContext: "eval" , fPassErrors: true, Strict); |
| 4512 | } |
| 4513 | |
| 4514 | static bool FnLocateFunc(C4AulContext *cthr, C4String *funcname, C4Object *pObj, C4ID idDef) |
| 4515 | { |
| 4516 | // safety |
| 4517 | if (!funcname || !funcname->Data.getData()) |
| 4518 | { |
| 4519 | LogNTr(level: spdlog::level::err, message: "No func name" ); |
| 4520 | return false; |
| 4521 | } |
| 4522 | // determine script context |
| 4523 | C4AulScript *pCheckScript; |
| 4524 | if (pObj) |
| 4525 | { |
| 4526 | pCheckScript = &pObj->Def->Script; |
| 4527 | } |
| 4528 | else if (idDef) |
| 4529 | { |
| 4530 | C4Def *pDef = C4Id2Def(id: idDef); |
| 4531 | if (!pDef) { LogNTr(level: spdlog::level::err, message: "Invalid or unloaded def" ); return false; } |
| 4532 | pCheckScript = &pDef->Script; |
| 4533 | } |
| 4534 | else |
| 4535 | { |
| 4536 | if (!cthr || !cthr->Caller || !cthr->Caller->Func || !cthr->Caller->Func->Owner) |
| 4537 | { |
| 4538 | LogNTr(level: spdlog::level::err, message: "No valid script context" ); |
| 4539 | return false; |
| 4540 | } |
| 4541 | pCheckScript = cthr->Caller->Func->Owner; |
| 4542 | } |
| 4543 | // get function by name |
| 4544 | C4AulFunc *pFunc = pCheckScript->GetFuncRecursive(pIdtf: funcname->Data.getData()); |
| 4545 | if (!pFunc) |
| 4546 | { |
| 4547 | LogNTr(level: spdlog::level::err, fmt: "Func {} not found" , args: funcname->Data.getData()); |
| 4548 | } |
| 4549 | else |
| 4550 | { |
| 4551 | const char *szPrefix = "" ; |
| 4552 | while (pFunc) |
| 4553 | { |
| 4554 | C4AulScriptFunc *pSFunc = pFunc->SFunc(); |
| 4555 | if (!pSFunc) |
| 4556 | { |
| 4557 | LogNTr(fmt: "{}{} (engine)" , args&: szPrefix, args: +pFunc->Name); |
| 4558 | } |
| 4559 | else if (!pSFunc->pOrgScript) |
| 4560 | { |
| 4561 | LogNTr(fmt: "{}{} (no owner)" , args&: szPrefix, args: +pSFunc->Name); |
| 4562 | } |
| 4563 | else |
| 4564 | { |
| 4565 | int32_t iLine = SGetLine(szText: pSFunc->pOrgScript->GetScript(), cpPosition: pSFunc->Script); |
| 4566 | LogNTr(fmt: "{}{} ({}:{})" , args&: szPrefix, args: +pFunc->Name, args: pSFunc->pOrgScript->ScriptName.c_str(), args: static_cast<int>(iLine)); |
| 4567 | } |
| 4568 | // next func in overload chain |
| 4569 | pFunc = pSFunc ? pSFunc->OwnerOverloaded : nullptr; |
| 4570 | szPrefix = "overloads " ; |
| 4571 | } |
| 4572 | } |
| 4573 | return true; |
| 4574 | } |
| 4575 | |
| 4576 | static C4Value FnVarN(C4AulContext *cthr, C4String *name) |
| 4577 | { |
| 4578 | const char *strName = FnStringPar(pString: name); |
| 4579 | |
| 4580 | if (!cthr->Caller) return C4VNull; |
| 4581 | |
| 4582 | // find variable |
| 4583 | int32_t iID = cthr->Caller->Func->VarNamed.GetItemNr(strName); |
| 4584 | if (iID < 0) |
| 4585 | return C4VNull; |
| 4586 | |
| 4587 | // return reference on variable |
| 4588 | return cthr->Caller->Vars[iID].GetRef(); |
| 4589 | } |
| 4590 | |
| 4591 | static C4Value FnLocalN(C4AulContext *cthr, C4String *name, C4Object *pObj) |
| 4592 | { |
| 4593 | const char *strName = FnStringPar(pString: name); |
| 4594 | if (!pObj) pObj = cthr->Obj; |
| 4595 | if (!pObj) return C4VNull; |
| 4596 | |
| 4597 | // find variable |
| 4598 | C4Value *pVarN = pObj->LocalNamed.GetItem(strName); |
| 4599 | |
| 4600 | if (!pVarN) return C4VNull; |
| 4601 | |
| 4602 | // return reference on variable |
| 4603 | return pVarN->GetRef(); |
| 4604 | } |
| 4605 | |
| 4606 | static C4Value FnGlobalN(C4AulContext *cthr, C4String *name) |
| 4607 | { |
| 4608 | const char *strName = FnStringPar(pString: name); |
| 4609 | |
| 4610 | // find variable |
| 4611 | C4Value *pVarN = Game.ScriptEngine.GlobalNamed.GetItem(strName); |
| 4612 | |
| 4613 | if (!pVarN) return C4VNull; |
| 4614 | |
| 4615 | // return reference on variable |
| 4616 | return pVarN->GetRef(); |
| 4617 | } |
| 4618 | |
| 4619 | static void FnSetSkyAdjust(C4AulContext *cthr, C4ValueInt dwAdjust, C4ValueInt dwBackClr) |
| 4620 | { |
| 4621 | // set adjust |
| 4622 | Game.Landscape.Sky.SetModulation(dwWithClr: dwAdjust, dwBackClr); |
| 4623 | } |
| 4624 | |
| 4625 | static void FnSetMatAdjust(C4AulContext *cthr, C4ValueInt dwAdjust) |
| 4626 | { |
| 4627 | // set adjust |
| 4628 | Game.Landscape.SetModulation(dwAdjust); |
| 4629 | } |
| 4630 | |
| 4631 | static C4ValueInt FnGetSkyAdjust(C4AulContext *cthr, bool fBackColor) |
| 4632 | { |
| 4633 | // get adjust |
| 4634 | return Game.Landscape.Sky.GetModulation(fBackClr: !!fBackColor); |
| 4635 | } |
| 4636 | |
| 4637 | static C4ValueInt FnGetMatAdjust(C4AulContext *cthr) |
| 4638 | { |
| 4639 | // get adjust |
| 4640 | return Game.Landscape.GetModulation(); |
| 4641 | } |
| 4642 | |
| 4643 | static C4ValueInt FnAnyContainer(C4AulContext *) { return ANY_CONTAINER; } |
| 4644 | static C4ValueInt FnNoContainer(C4AulContext *) { return NO_CONTAINER; } |
| 4645 | |
| 4646 | static std::optional<C4ValueInt> FnGetTime(C4AulContext *) |
| 4647 | { |
| 4648 | // check network, record, etc |
| 4649 | if (Game.Control.SyncMode()) return {}; |
| 4650 | return {timeGetTime()}; |
| 4651 | } |
| 4652 | |
| 4653 | static std::optional<C4ValueInt> FnGetSystemTime(C4AulContext *cthr, C4ValueInt iWhat) |
| 4654 | { |
| 4655 | // check network, record, etc |
| 4656 | if (Game.Control.SyncMode()) return {}; |
| 4657 | // check bounds |
| 4658 | if (!Inside<C4ValueInt>(ival: iWhat, lbound: 0, rbound: 7)) return {}; |
| 4659 | #ifdef _WIN32 |
| 4660 | SYSTEMTIME time; |
| 4661 | GetLocalTime(&time); |
| 4662 | // return queried value |
| 4663 | return {*(((WORD *)&time) + iWhat)}; |
| 4664 | #else |
| 4665 | struct timeval tv; |
| 4666 | if (gettimeofday(tv: &tv, tz: nullptr)) return {}; |
| 4667 | if (iWhat == 7) return tv.tv_usec / 1000; |
| 4668 | struct tm *time; |
| 4669 | time = localtime(timer: &tv.tv_sec); |
| 4670 | switch (iWhat) |
| 4671 | { |
| 4672 | case 0: return {time->tm_year + 1900}; |
| 4673 | case 1: return {time->tm_mon + 1}; |
| 4674 | case 2: return {time->tm_wday}; |
| 4675 | case 3: return {time->tm_mday}; |
| 4676 | case 4: return {time->tm_hour}; |
| 4677 | case 5: return {time->tm_min}; |
| 4678 | case 6: return {time->tm_sec}; |
| 4679 | } |
| 4680 | |
| 4681 | return {}; |
| 4682 | #endif |
| 4683 | } |
| 4684 | |
| 4685 | static C4Value (C4AulContext *cthr, C4ValueInt iPlayer, C4String *DataName, C4Value Data) |
| 4686 | { |
| 4687 | const char *strDataName = FnStringPar(pString: DataName); |
| 4688 | |
| 4689 | if (!strDataName || !strDataName[0]) return C4VNull; |
| 4690 | if (!StdCompiler::IsIdentifier(str: strDataName)) |
| 4691 | { |
| 4692 | StdStrBuf name{strDataName}; |
| 4693 | name.EscapeString(); |
| 4694 | DebugLog(level: spdlog::level::warn, fmt: "SetPlrExtraData: Ignoring invalid data name \"{}\"! Only alphanumerics, _ and - are allowed." , args: name.getData()); |
| 4695 | return C4VNull; |
| 4696 | } |
| 4697 | |
| 4698 | // valid player? (for great nullpointer prevention) |
| 4699 | if (!ValidPlr(plr: iPlayer)) return C4VNull; |
| 4700 | // do not allow data type C4V_String or C4V_C4Object |
| 4701 | if (Data.GetType() != C4V_Any && |
| 4702 | Data.GetType() != C4V_Int && |
| 4703 | Data.GetType() != C4V_Bool && |
| 4704 | Data.GetType() != C4V_C4ID) return C4VNull; |
| 4705 | // get pointer on player... |
| 4706 | C4Player *pPlayer = Game.Players.Get(iPlayer); |
| 4707 | // no name list created yet? |
| 4708 | if (!pPlayer->ExtraData.pNames) |
| 4709 | // create name list |
| 4710 | pPlayer->ExtraData.CreateTempNameList(); |
| 4711 | // data name already exists? |
| 4712 | C4ValueInt ival; |
| 4713 | if ((ival = pPlayer->ExtraData.pNames->GetItemNr(strName: strDataName)) != -1) |
| 4714 | pPlayer->ExtraData[ival] = Data; |
| 4715 | else |
| 4716 | { |
| 4717 | // add name |
| 4718 | pPlayer->ExtraData.pNames->AddName(pnName: strDataName); |
| 4719 | // get val id & set |
| 4720 | if ((ival = pPlayer->ExtraData.pNames->GetItemNr(strName: strDataName)) == -1) return C4VNull; |
| 4721 | pPlayer->ExtraData[ival] = Data; |
| 4722 | } |
| 4723 | // ok, return the value that has been set |
| 4724 | return Data; |
| 4725 | } |
| 4726 | |
| 4727 | static C4Value (C4AulContext *cthr, C4ValueInt iPlayer, C4String *DataName) |
| 4728 | { |
| 4729 | const char *strDataName = FnStringPar(pString: DataName); |
| 4730 | // valid player? |
| 4731 | if (!ValidPlr(plr: iPlayer)) return C4VNull; |
| 4732 | // get pointer on player... |
| 4733 | C4Player *pPlayer = Game.Players.Get(iPlayer); |
| 4734 | // no name list? |
| 4735 | if (!pPlayer->ExtraData.pNames) return C4VNull; |
| 4736 | C4ValueInt ival; |
| 4737 | if ((ival = pPlayer->ExtraData.pNames->GetItemNr(strName: strDataName)) == -1) return C4VNull; |
| 4738 | // return data |
| 4739 | return pPlayer->ExtraData[ival]; |
| 4740 | } |
| 4741 | |
| 4742 | static C4Value (C4AulContext *cthr, C4Object *pCrew, C4String *dataName, C4Value Data) |
| 4743 | { |
| 4744 | if (!pCrew) pCrew = cthr->Obj; |
| 4745 | const char *strDataName = FnStringPar(pString: dataName); |
| 4746 | |
| 4747 | if (!strDataName || !strDataName[0]) return C4VNull; |
| 4748 | if (!StdCompiler::IsIdentifier(str: strDataName)) |
| 4749 | { |
| 4750 | StdStrBuf name{strDataName}; |
| 4751 | name.EscapeString(); |
| 4752 | DebugLog(level: spdlog::level::err, fmt: "SetCrewExtraData: Ignoring invalid data name \"{}\"! Only alphanumerics, _ and - are allowed." , args: name.getData()); |
| 4753 | return C4VNull; |
| 4754 | } |
| 4755 | |
| 4756 | // valid crew with info? (for great nullpointer prevention) |
| 4757 | if (!pCrew || !pCrew->Info) return C4VNull; |
| 4758 | // do not allow data type C4V_String or C4V_C4Object |
| 4759 | if (Data.GetType() != C4V_Any && |
| 4760 | Data.GetType() != C4V_Int && |
| 4761 | Data.GetType() != C4V_Bool && |
| 4762 | Data.GetType() != C4V_C4ID) return C4VNull; |
| 4763 | // get pointer on info... |
| 4764 | C4ObjectInfo *pInfo = pCrew->Info; |
| 4765 | // no name list created yet? |
| 4766 | if (!pInfo->ExtraData.pNames) |
| 4767 | // create name list |
| 4768 | pInfo->ExtraData.CreateTempNameList(); |
| 4769 | // data name already exists? |
| 4770 | C4ValueInt ival; |
| 4771 | if ((ival = pInfo->ExtraData.pNames->GetItemNr(strName: strDataName)) != -1) |
| 4772 | pInfo->ExtraData[ival] = Data; |
| 4773 | else |
| 4774 | { |
| 4775 | // add name |
| 4776 | pInfo->ExtraData.pNames->AddName(pnName: strDataName); |
| 4777 | // get val id & set |
| 4778 | if ((ival = pInfo->ExtraData.pNames->GetItemNr(strName: strDataName)) == -1) return C4VNull; |
| 4779 | pInfo->ExtraData[ival] = Data; |
| 4780 | } |
| 4781 | // ok, return the value that has been set |
| 4782 | return Data; |
| 4783 | } |
| 4784 | |
| 4785 | static C4Value (C4AulContext *cthr, C4Object *pCrew, C4String *dataName) |
| 4786 | { |
| 4787 | if (!pCrew) pCrew = cthr->Obj; |
| 4788 | const char *strDataName = FnStringPar(pString: dataName); |
| 4789 | // valid crew with info? |
| 4790 | if (!pCrew || !pCrew->Info) return C4VNull; |
| 4791 | // get pointer on info... |
| 4792 | C4ObjectInfo *pInfo = pCrew->Info; |
| 4793 | // no name list? |
| 4794 | if (!pInfo->ExtraData.pNames) return C4VNull; |
| 4795 | C4ValueInt ival; |
| 4796 | if ((ival = pInfo->ExtraData.pNames->GetItemNr(strName: strDataName)) == -1) return C4VNull; |
| 4797 | // return data |
| 4798 | return pInfo->ExtraData[ival]; |
| 4799 | } |
| 4800 | |
| 4801 | static C4ValueInt FnDrawMatChunks(C4AulContext *cctx, C4ValueInt tx, C4ValueInt ty, C4ValueInt twdt, C4ValueInt thgt, C4ValueInt icntx, C4ValueInt icnty, C4String *strMaterial, C4String *strTexture, bool bIFT) |
| 4802 | { |
| 4803 | return Game.Landscape.DrawChunks(tx, ty, wdt: twdt, hgt: thgt, icntx, icnty, szMaterial: FnStringPar(pString: strMaterial), szTexture: FnStringPar(pString: strTexture), bIFT: bIFT != 0); |
| 4804 | } |
| 4805 | |
| 4806 | static std::optional<bool> FnGetCrewEnabled(C4AulContext *cctx, C4Object *pObj) |
| 4807 | { |
| 4808 | // local/safety |
| 4809 | if (!pObj) pObj = cctx->Obj; if (!pObj) return {}; |
| 4810 | // return status |
| 4811 | return !pObj->CrewDisabled; |
| 4812 | } |
| 4813 | |
| 4814 | static bool FnSetCrewEnabled(C4AulContext *cctx, bool fEnabled, C4Object *pObj) |
| 4815 | { |
| 4816 | // local/safety |
| 4817 | if (!pObj) pObj = cctx->Obj; if (!pObj) return false; |
| 4818 | // set status |
| 4819 | pObj->CrewDisabled = !fEnabled; |
| 4820 | // deselect |
| 4821 | if (!fEnabled) |
| 4822 | { |
| 4823 | pObj->Select = false; |
| 4824 | C4Player *pOwner; |
| 4825 | if (pOwner = Game.Players.Get(iPlayer: pObj->Owner)) |
| 4826 | { |
| 4827 | // if viewed player cursor gets deactivated and no new cursor is found, follow the old in target mode |
| 4828 | bool fWasCursorMode = (pOwner->ViewMode == C4PVM_Cursor); |
| 4829 | if (pOwner->Cursor == pObj) |
| 4830 | pOwner->AdjustCursorCommand(); |
| 4831 | if (!pOwner->ViewCursor && !pOwner->Cursor && fWasCursorMode) |
| 4832 | pOwner->SetViewMode(iMode: C4PVM_Target, pTarget: pObj); |
| 4833 | } |
| 4834 | } |
| 4835 | // success |
| 4836 | return true; |
| 4837 | } |
| 4838 | |
| 4839 | static bool FnUnselectCrew(C4AulContext *cctx, C4ValueInt iPlayer) |
| 4840 | { |
| 4841 | // get player |
| 4842 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 4843 | if (!pPlr) return false; |
| 4844 | // unselect crew |
| 4845 | pPlr->UnselectCrew(); |
| 4846 | // success |
| 4847 | return true; |
| 4848 | } |
| 4849 | |
| 4850 | static C4ValueInt FnDrawMap(C4AulContext *cctx, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4String *szMapDef) |
| 4851 | { |
| 4852 | // draw it! |
| 4853 | return Game.Landscape.DrawMap(iX, iY, iWdt, iHgt, szMapDef: FnStringPar(pString: szMapDef)); |
| 4854 | } |
| 4855 | |
| 4856 | static C4ValueInt FnDrawDefMap(C4AulContext *cctx, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4String *szMapDef) |
| 4857 | { |
| 4858 | // draw it! |
| 4859 | return Game.Landscape.DrawDefMap(iX, iY, iWdt, iHgt, szMapDef: FnStringPar(pString: szMapDef)); |
| 4860 | } |
| 4861 | |
| 4862 | static bool FnCreateParticle(C4AulContext *cthr, C4String *szName, C4ValueInt iX, C4ValueInt iY, C4ValueInt iXDir, C4ValueInt iYDir, C4ValueInt a, C4ValueInt b, C4Object *pObj, bool fBack) |
| 4863 | { |
| 4864 | // safety |
| 4865 | if (pObj && !pObj->Status) return false; |
| 4866 | // local offset |
| 4867 | if (cthr->Obj) |
| 4868 | { |
| 4869 | iX += cthr->Obj->x; |
| 4870 | iY += cthr->Obj->y; |
| 4871 | } |
| 4872 | // get particle |
| 4873 | C4ParticleDef *pDef = Game.Particles.GetDef(szName: FnStringPar(pString: szName)); |
| 4874 | if (!pDef) return false; |
| 4875 | // create |
| 4876 | Game.Particles.Create(pOfDef: pDef, x: static_cast<float>(iX), y: static_cast<float>(iY), xdir: static_cast<float>(iXDir) / 10.0f, ydir: static_cast<float>(iYDir) / 10.0f, a: static_cast<float>(a) / 10.0f, b, pPxList: pObj ? (fBack ? &pObj->BackParticles : &pObj->FrontParticles) : nullptr, pObj); |
| 4877 | // success, even if not created |
| 4878 | return true; |
| 4879 | } |
| 4880 | |
| 4881 | static bool FnCastAParticles(C4AulContext *cthr, C4String *szName, C4ValueInt iAmount, C4ValueInt iLevel, C4ValueInt iX, C4ValueInt iY, C4ValueInt a0, C4ValueInt a1, C4ValueInt b0, C4ValueInt b1, C4Object *pObj, bool fBack) |
| 4882 | { |
| 4883 | // safety |
| 4884 | if (pObj && !pObj->Status) return false; |
| 4885 | // local offset |
| 4886 | if (cthr->Obj) |
| 4887 | { |
| 4888 | iX += cthr->Obj->x; |
| 4889 | iY += cthr->Obj->y; |
| 4890 | } |
| 4891 | // get particle |
| 4892 | C4ParticleDef *pDef = Game.Particles.GetDef(szName: FnStringPar(pString: szName)); |
| 4893 | if (!pDef) return false; |
| 4894 | // cast |
| 4895 | Game.Particles.Cast(pOfDef: pDef, iAmount, x: static_cast<float>(iX), y: static_cast<float>(iY), level: iLevel, a0: static_cast<float>(a0) / 10.0f, b0, a1: static_cast<float>(a1) / 10.0f, b1, pPxList: pObj ? (fBack ? &pObj->BackParticles : &pObj->FrontParticles) : nullptr, pObj); |
| 4896 | // success, even if not created |
| 4897 | return true; |
| 4898 | } |
| 4899 | |
| 4900 | static bool FnCastParticles(C4AulContext *cthr, C4String *szName, C4ValueInt iAmount, C4ValueInt iLevel, C4ValueInt iX, C4ValueInt iY, C4ValueInt a0, C4ValueInt a1, C4ValueInt b0, C4ValueInt b1, C4Object *pObj) |
| 4901 | { |
| 4902 | return FnCastAParticles(cthr, szName, iAmount, iLevel, iX, iY, a0, a1, b0, b1, pObj, fBack: false); |
| 4903 | } |
| 4904 | |
| 4905 | static bool FnCastBackParticles(C4AulContext *cthr, C4String *szName, C4ValueInt iAmount, C4ValueInt iLevel, C4ValueInt iX, C4ValueInt iY, C4ValueInt a0, C4ValueInt a1, C4ValueInt b0, C4ValueInt b1, C4Object *pObj) |
| 4906 | { |
| 4907 | return FnCastAParticles(cthr, szName, iAmount, iLevel, iX, iY, a0, a1, b0, b1, pObj, fBack: true); |
| 4908 | } |
| 4909 | |
| 4910 | static bool FnPushParticles(C4AulContext *cthr, C4String *szName, C4ValueInt iAX, C4ValueInt iAY) |
| 4911 | { |
| 4912 | // particle given? |
| 4913 | C4ParticleDef *pDef = nullptr; |
| 4914 | if (szName) |
| 4915 | { |
| 4916 | pDef = Game.Particles.GetDef(szName: FnStringPar(pString: szName)); |
| 4917 | if (!pDef) return false; |
| 4918 | } |
| 4919 | // push them |
| 4920 | Game.Particles.Push(pOfDef: pDef, dxdir: static_cast<float>(iAX) / 10.0f, dydir: static_cast<float>(iAY) / 10.0f); |
| 4921 | // success |
| 4922 | return true; |
| 4923 | } |
| 4924 | |
| 4925 | static bool FnClearParticles(C4AulContext *cthr, C4String *szName, C4Object *pObj) |
| 4926 | { |
| 4927 | // particle given? |
| 4928 | C4ParticleDef *pDef = nullptr; |
| 4929 | if (szName) |
| 4930 | { |
| 4931 | pDef = Game.Particles.GetDef(szName: FnStringPar(pString: szName)); |
| 4932 | if (!pDef) return false; |
| 4933 | } |
| 4934 | // delete them |
| 4935 | if (pObj) |
| 4936 | { |
| 4937 | pObj->FrontParticles.Remove(pOfDef: pDef); |
| 4938 | pObj->BackParticles.Remove(pOfDef: pDef); |
| 4939 | } |
| 4940 | else |
| 4941 | Game.Particles.GlobalParticles.Remove(pOfDef: pDef); |
| 4942 | // success |
| 4943 | return true; |
| 4944 | } |
| 4945 | |
| 4946 | static bool FnIsNewgfx(C4AulContext *) { return true; } |
| 4947 | |
| 4948 | #define SkyPar_KEEP -163764 |
| 4949 | |
| 4950 | static void FnSetSkyParallax(C4AulContext *ctx, C4ValueInt iMode, C4ValueInt iParX, C4ValueInt iParY, C4ValueInt iXDir, C4ValueInt iYDir, C4ValueInt iX, C4ValueInt iY) |
| 4951 | { |
| 4952 | // set all parameters that aren't SkyPar_KEEP |
| 4953 | if (iMode != SkyPar_KEEP) |
| 4954 | if (Inside<C4ValueInt>(ival: iMode, lbound: 0, rbound: 1)) Game.Landscape.Sky.ParallaxMode = iMode; |
| 4955 | if (iParX != SkyPar_KEEP && iParX) Game.Landscape.Sky.ParX = iParX; |
| 4956 | if (iParY != SkyPar_KEEP && iParY) Game.Landscape.Sky.ParY = iParY; |
| 4957 | if (iXDir != SkyPar_KEEP) Game.Landscape.Sky.xdir = itofix(x: iXDir); |
| 4958 | if (iYDir != SkyPar_KEEP) Game.Landscape.Sky.ydir = itofix(x: iYDir); |
| 4959 | if (iX != SkyPar_KEEP) Game.Landscape.Sky.x = itofix(x: iX); |
| 4960 | if (iY != SkyPar_KEEP) Game.Landscape.Sky.y = itofix(x: iY); |
| 4961 | } |
| 4962 | |
| 4963 | static bool FnDoCrewExp(C4AulContext *ctx, C4ValueInt iChange, C4Object *pObj) |
| 4964 | { |
| 4965 | // local call/safety |
| 4966 | if (!pObj) pObj = ctx->Obj; if (!pObj) return false; |
| 4967 | // do exp |
| 4968 | pObj->DoExperience(change: iChange); |
| 4969 | // success |
| 4970 | return true; |
| 4971 | } |
| 4972 | |
| 4973 | static C4ValueInt FnReloadDef(C4AulContext *ctx, C4ID idDef) |
| 4974 | { |
| 4975 | // get def |
| 4976 | C4Def *pDef = nullptr; |
| 4977 | if (!idDef) |
| 4978 | { |
| 4979 | // no def given: local def |
| 4980 | if (ctx->Obj) pDef = ctx->Obj->Def; |
| 4981 | } |
| 4982 | else |
| 4983 | // def by ID |
| 4984 | pDef = Game.Defs.ID2Def(id: idDef); |
| 4985 | // safety |
| 4986 | if (!pDef) return false; |
| 4987 | // perform reload |
| 4988 | return Game.ReloadDef(id: pDef->id, reloadWhat: C4D_Load_RX); |
| 4989 | } |
| 4990 | |
| 4991 | static C4ValueInt FnReloadParticle(C4AulContext *ctx, C4String *szParticleName) |
| 4992 | { |
| 4993 | // perform reload |
| 4994 | return Game.ReloadParticle(szName: FnStringPar(pString: szParticleName)); |
| 4995 | } |
| 4996 | |
| 4997 | static void FnSetGamma(C4AulContext *ctx, C4ValueInt dwClr1, C4ValueInt dwClr2, C4ValueInt dwClr3, C4ValueInt iRampIndex) |
| 4998 | { |
| 4999 | Game.GraphicsSystem.SetGamma(dwClr1, dwClr2, dwClr3, iRampIndex); |
| 5000 | } |
| 5001 | |
| 5002 | static void FnResetGamma(C4AulContext *ctx, C4ValueInt iRampIndex) |
| 5003 | { |
| 5004 | Game.GraphicsSystem.SetGamma(dwClr1: 0x000000, dwClr2: 0x808080, dwClr3: 0xffffff, iRampIndex); |
| 5005 | } |
| 5006 | |
| 5007 | static C4ValueInt FnFrameCounter(C4AulContext *) { return Game.FrameCounter; } |
| 5008 | |
| 5009 | static C4ValueHash *FnGetPath(C4AulContext *ctx, C4ValueInt iFromX, C4ValueInt iFromY, C4ValueInt iToX, C4ValueInt iToY) |
| 5010 | { |
| 5011 | struct Waypoint |
| 5012 | { |
| 5013 | int32_t x = 0; |
| 5014 | int32_t y = 0; |
| 5015 | C4Object *obj = nullptr; |
| 5016 | }; |
| 5017 | |
| 5018 | struct PathInfo |
| 5019 | { |
| 5020 | std::vector<Waypoint> path; |
| 5021 | int32_t length = 0; |
| 5022 | }; |
| 5023 | |
| 5024 | auto SetWaypoint = [](int32_t x, int32_t y, intptr_t transferTarget, intptr_t pathInfo) -> bool |
| 5025 | { |
| 5026 | auto *target = reinterpret_cast<C4Object *>(transferTarget); |
| 5027 | auto *pathinfo = reinterpret_cast<PathInfo *>(pathInfo); |
| 5028 | |
| 5029 | const Waypoint &last = pathinfo->path.back(); |
| 5030 | pathinfo->length += Distance(iX1: last.x, iY1: last.y, iX2: x, iY2: y); |
| 5031 | |
| 5032 | pathinfo->path.push_back(x: {.x: x, .y: y, .obj: target}); |
| 5033 | return true; |
| 5034 | }; |
| 5035 | |
| 5036 | PathInfo pathinfo; |
| 5037 | pathinfo.path.push_back(x: {.x: static_cast<int32_t>(iFromX), .y: static_cast<int32_t>(iFromY), .obj: nullptr}); |
| 5038 | |
| 5039 | if (!Game.PathFinder.Find(iFromX, iFromY, iToX, iToY, fnSetWaypoint: SetWaypoint, iWaypointParameter: reinterpret_cast<intptr_t>(&pathinfo))) |
| 5040 | { |
| 5041 | return nullptr; |
| 5042 | } |
| 5043 | |
| 5044 | SetWaypoint(static_cast<int32_t>(iToX), static_cast<int32_t>(iToY), reinterpret_cast<intptr_t>(nullptr), reinterpret_cast<intptr_t>(&pathinfo)); |
| 5045 | |
| 5046 | auto *hash = new C4ValueHash; |
| 5047 | (*hash)[C4VString(strString: "Length" )] = C4VInt(iVal: pathinfo.length); |
| 5048 | |
| 5049 | auto *array = new C4ValueArray(static_cast<int32_t>(pathinfo.path.size())); |
| 5050 | |
| 5051 | if (!pathinfo.path.empty()) |
| 5052 | { |
| 5053 | for (size_t i = 0; i < pathinfo.path.size(); ++i) |
| 5054 | { |
| 5055 | auto *waypoint = new C4ValueHash; |
| 5056 | (*waypoint)[C4VString(strString: "X" )] = C4VInt(iVal: pathinfo.path[i].x); |
| 5057 | (*waypoint)[C4VString(strString: "Y" )] = C4VInt(iVal: pathinfo.path[i].y); |
| 5058 | if (pathinfo.path[i].obj) |
| 5059 | (*waypoint)[C4VString(strString: "TransferTarget" )] = C4VObj(pObj: pathinfo.path[i].obj); |
| 5060 | |
| 5061 | (*array)[static_cast<int32_t>(i)] = C4VMap(pMap: waypoint); |
| 5062 | } |
| 5063 | } |
| 5064 | |
| 5065 | (*hash)[C4VString(strString: "Waypoints" )] = C4VArray(pArray: array); |
| 5066 | |
| 5067 | return hash; |
| 5068 | } |
| 5069 | |
| 5070 | static C4ValueInt FnSetTextureIndex(C4AulContext *ctx, C4String *psMatTex, C4ValueInt iNewIndex, bool fInsert) |
| 5071 | { |
| 5072 | if (!Inside(ival: iNewIndex, lbound: C4ValueInt{0}, rbound: C4ValueInt{255})) return false; |
| 5073 | return Game.Landscape.SetTextureIndex(szMatTex: FnStringPar(pString: psMatTex), iNewIndex: uint8_t(iNewIndex), fInsert: !!fInsert); |
| 5074 | } |
| 5075 | |
| 5076 | static void FnRemoveUnusedTexMapEntries(C4AulContext *ctx) |
| 5077 | { |
| 5078 | Game.Landscape.RemoveUnusedTexMapEntries(); |
| 5079 | } |
| 5080 | |
| 5081 | static void FnSetLandscapePixel(C4AulContext *ctx, C4ValueInt iX, C4ValueInt iY, C4ValueInt dwValue) |
| 5082 | { |
| 5083 | // local call |
| 5084 | if (ctx->Obj) { iX += ctx->Obj->x; iY += ctx->Obj->y; } |
| 5085 | // set pixel in 32bit-sfc only |
| 5086 | Game.Landscape.SetPixDw(x: iX, y: iY, dwPix: dwValue); |
| 5087 | } |
| 5088 | |
| 5089 | static bool FnSetObjectOrder(C4AulContext *ctx, C4Object *pObjBeforeOrAfter, C4Object *pSortObj, bool fSortAfter) |
| 5090 | { |
| 5091 | // local call/safety |
| 5092 | if (!pSortObj) pSortObj = ctx->Obj; if (!pSortObj) return false; |
| 5093 | if (!pObjBeforeOrAfter) return false; |
| 5094 | // don't sort an object before or after itself, it messes up the object list and causes infinite loops |
| 5095 | if (pObjBeforeOrAfter == pSortObj) return false; |
| 5096 | // note that no category check is done, so this call might corrupt the main list! |
| 5097 | // the scripter must be wise enough not to call it for objects with different categories |
| 5098 | // create object resort |
| 5099 | C4ObjResort *pObjRes = new C4ObjResort(); |
| 5100 | pObjRes->pSortObj = pSortObj; |
| 5101 | pObjRes->pObjBefore = pObjBeforeOrAfter; |
| 5102 | pObjRes->fSortAfter = fSortAfter; |
| 5103 | // insert into game resort proc list |
| 5104 | pObjRes->Next = Game.Objects.ResortProc; |
| 5105 | Game.Objects.ResortProc = pObjRes; |
| 5106 | // done, success so far |
| 5107 | return true; |
| 5108 | } |
| 5109 | |
| 5110 | static bool FnDrawMaterialQuad(C4AulContext *ctx, C4String *szMaterial, C4ValueInt iX1, C4ValueInt iY1, C4ValueInt iX2, C4ValueInt iY2, C4ValueInt iX3, C4ValueInt iY3, C4ValueInt iX4, C4ValueInt iY4, bool fSub) |
| 5111 | { |
| 5112 | const char *szMat = FnStringPar(pString: szMaterial); |
| 5113 | return !!Game.Landscape.DrawQuad(iX1, iY1, iX2, iY2, iX3, iY3, iX4, iY4, szMaterial: szMat, bIFT: fSub); |
| 5114 | } |
| 5115 | |
| 5116 | static bool FnFightWith(C4AulContext *ctx, C4Object *pTarget, C4Object *pClonk) |
| 5117 | { |
| 5118 | // local call/safety |
| 5119 | if (!pTarget) return false; |
| 5120 | if (!pClonk) if (!(pClonk = ctx->Obj)) return false; |
| 5121 | // check OCF |
| 5122 | if (~(pTarget->OCF & pClonk->OCF) & OCF_FightReady) return false; |
| 5123 | // RejectFight callback |
| 5124 | if (pTarget->Call(PSF_RejectFight, pPars: {C4VObj(pObj: pTarget)}, fPassError: true).getBool()) return false; |
| 5125 | if (pClonk->Call(PSF_RejectFight, pPars: {C4VObj(pObj: pClonk)}, fPassError: true).getBool()) return false; |
| 5126 | // begin fighting |
| 5127 | ObjectActionFight(cObj: pClonk, pTarget); |
| 5128 | ObjectActionFight(cObj: pTarget, pTarget: pClonk); |
| 5129 | // success |
| 5130 | return true; |
| 5131 | } |
| 5132 | |
| 5133 | static bool FnSetFilmView(C4AulContext *ctx, C4ValueInt iToPlr) |
| 5134 | { |
| 5135 | // check player |
| 5136 | if (!ValidPlr(plr: iToPlr) && iToPlr != NO_OWNER) return false; |
| 5137 | // real switch in replays only |
| 5138 | if (!Game.Control.isReplay()) return true; |
| 5139 | // set new target plr |
| 5140 | if (const auto &viewports = Game.GraphicsSystem.GetViewports(); viewports.size() > 0) |
| 5141 | { |
| 5142 | viewports.front()->Init(iPlayer: iToPlr, fSetTempOnly: true); |
| 5143 | } |
| 5144 | // done, always success (sync) |
| 5145 | return true; |
| 5146 | } |
| 5147 | |
| 5148 | static bool (C4AulContext *ctx, C4Object *pObj) |
| 5149 | { |
| 5150 | // local call/safety |
| 5151 | if (!pObj) pObj = ctx->Obj; if (!pObj) return false; |
| 5152 | // check menu |
| 5153 | if (!pObj->Menu) return false; |
| 5154 | // clear the items |
| 5155 | pObj->Menu->ClearItems(fResetSelection: true); |
| 5156 | // success |
| 5157 | return true; |
| 5158 | } |
| 5159 | |
| 5160 | static C4Object *FnGetObjectLayer(C4AulContext *ctx, C4Object *pObj) |
| 5161 | { |
| 5162 | // local call/safety |
| 5163 | if (!pObj) if (!(pObj = ctx->Obj)) return nullptr; |
| 5164 | // get layer object |
| 5165 | return pObj->pLayer; |
| 5166 | } |
| 5167 | |
| 5168 | static bool FnSetObjectLayer(C4AulContext *ctx, C4Object *pNewLayer, C4Object *pObj) |
| 5169 | { |
| 5170 | // local call/safety |
| 5171 | if (!pObj) if (!(pObj = ctx->Obj)) return false; |
| 5172 | // set layer object |
| 5173 | pObj->pLayer = pNewLayer; |
| 5174 | // set for all contents as well |
| 5175 | for (C4ObjectLink *pLnk = pObj->Contents.First; pLnk; pLnk = pLnk->Next) |
| 5176 | if ((pObj = pLnk->Obj) && pObj->Status) |
| 5177 | pObj->pLayer = pNewLayer; |
| 5178 | // success |
| 5179 | return true; |
| 5180 | } |
| 5181 | |
| 5182 | static bool FnSetShape(C4AulContext *ctx, C4ValueInt iX, C4ValueInt iY, C4ValueInt iWdt, C4ValueInt iHgt, C4Object *pObj) |
| 5183 | { |
| 5184 | // local call / safety |
| 5185 | if (!pObj) if (!(pObj = ctx->Obj)) return false; |
| 5186 | // update shape |
| 5187 | pObj->Shape.x = iX; |
| 5188 | pObj->Shape.y = iY; |
| 5189 | pObj->Shape.Wdt = iWdt; |
| 5190 | pObj->Shape.Hgt = iHgt; |
| 5191 | // section list needs refresh |
| 5192 | pObj->UpdatePos(); |
| 5193 | // done, success |
| 5194 | return true; |
| 5195 | } |
| 5196 | |
| 5197 | static bool FnAddMsgBoardCmd(C4AulContext *ctx, C4String *pstrCommand, C4String *pstrScript, C4ValueInt iRestriction) |
| 5198 | { |
| 5199 | // safety |
| 5200 | if (!pstrCommand || !pstrScript) return false; |
| 5201 | // unrestricted commands cannot be set by direct-exec script (like /script). |
| 5202 | if (iRestriction != C4MessageBoardCommand::C4MSGCMDR_Identifier) |
| 5203 | if (!ctx->Caller || !*ctx->Caller->Func->Name) |
| 5204 | return false; |
| 5205 | C4MessageBoardCommand::Restriction eRestriction; |
| 5206 | switch (iRestriction) |
| 5207 | { |
| 5208 | case C4MessageBoardCommand::C4MSGCMDR_Escaped: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Escaped; break; |
| 5209 | case C4MessageBoardCommand::C4MSGCMDR_Plain: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Plain; break; |
| 5210 | case C4MessageBoardCommand::C4MSGCMDR_Identifier: eRestriction = C4MessageBoardCommand::C4MSGCMDR_Identifier; break; |
| 5211 | default: return false; |
| 5212 | } |
| 5213 | // add command |
| 5214 | Game.MessageInput.AddCommand(strCommand: FnStringPar(pString: pstrCommand), strScript: FnStringPar(pString: pstrScript), eRestriction); |
| 5215 | return true; |
| 5216 | } |
| 5217 | |
| 5218 | static bool FnSetGameSpeed(C4AulContext *ctx, C4ValueInt iSpeed) |
| 5219 | { |
| 5220 | // league games: disable direct exec (like /speed) |
| 5221 | if (Game.Parameters.isLeague()) |
| 5222 | if (!ctx->Caller || ctx->Caller->TemporaryScript) |
| 5223 | return false; |
| 5224 | // safety |
| 5225 | if (iSpeed) if (!Inside<C4ValueInt>(ival: iSpeed, lbound: 0, rbound: 1000)) return false; |
| 5226 | if (!iSpeed) iSpeed = 38; |
| 5227 | // set speed, restart timer |
| 5228 | Application.SetGameTickDelay(1000 / iSpeed); |
| 5229 | return true; |
| 5230 | } |
| 5231 | |
| 5232 | static bool FnSetObjDrawTransform(C4AulContext *ctx, C4ValueInt iA, C4ValueInt iB, C4ValueInt iC, C4ValueInt iD, C4ValueInt iE, C4ValueInt iF, C4Object *pObj, C4ValueInt iOverlayID) |
| 5233 | { |
| 5234 | // local call / safety |
| 5235 | if (!pObj) { if (!(pObj = ctx->Obj)) return false; } |
| 5236 | C4DrawTransform *pTransform; |
| 5237 | // overlay? |
| 5238 | if (iOverlayID) |
| 5239 | { |
| 5240 | // set overlay transform |
| 5241 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 5242 | if (!pOverlay) return false; |
| 5243 | pTransform = pOverlay->GetTransform(); |
| 5244 | } |
| 5245 | else |
| 5246 | { |
| 5247 | // set base transform |
| 5248 | pTransform = pObj->pDrawTransform; |
| 5249 | // del transform? |
| 5250 | if (!iB && !iC && !iD && !iF && iA == iE && (!iA || iA == 1000)) |
| 5251 | { |
| 5252 | // identity/0 and no transform defined: nothing to do |
| 5253 | if (!pTransform) return true; |
| 5254 | // transform has no flipdir? |
| 5255 | if (pTransform->FlipDir == 1) |
| 5256 | { |
| 5257 | // kill identity-transform, then |
| 5258 | delete pTransform; |
| 5259 | pObj->pDrawTransform = nullptr; |
| 5260 | return true; |
| 5261 | } |
| 5262 | // flipdir must remain: set identity |
| 5263 | pTransform->Set(fA: 1, fB: 0, fC: 0, fD: 0, fE: 1, fF: 0, fG: 0, fH: 0, fI: 1); |
| 5264 | return true; |
| 5265 | } |
| 5266 | // create draw transform if not already present |
| 5267 | if (!pTransform) pTransform = pObj->pDrawTransform = new C4DrawTransform(); |
| 5268 | } |
| 5269 | // assign values |
| 5270 | pTransform->Set(fA: static_cast<float>(iA) / 1000, fB: static_cast<float>(iB) / 1000, fC: static_cast<float>(iC) / 1000, fD: static_cast<float>(iD) / 1000, fE: static_cast<float>(iE) / 1000, fF: static_cast<float>(iF) / 1000, fG: 0, fH: 0, fI: 1); |
| 5271 | // done, success |
| 5272 | return true; |
| 5273 | } |
| 5274 | |
| 5275 | static bool FnSetObjDrawTransform2(C4AulContext *ctx, C4ValueInt iA, C4ValueInt iB, C4ValueInt iC, C4ValueInt iD, C4ValueInt iE, C4ValueInt iF, C4ValueInt iG, C4ValueInt iH, C4ValueInt iI, C4ValueInt iOverlayID) |
| 5276 | { |
| 5277 | // local call / safety |
| 5278 | C4Object *pObj = ctx->Obj; |
| 5279 | if (!pObj) return false; |
| 5280 | C4DrawTransform *pTransform; |
| 5281 | // overlay? |
| 5282 | if (iOverlayID) |
| 5283 | { |
| 5284 | // set overlay transform |
| 5285 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 5286 | if (!pOverlay) return false; |
| 5287 | pTransform = pOverlay->GetTransform(); |
| 5288 | } |
| 5289 | else |
| 5290 | { |
| 5291 | // set base transform |
| 5292 | pTransform = pObj->pDrawTransform; |
| 5293 | // create draw transform if not already present |
| 5294 | if (!pTransform) pTransform = pObj->pDrawTransform = new C4DrawTransform(1); |
| 5295 | } |
| 5296 | // assign values |
| 5297 | #define L2F(l) (static_cast<float>(l)/1000) |
| 5298 | CBltTransform matrix; |
| 5299 | matrix.Set(L2F(iA), L2F(iB), L2F(iC), L2F(iD), L2F(iE), L2F(iF), L2F(iG), L2F(iH), L2F(iI)); |
| 5300 | *pTransform *= matrix; |
| 5301 | #undef L2F |
| 5302 | // done, success |
| 5303 | return true; |
| 5304 | } |
| 5305 | |
| 5306 | bool SimFlight(C4Fixed &x, C4Fixed &y, C4Fixed &xdir, C4Fixed &ydir, int32_t iDensityMin, int32_t iDensityMax, int32_t iIter); |
| 5307 | |
| 5308 | static std::optional<bool> FnSimFlight(C4AulContext *ctx, C4Value *pvrX, C4Value *pvrY, C4Value *pvrXDir, C4Value *pvrYDir, std::optional<C4ValueInt> oiDensityMin, std::optional<C4ValueInt> oiDensityMax, std::optional<C4ValueInt> oiIter, std::optional<C4ValueInt> oiPrec) |
| 5309 | { |
| 5310 | // check and copy parameters |
| 5311 | if (!pvrX || !pvrY || !pvrXDir || !pvrYDir) return {}; |
| 5312 | |
| 5313 | C4ValueInt iDensityMin = oiDensityMin.value_or(u: C4M_Solid); |
| 5314 | C4ValueInt iDensityMax = oiDensityMax.value_or(u: 100); |
| 5315 | C4ValueInt iIter = oiIter.value_or(u: -1); |
| 5316 | C4ValueInt iPrec = oiPrec.value_or(u: 10); |
| 5317 | |
| 5318 | // convert to C4Fixed |
| 5319 | C4Fixed x = itofix(x: pvrX->getInt()), y = itofix(x: pvrY->getInt()), |
| 5320 | xdir = itofix(x: pvrXDir->getInt(), prec: iPrec), ydir = itofix(x: pvrYDir->getInt(), prec: iPrec); |
| 5321 | |
| 5322 | // simulate |
| 5323 | if (!SimFlight(x, y, xdir, ydir, iDensityMin, iDensityMax, iIter)) |
| 5324 | return {false}; |
| 5325 | |
| 5326 | // write results back |
| 5327 | *pvrX = C4VInt(iVal: fixtoi(x)); *pvrY = C4VInt(iVal: fixtoi(x: y)); |
| 5328 | *pvrXDir = C4VInt(iVal: fixtoi(x: xdir * iPrec)); *pvrYDir = C4VInt(iVal: fixtoi(x: ydir * iPrec)); |
| 5329 | |
| 5330 | return {true}; |
| 5331 | } |
| 5332 | |
| 5333 | static bool FnSetPortrait(C4AulContext *ctx, C4String *pstrPortrait, C4Object *pTarget, C4ID idSourceDef, bool fPermanent, bool fCopyGfx) |
| 5334 | { |
| 5335 | // safety |
| 5336 | const char *szPortrait; |
| 5337 | if (!pstrPortrait || !*(szPortrait = FnStringPar(pString: pstrPortrait))) return false; |
| 5338 | if (!pTarget) if (!(pTarget = ctx->Obj)) return false; |
| 5339 | if (!pTarget->Status || !pTarget->Info) return false; |
| 5340 | // special case: clear portrait |
| 5341 | if (SEqual(szStr1: szPortrait, C4Portrait_None)) return pTarget->Info->ClearPortrait(fPermanently: !!fPermanent); |
| 5342 | // get source def for portrait |
| 5343 | C4Def *pSourceDef; |
| 5344 | if (idSourceDef) pSourceDef = Game.Defs.ID2Def(id: idSourceDef); else pSourceDef = pTarget->Def; |
| 5345 | if (!pSourceDef) return false; |
| 5346 | // special case: random portrait |
| 5347 | if (SEqual(szStr1: szPortrait, C4Portrait_Random)) return pTarget->Info->SetRandomPortrait(idSourceDef: pSourceDef->id, fAssignPermanently: !!fPermanent, fCopyFile: !!fCopyGfx); |
| 5348 | // try to set portrait |
| 5349 | return pTarget->Info->SetPortrait(szPortraitName: szPortrait, pSourceDef, fAssignPermanently: !!fPermanent, fCopyFile: !!fCopyGfx); |
| 5350 | } |
| 5351 | |
| 5352 | static C4Value FnGetPortrait(C4AulContext *ctx, C4Object *pObj, bool fGetID, bool fGetPermanent) |
| 5353 | { |
| 5354 | // check valid object with info section |
| 5355 | if (!pObj) if (!(pObj = ctx->Obj)) return C4VNull; |
| 5356 | if (!pObj->Status || !pObj->Info) return C4VNull; |
| 5357 | // get portrait to examine |
| 5358 | C4Portrait *pPortrait; |
| 5359 | if (fGetPermanent) |
| 5360 | { |
| 5361 | // permanent: new portrait assigned? |
| 5362 | if (!(pPortrait = pObj->Info->pNewPortrait)) |
| 5363 | { |
| 5364 | // custom portrait? |
| 5365 | if (pObj->Info->pCustomPortrait) |
| 5366 | if (fGetID) return C4VNull; |
| 5367 | else |
| 5368 | return C4VString(C4Portrait_Custom); |
| 5369 | // portrait string from info? |
| 5370 | const char *szPortrait = pObj->Info->PortraitFile; |
| 5371 | // no portrait string: portrait undefined ("none" would mean no portrait) |
| 5372 | if (!*szPortrait) return C4VNull; |
| 5373 | // evaluate portrait string |
| 5374 | C4ID idPortraitSource = 0; |
| 5375 | szPortrait = C4Portrait::EvaluatePortraitString(szPortrait, rIDOut&: idPortraitSource, idDefaultID: pObj->Info->id, pdwClrOut: nullptr); |
| 5376 | // return desired value |
| 5377 | if (fGetID) |
| 5378 | return idPortraitSource ? C4VID(idVal: idPortraitSource) : C4VNull; |
| 5379 | else |
| 5380 | return szPortrait ? C4VString(strString: szPortrait) : C4VNull; |
| 5381 | } |
| 5382 | } |
| 5383 | else |
| 5384 | // get current portrait |
| 5385 | pPortrait = &(pObj->Info->Portrait); |
| 5386 | // get portrait graphics |
| 5387 | C4DefGraphics *pPortraitGfx = pPortrait->GetGfx(); |
| 5388 | // no portrait? |
| 5389 | if (!pPortraitGfx) return C4VNull; |
| 5390 | // get def or name |
| 5391 | if (fGetID) |
| 5392 | return (pPortraitGfx->pDef ? C4VID(idVal: pPortraitGfx->pDef->id) : C4VNull); |
| 5393 | else |
| 5394 | { |
| 5395 | const char *szPortraitName = pPortraitGfx->GetName(); |
| 5396 | return C4VString(strString: szPortraitName ? szPortraitName : C4Portrait_Custom); |
| 5397 | } |
| 5398 | } |
| 5399 | |
| 5400 | static C4ValueInt FnLoadScenarioSection(C4AulContext *ctx, C4String *pstrSection, C4ValueInt dwFlags) |
| 5401 | { |
| 5402 | // safety |
| 5403 | const char *szSection; |
| 5404 | if (!pstrSection || !*(szSection = FnStringPar(pString: pstrSection))) return false; |
| 5405 | // try to load it |
| 5406 | return Game.LoadScenarioSection(szSection, dwFlags); |
| 5407 | } |
| 5408 | |
| 5409 | static bool FnSetObjectStatus(C4AulContext *ctx, C4ValueInt iNewStatus, C4Object *pObj, bool fClearPointers) |
| 5410 | { |
| 5411 | // local call / safety |
| 5412 | if (!pObj) { if (!(pObj = ctx->Obj)) return false; } |
| 5413 | if (!pObj->Status) return false; |
| 5414 | // no change |
| 5415 | if (pObj->Status == iNewStatus) return true; |
| 5416 | // set new status |
| 5417 | switch (iNewStatus) |
| 5418 | { |
| 5419 | case C4OS_NORMAL: return pObj->StatusActivate(); break; |
| 5420 | case C4OS_INACTIVE: return pObj->StatusDeactivate(fClearPointers: !!fClearPointers); break; |
| 5421 | default: return false; // status unknown |
| 5422 | } |
| 5423 | } |
| 5424 | |
| 5425 | static std::optional<C4ValueInt> FnGetObjectStatus(C4AulContext *ctx, C4Object *pObj) |
| 5426 | { |
| 5427 | // local call / safety |
| 5428 | if (!pObj) { if (!(pObj = ctx->Obj)) return {}; } |
| 5429 | return {pObj->Status}; |
| 5430 | } |
| 5431 | |
| 5432 | static bool FnAdjustWalkRotation(C4AulContext *ctx, C4ValueInt iRangeX, C4ValueInt iRangeY, C4ValueInt iSpeed, C4Object *pObj) |
| 5433 | { |
| 5434 | // local call / safety |
| 5435 | if (!pObj) { if (!(pObj = ctx->Obj)) return false; } |
| 5436 | // must be rotateable and attached to solid ground |
| 5437 | if (!pObj->Def->Rotateable || ~pObj->Action.t_attach & CNAT_Bottom || pObj->Shape.AttachMat == MNone) |
| 5438 | return false; |
| 5439 | // adjust rotation |
| 5440 | return pObj->AdjustWalkRotation(iRangeX, iRangeY, iSpeed); |
| 5441 | } |
| 5442 | |
| 5443 | static C4ValueInt FnAddEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iPrio, C4ValueInt iTimerIntervall, C4Object *pCmdTarget, C4ID idCmdTarget, C4Value pvVal1, C4Value pvVal2, C4Value pvVal3, C4Value pvVal4) |
| 5444 | { |
| 5445 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5446 | // safety |
| 5447 | if (pTarget && !pTarget->Status) return 0; |
| 5448 | if (!szEffect || !*szEffect || !iPrio) return 0; |
| 5449 | // create effect |
| 5450 | int32_t iEffectNumber; |
| 5451 | new C4Effect(pTarget, szEffect, iPrio, iTimerIntervall, pCmdTarget, idCmdTarget, pvVal1, pvVal2, pvVal3, pvVal4, true, iEffectNumber, true); |
| 5452 | // return assigned effect number - may be 0 if he effect has been denied by another effect |
| 5453 | // may also be the number of another effect |
| 5454 | return iEffectNumber; |
| 5455 | } |
| 5456 | |
| 5457 | static C4Value FnGetEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iIndex, C4ValueInt iQueryValue, C4ValueInt iMaxPriority) |
| 5458 | { |
| 5459 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5460 | // get effects |
| 5461 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5462 | if (!pEffect) return C4VNull; |
| 5463 | // name/wildcard given: find effect by name and index |
| 5464 | if (szEffect && *szEffect) |
| 5465 | pEffect = pEffect->Get(szName: szEffect, iIndex, iMaxPriority); |
| 5466 | else |
| 5467 | // otherwise, get by number |
| 5468 | pEffect = pEffect->Get(iNumber: iIndex, fIncludeDead: true, iMaxPriority); |
| 5469 | // effect found? |
| 5470 | if (!pEffect) return C4VNull; |
| 5471 | // evaluate desired value |
| 5472 | switch (iQueryValue) |
| 5473 | { |
| 5474 | case 0: return C4VInt(iVal: pEffect->iNumber); // 0: number |
| 5475 | case 1: return C4VString(strString: pEffect->Name); // 1: name |
| 5476 | case 2: return C4VInt(iVal: Abs(val: pEffect->iPriority)); // 2: priority (may be negative for deactivated effects) |
| 5477 | case 3: return C4VInt(iVal: pEffect->iIntervall); // 3: timer intervall |
| 5478 | case 4: return C4VObj(pObj: pEffect->pCommandTarget); // 4: command target |
| 5479 | case 5: return C4VID(idVal: pEffect->idCommandTarget); // 5: command target ID |
| 5480 | case 6: return C4VInt(iVal: pEffect->iTime); // 6: effect time |
| 5481 | } |
| 5482 | // invalid data queried |
| 5483 | return C4VNull; |
| 5484 | } |
| 5485 | |
| 5486 | static bool FnRemoveEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iIndex, bool fDoNoCalls) |
| 5487 | { |
| 5488 | // evaluate parameters |
| 5489 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5490 | // get effects |
| 5491 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5492 | if (!pEffect) return false; |
| 5493 | // name/wildcard given: find effect by name and index |
| 5494 | if (szEffect && *szEffect) |
| 5495 | pEffect = pEffect->Get(szName: szEffect, iIndex); |
| 5496 | else |
| 5497 | // otherwise, get by number |
| 5498 | pEffect = pEffect->Get(iNumber: iIndex, fIncludeDead: false); |
| 5499 | // effect found? |
| 5500 | if (!pEffect) return false; |
| 5501 | // kill it |
| 5502 | if (fDoNoCalls) |
| 5503 | pEffect->SetDead(); |
| 5504 | else |
| 5505 | pEffect->Kill(pObj: pTarget); |
| 5506 | // done, success |
| 5507 | return true; |
| 5508 | } |
| 5509 | |
| 5510 | static bool FnChangeEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iIndex, C4String *psNewEffectName, C4ValueInt iNewTimer) |
| 5511 | { |
| 5512 | // evaluate parameters |
| 5513 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5514 | const char *szNewEffect = FnStringPar(pString: psNewEffectName); |
| 5515 | if (!szNewEffect || !*szNewEffect) return false; |
| 5516 | // get effects |
| 5517 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5518 | if (!pEffect) return false; |
| 5519 | // name/wildcard given: find effect by name and index |
| 5520 | if (szEffect && *szEffect) |
| 5521 | pEffect = pEffect->Get(szName: szEffect, iIndex); |
| 5522 | else |
| 5523 | // otherwise, get by number |
| 5524 | pEffect = pEffect->Get(iNumber: iIndex, fIncludeDead: false); |
| 5525 | // effect found? |
| 5526 | if (!pEffect) return false; |
| 5527 | // set new name |
| 5528 | SCopy(szSource: szNewEffect, sTarget: pEffect->Name, iMaxL: C4MaxName); |
| 5529 | pEffect->ReAssignCallbackFunctions(); |
| 5530 | // set new timer |
| 5531 | if (iNewTimer >= 0) |
| 5532 | { |
| 5533 | pEffect->iIntervall = iNewTimer; |
| 5534 | pEffect->iTime = 0; |
| 5535 | } |
| 5536 | // done, success |
| 5537 | return true; |
| 5538 | } |
| 5539 | |
| 5540 | static std::optional<C4ValueInt> FnCheckEffect(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iPrio, C4ValueInt iTimerIntervall, C4Value pvVal1, C4Value pvVal2, C4Value pvVal3, C4Value pvVal4) |
| 5541 | { |
| 5542 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5543 | // safety |
| 5544 | if (pTarget && !pTarget->Status) return {}; |
| 5545 | if (!szEffect || !*szEffect) return {}; |
| 5546 | // get effects |
| 5547 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5548 | if (!pEffect) return {}; |
| 5549 | // let them check |
| 5550 | return {pEffect->Check(pForObj: pTarget, szCheckEffect: szEffect, iPrio, iTimer: iTimerIntervall, rVal1: pvVal1, rVal2: pvVal2, rVal3: pvVal3, rVal4: pvVal4, passErrors: true)}; |
| 5551 | } |
| 5552 | |
| 5553 | static C4ValueInt FnGetEffectCount(C4AulContext *ctx, C4String *psEffectName, C4Object *pTarget, C4ValueInt iMaxPriority) |
| 5554 | { |
| 5555 | // evaluate parameters |
| 5556 | const char *szEffect = FnStringPar(pString: psEffectName); |
| 5557 | // get effects |
| 5558 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5559 | if (!pEffect) return false; |
| 5560 | // count effects |
| 5561 | if (!*szEffect) szEffect = nullptr; |
| 5562 | return pEffect->GetCount(szMask: szEffect, iMaxPriority); |
| 5563 | } |
| 5564 | |
| 5565 | static C4Value FnEffectVar(C4AulContext *cthr, C4ValueInt iVarIndex, C4Object *pObj, C4ValueInt iEffectNumber) |
| 5566 | { |
| 5567 | // safety |
| 5568 | if (iVarIndex < 0) return C4VNull; |
| 5569 | // get effect |
| 5570 | C4Effect *pEffect = pObj ? pObj->pEffects : Game.pGlobalEffects; |
| 5571 | if (!pEffect) return C4VNull; |
| 5572 | if (!(pEffect = pEffect->Get(iNumber: iEffectNumber, fIncludeDead: true))) return C4VNull; |
| 5573 | // return ref to var |
| 5574 | return pEffect->EffectVars[iVarIndex].GetRef(); |
| 5575 | } |
| 5576 | |
| 5577 | static C4Value FnEffectCall(C4AulContext *ctx, C4Object *pTarget, C4ValueInt iNumber, C4String *psCallFn, C4Value vVal1, C4Value vVal2, C4Value vVal3, C4Value vVal4, C4Value vVal5, C4Value vVal6, C4Value vVal7) |
| 5578 | { |
| 5579 | const char *szCallFn = FnStringPar(pString: psCallFn); |
| 5580 | // safety |
| 5581 | if (pTarget && !pTarget->Status) return C4VNull; |
| 5582 | if (!szCallFn || !*szCallFn) return C4VNull; |
| 5583 | // get effect |
| 5584 | C4Effect *pEffect = pTarget ? pTarget->pEffects : Game.pGlobalEffects; |
| 5585 | if (!pEffect) return C4VNull; |
| 5586 | if (!(pEffect = pEffect->Get(iNumber, fIncludeDead: true))) return C4VNull; |
| 5587 | // do call |
| 5588 | return pEffect->DoCall(pObj: pTarget, szFn: szCallFn, rVal1: vVal1, rVal2: vVal2, rVal3: vVal3, rVal4: vVal4, rVal5: vVal5, rVal6: vVal6, rVal7: vVal7, passErrors: true, convertNilToIntBool: !ctx->CalledWithStrictNil()); |
| 5589 | } |
| 5590 | |
| 5591 | static C4ValueInt FnModulateColor(C4AulContext *cthr, std::optional<C4ValueInt> iClr1, C4ValueInt iClr2) |
| 5592 | { |
| 5593 | // default color |
| 5594 | uint32_t dwClr1 = iClr1.value_or(u: 0xffffff); |
| 5595 | uint32_t dwClr2 = iClr2; |
| 5596 | // get alpha |
| 5597 | C4ValueInt iA1 = dwClr1 >> 24, iA2 = dwClr2 >> 24; |
| 5598 | // modulate color values; mod alpha upwards |
| 5599 | uint32_t r = ((dwClr1 & 0xff) * (dwClr2 & 0xff)) >> 8 | // blue |
| 5600 | ((dwClr1 >> 8 & 0xff) * (dwClr2 >> 8 & 0xff)) & 0xff00 | // green |
| 5601 | ((dwClr1 >> 16 & 0xff) * (dwClr2 >> 8 & 0xff00)) & 0xff0000 | // red |
| 5602 | std::min<C4ValueInt>(a: iA1 + iA2 - ((iA1 * iA2) >> 8), b: 255) << 24; // alpha |
| 5603 | return r; |
| 5604 | } |
| 5605 | |
| 5606 | static C4ValueInt FnWildcardMatch(C4AulContext *ctx, C4String *psString, C4String *psWildcard) |
| 5607 | { |
| 5608 | return SWildcardMatchEx(szString: FnStringPar(pString: psString), szWildcard: FnStringPar(pString: psWildcard)); |
| 5609 | } |
| 5610 | |
| 5611 | static std::optional<C4ValueInt> FnGetContact(C4AulContext *ctx, C4Object *pObj, C4ValueInt iVertex, C4ValueInt dwCheck) |
| 5612 | { |
| 5613 | // local call / safety |
| 5614 | if (!pObj) if (!(pObj = ctx->Obj)) return {}; |
| 5615 | // vertex not specified: check all |
| 5616 | if (iVertex == -1) |
| 5617 | { |
| 5618 | C4ValueInt iResult = 0; |
| 5619 | for (std::int32_t i = 0; i < pObj->Shape.VtxNum; ++i) |
| 5620 | iResult |= pObj->Shape.GetVertexContact(iVtx: i, dwCheckMask: dwCheck, tx: pObj->x, ty: pObj->y); |
| 5621 | return iResult; |
| 5622 | } |
| 5623 | // vertex specified: check it |
| 5624 | if (!Inside<C4ValueInt>(ival: iVertex, lbound: 0, rbound: pObj->Shape.VtxNum - 1)) return {}; |
| 5625 | return pObj->Shape.GetVertexContact(iVtx: iVertex, dwCheckMask: dwCheck, tx: pObj->x, ty: pObj->y); |
| 5626 | } |
| 5627 | |
| 5628 | static std::optional<C4ValueInt> FnSetObjectBlitMode(C4AulContext *ctx, C4ValueInt dwNewBlitMode, C4Object *pObj, C4ValueInt iOverlayID) |
| 5629 | { |
| 5630 | // local call / safety |
| 5631 | if (!pObj) if (!(pObj = ctx->Obj)) return {}; |
| 5632 | // overlay? |
| 5633 | if (iOverlayID) |
| 5634 | { |
| 5635 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 5636 | if (!pOverlay) |
| 5637 | { |
| 5638 | DebugLog(level: spdlog::level::err, fmt: "SetObjectBlitMode: Overlay {} not defined for object {} ({})" , args: static_cast<int>(iOverlayID), args: static_cast<int>(pObj->Number), args: pObj->GetName()); |
| 5639 | return {}; |
| 5640 | } |
| 5641 | pOverlay->SetBlitMode(dwNewBlitMode); |
| 5642 | return true; |
| 5643 | } |
| 5644 | // get prev blit mode |
| 5645 | uint32_t dwPrevMode = pObj->BlitMode; |
| 5646 | // iNewBlitMode = 0: reset to definition default |
| 5647 | if (!dwNewBlitMode) |
| 5648 | pObj->BlitMode = pObj->Def->BlitMode; |
| 5649 | else |
| 5650 | // otherwise, set the desired value |
| 5651 | // also ensure that the custom flag is set |
| 5652 | pObj->BlitMode = dwNewBlitMode | C4GFXBLIT_CUSTOM; |
| 5653 | // return previous value |
| 5654 | return dwPrevMode; |
| 5655 | } |
| 5656 | |
| 5657 | static std::optional<C4ValueInt> FnGetObjectBlitMode(C4AulContext *ctx, C4Object *pObj, C4ValueInt iOverlayID) |
| 5658 | { |
| 5659 | // local call / safety |
| 5660 | if (!pObj) if (!(pObj = ctx->Obj)) return {}; |
| 5661 | // overlay? |
| 5662 | if (iOverlayID) |
| 5663 | { |
| 5664 | C4GraphicsOverlay *pOverlay = pObj->GetGraphicsOverlay(iForID: iOverlayID, fCreate: false); |
| 5665 | if (!pOverlay) |
| 5666 | { |
| 5667 | DebugLog(level: spdlog::level::err, fmt: "SetObjectBlitMode: Overlay {} not defined for object {} ({})" , args: static_cast<int>(iOverlayID), args: static_cast<int>(pObj->Number), args: pObj->GetName()); |
| 5668 | return {}; |
| 5669 | } |
| 5670 | return {pOverlay->GetBlitMode()}; |
| 5671 | } |
| 5672 | // get blitting mode |
| 5673 | return {pObj->BlitMode}; |
| 5674 | } |
| 5675 | |
| 5676 | static bool FnSetViewOffset(C4AulContext *ctx, C4ValueInt iPlayer, C4ValueInt iX, C4ValueInt iY) |
| 5677 | { |
| 5678 | if (!ValidPlr(plr: iPlayer)) return false; |
| 5679 | // get player viewport |
| 5680 | C4Viewport *pView = Game.GraphicsSystem.GetViewport(iPlayer); |
| 5681 | if (!pView) return true; // sync safety |
| 5682 | // set |
| 5683 | pView->ViewOffsX = iX; |
| 5684 | pView->ViewOffsY = iY; |
| 5685 | // ok |
| 5686 | return true; |
| 5687 | } |
| 5688 | |
| 5689 | static bool FnSetPreSend(C4AulContext *cthr, C4ValueInt iToVal, C4String *pNewName) |
| 5690 | { |
| 5691 | if (iToVal < 0) return false; |
| 5692 | if (!Game.Control.isNetwork()) return true; |
| 5693 | if (iToVal == 0) iToVal = C4GameControlNetwork::DefaultTargetFPS; |
| 5694 | // dbg: manual presend |
| 5695 | const char *szClient = FnStringPar(pString: pNewName); |
| 5696 | if (!szClient || !*szClient || WildcardMatch(szFName1: szClient, szFName2: Game.Clients.getLocalName())) |
| 5697 | { |
| 5698 | Game.Control.Network.setTargetFPS(iToVal); |
| 5699 | Game.GraphicsSystem.FlashMessage(szMessage: ("TargetFPS: " + std::to_string(val: iToVal)).c_str()); |
| 5700 | } |
| 5701 | return true; |
| 5702 | } |
| 5703 | |
| 5704 | static std::optional<C4ValueInt> FnGetPlayerID(C4AulContext *cthr, C4ValueInt iPlayer) |
| 5705 | { |
| 5706 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 5707 | return pPlr ? std::make_optional(t&: pPlr->ID) : std::nullopt; |
| 5708 | } |
| 5709 | |
| 5710 | static std::optional<C4ValueInt> FnGetPlayerTeam(C4AulContext *cthr, C4ValueInt iPlayer) |
| 5711 | { |
| 5712 | // get player |
| 5713 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 5714 | if (!pPlr) return {}; |
| 5715 | // search team containing this player |
| 5716 | C4Team *pTeam = Game.Teams.GetTeamByPlayerID(iID: pPlr->ID); |
| 5717 | if (pTeam) return {pTeam->GetID()}; |
| 5718 | // special value of -1 indicating that the team is still to be chosen |
| 5719 | if (pPlr->IsChosingTeam()) return {-1}; |
| 5720 | // No team. |
| 5721 | return {0}; |
| 5722 | } |
| 5723 | |
| 5724 | static bool FnSetPlayerTeam(C4AulContext *cthr, C4ValueInt iPlayer, C4ValueInt idNewTeam, bool fNoCalls) |
| 5725 | { |
| 5726 | // no team changing in league games |
| 5727 | if (Game.Parameters.isLeague()) return false; |
| 5728 | // get player |
| 5729 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 5730 | if (!pPlr) return false; |
| 5731 | C4PlayerInfo *pPlrInfo = pPlr->GetInfo(); |
| 5732 | if (!pPlrInfo) return false; |
| 5733 | // already in that team? |
| 5734 | if (pPlr->Team == idNewTeam) return true; |
| 5735 | // ask team setting if it's allowed (also checks for valid team) |
| 5736 | if (!Game.Teams.IsJoin2TeamAllowed(idTeam: idNewTeam)) return false; |
| 5737 | // ask script if it's allowed |
| 5738 | if (!fNoCalls) |
| 5739 | { |
| 5740 | if (Game.Script.GRBroadcast(PSF_RejectTeamSwitch, pPars: {C4VInt(iVal: iPlayer), C4VInt(iVal: idNewTeam)}, fPassError: true, fRejectTest: true)) |
| 5741 | return false; |
| 5742 | } |
| 5743 | // exit previous team |
| 5744 | C4Team *pOldTeam = Game.Teams.GetTeamByPlayerID(iID: pPlr->ID); |
| 5745 | int32_t idOldTeam = 0; |
| 5746 | if (pOldTeam) |
| 5747 | { |
| 5748 | idOldTeam = pOldTeam->GetID(); |
| 5749 | pOldTeam->RemovePlayerByID(iID: pPlr->ID); |
| 5750 | } |
| 5751 | // enter new team |
| 5752 | if (idNewTeam) |
| 5753 | { |
| 5754 | C4Team *pNewTeam = Game.Teams.GetGenerateTeamByID(iID: idNewTeam); |
| 5755 | if (pNewTeam) |
| 5756 | { |
| 5757 | pNewTeam->AddPlayer(rInfo&: *pPlrInfo, fAdjustPlayer: true); |
| 5758 | idNewTeam = pNewTeam->GetID(); |
| 5759 | // Update common home base material |
| 5760 | if (Game.Rules & C4RULE_TeamHombase && !fNoCalls) pPlr->SyncHomebaseMaterialFromTeam(); |
| 5761 | } |
| 5762 | else |
| 5763 | { |
| 5764 | // unknown error |
| 5765 | pPlr->Team = idNewTeam = 0; |
| 5766 | } |
| 5767 | } |
| 5768 | // update hositlities if this is not a "silent" change |
| 5769 | if (!fNoCalls) |
| 5770 | { |
| 5771 | pPlr->SetTeamHostility(); |
| 5772 | } |
| 5773 | // do callback to reflect change in scenario |
| 5774 | if (!fNoCalls) |
| 5775 | Game.Script.GRBroadcast(PSF_OnTeamSwitch, pPars: {C4VInt(iVal: iPlayer), C4VInt(iVal: idNewTeam), C4VInt(iVal: idOldTeam)}, fPassError: true); |
| 5776 | return true; |
| 5777 | } |
| 5778 | |
| 5779 | static std::optional<C4ValueInt> FnGetTeamConfig(C4AulContext *cthr, C4ValueInt iConfigValue) |
| 5780 | { |
| 5781 | // query value |
| 5782 | switch (iConfigValue) |
| 5783 | { |
| 5784 | case C4TeamList::TEAM_Custom: return {Game.Teams.IsCustom()}; |
| 5785 | case C4TeamList::TEAM_Active: return {Game.Teams.IsMultiTeams()}; |
| 5786 | case C4TeamList::TEAM_AllowHostilityChange: return {Game.Teams.IsHostilityChangeAllowed()}; |
| 5787 | case C4TeamList::TEAM_Dist: return {Game.Teams.GetTeamDist()}; |
| 5788 | case C4TeamList::TEAM_AllowTeamSwitch: return {Game.Teams.IsTeamSwitchAllowed()}; |
| 5789 | case C4TeamList::TEAM_AutoGenerateTeams: return {Game.Teams.IsAutoGenerateTeams()}; |
| 5790 | case C4TeamList::TEAM_TeamColors: return {Game.Teams.IsTeamColors()}; |
| 5791 | } |
| 5792 | // undefined value |
| 5793 | DebugLog(level: spdlog::level::err, fmt: "GetTeamConfig: Unknown config value: {}" , args&: iConfigValue); |
| 5794 | return {}; |
| 5795 | } |
| 5796 | |
| 5797 | static C4String *FnGetTeamName(C4AulContext *cthr, C4ValueInt iTeam) |
| 5798 | { |
| 5799 | C4Team *pTeam = Game.Teams.GetTeamByID(iID: iTeam); |
| 5800 | if (!pTeam) return nullptr; |
| 5801 | return String(str: pTeam->GetName()); |
| 5802 | } |
| 5803 | |
| 5804 | static std::optional<C4ValueInt> FnGetTeamColor(C4AulContext *cthr, C4ValueInt iTeam) |
| 5805 | { |
| 5806 | C4Team *pTeam = Game.Teams.GetTeamByID(iID: iTeam); |
| 5807 | return pTeam ? std::make_optional(t: pTeam->GetColor()) : std::nullopt; |
| 5808 | } |
| 5809 | |
| 5810 | static std::optional<C4ValueInt> FnGetTeamByIndex(C4AulContext *cthr, C4ValueInt iIndex) |
| 5811 | { |
| 5812 | C4Team *pTeam = Game.Teams.GetTeamByIndex(iIndex); |
| 5813 | return pTeam ? std::make_optional(t: pTeam->GetID()) : std::nullopt; |
| 5814 | } |
| 5815 | |
| 5816 | static C4ValueInt FnGetTeamCount(C4AulContext *cthr) |
| 5817 | { |
| 5818 | return Game.Teams.GetTeamCount(); |
| 5819 | } |
| 5820 | |
| 5821 | static bool FnInitScenarioPlayer(C4AulContext *cthr, C4ValueInt iPlayer, C4ValueInt idTeam) |
| 5822 | { |
| 5823 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 5824 | if (!pPlr) return false; |
| 5825 | return pPlr->ScenarioAndTeamInit(idTeam); |
| 5826 | } |
| 5827 | |
| 5828 | static bool FnOnOwnerRemoved(C4AulContext *cthr) |
| 5829 | { |
| 5830 | // safety |
| 5831 | C4Object *pObj = cthr->Obj; if (!pObj) return false; |
| 5832 | C4Player *pPlr = Game.Players.Get(iPlayer: pObj->Owner); if (!pPlr) return false; |
| 5833 | if (pPlr->Crew.IsContained(pObj)) |
| 5834 | { |
| 5835 | // crew members: Those are removed later (AFTER the player has been removed, for backwards compatiblity with relaunch scripting) |
| 5836 | } |
| 5837 | else if ((~pObj->Category & C4D_StaticBack) || (pObj->id == C4ID_Flag)) |
| 5838 | { |
| 5839 | // Regular objects: Try to find a new, suitable owner from the same team |
| 5840 | // Ignore StaticBack, because this would not be backwards compatible with many internal objects such as team account |
| 5841 | // Do not ignore flags which might be StaticBack if being attached to castle parts |
| 5842 | int32_t iNewOwner = NO_OWNER; |
| 5843 | C4Team *pTeam; |
| 5844 | if (pPlr->Team) if (pTeam = Game.Teams.GetTeamByID(iID: pPlr->Team)) |
| 5845 | { |
| 5846 | for (int32_t i = 0; i < pTeam->GetPlayerCount(); ++i) |
| 5847 | { |
| 5848 | int32_t iPlrID = pTeam->GetIndexedPlayer(iIndex: i); |
| 5849 | if (iPlrID && iPlrID != pPlr->ID) |
| 5850 | { |
| 5851 | C4PlayerInfo *pPlrInfo = Game.PlayerInfos.GetPlayerInfoByID(id: iPlrID); |
| 5852 | if (pPlrInfo) if (pPlrInfo->IsJoined()) |
| 5853 | { |
| 5854 | // this looks like a good new owner |
| 5855 | iNewOwner = pPlrInfo->GetInGameNumber(); |
| 5856 | break; |
| 5857 | } |
| 5858 | } |
| 5859 | } |
| 5860 | } |
| 5861 | // if noone from the same team was found, try to find another non-hostile player |
| 5862 | // (necessary for cooperative rounds without teams) |
| 5863 | if (iNewOwner == NO_OWNER) |
| 5864 | for (C4Player *pOtherPlr = Game.Players.First; pOtherPlr; pOtherPlr = pOtherPlr->Next) |
| 5865 | if (pOtherPlr != pPlr) if (!pOtherPlr->Eliminated) |
| 5866 | if (!Game.Players.Hostile(iPlayer1: pOtherPlr->Number, iPlayer2: pPlr->Number)) |
| 5867 | iNewOwner = pOtherPlr->Number; |
| 5868 | |
| 5869 | // set this owner |
| 5870 | pObj->SetOwner(iNewOwner); |
| 5871 | } |
| 5872 | return true; |
| 5873 | } |
| 5874 | |
| 5875 | static void FnSetScoreboardData(C4AulContext *cthr, C4ValueInt iRowID, C4ValueInt iColID, C4String *pText, C4ValueInt iData) |
| 5876 | { |
| 5877 | Game.Scoreboard.SetCell(iColKey: iColID, iRowKey: iRowID, szValue: pText ? pText->Data.getData() : nullptr, iValue: iData); |
| 5878 | } |
| 5879 | |
| 5880 | static C4String *FnGetScoreboardString(C4AulContext *cthr, C4ValueInt iRowID, C4ValueInt iColID) |
| 5881 | { |
| 5882 | return String(str: Game.Scoreboard.GetCellString(iColKey: iColID, iRowKey: iRowID)); |
| 5883 | } |
| 5884 | |
| 5885 | static int32_t FnGetScoreboardData(C4AulContext *cthr, C4ValueInt iRowID, C4ValueInt iColID) |
| 5886 | { |
| 5887 | return Game.Scoreboard.GetCellData(iColKey: iColID, iRowKey: iRowID); |
| 5888 | } |
| 5889 | |
| 5890 | static bool FnDoScoreboardShow(C4AulContext *cthr, C4ValueInt iChange, C4ValueInt iForPlr) |
| 5891 | { |
| 5892 | C4Player *pPlr; |
| 5893 | if (iForPlr) |
| 5894 | { |
| 5895 | // abort if the specified player is not local - but always return if the player exists, |
| 5896 | // to ensure sync safety |
| 5897 | if (!(pPlr = Game.Players.Get(iPlayer: iForPlr - 1))) return false; |
| 5898 | if (!pPlr->LocalControl) return true; |
| 5899 | } |
| 5900 | Game.Scoreboard.DoDlgShow(iChange, fUserToggle: false); |
| 5901 | return true; |
| 5902 | } |
| 5903 | |
| 5904 | static bool FnSortScoreboard(C4AulContext *cthr, C4ValueInt iByColID, bool fReverse) |
| 5905 | { |
| 5906 | return Game.Scoreboard.SortBy(iColKey: iByColID, fReverse: !!fReverse); |
| 5907 | } |
| 5908 | |
| 5909 | static bool FnAddEvaluationData(C4AulContext *cthr, C4String *pText, C4ValueInt idPlayer) |
| 5910 | { |
| 5911 | // safety |
| 5912 | if (!pText) return false; |
| 5913 | if (!pText->Data.getLength()) return false; |
| 5914 | if (idPlayer && !Game.PlayerInfos.GetPlayerInfoByID(id: idPlayer)) return false; |
| 5915 | // add data |
| 5916 | Game.RoundResults.AddCustomEvaluationString(szCustomString: pText->Data.getData(), idPlayer); |
| 5917 | return true; |
| 5918 | } |
| 5919 | |
| 5920 | static std::optional<int32_t> FnGetLeagueScore(C4AulContext *cthr, C4ValueInt idPlayer) |
| 5921 | { |
| 5922 | // security |
| 5923 | if (idPlayer < 1) return {}; |
| 5924 | // get info |
| 5925 | C4PlayerInfo *pInfo = Game.PlayerInfos.GetPlayerInfoByID(id: idPlayer); |
| 5926 | if (!pInfo) return {}; |
| 5927 | // get league score |
| 5928 | return {pInfo->getLeagueScore()}; |
| 5929 | } |
| 5930 | |
| 5931 | static void FnHideSettlementScoreInEvaluation(C4AulContext *cthr, bool fHide) |
| 5932 | { |
| 5933 | Game.RoundResults.HideSettlementScore(fHide); |
| 5934 | } |
| 5935 | |
| 5936 | static std::optional<C4ValueInt> FnGetUnusedOverlayID(C4AulContext *ctx, C4ValueInt iBaseIndex, C4Object *pObj) |
| 5937 | { |
| 5938 | // local call / safety |
| 5939 | if (!iBaseIndex) return {}; |
| 5940 | if (!pObj) if (!(pObj = ctx->Obj)) return {}; |
| 5941 | // find search first unused index from there on |
| 5942 | int iSearchDir = (iBaseIndex < 0) ? -1 : 1; |
| 5943 | while (pObj->GetGraphicsOverlay(iForID: iBaseIndex, fCreate: false)) iBaseIndex += iSearchDir; |
| 5944 | return iBaseIndex; |
| 5945 | } |
| 5946 | |
| 5947 | static C4ValueInt (C4AulContext *ctx, C4ValueInt iPlayer) |
| 5948 | { |
| 5949 | // get target player |
| 5950 | C4Player *pPlr = Game.Players.Get(iPlayer); |
| 5951 | if (!pPlr) return false; |
| 5952 | // open menu |
| 5953 | return pPlr->Menu.ActivateGoals(iPlayer: pPlr->Number, fDoActivate: pPlr->LocalControl && !Game.Control.isReplay()); |
| 5954 | } |
| 5955 | |
| 5956 | static void FnFatalError(C4AulContext *ctx, C4String *pErrorMsg) |
| 5957 | { |
| 5958 | throw C4AulExecError(ctx->Obj, std::format(fmt: "User error: {}" , args: pErrorMsg ? pErrorMsg->Data.getData() : "(no error)" )); |
| 5959 | } |
| 5960 | |
| 5961 | static void FnStartCallTrace(C4AulContext *ctx) |
| 5962 | { |
| 5963 | extern void C4AulStartTrace(); |
| 5964 | C4AulStartTrace(); |
| 5965 | } |
| 5966 | |
| 5967 | static bool FnStartScriptProfiler(C4AulContext *ctx, C4ID idScript) |
| 5968 | { |
| 5969 | // get script to profile |
| 5970 | C4AulScript *pScript; |
| 5971 | if (idScript) |
| 5972 | { |
| 5973 | C4Def *pDef = C4Id2Def(id: idScript); |
| 5974 | if (!pDef) return false; |
| 5975 | pScript = &pDef->Script; |
| 5976 | } |
| 5977 | else |
| 5978 | pScript = &Game.ScriptEngine; |
| 5979 | // profile it |
| 5980 | C4AulProfiler::StartProfiling(pScript); |
| 5981 | return true; |
| 5982 | } |
| 5983 | |
| 5984 | static void FnStopScriptProfiler(C4AulContext *ctx) |
| 5985 | { |
| 5986 | C4AulProfiler::StopProfiling(); |
| 5987 | } |
| 5988 | |
| 5989 | static bool FnCustomMessage(C4AulContext *ctx, C4String *pMsg, C4Object *pObj, C4ValueInt iOwner, C4ValueInt iOffX, C4ValueInt iOffY, std::optional<C4ValueInt> clr, C4ID idDeco, C4String *sPortrait, C4ValueInt dwFlags, C4ValueInt iHSize) |
| 5990 | { |
| 5991 | // safeties |
| 5992 | if (!pMsg) return false; |
| 5993 | if (pObj && !pObj->Status) return false; |
| 5994 | const char *szMsg = pMsg->Data.getData(); |
| 5995 | if (!szMsg) return false; |
| 5996 | if (idDeco && !C4Id2Def(id: idDeco)) return false; |
| 5997 | // only one positioning flag per direction allowed |
| 5998 | uint32_t hpos = dwFlags & (C4GM_Left | C4GM_HCenter | C4GM_Right); |
| 5999 | uint32_t vpos = dwFlags & (C4GM_Top | C4GM_VCenter | C4GM_Bottom); |
| 6000 | if (((hpos | hpos - 1) + 1) >> 1 != hpos) |
| 6001 | { |
| 6002 | throw C4AulExecError(ctx->Obj, "CustomMessage: Only one horizontal positioning flag allowed!" ); |
| 6003 | } |
| 6004 | if (((vpos | vpos - 1) + 1) >> 1 != vpos) |
| 6005 | { |
| 6006 | throw C4AulExecError(ctx->Obj, "CustomMessage: Only one vertical positioning flag allowed!" ); |
| 6007 | } |
| 6008 | |
| 6009 | uint32_t alignment = dwFlags & (C4GM_ALeft | C4GM_ACenter | C4GM_ARight); |
| 6010 | if (((alignment | alignment - 1) + 1) >> 1 != alignment) |
| 6011 | { |
| 6012 | throw C4AulExecError(ctx->Obj, "CustomMessage: Only one text alignment flag allowed!" ); |
| 6013 | } |
| 6014 | |
| 6015 | // message color |
| 6016 | const auto dwClr = InvertRGBAAlpha(dwFromClr: clr.value_or(u: 0xffffff)); |
| 6017 | // message type |
| 6018 | int32_t iType; |
| 6019 | if (pObj) |
| 6020 | if (iOwner != NO_OWNER) |
| 6021 | iType = C4GM_TargetPlayer; |
| 6022 | else |
| 6023 | iType = C4GM_Target; |
| 6024 | else if (iOwner != NO_OWNER) |
| 6025 | iType = C4GM_GlobalPlayer; |
| 6026 | else |
| 6027 | iType = C4GM_Global; |
| 6028 | // remove speech? |
| 6029 | StdStrBuf sMsg; |
| 6030 | sMsg.Ref(pnData: szMsg); |
| 6031 | if (dwFlags & C4GM_DropSpeech) sMsg.SplitAtChar(cSplit: '$', psSplit: nullptr); |
| 6032 | // create it! |
| 6033 | return Game.Messages.New(iType, Text: sMsg, pTarget: pObj, iPlayer: iOwner, iX: iOffX, iY: iOffY, dwClr: static_cast<uint32_t>(dwClr), idDecoID: idDeco, szPortraitDef: sPortrait ? sPortrait->Data.getData() : nullptr, dwFlags, width: iHSize); |
| 6034 | } |
| 6035 | |
| 6036 | static void FnPauseGame(C4AulContext *ctx, bool fToggle) |
| 6037 | { |
| 6038 | // not in replay (film) |
| 6039 | if (Game.Control.isReplay()) return; |
| 6040 | // script method for halting game (for films) |
| 6041 | if (fToggle) |
| 6042 | Console.TogglePause(); |
| 6043 | else |
| 6044 | Console.DoHalt(); |
| 6045 | } |
| 6046 | |
| 6047 | static void FnSetNextMission(C4AulContext *ctx, C4String *szNextMission, C4String *szNextMissionText, C4String *szNextMissionDesc) |
| 6048 | { |
| 6049 | if (!szNextMission || !szNextMission->Data.getLength()) |
| 6050 | { |
| 6051 | // param empty: clear next mission |
| 6052 | Game.NextMission.Clear(); |
| 6053 | Game.NextMissionText.Clear(); |
| 6054 | } |
| 6055 | else |
| 6056 | { |
| 6057 | // set next mission, button and button desc if given |
| 6058 | Game.NextMission.Copy(Buf2: szNextMission->Data); |
| 6059 | if (szNextMissionText && szNextMissionText->Data.getData()) |
| 6060 | { |
| 6061 | Game.NextMissionText.Copy(Buf2: szNextMissionText->Data); |
| 6062 | } |
| 6063 | else |
| 6064 | { |
| 6065 | Game.NextMissionText.Copy(pnData: LoadResStr(id: C4ResStrTableKey::IDS_BTN_NEXTSCENARIO)); |
| 6066 | } |
| 6067 | if (szNextMissionDesc && szNextMissionDesc->Data.getData()) |
| 6068 | { |
| 6069 | Game.NextMissionDesc.Copy(Buf2: szNextMissionDesc->Data); |
| 6070 | } |
| 6071 | else |
| 6072 | { |
| 6073 | Game.NextMissionDesc.Copy(pnData: LoadResStr(id: C4ResStrTableKey::IDS_DESC_NEXTSCENARIO)); |
| 6074 | } |
| 6075 | } |
| 6076 | } |
| 6077 | |
| 6078 | static C4ValueArray *FnGetKeys(C4AulContext *ctx, C4ValueHash *map) |
| 6079 | { |
| 6080 | if (!map) throw C4AulExecError(ctx->Obj, "GetKeys(): map expected, got 0" ); |
| 6081 | |
| 6082 | C4ValueArray *keys = new C4ValueArray(map->size()); |
| 6083 | |
| 6084 | size_t i = 0; |
| 6085 | for (const auto &[key, value] : *map) |
| 6086 | { |
| 6087 | (*keys)[i] = key; |
| 6088 | ++i; |
| 6089 | } |
| 6090 | |
| 6091 | return keys; |
| 6092 | } |
| 6093 | |
| 6094 | static C4ValueArray *FnGetValues(C4AulContext *ctx, C4ValueHash *map) |
| 6095 | { |
| 6096 | if (!map) throw C4AulExecError(ctx->Obj, "GetValues(): map expected, got 0" ); |
| 6097 | |
| 6098 | C4ValueArray *keys = new C4ValueArray(map->size()); |
| 6099 | |
| 6100 | size_t i = 0; |
| 6101 | for (const auto &[key, value] : *map) |
| 6102 | { |
| 6103 | (*keys)[i] = value; |
| 6104 | ++i; |
| 6105 | } |
| 6106 | |
| 6107 | return keys; |
| 6108 | } |
| 6109 | |
| 6110 | static void FnSetRestoreInfos(C4AulContext *ctx, C4ValueInt what) |
| 6111 | { |
| 6112 | Game.RestartRestoreInfos.What = static_cast<std::underlying_type_t<C4NetworkRestartInfos::RestoreInfo>>(what); |
| 6113 | } |
| 6114 | |
| 6115 | template<std::size_t ParCount> |
| 6116 | class C4AulEngineFuncHelper : public C4AulFunc |
| 6117 | { |
| 6118 | const std::array<C4V_Type, ParCount> parTypes; |
| 6119 | const bool pub; |
| 6120 | |
| 6121 | public: |
| 6122 | template<typename... ParTypes> |
| 6123 | C4AulEngineFuncHelper(C4AulScript *owner, const char *name, bool pub, ParTypes... parTypes) : C4AulFunc{owner, name}, parTypes{parTypes...}, pub{pub} {} |
| 6124 | virtual const C4V_Type *GetParType() noexcept override { return parTypes.data(); } |
| 6125 | virtual int GetParCount() noexcept override { return ParCount; } |
| 6126 | virtual bool GetPublic() noexcept override { return pub; } |
| 6127 | }; |
| 6128 | |
| 6129 | template<typename Ret, typename... Pars> |
| 6130 | class C4AulEngineFunc : public C4AulEngineFuncHelper<sizeof...(Pars)> |
| 6131 | { |
| 6132 | constexpr static auto ParCount = sizeof...(Pars); |
| 6133 | using Func = Ret(&)(C4AulContext *context, Pars...); |
| 6134 | constexpr auto static isVoid = std::is_same_v<Ret, void>; |
| 6135 | Func func; |
| 6136 | |
| 6137 | public: |
| 6138 | C4AulEngineFunc(C4AulScript *owner, const char *name, Func func, bool pub) : C4AulEngineFuncHelper<ParCount>{owner, name, pub, C4ValueConv<Pars>::Type()...}, func{func} {} |
| 6139 | |
| 6140 | virtual C4V_Type GetRetType() noexcept override |
| 6141 | { |
| 6142 | if constexpr (isVoid) { return C4V_Any; } |
| 6143 | else return C4ValueConv<Ret>::Type(); |
| 6144 | } |
| 6145 | |
| 6146 | C4Value Exec(C4AulContext *context, const C4Value pars[], bool = false) override |
| 6147 | { |
| 6148 | constexpr auto callHelper = [](C4AulEngineFunc *that, C4AulContext *context, const C4Value pars[]) |
| 6149 | { |
| 6150 | return that->ExecHelper(context, pars, std::make_index_sequence<ParCount>()); |
| 6151 | }; |
| 6152 | if constexpr (isVoid) |
| 6153 | { |
| 6154 | callHelper(this, context, pars); |
| 6155 | return C4VNull; |
| 6156 | } |
| 6157 | else |
| 6158 | { |
| 6159 | return C4ValueConv<Ret>::ToC4V(callHelper(this, context, pars)); |
| 6160 | } |
| 6161 | } |
| 6162 | |
| 6163 | private: |
| 6164 | template<std::size_t... indices> |
| 6165 | auto ExecHelper(C4AulContext *context, const C4Value pars[], std::index_sequence<indices...>) const |
| 6166 | { |
| 6167 | return func(context, C4ValueConv<Pars>::_FromC4V(pars[indices])...); |
| 6168 | } |
| 6169 | }; |
| 6170 | |
| 6171 | template <typename Ret, typename... Pars> |
| 6172 | static void AddFunc(C4AulScript *owner, const char *name, Ret (&func)(C4AulContext *context, Pars...), bool pub = true) |
| 6173 | { |
| 6174 | new C4AulEngineFunc<Ret, Pars...>{owner, name, func, pub}; |
| 6175 | } |
| 6176 | |
| 6177 | template<C4V_Type fromType, C4V_Type toType> |
| 6178 | class C4AulDefCastFunc : public C4AulEngineFuncHelper<1> |
| 6179 | { |
| 6180 | public: |
| 6181 | C4AulDefCastFunc(C4AulScript *owner, const char *name) : |
| 6182 | C4AulEngineFuncHelper<1>(owner, name, false, fromType) {} |
| 6183 | |
| 6184 | C4Value Exec(C4AulContext *, const C4Value pars[], bool = false) override |
| 6185 | { |
| 6186 | return C4Value{pars->GetData(), toType}; |
| 6187 | } |
| 6188 | |
| 6189 | C4V_Type GetRetType() noexcept override { return toType; } |
| 6190 | }; |
| 6191 | |
| 6192 | template<std::size_t ParCount, C4V_Type RetType> |
| 6193 | class C4AulEngineFuncParArray : public C4AulEngineFuncHelper<ParCount> |
| 6194 | { |
| 6195 | using Func = C4Value(&)(C4AulContext *context, const C4Value *pars); |
| 6196 | Func func; |
| 6197 | |
| 6198 | public: |
| 6199 | template<typename... ParTypes> |
| 6200 | C4AulEngineFuncParArray(C4AulScript *owner, const char *name, Func func, ParTypes... parTypes) : C4AulEngineFuncHelper<ParCount>{owner, name, true, parTypes...}, func{func} {} |
| 6201 | C4V_Type GetRetType() noexcept override { return RetType; } |
| 6202 | C4Value Exec(C4AulContext *context, const C4Value pars[], bool = false) override |
| 6203 | { |
| 6204 | return func(context, pars); |
| 6205 | } |
| 6206 | }; |
| 6207 | |
| 6208 | static constexpr C4ScriptConstDef C4ScriptConstMap[] = |
| 6209 | { |
| 6210 | { .Identifier: "C4D_All" , .ValType: C4V_Int, .Data: C4D_All }, |
| 6211 | { .Identifier: "C4D_StaticBack" , .ValType: C4V_Int, .Data: C4D_StaticBack }, |
| 6212 | { .Identifier: "C4D_Structure" , .ValType: C4V_Int, .Data: C4D_Structure }, |
| 6213 | { .Identifier: "C4D_Vehicle" , .ValType: C4V_Int, .Data: C4D_Vehicle }, |
| 6214 | { .Identifier: "C4D_Living" , .ValType: C4V_Int, .Data: C4D_Living }, |
| 6215 | { .Identifier: "C4D_Object" , .ValType: C4V_Int, .Data: C4D_Object }, |
| 6216 | { .Identifier: "C4D_Goal" , .ValType: C4V_Int, .Data: C4D_Goal }, |
| 6217 | { .Identifier: "C4D_Environment" , .ValType: C4V_Int, .Data: C4D_Environment }, |
| 6218 | { .Identifier: "C4D_Knowledge" , .ValType: C4V_Int, .Data: C4D_SelectKnowledge }, |
| 6219 | { .Identifier: "C4D_Magic" , .ValType: C4V_Int, .Data: C4D_Magic }, |
| 6220 | { .Identifier: "C4D_Rule" , .ValType: C4V_Int, .Data: C4D_Rule }, |
| 6221 | { .Identifier: "C4D_Background" , .ValType: C4V_Int, .Data: C4D_Background }, |
| 6222 | { .Identifier: "C4D_Parallax" , .ValType: C4V_Int, .Data: C4D_Parallax }, |
| 6223 | { .Identifier: "C4D_MouseSelect" , .ValType: C4V_Int, .Data: C4D_MouseSelect }, |
| 6224 | { .Identifier: "C4D_Foreground" , .ValType: C4V_Int, .Data: C4D_Foreground }, |
| 6225 | { .Identifier: "C4D_MouseIgnore" , .ValType: C4V_Int, .Data: C4D_MouseIgnore }, |
| 6226 | { .Identifier: "C4D_IgnoreFoW" , .ValType: C4V_Int, .Data: C4D_IgnoreFoW }, |
| 6227 | |
| 6228 | { .Identifier: "C4D_GrabGet" , .ValType: C4V_Int, .Data: C4D_Grab_Get }, |
| 6229 | { .Identifier: "C4D_GrabPut" , .ValType: C4V_Int, .Data: C4D_Grab_Put }, |
| 6230 | |
| 6231 | { .Identifier: "C4D_LinePower" , .ValType: C4V_Int, .Data: C4D_Line_Power }, |
| 6232 | { .Identifier: "C4D_LineSource" , .ValType: C4V_Int, .Data: C4D_Line_Source }, |
| 6233 | { .Identifier: "C4D_LineDrain" , .ValType: C4V_Int, .Data: C4D_Line_Drain }, |
| 6234 | { .Identifier: "C4D_LineLightning" , .ValType: C4V_Int, .Data: C4D_Line_Lightning }, |
| 6235 | { .Identifier: "C4D_LineVolcano" , .ValType: C4V_Int, .Data: C4D_Line_Volcano }, |
| 6236 | { .Identifier: "C4D_LineRope" , .ValType: C4V_Int, .Data: C4D_Line_Rope }, |
| 6237 | { .Identifier: "C4D_LineColored" , .ValType: C4V_Int, .Data: C4D_Line_Colored }, |
| 6238 | { .Identifier: "C4D_LineVertex" , .ValType: C4V_Int, .Data: C4D_Line_Vertex }, |
| 6239 | |
| 6240 | { .Identifier: "C4D_PowerInput" , .ValType: C4V_Int, .Data: C4D_Power_Input }, |
| 6241 | { .Identifier: "C4D_PowerOutput" , .ValType: C4V_Int, .Data: C4D_Power_Output }, |
| 6242 | { .Identifier: "C4D_LiquidInput" , .ValType: C4V_Int, .Data: C4D_Liquid_Input }, |
| 6243 | { .Identifier: "C4D_LiquidOutput" , .ValType: C4V_Int, .Data: C4D_Liquid_Output }, |
| 6244 | { .Identifier: "C4D_PowerGenerator" , .ValType: C4V_Int, .Data: C4D_Power_Generator }, |
| 6245 | { .Identifier: "C4D_PowerConsumer" , .ValType: C4V_Int, .Data: C4D_Power_Consumer }, |
| 6246 | { .Identifier: "C4D_LiquidPump" , .ValType: C4V_Int, .Data: C4D_Liquid_Pump }, |
| 6247 | { .Identifier: "C4D_EnergyHolder" , .ValType: C4V_Int, .Data: C4D_EnergyHolder }, |
| 6248 | |
| 6249 | { .Identifier: "C4V_Any" , .ValType: C4V_Int, .Data: C4V_Any }, |
| 6250 | { .Identifier: "C4V_Int" , .ValType: C4V_Int, .Data: C4V_Int }, |
| 6251 | { .Identifier: "C4V_Bool" , .ValType: C4V_Int, .Data: C4V_Bool }, |
| 6252 | { .Identifier: "C4V_C4ID" , .ValType: C4V_Int, .Data: C4V_C4ID }, |
| 6253 | { .Identifier: "C4V_C4Object" , .ValType: C4V_Int, .Data: C4V_C4Object }, |
| 6254 | { .Identifier: "C4V_String" , .ValType: C4V_Int, .Data: C4V_String }, |
| 6255 | { .Identifier: "C4V_Array" , .ValType: C4V_Int, .Data: C4V_Array }, |
| 6256 | { .Identifier: "C4V_Map" , .ValType: C4V_Int, .Data: C4V_Map }, |
| 6257 | |
| 6258 | { .Identifier: "COMD_None" , .ValType: C4V_Int, COMD_None }, |
| 6259 | { .Identifier: "COMD_Stop" , .ValType: C4V_Int, COMD_Stop }, |
| 6260 | { .Identifier: "COMD_Up" , .ValType: C4V_Int, COMD_Up }, |
| 6261 | { .Identifier: "COMD_UpRight" , .ValType: C4V_Int, COMD_UpRight }, |
| 6262 | { .Identifier: "COMD_Right" , .ValType: C4V_Int, COMD_Right }, |
| 6263 | { .Identifier: "COMD_DownRight" , .ValType: C4V_Int, COMD_DownRight }, |
| 6264 | { .Identifier: "COMD_Down" , .ValType: C4V_Int, COMD_Down }, |
| 6265 | { .Identifier: "COMD_DownLeft" , .ValType: C4V_Int, COMD_DownLeft }, |
| 6266 | { .Identifier: "COMD_Left" , .ValType: C4V_Int, COMD_Left }, |
| 6267 | { .Identifier: "COMD_UpLeft" , .ValType: C4V_Int, COMD_UpLeft }, |
| 6268 | |
| 6269 | { .Identifier: "DIR_Left" , .ValType: C4V_Int, DIR_Left }, |
| 6270 | { .Identifier: "DIR_Right" , .ValType: C4V_Int, DIR_Right }, |
| 6271 | |
| 6272 | { .Identifier: "CON_CursorLeft" , .ValType: C4V_Int, .Data: CON_CursorLeft }, |
| 6273 | { .Identifier: "CON_CursorToggle" , .ValType: C4V_Int, .Data: CON_CursorToggle }, |
| 6274 | { .Identifier: "CON_CursorRight" , .ValType: C4V_Int, .Data: CON_CursorRight }, |
| 6275 | { .Identifier: "CON_Throw" , .ValType: C4V_Int, .Data: CON_Throw }, |
| 6276 | { .Identifier: "CON_Up" , .ValType: C4V_Int, .Data: CON_Up }, |
| 6277 | { .Identifier: "CON_Dig" , .ValType: C4V_Int, .Data: CON_Dig }, |
| 6278 | { .Identifier: "CON_Left" , .ValType: C4V_Int, .Data: CON_Left }, |
| 6279 | { .Identifier: "CON_Down" , .ValType: C4V_Int, .Data: CON_Down }, |
| 6280 | { .Identifier: "CON_Right" , .ValType: C4V_Int, .Data: CON_Right }, |
| 6281 | { .Identifier: "CON_Menu" , .ValType: C4V_Int, .Data: CON_Menu }, |
| 6282 | { .Identifier: "CON_Special" , .ValType: C4V_Int, .Data: CON_Special }, |
| 6283 | { .Identifier: "CON_Special2" , .ValType: C4V_Int, .Data: CON_Special2 }, |
| 6284 | |
| 6285 | { .Identifier: "OCF_Construct" , .ValType: C4V_Int, .Data: OCF_Construct }, |
| 6286 | { .Identifier: "OCF_Grab" , .ValType: C4V_Int, .Data: OCF_Grab }, |
| 6287 | { .Identifier: "OCF_Collectible" , .ValType: C4V_Int, .Data: OCF_Carryable }, |
| 6288 | { .Identifier: "OCF_OnFire" , .ValType: C4V_Int, .Data: OCF_OnFire }, |
| 6289 | { .Identifier: "OCF_HitSpeed1" , .ValType: C4V_Int, .Data: OCF_HitSpeed1 }, |
| 6290 | { .Identifier: "OCF_Fullcon" , .ValType: C4V_Int, .Data: OCF_FullCon }, |
| 6291 | { .Identifier: "OCF_Inflammable" , .ValType: C4V_Int, .Data: OCF_Inflammable }, |
| 6292 | { .Identifier: "OCF_Chop" , .ValType: C4V_Int, .Data: OCF_Chop }, |
| 6293 | { .Identifier: "OCF_Rotate" , .ValType: C4V_Int, .Data: OCF_Rotate }, |
| 6294 | { .Identifier: "OCF_Exclusive" , .ValType: C4V_Int, .Data: OCF_Exclusive }, |
| 6295 | { .Identifier: "OCF_Entrance" , .ValType: C4V_Int, .Data: OCF_Entrance }, |
| 6296 | { .Identifier: "OCF_HitSpeed2" , .ValType: C4V_Int, .Data: OCF_HitSpeed2 }, |
| 6297 | { .Identifier: "OCF_HitSpeed3" , .ValType: C4V_Int, .Data: OCF_HitSpeed3 }, |
| 6298 | { .Identifier: "OCF_Collection" , .ValType: C4V_Int, .Data: OCF_Collection }, |
| 6299 | { .Identifier: "OCF_Living" , .ValType: C4V_Int, .Data: OCF_Living }, |
| 6300 | { .Identifier: "OCF_HitSpeed4" , .ValType: C4V_Int, .Data: OCF_HitSpeed4 }, |
| 6301 | { .Identifier: "OCF_FightReady" , .ValType: C4V_Int, .Data: OCF_FightReady }, |
| 6302 | { .Identifier: "OCF_LineConstruct" , .ValType: C4V_Int, .Data: OCF_LineConstruct }, |
| 6303 | { .Identifier: "OCF_Prey" , .ValType: C4V_Int, .Data: OCF_Prey }, |
| 6304 | { .Identifier: "OCF_AttractLightning" , .ValType: C4V_Int, .Data: OCF_AttractLightning }, |
| 6305 | { .Identifier: "OCF_NotContained" , .ValType: C4V_Int, .Data: OCF_NotContained }, |
| 6306 | { .Identifier: "OCF_CrewMember" , .ValType: C4V_Int, .Data: OCF_CrewMember }, |
| 6307 | { .Identifier: "OCF_Edible" , .ValType: C4V_Int, .Data: OCF_Edible }, |
| 6308 | { .Identifier: "OCF_InLiquid" , .ValType: C4V_Int, .Data: OCF_InLiquid }, |
| 6309 | { .Identifier: "OCF_InSolid" , .ValType: C4V_Int, .Data: OCF_InSolid }, |
| 6310 | { .Identifier: "OCF_InFree" , .ValType: C4V_Int, .Data: OCF_InFree }, |
| 6311 | { .Identifier: "OCF_Available" , .ValType: C4V_Int, .Data: OCF_Available }, |
| 6312 | { .Identifier: "OCF_PowerConsumer" , .ValType: C4V_Int, .Data: OCF_PowerConsumer }, |
| 6313 | { .Identifier: "OCF_PowerSupply" , .ValType: C4V_Int, .Data: OCF_PowerSupply }, |
| 6314 | { .Identifier: "OCF_Container" , .ValType: C4V_Int, .Data: OCF_Container }, |
| 6315 | { .Identifier: "OCF_Alive" , .ValType: C4V_Int, .Data: static_cast<C4ValueInt>(OCF_Alive) }, |
| 6316 | |
| 6317 | { .Identifier: "VIS_All" , .ValType: C4V_Int, VIS_All }, |
| 6318 | { .Identifier: "VIS_None" , .ValType: C4V_Int, VIS_None }, |
| 6319 | { .Identifier: "VIS_Owner" , .ValType: C4V_Int, VIS_Owner }, |
| 6320 | { .Identifier: "VIS_Allies" , .ValType: C4V_Int, VIS_Allies }, |
| 6321 | { .Identifier: "VIS_Enemies" , .ValType: C4V_Int, VIS_Enemies }, |
| 6322 | { .Identifier: "VIS_Local" , .ValType: C4V_Int, VIS_Local }, |
| 6323 | { .Identifier: "VIS_God" , .ValType: C4V_Int, VIS_God }, |
| 6324 | { .Identifier: "VIS_LayerToggle" , .ValType: C4V_Int, VIS_LayerToggle }, |
| 6325 | { .Identifier: "VIS_OverlayOnly" , .ValType: C4V_Int, VIS_OverlayOnly }, |
| 6326 | |
| 6327 | { .Identifier: "C4X_Ver1" , .ValType: C4V_Int, C4XVER1 }, |
| 6328 | { .Identifier: "C4X_Ver2" , .ValType: C4V_Int, C4XVER2 }, |
| 6329 | { .Identifier: "C4X_Ver3" , .ValType: C4V_Int, C4XVER3 }, |
| 6330 | { .Identifier: "C4X_Ver4" , .ValType: C4V_Int, C4XVER4 }, |
| 6331 | { .Identifier: "C4X_VerBuild" , .ValType: C4V_Int, C4XVERBUILD }, |
| 6332 | |
| 6333 | { .Identifier: "SkyPar_Keep" , .ValType: C4V_Int, SkyPar_KEEP }, |
| 6334 | |
| 6335 | { .Identifier: "C4MN_Style_Normal" , .ValType: C4V_Int, .Data: C4MN_Style_Normal }, |
| 6336 | { .Identifier: "C4MN_Style_Context" , .ValType: C4V_Int, .Data: C4MN_Style_Context }, |
| 6337 | { .Identifier: "C4MN_Style_Info" , .ValType: C4V_Int, .Data: C4MN_Style_Info }, |
| 6338 | { .Identifier: "C4MN_Style_Dialog" , .ValType: C4V_Int, .Data: C4MN_Style_Dialog }, |
| 6339 | { .Identifier: "C4MN_Style_EqualItemHeight" , .ValType: C4V_Int, .Data: C4MN_Style_EqualItemHeight }, |
| 6340 | |
| 6341 | { .Identifier: "C4MN_Extra_None" , .ValType: C4V_Int, .Data: C4MN_Extra_None }, |
| 6342 | { .Identifier: "C4MN_Extra_Components" , .ValType: C4V_Int, .Data: C4MN_Extra_Components }, |
| 6343 | { .Identifier: "C4MN_Extra_Value" , .ValType: C4V_Int, .Data: C4MN_Extra_Value }, |
| 6344 | { .Identifier: "C4MN_Extra_MagicValue" , .ValType: C4V_Int, .Data: C4MN_Extra_MagicValue }, |
| 6345 | { .Identifier: "C4MN_Extra_Info" , .ValType: C4V_Int, .Data: C4MN_Extra_Info }, |
| 6346 | { .Identifier: "C4MN_Extra_ComponentsMagic" , .ValType: C4V_Int, .Data: C4MN_Extra_ComponentsMagic }, |
| 6347 | { .Identifier: "C4MN_Extra_LiveMagicValue" , .ValType: C4V_Int, .Data: C4MN_Extra_LiveMagicValue }, |
| 6348 | { .Identifier: "C4MN_Extra_ComponentsLiveMagic" , .ValType: C4V_Int, .Data: C4MN_Extra_ComponentsLiveMagic }, |
| 6349 | |
| 6350 | { .Identifier: "C4MN_Add_ImgRank" , .ValType: C4V_Int, .Data: C4MN_Add_ImgRank }, |
| 6351 | { .Identifier: "C4MN_Add_ImgIndexed" , .ValType: C4V_Int, .Data: C4MN_Add_ImgIndexed }, |
| 6352 | { .Identifier: "C4MN_Add_ImgObjRank" , .ValType: C4V_Int, .Data: C4MN_Add_ImgObjRank }, |
| 6353 | { .Identifier: "C4MN_Add_ImgObject" , .ValType: C4V_Int, .Data: C4MN_Add_ImgObject }, |
| 6354 | { .Identifier: "C4MN_Add_ImgTextSpec" , .ValType: C4V_Int, .Data: C4MN_Add_ImgTextSpec }, |
| 6355 | { .Identifier: "C4MN_Add_ImgColor" , .ValType: C4V_Int, .Data: C4MN_Add_ImgColor }, |
| 6356 | { .Identifier: "C4MN_Add_ImgIndexedColor" , .ValType: C4V_Int, .Data: C4MN_Add_ImgIndexedColor }, |
| 6357 | { .Identifier: "C4MN_Add_PassValue" , .ValType: C4V_Int, .Data: C4MN_Add_PassValue }, |
| 6358 | { .Identifier: "C4MN_Add_ForceCount" , .ValType: C4V_Int, .Data: C4MN_Add_ForceCount }, |
| 6359 | { .Identifier: "C4MN_Add_ForceNoDesc" , .ValType: C4V_Int, .Data: C4MN_Add_ForceNoDesc }, |
| 6360 | |
| 6361 | { .Identifier: "FX_OK" , .ValType: C4V_Int, C4Fx_OK }, // generic standard behaviour for all effect callbacks |
| 6362 | { .Identifier: "FX_Effect_Deny" , .ValType: C4V_Int, C4Fx_Effect_Deny }, // delete effect |
| 6363 | { .Identifier: "FX_Effect_Annul" , .ValType: C4V_Int, C4Fx_Effect_Annul }, // delete effect, because it has annulled a countereffect |
| 6364 | { .Identifier: "FX_Effect_AnnulDoCalls" , .ValType: C4V_Int, C4Fx_Effect_AnnulCalls }, // delete effect, because it has annulled a countereffect; temp readd countereffect |
| 6365 | { .Identifier: "FX_Execute_Kill" , .ValType: C4V_Int, C4Fx_Execute_Kill }, // execute callback: Remove effect now |
| 6366 | { .Identifier: "FX_Stop_Deny" , .ValType: C4V_Int, C4Fx_Stop_Deny }, // deny effect removal |
| 6367 | { .Identifier: "FX_Start_Deny" , .ValType: C4V_Int, C4Fx_Start_Deny }, // deny effect start |
| 6368 | |
| 6369 | { .Identifier: "FX_Call_Normal" , .ValType: C4V_Int, C4FxCall_Normal }, // normal call; effect is being added or removed |
| 6370 | { .Identifier: "FX_Call_Temp" , .ValType: C4V_Int, C4FxCall_Temp }, // temp call; effect is being added or removed in responce to a lower-level effect change |
| 6371 | { .Identifier: "FX_Call_TempAddForRemoval" , .ValType: C4V_Int, C4FxCall_TempAddForRemoval }, // temp call; effect is being added because it had been temp removed and is now removed forever |
| 6372 | { .Identifier: "FX_Call_RemoveClear" , .ValType: C4V_Int, C4FxCall_RemoveClear }, // effect is being removed because object is being removed |
| 6373 | { .Identifier: "FX_Call_RemoveDeath" , .ValType: C4V_Int, C4FxCall_RemoveDeath }, // effect is being removed because object died - return -1 to avoid removal |
| 6374 | { .Identifier: "FX_Call_DmgScript" , .ValType: C4V_Int, C4FxCall_DmgScript }, // damage through script call |
| 6375 | { .Identifier: "FX_Call_DmgBlast" , .ValType: C4V_Int, C4FxCall_DmgBlast }, // damage through blast |
| 6376 | { .Identifier: "FX_Call_DmgFire" , .ValType: C4V_Int, C4FxCall_DmgFire }, // damage through fire |
| 6377 | { .Identifier: "FX_Call_DmgChop" , .ValType: C4V_Int, C4FxCall_DmgChop }, // damage through chopping |
| 6378 | { .Identifier: "FX_Call_Energy" , .ValType: C4V_Int, .Data: 32 }, // bitmask for generic energy loss |
| 6379 | { .Identifier: "FX_Call_EngScript" , .ValType: C4V_Int, C4FxCall_EngScript }, // energy loss through script call |
| 6380 | { .Identifier: "FX_Call_EngBlast" , .ValType: C4V_Int, C4FxCall_EngBlast }, // energy loss through blast |
| 6381 | { .Identifier: "FX_Call_EngObjHit" , .ValType: C4V_Int, C4FxCall_EngObjHit }, // energy loss through object hitting the living |
| 6382 | { .Identifier: "FX_Call_EngFire" , .ValType: C4V_Int, C4FxCall_EngFire }, // energy loss through fire |
| 6383 | { .Identifier: "FX_Call_EngBaseRefresh" , .ValType: C4V_Int, C4FxCall_EngBaseRefresh }, // energy reload in base (also by base object, but that's normally not called) |
| 6384 | { .Identifier: "FX_Call_EngAsphyxiation" , .ValType: C4V_Int, C4FxCall_EngAsphyxiation }, // energy loss through asphyxiaction |
| 6385 | { .Identifier: "FX_Call_EngCorrosion" , .ValType: C4V_Int, C4FxCall_EngCorrosion }, // energy loss through corrosion (acid) |
| 6386 | { .Identifier: "FX_Call_EngStruct" , .ValType: C4V_Int, C4FxCall_EngStruct }, // regular structure energy loss (normally not called) |
| 6387 | { .Identifier: "FX_Call_EngGetPunched" , .ValType: C4V_Int, C4FxCall_EngGetPunched }, // energy loss during fighting |
| 6388 | |
| 6389 | { .Identifier: "GFXOV_MODE_None" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_None }, // gfx overlay modes |
| 6390 | { .Identifier: "GFXOV_MODE_Base" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_Base }, |
| 6391 | { .Identifier: "GFXOV_MODE_Action" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_Action }, |
| 6392 | { .Identifier: "GFXOV_MODE_Picture" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_Picture }, |
| 6393 | { .Identifier: "GFXOV_MODE_IngamePicture" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_IngamePicture }, |
| 6394 | { .Identifier: "GFXOV_MODE_Object" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_Object }, |
| 6395 | { .Identifier: "GFXOV_MODE_ExtraGraphics" , .ValType: C4V_Int, .Data: C4GraphicsOverlay::MODE_ExtraGraphics }, |
| 6396 | { .Identifier: "GFX_Overlay" , .ValType: C4V_Int, .Data: 1 }, // default overlay index |
| 6397 | { .Identifier: "GFXOV_Clothing" , .ValType: C4V_Int, .Data: 1000 }, // overlay indices for clothes on Clonks, etc. |
| 6398 | { .Identifier: "GFXOV_Tools" , .ValType: C4V_Int, .Data: 2000 }, // overlay indices for tools, weapons, etc. |
| 6399 | { .Identifier: "GFXOV_ProcessTarget" , .ValType: C4V_Int, .Data: 3000 }, // overlay indices for objects processed by a Clonk |
| 6400 | { .Identifier: "GFXOV_Misc" , .ValType: C4V_Int, .Data: 5000 }, // overlay indices for other stuff |
| 6401 | { .Identifier: "GFXOV_UI" , .ValType: C4V_Int, .Data: 6000 }, // overlay indices for user interface |
| 6402 | { .Identifier: "GFX_BLIT_Additive" , .ValType: C4V_Int, C4GFXBLIT_ADDITIVE }, // blit modes |
| 6403 | { .Identifier: "GFX_BLIT_Mod2" , .ValType: C4V_Int, C4GFXBLIT_MOD2 }, |
| 6404 | { .Identifier: "GFX_BLIT_ClrSfc_OwnClr" , .ValType: C4V_Int, C4GFXBLIT_CLRSFC_OWNCLR }, |
| 6405 | { .Identifier: "GFX_BLIT_ClrSfc_Mod2" , .ValType: C4V_Int, C4GFXBLIT_CLRSFC_MOD2 }, |
| 6406 | { .Identifier: "GFX_BLIT_Custom" , .ValType: C4V_Int, C4GFXBLIT_CUSTOM }, |
| 6407 | { .Identifier: "GFX_BLIT_Parent" , .ValType: C4V_Int, C4GFXBLIT_PARENT }, |
| 6408 | |
| 6409 | { .Identifier: "NO_OWNER" , .ValType: C4V_Int, .Data: NO_OWNER }, // invalid player number |
| 6410 | |
| 6411 | // contact attachment |
| 6412 | { .Identifier: "CNAT_None" , .ValType: C4V_Int, .Data: CNAT_None }, |
| 6413 | { .Identifier: "CNAT_Left" , .ValType: C4V_Int, .Data: CNAT_Left }, |
| 6414 | { .Identifier: "CNAT_Right" , .ValType: C4V_Int, .Data: CNAT_Right }, |
| 6415 | { .Identifier: "CNAT_Top" , .ValType: C4V_Int, .Data: CNAT_Top }, |
| 6416 | { .Identifier: "CNAT_Bottom" , .ValType: C4V_Int, .Data: CNAT_Bottom }, |
| 6417 | { .Identifier: "CNAT_Center" , .ValType: C4V_Int, .Data: CNAT_Center }, |
| 6418 | { .Identifier: "CNAT_MultiAttach" , .ValType: C4V_Int, .Data: CNAT_MultiAttach }, |
| 6419 | { .Identifier: "CNAT_NoCollision" , .ValType: C4V_Int, .Data: CNAT_NoCollision }, |
| 6420 | |
| 6421 | // vertex data |
| 6422 | { .Identifier: "VTX_X" , .ValType: C4V_Int, .Data: VTX_X }, |
| 6423 | { .Identifier: "VTX_Y" , .ValType: C4V_Int, .Data: VTX_Y }, |
| 6424 | { .Identifier: "VTX_CNAT" , .ValType: C4V_Int, .Data: VTX_CNAT }, |
| 6425 | { .Identifier: "VTX_Friction" , .ValType: C4V_Int, .Data: VTX_Friction }, |
| 6426 | |
| 6427 | // vertex set mode |
| 6428 | { .Identifier: "VTX_SetPermanent" , .ValType: C4V_Int, .Data: VTX_SetPermanent }, |
| 6429 | { .Identifier: "VTX_SetPermanentUpd" , .ValType: C4V_Int, .Data: VTX_SetPermanentUpd }, |
| 6430 | |
| 6431 | // material density |
| 6432 | { .Identifier: "C4M_Vehicle" , .ValType: C4V_Int, .Data: C4M_Vehicle }, |
| 6433 | { .Identifier: "C4M_Solid" , .ValType: C4V_Int, .Data: C4M_Solid }, |
| 6434 | { .Identifier: "C4M_SemiSolid" , .ValType: C4V_Int, .Data: C4M_SemiSolid }, |
| 6435 | { .Identifier: "C4M_Liquid" , .ValType: C4V_Int, .Data: C4M_Liquid }, |
| 6436 | { .Identifier: "C4M_Background" , .ValType: C4V_Int, .Data: C4M_Background }, |
| 6437 | |
| 6438 | // scoreboard |
| 6439 | { .Identifier: "SBRD_Caption" , .ValType: C4V_Int, .Data: C4Scoreboard::TitleKey }, // used to set row/coloumn headers |
| 6440 | |
| 6441 | // teams - constants for GetTeamConfig |
| 6442 | { .Identifier: "TEAM_Custom" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_Custom }, |
| 6443 | { .Identifier: "TEAM_Active" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_Active }, |
| 6444 | { .Identifier: "TEAM_AllowHostilityChange" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_AllowHostilityChange }, |
| 6445 | { .Identifier: "TEAM_Dist" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_Dist }, |
| 6446 | { .Identifier: "TEAM_AllowTeamSwitch" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_AllowTeamSwitch }, |
| 6447 | { .Identifier: "TEAM_AutoGenerateTeams" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_AutoGenerateTeams }, |
| 6448 | { .Identifier: "TEAM_TeamColors" , .ValType: C4V_Int, .Data: C4TeamList::TEAM_TeamColors }, |
| 6449 | |
| 6450 | { .Identifier: "C4OS_DELETED" , .ValType: C4V_Int, C4OS_DELETED }, |
| 6451 | { .Identifier: "C4OS_NORMAL" , .ValType: C4V_Int, C4OS_NORMAL }, |
| 6452 | { .Identifier: "C4OS_INACTIVE" , .ValType: C4V_Int, C4OS_INACTIVE }, |
| 6453 | |
| 6454 | { .Identifier: "C4MSGCMDR_Escaped" , .ValType: C4V_Int, .Data: C4MessageBoardCommand::C4MSGCMDR_Escaped }, |
| 6455 | { .Identifier: "C4MSGCMDR_Plain" , .ValType: C4V_Int, .Data: C4MessageBoardCommand::C4MSGCMDR_Plain }, |
| 6456 | { .Identifier: "C4MSGCMDR_Identifier" , .ValType: C4V_Int, .Data: C4MessageBoardCommand::C4MSGCMDR_Identifier }, |
| 6457 | |
| 6458 | { .Identifier: "BASEFUNC_Default" , .ValType: C4V_Int, .Data: BASEFUNC_Default }, |
| 6459 | { .Identifier: "BASEFUNC_AutoSellContents" , .ValType: C4V_Int, .Data: BASEFUNC_AutoSellContents }, |
| 6460 | { .Identifier: "BASEFUNC_RegenerateEnergy" , .ValType: C4V_Int, .Data: BASEFUNC_RegenerateEnergy }, |
| 6461 | { .Identifier: "BASEFUNC_Buy" , .ValType: C4V_Int, .Data: BASEFUNC_Buy }, |
| 6462 | { .Identifier: "BASEFUNC_Sell" , .ValType: C4V_Int, .Data: BASEFUNC_Sell }, |
| 6463 | { .Identifier: "BASEFUNC_RejectEntrance" , .ValType: C4V_Int, .Data: BASEFUNC_RejectEntrance }, |
| 6464 | { .Identifier: "BASEFUNC_Extinguish" , .ValType: C4V_Int, .Data: BASEFUNC_Extinguish }, |
| 6465 | |
| 6466 | { .Identifier: "C4FO_Not" , .ValType: C4V_Int, .Data: C4FO_Not }, |
| 6467 | { .Identifier: "C4FO_And" , .ValType: C4V_Int, .Data: C4FO_And }, |
| 6468 | { .Identifier: "C4FO_Or" , .ValType: C4V_Int, .Data: C4FO_Or }, |
| 6469 | { .Identifier: "C4FO_Exclude" , .ValType: C4V_Int, .Data: C4FO_Exclude }, |
| 6470 | { .Identifier: "C4FO_InRect" , .ValType: C4V_Int, .Data: C4FO_InRect }, |
| 6471 | { .Identifier: "C4FO_AtPoint" , .ValType: C4V_Int, .Data: C4FO_AtPoint }, |
| 6472 | { .Identifier: "C4FO_AtRect" , .ValType: C4V_Int, .Data: C4FO_AtRect }, |
| 6473 | { .Identifier: "C4FO_OnLine" , .ValType: C4V_Int, .Data: C4FO_OnLine }, |
| 6474 | { .Identifier: "C4FO_Distance" , .ValType: C4V_Int, .Data: C4FO_Distance }, |
| 6475 | { .Identifier: "C4FO_ID" , .ValType: C4V_Int, .Data: C4FO_ID }, |
| 6476 | { .Identifier: "C4FO_OCF" , .ValType: C4V_Int, .Data: C4FO_OCF }, |
| 6477 | { .Identifier: "C4FO_Category" , .ValType: C4V_Int, .Data: C4FO_Category }, |
| 6478 | { .Identifier: "C4FO_Action" , .ValType: C4V_Int, .Data: C4FO_Action }, |
| 6479 | { .Identifier: "C4FO_ActionTarget" , .ValType: C4V_Int, .Data: C4FO_ActionTarget }, |
| 6480 | { .Identifier: "C4FO_Container" , .ValType: C4V_Int, .Data: C4FO_Container }, |
| 6481 | { .Identifier: "C4FO_AnyContainer" , .ValType: C4V_Int, .Data: C4FO_AnyContainer }, |
| 6482 | { .Identifier: "C4FO_Owner" , .ValType: C4V_Int, .Data: C4FO_Owner }, |
| 6483 | { .Identifier: "C4FO_Controller" , .ValType: C4V_Int, .Data: C4FO_Controller }, |
| 6484 | { .Identifier: "C4FO_Func" , .ValType: C4V_Int, .Data: C4FO_Func }, |
| 6485 | { .Identifier: "C4FO_Layer" , .ValType: C4V_Int, .Data: C4FO_Layer }, |
| 6486 | |
| 6487 | { .Identifier: "C4SO_Reverse" , .ValType: C4V_Int, .Data: C4SO_Reverse }, |
| 6488 | { .Identifier: "C4SO_Multiple" , .ValType: C4V_Int, .Data: C4SO_Multiple }, |
| 6489 | { .Identifier: "C4SO_Distance" , .ValType: C4V_Int, .Data: C4SO_Distance }, |
| 6490 | { .Identifier: "C4SO_Random" , .ValType: C4V_Int, .Data: C4SO_Random }, |
| 6491 | { .Identifier: "C4SO_Speed" , .ValType: C4V_Int, .Data: C4SO_Speed }, |
| 6492 | { .Identifier: "C4SO_Mass" , .ValType: C4V_Int, .Data: C4SO_Mass }, |
| 6493 | { .Identifier: "C4SO_Value" , .ValType: C4V_Int, .Data: C4SO_Value }, |
| 6494 | { .Identifier: "C4SO_Func" , .ValType: C4V_Int, .Data: C4SO_Func }, |
| 6495 | |
| 6496 | { .Identifier: "PHYS_Current" , .ValType: C4V_Int, .Data: PHYS_Current }, |
| 6497 | { .Identifier: "PHYS_Permanent" , .ValType: C4V_Int, .Data: PHYS_Permanent }, |
| 6498 | { .Identifier: "PHYS_Temporary" , .ValType: C4V_Int, .Data: PHYS_Temporary }, |
| 6499 | { .Identifier: "PHYS_StackTemporary" , .ValType: C4V_Int, .Data: PHYS_StackTemporary }, |
| 6500 | |
| 6501 | { .Identifier: "C4CMD_Base" , .ValType: C4V_Int, .Data: C4CMD_Mode_Base }, |
| 6502 | { .Identifier: "C4CMD_SilentBase" , .ValType: C4V_Int, .Data: C4CMD_Mode_SilentBase }, |
| 6503 | { .Identifier: "C4CMD_Sub" , .ValType: C4V_Int, .Data: C4CMD_Mode_Sub }, |
| 6504 | { .Identifier: "C4CMD_SilentSub" , .ValType: C4V_Int, .Data: C4CMD_Mode_SilentSub }, |
| 6505 | |
| 6506 | { .Identifier: "C4CMD_MoveTo_NoPosAdjust" , .ValType: C4V_Int, .Data: C4CMD_MoveTo_NoPosAdjust }, |
| 6507 | { .Identifier: "C4CMD_MoveTo_PushTarget" , .ValType: C4V_Int, .Data: C4CMD_MoveTo_PushTarget }, |
| 6508 | { .Identifier: "C4CMD_Enter_PushTarget" , .ValType: C4V_Int, .Data: C4CMD_Enter_PushTarget }, |
| 6509 | |
| 6510 | { .Identifier: "C4SECT_SaveLandscape" , .ValType: C4V_Int, C4S_SAVE_LANDSCAPE }, |
| 6511 | { .Identifier: "C4SECT_SaveObjects" , .ValType: C4V_Int, C4S_SAVE_OBJECTS }, |
| 6512 | { .Identifier: "C4SECT_KeepEffects" , .ValType: C4V_Int, C4S_KEEP_EFFECTS }, |
| 6513 | |
| 6514 | { .Identifier: "TEAMID_New" , .ValType: C4V_Int, .Data: TEAMID_New }, |
| 6515 | |
| 6516 | { .Identifier: "MSG_NoLinebreak" , .ValType: C4V_Int, .Data: C4GM_NoBreak }, |
| 6517 | { .Identifier: "MSG_Bottom" , .ValType: C4V_Int, .Data: C4GM_Bottom }, |
| 6518 | { .Identifier: "MSG_Multiple" , .ValType: C4V_Int, .Data: C4GM_Multiple }, |
| 6519 | { .Identifier: "MSG_Top" , .ValType: C4V_Int, .Data: C4GM_Top }, |
| 6520 | { .Identifier: "MSG_Left" , .ValType: C4V_Int, .Data: C4GM_Left }, |
| 6521 | { .Identifier: "MSG_Right" , .ValType: C4V_Int, .Data: C4GM_Right }, |
| 6522 | { .Identifier: "MSG_HCenter" , .ValType: C4V_Int, .Data: C4GM_HCenter }, |
| 6523 | { .Identifier: "MSG_VCenter" , .ValType: C4V_Int, .Data: C4GM_VCenter }, |
| 6524 | { .Identifier: "MSG_DropSpeech" , .ValType: C4V_Int, .Data: C4GM_DropSpeech }, |
| 6525 | { .Identifier: "MSG_WidthRel" , .ValType: C4V_Int, .Data: C4GM_WidthRel }, |
| 6526 | { .Identifier: "MSG_XRel" , .ValType: C4V_Int, .Data: C4GM_XRel }, |
| 6527 | { .Identifier: "MSG_YRel" , .ValType: C4V_Int, .Data: C4GM_YRel }, |
| 6528 | { .Identifier: "MSG_ALeft" , .ValType: C4V_Int, .Data: C4GM_ALeft }, |
| 6529 | { .Identifier: "MSG_ACenter" , .ValType: C4V_Int, .Data: C4GM_ACenter }, |
| 6530 | { .Identifier: "MSG_ARight" , .ValType: C4V_Int, .Data: C4GM_ARight }, |
| 6531 | |
| 6532 | { .Identifier: "C4PT_User" , .ValType: C4V_Int, .Data: C4PT_User }, |
| 6533 | { .Identifier: "C4PT_Script" , .ValType: C4V_Int, .Data: C4PT_Script }, |
| 6534 | |
| 6535 | { .Identifier: "CSPF_FixedAttributes" , .ValType: C4V_Int, .Data: CSPF_FixedAttributes }, |
| 6536 | { .Identifier: "CSPF_NoScenarioInit" , .ValType: C4V_Int, .Data: CSPF_NoScenarioInit }, |
| 6537 | { .Identifier: "CSPF_NoEliminationCheck" , .ValType: C4V_Int, .Data: CSPF_NoEliminationCheck }, |
| 6538 | { .Identifier: "CSPF_Invisible" , .ValType: C4V_Int, .Data: CSPF_Invisible }, |
| 6539 | |
| 6540 | { .Identifier: "RESTORE_None" , .ValType: C4V_Int, .Data: C4NetworkRestartInfos::None }, |
| 6541 | { .Identifier: "RESTORE_ScriptPlayers" , .ValType: C4V_Int, .Data: C4NetworkRestartInfos::ScriptPlayers }, |
| 6542 | { .Identifier: "RESTORE_PlayerTeams" , .ValType: C4V_Int, .Data: C4NetworkRestartInfos::PlayerTeams }, |
| 6543 | |
| 6544 | { .Identifier: "C4PVM_Cursor" , .ValType: C4V_Int, .Data: C4PVM_Cursor }, |
| 6545 | { .Identifier: "C4PVM_Target" , .ValType: C4V_Int, .Data: C4PVM_Target }, |
| 6546 | { .Identifier: "C4PVM_Scrolling" , .ValType: C4V_Int, .Data: C4PVM_Scrolling }, |
| 6547 | }; |
| 6548 | |
| 6549 | template <> struct C4ValueConv<C4Value> |
| 6550 | { |
| 6551 | inline static C4V_Type Type() { return C4V_Any; } |
| 6552 | inline static C4Value FromC4V(C4Value &v) { return v; } |
| 6553 | inline static C4Value _FromC4V(const C4Value &v) { return v; } |
| 6554 | inline static C4Value ToC4V(C4Value v) { return v; } |
| 6555 | }; |
| 6556 | |
| 6557 | template <typename T> struct C4ValueConv<std::optional<T>> |
| 6558 | { |
| 6559 | inline static C4V_Type Type() { return C4ValueConv<T>::Type(); } |
| 6560 | inline static std::optional<T> FromC4V(C4Value &v) |
| 6561 | { |
| 6562 | if (v.GetType() != C4V_Any) return {C4ValueConv<T>::FromC4V(v)}; |
| 6563 | return {}; |
| 6564 | } |
| 6565 | inline static std::optional<T> _FromC4V(const C4Value &v) |
| 6566 | { |
| 6567 | if (v.GetType() != C4V_Any) return {C4ValueConv<T>::_FromC4V(v)}; |
| 6568 | return {}; |
| 6569 | } |
| 6570 | inline static C4Value ToC4V(const std::optional<T>& v) |
| 6571 | { |
| 6572 | if (v) return C4ValueConv<T>::ToC4V(*v); |
| 6573 | return C4VNull; |
| 6574 | } |
| 6575 | }; |
| 6576 | |
| 6577 | void InitFunctionMap(C4AulScriptEngine *pEngine) |
| 6578 | { |
| 6579 | // add all def constants (all Int) |
| 6580 | for (const auto &def : C4ScriptConstMap) |
| 6581 | Game.ScriptEngine.RegisterGlobalConstant(szName: def.Identifier, rValue: C4Value(def.Data, def.ValType)); |
| 6582 | |
| 6583 | AddFunc(owner: pEngine, name: "goto" , func&: Fn_goto); |
| 6584 | AddFunc(owner: pEngine, name: "this" , func&: Fn_this); |
| 6585 | AddFunc(owner: pEngine, name: "Equal" , func&: FnEqual); |
| 6586 | AddFunc(owner: pEngine, name: "Var" , func&: FnVar); |
| 6587 | AddFunc(owner: pEngine, name: "AssignVar" , func&: FnSetVar, pub: false); |
| 6588 | AddFunc(owner: pEngine, name: "SetVar" , func&: FnSetVar); |
| 6589 | AddFunc(owner: pEngine, name: "IncVar" , func&: FnIncVar); |
| 6590 | AddFunc(owner: pEngine, name: "DecVar" , func&: FnDecVar); |
| 6591 | AddFunc(owner: pEngine, name: "SetGlobal" , func&: FnSetGlobal); |
| 6592 | AddFunc(owner: pEngine, name: "Global" , func&: FnGlobal); |
| 6593 | AddFunc(owner: pEngine, name: "SetLocal" , func&: FnSetLocal); |
| 6594 | AddFunc(owner: pEngine, name: "Local" , func&: FnLocal); |
| 6595 | AddFunc(owner: pEngine, name: "Explode" , func&: FnExplode); |
| 6596 | AddFunc(owner: pEngine, name: "Incinerate" , func&: FnIncinerate); |
| 6597 | AddFunc(owner: pEngine, name: "IncinerateLandscape" , func&: FnIncinerateLandscape); |
| 6598 | AddFunc(owner: pEngine, name: "Extinguish" , func&: FnExtinguish); |
| 6599 | AddFunc(owner: pEngine, name: "GrabContents" , func&: FnGrabContents); |
| 6600 | AddFunc(owner: pEngine, name: "Punch" , func&: FnPunch); |
| 6601 | AddFunc(owner: pEngine, name: "Kill" , func&: FnKill); |
| 6602 | AddFunc(owner: pEngine, name: "Fling" , func&: FnFling); |
| 6603 | AddFunc(owner: pEngine, name: "Jump" , func&: FnJump); |
| 6604 | AddFunc(owner: pEngine, name: "ChangeDef" , func&: FnChangeDef); |
| 6605 | AddFunc(owner: pEngine, name: "Exit" , func&: FnExit); |
| 6606 | AddFunc(owner: pEngine, name: "Enter" , func&: FnEnter); |
| 6607 | AddFunc(owner: pEngine, name: "Collect" , func&: FnCollect); |
| 6608 | AddFunc(owner: pEngine, name: "Split2Components" , func&: FnSplit2Components); |
| 6609 | AddFunc(owner: pEngine, name: "PlayerObjectCommand" , func&: FnPlayerObjectCommand); |
| 6610 | AddFunc(owner: pEngine, name: "SetCommand" , func&: FnSetCommand); |
| 6611 | AddFunc(owner: pEngine, name: "AddCommand" , func&: FnAddCommand); |
| 6612 | AddFunc(owner: pEngine, name: "AppendCommand" , func&: FnAppendCommand); |
| 6613 | AddFunc(owner: pEngine, name: "GetCommand" , func&: FnGetCommand); |
| 6614 | AddFunc(owner: pEngine, name: "DeathAnnounce" , func&: FnDeathAnnounce); |
| 6615 | AddFunc(owner: pEngine, name: "FindObject" , func&: FnFindObject); |
| 6616 | AddFunc(owner: pEngine, name: "ObjectCount" , func&: FnObjectCount); |
| 6617 | AddFunc(owner: pEngine, name: "ObjectCall" , func&: FnObjectCall); |
| 6618 | AddFunc(owner: pEngine, name: "ProtectedCall" , func&: FnProtectedCall); |
| 6619 | AddFunc(owner: pEngine, name: "PrivateCall" , func&: FnPrivateCall); |
| 6620 | AddFunc(owner: pEngine, name: "GameCall" , func&: FnGameCall); |
| 6621 | AddFunc(owner: pEngine, name: "GameCallEx" , func&: FnGameCallEx); |
| 6622 | AddFunc(owner: pEngine, name: "DefinitionCall" , func&: FnDefinitionCall); |
| 6623 | AddFunc(owner: pEngine, name: "Call" , func&: FnCall, pub: false); |
| 6624 | AddFunc(owner: pEngine, name: "GetPlrKnowledge" , func&: FnGetPlrKnowledge); |
| 6625 | AddFunc(owner: pEngine, name: "GetPlrMagic" , func&: FnGetPlrMagic); |
| 6626 | AddFunc(owner: pEngine, name: "GetComponent" , func&: FnGetComponent); |
| 6627 | AddFunc(owner: pEngine, name: "PlayerMessage" , func&: FnPlayerMessage); |
| 6628 | AddFunc(owner: pEngine, name: "Message" , func&: FnMessage); |
| 6629 | AddFunc(owner: pEngine, name: "AddMessage" , func&: FnAddMessage); |
| 6630 | AddFunc(owner: pEngine, name: "PlrMessage" , func&: FnPlrMessage); |
| 6631 | AddFunc(owner: pEngine, name: "Log" , func&: FnLog); |
| 6632 | AddFunc(owner: pEngine, name: "DebugLog" , func&: FnDebugLog); |
| 6633 | AddFunc(owner: pEngine, name: "Format" , func&: FnFormat); |
| 6634 | AddFunc(owner: pEngine, name: "EditCursor" , func&: FnEditCursor); |
| 6635 | AddFunc(owner: pEngine, name: "AddMenuItem" , func&: FnAddMenuItem); |
| 6636 | AddFunc(owner: pEngine, name: "SetSolidMask" , func&: FnSetSolidMask); |
| 6637 | AddFunc(owner: pEngine, name: "SetGravity" , func&: FnSetGravity); |
| 6638 | AddFunc(owner: pEngine, name: "GetGravity" , func&: FnGetGravity); |
| 6639 | AddFunc(owner: pEngine, name: "GetHomebaseMaterial" , func&: FnGetHomebaseMaterial); |
| 6640 | AddFunc(owner: pEngine, name: "GetHomebaseProduction" , func&: FnGetHomebaseProduction); |
| 6641 | AddFunc(owner: pEngine, name: "IsRef" , func&: FnIsRef); |
| 6642 | AddFunc(owner: pEngine, name: "GetType" , func&: FnGetType); |
| 6643 | AddFunc(owner: pEngine, name: "CreateArray" , func&: FnCreateArray); |
| 6644 | AddFunc(owner: pEngine, name: "GetLength" , func&: FnGetLength); |
| 6645 | AddFunc(owner: pEngine, name: "GetIndexOf" , func&: FnGetIndexOf); |
| 6646 | AddFunc(owner: pEngine, name: "GetDefCoreVal" , func&: FnGetDefCoreVal); |
| 6647 | AddFunc(owner: pEngine, name: "GetActMapVal" , func&: FnGetActMapVal); |
| 6648 | AddFunc(owner: pEngine, name: "GetObjectVal" , func&: FnGetObjectVal); |
| 6649 | AddFunc(owner: pEngine, name: "GetObjectInfoCoreVal" , func&: FnGetObjectInfoCoreVal); |
| 6650 | AddFunc(owner: pEngine, name: "GetScenarioVal" , func&: FnGetScenarioVal); |
| 6651 | AddFunc(owner: pEngine, name: "GetPlayerVal" , func&: FnGetPlayerVal); |
| 6652 | AddFunc(owner: pEngine, name: "GetPlayerInfoCoreVal" , func&: FnGetPlayerInfoCoreVal); |
| 6653 | AddFunc(owner: pEngine, name: "GetMaterialVal" , func&: FnGetMaterialVal); |
| 6654 | AddFunc(owner: pEngine, name: "SetPlrExtraData" , func&: FnSetPlrExtraData); |
| 6655 | AddFunc(owner: pEngine, name: "GetPlrExtraData" , func&: FnGetPlrExtraData); |
| 6656 | AddFunc(owner: pEngine, name: "SetCrewExtraData" , func&: FnSetCrewExtraData); |
| 6657 | AddFunc(owner: pEngine, name: "GetCrewExtraData" , func&: FnGetCrewExtraData); |
| 6658 | AddFunc(owner: pEngine, name: "GetPortrait" , func&: FnGetPortrait); |
| 6659 | AddFunc(owner: pEngine, name: "AddEffect" , func&: FnAddEffect); |
| 6660 | AddFunc(owner: pEngine, name: "GetEffect" , func&: FnGetEffect); |
| 6661 | AddFunc(owner: pEngine, name: "CheckEffect" , func&: FnCheckEffect); |
| 6662 | AddFunc(owner: pEngine, name: "EffectCall" , func&: FnEffectCall); |
| 6663 | AddFunc(owner: pEngine, name: "eval" , func&: FnEval); |
| 6664 | AddFunc(owner: pEngine, name: "VarN" , func&: FnVarN); |
| 6665 | AddFunc(owner: pEngine, name: "LocalN" , func&: FnLocalN); |
| 6666 | AddFunc(owner: pEngine, name: "GlobalN" , func&: FnGlobalN); |
| 6667 | AddFunc(owner: pEngine, name: "Set" , func&: FnSet); |
| 6668 | AddFunc(owner: pEngine, name: "Inc" , func&: FnInc); |
| 6669 | AddFunc(owner: pEngine, name: "Dec" , func&: FnDec); |
| 6670 | AddFunc(owner: pEngine, name: "SetLength" , func&: FnSetLength); |
| 6671 | AddFunc(owner: pEngine, name: "SimFlight" , func&: FnSimFlight); |
| 6672 | AddFunc(owner: pEngine, name: "EffectVar" , func&: FnEffectVar); |
| 6673 | AddFunc(owner: pEngine, name: "Or" , func&: FnOr, pub: false); |
| 6674 | AddFunc(owner: pEngine, name: "Not" , func&: FnNot, pub: false); |
| 6675 | AddFunc(owner: pEngine, name: "And" , func&: FnAnd, pub: false); |
| 6676 | AddFunc(owner: pEngine, name: "BitAnd" , func&: FnBitAnd, pub: false); |
| 6677 | AddFunc(owner: pEngine, name: "Sum" , func&: FnSum, pub: false); |
| 6678 | AddFunc(owner: pEngine, name: "Sub" , func&: FnSub, pub: false); |
| 6679 | AddFunc(owner: pEngine, name: "Abs" , func&: FnAbs); |
| 6680 | AddFunc(owner: pEngine, name: "Min" , func&: FnMin); |
| 6681 | AddFunc(owner: pEngine, name: "Max" , func&: FnMax); |
| 6682 | AddFunc(owner: pEngine, name: "Mul" , func&: FnMul, pub: false); |
| 6683 | AddFunc(owner: pEngine, name: "Div" , func&: FnDiv, pub: false); |
| 6684 | AddFunc(owner: pEngine, name: "Mod" , func&: FnMod, pub: false); |
| 6685 | AddFunc(owner: pEngine, name: "Pow" , func&: FnPow, pub: false); |
| 6686 | AddFunc(owner: pEngine, name: "Sin" , func&: FnSin); |
| 6687 | AddFunc(owner: pEngine, name: "Cos" , func&: FnCos); |
| 6688 | AddFunc(owner: pEngine, name: "Sqrt" , func&: FnSqrt); |
| 6689 | AddFunc(owner: pEngine, name: "ArcSin" , func&: FnArcSin); |
| 6690 | AddFunc(owner: pEngine, name: "ArcCos" , func&: FnArcCos); |
| 6691 | AddFunc(owner: pEngine, name: "LessThan" , func&: FnLessThan, pub: false); |
| 6692 | AddFunc(owner: pEngine, name: "GreaterThan" , func&: FnGreaterThan, pub: false); |
| 6693 | AddFunc(owner: pEngine, name: "BoundBy" , func&: FnBoundBy); |
| 6694 | AddFunc(owner: pEngine, name: "Inside" , func&: FnInside); |
| 6695 | AddFunc(owner: pEngine, name: "SEqual" , func&: FnSEqual, pub: false); |
| 6696 | AddFunc(owner: pEngine, name: "Random" , func&: FnRandom); |
| 6697 | AddFunc(owner: pEngine, name: "AsyncRandom" , func&: FnAsyncRandom); |
| 6698 | AddFunc(owner: pEngine, name: "DoCon" , func&: FnDoCon); |
| 6699 | AddFunc(owner: pEngine, name: "GetCon" , func&: FnGetCon); |
| 6700 | AddFunc(owner: pEngine, name: "DoDamage" , func&: FnDoDamage); |
| 6701 | AddFunc(owner: pEngine, name: "DoEnergy" , func&: FnDoEnergy); |
| 6702 | AddFunc(owner: pEngine, name: "DoBreath" , func&: FnDoBreath); |
| 6703 | AddFunc(owner: pEngine, name: "DoMagicEnergy" , func&: FnDoMagicEnergy); |
| 6704 | AddFunc(owner: pEngine, name: "GetMagicEnergy" , func&: FnGetMagicEnergy); |
| 6705 | AddFunc(owner: pEngine, name: "EnergyCheck" , func&: FnEnergyCheck); |
| 6706 | AddFunc(owner: pEngine, name: "CheckEnergyNeedChain" , func&: FnCheckEnergyNeedChain); |
| 6707 | AddFunc(owner: pEngine, name: "GetEnergy" , func&: FnGetEnergy); |
| 6708 | AddFunc(owner: pEngine, name: "OnFire" , func&: FnOnFire); |
| 6709 | AddFunc(owner: pEngine, name: "Smoke" , func&: FnSmoke); |
| 6710 | AddFunc(owner: pEngine, name: "Stuck" , func&: FnStuck); |
| 6711 | AddFunc(owner: pEngine, name: "InLiquid" , func&: FnInLiquid); |
| 6712 | AddFunc(owner: pEngine, name: "Bubble" , func&: FnBubble); |
| 6713 | AddFunc(owner: pEngine, name: "SetAction" , func&: FnSetAction); |
| 6714 | AddFunc(owner: pEngine, name: "SetActionData" , func&: FnSetActionData); |
| 6715 | AddFunc(owner: pEngine, name: "SetBridgeActionData" , func&: FnSetBridgeActionData); |
| 6716 | AddFunc(owner: pEngine, name: "GetAction" , func&: FnGetAction); |
| 6717 | AddFunc(owner: pEngine, name: "GetActTime" , func&: FnGetActTime); |
| 6718 | AddFunc(owner: pEngine, name: "GetOwner" , func&: FnGetOwner); |
| 6719 | AddFunc(owner: pEngine, name: "GetMass" , func&: FnGetMass); |
| 6720 | AddFunc(owner: pEngine, name: "GetBreath" , func&: FnGetBreath); |
| 6721 | AddFunc(owner: pEngine, name: "GetX" , func&: FnGetX); |
| 6722 | AddFunc(owner: pEngine, name: "GetY" , func&: FnGetY); |
| 6723 | AddFunc(owner: pEngine, name: "GetBase" , func&: FnGetBase); |
| 6724 | AddFunc(owner: pEngine, name: "GetMenu" , func&: FnGetMenu); |
| 6725 | AddFunc(owner: pEngine, name: "GetVertexNum" , func&: FnGetVertexNum); |
| 6726 | AddFunc(owner: pEngine, name: "GetVertex" , func&: FnGetVertex); |
| 6727 | AddFunc(owner: pEngine, name: "SetVertex" , func&: FnSetVertex); |
| 6728 | AddFunc(owner: pEngine, name: "AddVertex" , func&: FnAddVertex); |
| 6729 | AddFunc(owner: pEngine, name: "RemoveVertex" , func&: FnRemoveVertex); |
| 6730 | AddFunc(owner: pEngine, name: "SetContactDensity" , func&: FnSetContactDensity, pub: false); |
| 6731 | AddFunc(owner: pEngine, name: "AnyContainer" , func&: FnAnyContainer); |
| 6732 | AddFunc(owner: pEngine, name: "NoContainer" , func&: FnNoContainer); |
| 6733 | AddFunc(owner: pEngine, name: "GetController" , func&: FnGetController); |
| 6734 | AddFunc(owner: pEngine, name: "SetController" , func&: FnSetController); |
| 6735 | AddFunc(owner: pEngine, name: "GetKiller" , func&: FnGetKiller); |
| 6736 | AddFunc(owner: pEngine, name: "SetKiller" , func&: FnSetKiller); |
| 6737 | AddFunc(owner: pEngine, name: "GetPhase" , func&: FnGetPhase); |
| 6738 | AddFunc(owner: pEngine, name: "SetPhase" , func&: FnSetPhase); |
| 6739 | AddFunc(owner: pEngine, name: "GetCategory" , func&: FnGetCategory); |
| 6740 | AddFunc(owner: pEngine, name: "GetOCF" , func&: FnGetOCF); |
| 6741 | AddFunc(owner: pEngine, name: "SetAlive" , func&: FnSetAlive); |
| 6742 | AddFunc(owner: pEngine, name: "GetAlive" , func&: FnGetAlive); |
| 6743 | AddFunc(owner: pEngine, name: "GetDamage" , func&: FnGetDamage); |
| 6744 | AddFunc(owner: pEngine, name: "CrewMember" , func&: FnCrewMember); |
| 6745 | AddFunc(owner: pEngine, name: "ObjectSetAction" , func&: FnObjectSetAction, pub: false); |
| 6746 | AddFunc(owner: pEngine, name: "ComponentAll" , func&: FnComponentAll); |
| 6747 | AddFunc(owner: pEngine, name: "SetComDir" , func&: FnSetComDir); |
| 6748 | AddFunc(owner: pEngine, name: "GetComDir" , func&: FnGetComDir); |
| 6749 | AddFunc(owner: pEngine, name: "SetDir" , func&: FnSetDir); |
| 6750 | AddFunc(owner: pEngine, name: "GetDir" , func&: FnGetDir); |
| 6751 | AddFunc(owner: pEngine, name: "SetEntrance" , func&: FnSetEntrance); |
| 6752 | AddFunc(owner: pEngine, name: "GetEntrance" , func&: FnGetEntrance); |
| 6753 | AddFunc(owner: pEngine, name: "SetCategory" , func&: FnSetCategory); |
| 6754 | AddFunc(owner: pEngine, name: "FinishCommand" , func&: FnFinishCommand); |
| 6755 | AddFunc(owner: pEngine, name: "GetDefinition" , func&: FnGetDefinition); |
| 6756 | AddFunc(owner: pEngine, name: "ActIdle" , func&: FnActIdle); |
| 6757 | AddFunc(owner: pEngine, name: "SetRDir" , func&: FnSetRDir); |
| 6758 | AddFunc(owner: pEngine, name: "GetRDir" , func&: FnGetRDir); |
| 6759 | AddFunc(owner: pEngine, name: "GetXDir" , func&: FnGetXDir); |
| 6760 | AddFunc(owner: pEngine, name: "GetYDir" , func&: FnGetYDir); |
| 6761 | AddFunc(owner: pEngine, name: "GetR" , func&: FnGetR); |
| 6762 | AddFunc(owner: pEngine, name: "GetName" , func&: FnGetName); |
| 6763 | AddFunc(owner: pEngine, name: "SetName" , func&: FnSetName); |
| 6764 | AddFunc(owner: pEngine, name: "GetDesc" , func&: FnGetDesc); |
| 6765 | AddFunc(owner: pEngine, name: "GetPlayerName" , func&: FnGetPlayerName); |
| 6766 | AddFunc(owner: pEngine, name: "GetTaggedPlayerName" , func&: FnGetTaggedPlayerName); |
| 6767 | AddFunc(owner: pEngine, name: "GetPlayerType" , func&: FnGetPlayerType); |
| 6768 | AddFunc(owner: pEngine, name: "SetXDir" , func&: FnSetXDir); |
| 6769 | AddFunc(owner: pEngine, name: "SetYDir" , func&: FnSetYDir); |
| 6770 | AddFunc(owner: pEngine, name: "SetR" , func&: FnSetR); |
| 6771 | AddFunc(owner: pEngine, name: "SetOwner" , func&: FnSetOwner); |
| 6772 | AddFunc(owner: pEngine, name: "CreateObject" , func&: FnCreateObject); |
| 6773 | AddFunc(owner: pEngine, name: "MakeCrewMember" , func&: FnMakeCrewMember); |
| 6774 | AddFunc(owner: pEngine, name: "GrabObjectInfo" , func&: FnGrabObjectInfo); |
| 6775 | AddFunc(owner: pEngine, name: "CreateContents" , func&: FnCreateContents); |
| 6776 | AddFunc(owner: pEngine, name: "ShiftContents" , func&: FnShiftContents); |
| 6777 | AddFunc(owner: pEngine, name: "ComposeContents" , func&: FnComposeContents); |
| 6778 | AddFunc(owner: pEngine, name: "CreateConstruction" , func&: FnCreateConstruction); |
| 6779 | AddFunc(owner: pEngine, name: "GetID" , func&: FnGetID); |
| 6780 | AddFunc(owner: pEngine, name: "Contents" , func&: FnContents); |
| 6781 | AddFunc(owner: pEngine, name: "ScrollContents" , func&: FnScrollContents); |
| 6782 | AddFunc(owner: pEngine, name: "Contained" , func&: FnContained); |
| 6783 | AddFunc(owner: pEngine, name: "ContentsCount" , func&: FnContentsCount); |
| 6784 | AddFunc(owner: pEngine, name: "FindContents" , func&: FnFindContents); |
| 6785 | AddFunc(owner: pEngine, name: "FindConstructionSite" , func&: FnFindConstructionSite); |
| 6786 | AddFunc(owner: pEngine, name: "FindOtherContents" , func&: FnFindOtherContents); |
| 6787 | AddFunc(owner: pEngine, name: "FindBase" , func&: FnFindBase); |
| 6788 | AddFunc(owner: pEngine, name: "Sound" , func&: FnSound); |
| 6789 | AddFunc(owner: pEngine, name: "Music" , func&: FnMusic); |
| 6790 | AddFunc(owner: pEngine, name: "MusicLevel" , func&: FnMusicLevel); |
| 6791 | AddFunc(owner: pEngine, name: "SetPlayList" , func&: FnSetPlayList); |
| 6792 | AddFunc(owner: pEngine, name: "SoundLevel" , func&: FnSoundLevel, pub: false); |
| 6793 | AddFunc(owner: pEngine, name: "FindObjectOwner" , func&: FnFindObjectOwner); |
| 6794 | AddFunc(owner: pEngine, name: "RemoveObject" , func&: FnRemoveObject); |
| 6795 | AddFunc(owner: pEngine, name: "GetActionTarget" , func&: FnGetActionTarget); |
| 6796 | AddFunc(owner: pEngine, name: "SetActionTargets" , func&: FnSetActionTargets); |
| 6797 | AddFunc(owner: pEngine, name: "SetPlrView" , func&: FnSetPlrView); |
| 6798 | AddFunc(owner: pEngine, name: "SetPlrKnowledge" , func&: FnSetPlrKnowledge); |
| 6799 | AddFunc(owner: pEngine, name: "SetPlrMagic" , func&: FnSetPlrMagic); |
| 6800 | AddFunc(owner: pEngine, name: "GetPlrDownDouble" , func&: FnGetPlrDownDouble); |
| 6801 | AddFunc(owner: pEngine, name: "ClearLastPlrCom" , func&: FnClearLastPlrCom); |
| 6802 | AddFunc(owner: pEngine, name: "GetPlrViewMode" , func&: FnGetPlrViewMode); |
| 6803 | AddFunc(owner: pEngine, name: "GetPlrView" , func&: FnGetPlrView); |
| 6804 | AddFunc(owner: pEngine, name: "GetWealth" , func&: FnGetWealth); |
| 6805 | AddFunc(owner: pEngine, name: "SetWealth" , func&: FnSetWealth); |
| 6806 | AddFunc(owner: pEngine, name: "SetComponent" , func&: FnSetComponent); |
| 6807 | AddFunc(owner: pEngine, name: "DoScore" , func&: FnDoScore); |
| 6808 | AddFunc(owner: pEngine, name: "GetScore" , func&: FnGetScore); |
| 6809 | AddFunc(owner: pEngine, name: "GetPlrValue" , func&: FnGetPlrValue); |
| 6810 | AddFunc(owner: pEngine, name: "GetPlrValueGain" , func&: FnGetPlrValueGain); |
| 6811 | AddFunc(owner: pEngine, name: "SetPlrShowControl" , func&: FnSetPlrShowControl); |
| 6812 | AddFunc(owner: pEngine, name: "SetPlrShowControlPos" , func&: FnSetPlrShowControlPos); |
| 6813 | AddFunc(owner: pEngine, name: "GetPlrControlName" , func&: FnGetPlrControlName); |
| 6814 | AddFunc(owner: pEngine, name: "GetPlrJumpAndRunControl" , func&: FnGetPlrJumpAndRunControl); |
| 6815 | AddFunc(owner: pEngine, name: "SetPlrShowCommand" , func&: FnSetPlrShowCommand); |
| 6816 | AddFunc(owner: pEngine, name: "GetWind" , func&: FnGetWind); |
| 6817 | AddFunc(owner: pEngine, name: "SetWind" , func&: FnSetWind); |
| 6818 | AddFunc(owner: pEngine, name: "SetSkyFade" , func&: FnSetSkyFade); |
| 6819 | AddFunc(owner: pEngine, name: "SetSkyColor" , func&: FnSetSkyColor); |
| 6820 | AddFunc(owner: pEngine, name: "GetSkyColor" , func&: FnGetSkyColor); |
| 6821 | AddFunc(owner: pEngine, name: "GetTemperature" , func&: FnGetTemperature); |
| 6822 | AddFunc(owner: pEngine, name: "SetTemperature" , func&: FnSetTemperature); |
| 6823 | AddFunc(owner: pEngine, name: "LaunchLightning" , func&: FnLaunchLightning); |
| 6824 | AddFunc(owner: pEngine, name: "LaunchVolcano" , func&: FnLaunchVolcano); |
| 6825 | AddFunc(owner: pEngine, name: "LaunchEarthquake" , func&: FnLaunchEarthquake); |
| 6826 | AddFunc(owner: pEngine, name: "ShakeFree" , func&: FnShakeFree); |
| 6827 | AddFunc(owner: pEngine, name: "ShakeObjects" , func&: FnShakeObjects); |
| 6828 | AddFunc(owner: pEngine, name: "DigFree" , func&: FnDigFree); |
| 6829 | AddFunc(owner: pEngine, name: "FreeRect" , func&: FnFreeRect); |
| 6830 | AddFunc(owner: pEngine, name: "DigFreeRect" , func&: FnDigFreeRect); |
| 6831 | AddFunc(owner: pEngine, name: "CastPXS" , func&: FnCastPXS); |
| 6832 | AddFunc(owner: pEngine, name: "CastObjects" , func&: FnCastObjects); |
| 6833 | AddFunc(owner: pEngine, name: "Hostile" , func&: FnHostile); |
| 6834 | AddFunc(owner: pEngine, name: "SetHostility" , func&: FnSetHostility); |
| 6835 | AddFunc(owner: pEngine, name: "PlaceVegetation" , func&: FnPlaceVegetation); |
| 6836 | AddFunc(owner: pEngine, name: "PlaceAnimal" , func&: FnPlaceAnimal); |
| 6837 | AddFunc(owner: pEngine, name: "GameOver" , func&: FnGameOver); |
| 6838 | AddFunc(owner: pEngine, name: "C4Id" , func&: FnC4Id); |
| 6839 | AddFunc(owner: pEngine, name: "ScriptGo" , func&: FnScriptGo); |
| 6840 | AddFunc(owner: pEngine, name: "GetHiRank" , func&: FnGetHiRank); |
| 6841 | AddFunc(owner: pEngine, name: "GetCrew" , func&: FnGetCrew); |
| 6842 | AddFunc(owner: pEngine, name: "GetCrewCount" , func&: FnGetCrewCount); |
| 6843 | AddFunc(owner: pEngine, name: "GetPlayerCount" , func&: FnGetPlayerCount); |
| 6844 | AddFunc(owner: pEngine, name: "GetPlayerByIndex" , func&: FnGetPlayerByIndex); |
| 6845 | AddFunc(owner: pEngine, name: "EliminatePlayer" , func&: FnEliminatePlayer); |
| 6846 | AddFunc(owner: pEngine, name: "SurrenderPlayer" , func&: FnSurrenderPlayer); |
| 6847 | AddFunc(owner: pEngine, name: "SetLeaguePerformance" , func&: FnSetLeaguePerformance); |
| 6848 | AddFunc(owner: pEngine, name: "SetLeagueProgressData" , func&: FnSetLeagueProgressData); |
| 6849 | AddFunc(owner: pEngine, name: "GetLeagueProgressData" , func&: FnGetLeagueProgressData); |
| 6850 | AddFunc(owner: pEngine, name: "CreateScriptPlayer" , func&: FnCreateScriptPlayer); |
| 6851 | AddFunc(owner: pEngine, name: "GetCursor" , func&: FnGetCursor); |
| 6852 | AddFunc(owner: pEngine, name: "GetViewCursor" , func&: FnGetViewCursor); |
| 6853 | AddFunc(owner: pEngine, name: "GetCaptain" , func&: FnGetCaptain); |
| 6854 | AddFunc(owner: pEngine, name: "SetCursor" , func&: FnSetCursor); |
| 6855 | AddFunc(owner: pEngine, name: "SetViewCursor" , func&: FnSetViewCursor); |
| 6856 | AddFunc(owner: pEngine, name: "SelectCrew" , func&: FnSelectCrew); |
| 6857 | AddFunc(owner: pEngine, name: "GetSelectCount" , func&: FnGetSelectCount); |
| 6858 | AddFunc(owner: pEngine, name: "SetCrewStatus" , func&: FnSetCrewStatus, pub: false); |
| 6859 | AddFunc(owner: pEngine, name: "SetPosition" , func&: FnSetPosition); |
| 6860 | AddFunc(owner: pEngine, name: "ExtractLiquid" , func&: FnExtractLiquid); |
| 6861 | AddFunc(owner: pEngine, name: "GetMaterial" , func&: FnGetMaterial); |
| 6862 | AddFunc(owner: pEngine, name: "GetTexture" , func&: FnGetTexture); |
| 6863 | AddFunc(owner: pEngine, name: "GetMaterialCount" , func&: FnGetMaterialCount); |
| 6864 | AddFunc(owner: pEngine, name: "GBackSolid" , func&: FnGBackSolid); |
| 6865 | AddFunc(owner: pEngine, name: "GBackSemiSolid" , func&: FnGBackSemiSolid); |
| 6866 | AddFunc(owner: pEngine, name: "GBackLiquid" , func&: FnGBackLiquid); |
| 6867 | AddFunc(owner: pEngine, name: "GBackSky" , func&: FnGBackSky); |
| 6868 | AddFunc(owner: pEngine, name: "Material" , func&: FnMaterial); |
| 6869 | AddFunc(owner: pEngine, name: "BlastObjects" , func&: FnBlastObjects); |
| 6870 | AddFunc(owner: pEngine, name: "BlastObject" , func&: FnBlastObject); |
| 6871 | AddFunc(owner: pEngine, name: "BlastFree" , func&: FnBlastFree); |
| 6872 | AddFunc(owner: pEngine, name: "InsertMaterial" , func&: FnInsertMaterial); |
| 6873 | AddFunc(owner: pEngine, name: "DrawVolcanoBranch" , func&: FnDrawVolcanoBranch, pub: false); |
| 6874 | AddFunc(owner: pEngine, name: "FlameConsumeMaterial" , func&: FnFlameConsumeMaterial, pub: false); |
| 6875 | AddFunc(owner: pEngine, name: "LandscapeWidth" , func&: FnLandscapeWidth); |
| 6876 | AddFunc(owner: pEngine, name: "LandscapeHeight" , func&: FnLandscapeHeight); |
| 6877 | AddFunc(owner: pEngine, name: "Resort" , func&: FnResort); |
| 6878 | AddFunc(owner: pEngine, name: "CreateMenu" , func&: FnCreateMenu); |
| 6879 | AddFunc(owner: pEngine, name: "SelectMenuItem" , func&: FnSelectMenuItem); |
| 6880 | AddFunc(owner: pEngine, name: "SetMenuDecoration" , func&: FnSetMenuDecoration); |
| 6881 | AddFunc(owner: pEngine, name: "SetMenuTextProgress" , func&: FnSetMenuTextProgress); |
| 6882 | AddFunc(owner: pEngine, name: "SetSeason" , func&: FnSetSeason); |
| 6883 | AddFunc(owner: pEngine, name: "GetSeason" , func&: FnGetSeason); |
| 6884 | AddFunc(owner: pEngine, name: "SetClimate" , func&: FnSetClimate); |
| 6885 | AddFunc(owner: pEngine, name: "GetClimate" , func&: FnGetClimate); |
| 6886 | AddFunc(owner: pEngine, name: "Distance" , func&: FnDistance); |
| 6887 | AddFunc(owner: pEngine, name: "ObjectDistance" , func&: FnObjectDistance); |
| 6888 | AddFunc(owner: pEngine, name: "GetValue" , func&: FnGetValue); |
| 6889 | AddFunc(owner: pEngine, name: "GetRank" , func&: FnGetRank); |
| 6890 | AddFunc(owner: pEngine, name: "Value" , func&: FnValue); |
| 6891 | AddFunc(owner: pEngine, name: "Angle" , func&: FnAngle); |
| 6892 | AddFunc(owner: pEngine, name: "DoHomebaseMaterial" , func&: FnDoHomebaseMaterial); |
| 6893 | AddFunc(owner: pEngine, name: "DoHomebaseProduction" , func&: FnDoHomebaseProduction); |
| 6894 | AddFunc(owner: pEngine, name: "GainMissionAccess" , func&: FnGainMissionAccess); |
| 6895 | AddFunc(owner: pEngine, name: "SetPhysical" , func&: FnSetPhysical); |
| 6896 | AddFunc(owner: pEngine, name: "TrainPhysical" , func&: FnTrainPhysical); |
| 6897 | AddFunc(owner: pEngine, name: "GetPhysical" , func&: FnGetPhysical); |
| 6898 | AddFunc(owner: pEngine, name: "ResetPhysical" , func&: FnResetPhysical); |
| 6899 | AddFunc(owner: pEngine, name: "SetTransferZone" , func&: FnSetTransferZone); |
| 6900 | AddFunc(owner: pEngine, name: "IsNetwork" , func&: FnIsNetwork); |
| 6901 | AddFunc(owner: pEngine, name: "GetLeague" , func&: FnGetLeague); |
| 6902 | AddFunc(owner: pEngine, name: "TestMessageBoard" , func&: FnTestMessageBoard, pub: false); |
| 6903 | AddFunc(owner: pEngine, name: "CallMessageBoard" , func&: FnCallMessageBoard, pub: false); |
| 6904 | AddFunc(owner: pEngine, name: "AbortMessageBoard" , func&: FnAbortMessageBoard, pub: false); |
| 6905 | AddFunc(owner: pEngine, name: "OnMessageBoardAnswer" , func&: FnOnMessageBoardAnswer, pub: false); |
| 6906 | AddFunc(owner: pEngine, name: "ScriptCounter" , func&: FnScriptCounter); |
| 6907 | AddFunc(owner: pEngine, name: "SetMass" , func&: FnSetMass); |
| 6908 | AddFunc(owner: pEngine, name: "GetColor" , func&: FnGetColor); |
| 6909 | AddFunc(owner: pEngine, name: "SetColor" , func&: FnSetColor); |
| 6910 | AddFunc(owner: pEngine, name: "SetFoW" , func&: FnSetFoW); |
| 6911 | AddFunc(owner: pEngine, name: "SetPlrViewRange" , func&: FnSetPlrViewRange); |
| 6912 | AddFunc(owner: pEngine, name: "GetMaxPlayer" , func&: FnGetMaxPlayer); |
| 6913 | AddFunc(owner: pEngine, name: "SetMaxPlayer" , func&: FnSetMaxPlayer); |
| 6914 | AddFunc(owner: pEngine, name: "SetPicture" , func&: FnSetPicture); |
| 6915 | AddFunc(owner: pEngine, name: "Buy" , func&: FnBuy); |
| 6916 | AddFunc(owner: pEngine, name: "Sell" , func&: FnSell); |
| 6917 | AddFunc(owner: pEngine, name: "GetProcedure" , func&: FnGetProcedure); |
| 6918 | AddFunc(owner: pEngine, name: "GetChar" , func&: FnGetChar); |
| 6919 | AddFunc(owner: pEngine, name: "ActivateGameGoalMenu" , func&: FnActivateGameGoalMenu); |
| 6920 | AddFunc(owner: pEngine, name: "SetGraphics" , func&: FnSetGraphics); |
| 6921 | AddFunc(owner: pEngine, name: "Object" , func&: FnObject); |
| 6922 | AddFunc(owner: pEngine, name: "ObjectNumber" , func&: FnObjectNumber); |
| 6923 | AddFunc(owner: pEngine, name: "ShowInfo" , func&: FnShowInfo); |
| 6924 | AddFunc(owner: pEngine, name: "GetTime" , func&: FnGetTime); |
| 6925 | AddFunc(owner: pEngine, name: "GetSystemTime" , func&: FnGetSystemTime, pub: false); |
| 6926 | AddFunc(owner: pEngine, name: "SetVisibility" , func&: FnSetVisibility); |
| 6927 | AddFunc(owner: pEngine, name: "GetVisibility" , func&: FnGetVisibility); |
| 6928 | AddFunc(owner: pEngine, name: "SetClrModulation" , func&: FnSetClrModulation); |
| 6929 | AddFunc(owner: pEngine, name: "GetClrModulation" , func&: FnGetClrModulation); |
| 6930 | AddFunc(owner: pEngine, name: "GetMissionAccess" , func&: FnGetMissionAccess); |
| 6931 | AddFunc(owner: pEngine, name: "CloseMenu" , func&: FnCloseMenu); |
| 6932 | AddFunc(owner: pEngine, name: "GetMenuSelection" , func&: FnGetMenuSelection); |
| 6933 | AddFunc(owner: pEngine, name: "ResortObjects" , func&: FnResortObjects); |
| 6934 | AddFunc(owner: pEngine, name: "ResortObject" , func&: FnResortObject); |
| 6935 | AddFunc(owner: pEngine, name: "GetDefBottom" , func&: FnGetDefBottom); |
| 6936 | AddFunc(owner: pEngine, name: "SetMaterialColor" , func&: FnSetMaterialColor); |
| 6937 | AddFunc(owner: pEngine, name: "GetMaterialColor" , func&: FnGetMaterialColor); |
| 6938 | AddFunc(owner: pEngine, name: "MaterialName" , func&: FnMaterialName); |
| 6939 | AddFunc(owner: pEngine, name: "SetMenuSize" , func&: FnSetMenuSize); |
| 6940 | AddFunc(owner: pEngine, name: "GetNeededMatStr" , func&: FnGetNeededMatStr); |
| 6941 | AddFunc(owner: pEngine, name: "GetCrewEnabled" , func&: FnGetCrewEnabled); |
| 6942 | AddFunc(owner: pEngine, name: "SetCrewEnabled" , func&: FnSetCrewEnabled); |
| 6943 | AddFunc(owner: pEngine, name: "UnselectCrew" , func&: FnUnselectCrew); |
| 6944 | AddFunc(owner: pEngine, name: "DrawMap" , func&: FnDrawMap); |
| 6945 | AddFunc(owner: pEngine, name: "DrawDefMap" , func&: FnDrawDefMap); |
| 6946 | AddFunc(owner: pEngine, name: "CreateParticle" , func&: FnCreateParticle); |
| 6947 | AddFunc(owner: pEngine, name: "CastParticles" , func&: FnCastParticles); |
| 6948 | AddFunc(owner: pEngine, name: "CastBackParticles" , func&: FnCastBackParticles); |
| 6949 | AddFunc(owner: pEngine, name: "PushParticles" , func&: FnPushParticles); |
| 6950 | AddFunc(owner: pEngine, name: "ClearParticles" , func&: FnClearParticles); |
| 6951 | AddFunc(owner: pEngine, name: "IsNewgfx" , func&: FnIsNewgfx, pub: false); |
| 6952 | AddFunc(owner: pEngine, name: "SetSkyAdjust" , func&: FnSetSkyAdjust); |
| 6953 | AddFunc(owner: pEngine, name: "SetMatAdjust" , func&: FnSetMatAdjust); |
| 6954 | AddFunc(owner: pEngine, name: "GetSkyAdjust" , func&: FnGetSkyAdjust); |
| 6955 | AddFunc(owner: pEngine, name: "GetMatAdjust" , func&: FnGetMatAdjust); |
| 6956 | AddFunc(owner: pEngine, name: "SetSkyParallax" , func&: FnSetSkyParallax); |
| 6957 | AddFunc(owner: pEngine, name: "DoCrewExp" , func&: FnDoCrewExp); |
| 6958 | AddFunc(owner: pEngine, name: "ReloadDef" , func&: FnReloadDef); |
| 6959 | AddFunc(owner: pEngine, name: "ReloadParticle" , func&: FnReloadParticle); |
| 6960 | AddFunc(owner: pEngine, name: "SetGamma" , func&: FnSetGamma); |
| 6961 | AddFunc(owner: pEngine, name: "ResetGamma" , func&: FnResetGamma); |
| 6962 | AddFunc(owner: pEngine, name: "FrameCounter" , func&: FnFrameCounter); |
| 6963 | AddFunc(owner: pEngine, name: "SetLandscapePixel" , func&: FnSetLandscapePixel); |
| 6964 | AddFunc(owner: pEngine, name: "SetObjectOrder" , func&: FnSetObjectOrder); |
| 6965 | AddFunc(owner: pEngine, name: "SetColorDw" , func&: FnSetColorDw); |
| 6966 | AddFunc(owner: pEngine, name: "GetColorDw" , func&: FnGetColorDw); |
| 6967 | AddFunc(owner: pEngine, name: "GetPlrColorDw" , func&: FnGetPlrColorDw); |
| 6968 | AddFunc(owner: pEngine, name: "DrawMaterialQuad" , func&: FnDrawMaterialQuad); |
| 6969 | AddFunc(owner: pEngine, name: "FightWith" , func&: FnFightWith); |
| 6970 | AddFunc(owner: pEngine, name: "SetFilmView" , func&: FnSetFilmView); |
| 6971 | AddFunc(owner: pEngine, name: "ClearMenuItems" , func&: FnClearMenuItems); |
| 6972 | AddFunc(owner: pEngine, name: "GetObjectLayer" , func&: FnGetObjectLayer, pub: false); |
| 6973 | AddFunc(owner: pEngine, name: "SetObjectLayer" , func&: FnSetObjectLayer, pub: false); |
| 6974 | AddFunc(owner: pEngine, name: "SetShape" , func&: FnSetShape); |
| 6975 | AddFunc(owner: pEngine, name: "AddMsgBoardCmd" , func&: FnAddMsgBoardCmd); |
| 6976 | AddFunc(owner: pEngine, name: "SetGameSpeed" , func&: FnSetGameSpeed, pub: false); |
| 6977 | AddFunc(owner: pEngine, name: "DrawMatChunks" , func&: FnDrawMatChunks, pub: false); |
| 6978 | AddFunc(owner: pEngine, name: "GetPath" , func&: FnGetPath); |
| 6979 | AddFunc(owner: pEngine, name: "SetTextureIndex" , func&: FnSetTextureIndex, pub: false); |
| 6980 | AddFunc(owner: pEngine, name: "RemoveUnusedTexMapEntries" , func&: FnRemoveUnusedTexMapEntries, pub: false); |
| 6981 | AddFunc(owner: pEngine, name: "SetObjDrawTransform" , func&: FnSetObjDrawTransform); |
| 6982 | AddFunc(owner: pEngine, name: "SetObjDrawTransform2" , func&: FnSetObjDrawTransform2, pub: false); |
| 6983 | AddFunc(owner: pEngine, name: "SetPortrait" , func&: FnSetPortrait); |
| 6984 | AddFunc(owner: pEngine, name: "LoadScenarioSection" , func&: FnLoadScenarioSection, pub: false); |
| 6985 | AddFunc(owner: pEngine, name: "SetObjectStatus" , func&: FnSetObjectStatus, pub: false); |
| 6986 | AddFunc(owner: pEngine, name: "GetObjectStatus" , func&: FnGetObjectStatus, pub: false); |
| 6987 | AddFunc(owner: pEngine, name: "AdjustWalkRotation" , func&: FnAdjustWalkRotation, pub: false); |
| 6988 | AddFunc(owner: pEngine, name: "FxFireStart" , func&: FnFxFireStart, pub: false); |
| 6989 | AddFunc(owner: pEngine, name: "FxFireTimer" , func&: FnFxFireTimer, pub: false); |
| 6990 | AddFunc(owner: pEngine, name: "FxFireStop" , func&: FnFxFireStop, pub: false); |
| 6991 | AddFunc(owner: pEngine, name: "FxFireInfo" , func&: FnFxFireInfo, pub: false); |
| 6992 | AddFunc(owner: pEngine, name: "RemoveEffect" , func&: FnRemoveEffect); |
| 6993 | AddFunc(owner: pEngine, name: "ChangeEffect" , func&: FnChangeEffect); |
| 6994 | AddFunc(owner: pEngine, name: "ModulateColor" , func&: FnModulateColor); |
| 6995 | AddFunc(owner: pEngine, name: "WildcardMatch" , func&: FnWildcardMatch); |
| 6996 | AddFunc(owner: pEngine, name: "GetContact" , func&: FnGetContact); |
| 6997 | AddFunc(owner: pEngine, name: "SetObjectBlitMode" , func&: FnSetObjectBlitMode); |
| 6998 | AddFunc(owner: pEngine, name: "GetObjectBlitMode" , func&: FnGetObjectBlitMode); |
| 6999 | AddFunc(owner: pEngine, name: "SetViewOffset" , func&: FnSetViewOffset); |
| 7000 | AddFunc(owner: pEngine, name: "SetPreSend" , func&: FnSetPreSend, pub: false); |
| 7001 | AddFunc(owner: pEngine, name: "GetPlayerID" , func&: FnGetPlayerID, pub: false); |
| 7002 | AddFunc(owner: pEngine, name: "GetPlayerTeam" , func&: FnGetPlayerTeam); |
| 7003 | AddFunc(owner: pEngine, name: "SetPlayerTeam" , func&: FnSetPlayerTeam); |
| 7004 | AddFunc(owner: pEngine, name: "GetTeamConfig" , func&: FnGetTeamConfig); |
| 7005 | AddFunc(owner: pEngine, name: "GetTeamName" , func&: FnGetTeamName); |
| 7006 | AddFunc(owner: pEngine, name: "GetTeamColor" , func&: FnGetTeamColor); |
| 7007 | AddFunc(owner: pEngine, name: "GetTeamByIndex" , func&: FnGetTeamByIndex); |
| 7008 | AddFunc(owner: pEngine, name: "GetTeamCount" , func&: FnGetTeamCount); |
| 7009 | AddFunc(owner: pEngine, name: "InitScenarioPlayer" , func&: FnInitScenarioPlayer, pub: false); |
| 7010 | AddFunc(owner: pEngine, PSF_OnOwnerRemoved, func&: FnOnOwnerRemoved, pub: false); |
| 7011 | AddFunc(owner: pEngine, name: "SetScoreboardData" , func&: FnSetScoreboardData, pub: false); |
| 7012 | AddFunc(owner: pEngine, name: "GetScoreboardString" , func&: FnGetScoreboardString, pub: false); |
| 7013 | AddFunc(owner: pEngine, name: "GetScoreboardData" , func&: FnGetScoreboardData, pub: false); |
| 7014 | AddFunc(owner: pEngine, name: "DoScoreboardShow" , func&: FnDoScoreboardShow, pub: false); |
| 7015 | AddFunc(owner: pEngine, name: "SortScoreboard" , func&: FnSortScoreboard, pub: false); |
| 7016 | AddFunc(owner: pEngine, name: "AddEvaluationData" , func&: FnAddEvaluationData, pub: false); |
| 7017 | AddFunc(owner: pEngine, name: "GetLeagueScore" , func&: FnGetLeagueScore, pub: false); |
| 7018 | AddFunc(owner: pEngine, name: "HideSettlementScoreInEvaluation" , func&: FnHideSettlementScoreInEvaluation, pub: false); |
| 7019 | AddFunc(owner: pEngine, name: "GetUnusedOverlayID" , func&: FnGetUnusedOverlayID, pub: false); |
| 7020 | AddFunc(owner: pEngine, name: "FatalError" , func&: FnFatalError, pub: false); |
| 7021 | AddFunc(owner: pEngine, name: "ExtractMaterialAmount" , func&: FnExtractMaterialAmount); |
| 7022 | AddFunc(owner: pEngine, name: "GetEffectCount" , func&: FnGetEffectCount); |
| 7023 | AddFunc(owner: pEngine, name: "StartCallTrace" , func&: FnStartCallTrace); |
| 7024 | AddFunc(owner: pEngine, name: "StartScriptProfiler" , func&: FnStartScriptProfiler); |
| 7025 | AddFunc(owner: pEngine, name: "StopScriptProfiler" , func&: FnStopScriptProfiler); |
| 7026 | AddFunc(owner: pEngine, name: "CustomMessage" , func&: FnCustomMessage); |
| 7027 | AddFunc(owner: pEngine, name: "PauseGame" , func&: FnPauseGame); |
| 7028 | AddFunc(owner: pEngine, name: "ExecuteCommand" , func&: FnExecuteCommand); |
| 7029 | AddFunc(owner: pEngine, name: "LocateFunc" , func&: FnLocateFunc); |
| 7030 | AddFunc(owner: pEngine, name: "PathFree" , func&: FnPathFree); |
| 7031 | AddFunc(owner: pEngine, name: "PathFree2" , func&: FnPathFree2); |
| 7032 | AddFunc(owner: pEngine, name: "SetNextMission" , func&: FnSetNextMission); |
| 7033 | AddFunc(owner: pEngine, name: "GetKeys" , func&: FnGetKeys); |
| 7034 | AddFunc(owner: pEngine, name: "GetValues" , func&: FnGetValues); |
| 7035 | AddFunc(owner: pEngine, name: "SetRestoreInfos" , func&: FnSetRestoreInfos); |
| 7036 | new C4AulDefCastFunc<C4V_C4ID, C4V_Int>{pEngine, "ScoreboardCol" }; |
| 7037 | new C4AulDefCastFunc<C4V_Any, C4V_Int>{pEngine, "CastInt" }; |
| 7038 | new C4AulDefCastFunc<C4V_Any, C4V_Bool>{pEngine, "CastBool" }; |
| 7039 | new C4AulDefCastFunc<C4V_Any, C4V_C4ID>{pEngine, "CastC4ID" }; |
| 7040 | new C4AulDefCastFunc<C4V_Any, C4V_Any>{pEngine, "CastAny" }; |
| 7041 | |
| 7042 | new C4AulEngineFuncParArray<10, C4V_C4Object>{pEngine, "FindObject2" , FnFindObject2, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array}; |
| 7043 | new C4AulEngineFuncParArray<10, C4V_Array> {pEngine, "FindObjects" , FnFindObjects, C4V_Array, C4V_Any, C4V_Any, C4V_Any, C4V_Any, C4V_Any, C4V_Any, C4V_Any, C4V_Any, C4V_Any}; |
| 7044 | new C4AulEngineFuncParArray<10, C4V_Int> {pEngine, "ObjectCount2" , FnObjectCount2, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array, C4V_Array}; |
| 7045 | } |
| 7046 | |