mahlendur/_work/Data/Scripts/Content/Misc/Wld_StopEffect.d
Daniel Heße 892a40ff0f Initial commit with Subversion-codebase from 13/05/2022.
Cleaned up the mess, at this time, only viable data get synced (_work directory for Gothic-data, miranda for mdc-scripts.
Need to symlink files to a working directory.
2022-05-13 17:38:52 +02:00

176 lines
No EOL
7.2 KiB
D

// Extended functionality for Wld_StopEffect()
// See https://forum.worldofplayers.de/forum/threads/1495001-Scriptsammlung-ScriptBin?p=25548652&viewfull=1#post25548652
// Made by mud-freak (@szapp) 2017-08-05 (modified 2017-08-09)
//
// Compatible with Gothic 1 and Gothic 2
// Requirements: Ikarus 1.2
/*
* Emulate the Gothic 2 external function Wld_StopEffect(), with additional settings: Usually it is not clear which
* effect will be stopped, leading to effects getting "stuck". Here, Wld_StopEffect is extended with additional checks
* for origin and/or target vob and whether to stop all matching FX or only the first one found (like in Wld_StopEffect)
* The function returns the number of stopped effects, or zero if none was found or an error occurred.
* Compatible with Gothic 1 and Gothic 2. This means there is finally the possibility to stop effects in Gothic 1!
*
* Examples:
* var C_NPC Diego; Diego = Hlp_GetNpc(PC_ThiefOW);
* Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, Diego, 2, 150, DAM_FIRE, TRUE);
* Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, hero, 2, 150, DAM_FIRE, TRUE);
* Wld_StopEffect_Ext("SPELLFX_SLEEPER_FIREBALL", 0, Diego, 0); // Stops only the first effect
*
* Calling Wld_StopEffect("EFFECT_1") corresponds to Wld_StopEffect_Ext("EFFECT_1", 0, 0, 0).
*
* Big parts if this function are taken from Wld_StopEffect. Gothic 2: sub_006E32B0() 0x6E32B0
*/
func int Wld_StopEffect_Ext(var string effectName, var int originInst, var int targetInst, var int all) {
// Gothic 1 addresses and offsets
const int zCVob__classDef_G1 = 9269976; //0x8D72D8
const int zCWorld__SearchVobListByClass_G1 = 6249792; //0x5F5D40
const int oCVisualFX__classDef_G1 = 8822272; //0x869E00
const int oCVisualFX__Stop_G1 = 4766512; //0x48BB30
const int oCVisualFX_originVob_offset_G1 = 1112; //0x0458
const int oCVisualFX_targetVob_offset_G1 = 1120; //0x0460
const int oCVisualFX_instanceName_offset_G1 = 1140; //0x0474
// Gothic 2 addresses and offsets
const int zCVob__classDef_G2 = 10106072; //0x9A34D8
const int zCWorld__SearchVobListByClass_G2 = 6439504; //0x624250
const int oCVisualFX__classDef_G2 = 9234008; //0x8CE658
const int oCVisualFX__Stop_G2 = 4799456; //0x493BE0
const int oCVisualFX_originVob_offset_G2 = 1192; //0x04A8
const int oCVisualFX_targetVob_offset_G2 = 1200; //0x04B0
const int oCVisualFX_instanceName_offset_G2 = 1220; //0x04C4
var int zCVob__classDef;
var int zCWorld__SearchVobListByClass;
var int oCVisualFX__classDef;
var int oCVisualFX__Stop;
var int oCVisualFX_originVob_offset;
var int oCVisualFX_targetVob_offset;
var int oCVisualFX_instanceName_offset;
zCVob__classDef = MEMINT_SwitchG1G2(zCVob__classDef_G1,
zCVob__classDef_G2);
zCWorld__SearchVobListByClass = MEMINT_SwitchG1G2(zCWorld__SearchVobListByClass_G1,
zCWorld__SearchVobListByClass_G2);
oCVisualFX__classDef = MEMINT_SwitchG1G2(oCVisualFX__classDef_G1,
oCVisualFX__classDef_G2);
oCVisualFX__Stop = MEMINT_SwitchG1G2(oCVisualFX__Stop_G1,
oCVisualFX__Stop_G2);
oCVisualFX_originVob_offset = MEMINT_SwitchG1G2(oCVisualFX_originVob_offset_G1,
oCVisualFX_originVob_offset_G2);
oCVisualFX_targetVob_offset = MEMINT_SwitchG1G2(oCVisualFX_targetVob_offset_G1,
oCVisualFX_targetVob_offset_G2);
oCVisualFX_instanceName_offset = MEMINT_SwitchG1G2(oCVisualFX_instanceName_offset_G1,
oCVisualFX_instanceName_offset_G2);
var int worldPtr; worldPtr = _@(MEM_World);
if (!worldPtr) {
return 0;
};
// Create array from all oCVisualFX vobs
var int vobArrayPtr; vobArrayPtr = MEM_ArrayCreate();
var zCArray vobArray; vobArray = _^(vobArrayPtr);
const int call = 0; var int zero;
if (CALL_Begin(call)) {
CALL_PtrParam(_@(zero)); // Vob tree (0 == globalVobTree)
CALL_PtrParam(_@(vobArrayPtr)); // Array to store found vobs in
CALL_PtrParam(_@(oCVisualFX__classDef)); // Class definition
CALL__thiscall(_@(worldPtr), zCWorld__SearchVobListByClass);
call = CALL_End();
};
if (!vobArray.numInArray) {
MEM_ArrayFree(vobArrayPtr);
return 0;
};
effectName = STR_Upper(effectName);
var zCPar_Symbol symb;
// Validate origin vob instance
if (originInst) {
// Get pointer from instance symbol
if (originInst > 0) && (originInst < MEM_Parser.symtab_table_numInArray) {
symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, originInst));
originInst = symb.offset;
} else {
originInst = 0;
};
if (!objCheckInheritance(originInst, zCVob__classDef)) {
MEM_Warn("Wld_StopEffect_Ext: Origin is not a valid vob");
return 0;
};
};
// Validate target vob instance
if (targetInst) {
// Get pointer from instance symbol
if (targetInst > 0) && (targetInst < MEM_Parser.symtab_table_numInArray) {
symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, targetInst));
targetInst = symb.offset;
} else {
targetInst = 0;
};
if (!objCheckInheritance(targetInst, zCVob__classDef)) {
MEM_Warn("Wld_StopEffect_Ext: Target is not a valid vob");
return 0;
};
};
// Search all vobs for the matching name
var int stopped; stopped = 0; // Number of FX stopped
repeat(i, vobArray.numInArray); var int i;
var int vobPtr; vobPtr = MEM_ArrayRead(vobArrayPtr, i);
if (!vobPtr) {
continue;
};
// Search for FX with matching name
if (!Hlp_StrCmp(effectName, "")) {
var string effectInst; effectInst = MEM_ReadString(vobPtr+oCVisualFX_instanceName_offset);
if (!Hlp_StrCmp(effectInst, effectName)) {
continue;
};
};
// Search for a specific origin vob
if (originInst) {
var int originVob; originVob = MEM_ReadInt(vobPtr+oCVisualFX_originVob_offset);
if (originVob != originInst) {
continue;
};
};
// Search for a specific target vob
if (targetInst) {
var int targetVob; targetVob = MEM_ReadInt(vobPtr+oCVisualFX_targetVob_offset);
if (targetVob != targetInst) {
continue;
};
};
// Stop the oCVisualFX
const int call2 = 0; const int one = 1;
if (CALL_Begin(call2)) {
CALL_PtrParam(_@(one));
CALL__thiscall(_@(vobPtr), oCVisualFX__Stop);
call2 = CALL_End();
};
stopped += 1;
if (!all) {
break;
};
end;
MEM_ArrayFree(vobArrayPtr);
return stopped;
};