About buff's - i "rewrited" buff's package from LeGo, to similary AST.
Code:
const int BUFF_NORMAL = 0;
const int BUFF_BAD = 1;
const int BUFF_GOOD = 2;
const int Buff_TextureSize = 64;
class CBuff
{
var int Type;
var int ID;
var int EndTime;
var int OldTime;
var int pSelf; // oCNpc*
var int OnApply;
var int OnTick;
var int OnRemove;
var int delay; //
var int Cycles;
};
var int m_arrBuffs; //zCArray<CBuff*>
var int Current_Buff; //CBuff*
func int SAVE_GetFuncID(var func f)
{
var int i; i = MEM_GetUseInstance();
var int res; res = MEM_GetFuncID(f);
MEM_SetUseInstance(i);
return res;
};
func void GetBuffsByNpc(var int Array_Ptr, var c_npc slf)
{
var int InstID; InstID = Hlp_GetInstanceID(slf);
if(!Array_Ptr || !m_arrBuffs)
{
return;
};
var int size; size = MEM_ArraySize(m_arrBuffs);
if(size)
{
var int i; i = 0;
repeat(i, size);
var int ptr; ptr = MEM_ArrayRead(m_arrBuffs, i);
if(Hlp_IsValidHandle(ptr))
{
var CBuff bf; bf = get(ptr);
if(bf.pSelf == InstID)
{
MEM_ArrayInsert(Array_Ptr, ptr);
};
};
end;
};
};
func int Npc_HasBuff(var c_npc slf, var int ID)
{
var int arr; arr = MEM_ArrayCreate();
GetBuffsByNpc(arr, slf);
if(arr)
{
var int size; size = MEM_ArraySize(arr);
if(size)
{
var int i; i = 0;
repeat(i, size);
var int ptr; ptr = MEM_ArrayRead(arr, i);
if(Hlp_IsValidHandle(ptr))
{
var CBuff bf; bf = get(ptr);
if(bf.ID == ID)
{
MEM_ArrayFree(arr);
return true;
};
};
end;
};
};
MEM_ArrayFree(arr);
return false;
};
func void Buff_Apply(var c_npc slf, var int _bf) //Operator new
{
var int InstID; InstID = Hlp_GetInstanceID(slf);
var int ptr; ptr = new(_bf);
var CBuff buff; buff = get(ptr);
buff.pSelf = InstID;
buff.EndTime = Timer();
buff.OldTime = Timer();
if(!m_arrBuffs)
{
m_arrBuffs = MEM_ArrayCreate();
};
if(!m_arrBuffs)
{
return;
};
MEM_ArrayInsert(m_arrBuffs, ptr);
//OnApply
if(buff.OnApply > 0)
{
var c_npc n; n = Hlp_GetNpc(InstID);
MEM_PushInstParam(n);
MEM_CallByID(buff.OnApply);
};
};
func void Buff_ApplyUnique(var c_npc slf, var int _bf)
{
var int hlp; hlp = new(_bf);
var CBuff b; b = get(hlp);
if(!Npc_HasBuff(slf, b.ID))
{
Buff_Apply(slf, _bf);
};
};
func void Buff_Delete(var int ptr)
{
if(m_arrBuffs)
{
var CBuff b; b = get(ptr);
if(b.OnRemove > 0)
{
var c_npc slf; slf = Hlp_GetNpc(b.pSelf);
MEM_PushInstParam(slf);
MEM_CallByID(b.OnRemove);
};
MEM_ArrayRemoveValue(m_arrBuffs, ptr);
if(MEM_ArraySize(m_arrBuffs) <= 0)
{
MEM_ArrayClear(m_arrBuffs);
m_arrBuffs = 0;
};
};
};
func void Buff_End()
{
Buff_Delete(Current_Buff);
};
func void Buff_CallFunc(var int ptr)
{
var CBuff b; b = get(ptr);
if(b.OnTick > 0)
{
var c_npc slf; slf = Hlp_GetNpc(b.pSelf);
MEM_PushInstParam(slf);
MEM_CallByID(b.OnTick);
};
};
func void Buff_Do(var int nr)
{
if(!m_arrBuffs)
{
return;
};
var int ptr; ptr = MEM_ArrayRead(m_arrBuffs, nr);
if(!Hlp_IsValidHandle(ptr))
{
return;
};
var int bPause;
var int NowTime;
var CBuff buff;
bPause = MEM_GAME.singleStep; //BOOL
Current_Buff = ptr;
NowTime = Timer();
buff = get(ptr);
if(!bPause)
{
if(NowTime >= buff.EndTime)
{
buff.EndTime += buff.delay;
Buff_CallFunc(ptr);
if(buff.Cycles != -1)
{
buff.Cycles -= 1;
if(buff.Cycles < 1 )
{
Buff_Delete(ptr);
return;
};
};
};
}
else
{
buff.EndTime += Timer() - buff.OldTime;
};
buff.OldTime = NowTime;
};
func void Buffs_Attach()
{
if(m_arrBuffs)
{
if(MEM_ArraySize(m_arrBuffs))
{
var int i; i = 0;
var int pos; pos = MEM_StackPos.position;
if(i < MEM_ArraySize(m_arrBuffs)) //for(int i = 0; i < m_arrBuffs.GetSize(); i++);
{
Buff_Do(i);
i += 1;
MEM_StackPos.position = pos;
};
};
};
};
func void Buff_RemoveByType(var c_npc slf, var int type)
{
var int arr; arr = MEM_ArrayCreate();
GetBuffsByNpc(arr, slf);
if(arr)
{
var int size; size = MEM_ArraySize(arr);
if(size)
{
var int i; i = 0;
repeat(i, size);
var int ptr; ptr = MEM_ArrayRead(arr, i);
if(Hlp_IsValidHandle(ptr))
{
var CBuff b; b = get(ptr);
if(type == b.Type)
{
Buff_Delete(ptr);
};
};
end;
};
};
MEM_ArrayFree(arr);
};
func void Buff_RemoveByID(var c_npc slf, var int id)
{
var int arr; arr = MEM_ArrayCreate();
GetBuffsByNpc(arr, slf);
if(arr)
{
var int size; size = MEM_ArraySize(arr);
if(size)
{
var int i; i = 0;
repeat(i, size);
var int ptr; ptr = MEM_ArrayRead(arr, i);
if(Hlp_IsValidHandle(ptr))
{
var CBuff b; b = get(ptr);
if(id == b.ID)
{
Buff_Delete(ptr);
};
};
end;
};
};
MEM_ArrayFree(arr);
};
func void Buff_SetCycles(var c_npc slf, var int ID, var int cycles)
{
var int arr; arr = MEM_ArrayCreate();
GetBuffsByNpc(arr, slf);
if(arr)
{
var int size; size = MEM_ArraySize(arr);
if(size)
{
var int i; i = 0;
repeat(i, size);
var int ptr; ptr = MEM_ArrayRead(arr, i);
if(Hlp_IsValidHandle(ptr))
{
var CBuff b; b = get(ptr);
if(id == b.ID)
{
b.cycles = cycles;
};
};
end;
};
};
MEM_ArrayFree(arr);
};
func int Buff_CreateView(var int x, var int y, var string texture)
{
var int ptr; ptr = View_CreateCenter(x, y,
Print_ToVirtual(Buff_TextureSize, PS_X),
Print_ToVirtual(Buff_TextureSize, PS_Y));
View_SetTexture(ptr, texture);
View_Open(ptr);
return ptr;
};
Cinemascope was wrote by OrcWarriorPL many years ago. I just ordered it, because script was practically illegible. Bottom part of script (strange formula) is for moving choice box bellow black bar when resolution is set at 1024x768 or lower. It's not necessary, because hardly anyone plays at these resolutions yet :P I think it may be written simplier, but I'm lazy xD
That looks a lot better! I still have to ask... what's he computing with the %1 in the formula at the bottom? I had asked the last time this script showed up but no one was able to answer me
Zitat von Rayzer
Btw. Some time ago I wrote script of temporary regeneration for my personal use, as alternative of Buffs. You can set delay and ticks. Usage is very easy. Just call fuction RE_CastEffects per frame. Example:
Code:
RE_AddEffect (self, ATR_HITPOINTS, 120, 8, 1000);
Code:
Code:
class RegenerationEffect
{
var int instance;
var int attribute;
var int value;
var int cycles;
var int cycles_current;
var int delay;
var int time;
};
instance RegenerationEffect@ (RegenerationEffect);
func void RE_AddEffect (var c_npc slf, var int attribute, var int value, var int cycles, var int delayMS)
{
var int hndl; hndl = new (RegenerationEffect@);
var RegenerationEffect effect; effect = get (hndl);
effect.instance = Hlp_GetInstanceID (slf);
effect.attribute = attribute;
effect.value = value;
effect.cycles = cycles;
effect.cycles_current = cycles;
effect.delay = delayMS;
effect.time = MEM_Timer.totalTime;
};
func void RE_CastEffect (var int hndl)
{
var RegenerationEffect effect; effect = get (hndl);
if (MEM_Timer.totalTime - effect.time < effect.delay || MEM_Game.singleStep == true)
{
return;
};
if (effect.cycles_current > 0)
{
var c_npc slf; slf = Hlp_GetNpc (effect.instance);
var int value; value = roundf (divf (mkf (effect.value), mkf (effect.cycles)));
effect.cycles_current -= 1;
effect.time = MEM_Timer.totalTime;
if (effect.cycles_current == 0 && effect.value - (value*effect.cycles) > 0)
{
value += effect.value - (value*effect.cycles);
};
if (slf.attribute[ATR_HITPOINTS] > 0)
{
Npc_ChangeAttribute (slf, effect.attribute, value);
};
};
if (effect.cycles_current == 0 || slf.attribute[ATR_HITPOINTS] == 0)
{
delete (hndl);
};
};
func void RE_CastEffects ()
{
foreachHndl (RegenerationEffect@, RE_CastEffect);
};
The script looks good but I don't think there's any use for it given that LeGo implements its own buffs - I think it's only marginally more work to implement a regen effect using them.
I think your script may have problems when such an effect is applied to monsters (e.g. more than one NPC of the given instance). I think the only and thus best way to save NPCs is Npc_GetID()/Npc_FindByID().
@Siemekk: I don't mind you rewriting stuff (although I have to ask why: It looks like you're still using LeGo functions in there anyway?), but I really see nothing to gain here. Why publish a script that is almost a literal copy?
I don't know how's look's buffs in LeGo - last time when i used this package i had crash in buff_apply. So i rewrited system - my script save all values to array. It's working, but if buff's from LeGo work, for others this script is no sense.
I don't know how's look's buffs in LeGo - last time when i used this package i had crash in buff_apply. So i rewrited system - my script save all values to array. It's working, but if buff's from LeGo work, for others this script is no sense.
Oh, that is understandable! For future reference: If you find crashes (or other bugs) when using LeGo, make a small post in the LeGo thread! I'd love to fix them.
That looks a lot better! I still have to ask... what's he computing with the %1 in the formula at the bottom? I had asked the last time this script showed up but no one was able to answer me
I don't know. This is also strange to me. This question should be addressed to OrcWarrior, but it's hard to get in touch with him. Here is original script: https://github.com/orcwarrior/Czas_Z...nctions.d#L192
Be careful. Eyes can hurt from reading this xD
Zitat von Lehona
The script looks good but I don't think there's any use for it given that LeGo implements its own buffs - I think it's only marginally more work to implement a regen effect using them.
I think your script may have problems when such an effect is applied to monsters (e.g. more than one NPC of the given instance). I think the only and thus best way to save NPCs is Npc_GetID()/Npc_FindByID().
Thanks. I think this will help. I did not think about monsters, because I wrote this script for food and potions.
Schon immer hat mich an Wld_PlayEffect genervt, dass man Effekte nicht verlässlich stoppen kann. Wld_StopEffect beendet nur den erst gefundenen Effekt mit dem Namen, was häufig dazu geführt hat, dass Effekte in der Welt hängen geblieben sind. Ausserdem gibt es in Gothic 1 gar kein Wld_StopEffect, wodurch man gestartete Effekte gar nicht erst beenden konnte.
Ich möchte hier Wld_StopEffect_Ext vorstellen. Ein Skript, mit dem man genau bestimmen kann welcher Effekt beendet werden soll (und ob nur einer oder alle übereinstimmenden). Das ganze kompatibel mit Gothic 2 und Gothic 1. Die Funktion tut haargenau das, was Wld_StopEffect in der Engine tut, nur mit erweiterter Funktionalität.
Genauer:
Es gibt drei zusätzliche Funktionsparamenter und einen Rückgabewert:
func int Wld_StopEffect_Ext(string effect, int origin, int target, int stopAll)
Parameter zwei und drei sind Ursprungsobjekt und Zielobjekt (so wie man das von Wld_PlayEffect kennt). Übergeben wird jeweils eine Instanz. So kann mal sowohl NPCs und Items, als auch jegliche andere Instanz übergeben, die von der Klasse zCVob erbt. Diese Parameter können auch null sein, wenn sie nicht festgelegt werden sollen.
Der vierte Parameter lässt entscheiden, ob nur der erst gefundene Effekt gestoppt werden soll (0), so wie bei Wld_StopEffect, oder alle Effekte gestoppt werden sollen, die mit den Voraussetzungen übereinstimmen (1).
Der Rückgabewert gibt an, wie viele Effekte gestoppt wurden. Null bedeutet, dass entweder keine passenden Effekte gefunden wurden, oder die Argumente fehlerhaft waren. Mit diesem Rückgabewert hat man aus der Skripten nun auch mehr Kontrolle über was geschieht.
Beispiel:
Code:
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 exactly and only the first effect
Aufgrund der vielen Speicheradressen für sowohl Gothic 1, als auch Gothic 2, wirkt das Skript enorm lang, ist aber eigentlich ziemlich kurz und simpel.
Ich habe das Skript schon in die Form der übrigen Skripte aus dem ScriptBin gebracht (Kopfzeile im Skript), kann also direkt so übernommen werden.
Code:
// 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
/*
* Check the inheritance of a zCObject against a zCClassDef. Emulating zCObject::CheckInheritance() at 0x476E30 in G2.
* This function is used in Wld_StopEffect_Ext().
*/
func int objCheckInheritance(var int objPtr, var int classDef){
if (!objPtr) || (!classDef){
return 0;
};
const int zCClassDef_baseClassDef_offset = 60; //0x003C
// Iterate over base classes
var int curClassDef; curClassDef = MEM_GetClassDef(objPtr);
while((curClassDef) && (curClassDef != classDef));
curClassDef = MEM_ReadInt(curClassDef+zCClassDef_baseClassDef_offset);
end;
return (curClassDef == classDef);
};
/*
* 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 = _at(MEM_World);
if (!worldPtr){
return 0;
};
// Create array from all oCVisualFX vobs
var int vobArrayPtr; vobArrayPtr = MEM_ArrayCreate();
var zCArray vobArray; vobArray = _hat(vobArrayPtr);
const int call = 0; var int zero;
if (CALL_Begin(call)){
CALL_PtrParam(_at(zero)); // Vob tree (0 == globalVobTree)
CALL_PtrParam(_at(vobArrayPtr)); // Array to store found vobs in
CALL_PtrParam(_at(oCVisualFX__classDef)); // Class definition
CALL__thiscall(_at(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 = _hat(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 = _hat(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(_at(one));
CALL__thiscall(_at(vobPtr), oCVisualFX__Stop);
call2 = CALL_End();
};
stopped += 1;
if (!all){
break;
};
end;
MEM_ArrayFree(vobArrayPtr);
return stopped;
};
Was haltet ihr eigentlich davon, diesen Thread mal anzupinnen?
Was hat es mit dem _at auf sich? Das wird bei mir nicht gefunden und ich weiß auch nicht, wo es herkommen müsste.
_at() und _hat() sind _@() beziehungsweise _^(). Ich nehme an, da ist irgendwas beim schön formatieren kaputt gegangen? Vielleicht mag mud-freak auch einfach die Symbole nicht, ich hab gehört die Schweizer benutzen ein anderes Tastaturlayout als das deutsche.
Die Datei war im ScriptBin nicht in die zugehörige .src eingetragen, daher ist mir das nicht aufgefallen. Aktualisierte .src und Wld_StopEffect.d (die sich parsen lässt) sind jetzt auf dem SVN.
Schon immer hat mich an Wld_PlayEffect genervt, dass man Effekte nicht verlässlich stoppen kann. Wld_StopEffect beendet nur den erst gefundenen Effekt mit dem Namen, was häufig dazu geführt hat, dass Effekte in der Welt hängen geblieben sind. Ausserdem gibt es in Gothic 1 gar kein Wld_StopEffect, wodurch man gestartete Effekte gar nicht erst beenden konnte.
Ich möchte hier Wld_StopEffect_Ext vorstellen. Ein Skript, mit dem man genau bestimmen kann welcher Effekt beendet werden soll (und ob nur einer oder alle übereinstimmenden). Das ganze kompatibel mit Gothic 2 und Gothic 1. Die Funktion tut haargenau das, was Wld_StopEffect in der Engine tut, nur mit erweiterter Funktionalität.
Genauer:
Es gibt drei zusätzliche Funktionsparamenter und einen Rückgabewert:
func int Wld_StopEffect_Ext(string effect, int origin, int target, int stopAll)
Parameter zwei und drei sind Ursprungsobjekt und Zielobjekt (so wie man das von Wld_PlayEffect kennt). Übergeben wird jeweils eine Instanz. So kann mal sowohl NPCs und Items, als auch jegliche andere Instanz übergeben, die von der Klasse zCVob erbt. Diese Parameter können auch null sein, wenn sie nicht festgelegt werden sollen.
Der vierte Parameter lässt entscheiden, ob nur der erst gefundene Effekt gestoppt werden soll (0), so wie bei Wld_StopEffect, oder alle Effekte gestoppt werden sollen, die mit den Voraussetzungen übereinstimmen (1).
Der Rückgabewert gibt an, wie viele Effekte gestoppt wurden. Null bedeutet, dass entweder keine passenden Effekte gefunden wurden, oder die Argumente fehlerhaft waren. Mit diesem Rückgabewert hat man aus der Skripten nun auch mehr Kontrolle über was geschieht.
Beispiel:
Code:
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 exactly and only the first effect
Aufgrund der vielen Speicheradressen für sowohl Gothic 1, als auch Gothic 2, wirkt das Skript enorm lang, ist aber eigentlich ziemlich kurz und simpel.
Ich habe das Skript schon in die Form der übrigen Skripte aus dem ScriptBin gebracht (Kopfzeile im Skript), kann also direkt so übernommen werden.
Code:
// 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
/*
* Check the inheritance of a zCObject against a zCClassDef. Emulating zCObject::CheckInheritance() at 0x476E30 in G2.
* This function is used in Wld_StopEffect_Ext().
*/
func int objCheckInheritance(var int objPtr, var int classDef){
if (!objPtr) || (!classDef){
return 0;
};
const int zCClassDef_baseClassDef_offset = 60; //0x003C
// Iterate over base classes
var int curClassDef; curClassDef = MEM_GetClassDef(objPtr);
while((curClassDef) && (curClassDef != classDef));
curClassDef = MEM_ReadInt(curClassDef+zCClassDef_baseClassDef_offset);
end;
return (curClassDef == classDef);
};
/*
* 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;
};
Im ScriptBin fehlt die Funktion objCheckInheritance, bzw. ist sie nicht in dieser Datei zu finden. Die Funktion sollte aber mindestens unter den Voraussetzungen genannt und verlinkt werden.
Im ScriptBin fehlt die Funktion objCheckInheritance, bzw. ist sie nicht in dieser Datei zu finden. Die Funktion sollte aber mindestens unter den Voraussetzungen genannt und verlinkt werden.
Doch die ist dabei. Lehona hat sie nur von dem Skript abgetrennt und separat in der Datei /Ikarus_Scripts/Misc.d aufgenommen.
Doch die ist dabei. Lehona hat sie nur von dem Skript abgetrennt und separat in der Datei /Ikarus_Scripts/Misc.d aufgenommen.
Ja, dann wäre es schön, wenn das im Kopf der Datei vermerkt oder verlinkt wäre. Ich könnte mir vorstellen, dass der ein oder andere so wie ich nicht alle Skripte nimmt, sondern sich die raussucht, die er /sie braucht
Ja, dann wäre es schön, wenn das im Kopf der Datei vermerkt oder verlinkt wäre. Ich könnte mir vorstellen, dass der ein oder andere so wie ich nicht alle Skripte nimmt, sondern sich die raussucht, die er /sie braucht
Gut, dem muss ich zustimmen. Das fänd ich auch gut.
Wo ich gerade mal hier bin: Mir ist aufgefallen, dass das InsertAnything-Skript fehlerhaft ist. Unter gewissen Umständen gehen Vobs nach Speichern und Laden verloren. Ausserdem ist es eher suboptimal implementiert. Beheben lässt sich das ganz einfach, aber das Skript ist einfach so unleserlich formatiert (80 Zeichen Zeilenlänge und kaum Leerzeilen), dass ich da gar keine Lust drauf habe.
Ich werde mir das heute vielleicht mal anschauen und es bei der Gelegenheit auch mal für Gothic 1 kompatibel machen.
Ich habe das Skript jetzt komplett geändert. Die Funktionen haben jetzt nicht mehr so viele Parameter und sind übersichtlicher (stattdessen kann man bei Bedarf weitere Funktionen nach dem Einfügen aufrufen, um bspw. eine Truhe zu füllen, oder eine Tür zu verschliessen).
Die Funktionen sind jetzt auch performanter (falls das eine Rolle spielt) und das ganze ist so aufgesetzt, dass man nun Objekte jeder beliebigen Art einfügen kann, die von zCVob erben. Für die meist genutzten habe ich aber Wrapper-Funktionen erstellt, um die Anzahl der Argumente klein und es übersichtlich zu halten.
Alles sollte jetzt auch unter Gothic 1 laufen, habe ich aber nicht mehr explizit alles durchgetestet.
Und hier ein kleines, nettes Beispiel:
Code:
const float pos[3] = { 9458.563477, 589.735718, -4732.891602 }; // World coordinates (use [ALT]+[P] in MARVIN-mode)
var int chestPtr;
chestPtr = InsertMobContainerPos("myNewChest", "CHESTBIG_OCCHESTLARGE.MDS", _@f(pos), 0);
SetMobName(chestPtr, "MOBNAME_CHEST"); // Set focus name
LockMobLockable(chestPtr, "ItKe_Key_01", "LRLR", TRUE); // A key and/or lock picking string can be set
FillMobContainer(chestPtr, "ItMi_Gold:23,ItKe_Key_01:1 "); // Whoops, dropped the key inside!
Und hier ein Beispiel, wie man Objekte jeglicher (von zCVob erbenden) Klasse einfügen kann. Das obere Beispiel kann man auch so schreiben. Man muss nur die Klassenbezeichnung wissen, hier "oCMobContainer".
Hier das Skript. Kann dann bei Gelegenheit im Scriptbin aktualisiert werden.
Spoiler:(zum lesen bitte Text markieren)
Code:
/*
* insertAnything.d
* Source: https://forum.worldofplayers.de/forum/threads/?p=25712257
*
* Create and insert any kind of object inheriting from the zCVob class in real time.
*
*
* The core function behind this is
*
* func int InsertObject(string class, string objName, string visual, int trafoPtr, int parentVobPtr)
*
* However, for the most common object classes there are specific functions with simpler signature for inserting at
* - way points (functions with "WP" postfix)
* - exact coordinates with optionally specifying the direction (functions with "Pos" postfix)
* - aligned at a full trafo-matrix (functions without postfix)
*
* Additionally, the objects may be inserted as child vobs of other vobs. (functions with "AsChild" postfix)
* Objects inheriting from the oCMob class can then be further adjusted with additional functions listed below.
*
* [A] = {Vob,Mob,MobInter,MobLockable,MobContainer,MobDoor,MobFire}
*
* func int Insert[A]WP (string objName, string visual, string waypoint)
* func int Insert[A]Pos (string objName, string visual, int posPtr, int dirPtr)
* func int Insert[A] (string objName, string visual, int trafoPtr)
*
* func int Insert[A]AsChildWP (string objName, string visual, string waypoint, int parentVobPtr)
* func int Insert[A]AsChildPos (string objName, string visual, int posPtr, int dirPtr, int parentVobPtr)
* func int Insert[A]AsChild (string objName, string visual, int trafoPtr, int parentVobPtr)
*
*
* [B] = {Trigger,TriggerScript,TriggerChangeLevel}
*
* func int Insert[B]Pos (string objName, int posPtr, int dirPtr)
* func int Insert[B] (string objName, int trafoPtr)
*
* func int InsertMoverPos (string objName, string visual, int posPtr, int dirPtr)
* func int InsertMover (string objName, string visual, int trafoPtr)
*
* func int InsertItemWP (string scriptInst, int amount, string waypoint)
* func int InsertItemPos (string scriptInst, int amount, int posPtr, int dirPtr)
* func int InsertItem (string scriptInst, int amount, int trafoPtr)
*
* func void InsertPileOfVobs (string objName, string visual, int trafoPtr, int amount, int cm2, int rotate)
* func void InsertPileOfItems (string scriptInst, int trafoPtr, int amount, int cm2, int rotate)
*
*
* Additional functions (not all functions are mentioned here)
*
* func void SetVobToFloor (int vobPtr)
* func void SetWPToFloor (int wpPtr)
*
*
* Further mob setter-functions
*
* func int SetMobName (int mobPtr, string symbolicFocusName)
* func void SetMobOwner (int mobPtr, string owner, string ownerGuild)
* func void SetMobMisc (int mobPtr, string triggerTarget, string useWithItem, string onStateFuncName)
* func void LockMobLockable (int mobPtr, string keyInstance, string pickLockStr, int isLocked)
* func void FillMobContainer (int mobPtr, string contents)
*
*
* Example
*
* // Inserting a locked chest with specific contents
*
* const float pos[3] = { 9458.563477, 589.735718, -4732.891602 }; // World coordinates (use [ALT]+[P] in MARVIN-mode)
*
* var int chestPtr;
* chestPtr = InsertMobContainerPos("myNewChest", "CHESTBIG_OCCHESTLARGE.MDS", _@f(pos), 0);
*
* SetMobName(chestPtr, "MOBNAME_CHEST"); // Set focus name
* LockMobLockable(chestPtr, "ItKe_Key_01", "LRLR", TRUE); // A key and/or lock picking string can be set
* FillMobContainer(chestPtr, "ItMi_Gold:23,ItKe_Key_01:1 "); // Whoops, dropped the key inside!
*
*//*
* Creates an "empty" trafo-matrix
*/
func void NewTrafo(var int trafoPtr){
const int zMAT4__s_identity_G1 = 8845416; //0x86F868
const int zMAT4__s_identity_G2 = 9258472; //0x8D45E8
const int sizeof_zMAT4 = 64; // Same for G1 and G2
MEM_CopyBytes(MEMINT_SwitchG1G2(zMAT4__s_identity_G1, zMAT4__s_identity_G2), trafoPtr, sizeof_zMAT4);
};
/*
* Rotate trafo-matrix around its up-vector (change front-facing direction)
*/
func void RotateTrafoY(var int trafoPtr, var int degrees){
const int zMAT4__PostRotateY_G1 = 5274256; //0x507A90
const int zMAT4__PostRotateY_G2 = 5339008; //0x517780
const int call = 0;
if (CALL_Begin(call)){
CALL_FloatParam(_@(degrees));
CALL__thiscall(_@(trafoPtr), MEMINT_SwitchG1G2(zMAT4__PostRotateY_G1, zMAT4__PostRotateY_G2));
call = CALL_End();
};
};
/*
* Store the positional information of a trafo-matrix into a vector
*/
func void TrfToPos(var int trafoPtr, var int posPtr){
MEM_WriteIntArray(posPtr, 0, MEM_ReadIntArray(trafoPtr, 3));
MEM_WriteIntArray(posPtr, 1, MEM_ReadIntArray(trafoPtr, 7));
MEM_WriteIntArray(posPtr, 2, MEM_ReadIntArray(trafoPtr, 11));
};
/*
* Store positional and/or directional information into a trafo-matrix
*/
func void PosDirToTrf(var int posPtr, var int dirPtr, var int trafoPtr){
const int zMAT4__MakeOrthonormal_G1 = 5273152; //0x507640
const int zMAT4__MakeOrthonormal_G2 = 5337904; //0x517330
if (posPtr){
MEM_WriteIntArray(trafoPtr, 3, MEM_ReadIntArray(posPtr, 0));
MEM_WriteIntArray(trafoPtr, 7, MEM_ReadIntArray(posPtr, 1));
MEM_WriteIntArray(trafoPtr, 11, MEM_ReadIntArray(posPtr, 2));
};
if (dirPtr){
MEM_WriteIntArray(trafoPtr, 2, MEM_ReadIntArray(dirPtr, 0));
MEM_WriteIntArray(trafoPtr, 6, MEM_ReadIntArray(dirPtr, 1));
MEM_WriteIntArray(trafoPtr, 10, MEM_ReadIntArray(dirPtr, 2));
const int call = 0;
if (CALL_Begin(call)){
CALL__thiscall(_@(trafoPtr), MEMINT_SwitchG1G2(zMAT4__MakeOrthonormal_G1, zMAT4__MakeOrthonormal_G2));
call = CALL_End();
};
};
};
/*
* Get ground level (y-coordinate) from a position
*/
func int GetGroundLvlPos(var int posPtr){
const float dir[3] = { 0.0, -2000.0, 0.0 }; // Check for ground up to 2000 cm below (Gothic does 1000 cm)
const int zCWorld__TraceRayNearestHit_G1 = 6243008; //0x5F42C0
const int zCWorld__TraceRayNearestHit_G2 = 6429568; //0x621B80
const int flags = 33; // 0x21 (zTRACERAY_VOB_IGNORE_NO_CD_DYN | zTRACERAY_STAT_POLY)
const int ignoreList = 0;
var int worldPtr; worldPtr = MEM_Game._zCSession_world;
var int dirPtr; dirPtr = _@f(dir);
const int call = 0;
if (CALL_Begin(call)){
CALL_IntParam(_@(flags));
CALL_PtrParam(_@(ignoreList));
CALL_PtrParam(_@(dirPtr));
CALL__fastcall(_@(worldPtr), _@(posPtr), MEMINT_SwitchG1G2(zCWorld__TraceRayNearestHit_G1,
zCWorld__TraceRayNearestHit_G2));
call = CALL_End();
};
// Check for intersection and return y-position
if (CALL_RetValAsInt()) && ((MEM_World.foundPoly) || (MEM_World.foundVob)){
return MEM_World.foundIntersection[1];
} else {
return subf(MEM_ReadInt(posPtr+4), mkf(2000));
};
};
/*
* Get ground level (y-coordinate) from a trafo-matrix
*/
func int GetGroundLvl(var int trfPtr){
var int pos[3];
TrfToPos(trfPtr, _@(pos));
return GetGroundLvlPos(_@(pos));
};
/*
* Search a way point by its name
*/
func int SearchWaypointByName(var string waypoint){
const int zCWayNet__GetWaypoint_G1 = 7366448; //0x706730
const int zCWayNet__GetWaypoint_G2 = 8061744; //0x7B0330
var int waynetPtr; waynetPtr = MEM_World.wayNet;
var int wpNamePtr; wpNamePtr = _@s(waypoint);
const int call = 0;
if (Call_Begin(call)){
CALL__fastcall(_@(waynetPtr), _@(wpNamePtr), MEMINT_SwitchG1G2(zCWayNet__GetWaypoint_G1,
zCWayNet__GetWaypoint_G2));
call = CALL_End();
};
return CALL_RetValAsPtr();
};
/*
* Get trafo-matrix from way point
*/
func void GetTrafoFromWP(var string wpName, var int trafoPtr){
var int wpPtr; wpPtr = SearchWaypointByName(wpName);
if (!wpPtr){
MEM_Warn("Way point not found!");
return;
};
var zCWaypoint wp; wp = _^(wpPtr);
PosDirToTrf(_@(wp.pos), _@(wp.dir), trafoPtr);
};
/*
* Set way point to correct height above ground level
*/
func void SetWPToFloor(var int wpPtr){
const int zCWaypoint__CorrectHeight_G1 = 7365792; //0x7064A0
const int zCWaypoint__CorrectHeight_G2 = 8061088; //0x7B00A0
var int worldPtr; worldPtr = MEM_Game._zCSession_world;
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(worldPtr));
CALL__thiscall(_@(wpPtr), MEMINT_SwitchG1G2(zCWaypoint__CorrectHeight_G1, zCWaypoint__CorrectHeight_G2));
call = CALL_End();
};
};
/*
* Align a vob to a trafo-matrix
*/
func void AlignVobAt(var int vobPtr, var int trfPtr){
if (!vobPtr) || (!trfPtr){
return;
};
const int zCVob__SetTrafoObjToWorld_G1 = 6219616; //0x5EE760
const int zCVob__SetTrafoObjToWorld_G2 = 6405248; //0x61BC80
// Lift collision
var zCVob vob; vob = _^(vobPtr);
var int bits; bits = vob.bitfield[0];
vob.bitfield[0] = vob.bitfield[0] & ~zCVob_bitfield0_collDetectionStatic & ~zCVob_bitfield0_collDetectionDynamic;
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(trfPtr));
CALL__thiscall(_@(vobPtr), MEMINT_SwitchG1G2(zCVob__SetTrafoObjToWorld_G1, zCVob__SetTrafoObjToWorld_G2));
call = CALL_End();
};
// Restore bits
vob.bitfield[0] = bits;
};
/*
* Set vob to align at ground level
*/
func void SetVobToFloor(var int vobPtr){
if (!vobPtr){
return;
};
// Correct height
var zCVob vob; vob = _^(vobPtr);
var int half; half = subf(vob.trafoObjToWorld[7], vob.bbox3D_mins[1]);
vob.trafoObjToWorld[7] = GetGroundLvl(_@(vob.trafoObjToWorld));
vob.trafoObjToWorld[7] = addf(vob.trafoObjToWorld[7], half);
vob.trafoObjToWorld[7] = subf(vob.trafoObjToWorld[7], castToIntf(0.5));
// Update position
AlignVobAt(vobPtr, _@(vob.trafoObjToWorld));
};
/*
* Set a visual of a given vob by string
*/
func void VobSetVisual(var int vobPtr, var String visual){
const int zCVob__SetVisual_G1 = 6123424; //0x5D6FA0
const int zCVob__SetVisual_G2 = 6301312; //0x602680
if (!vobPtr){
return;
};
var int strPtr; strPtr = _@s(visual);
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(strPtr));
CALL__thiscall(_@(vobPtr), MEMINT_SwitchG1G2(zCVob__SetVisual_G1, zCVob__SetVisual_G2));
call = CALL_End();
};
};
/*
* Retrieve class definition address by string
*/
func int GetClassDefByString(var string classDefName){
const int zCClassDef__GetClassDef_G1 = 5809264; //0x58A470
const int zCClassDef__GetClassDef_G2 = 5939168; //0x5A9FE0
var int classDefNamePtr; classDefNamePtr = _@s(classDefName);
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(classDefNamePtr));
CALL__cdecl(MEMINT_SwitchG1G2(zCClassDef__GetClassDef_G1, zCClassDef__GetClassDef_G2));
call = CALL_End();
};
return CALL_RetValAsPtr();
};
/*
* Create a new instance by class definition
*/
func int CreateNewInstance(var int classDefAddr){
const int zCClassDef__createNewInstance_offset = 64; //0x40 Same for G1 and G2
// This is a non-recyclable call, because of varying function address
CALL__cdecl(MEM_ReadInt(classDefAddr+zCClassDef__createNewInstance_offset));
return CALL_RetValAsPtr();
};
/*
* Create new instance by class definition name
*/
func int CreateNewInstanceByString(var string classDefName){
var int classDefAddr; classDefAddr = GetClassDefByString(classDefName);
if (!classDefAddr){
MEM_Warn("ClassDef not found");
return 0;
};
return CreateNewInstance(classDefAddr);
};
/*
* Create and insert object
*/
func int InsertObject(var string class, var string objName, var string visual, var int trfPtr, var int parentPtr){
var int vobPtr; vobPtr = CreateNewInstanceByString(class);
if (!vobPtr){
return 0;
};
VobSetVisual(vobPtr, visual);
MEM_RenameVob(vobPtr, objName);
// Adjust bits
var zCVob vob; vob = _^(vobPtr);
vob.bitfield[0] = vob.bitfield[0] & (-67108865); //0xFBFFFFFF
vob.bitfield[0] = vob.bitfield[0] & ~zCVob_bitfield0_collDetectionStatic & ~zCVob_bitfield0_collDetectionDynamic;
// Set positional and rotational information
AlignVobAt(vobPtr, trfPtr);
// Get parent vob tree
var int vobTreePtr;
if (parentPtr){
var zCVob parent; parent = _^(parentPtr);
vobTreePtr = parent.globalVobTreeNode;
} else {
vobTreePtr = _@(MEM_Vobtree); // Global vob tree
};
// Insert into world
const int oCWorld__AddVobAsChild_G1 = 7171232; //0x6D6CA0
const int oCWorld__AddVobAsChild_G2 = 7863856; //0x77FE30
var int worldPtr; worldPtr = MEM_Game._zCSession_world;
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(vobTreePtr));
CALL_PtrParam(_@(vobPtr));
CALL_PutRetValTo(0);
CALL__thiscall(_@(worldPtr), MEMINT_SwitchG1G2(oCWorld__AddVobAsChild_G1, oCWorld__AddVobAsChild_G2));
call = CALL_End();
};
// Set bits
vob.bitfield[0] = vob.bitfield[0] | zCVob_bitfield0_collDetectionStatic | zCVob_bitfield0_collDetectionDynamic;
vob.bitfield[2] = vob.bitfield[2] & ~zCVob_bitfield2_sleepingMode; // vob.SetSleeping(1);
// Decrease reference counter... why is that necessary?
vob._zCObject_refCtr -= 1;
if (vob._zCObject_refCtr <= 0){
const int _scalar_deleting_destructor_offset = 12; // Same for G1 and G2
CALL_IntParam(1);
CALL__thiscall(vobPtr, MEM_ReadInt(vob._vtbl+_scalar_deleting_destructor_offset));
};
return vobPtr;
};
func int InsertObjectPos(var string class, var string nm, var string vis, var int pos, var int dir, var int par){
var int trafo[16]; NewTrafo(_@(trafo));
PosDirToTrf(pos, dir, _@(trafo));
return InsertObject(class, nm, vis, _@(trafo), par);
};
func int InsertObjectWP(var string class, var string nm, var string vis, var string wpName, var int par){
var int wpPtr; wpPtr = SearchWaypointByName(wpName);
if (!wpPtr){
MEM_Warn(ConcatStrings("Way point not found: ", wpName));
return 0;
};
var zCWaypoint wp; wp = _^(wpPtr);
return InsertObjectPos(class, nm, vis, _@(wp.pos), _@(wp.dir), par);
};
/*
* zCVob/oCVob functions:
*
* InsertVobWP (string objName, string visual, string waypoint)
* InsertVobPos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertVob (string objName, string visual, int[16] *trafoMat)
*
* InsertVobAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertVobAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertVobAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertVobAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("zCVob", nm, vis, trf, par);
};
func int InsertVobAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("zCVob", nm, vis, pos, dir, par);
};
func int InsertVobAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("zCVob", nm, vis, wp, par);
};
func int InsertVob(var string nm, var string vis, var int trf){
return InsertObject("zCVob", nm, vis, trf, 0);
};
func int InsertVobPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("zCVob", nm, vis, pos, dir, 0);
};
func int InsertVobWP(var string nm, var string vis, var string wp){
return InsertObjectWP("zCVob", nm, vis, wp, 0);
};
/*
* oCMob functions:
*
* InsertMobWP (string objName, string visual, string waypoint)
* InsertMobPos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMob (string objName, string visual, int[16] *trafoMat)
*
* InsertMobAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMOB", nm, vis, trf, par);
};
func int InsertMobAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMOB", nm, vis, pos, dir, par);
};
func int InsertMobAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMOB", nm, vis, wp, par);
};
func int InsertMob(var string nm, var string vis, var int trf){
return InsertObject("oCMOB", nm, vis, trf, 0);
};
func int InsertMobPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMOB", nm, vis, pos, dir, 0);
};
func int InsertMobWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMOB", nm, vis, wp, 0);
};
/*
* oCMobInter functions:
*
* InsertMobInterWP (string objName, string visual, string waypoint)
* InsertMobInterPos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMobInter (string objName, string visual, int[16] *trafoMat)
*
* InsertMobInterAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobInterAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobInterAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobInterAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMobInter", nm, vis, trf, par);
};
func int InsertMobInterAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMobInter", nm, vis, pos, dir, par);
};
func int InsertMobInterAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMobInter", nm, vis, wp, par);
};
func int InsertMobInter(var string nm, var string vis, var int trf){
return InsertObject("oCMobInter", nm, vis, trf, 0);
};
func int InsertMobInterPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMobInter", nm, vis, pos, dir, 0);
};
func int InsertMobInterWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMobInter", nm, vis, wp, 0);
};
/*
* oCMobLockable functions:
*
* InsertMobLockableWP (string objName, string visual, string waypoint)
* InsertMobLockablePos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMobLockable (string objName, string visual, int[16] *trafoMat)
*
* InsertMobLockableAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobLockableAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobLockableAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobLockableAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMobLockable", nm, vis, trf, par);
};
func int InsertMobLockableAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMobLockable", nm, vis, pos, dir, par);
};
func int InsertMobLockableAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMobLockable", nm, vis, wp, par);
};
func int InsertMobLockable(var string nm, var string vis, var int trf){
return InsertObject("oCMobLockable", nm, vis, trf, 0);
};
func int InsertMobLockablePos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMobLockable", nm, vis, pos, dir, 0);
};
func int InsertMobLockableWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMobLockable", nm, vis, wp, 0);
};
/*
* oCMobContainer functions:
*
* InsertMobContainerWP (string objName, string visual, string waypoint)
* InsertMobContainerPos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMobContainer (string objName, string visual, int[16] *trafoMat)
*
* InsertMobContainerAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobContainerAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobContainerAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobContainerAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMobContainer", nm, vis, trf, par);
};
func int InsertMobContainerAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMobContainer", nm, vis, pos, dir, par);
};
func int InsertMobContainerAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMobContainer", nm, vis, wp, par);
};
func int InsertMobContainer(var string nm, var string vis, var int trf){
return InsertObject("oCMobContainer", nm, vis, trf, 0);
};
func int InsertMobContainerPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMobContainer", nm, vis, pos, dir, 0);
};
func int InsertMobContainerWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMobContainer", nm, vis, wp, 0);
};
/*
* oCMobDoor functions:
*
* InsertMobDoorWP (string objName, string visual, string waypoint)
* InsertMobDoorPos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMobDoor (string objName, string visual, int[16] *trafoMat)
*
* InsertMobDoorAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobDoorAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobDoorAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobDoorAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMobDoor", nm, vis, trf, par);
};
func int InsertMobDoorAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMobDoor", nm, vis, pos, dir, par);
};
func int InsertMobDoorAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMobDoor", nm, vis, wp, par);
};
func int InsertMobDoor(var string nm, var string vis, var int trf){
return InsertObject("oCMobDoor", nm, vis, trf, 0);
};
func int InsertMobDoorPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMobDoor", nm, vis, pos, dir, 0);
};
func int InsertMobDoorWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMobDoor", nm, vis, wp, 0);
};
/*
* oCMobFire functions:
*
* InsertMobFireWP (string objName, string visual, string waypoint)
* InsertMobFirePos (string objName, string visual, int[3] *pos, int[3] *dir)
* InsertMobFire (string objName, string visual, int[16] *trafoMat)
*
* InsertMobFireAsChildWP (string objName, string visual, string waypoint, int *parentVob)
* InsertMobFireAsChildPos(string objName, string visual, int[3] *pos, int[3] *dir, int *parentVob)
* InsertMobFireAsChild (string objName, string visual, int[16] *trafoMat, int *parentVob)
*/
func int InsertMobFireAsChild(var string nm, var string vis, var int trf, var int par){
return InsertObject("oCMobFire", nm, vis, trf, par);
};
func int InsertMobFireAsChildPos(var string nm, var string vis, var int pos, var int dir, var int par){
return InsertObjectPos("oCMobFire", nm, vis, pos, dir, par);
};
func int InsertMobFireAsChildWP(var string nm, var string vis, var string wp, var int par){
return InsertObjectWP("oCMobFire", nm, vis, wp, par);
};
func int InsertMobFire(var string nm, var string vis, var int trf){
return InsertObject("oCMobFire", nm, vis, trf, 0);
};
func int InsertMobFirePos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("oCMobFire", nm, vis, pos, dir, 0);
};
func int InsertMobFireWP(var string nm, var string vis, var string wp){
return InsertObjectWP("oCMobFire", nm, vis, wp, 0);
};
/*
* "Abstract" vob functions:
*
* InsertTriggerPos (string objName, int[3] *pos, int[3] *dir)
* InsertTriggerScriptPos (string objName, int[3] *pos, int[3] *dir)
* InsertTriggerChangeLevelPos(string objName, int[3] *pos, int[3] *dir)
* InsertMoverPos (string objName, string visual, int[3] *pos, int[3] *dir)
*
* InsertTrigger (string objName, int[16] *trafoMat)
* InsertTriggerScript (string objName, int[16] *trafoMat)
* InsertTriggerChangeLevel (string objName, int[16] *trafoMat)
* InsertMover (string objName, string visual, int[16] *trafoMat)
*/
func int InsertTrigger(var string nm, var int trf){
return InsertObject("zCTrigger", nm, "", trf, 0);
};
func int InsertTriggerPos(var string nm, var int pos, var int dir){
return InsertObjectPos("zCTrigger", nm, "", pos, dir, 0);
};
func int InsertTriggerScript(var string nm, var int trf){
return InsertObject("oCTriggerScript", nm, "", trf, 0);
};
func int InsertTriggerScriptPos(var string nm, var int pos, var int dir){
return InsertObjectPos("oCTriggerScript", nm, "", pos, dir, 0);
};
func int InsertTriggerChangeLevel(var string nm, var int trf){
return InsertObject("oCTriggerChangeLevel", nm, "", trf, 0);
};
func int InsertTriggerChangeLevelPos(var string nm, var int pos, var int dir){
return InsertObjectPos("oCTriggerChangeLevel", nm, "", pos, dir, 0);
};
func int InsertMover(var string nm, var string vis, var int trf){
return InsertObject("zCMover", nm, vis, trf, 0);
};
func int InsertMoverPos(var string nm, var string vis, var int pos, var int dir){
return InsertObjectPos("zCMover", nm, vis, pos, dir, 0);
};
/*
* oCItem functions:
*
* InsertItemWP (string itemInstance, int amount, string waypoint)
* InsertItemPos(string itemInstance, int amount, int* pos, int* dir)
* InsertItem (string itemInstance, int amount, int* trafoMat)
*/
func int InsertItemWP(var string itmInst, var int amount, var string wp){
var int symbIdx; symbIdx = MEM_GetSymbolIndex(itmInst);
Wld_InsertItem(symbIdx, wp);
var zCTree newTreeNode; newTreeNode = _^(MEM_World.globalVobTree_firstChild);
var int itmPtr; itmPtr = newTreeNode.data;
if (!Hlp_Is_oCItem(itmPtr)){// Item effect is spawned last
newTreeNode = _^ (newTreeNode.next);
itmPtr = newTreeNode.data;
if (!Hlp_Is_oCItem(itmPtr)){
MEM_Warn(ConcatStrings("Could not insert item: ", itmInst));
return 0;
};
};
var oCItem itm; itm = _^(itmPtr);
if (itm.instanz != symbIdx){
MEM_Warn(ConcatStrings("Could not insert item: ", itmInst));
return 0;
};
itm.amount = amount;
return itmPtr;
};
func int InsertItem(var string itmInst, var int amount, var int trf){
var int itmPtr; itmPtr = InsertItemWP(itmInst, amount, MEM_FARFARAWAY);
AlignVobAt(itmPtr, trf);
return itmPtr;
};
func int InsertItemPos(var string itmInst, var int amount, var int pos, var int dir){
var int trafo[16];
NewTrafo(_@(trafo));
PosDirToTrf(pos, dir, _@(trafo));
var int itmPtr; itmPtr = InsertItem(itmInst, amount, _@(trafo));
SetVobToFloor(itmPtr);
return itmPtr;
};
/*
* PileOf functions:
*
* InsertPileOf (string class, string objName, string visual, int[16]* trafoMat, int amount, int cm2, int rotate)
* InsertPileOfVobs ( string objName, string visual, int[16]* trafoMat, int amount, int cm2, int rotate)
* InsertPileOfItems( string itmInst, int[16]* trafoMat, int amount, int cm2, int rotate)
*/
func void InsertPileOf(var string cl, var string nm, var string vis, var int trf, var int am, var int cm, var int rot){
const int sizeof_zMAT4 = 64; // Same for G1 and G2
repeat(i, am); var int i;
// Get new trafo from the original
var int trafo[16];
MEM_CopyBytes(trf, _@(trafo), sizeof_zMAT4);
// Increase height for better piling (will be "dropped")
trafo[ 7] = addf(trafo[ 7], mkf(200));
// Shift position (will be distributed over a square not a circle)
trafo[ 3] = addf(trafo[ 3], mkf(Hlp_Random(cm*2)-cm));
trafo[11] = addf(trafo[11], mkf(Hlp_Random(cm*2)-cm));
// Rotate
if (rot){
RotateTrafoY(_@(trafo), mkf(Hlp_Random(360)));
};
// Create vob or item
var int vobPtr;
if (Hlp_StrCmp(cl, "oCItem")){
vobPtr = InsertItem(nm, 1, _@(trafo));
} else {
var string name; name = ConcatStrings(nm, IntToString(i+1));
vobPtr = InsertObject(cl, name, vis, _@(trafo), 0);
};
SetVobToFloor(vobPtr);
end;
};
func void InsertPileOfVobs(var string nm, var string vis, var int trf, var int am, var int cm, var int rot){
InsertPileOf("zCVob", nm, vis, trf, am, cm, rot);
};
func void InsertPileOfItems(var string itmInst, var int trf, var int am, var int cm, var int rot){
InsertPileOf("oCItem", itmInst, "", trf, am, cm, rot);
};
/*
* Post-insert functions
*//*
* Set the focus name of a mob (see Text.d)
*/
func int SetMobName(var int mobPtr, var string symbolicFocusName){
if (Hlp_Is_oCMob(mobPtr)){
var oCMob mob; mob = _^(mobPtr);
mob.name = symbolicFocusName;
mob.focusNameIndex = MEM_GetSymbolIndex(symbolicFocusName);
};
return mobPtr;
};
/*
* Set mob owner. Thanks to Bisasam!
*/
func void SetMobOwner(var int mobPtr, var string owner, var string ownerGuild){
if (!Hlp_Is_oCMob(mobPtr)){
MEM_Warn("Not a oCMob!");
return;
};
var oCMob mob; mob = _^(mobPtr);
mob.ownerStr = owner;
mob.ownerGuildStr = ownerGuild;
};
/*
* Set some miscellaneous properties of mobs
*/
func void SetMobMisc(var int mobPtr, var string triggerTarget, var string useWithItem, var string onStateFuncName){
if (!Hlp_Is_oCMobInter(mobPtr)){
MEM_Warn("Not a oCMobInter!");
return;
};
var oCMobInter mob; mob = _^(mobPtr);
mob.triggerTarget = triggerTarget;
mob.useWithItem = useWithItem;
mob.onStateFuncName = onStateFuncName;
};
/*
* Lock a oCMobLockable
*/
func void LockMobLockable(var int mobPtr, var string keyInstance, var string pickLockStr, var int locked){
if (!Hlp_Is_oCMobLockable(mobPtr)){
MEM_Warn("Not a oCMobLocable!");
return;
};
var oCMobLockable mob; mob = _^(mobPtr);
mob.keyInstance = keyInstance;
mob.pickLockStr = pickLockStr;
if (locked){
mob.bitfield = mob.bitfield | oCMobLockable_bitfield_locked;
};
};
/*
* Create contents of oCMobContainers by string
*/
func void FillMobContainer(var int mobPtr, var string contents){
if (!Hlp_Is_oCMobContainer(mobPtr)){
MEM_Warn("Not a oCMobContainer!");
return;
};
const int oCMobContainer__CreateContents_G1 = 6832208; //0x684050
const int oCMobContainer__CreateContents_G2 = 7496080; //0x726190
var int contentsPtr; contentsPtr = _@s(contents);
const int call = 0;
if (CALL_Begin(call)){
CALL_PtrParam(_@(contentsPtr));
CALL__thiscall(_@(mobPtr), MEMINT_SwitchG1G2(oCMobContainer__CreateContents_G1,
oCMobContainer__CreateContents_G2));
call = CALL_End();
};
};
Hier ist noch ein Tipp zur Benutzung. Ich habe ein kleines Skript geschrieben, das die Trafo-Matrix vom Helden, dem Fokusvob oder einem Vob nach Name formatiert auf dem zSpy ausgibt. Das ganz sehr nützlich sein, um schnell an vernünftige Koordinaten um Einfügen von Vobs heranzukommen.
Spoiler:(zum lesen bitte Text markieren)
Code:
/*
* Print the current trafo-matrix to zSpy
*//*
* Send readable trafo of vob to zSpy
*/
func void printTrafo(var int vobPtr){
if (!vobPtr){
return;
};
var zCVob vob; vob = _^(vobPtr);
MEM_Info(ConcatStrings("Print trafo of ", vob._zCObject_objectname));
var int s; s = SB_New();
repeat(i, 4); var int i;
SB(" ");
repeat(j, 4); var int j;
SBf(MEM_ReadStatArr(_@(vob.trafoObjToWorld), j+i*4));
if (j+i*4 != 15){
SB(", ");
};
end;
MEM_Info(SB_ToString());
SB_Clear();
end;
SB_Destroy();
};
/*
* Console command for hero trafo
*/
func string CC_PrintTrafoHero(var string _){
printTrafo(_@(hero));
return "Trafo sent to zSpy";
};
func void CC_PrintTrafoHeroInit(){
CC_Register(CC_PrintTrafoHero, "print trafo hero", "Send the trafo coordinates of the hero to the zSpy");
};
/*
* Console command for focus trafo
*/
func string CC_PrintTrafoFocus(var string _){
var oCNpc her; her = Hlp_GetNpc(hero);
printTrafo(her.focus_vob);
return "Trafo sent to zSpy";
};
func void CC_PrintTrafoFocusInit(){
CC_Register(CC_PrintTrafoFocus, "print trafo focus", "Send the trafo coordinates of the focus vob to the zSpy");
};
/*
* Console command for trafo by vob name
*/
func string CC_PrintTrafoVobByName(var string vobname){
var int vobPtr; vobPtr = MEM_SearchVobByName(vobName);
if (!vobPtr){
return "Vob not found";
};
printTrafo(vobPtr);
return "Trafo sent to zSpy";
};
func void CC_PrintTrafoVobByNameInit(){
CC_Register(CC_PrintTrafoVobByName, "print trafo vob ", "Send the trafo coordinates by vob name to the zSpy");
};
Initialisieren der Konsolenbefehle in der der Init_Global mit:
Mir ist aufgefallen, dass das InsertAnything-Skript fehlerhaft ist. Unter gewissen Umständen gehen Vobs nach Speichern und Laden verloren.
Kannst du ausführen was für Umstände das sind?
Beim Wechsel zum neuen Skript verliert man leider einige der nützlichen Hilfsfunktionen die im alten Skript drin sind, im Scriptbin einfach ersetzten ist daher eventuell nicht ideal.
Nicht genau. Bei mir kam es bei Verwendung dazu, dass Vobs, die ich mit InsertVobAt eingefügt hatte, nach dem Spielladen mit Fehlermeldungen nicht mehr da waren. Ich vermute stark, dass es mit der Allokation von deren Speicher zusammenhing.
Das war seitens des Skripts übernommen und wird im neuen Skript jetzt von Gothic selbst verwaltet.
Zitat von Cryp18Struct
Beim Wechsel zum neuen Skript verliert man leider einige der nützlichen Hilfsfunktionen die im alten Skript drin sind, im Scriptbin einfach ersetzten ist daher eventuell nicht ideal.
Rückwärtskompatibilität habe ich aufgegeben, nachdem ich bemerkt habe, dass mehrere der Funktionen fehlerhaft waren (z.B. LevelVec) und ich wollte die Anzahl der Funktionsparameter verringern, sodass ich irgendwann mehr oder weniger von null gestartet bin, wodurch einige Funktionen einfach nicht mehr notwendig waren.
Gibt es bestimmte Funktionen die du vermisst? Sicher kann ich die dort wieder irgendwie einbauen.
Gibt es bestimmte Funktionen die du vermisst? Sicher kann ich die dort wieder irgendwie einbauen.
Unter der Annahme das es keine Probleme gibt(und mir sind keine aufgefallen):
RemoveoCVobSafe/RemovezCVobSafe sind sehr praktisch. Sollte jeder haben. Und passt auch thematisch: wenn man dynamisch Objekte erzeugt kommt es bestimmt auch vor das man sie löschen möchte.
Unter der Annahme das es keine Probleme gibt(und mir sind keine aufgefallen):
RemoveoCVobSafe/RemovezCVobSafe sind sehr praktisch. Sollte jeder haben. Und passt auch thematisch: wenn man dynamisch Objekte erzeugt kommt es bestimmt auch vor das man sie löschen möchte.
Vobs löschen ging schon die ganze Zeit mit den "Basis"-Skripten von Ikarus. Dort gibt es eine Funktion MEM_DeleteVob. Das wusste ich zu dem Zeitpunkt nicht und hatte sie selbst noch einmal erstellt.
Die anderen Funktionen, die du erwähnt hast, kann ich wieder (etwas verbessert) aufnehmen. Das schaue ich mir dann in den nächsten Tagen an. Die PileOf*-Funktionen waren eine Spielerei, die im Grunde nur x Items/Vobs mit zufälligem Radius y um eine Position z einfügen. Kann ich aber auch wieder mit reinnehmen.
Ich habe das Skript oben (u.a.) mit folgenden Funktionen ergänzt.
Code:
func int GetGroundLvlPos(int posPtr)
func int GetGroundLvl (int trafoPtr)
func void GetTrafoFromWP(string waypoint, int trafoPtr)
func void SetWPToFloor (int wpPtr)
func int InsertItem(string scriptInst, int amount, int trafoPtr)
func void InsertPileOf (string class, string objName, string visual, int trafoPtr, int amount, int cm2, int rotate)
func void InsertPileOfVobs ( string objName, string visual, int trafoPtr, int amount, int cm2, int rotate)
func void InsertPileOfItems( string scriptInst, int trafoPtr, int amount, int cm2, int rotate)
EDIT: Ich habe die Funktion SetVobToFloor verschönert; Vobs schliessen jetzt tatsächlich am Boden an und schweben nicht mehr 4cm darüber.