Obiecany skrypt dzieki któremu w G1 Npc mogą odrazu padać martwi + mój lekko zmodyfikowany HookEngine do G1:
HookEngine.d (parsować w gothic.src gdzies zaraz po Ikarus.d)
Spoiler
/****************************************************\
* ENGINEHOOKS *
* Dieses kleine Paket erlaubt Daedalusfunktionen *
* an Enginefunktionen zu hängen und somit Zugriff *
* auf bestimmte Vorgänge außerhalb der Scripte zu *
* bekommen. *
* Beispiel: Man könnte einen Hook an die Speicher- *
* funktion der Engine setzen und damit strings die *
* regulär nicht gespeichert werden noch schnell in *
* bspw. den Namen eines zCVob legen um sie zu be- *
* halten. *
\****************************************************/
//-------------------
// OPCODES
//-------------------
/* 1 Byte */
const int ASMINT_OP_pusha = 96; //0x60
const int ASMINT_OP_popa = 97; //0x61
const int ASMINT_OP_movMemToEAX = 161; //0xA1
/* 2 Byte */
const int ASMINT_OP_movECXtoEAX = 49547; //0xC18B
const int ASMINT_OP_movESPtoEAX = 50315; //0xC48B
const int ASMINT_OP_movEAXtoECX = 49545; //0xC189
const int ASMINT_OP_movEBXtoEAX = 55433; //0xD889
const int ASMINT_OP_movEBPtoEAX = 50571; //0xC58B
//-------------------
// KONSTANTEN
//-------------------
const int parser = ContentParserAddress; //0xAB40C0 zCParser
const int zParser__CallFunc = 7247504; //0x6E9690 CallFunc(int,...)
//-------------------
// Hooks varibles
//-------------------
var int HookEngine_Hook_PreUnconscious_JmpAdress; //Where jmp adress is placed rite now;
var int HookEngine_Hook_PreDropVob_JmpAdress;
var string HooksReinited;
//-------------------
// RÜCKGABEVARIABLEN
//-------------------
var int EAX;
func int GetEAX() { return EAX; };
func int EAXAdr() {
GetEAX();
MEMINT_StackPopInst();
MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
};
var int ECX;
func int GetECX() { return ECX; };
func int ECXAdr() {
GetECX();
MEMINT_StackPopInst();
MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
};
var int ESP;
func int GetESP() { return ESP; };
func int ESPAdr() {
GetESP();
MEMINT_StackPopInst();
MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
};
var int EBX;
func int GetEBX() { return EBX; };
func int EBXAdr() {
GetEBX();
MEMINT_StackPopInst();
MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
};
var int EBP;
func int GetEBP() { return EBP; };
func int EBPAdr() {
GetEBP();
MEMINT_StackPopInst();
MEMINT_StackPushInst(zPAR_TOK_PUSHINT);
};
/*============================*
/* HOOKENGINE *
/*============================*
- address: Addresse einer Enginefunktion an die die Funktion angehängt werden soll.
- oldInstr: Die Länge in Bytes der Anweisung die an 'address' zu finden ist, mindestens 5 Bytes (Notfalls nächste Zeile noch mitnehmen).
Kann zB. in IDA nachgesehen werden.
- function: Die Daedalusfunktion die aufgerufen werden soll.
*/
const int SKIP_INSTR = 0;
const int COPY_INSTR = 1;
func int HookEngine(var int address, var int oldInstr, var string function,var int skipInstr) {
var int SymbID; // Symbolindex von 'function'
var int ptr; // Pointer auf den Zwischenspeicher der alten Anweisung
var int relAdr; // Relative Addresse zum neuen Assemblercode, ausgehend von 'address'
var int HookEngine_JmpAdr;
// ----- Sicherheitsabfragen -----
if(oldInstr < 5) {
PrintDebug("HOOKENGINE: oldInstr ist zu kurz. Es werden mindestens 5 Bytes erwartet.");
return -1;
};
SymbID = MEM_FindParserSymbol(function);
if(!SymbID) {
PrintDebug("HOOKENGINE: Die gegebene Daedalusfunktion kann nicht gefunden werden.");
return -1;
};
MemoryProtectionOverride (address, oldInstr+3);
// ----- Eventuell geschützen Speicher behandeln -----
// ----- Die alte Anweisung sichern -----
ptr = MEM_Alloc(oldInstr);
MEM_CopyBytes(address, ptr, oldInstr);
// ----- Einen neuen Stream für den Assemblercode anlegen -----
ASM_Open(100 + oldInstr);
// ----- Jump aus der Enginefunktion in den neuen Code einfügen -----
relAdr = ASMINT_CurrRun-address-5;
MEM_WriteInt(address + 0, 233);
MEM_WriteInt(address + 1, relAdr);
// ----- Neuen Assemblercode verfassen -----
// Alle Register sichern
// EAX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(EAXAdr());
ASM_1(ASMINT_OP_pusha);
// ECX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movECXtoEAX);
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(ECXAdr());
// ESP in Daedalus Variable sichern
ASM_2(ASMINT_OP_movESPtoEAX);
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(ESPAdr());
// EBX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEBXtoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(EBXAdr());
// EBP in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEBPtoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(EBPAdr());
// --- Daedalusfunktion aufrufen ---
ASM_1(ASMINT_OP_pushIm);
ASM_4(SymbID);
ASM_1(ASMINT_OP_pushIm);
ASM_4(parser);
ASM_1(ASMINT_OP_call);
ASM_4(zParser__CallFunc-ASM_Here()-4);
ASM_2(ASMINT_OP_addImToESP);
ASM_1(8);
ASM_1(ASMINT_OP_popa);
ASM_1(ASMINT_OP_movMemToEAX);
ASM_4(ECXAdr());
ASM_2(ASMINT_OP_movEAXtoECX);
ASM_1(ASMINT_OP_movMemToEAX);
ASM_4(EAXAdr());
// Alte Anweisung wieder einfügen
if(skipInstr == COPY_INSTR)
{
MEM_CopyBytes(ptr, ASMINT_Cursor, oldInstr);
//printdebug_s_i("HOOKENGINE: ASMINT_Cursor(oldinstr):",ASMINT_Cursor);
ASMINT_Cursor += oldInstr;
};
MEM_Free(ptr);
// Engine function to return
ASM_1(ASMINT_OP_pushIm);
HookEngine_JmpAdr = ASMINT_Cursor;
ASM_4(address + oldInstr);
ASM_1(ASMINT_OP_retn);
ASM_Close();
return HookEngine_JmpAdr;
};
W pliku startup.d musimy mieć funkcje która wywołuje się z INITów każdego z używanych światów (czyli np. Init_World/Init_OldMine itd.)
Dopisujemy tam:
//Engine Hook's:
if(!Hlp_StrCmp(HooksReinited, "Yes"))
{
HooksReinited="Yes";
HookEngine_Hook_PreUnconscious_JmpAdress = HookEngine(7630776,6,"HOOK_PREUNCONSCIOUS",COPY_INSTR);
//HookEngine_Hook_PreDropVob_JmpAdress = HookEngine(7023277,5,"HOOK_PREDROPVOB",COPY_INSTR);
};
Na koniec sam własciwy skrypt który dodajemy w AI_Inter/ZS_Human/ZS_Unconscious.d:
Spoiler
//Funkcja warunkowa
// -false oCNpc slf będzie odrazu martwy
// -true oCNpc slf upadnie na ziemie
// warunki dowolne
// obawiam się ze moga wydarzyć się wypadki gdy oth nie jest wcale
// oCNPC a jedynie cymś zupełnie losowym, wiec lepiej używać tego ostrożnie!
func int Npc_CanBeUnconscious(var oCNpc slf,var oCNpc oth)
{
if((slf.variousFlags & NPC_FLAG_INSTANTDEATH) != false)
||((oth.variousFlags & NPC_FLAG_KILLER) != false)
{
return FALSE;
};
return TRUE;
};
//Hook caled before oCNpc_DropUnconscious
func void HOOK_PREUNCONSCIOUS()
{
var oCNpc npc; var oCNpc oth;
//ECX to oCNPC wiec ECX+0x100 to C_NPC (taki cast nie działa, calość oparta na oCNPC
MEM_AssignContentInst (npc,GetECX());
MEM_AssignContentInst (oth,GetESP()+128);
//Npc_ClearAiQueue(self) -> but in oCNPC way ;-)
CALL__thiscall (MEM_InstToPtr(npc), oCNpc__ClearEM_offset);
CALL__thiscall (npc.anictrl, oCAniCtrl_Human_StopTurnAnis_offset);
if(Npc_CanBeUnconscious(npc,oth))
{//Npc Normalnie upada na ziemie
MEM_WriteInt(HookEngine_Hook_PreUnconscious_JmpAdress,7630776+6);
}
else
{//Npc odrazu umiera (7630776 = 1 arg. wywolania HookEngine w Startup + 6 = 2 arg. wywołania
MEM_WriteInt(HookEngine_Hook_PreUnconscious_JmpAdress,7632080);
};
};
Jak widać skorzystałem z dwóch flag dla npc, które w mojej wersji trzeba dopisywać by npc odrazu padał/zabijał innych.
Trzeba je dodać w _Intern/constants.d
CONST INT NPC_FLAG_INSTANTDEATH = 1 << 2 ;//Npc dies instantly
CONST INT NPC_FLAG_KILLER = 1 << 4 ;//Npc kills enemies instantly
Będzie potrzebne kilka adresów funkcji ja daje wszystkie które do tej pory znalazłem, do wklejenia gdzieś w Ikarus_Const_G1.d
Spoiler
const int zCView_zCView_offset = 7322464; //0x6FBB60 (void)
const int zCView_InsertItem_offset = 7347872; //0x701EA0 (zcview*,int)
const int zCView_RemoveItem_offset = 7348448; //0x7020E0 (zcview*)
const int zCView_Init_offset = 7324512; //0x6FC360 stdcall(void) /returns zCView*?
const int zCView_Create_offset = 7324512; //0x6FCC90 thiscall(string&,enum,enum,float,int)
const int zCView_SetPos_offset = 7330320; //0x6FDA10 thiscall(int,int)
const int zCView_SetSize_offset = 7330816; //0x6FDC00 thiscall(int,int)
const int zCView_Open_offset = 7327856; //0x6FD070 thiscall(void)
const int zCView_Close_offset = 7328400; //0x6FD290 thiscall(void)
const int zCView_Render_offset = 7349744; //0x7025F0 thiscall(void)
const int zCView_SetAlphaBlendFunc_offset = 7325056; //0x6FC580 thiscall(enum)
const int zCView_SetTransparency_offset = 7325040; //thiscall(int)
const int zCView_InsertBack_offset = 7325248; //thiscall(&string)
const int zCView_CreateText_offset = 7341792; //0x7006E0 thiscall(int, int, class zSTRING const &)
const int zCView_CalcPixelPos_offset = 7330528; //0x6FDAE0 thiscall(px,py)
const int zCView_GetPixelPos_offset = 7330592; //6FDB20 thiscall(px,py)
const int zCView_SetFontColor_offset = 7339392; //6FFD80 thiscall(zCColor)
const int zCView_SetFont_offset = 7339408; //6FFD90 thiscall(string font)
const int zCViewStatusBar_SetValue_offset = 4629600; // (float)
const int zCViewStatusBar_Init_offset = 4629200; // 0x46A2D0 (void)
const int oCViewStatusBar_SetMaxRange_offset = 4432176; // (float,float)
const int oCViewStatusBar_SetRange_offset = 4432448; //0x46A3C0 (float,float))
const int oCViewStatusBar_SetValue_offset = 4432640; //43A300 (char)
const int zCMenuItem__SetText_offset = 5063504; //0x4D4350 (*ZStr,line,now?) /Crashing on updatesize???
const int zCMenuItem__DrawFront_offset = 5065040;//0x4D4950 ()
const int zCInput_SetState_offset = 4991120; //43A300 (char,char)
const int oCAniCtrl_Human_SetAlwaysWalk_offset = 6436576; //6236E0 (state)
const int oCAniCtrl_Human_ToggleWalkMode_offset = 6442544; //(char?)
const int oCAniCtrl_Human_PC_SlowMove_offset = 6373952; //0x614240(int?)
const int oCAniCtrl_Human_IsStanding_offset = 6444512;//0x6255E0 (void)
const int oCAniCtrl_Human_IsWalking_offset = 6445024;//0x6255E0 (void)
const int oCAniCtrl_Human_IsStateAniActive_offset = 6444304;//0x6255E0 (void)
const int oCAniCtrl_Human_GetWalkModeString_offset = 6432560;// (void) ret string
const int oCAniCtrl_Human_StopTurnAnis_offset = 6445600; //0x625A20 (void)
const int zCAniCtrl_StartAni_offset = 6404000;//0x61B7A0 (oCModelAni*,oCModelAniNxt)
const int JUMPUP_AniID = 4180;
const int zCModel_StartAni_offset = 5640944;//0x5612F0 (oCModelAni*,layer?)
const int zCModel_RemoveChildVobFromNode_offset = 5662496;//0x566721 (oCVob*)
const int zCModel_AttachChildVobToNode_offset = 5662128;//0x5665B0 (oCVob*,*Node)
const int zCVob_RotateWorldY_offset = 6218528;//0x5EE320 (float)
const int zCRnd_D3D__SetBilerpFilterEnable_offset = 7445792;//(int)
const int zCRnd_D3D__GetBilerpFilterEnable_offset = 7445920;//(void)
const int zCRnd_D3D__SetFog_offset = 7445360;//719B70 (int foggy?)
const int zCRnd_D3D__SetFogRange_offset = 7445600;//0719C60 (float nearz,float farz, int falloff/fogmode?)
const int oCNpc__CloseDeadNpc_offset = 7060128;//(void)
const int oCNpc__CloseInventory_offset = 7058160;//(void)
const int oCNpc__RenderNpc_offset = 6940528;//0x69E770 (zcView*)
const int oCNpc__RemoveFromSlot_offset = 6971216;//0x6A5F50 (*TNpcSlot,drop_bool)
const int oCNpc__StringRemoveFromSlot_offset = 6971008;//0x6A5E80 (*TNpcSlot,drop_bool)
const int oCNpc__DropFromSlot_offset = 6972016;//0x6A6270 (*TNpcSlot)
const int oCNpc__DoDropVob_offset = 6951152;//0x6A10F0 (*zCVob)
const int oCNpc__DoSwapMesh_offset = 6947120;//0x6A0130 (ZString node1, zString node2)
const int oCNpc__SetTorchAni_offset = 6914064;//0x0698010 (int f, int now)
const int oCNpc__DoExchangeTorch_offset = 6952576;//0x06A1680 (void)
const int oCNpc__PutInSlot_offset = 6969872;//0x6A5A10 (*TNpcSlot,oCVob)
const int oCNpc__PutInRightHand_offset = 6913472;//0x697DC0 (*oCVob)
const int oCNpc__Equip_offset = 6908144;//0x6968F0 (*oCItem)
const int oCNpc__Disable_offset = 6954272;//0x6A1D20 ()
const int oCNpc__ai_disabled_adress = 9288604;//bool?
const int oCNpc__ai_messagesSkip_adress = 9288608;//zfloat
const int oCNpc__ai_ScriptStatesSkip_adress = 9288616;//zfloat
const int oCNpc__game_aicon_baseAIenabled_adress = 9283196;//int
const int oCNpc__game_aicon_messagesSkip_adress = 9283200;//int
const int oCNpc__SetAsPlayer_offset = 6941408;//0x69EAE0 ()
const int oCNpc__GetScriptInstance_offset = 6953920;//06A1BC0 (zString instance,int id)
const int oCNpc__CreateVobList_offset = 7041296;//6B7110 (float distance)
const int oCNpc__ClearVobList_offset = 7040688;//6B6EB0 ()
const int oCNpc__DoDie_offset = 6894752;//6934A0 (ocNpc attacker)
const int oCNpc__StartFadingAway_offset = 6895984;//0x693970 (void)
const int oCNpc__ClearEM_offset = 6956560;//0x6A2610 (void)
const int oCNpc__DropUnconscious_offset = 6892560;//692C10 (float azi,ocNpc attacker)
const int oCGame__SetAsPlayer_offset = 6542288;//0x63D3D0 (InstanceID string)
const int oCGame__TriggerChangeLevel_offset = 6542464;//0x63D480 (zen_name,wpname)
const int oCTriggerChangeLevel__oCTriggerChangeLevel_offset = 4424256;// (void)
const int oCTriggerChangeLevel__SetLevelName_offset = 4425392;// (zen_name,wpname)
const int oCTriggerChangeLevel__TriggerTarget_offset = 4424560;//0x438370 (vob caller)
const int oCWorld__SearchVobByName_adress = 7173120;// (zString,?,?)
const int zMDL_MAX_FPS = 8208616;//int
const int oCItem__oCitem_offset = 6754208;//0x0670FA0 (zString,int)
const int zCZone__GetCamPosWeight_offset = 6339472;//0x060BB90 (void) ret zFloat
const int zCZoneZFog__GetActiveRange_offset = 6340656;//0x060C030 (void) ret zFloat
const int TNpcSlot__SetVob_offset = 6857884;//0x68A49C (*oCVob)
const int TNpcSlot__ClearVob_offset = 6876768;//0x68EE60 (void)
const int zCTexture__SearchName_offset = 6064544;//_cdecl (zString*)
const int zCTexture__LoadSingle_offset = 6064544;//_cdecl (zString*,int flags)//Needed if tex is still unused (SearchName won't be working)
const int zCPolygon_TexScale_offset = 5868192;//598AA0 thiscall (float,float)
const int zCPolygon_Flip_offset = 5867872;//598960 thiscall (void)
const int zCMesh_Load_offset = 5570976;//5501A0 cdecl (*zString)
const int zCMaterial__SetTexScale_offset = 5562336;// (float,float)
const int zCMaterial__SetTex_offset = 5561024;//0x54DAC0 (zString)
const int oCSkyController_SkyVari_int = 9235392;//0=poly/1=dome (???)
const int oCSkyController_SkyDomeTex_adr = 9235264;//??
const int oCSkyController_SkyMesh_adr = 9235380;//??ptr?
const int oCSkyController_SkyOffset_adr = 9235024;//?
const int oCSkyController_SkyRainCloudsStr_adr = 8660092;//"SKYRAINCLOUDS.TGA"
const int Apply_Options_Control = 4371792; //42B550 cdecl
const int zCInput_Class_ptr = 8834208;//86CCA0;
const int zCInput__BindKeys = 5003568;//(void)
Gdyby były jakieś problemy mogę pomóc, oczywiscie wymagane jakieś dokładniejsze opisy niż
"Eeee... mi to to nie działa."
Jeżeli zamierzacie użyć tego skryptu wypadałoby wspomnieć o jego autorze, lub modyfikacji którą tworzy.