-
Hi mud-freak,
Hope you can help me - I am trying to pinpoint an NPC to its waypoint (to get same result as with AI_AlignToWP). I was trying functions GetTrafoFromWP & AlignVobAt from your InsertAnything.d package, but I failed to get it working. Can you advise what am I doing wrong here ?
Code:
var zCVob vobSelf;
vobSelf = Hlp_GetNPC (self);
var int Y; Y = vobSelf.trafoObjToWorld [07];
var int vobPtr;
vobPtr = _@ (vobSelf);
var int trafoPtr;
GetTrafoFromWP (self.WP, trafoPtr);
AlignVobAt (vobPtr, trafoPtr);
vobSelf.trafoObjToWorld [07] = Y;
-
Zitat von F a w k e s
Hi mud-freak,
Hope you can help me - I am trying to pinpoint an NPC to its waypoint (to get same result as with AI_AlignToWP). I was trying functions GetTrafoFromWP & AlignVobAt from your InsertAnything.d package, but I failed to get it working. Can you advise what am I doing wrong here ?
I think the problem is that trafoPtr has to be allocated appropriately. Either with MEM_Alloc and MEM_Free, or - in my opinion - easier with
Code:
var int trafo[16];
...
_@(trafo)
-
thank you - it works now!
-
-
Siemekk
Great improvement after this version: https://forum.worldofplayers.de/foru...ic-II-QuickBar
I try new version and get crashes, after try use weapon from slot, that contain more than one instance. On old version thats crashes absents.
Some zSpy Log
Code:
02:27 Info: 10 U: (oCWorld::RemoveVob) ITMW_1H_DAEMONBLADE_01 (1) .... <oWorld.cpp,#475>
02:27 Info: 10 U: (oCWorld::CreateVob) 18788 .... <oWorld.cpp,#315>
02:27 Info: 10 U: (oCWorld::RemoveVob) ITMW_1H_MACE_WAR_04 (1) .... <oWorld.cpp,#475>
02:27 Warn: 0 D: zModel.cpp(zCModel::StartAni): Ani not found: CALL I 835126688 13537 .... <zModel.cpp,#2581>
02:27 Info: 9 U: Mark Conversationmessage for deletion .... <oNpc.cpp,#10781>
02:27 Fault: 0 Q: [start of stacktrace]
02:27 Fault: 0 Q: ASMINT_CALLMYEXTERNAL() + 5 bytes
02:27 Fault: 0 Q: [end of stacktrace]
02:27 Fault: 0 Q: Exception handler was invoked. Ikarus tried to print a Daedalus-Stacktrace to zSpy. Gothic will now crash and probably give you a stacktrace of its own.
02:27 Info: 5 X: Vid_SetScreenMode: No changes ... .... <zRndD3D_Vid.cpp,#559>
02:27 Info: 5 X: Vid_SetScreenMode: No changes ... .... <zRndD3D_Vid.cpp,#559>
02:27 Info: 8 C: WM_CANCELMODE received .... <zWin32.cpp,#1728>
02:27 Info: 8 C: WM_ACTIVATE received .... <zWin32.cpp,#1720>
02:32 Info: 8 C: WM_ACTIVATE received .... <zWin32.cpp,#1720>
Anhang 48279
-
that contain more than one instance
Example... I, and in 3 other testers don't had any bugs.
-
Zitat von Siemekk
Example... I, and in 3 other testers don't had any bugs.
Well, it probably conflicts with my other scripts... I will try to look for the cause.
-
Zitat von Siemekk
QuickSlot
Download files from my GDrive
Parse files after Startup.D
In Init_Global add this line:
Features:
* Full QuickSlot source code for Gothic 2
* Powered by Ikarus, LeGo, and System Pack.
* You can assign items for every key
* Highlight items in inventory if this is assign to QS key
* Full Config file
* And more...
You must add this line to SystemPack patch file (MACHINE CODE)
(It's fix for climbing)
Code:
[FIX_CLIMBING_1]
Addr = "0x0050C585"
Type = "hex"
New = "68 C8 00 00 00 EB 06 90 90 90 90 EB F3"
[FIX_CLIMBING_2]
Addr = "0x0050C586"
Type = "int"
New = "400"
And it's all
Big thanks for:
* @mud-freak
* @Lehona
* @Gratt
* @Boguś
If you planing use this code, add me as author
Regards Siemekk!
Ingame (Screen from version v0.5.0, you can change texture in config file - with position, maybe I will made tutorial about that):
Amazing! Thanks for sharing. I was using your old script for my mod but now I'll switch to this.
-
Zitat von Siemekk
What LeGo flags you inicialize in Init_Global?
Please write you string.
-
Zitat von ukur
What LeGo flags you inicialize in Init_Global?
Please write you string.
I used:
Code:
LeGo_Init(LeGo_ALL);
But you can use this:
Code:
LeGo_Init(YOU_LEGO_FLAGS & QS_LeGo_Flags);
-
Siemekk
In a separate directory installed G2NotR, then Clean Scripts from G2MDK, then Ikarus, LeGo and QuickSlots, and I get the same crash when using more than one weapon in the slot.
Anhang 48282
Mystic!
-
@Fisk - It's work?
@ukur - Try this:
Fresh Gothic 2 NoTR -> Fix 2.6 -> PlayerKit -> SystemPack 1.7 -> Ikarus 1.2.1 -> LeGo -> QuickBar.
-
Zitat von Siemekk
@ukur - Try this:
Fresh Gothic 2 NoTR -> Fix 2.6 -> PlayerKit -> SystemPack 1.7 -> Ikarus 1.2.1 -> LeGo -> QuickBar.
I tried this way on clean G2NoTR and also my Mod, I use LeGo v2.6, tried to compile it with a game through GothicStarter_Mod.exe and through Spacer. Crash with multiple instances weapon in one slot and other weapon same type present in all cases when i try switch weapon to use. For Example in first slot hang some clubs, in second hang one sword, then switch between them and get crash. Same crash get with ranged weapon if in one slot hangs some bows, in other slot one crossbow, when switching also get crash.
-
Try use LeGo 2.5.1
-
Zitat von Siemekk
Try use LeGo 2.5.1
I try with LeGo 2.5.1 on Clean G2NoTR - Same Crash.
-
Hätte jemand zufällig für diese Funktionen: https://forum.worldofplayers.de/foru...1#post16944337 die G1 Adressen? Die sind nämlich ziemlich praktisch. Hatte vor, das zu benutzen um eine herrlich variable und flexibel einsetzbare visuelle Übergabe von Items zu ermöglichen.
Das Skript für diese Spielerei wollte ich dann auch hier reinstellen.
"Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
-Korallenkette
-
Zitat von Bisasam
Hätte jemand zufällig für diese Funktionen: https://forum.worldofplayers.de/foru...1#post16944337 die G1 Adressen? Die sind nämlich ziemlich praktisch. Hatte vor, das zu benutzen um eine herrlich variable und flexibel einsetzbare visuelle Übergabe von Items zu ermöglichen.
Das Skript für diese Spielerei wollte ich dann auch hier reinstellen.
Didn't tested this - but it should be working like this for G1:
Code:
/*
Neither address nor function in LeGo 2.5.1 EngineAdr_G1.d are correct.
Function below was changed as per advice from MudFreak.
*/
func void oCNpc_RemoveFromSlot (var c_npc slf, var string SlotName, var int retVal, var int SlotID) {
//006A5E80 .text Debug data ?RemoveFromSlot@oCNpc@@QAEPAVoCVob@@ABVzSTRING@@H@Z
const int oCNPC__RemoveFromSlot_G1 = 6971008;
//0x0074A270 public: class oCVob * __thiscall oCNpc::RemoveFromSlot(class zSTRING const &,int,int)
const int oCNPC__RemoveFromSlot_G2 = 7643760;
var int oCNPC__RemoveFromSlot;
oCNPC__RemoveFromSlot = MEMINT_SwitchG1G2 (oCNPC__RemoveFromSlot_G1, oCNPC__RemoveFromSlot_G2);
CALL_IntParam (SlotID);
if (GOTHIC_BASE_VERSION == 1) {
CALL_PutRetValTo (_@(retVal)); // Gothic 1: Return value
} else {
CALL_IntParam (retVal); // Gothic 2: Parameter
};
CALL_zStringPtrParam (SlotName);
CALL__thiscall (MEM_InstToPtr (slf), oCNPC__RemoveFromSlot);
};
/*
This is working and available in EngineAdr_G1.d
Will put it here just for the sake of code completion.
*/
func int oCNpc_PutInSlot (var c_npc slf, var string SlotName, var int oCVobPtr, var int SlotID) {
//006A5940 .text Debug data ?PutInSlot@oCNpc@@QAEXABVzSTRING@@PAVoCVob@@H@Z
const int oCNpc__PutInSlot_G1 = 6969664;
//0x00749CB0 public: void __thiscall oCNpc::PutInSlot(class zSTRING const &,class oCVob *,int)
const int oCNpc__PutInSlot_G2 = 7642288;
var int oCNpc__PutInSlot;
oCNpc__PutInSlot = MEMINT_SwitchG1G2 (oCNpc__PutInSlot_G1, oCNpc__PutInSlot_G2);
CALL_IntParam (SlotID);
CALL_PtrParam (oCVobPtr);
CALL_zStringPtrParam (SlotName);
CALL__thiscall (MEM_InstToPtr (slf), oCNpc__PutInSlot);
return CALL_RetValAsInt ();
};
//************************************************
// Waffen die anderes visual haben, wenn gezogen.
//************************************************
func void HandleDynamicWeaponVisual(var int itemEquipped, var int itemReadied) {
var oCItem weap;
if (Npc_HasReadiedMeleeWeapon(hero) || Npc_HasReadiedRangedWeapon(hero)) {
weap = Npc_GetReadiedWeapon(hero);
if (Hlp_GetInstanceID(weap) == itemEquipped) {
//remove from slot
var int killEffect; killEffect = TRUE;
var int dontDrop; dontDrop = FALSE;
oCNpc_RemoveFromSlot (hero, "ZS_RIGHTHAND", dontDrop, killEffect);
//exchange items
Npc_RemoveInvItem(hero, itemEquipped);
CreateInvItem(hero, itemReadied);
//put in Slot
var int isInInventory; isInInventory = TRUE;
if (weap.flags & ITEM_BOW) {
//bogen links!
oCNpc_PutInSlot (hero, "ZS_LEFTHAND", MEM_InstToPtr(item), isInInventory);
} else {
oCNpc_PutInSlot (hero, "ZS_RIGHTHAND", MEM_InstToPtr(item), isInInventory);
};
};
} else {
var int doIt; doIt = false;
weap = Npc_GetEquippedMeleeWeapon(hero);
if (Hlp_GetInstanceID(weap) == itemReadied) { doIt = true; };
weap = Npc_GetEquippedRangedWeapon(hero);
if (Hlp_GetInstanceID(weap) == itemReadied) { doIt = true; };
if (doIt) {
CreateInvItem(hero, itemEquipped);
EquipWeapon(hero, itemEquipped);
Npc_RemoveInvItem(hero, itemReadied);
};
};
};
-
Ein Beitrag für den Skriptbin. Hoffe das ist für Fawkes okay, da es seine GetAni-Funktion als Kern hat. Habe entsprechende Skriptstelle markiert:
Zitat von Bisasam
Soo das ist die Animationsabfragefunktion:
Code:
///// Npc_GetAniName ist von FAWKES /////
FUNC STRING NPC_GetAniName (var int slfInstance)
{
var oCNPC slf;
slf = Hlp_GetNPC (slfInstance);
var string str_Ani;
str_Ani = oCAniCtrl__GetCurrentAniName (slf.AniCtrl);
return str_Ani;
};
///// Ab hier Bisasam /////
func string BuildAniString(var string Beginning,var string Middle, var string End)
{
var string ReturnString;
ReturnString=Concatstrings(Beginning,Middle);
ReturnString=Concatstrings(ReturnString,End);
return ReturnString;
};
func int Npc_IsInAnimation(var int NscInst, var string CurrAni, var int IgnoreState)
{
var string HerosAniName;
HerosAniName=NPC_GetAniName(NscInst);
var string ConcAni;
////////////////////////////////
// FALLS MAN IN DER ABFRAGE SCHON SO GENAU WAR DASS ES SOFORT PASST
if Hlp_StrCmp(HerosAniName,CurrAni)==TRUE
{
return TRUE;
};
//////////////////////////////////////////
// STATE und TRANSITION, nicht für Bewegungen wie Waffenlauf, Schleichen etc. geeignet!
// Für obige Spezialfälle bitte schon bei Varübergabe konkret werden!
// Es wird deswegen nicht mit || gearbeitet weil Gothic 1 ein Problem mit zu vielen
// Verschachtelungen kriegt wenn ein und dieselbe Funktion oft aufgerufen wird
if IgnoreState==FALSE //Sollen S_X_S1 etc. Funktionen ignoriert werden?
{
ConcAni=BuildAniString("S_",CurrAni,"_S0");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("S_",CurrAni,"_S1");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("S_",CurrAni,"_S2");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("S_",CurrAni,"_S3");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("S_",CurrAni,"_S4");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
};
/////////////////////////////////////////////////
// State Trans
ConcAni=BuildAniString("T_",CurrAni,"_S0_2_S1");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S1_2_S0");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S1_2_S2");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S2_2_S1");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S2_2_S3");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S3_2_S2");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S3_2_S4");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_S4_2_S3");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
//////////////////////////////////////////
// Zurück zu stand
ConcAni=BuildAniString("T_",CurrAni,"_S0_2_STAND");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_STAND_2_S0");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
//////////////////////////////////////
// SPEZIALFALL T_STAND_2_SIT u.ä.
//
ConcAni=BuildAniString("T_STAND_2_",CurrAni,"");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("T_",CurrAni,"_2_STAND");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
if IgnoreState==FALSE
{
ConcAni=BuildAniString("S_",CurrAni,"");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
};
//////////////////////////////////////////////////
// RANDOM ANIS BENCH, CHAIR, ETC.
ConcAni=BuildAniString("R_",CurrAni,"_RANDOM_1");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("R_",CurrAni,"_RANDOM_2");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("R_",CurrAni,"_RANDOM_3");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
ConcAni=BuildAniString("R_",CurrAni,"_RANDOM_4");
if Hlp_StrCmp(HerosAniName,ConcAni)==TRUE
{
return TRUE;
};
/////////////////////////////
// Passt alles nicht?
return FALSE;
};
func int Npc_IsInTransitionAni(var int NscInst)
{
// INSTANZ , ANINAME , S_Anis Ignorieren?
if Npc_IsInAnimation(NscInst,"SLEEPGROUND",TRUE)==TRUE
|| Npc_IsInAnimation(NscInst,"WASH",TRUE)==TRUE
|| Npc_IsInAnimation(NscInst,"SIT",TRUE)==TRUE
|| Npc_IsInAnimation(NscInst,"LGUARD",TRUE)==TRUE
|| Npc_IsInAnimation(NscInst,"HGUARD",TRUE)==TRUE
{
return TRUE;
};
return FALSE;
};
Die Abfrage nimmt eine Instanz entgegen, ermittelt deren aktuelle Animation und gleicht ab, ob sie mit der gesuchten Animation übereinstimmt.
var int IgnoreState ist für S-Animationen zuständig. Also z.B. S_SIT, S_BATHTUB_S1 etc. Wenn ihr dort TRUE reinschreibt, wird die Überprüfung auf die genannten Animationen NICHT stattfinden. Das ist vor allem dann wichtig, wenn ihr nur die T- oder R-Animationen überprüfen möchtet. Ich benutze das um rauszukriegen, ob sich mein Held gerade in einer Übergangsanimation befindet. Dann sollen bestimmte Dinge nicht möglich sein um Bugs auszumerzen.
Wenn ihr FALSE schreibt, wird die Prüfung auf S_BATHTUB_S1 stattfinden.
Für Kampf- und Bewegungsanimationen konnte ich kein Standardschema erstellen da diese immer unterschiedlich sind. Aus diesem Grund solltet ihr diese Fälle konkret eingeben statt nur den Mittelteil. Statt "RUN_2_WALK" also lieber "T_RUN_2_WALK"
"Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
-Korallenkette
-
Lehrling
Zitat von ukur
Siemekk
In a separate directory installed G2NotR, then Clean Scripts from G2MDK, then Ikarus, LeGo and QuickSlots, and I get the same crash when using more than one weapon in the slot.
Anhang 48282
Mystic!
I have the same problem
-
Hello folks,
I have couple of useful functions. These can be used to improve vanilla G1 scripts. (might be these work with G2A as well)
NPC_HasOverlay
Usage: In G1 if NPC has active overlay 'HUMANS_DRUNKEN.MDS' and goes into attack - whole game freezes.
If you use function Mdl_RemoveOverlayMDS (self, "HUMANS_DRUNKEN.MDS"); to remove this overlay while it was not previously applied - it might screw up some AI behavior of NPC (in my case any NPC which was in fightmode FMODE_FAR froze).
Code:
//returns true if NPC has an overlay, otherwise false
FUNC INT NPC_HasOverlay (var int slfInstance, var string testOverlay)
{
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (Hlp_IsValidNPC (slf)) {
var int i; i = 0;
var int loop; loop = MEM_StackPos.position;
if (i < slf.activeOverlays_numInArray)
{
var string overlay; overlay = MEM_ReadStringArray (slf.activeOverlays_array, i);
if (Hlp_StrCmp (overlay, testOverlay)) {
return TRUE;
};
i += 1;
if (i < slf.activeOverlays_numInArray) {
MEM_StackPos.position = loop;
};
};
};
return FALSE;
};
...
FUNC VOID ZS_Attack ()
{
...
if (NPC_HasOverlay (self, "HUMANS_DRUNKEN.MDS")) {
Mdl_RemoveOverlayMDS (self, "HUMANS_DRUNKEN.MDS");
};
};
NPC_IsInActiveVobList
Usage: If you call NPC_ClearAIQueue on NPC which is not in activeVobList_array - game will crash:
Code:
//Code taken from Broadcasts.d
//https://forum.worldofplayers.de/forum/threads/775333-Script-Broadcasts?p=17232705&viewfull=1#post17232705
//returns true if NPC is in activeVobList_array, otherwise false
FUNC INT NPC_IsInActiveVobList (var int slfInstance)
{
var C_NPC slf; slf = Hlp_GetNPC (slfInstance);
if (Hlp_IsValidNPC (slf)) {
var int i; i = 0;
var int loop; loop = MEM_StackPos.position;
if (i < MEM_World.activeVobList_numInArray) {
var int ptr;
ptr = MEM_ReadIntArray(MEM_World.activeVobList_array, i);
if (Hlp_Is_oCNpc (ptr)) {
var C_NPC npc; npc = MEM_PtrToInst (ptr);
if (Hlp_GetInstanceID (npc) == Hlp_GetInstanceID (slf))
{
return TRUE;
};
};
i += 1;
if (i < MEM_World.activeVobList_numInArray) {
MEM_StackPos.position = loop;
};
};
};
return FALSE;
};
...
FUNC VOID B_FullStop (var C_NPC npc)
{
if (NPC_IsInActiveVobList (npc)) {
Npc_ClearAIQueue (npc);
AI_StandupQuick (npc);
};
};
NPC_GetAnglesVob, NPC_IsInAngleXNPC, NPC_IsInAngleYNPC
Usage: Many ZS functions which call AI_TurnToNPC can be improved. For example ZS_Smalltalk: 2 NPCs talking with each other will turn to each other every loop.
AI_TurnToNPC will cause something like 'shivering' effect on NPC. So by checking angle, you can avoid unnecessary turn animation.
Code:
//NPC_GetAnglesVob (self, vobPtr, angleXPtr, angleYPtr)
//returns angle of self in relation to vobPtr, returned values are written to angleXPtr & angleYPtr
//angleX: Negative number vob is on lefthand-side
// 0 vob is directly in front of npc
// Positive number vob is on righthand-side
//angleY: Negative number vob is below npc
// 0 vob is directly in front of NPC
// Positive number vob is above npc
FUNC VOID NPC_GetAnglesVob (var int slfInstance, var int vobPtr, var int angleXPtr, var int angleYPtr)
{
//0074C0D0 .text Debug data ?GetAngles@oCNPC@@QAEXPAVzCVob@@AAM1@Z
const int oCNPC__GetAnglesVob_G1 = 7651536;
//0x00681680 public: void __thiscall oCNpc::GetAngles(class zCVob *,float &,float &)
const int oCNPC__GetAnglesVob_G2 = 6821504;
var oCNPC slf; slf = Hlp_GetNPC (slfInstance);
if (!vobPtr) { return; };
if (Hlp_IsValidNPC (slf)) {
CALL_PtrParam (angleYPtr);
CALL_PtrParam (angleXPtr);
CALL_PtrParam (vobPtr);
CALL__thiscall (MEM_InstToPtr (slf), MEMINT_SwitchG1G2 (oCNPC__GetAnglesVob_G1, oCNPC__GetAnglesVob_G2));
};
};
//NPC_IsInAngleXNPC (self, other, angle)
//returns true if self is looking at other within 'angle' on X axis
FUNC INT NPC_IsInAngleXNPC (var int slfInstance, var int npcInstance, var int angle)
{
var oCNPC slf;
var oCNPC npc;
slf = Hlp_GetNPC (slfInstance);
npc = Hlp_GetNPC (npcInstance);
if (Hlp_IsValidNPC (slf))
&& (Hlp_IsValidNPC (npc))
{
var int angleX;
var int angleY;
NPC_GetAnglesVob (slfInstance, _@ (npc), _@ (angleX), _@ (angleY));
if (gef (angleX, negf (mkf (angle))))
&& (lef (angleX, mkf (angle)))
{
return TRUE;
};
};
return FALSE;
};
//NPC_IsInAngleYNPC (self, other, angle)
//returns true if self is looking at other within 'angle' on Y axis
FUNC INT NPC_IsInAngleYNPC (var int slfInstance, var int npcInstance, var int angle)
{
var oCNPC slf;
var oCNPC npc;
slf = Hlp_GetNPC (slfInstance);
npc = Hlp_GetNPC (npcInstance);
if (Hlp_IsValidNPC (slf))
&& (Hlp_IsValidNPC (npc))
{
var int angleX;
var int angleY;
NPC_GetAnglesVob (slfInstance, _@ (npc), _@ (angleX), _@ (angleY));
if (gef (angleY, negf (mkf (angle))))
&& (lef (angleY, mkf (angle)))
{
return TRUE;
};
};
return FALSE;
};
...
FUNC VOID ZS_Smalltalk_Loop ()
{
...
if (!NPC_IsInAngleXNPC (self, other, 10)) {
AI_TurnToNPC (self, other);
};
...
};
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|