| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design) |
| 5 | * Copyright (c) 2017-2022, The LegacyClonk Team and contributors |
| 6 | * |
| 7 | * Distributed under the terms of the ISC license; see accompanying file |
| 8 | * "COPYING" for details. |
| 9 | * |
| 10 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 11 | * See accompanying file "TRADEMARK" for details. |
| 12 | * |
| 13 | * To redistribute this file separately, substitute the full license texts |
| 14 | * for the above references. |
| 15 | */ |
| 16 | |
| 17 | // C4AulFun-based effects assigned to an object |
| 18 | // an effect itself only supplies the callback mechanism for effects assigned to objects |
| 19 | // the effect itself supplies the callback mechanism for creation, destruction, timers |
| 20 | // and overlapped effects |
| 21 | /* Also contains some helper functions for various landscape effects */ |
| 22 | |
| 23 | #pragma once |
| 24 | |
| 25 | #include "C4Aul.h" |
| 26 | #include "C4Constants.h" |
| 27 | #include "C4DeletionTrackable.h" |
| 28 | #include "C4EnumeratedObjectPtr.h" |
| 29 | #include "C4ValueList.h" |
| 30 | |
| 31 | typedef unsigned long C4ID; |
| 32 | |
| 33 | // callback return values |
| 34 | #define C4Fx_OK 0 // generic standard behaviour for all effect callbacks |
| 35 | |
| 36 | #define C4Fx_Effect_Deny -1 // delete effect |
| 37 | #define C4Fx_Effect_Annul -2 // delete effect, because it has annulled a countereffect |
| 38 | #define C4Fx_Effect_AnnulCalls -3 // delete effect, because it has annulled a countereffect; temp readd countereffect |
| 39 | |
| 40 | #define C4Fx_Execute_Kill -1 // execute callback: Remove effect now |
| 41 | |
| 42 | #define C4Fx_Stop_Deny -1 // deny effect removal |
| 43 | #define C4Fx_Start_Deny -1 // deny effect start |
| 44 | |
| 45 | // parameters for effect callbacks |
| 46 | #define C4FxCall_Normal 0 // normal call; effect is being added or removed |
| 47 | #define C4FxCall_Temp 1 // temp call; effect is being added or removed in responce to a lower-level effect change |
| 48 | #define C4FxCall_TempAddForRemoval 2 // temp call; effect is being added because it had been temp removed and is now removed forever |
| 49 | #define C4FxCall_RemoveClear 3 // effect is being removed because object is being removed |
| 50 | #define C4FxCall_RemoveDeath 4 // effect is being removed because object died - return -1 to avoid removal |
| 51 | |
| 52 | // damage-callbacks |
| 53 | #define C4FxCall_DmgScript 0 // damage through script call |
| 54 | #define C4FxCall_DmgBlast 1 // damage through blast |
| 55 | #define C4FxCall_DmgFire 2 // damage through fire |
| 56 | #define C4FxCall_DmgChop 3 // damage through chopping |
| 57 | |
| 58 | // energy loss callbacks |
| 59 | #define C4FxCall_EngScript 32 // energy loss through script call |
| 60 | #define C4FxCall_EngBlast 33 // energy loss through blast |
| 61 | #define C4FxCall_EngObjHit 34 // energy loss through object hitting the living |
| 62 | #define C4FxCall_EngFire 35 // energy loss through fire |
| 63 | #define C4FxCall_EngBaseRefresh 36 // energy reload in base (also by base object, but that's normally not called) |
| 64 | #define C4FxCall_EngAsphyxiation 37 // energy loss through asphyxiaction |
| 65 | #define C4FxCall_EngCorrosion 38 // energy loss through corrosion (acid) |
| 66 | #define C4FxCall_EngStruct 39 // regular structure energy loss (normally not called) |
| 67 | #define C4FxCall_EngGetPunched 40 // energy loss during fighting |
| 68 | |
| 69 | // fire drawing modes |
| 70 | #define C4Fx_FireMode_Default 0 // determine mode by category |
| 71 | #define C4Fx_FireMode_LivingVeg 2 // C4D_Living and C4D_StaticBack |
| 72 | #define C4Fx_FireMode_StructVeh 1 // C4D_Structure and C4D_Vehicle |
| 73 | #define C4Fx_FireMode_Object 3 // other (C4D_Object and no bit set (magic)) |
| 74 | #define C4Fx_FireMode_Last 3 // largest valid fire mode |
| 75 | |
| 76 | // generic object effect |
| 77 | class C4Effect : private C4DeletionTrackable |
| 78 | { |
| 79 | public: |
| 80 | char Name[C4MaxDefString + 1]; // name of effect |
| 81 | C4EnumeratedObjectPtr pCommandTarget; // target object for script callbacks - if deleted, the effect is removed without callbacks |
| 82 | C4ID idCommandTarget; // ID of command target definition |
| 83 | |
| 84 | int32_t iPriority; // effect priority for sorting into effect list; -1 indicates a dead effect |
| 85 | C4ValueList EffectVars; // custom effect variables |
| 86 | int32_t iTime, iIntervall; // effect time; effect callback intervall |
| 87 | int32_t iNumber; // effect number for addressing |
| 88 | |
| 89 | C4Effect *pNext; // next effect in linked list |
| 90 | |
| 91 | protected: |
| 92 | // presearched callback functions for faster calling |
| 93 | C4AulFunc *pFnTimer; // timer function Fx%sTimer |
| 94 | C4AulFunc *pFnStart, *pFnStop; // init/deinit-functions Fx%sStart, Fx%sStop |
| 95 | C4AulFunc *pFnEffect; // callback if other effect tries to register |
| 96 | C4AulFunc *pFnDamage; // callback when owned object gets damage |
| 97 | |
| 98 | void AssignCallbackFunctions(); // resolve callback function names |
| 99 | |
| 100 | public: |
| 101 | C4Effect(C4Object *pForObj, const char *szName, int32_t iPrio, int32_t iTimerIntervall, C4Object *pCmdTarget, C4ID idCmdTarget, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4, bool fDoCalls, int32_t &riStoredAsNumber, bool passErrors = false); |
| 102 | C4Effect(StdCompiler *pComp); // ctor: compile |
| 103 | ~C4Effect(); // dtor - deletes all following effects |
| 104 | |
| 105 | void EnumeratePointers(); // object pointers to numbers |
| 106 | void DenumeratePointers(); // numbers to object pointers |
| 107 | void ClearPointers(C4Object *pObj); // clear all pointers to object - may kill some effects w/o callback, because the callback target is lost |
| 108 | |
| 109 | void SetDead() { iPriority = 0; } // mark effect to be removed in next execution cycle |
| 110 | bool IsDead() { return !iPriority; } // return whether effect is to be removed |
| 111 | void FlipActive() { iPriority *= -1; } // alters activation status |
| 112 | bool IsActive() { return iPriority > 0; } // returns whether effect is active |
| 113 | bool IsInactiveAndNotDead() { return iPriority < 0; } // as the name says |
| 114 | |
| 115 | C4Effect *Get(const char *szName, int32_t iIndex = 0, int32_t iMaxPriority = 0); // get effect by name |
| 116 | C4Effect *Get(int32_t iNumber, bool fIncludeDead, int32_t iMaxPriority = 0); // get effect by number |
| 117 | int32_t GetCount(const char *szMask, int32_t iMaxPriority = 0); // count effects that match the mask |
| 118 | int32_t Check(C4Object *pForObj, const char *szCheckEffect, int32_t iPrio, int32_t iTimer, const C4Value &rVal1 = C4VNull, const C4Value &rVal2 = C4VNull, const C4Value &rVal3 = C4VNull, const C4Value &rVal4 = C4VNull, bool passErrors = false); // do some effect callbacks |
| 119 | C4AulScript *GetCallbackScript(); // get script context for effect callbacks |
| 120 | |
| 121 | void Execute(C4Object *pObj); // execute all effects |
| 122 | void Kill(C4Object *pObj); // mark this effect deleted and do approprioate calls |
| 123 | void ClearAll(C4Object *pObj, int32_t iClearFlag); // kill all effects doing removal calls w/o reagard of inactive effects |
| 124 | void DoDamage(C4Object *pObj, int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr); // ask all effects for damage |
| 125 | |
| 126 | C4Value DoCall(C4Object *pObj, const char *szFn, const C4Value &rVal1 = C4VNull, const C4Value &rVal2 = C4VNull, const C4Value &rVal3 = C4VNull, const C4Value &rVal4 = C4VNull, const C4Value &rVal5 = C4VNull, const C4Value &rVal6 = C4VNull, const C4Value &rVal7 = C4VNull, bool passErrors = false, bool convertNilToIntBool = true); // custom call |
| 127 | |
| 128 | void ReAssignCallbackFunctions() |
| 129 | { |
| 130 | AssignCallbackFunctions(); |
| 131 | } |
| 132 | |
| 133 | void ReAssignAllCallbackFunctions() |
| 134 | { |
| 135 | ReAssignCallbackFunctions(); |
| 136 | if (pNext) pNext->ReAssignAllCallbackFunctions(); |
| 137 | } |
| 138 | |
| 139 | void OnObjectChangedDef(C4Object *pObj); |
| 140 | |
| 141 | void CompileFunc(StdCompiler *pComp); |
| 142 | |
| 143 | protected: |
| 144 | void TempRemoveUpperEffects(C4Object *pObj, bool fTempRemoveThis, C4Effect **ppLastRemovedEffect); // temp remove all effects with higher priority |
| 145 | void TempReaddUpperEffects(C4Object *pObj, C4Effect *pLastReaddEffect); // temp remove all effects with higher priority |
| 146 | }; |
| 147 | |
| 148 | // ctor for StdPtrAdapt |
| 149 | inline void CompileNewFunc(C4Effect *&pRes, StdCompiler *pComp) { pRes = new C4Effect(pComp); } |
| 150 | |
| 151 | // fire effect constants |
| 152 | #define MaxFirePhase 15 |
| 153 | #define C4Fx_Fire "Fire" |
| 154 | #define C4Fx_AnyFire "*Fire*" |
| 155 | #define C4Fx_Internal "Int*" |
| 156 | #define C4Fx_FirePriority 100 |
| 157 | #define C4Fx_FireTimer 1 |
| 158 | |
| 159 | // fire effect |
| 160 | int32_t FnFxFireStart(C4AulContext *ctx, C4Object *pObj, int32_t iNumber, int32_t iTemp, int32_t iCausedBy, bool fBlasted, C4Object *pIncineratingObject); |
| 161 | int32_t FnFxFireTimer(C4AulContext *ctx, C4Object *pObj, int32_t iNumber, int32_t iTime); |
| 162 | int32_t FnFxFireStop(C4AulContext *ctx, C4Object *pObj, int32_t iNumber, int32_t iReason, bool fTemp); |
| 163 | C4String *FnFxFireInfo(C4AulContext *ctx, C4Object *pObj, int32_t iNumber); |
| 164 | class C4Value &FxFireVarCausedBy(C4Effect *pEffect); |
| 165 | |
| 166 | // some other hardcoded engine effects |
| 167 | void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj); |
| 168 | void Explosion(int32_t tx, int32_t ty, int32_t level, C4Object *inobj, int32_t iCausedBy, C4Object *pByObj, C4ID idEffect, const char *szEffect); |
| 169 | void Smoke(int32_t tx, int32_t ty, int32_t level, uint32_t dwClr = 0); |
| 170 | void BubbleOut(int32_t tx, int32_t ty); |
| 171 | |