Kann es passieren, dass NPC in einem Trialog weiter ihrem TA nachgehen, wenn sie gerade nicht sprechen / nicht self sind?
Das kann gut sein. Mit der Absicht zu beheben, dass eingeladene Gesprächspartner nach einem Dialog ihren TA nicht weiter ausführen und dem entsprechend auf nichts mehr reagieren, habe ich in den Trialogen womöglich einen Fehler eingebaut. (Das wäre also meine Schuld.)
Folgendes kannst du versuchen. Wenn das funktioniert, würde ich das gern im SVN übernehmen:
EDIT: Keine Änderungen notwendig, siehe hier und hier.
Spoiler:(zum lesen bitte Text markieren)
Änderungen als unified diff (grüne Zeilen werden hinzugefügt, rote gelöscht, betroffene Zeilennummern in grau).
Code:
--- _work/data/Scripts/Content/LeGo/Trialoge.d
+++ _work/data/Scripts/Content/LeGo/Trialoge.d
@@ -106,13 +106,7 @@
var string TRIA_Camera; // Läuft eine Kamerafahrt?
func void ZS_TRIA() {};
-func int ZS_TRIA_Loop() {
- if (InfoManager_hasFinished()) { // Im Zustand bleiben bis Dialog fertig
- return LOOP_END;
- } else {
- return LOOP_CONTINUE;
- };
-};
+func int ZS_TRIA_Loop() { return LOOP_CONTINUE; };
//========================================
// Npcs aufeinander warten lassen
@@ -386,7 +380,7 @@
var int p; p = MEM_StackPos.position;
if(i < TRIA_CPtr-1) {
var c_npc slf; slf = MEM_PtrToInst(MEM_ReadStatArr(TRIA_NpcPtr, i));
- //AI_ContinueRoutine(slf);
+ AI_ContinueRoutine(slf);
i += 1;
MEM_StackPos.position = p;
};
Komplette Trialoge.d
Spoiler:(zum lesen bitte Text markieren)
Code:
/***********************************\
TRIALOGE
\***********************************/
//========================================
// EquipWeapon von Sektenspinner
// Wer diese Funktion schon besitzt kann
// sie hier einfach auskommentieren
//========================================
/* EquipWeapon_TogglesEquip configure the behaviour
when trying to equip an already equipped weapon:
0: EquipWeapon will do nothing
1: EquipWeapon will unequip this weapon
*/
const int EquipWeapon_TogglesEquip = 1;
func void EquipWeapon (var C_NPC slf, var int ItemInst) {
if (!Npc_HasItems (slf, ItemInst)) {
CreateInvItems (slf, ItemInst, 1);
};
if (!Npc_GetInvItem(slf, ItemInst)) {
MEM_AssertFail("Unexpected behaviour in EquipWeapon.");
return;
};
if ((item.mainflag == ITEM_KAT_NF) && (Npc_HasReadiedMeleeWeapon(slf)))
|| ((item.mainflag == ITEM_KAT_FF) && (Npc_HasReadiedRangedWeapon(slf))) {
MEM_Warn ("EquipWeapon: Caller wants to equip a weapon while weapon of the same type is readied. Ignoring request.");
return;
};
if (item.flags & ITEM_ACTIVE_LEGO)
&& (!EquipWeapon_TogglesEquip) {
/* calling EquipWeapon would unequip the weapon. */
MEM_Info ("EquipWeapon: This weapon is already equipped. Ignoring request.");
return;
};
CALL_PtrParam(MEM_InstToPtr(item));
CALL__thiscall(MEM_InstToPtr(slf), oCNpc__EquipWeapon);
};
//========================================
// Hilfsfunktionen
//========================================
func int Npc_GetArmor(var c_npc slf) {
if(!Npc_HasEquippedArmor(slf)) { return -1; };
var c_item itm; itm = Npc_GetEquippedArmor(slf);
return Hlp_GetInstanceID(itm);
};
func int Npc_GetMeleeWeapon(var c_npc slf) {
if(!Npc_HasEquippedMeleeWeapon(slf)) { return 0; };
var c_item itm; itm = Npc_GetEquippedMeleeWeapon(slf);
return Hlp_GetInstanceID(itm);
};
func int Npc_GetRangedWeapon(var c_npc slf) {
if(!Npc_HasEquippedRangedWeapon(slf)) { return 0; };
var c_item itm; itm = Npc_GetEquippedRangedWeapon(slf);
return Hlp_GetInstanceID(itm);
};
//========================================
// Userkonstanten
//========================================
const int TRIA_MaxNPC = 256; // Wie viele Npcs nehmen maximal an einem Trialog teil?
//========================================
// Dialogkamera neu einstellen
//========================================
func void DiaCAM_Update() {
// Diese Funktion wurde von Sektenspinner niedergeschrieben.
if(InfoManager_HasFinished()) { return; };
var int aiCam; aiCam = MEM_ReadInt(zCAICamera__current);
CALL_IntParam(1);
CALL__thiscall(aiCam, zCAICamera_StartDialogCam);
};
//========================================
// Dialogkamera abschalten
//========================================
func void DiaCAM_Disable() {
MemoryProtectionOverride(zCAICamera__StartDialogCam, 4);
MEM_WriteInt(zCAICamera__StartDialogCam, 268436674); // retn 4
};
//========================================
// Dialogkamera einschalten
//========================================
func void DiaCAM_Enable() {
MemoryProtectionOverride(zCAICamera__StartDialogCam, 4);
MEM_WriteInt(zCAICamera__StartDialogCam, zCAICamera__StartDialogCam_oldInstr);
};
//========================================
// [intern] Variablen
//========================================
var int TRIA_NpcPtr[TRIA_MaxNPC]; // Sammlung aller Teilnehmer
var int TRIA_Running; // Läuft ein Trialog?
var int TRIA_CPtr; // Zähler für die Sammlung
var int TRIA_Last; // Der Npc der zuletzt gesprochen hat
var int TRIA_Self; // Pointer auf self
var string TRIA_Camera; // Läuft eine Kamerafahrt?
func void ZS_TRIA() {};
func int ZS_TRIA_Loop() { return LOOP_CONTINUE; };
//========================================
// Npcs aufeinander warten lassen
//========================================
func void TRIA_Wait() {
AI_WaitTillEnd(hero, self);
AI_WaitTillEnd(self, hero);
AI_WaitTillEnd(hero, self);
};
//========================================
// [intern] Visuals aktualisieren
//========================================
func void _TRIA_UpdateVisual(var c_npc slf, var int armor) {
var oCNpc npc; npc = Hlp_GetNpc(slf);
Mdl_SetVisualBody(slf, npc.body_visualName, (npc.bitfield[0]&oCNpc_bitfield0_body_TexVarNr)>>14, 0, npc.head_visualName, (npc.bitfield[1]&oCNpc_bitfield1_head_TexVarNr)>>16, 0, armor);
};
//========================================
// Angelegte Waffe tauschen
//========================================
func void Npc_TradeItem(var c_npc slf, var int itm0, var int itm1) {
if(itm0) {
EquipWeapon(slf, itm0);
Npc_RemoveInvItem(slf, itm0);
};
if(itm1) {
CreateInvItem(slf, itm1);
EquipWeapon(slf, itm1);
};
};
//========================================
// [intern] Npcs kopieren
//========================================
class _TRIA_fltWrapper {
var float f0;
var float f1;
var float f2;
var float f3;
};
func void _TRIA_Copy(var int n0, var int n1) {
var c_npc np0; np0 = MEM_PtrToInst(n0);
var c_npc np1; np1 = MEM_PtrToInst(n1);
var oCNpc onp0; onp0 = MEM_PtrToInst(n0);
var oCNpc onp1; onp1 = MEM_PtrToInst(n1);
var int a0; a0 = Npc_GetArmor(np0);
var int a1; a1 = Npc_GetArmor(np1);
var _TRIA_fltWrapper fn0; fn0 = MEM_PtrToInst(_@(onp0.model_scale));
var _TRIA_fltWrapper fn1; fn1 = MEM_PtrToInst(_@(onp1.model_scale));
MEM_SwapBytes(n0+60, n1+60, 64); // trafo
MEM_SwapBytes(n0+MEM_NpcName_Offset, n1+MEM_NpcName_Offset, MEMINT_SwitchG1G2(272, 312)); // name, voice
MEM_SwapBytes(_@(onp0.bitfield), _@(onp1.bitfield), 20); // bitfield
MEM_SwapBytes(_@s(onp0.mds_name), _@s(onp1.mds_name), 76); // visuals
MEM_SwapBytes(_@(onp0._zCVob_bitfield), _@(onp1._zCVob_bitfield), 20); // vob bitfield
MEM_SwapBytes(_@(onp0._zCVob_visualAlpha), _@(onp1._zCVob_visualAlpha), 4);
Mdl_SetModelScale(np0, fn0.f0, fn0.f1, fn0.f2);
Mdl_SetModelScale(np1, fn1.f0, fn1.f1, fn1.f2);
Mdl_SetModelFatness(np0, fn0.f3);
Mdl_SetModelFatness(np1, fn1.f3);
_TRIA_UpdateVisual(np0, a1);
_TRIA_UpdateVisual(np1, a0);
Npc_RemoveInvItem(np0, a0);
Npc_RemoveInvItem(np1, a1);
var int mw0; mw0 = Npc_GetMeleeWeapon(np0);
var int rw0; rw0 = Npc_GetRangedWeapon(np0);
var int mw1; mw1 = Npc_GetMeleeWeapon(np1);
var int rw1; rw1 = Npc_GetRangedWeapon(np1);
Npc_TradeItem(np0, mw0, mw1);
Npc_TradeItem(np0, rw0, rw1);
Npc_TradeItem(np1, mw1, mw0);
Npc_TradeItem(np1, rw1, rw0);
};
//========================================
// [intern] Kopieren.
//========================================
func void _TRIA_CopyNpc(var int slf) {
if(slf == TRIA_Last) {
return;
};
if(slf == TRIA_Self) {
_TRIA_Copy(TRIA_Self, TRIA_Last);
}
else if(TRIA_Last == TRIA_Self) {
_TRIA_Copy(TRIA_Self, slf);
}
else {
_TRIA_Copy(TRIA_Self, TRIA_Last);
_TRIA_Copy(TRIA_Self, slf);
};
TRIA_Last = slf;
};
//========================================
// [intern] Npcs einstellen
//========================================
func void _TRIA_InitNPC(var c_npc slf) {
Npc_ClearAIQueue(slf);
AI_StandUp(slf);
AI_StopLookAt(slf);
AI_RemoveWeapon(slf);
AI_TurnToNpc(slf, hero);
AI_WaitTillEnd(hero, slf);
AI_StartState(slf, ZS_TRIA, 0, "");
};
//========================================
// Npc in das Gespräch einladen
//========================================
func void TRIA_Invite(var c_npc slf) {
if(TRIA_Running) {
MEM_Warn("TRIA_Invite: Der Trialog läuft bereits.");
return;
};
if(TRIA_CPtr == TRIA_MaxNPC) {
MEM_Error("TRIA_Invite: Zu viele Npcs. Erhöhe bitte TRIA_MaxNPC.");
return;
};
if(Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(hero)
|| Hlp_GetInstanceID(slf) == Hlp_GetInstanceID(self)) {
MEM_Warn("TRIA_Invite: Der Held und/oder Self können nicht eingeladen werden. Sie sind bereits anwesend.");
return;
};
if((Npc_GetDistToNpc(slf, hero) > truncf(MEM_ReadInt(SPAWN_INSERTRANGE_Address)))
|| (Npc_IsDead(slf))
|| (!Hlp_IsValidNpc(slf))) {
MEM_Error(ConcatStrings("TRIA_Invite: Der Npc ist nicht in der KI-Glocke und/oder tot: ", slf.name));
return;
};
MEM_WriteStatArr(TRIA_NpcPtr, TRIA_CPtr, MEM_InstToPtr(slf));
TRIA_CPtr += 1;
};
//========================================
// Trialog starten
//========================================
func void TRIA_Start() {
if(TRIA_Running) {
MEM_Warn("TRIA_Start: Es läuft bereits ein Trialog.");
return;
};
var int i; i = 0;
var int p; p = MEM_StackPos.position;
if(i < TRIA_CPtr) {
var c_npc slf; slf = MEM_PtrToInst(MEM_ReadStatArr(TRIA_NpcPtr, i));
_TRIA_InitNpc(slf);
i += 1;
MEM_StackPos.position = p;
};
// Npc_ClearAIQueue(self); //Mit diesem Befehl beendet sich der Dialog nicht richtig, daher auskommentiert. Ich habe Angst, dass ich irgendwas anderes kaputt gemacht habe, aber bisher konnte ich keine Probleme feststellen.
Npc_ClearAIQueue(hero);
Ai_Output(hero,self,"");
var c_npc selfCopy; selfCopy = Hlp_GetNpc(self);
self = MEM_NullToInst();
TRIA_Invite(selfCopy);
self = Hlp_GetNpc(selfCopy);
TRIA_Wait();
TRIA_Last = MEM_InstToPtr(self);
TRIA_Self = TRIA_Last;
TRIA_Running = 1;
};
//========================================
// Alle Npcs aufeinander warten lassen
//========================================
func void TRIA_Barrier() {
if(!TRIA_Running) {
MEM_Warn("TRIA_Next: Kein Trialog gestartet.");
return;
};
TRIA_Wait();
var int i; i = !1;
var int j; j = 0;
var c_npc last; last = MEM_PtrToInst(MEM_ReadStatArr(TRIA_NpcPtr, TRIA_CPtr)); // Ist immer self, aber so ist es verständlicher
var int p; p = MEM_StackPos.position;
if(i < TRIA_CPtr) {
var c_npc curr; curr = MEM_PtrToInst(MEM_ReadStatArr(TRIA_NpcPtr, i));
AI_WaitTillEnd(curr, last);
last = Hlp_GetNpc(curr);
i += 1;
MEM_StackPos.position = p;
};
if(!j) {
j = 1; i = 0;
MEM_StackPos.position = p;
};
};
//========================================
// Den nächsten Npc als "self" setzen
//========================================
func void TRIA_Next(var c_npc n0) {
if(!TRIA_Running) {
MEM_Warn("TRIA_Next: Kein Trialog gestartet.");
return;
};
if(Hlp_GetInstanceID(n0) == Hlp_GetInstanceID(hero)) {
MEM_Warn("TRIA_Next: 'hero' ist kein erlaubter Parameter für diese Funktion.");
return;
};
var int i; i = 0;
var int j; j = MEM_InstToPtr(n0);
var int p; p = MEM_StackPos.position;
if(i < TRIA_CPtr) {
if(MEM_ReadStatArr(TRIA_NpcPtr, i) != j) {
i += 1;
MEM_StackPos.position = p;
};
};
if(i == TRIA_CPtr) {
MEM_Error(ConcatStrings("TRIA_Next: Der Npc ist nicht eingeladen worden: ", n0.name));
return;
};
TRIA_Wait();
AI_Function_I(hero, _TRIA_Next, j);
};
func void _TRIA_Next(var int n0) {
_TRIA_CopyNpc(n0);
};
//========================================
// Kamerafahrt starten
//========================================
func void TRIA_Cam(var string evt) {
TRIA_Wait();
if(!STR_Len(evt)) {
if(!STR_Len(TRIA_Camera)) { return; };
AI_Function_S(hero, _TRIA_Uncam, TRIA_Camera);
}
else {
if(STR_Len(TRIA_Camera)) {
AI_Function_S(hero, Wld_SendUntrigger, TRIA_Camera);
};
AI_Function_S(hero, _TRIA_Cam, evt);
};
TRIA_Camera = evt;
};
func void _TRIA_Cam(var string evt) {
DiaCAM_Disable();
Wld_SendTrigger(evt);
};
func void _TRIA_Uncam(var string evt) {
DiaCAM_Enable();
DiaCAM_Update();
Wld_SendUntrigger(evt);
};
//========================================
// Trialog abschließen
//========================================
func void TRIA_Finish() {
if(!TRIA_Running) {
MEM_Warn("TRIA_Finish: Kein Trialog gestartet.");
return;
};
TRIA_Wait();
TRIA_Cam("");
AI_Function(hero, _TRIA_Finish);
};
func void _TRIA_Finish() {
if(TRIA_Last != TRIA_Self) {
_TRIA_Copy(TRIA_Self, TRIA_Last);
};
var int i; i = 0;
var int p; p = MEM_StackPos.position;
if(i < TRIA_CPtr-1) {
var c_npc slf; slf = MEM_PtrToInst(MEM_ReadStatArr(TRIA_NpcPtr, i));
AI_ContinueRoutine(slf);
i += 1;
MEM_StackPos.position = p;
};
TRIA_Running = 0;
TRIA_CPtr = 0;
};
EDIT: Das sollte beide Fehler beheben.
EDIT2: Code korrigiert.
Geändert von mud-freak (06.01.2018 um 07:28 Uhr)
Grund: Änderungen unnötig
ich habe noch nicht auf die LeGo-Version, die es vor ein paar Monaten gab, geupdated. Kann es trotzdem daran liegen bzw. damit behoben sein? (ich weiß nicht, ob du schon die alten Trialoge geschrieben hattest?)
Gibt es in der aktuellsten LeGo-Version noch bekannte Fehler / Instabilitäten oder würdet ihr empfehlen darauf umzusteigen?
Demnächst geht es Richtung mehr oder weniger finaler LoA-Version, so dass wir da ggf. auf anstehende Fehlerbehebungen warten oder auf alte Versionen gehen müssten.
ich habe noch nicht auf die LeGo-Version, die es vor ein paar Monaten gab, geupdated. Kann es trotzdem daran liegen bzw. damit behoben sein? (ich weiß nicht, ob du schon die alten Trialoge geschrieben hattest?)
Gibt es in der aktuellsten LeGo-Version noch bekannte Fehler / Instabilitäten oder würdet ihr empfehlen darauf umzusteigen?
Demnächst geht es Richtung mehr oder weniger finaler LoA-Version, so dass wir da ggf. auf anstehende Fehlerbehebungen warten oder auf alte Versionen gehen müssten.
Also bei mir lief der Umstieg bis auf Problem mit eigenen Fixes in LeGo, die ich mir überschrieben hatte, bisher problemlos. Tester haben sich auch nicht beschwert, wobei nach Umstieg auch nur noch ein paar Stunden getestet wurde (also vielleicht so 50). Kannst ja noch eine Woche abwarten und gucken, wie viele Beschwerden es bei XR gibt
In den 40 Posts seit Release wurden nur zwei Fehler gemeldet, die aber keinesfalls neu waren. Insofern sieht es recht stabil aus. Aber wenn ihr keinen Nutzen aus der neuen Version zieht, würde ich (so kurz vor Release) auch keinesfalls updaten. Die einzige relevante Neuerung scheint ein Bugfix in den Trialogen zu sein (NPCs bleiben "stecken" nach einem Trialog), aber das scheint bei euch ja entweder nicht aufzutreten oder ihr habt es schon behoben...
In den 40 Posts seit Release wurden nur zwei Fehler gemeldet, die aber keinesfalls neu waren. Insofern sieht es recht stabil aus. Aber wenn ihr keinen Nutzen aus der neuen Version zieht, würde ich (so kurz vor Release) auch keinesfalls updaten. Die einzige relevante Neuerung scheint ein Bugfix in den Trialogen zu sein (NPCs bleiben "stecken" nach einem Trialog), aber das scheint bei euch ja entweder nicht aufzutreten oder ihr habt es schon behoben...
Es gibt schon noch mindestens einen kompletten Durchlauf mehrerer Tester. Version 2.5 wird auch für GothicFreeAim gebraucht? Dann lohnt sich der Umstieg für uns schon. Bei den beiden Fehlern auf den letzten Seiten war ich mir nur nicht sicher, ob es sich um neue Probleme handelt
Danke an alle!
@Bonne: so schnell bin ich eh noch nicht mit unserer aktuellen Version fertig. Ich beobachte dann einfach mal, was bei dir passiert
@mud-freak: ich teste den neuen Code mal in den nächsten Tagen und sage dann, ob es klappt oder nicht.
@mud-freak: ich teste den neuen Code mal in den nächsten Tagen und sage dann, ob es klappt oder nicht.
Wenn ich mir das noch einmal so angucke, sollte mein Vorschlag eigentlich keine Auswirkung haben - sowohl bezüglich deines Problems, als auch eines womöglichen Denkfehlers. Im Endeffekt sollte das Verhalten der NPCs durch die oben beschriebene Änderung so bleiben wie es vorher war. Meinen Post kann man also glaube ich ignorieren.
Da du aber von einer älteren LeGo Version schreibst, weiss ich nicht, was sich seit dem möglicherweise noch in der Trialoge.d verändert hat.
Interessant wäre es, ob das beschriebene Problem auch mit LeGo 2.5 auftritt.
Wenn ich mich recht entsinne, stoppt TRIA_Start() die laufenden Routinen aller eingeladener Gesprächsteilnehmer, so dass diese stehen bleiben sollten, sobald sie eingeladen werden (der Besitzer des Dialogs aber nicht). Startet der TA zeitlich aber nachTRIA_Start(), ist das vielleicht nicht gewährleistet.
Entschuldigung für das viele "Vieleicht" und "Möglicherweise", ich habe gerade nicht so viel Zeit das nach zu sehen.
Wenn das Problem wirklich nur bei dem erwähnten Trialog auftritt, könntest du aber auch die entsprechenden Skripte posten. Die benutzte LeGo Version wäre aber zunächst interessanter.
Es könnte tatsächlich an B_StartOtherRoutine liegen, werde das auf jeden Fall mal ausprobieren (falls ich den von den Testern gemeldeten Fehler reproduzieren kann).
Kleines Problemchen meinerseits. Folgende Situation: Spiel gespeichert, Spiel geladen. Läuft bis 98% durch, danach CtD. Folgender Stacktrace wurde ausgegeben:
Kommentiere ich einige der FF aus, tritt der Crash nicht auf. Allerdings kann ich mir nicht erklären, woran es bei FF's scheitern soll, die eigentlich "nur" ein paar Variablen ändern, bzw. Leben regenerieren
Hat vielleicht jemand 'ne Idee? Bei Bedarf gibts auch mehr Code, möchte hier nur nicht direkt alles zumüllen
Kannst du mal die SCRPTSAV.SAV hier reinstellen? Allerdings scheint der Crash in den Ikarus-Scripten aufzutreten, das ist höchst ungewöhnlich
Gibt's noch weitere Fehlermeldungen? Eine Access Violation vielleicht?
Es könnte tatsächlich an B_StartOtherRoutine liegen, werde das auf jeden Fall mal ausprobieren (falls ich den von den Testern gemeldeten Fehler reproduzieren kann).
Noch einmal dazu. Das wird tatsächlich an B_StartOtherRoutine liegen, denn das enthält AI_ContinueRoutine, was den Trialog-Zustand ZS_TRIA unterbricht, der dafür sorgen soll, dass eingeladene Gesprächspartner nicht weglaufen o.ä.
Falls ihr das Problem also noch nicht lösen konntet, probier es mal direkt mit Npc_ExchangeRoutine. Das sollte den ZS nicht unterbrechen. Wenn das nicht geht, reihe B_StartOtherRoutine mit AI_Function in die AI-Queue ein.
Hi guys!
Haven't been here for a while Wish you all Happy New Year!
Now lets back to work I came back to modding Gothic and I have an issue Right lets start from beginning.
I created poisoned arrows and added something like this on B_AssessDamage:
Code:
func void CheckPoisonArrowDamage (var C_Npc other, var C_Npc self )
{
equippedbow = Npc_GetEquippedRangedWeapon(other);
damagehit = Hlp_Random (99);
if (Npc_IsPlayer (other))
{ if ( zatrut == TRUE ) // Jezeli strzala jest zatruta
{
if (other.HitChance[NPC_TALENT_BOW] >= damagehit )
{
Buff_Apply (self, slabe_zatrucie);
};
if (other.HitChance[NPC_TALENT_BOW] < damagehit )
{ };
};
if (self.attribute[ATR_HITPOINTS] <= 0)
{ B_GivePlayerXP(self.level*10);
};
};};
This is working at the minute if my hero select poisoned arrows and shoot other npc it will take damage as normally it would from arrows plus it will add buff to npc that was attacked. Buff and buffdamage scripts:
Code:
func void slabe_zatrucie_damage(var int bh)
{ var int ptr; ptr = Buff_GetNpc(bh);
if (!ptr)
{
return;
}; // Kann passieren, falls z.B. die Welt gewechselt wurde
if (self.attribute[ATR_HITPOINTS] > 0)
{ var c_npc n; n = _^(ptr);
Npc_ChangeAttribute(n, ATR_HITPOINTS, -30); // 3 Schaden
Wld_PlayEffect("spellFX_SuckEnergy", self, self, 0, 0, 0, FALSE ); // efekt na npc
PrintScreen ("Just for test purpose", -1, -1, FONT_SCREEN, 1);
};
if (self.attribute[ATR_HITPOINTS] <= 0)
{
B_GivePlayerXP(self.level*10);
PrintScreen ("Testuje", -1, -1, FONT_SCREEN, 1);
};
};
instance slabe_zatrucie(lCBuff) {
name = "slabe_zatrucie"; bufftype = 1; durationMS = 10*1000; //10 sekund dlugie tickMS = 3000; // Jedna sekunda onTick = SAVE_GetFuncID(slabe_zatrucie_damage); buffTex = "zFlare2.TGA";
};
and this is more less working fine... yep more less... The problem I have with it is if I hit someone it will add buff to him/her but if I shot that person again it will add another buff so buffs will just multiply which I don't want to happen. Another issue I have is that if I NPC will be killed by buff I will not get any exp.
Hello everyone!
There is any way to disable dialog gestures for some actions in G1 (i.e. sitting)? In Gothic 2 npcs doesn't gesticulate then, I think its a good idea to import it to Gothic 1.
Ich habe einen Bug in LeGo gefunden. Das Quicksave-Laden wird von LeGo nicht vernünftig erkannt. Der ermittelte Ladeslot ist bei Quicksaves inkorrekt, sodass SCRPTSAVE.SAV aus einem der anderen Save-Ordner geladen wird und somit sämtliche PermMem-Handles (meist) falsch sind.
Ähnlich, aber etwas anders, hatte das Mark56 schon einmal berichtet. Ich schätze das hängt zusammen (bzw. er meinte eben genau das).
Ich schaue mir das Problem gerade mal an, aber wollte das hier nur schon einmal berichten.
Geändert von mud-freak (23.01.2018 um 15:01 Uhr)
Grund: Link korrigiert
Der Link geht auf eine IP, da hattest du wohl was falsches in der Zwischenablage
Aber ja, dass das Problem schonmal erwähnt wurde, daran erinnere ich mich auch. Ich dachte aber eigentlich, dass sei gefixt? Kann mich auch irren - habe Quicksaves nie benutzt.
Danke übrigens für deine Änderungen an Anim8, inbesondere der OnRemove-Callback macht viele Anwendungen natürlicher.
Habe den Link korrigiert. Hatte ihn versehentlich in den [URL]-Tag anstatt in den [POST]-Tag gesteckt.
Das Problem ist die Verwendung des letzten Menü-Elements im Loading-Menu zur Bestimmung des Lade-Slots (_BR_GetSelectedSlot). Das stimmt im Falle von einem Quicksave natürlich nicht, da es meist nicht vom Menü gestartet wird. Bisher habe noch keine gute Idee wie man an den Slot des tatsächlich zuletzt geladenen Spielstand kommt, weil der während des Ladens (glaube ich) von einer Funktion zur nächsten nur als Argument übergeben wird und anschliessend nirgendwo auszulesen ist.
Das Problem dürfte nun gefixt sein. Hat eine Weile gedauert, weil ich mich noch um das SystemPack herum winden musste, das bei Gothic 1 etwas an den Quicksaves ändert (bzw. sie repariert).
EDIT: Ich habe bei der Gelegenheit auch den Fehler mit den Dialoggesten korrigiert, von dem Cryp18Struct hier vor einer Weile berichtet hat.
Geändert von mud-freak (23.01.2018 um 22:35 Uhr)
Grund: Folgeproblem gefixt, Dialoggesten gefixt
const int ASMINT_OP_addMemToESP = 9475; //0x2503
const int ASMINT_OP_movESItoEAX = 61577; //0xF089
const int ASMINT_OP_movEAXtoEDI = 51081; //0xC789
als Teil der Hook-Engine. Hat es damit noch mehr auf sich?
Ich frage, weil ich gerade in den LoA-Skripten das hier entdeckt habe:
Code:
var int RET;
func void HookByConditionalFunctionI (var int address, var int oldInstr, var int jumpAddress, var int function) {
var int SymbID;
var int ptr; //ptr to store old instruction
var int relAdr; //Difference for jmp instruction
// ----- Sicherheitsabfragen -----
if(oldInstr < 5) {
PrintDebug("HOOKENGINE: oldInstr ist zu kurz. Es werden mindestens 5 Bytes erwartet.");
return;
};
SymbID = function;
if(SymbID == -1) {
PrintDebug("HOOKENGINE: Die gegebene Daedalusfunktion kann nicht gefunden werden.");
return;
};
// ----- Eventuell geschützen Speicher behandeln -----
MemoryProtectionOverride (address, oldInstr+3);
// ----- Die alte Anweisung sichern -----
ptr = MEM_Alloc(oldInstr);
MEM_CopyBytes(address, ptr, oldInstr);
// ----- Einen neuen Stream für den Assemblercode anlegen -----
ASM_Open(200 + oldInstr); // Play it safe.
// ----- Jump aus der Enginefunktion in den neuen Code einfügen -----
relAdr = ASMINT_CurrRun-address-5;
MEM_WriteInt(address, 233);
MEM_WriteInt(address + 1, relAdr);
// Alle Register sichern
// EAX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(_@(EAX));
ASM_1(ASMINT_OP_pusha);
// ECX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movECXtoEAX);
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(_@(ECX));
// ESP in Daedalus Variable sichern
ASM_2(ASMINT_OP_movESPtoEAX);
ASM_2(ASMINT_OP_addImToEAX);
ASM_1(4*8); // Wegen pushad [Danke an Sektenspinner]
ASM_2(ASMINT_OP_movEAXToMem);
ASM_4(_@(ESP));
// EBX in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEBXtoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(_@(EBX));
// EBP in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEBPtoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(_@(EBP));
// EDI in Daedalus Variable sichern
ASM_2(ASMINT_OP_movEDItoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(_@(EDI));
// ESI in Daedalus Variable sichern
ASM_2(ASMINT_OP_movESItoEAX);
ASM_2(ASMINT_OP_movEAXtoMem);
ASM_4(_@(ESI));
//Daedalus-Funktion 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);
// teste die Rückgabe RET auf ihren Wahrheitsgehalt
ASM_1(ASMINT_OP_movMemToEAX);
ASM_4(_@(RET));
//85 c0 test eax,eax
ASM_1(133);
ASM_1(192);
ASM_1(ASMINT_OP_popa);
// Register widerherstellen
ASM_1(ASMINT_OP_movMemToEAX);
ASM_4(_@(ECX));
ASM_2(ASMINT_OP_movEAXtoECX);
ASM_1(ASMINT_OP_movMemToEax);
ASM_4(_@(EDI));
ASM_2(ASMINT_OP_movEAXtoEDI);
ASM_1(ASMINT_OP_movMemToEAX);
ASM_4(_@(EAX));
//Do conditional jump; execute original code, if RET is FALSE
//74 05 jz 6
ASM_1(116);
ASM_1(6);
// RET ist wahr -> überspringe den originalen Code
ASM_1(ASMINT_OP_pushIm);
ASM_4(jumpAddress);
ASM_1(ASMINT_OP_retn);
// RET ist falsch -> führe die Funktion normal aus
// Alte Anweisung wieder einfügen
MEM_CopyBytes(ptr, ASMINT_Cursor, oldInstr);
MEM_Free(ptr);
ASMINT_Cursor += oldInstr;
ASM_1(ASMINT_OP_pushIm);
ASM_4(address + oldInstr);
ASM_1(ASMINT_OP_retn);
var int i; i = ASM_Close();
};
func void HookByConditionalFunctionF (var int address, var int oldInstr, var int jumpAddress, var func function) {
HookByConditionalFunctionI(address, oldInstr, jumpAddress, MEM_GetFuncID(function));
};
func void HookByConditionalFunction(var int address, var int oldInstr, var int jumpAddress, var string function) {
HookByConditionalFunctionI(address, oldInstr, jumpAddress, MEM_FindParserSymbol(STR_Upper(function)));
};
was diese Variablen genutzt hat. Allerdings kann ich auch nicht sagen, was dieser Code hier macht Vielleicht findet es ja jemand raus und findet es nützlich...