Den toten Goblins von den Waffen befreien [Bugfix]
Ich habe einen kleinen Fix bauen wollen, damit tote Goblins nach dem Laden nicht erneut wieder ihre Waffen an der Hand halten.
Das sieht folgendermaßen aus: Beim Tod soll der Fightmode zurückgesetzt bzw geändert wird, der in der npc instance anfangs festgelegt wird. Das stellte sich aber wohl als nicht so einfach heraus.
In this topic, you can download a fix for goblins and skeletons-goblin. I also attach the code for Union, maybe someone wants to transfer it to ikarus+lego, the point is to find and remove weapons from the right-hand slot.
In this topic, you can download a fix for goblins and skeletons-goblin. I also attach the code for Union, maybe someone wants to transfer it to ikarus+lego, the point is to find and remove weapons from the right-hand slot.
.....
I translated this code to daedalus/Ikarus/LeGo
But it only works AFTER the inital loading of the game. This is due to me not knowing how to run hooks earlier than Startup.d (Is there something that can be run on initial menu creation?)
Also it is currently only for Gothic 2 NotR. You'd need to find the correct addresses for G1 and put them in place (i created the empty Constants for G1 which just need to point to the correct function, and remove guild-checks for non existing creatures in G1)
Spoiler:(zum lesen bitte Text markieren)
Code:
/*
pNpc_Unarchive(_this, ar);
if (_this && (_this->guild == NPC_GIL_GOBBO || _this->guild == NPC_GIL_GOBBO_SKELETON || _this->guild == NPC_GIL_SUMMONED_GOBBO_SKELETON) && _this->attribute[NPC_ATR_HITPOINTS] == 0)
{
zCModel* pModel = _this->GetModel();
if (!pModel)
return;
zCModelNodeInst* pNodeInst = pModel->SearchNode(NPC_NODE_RIGHTHAND);
if (!pNodeInst)
return;
pModel->SetNodeVisual(pNodeInst, NULL, FALSE);
}
*/
func int oCNpc_GetModel(var int _this) {
const int oCNpc__GetModel_G1 = 0; // 0
const int oCNpc__GetModel_G2 = 7571232; // 0x00738720
const int call = 0;
if (CALL_Begin(call)) {
CALL_PutRetValTo(_@(retVal));
CALL__thiscall(_@(_this), MEMINT_SwitchG1G2(oCNpc__GetModel_G1, oCNpc__GetModel_G2));
call = CALL_End();
};
var int retVal;
return retVal;
};
/// Sucht eine Node eines zCModel.
/// ____
/// Gültige nodeName Werte:
/// ```
/// "ZS_RIGHTHAND", "ZS_LEFTHAND"
/// "ZS_SWORD", "ZS_LONGSWORD"
/// "ZS_BOW", "ZS_CROSSBOW"
/// "ZS_SHIELD", "ZS_HELMET"
/// "ZS_JAWS"
/// ```
func int zCModel_SearchNode(var int _this, var string nodeName) {
const int zCModel__SearchNode_G1 = 0; // 0
const int zCModel__SearchNode_G2 = 5758960; // 0x0057DFF0
CALL_zStringPtrParam(nodeName);
CALL__thiscall(_this, MEMINT_SwitchG1G2(zCModel__SearchNode_G1, zCModel__SearchNode_G2));
var int retVal; retVal = CALL_RetValAsInt();
return retVal;
};
func int zCModel_SetNodeVisual(var int _this, var int nodePtr, var int visualPtr, var int animated) {
const int zCModel_SetNodeVisual_G1 = 0; // 0
const int zCModel_SetNodeVisual_G2 = 5739168; // 0x005792A0
const int call = 0;
if (CALL_Begin(call)) {
CALL_IntParam(_@(animated));
CALL_IntParam(_@(visualPtr));
CALL_IntParam(_@(nodePtr));
CALL__thiscall(_@(_this), MEMINT_SwitchG1G2(zCModel_SetNodeVisual_G1, zCModel_SetNodeVisual_G2));
call = CALL_End();
};
var int retVal;
return retVal;
};
func void _Fix_GoblinClubs_NpcUnarchive_Hook() {
var int _this; _this = EBP;
if (!_this) { return; };
var C_Npc _thisNpc; _thisNpc = _^(_this);
if (
!(_thisNpc.guild == GIL_GOBBO
|| _thisNpc.guild == GIL_GOBBO_SKELETON
|| _thisNpc.guild == GIL_SUMMONED_GOBBO_SKELETON )
) { return; };
if (_thisNpc.attribute[ATR_HITPOINTS] != 0) { return; };
var int pModel; pModel = oCNpc_GetModel(_this);
if (!pModel) { return; };
var int pNodeInst; pNodeInst = zCModel_SearchNode(pModel, "ZS_RIGHTHAND");
if (!pNodeInst) { return; };
zCModel_SetNodeVisual(pModel, pNodeInst, 0, FALSE);
};
func void Fix_GoblinClubs_Init() {
const int oCNpc__Unarchive_End_G1 = 0; // 0x0
const int oCNpc__Unarchive_End_G2 = 7636622; // 0x0074868E
const int once = TRUE;
if (once) {
HookEngineF(MEMINT_SwitchG1G2(oCNpc__Unarchive_End_G1, oCNpc__Unarchive_End_G2), 7, _Fix_GoblinClubs_NpcUnarchive_Hook);
once = FALSE;
};
};
EDIT:
Es wäre deutlich leichter, beim Tod eines Goblins die aktive Waffe als "Nicht aktiv" zu kennzeichnen. (ACTIVE flag entfernen: oCItem.flags & ~(ITEM_ACTIVE_LEGO) ) das "könnte" auch funktionieren.
Also über das Inventar gucken und allen items das Flag für ACTIVE entziehen.
But it only works AFTER the inital loading of the game. This is due to me not knowing how to run hooks earlier than Startup.d (Is there something that can be run on initial menu creation?)
Also it is currently only for Gothic 2 NotR. You'd need to find the correct addresses for G1 and put them in place (i created the empty Constants for G1 which just need to point to the correct function, and remove guild-checks for non existing creatures in G1)
Spoiler:(zum lesen bitte Text markieren)
Code:
/*
pNpc_Unarchive(_this, ar);
if (_this && (_this->guild == NPC_GIL_GOBBO || _this->guild == NPC_GIL_GOBBO_SKELETON || _this->guild == NPC_GIL_SUMMONED_GOBBO_SKELETON) && _this->attribute[NPC_ATR_HITPOINTS] == 0)
{
zCModel* pModel = _this->GetModel();
if (!pModel)
return;
zCModelNodeInst* pNodeInst = pModel->SearchNode(NPC_NODE_RIGHTHAND);
if (!pNodeInst)
return;
pModel->SetNodeVisual(pNodeInst, NULL, FALSE);
}
*/
func int oCNpc_GetModel(var int _this) {
const int oCNpc__GetModel_G1 = 0; // 0
const int oCNpc__GetModel_G2 = 7571232; // 0x00738720
const int call = 0;
if (CALL_Begin(call)) {
CALL_PutRetValTo(_@(retVal));
CALL__thiscall(_@(_this), MEMINT_SwitchG1G2(oCNpc__GetModel_G1, oCNpc__GetModel_G2));
call = CALL_End();
};
var int retVal;
return retVal;
};
/// Sucht eine Node eines zCModel.
/// ____
/// Gültige nodeName Werte:
/// ```
/// "ZS_RIGHTHAND", "ZS_LEFTHAND"
/// "ZS_SWORD", "ZS_LONGSWORD"
/// "ZS_BOW", "ZS_CROSSBOW"
/// "ZS_SHIELD", "ZS_HELMET"
/// "ZS_JAWS"
/// ```
func int zCModel_SearchNode(var int _this, var string nodeName) {
const int zCModel__SearchNode_G1 = 0; // 0
const int zCModel__SearchNode_G2 = 5758960; // 0x0057DFF0
CALL_zStringPtrParam(nodeName);
CALL__thiscall(_this, MEMINT_SwitchG1G2(zCModel__SearchNode_G1, zCModel__SearchNode_G2));
var int retVal; retVal = CALL_RetValAsInt();
return retVal;
};
func int zCModel_SetNodeVisual(var int _this, var int nodePtr, var int visualPtr, var int animated) {
const int zCModel_SetNodeVisual_G1 = 0; // 0
const int zCModel_SetNodeVisual_G2 = 5739168; // 0x005792A0
const int call = 0;
if (CALL_Begin(call)) {
CALL_IntParam(_@(animated));
CALL_IntParam(_@(visualPtr));
CALL_IntParam(_@(nodePtr));
CALL__thiscall(_@(_this), MEMINT_SwitchG1G2(zCModel_SetNodeVisual_G1, zCModel_SetNodeVisual_G2));
call = CALL_End();
};
var int retVal;
return retVal;
};
func void _Fix_GoblinClubs_NpcUnarchive_Hook() {
var int _this; _this = EBP;
if (!_this) { return; };
var C_Npc _thisNpc; _thisNpc = _^(_this);
if (
!(_thisNpc.guild == GIL_GOBBO
|| _thisNpc.guild == GIL_GOBBO_SKELETON
|| _thisNpc.guild == GIL_SUMMONED_GOBBO_SKELETON )
) { return; };
if (_thisNpc.attribute[ATR_HITPOINTS] != 0) { return; };
var int pModel; pModel = oCNpc_GetModel(_this);
if (!pModel) { return; };
var int pNodeInst; pNodeInst = zCModel_SearchNode(pModel, "ZS_RIGHTHAND");
if (!pNodeInst) { return; };
zCModel_SetNodeVisual(pModel, pNodeInst, 0, FALSE);
};
func void Fix_GoblinClubs_Init() {
const int oCNpc__Unarchive_End_G1 = 0; // 0x0
const int oCNpc__Unarchive_End_G2 = 7636622; // 0x0074868E
const int once = TRUE;
if (once) {
HookEngineF(MEMINT_SwitchG1G2(oCNpc__Unarchive_End_G1, oCNpc__Unarchive_End_G2), 7, _Fix_GoblinClubs_NpcUnarchive_Hook);
once = FALSE;
};
};
EDIT:
Es wäre deutlich leichter, beim Tod eines Goblins die aktive Waffe als "Nicht aktiv" zu kennzeichnen. (ACTIVE flag entfernen: oCItem.flags & ~(ITEM_ACTIVE_LEGO) ) das "könnte" auch funktionieren.
Also über das Inventar gucken und allen items das Flag für ACTIVE entziehen.
Ob das funktioniert ... müsste man prüfen
Warum const int once = TRUE;? Das wird von Gothic nicht erkannt.
Code:
var int once;
if (once == FALSE) {
HookEngineF(MEMINT_SwitchG1G2(oCNpc__Unarchive_End_G1, oCNpc__Unarchive_End_G2), 7, _Fix_GoblinClubs_NpcUnarchive_Hook);
once = TRUE;
Hab es so geändert, das scheint zu klappen. Und da das Problem mit dem Waffen auch erst nach dem laden auftritt, sollte das passen, oder?
Eher so, keine var
Code:
const int once = 1;
if (once)
{
HookEngineF(MEMINT_SwitchG1G2(oCNpc__Unarchive_End_G1, oCNpc__Unarchive_End_G2), 7, _Fix_GoblinClubs_NpcUnarchive_Hook);
once = 0;
};
Warum const int once = TRUE;? Das wird von Gothic nicht erkannt.
Code:
var int once;
if (once == FALSE) {
HookEngineF(MEMINT_SwitchG1G2(oCNpc__Unarchive_End_G1, oCNpc__Unarchive_End_G2), 7, _Fix_GoblinClubs_NpcUnarchive_Hook);
once = TRUE;
Hab es so geändert, das scheint zu klappen. Und da das Problem mit dem Waffen auch erst nach dem laden auftritt, sollte das passen, oder?
Interessant, ich benutze überall "const int once = TRUE;" für meine Hooks.
Das ist, damit der Hook nur einmal in der session passiert und keine var im savegame landet. Keine ahnung was passiert, oder ob überhaupt irgendwas passiert, wenn man es mit einer var macht.
Kannst ja auch einfach const int once = 1; machen, vielleicht ist in deinen Skripten "TRUE / FALSE" nicht als const sondern als var definiert :/
Wenn du das spiel startest und neben einem Toten goblin stehst, hat er die Waffe in der hand. Wenn du jetzt neu-lädst, ist die waffe weg.
Interessant, ich benutze überall "const int once = TRUE;" für meine Hooks.
Das ist, damit der Hook nur einmal in der session passiert und keine var im savegame landet. Keine ahnung was passiert, oder ob überhaupt irgendwas passiert, wenn man es mit einer var macht.
Wenn du das spiel startest und neben einem Toten goblin stehst, hat er die Waffe in der hand. Wenn du jetzt neu-lädst, ist die waffe weg.
True - False? Funktioniert glaub ich nur mit 1 und 0, weil es eine const ist.
Edit: Da waren wir wohl gleich schnell
Genau, beim Spiel Starten und laden haben sie die Waffen, nach erneutem Laden verschwinden sie.
But it only works AFTER the inital loading of the game. This is due to me not knowing how to run hooks earlier than Startup.d (Is there something that can be run on initial menu creation?)
Warum const int once = TRUE;? Das wird von Gothic nicht erkannt.
[...]
Hab es so geändert, das scheint zu klappen. Und da das Problem mit dem Waffen auch erst nach dem laden auftritt, sollte das passen, oder?
Das wird nicht funktionieren. So wird der Hook nur einmalig in der ersten Spielsession gesetzt, nach neu starten von Gothic aber dann nie wieder. Solche once-Konstrukte funktionieren nur mit Konstanten.
Zitat von Kirides
Interessant, ich benutze überall "const int once = TRUE;" für meine Hooks.
Das ist, damit der Hook nur einmal in der session passiert und keine var im savegame landet.
Mit einer Variable würde es nicht einmal pro Session sondern einmal pro Spielstand passieren, was wie oben beschrieben hinfällig ist.
Das once-Konstrukt im Zusammenhang mit Hooks ist veraltet und nicht länger nötig. Hooks werden seit geraumer Zeit nur noch einmal gesetzt. Am besten solltest du es komplett weg lassen, das macht alles leserlicher.
Das wird nicht funktionieren. So wird der Hook nur einmalig in der ersten Spielsession gesetzt, nach neu starten von Gothic aber dann nie wieder. Solche once-Konstrukte funktionieren nur mit Konstanten.
Mit einer Variable würde es nicht einmal pro Session sondern einmal pro Spielstand passieren, was wie oben beschrieben hinfällig ist.
Das once-Konstrukt im Zusammenhang mit Hooks ist veraltet und nicht länger nötig. Hooks werden seit geraumer Zeit nur noch einmal gesetzt. Am besten solltest du es komplett weg lassen, das macht alles leserlicher.
Naja in meinem fall sind in den Once abfragen immer auch weitere config auslese oder const-setz Dinge mit drin, welche nur einmal ausgeführt werden müssen.
Aber gut zu wissen mit den Hooks