|
-
Zitat von Lehona
For a bug to occur without the '+', the following conditions are necessary:
A function f that returns a variable directly, not a computation ( return x; vs return x+1)
And a caller has to use f in a way such that it is called twice before either return value is used in a computation. Essentially:
Code:
func int thingy(var int x) {
return x;
};
func int bug() {
// Prints 8, not 7
print(IntToString(thingy(3)+thingy(4)));
};
Changing thingy to 'return +x;' instead fixes the bug.
Danke für das Beispiel. Jetzt ist mir auch wieder eingefallen, wo das Problem im Zusammenhang mit HookEngineF und MEMINT_SwitchG1G2 auftrat:
Code:
HookEngineF(MEMINT_SwitchG1G2(addrG1, addrG2), MEMINT_SwitchG1G2(5, 7), someFunction);
-
I want to use Fawkes "MoveVobs"-Script in Gothic 2. How I can define "oCMobLadder_vtbl"? Maybe its my mistake but I cant find it anywhere (except Ikarus_Const_G1.d).
-
Zitat von Fisk2033
I want to use Fawkes "MoveVobs"-Script in Gothic 2. How I can define "oCMobLadder_vtbl"? Maybe its my mistake but I cant find it anywhere (except Ikarus_Const_G1.d).
This should be constant for G2A:
Code:
//0x0083CF2C const oCMobLadder::`vftable'
const int oCMobLadder_vtbl = 8638252;
-
G1 In-game object moving v2
Hello folks,
Slightly improved version:
Press '[' to activate select mode.
Select mode:
Use left/right arrows to select objects you want to move/rotate.
Press '[' to confirm selection of the object - this will activate Transform mode.
Press ']' to cancel select mode.
Transform mode:
Move around hero to move around object.
Press 'E' to adjust elevation: use up/down arrows to adjust vertical position of object
Press 'X', 'Y', or 'Z' to activate rotation mode.
Press '[' to stop interaction.
Press ']' to align to surface.
Rotation mode:
Use arrow keys to adjust rotation of respective axis.
[Video]
Here is code if you would be interested:
Required:
Ikarus 1.2.1
Function NPC_CanSee & AI_TurnToVobPtr from:
https://forum.worldofplayers.de/foru...1#post26640112
Function SetVobToFloor from Scriptbin\InsertAnything:
https://forum.worldofplayers.de/foru...1#post25712257
Functions from Scriptbin\NPCVobList.d:
https://forum.worldofplayers.de/foru...1#post26052199
Functions from Scriptbin\gameKeyEvents.d
https://forum.worldofplayers.de/foru...1#post26055992
Other variables and functions which are required:
Code:
//--- vob Transport global variables & constants
const int vobTRange = 300;
var int vobTPtr;
var int vobTVobList;
var int vobTMode;
const int cvobTMode_Disabled = 0;
const int cvobTMode_Init = 1;
const int cvobTMode_Select = 2;
const int cvobTMode_Select_Next = 3;
const int cvobTMode_Select_Previous = 4;
const int cvobTMode_Select_Confirm = 5;
const int cvobTMode_Moving = 6;
const int cvobTMode_Done = 7;
var int vobTModeAlignToFloor;
var int vobTCollBits;
var int vobTMovementSpeed;
var int vobTModeXYZE;
const int cvobTRotationMode_0 = 0;
const int cvobTRotationMode_X = 1;
const int cvobTRotationMode_Y = 2;
const int cvobTRotationMode_Z = 3;
const int cvobTRotationMode_E = 4; //Elevation
var int vobTRotX;
var int vobTRotY;
var int vobTRotZ;
var int vobTElevation;
/***
Hero_Lock will freeze player in place (he will not move)
***/
FUNC VOID Hero_Lock () {
NPC_ClearAIQueue (hero);
var oCNpc her;
her = Hlp_GetNpc (hero);
her._zCVob_bitfield[2] = (her._zCVob_bitfield[2] & ~ zCVob_bitfield2_sleepingMode) | 0;
};
/***
Hero_UnLock will unfreeze player
***/
FUNC VOID Hero_UnLock () {
NPC_ClearAIQueue (hero);
var oCNpc her;
her = Hlp_GetNpc (hero);
her._zCVob_bitfield[2] = (her._zCVob_bitfield[2] & ~ zCVob_bitfield2_sleepingMode) | 1;
};
/***
Will draw BBox3D on Vob
***/
FUNC VOID Vob_SetDrawBBox3D (var int vobPtr, var int onOff) {
//00645030 .text Debug data ?SetDrawBBox3D@zCVob@@QAEXH@Z
const int zCVob__SetDrawBBox3D_G1 = 6574128;
//0x006CFFE0 public: void __thiscall zCVob::SetDrawBBox3D(int)
const int zCVob__SetDrawBBox3D_G2 = 7143392;
if (!vobPtr) { return; };
CALL_IntParam (onOff);
CALL__thiscall (vobPtr, MEMINT_SwitchG1G2 (zCVob__SetDrawBBox3D_G1, zCVob__SetDrawBBox3D_G2));
};
/***
VobGetCollBits will return collision bitfield values
***/
FUNC INT VobGetCollBits (var int vobPtr) {
if (!vobPtr) { return 0; };
var int collBits; collBits = (zCVob_bitfield0_collDetectionStatic + zCVob_bitfield0_collDetectionDynamic);
var zCVob vob; vob = MEM_PtrToInst (vobPtr);
return (vob.bitfield[0] & (collBits));
};
/***
VobRemoveCollBits - will remove collisions based on input bitfield values in collBits
***/
FUNC VOID VobRemoveCollBits (var int vobPtr, var int collBits) {
if (!vobPtr) { return; };
var zCVob vob; vob = MEM_PtrToInst (vobPtr);
vob.bitfield[0] = vob.bitfield[0] & ~ (collBits);
};
/***
VobRestoreCollBits - will apply collisions based on input bitfield values in collBits
***/
FUNC VOID VobRestoreCollBits (var int vobPtr, var int collBits) {
if (!vobPtr) { return; };
var zCVob vob; vob = MEM_PtrToInst (vobPtr);
vob.bitfield[0] = vob.bitfield[0] | (collBits);
};
/***
Rotates vob on its X axis
***/
func void TRF_RotateLocalX(var zCVob obj, var int x) {
//005EE1A0 .text Debug data ?RotateLocalX@zCVob@@QAEXM@Z
const int zCVob__RotateLocalX_G1 = 6218144;
//0x0061B6B0 public: void __thiscall zCVob::RotateLocalX(float)
const int zCVob__RotateLocalX_G2 = 6403760;
CALL_FloatParam(x);
CALL__thiscall(MEM_InstToPtr(obj), MEMINT_SwitchG1G2 (zCVob__RotateLocalX_G1, zCVob__RotateLocalX_G2));
};
/***
Rotates vob on its Y axis
***/
func void TRF_RotateLocalY(var zCVob obj, var int x) {
//005EE210 .text Debug data ?RotateLocalY@zCVob@@QAEXM@Z
const int zCVob__RotateLocalY_G1 = 6218256;
//0x0061B720 public: void __thiscall zCVob::RotateLocalY(float)
const int zCVob__RotateLocalY_G2 = 6403872;
CALL_FloatParam(x);
CALL__thiscall(MEM_InstToPtr(obj), MEMINT_SwitchG1G2 (zCVob__RotateLocalY_G1, zCVob__RotateLocalY_G2));
};
/***
Rotates vob on its Z axis
***/
func void TRF_RotateLocalZ(var zCVob obj, var int x) {
//005EE280 .text Debug data ?RotateLocalZ@zCVob@@QAEXM@Z
const int zCVob__RotateLocalZ_G1 = 6218368;
//0x0061B790 public: void __thiscall zCVob::RotateLocalZ(float)
const int zCVob__RotateLocalZ_G2 = 6403984;
CALL_FloatParam(x);
CALL__thiscall(MEM_InstToPtr(obj), MEMINT_SwitchG1G2 (zCVob__RotateLocalZ_G1, zCVob__RotateLocalZ_G2));
};
/***
Rotates vob on its X Y Z axes
***/
func void TRF_RotateLocal(var zCVob obj, var int x, var int y, var int z) {
TRF_RotateLocalX(obj, x);
TRF_RotateLocalY(obj, y);
TRF_RotateLocalZ(obj, z);
};
//http://themodders.org/index.php?topic=10383.msg1256794#msg1256794
func void Vob_Move(var int ptr, var int x, var int y, var int z) {
const int zCVob__Move_G1 = 6217184; //0x5EDDE0
const int zCVob__Move_G2 = 6402784; //0x61B2E0
CALL_FloatParam (x);
CALL_FloatParam (y);
CALL_FloatParam (z);
CALL__thiscall (ptr, MEMINT_SwitchG1G2 (zCVob__Move_G1, zCVob__Move_G2));
};
func void MoveVobInFront(var int slfInstance, var int vobPtr) {
var zCVob slf; slf = Hlp_GetNPC (slfInstance);
var zCVob vob; vob = _^ (vobPtr);
//Move vob to NPC X Y Z coordinates
Vob.trafoObjToWorld [03] = slf.trafoObjToWorld [03];
Vob.trafoObjToWorld [07] = slf.trafoObjToWorld [07];
Vob.trafoObjToWorld [11] = slf.trafoObjToWorld [11];
//Adjust 'elevation'
Vob.trafoObjToWorld [07] = addf (Vob.trafoObjToWorld [07], mkf (vobTElevation));
//Keep vob data (rotation)
MEM_CopyBytes(_@(vob) + 60, vobPtr + 60, 64);
// Vob vor den Helden setzen
var int delta;
delta = mkf(150);
Vob_Move (vobPtr, mulf (slf.trafoObjToWorld[10], delta), mulf (slf.trafoObjToWorld[6], delta), mulf (slf.trafoObjToWorld[2], delta));
};
FrameHandler_VobTransport function - has to be called every frame:
Code:
FUNC VOID FrameHandler_vobTransport ()
{
//Loop through all nearby vobs
var int i;
var int loop;
var int vobPtr;
//Identification of object which should be moved around
if (vobTMode == cvobTMode_Init) {
//Safety-check
if (Hlp_IsValidNPC (hero)) {
var oCNPC her;
her = Hlp_GetNPC (hero);
var zCVob vob;
//Reset
vobTPtr = 0;
//Is there anything in hero's focus ?
if (her.focus_vob) {
//Move around following objects
if (Hlp_Is_oCMob (her.focus_vob))
|| (Hlp_Is_oCMobInter (her.focus_vob))
|| (Hlp_Is_oCMobFire (her.focus_vob))
|| (Hlp_Is_oCMobLockable (her.focus_vob))
|| (Hlp_Is_oCMobContainer (her.focus_vob))
|| (Hlp_Is_oCMobDoor (her.focus_vob))
|| (Hlp_Is_oCMobLadder (her.focus_vob))
{
//Get pointer of focus_vob
vobTPtr = her.focus_vob;
//Change vobTMode
vobTMode = cvobTMode_Select;
};
};
//Detect all nearby objects
NPC_ClearVobList (hero);
NPC_CreateVobList (hero, vobTRange);
vobTVobList = her.vobList_array;
//If there was nothing in focus - find an object
if (!vobTPtr) {
MEM_InitLabels ();
i = 0;
loop = MEM_StackPos.position;
if (her.vobList_numInArray > 0) {
vobPtr = MEM_ReadIntArray (her.vobList_array, i);
if (Hlp_Is_oCMob (vobPtr))
|| (Hlp_Is_oCMobInter (vobPtr))
|| (Hlp_Is_oCMobFire (vobPtr))
|| (Hlp_Is_oCMobLockable (vobPtr))
|| (Hlp_Is_oCMobContainer (vobPtr))
|| (Hlp_Is_oCMobDoor (vobPtr))
|| (Hlp_Is_oCMobLadder (vobPtr))
//zCVob
|| (MEM_ReadInt (vobPtr) == zCVob_vtbl)
{
//Is this vob in front of player - can player see it?
if (NPC_CanSee (hero, vobPtr, 0)) {
//Get pointer of moved object
vobTPtr = vobPtr;
//Change vobTMode
vobTMode = cvobTMode_Select;
};
};
//If vobTMode was not changed ... continue in loop (or exit)
if (vobTMode == cvobTMode_Init) {
i += 1;
if (i < her.vobList_numInArray) {
MEM_StackPos.position = loop;
};
};
};
};
};
//If vobTMode was not changed ... then there was no object detected - disable vobTMode
if (vobTMode == cvobTMode_Init) {
vobTMode = cvobTMode_Disabled;
} else {
//Select mode - draw BBox and lock hero
Vob_SetDrawBBox3D (vobTPtr, 1);
Hero_Lock ();
};
};
if (vobTMode == cvobTMode_Select_Next) {
//loop through vob list - select next in the list
var int flg_Next; flg_Next = FALSE;
/*
NPC_ClearVobList (hero);
NPC_CreateVobList (hero, vobTRange);
*/
her.vobList_array = vobTVobList;
MEM_InitLabels ();
i = 0;
loop = MEM_StackPos.position;
if (her.vobList_numInArray > 0) {
vobPtr = MEM_ReadIntArray (her.vobList_array, i);
if (Hlp_Is_oCMob (vobPtr))
|| (Hlp_Is_oCMobInter (vobPtr))
|| (Hlp_Is_oCMobFire (vobPtr))
|| (Hlp_Is_oCMobLockable (vobPtr))
|| (Hlp_Is_oCMobContainer (vobPtr))
|| (Hlp_Is_oCMobDoor (vobPtr))
|| (Hlp_Is_oCMobLadder (vobPtr))
//zCVob
|| (MEM_ReadInt (vobPtr) == zCVob_vtbl)
{
if (flg_Next == FALSE) {
if (vobTPtr == vobPtr) {
flg_Next = TRUE;
};
} else {
//Remove BBox from last vobPtr
Vob_SetDrawBBox3D (vobTPtr, 0);
//Get pointer of moved object
vobTPtr = vobPtr;
//Add Bbox to next vobPtr
Vob_SetDrawBBox3D (vobTPtr, 1);
NPC_ClearAIQueue (hero);
AI_TurnToVobPtr (hero, vobTPtr);
//Change vobTMode
vobTMode = cvobTMode_Select;
};
};
//If vobTMode was not changed ... continue in loop (or exit)
if (vobTMode == cvobTMode_Select_Next) {
i += 1;
if (i < her.vobList_numInArray) {
MEM_StackPos.position = loop;
};
vobTMode = cvobTMode_Select;
};
};
};
if (vobTMode == cvobTMode_Select_Previous) {
//loop through vob list - select previous in the list
var int flg_Previous; flg_Previous = FALSE;
//NPC_ClearVobList (hero);
//NPC_CreateVobList (hero, vobTRange);
her.vobList_array = vobTVobList;
MEM_InitLabels ();
i = 0;
loop = MEM_StackPos.position;
if (her.vobList_numInArray > 0) {
vobPtr = MEM_ReadIntArray (her.vobList_array, i);
if (Hlp_Is_oCMob (vobPtr))
|| (Hlp_Is_oCMobInter (vobPtr))
|| (Hlp_Is_oCMobFire (vobPtr))
|| (Hlp_Is_oCMobLockable (vobPtr))
|| (Hlp_Is_oCMobContainer (vobPtr))
|| (Hlp_Is_oCMobDoor (vobPtr))
|| (Hlp_Is_oCMobLadder (vobPtr))
//zCVob
|| (MEM_ReadInt (vobPtr) == zCVob_vtbl)
{
if (flg_Previous == FALSE) {
if (vobTPtr == vobPtr) {
flg_Previous = TRUE;
};
} else {
//Remove Bbox from last vobPtr
Vob_SetDrawBBox3D (vobTPtr, 0);
//Get pointer of moved object
vobTPtr = vobPtr;
//Add Bbox to previous vobPtr
Vob_SetDrawBBox3D (vobTPtr, 1);
NPC_ClearAIQueue (hero);
AI_TurnToVobPtr (hero, vobTPtr);
//Change vobTMode
vobTMode = cvobTMode_Select;
};
};
//If vobTMode was not changed ... continue in loop (or exit)
if (vobTMode == cvobTMode_Select_Previous) {
if (flg_Previous == FALSE) {
i += 1;
if (i < her.vobList_numInArray) {
MEM_StackPos.position = loop;
};
} else {
if (i > 0) {
i -= 1;
};
MEM_StackPos.position = loop;
};
vobTMode = cvobTMode_Select;
};
};
};
if (vobTMode == cvobTMode_Select_Confirm) {
//Backup collision bitfields
vobTCollBits = VobGetCollBits (vobTPtr);
//Remove active collisions
VobRemoveCollBits (vobTPtr, vobTCollBits);
vobTMode = cvobTMode_Moving;
Hero_UnLock ();
};
//Moving mode
if (vobTMode == cvobTMode_Moving) {
if (vobTPtr) {
//Move object in front of hero (X, Y, Z)
MoveVobInFront (hero, vobTPtr);
Vob = _^ (vobTPtr);
//Rotate
TRF_RotateLocal (Vob, mkf (vobTRotX), mkf (vobTRotY), mkf (vobTRotZ));
vobTRotX = 0; vobTRotY = 0; vobTRotZ = 0;
//Align vob to floor
if (vobTModeXYZE != cvobTRotationMode_E) {
if (vobTModeAlignToFloor == TRUE) {
SetVobToFloor (vobTPtr);
};
};
};
};
//Stop transport mode
if (vobTMode == cvobTMode_Done) {
//Restore collision bitfields
VobRestoreCollBits (vobTPtr, vobTCollBits);
//Disable vobTMode
vobTMode = cvobTMode_Disabled;
};
};
This one will be triggered from gameKeyEvents.d
Code:
/*
* Customizable function to handle key events (pressed is FALSE: key is held, pressed is TRUE: key press onset)
*/
func void Game_KeyEvent(var int key, var int pressed) {
//--- Activate Vob Transport mode
if (key == KEY_LBRACKET) && (pressed)
{
//Start vob/focus selection
if (vobTMode == cvobTMode_Disabled) {
vobTMode = cvobTMode_Init;
vobTMovementSpeed = 1;
};
//Confirm selection
if (vobTMode == cvobTMode_Select) {
vobTMode = cvobTMode_Select_Confirm;
};
//End interaction
if (vobTMode == cvobTMode_Moving) {
Vob_SetDrawBBox3D (vobTPtr, 0);
Hero_UnLock ();
vobTModeXYZE = cvobTRotationMode_0;
vobTMode = cvobTMode_Done;
};
};
if (vobTMode == cvobTMode_Select) {
//Select previous Vob
if (key == KEY_LEFTARROW) && (pressed) {
if (vobTMode == cvobTMode_Select) {
vobTMode = cvobTMode_Select_Previous;
};
};
//Select next Vob
if (key == KEY_RIGHTARROW) && (pressed) {
if (vobTMode == cvobTMode_Select) {
vobTMode = cvobTMode_Select_Next;
};
};
//Cancel selection (escape is bringing main menu :()
if (key == KEY_ESCAPE) && (pressed)
|| (key == KEY_RBRACKET) && (pressed) {
Vob_SetDrawBBox3D (vobTPtr, 0);
Hero_UnLock ();
vobTModeXYZE = cvobTRotationMode_0;
vobTMode = cvobTMode_Disabled;
};
};
if (vobTMode == cvobTMode_Moving) {
//Align to surface on/off
if (vobTModeXYZE != cvobTRotationMode_E) {
if (key == KEY_RBRACKET) && (pressed) {
vobTModeAlignToFloor = !vobTModeAlignToFloor;
};
};
//Space - increase movement speed 1 - 10 - 20
if (key == KEY_SPACE) && (pressed) {
if (vobTMovementSpeed == 1) {
vobTMovementSpeed = 10;
} else
if (vobTMovementSpeed == 10) {
vobTMovementSpeed = 20;
} else {
vobTMovementSpeed = 1;
};
};
//X - rotate X axis
if (key == KEY_X) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_X) {
vobTModeXYZE = cvobTRotationMode_0;
Hero_UnLock ();
} else {
vobTModeXYZE = cvobTRotationMode_X;
Hero_Lock ();
};
};
//Y - rotate Y axis
if (key == KEY_Y) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_Y) {
vobTModeXYZE = cvobTRotationMode_0;
Hero_UnLock ();
} else {
vobTModeXYZE = cvobTRotationMode_Y;
Hero_Lock ();
};
};
//Z - rotate Z axis
if (key == KEY_Z) && (pressed)
{
if (vobTModeXYZE == cvobTRotationMode_Z) {
vobTModeXYZE = cvobTRotationMode_0;
Hero_UnLock ();
} else {
vobTModeXYZE = cvobTRotationMode_Z;
Hero_Lock ();
};
};
//E - elevate
if (key == KEY_E) && (pressed)
{
if (vobTModeXYZE == cvobTRotationMode_E) {
vobTModeXYZE = cvobTRotationMode_0;
Hero_UnLock ();
} else {
vobTModeXYZE = cvobTRotationMode_E;
Hero_Lock ();
};
};
//--- Rotation - left / down key
if (key == KEY_LEFTARROW) && (pressed)
|| (key == KEY_DOWNARROW) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_X) {
vobTRotX -= vobTMovementSpeed;
};
if (vobTModeXYZE == cvobTRotationMode_Y) {
vobTRotY -= vobTMovementSpeed;
};
if (vobTModeXYZE == cvobTRotationMode_Z) {
vobTRotZ -= vobTMovementSpeed;
};
};
// right / up key
if (key == KEY_RIGHTARROW) && (pressed)
|| (key == KEY_UPARROW) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_X) {
vobTRotX += vobTMovementSpeed;
};
if (vobTModeXYZE == cvobTRotationMode_Y) {
vobTRotY += vobTMovementSpeed;
};
if (vobTModeXYZE == cvobTRotationMode_Z) {
vobTRotZ += vobTMovementSpeed;
};
};
//--- Elevation - up - down key
if (key == KEY_UPARROW) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_E) {
vobTElevation += vobTMovementSpeed;
};
};
if (key == KEY_DOWNARROW) && (pressed) {
if (vobTModeXYZE == cvobTRotationMode_E) {
vobTElevation -= vobTMovementSpeed;
};
};
//--- Safety checks for rotation
if (vobTRotX < 0) { vobTRotX = 360 - (0 - vobTRotX); };
if (vobTRotY < 0) { vobTRotY = 360 - (0 - vobTRotY); };
if (vobTRotZ < 0) { vobTRotZ = 360 - (0 - vobTRotZ); };
if (vobTRotX > 360) { vobTRotX = vobTRotX - 360; };
if (vobTRotY > 360) { vobTRotY = vobTRotY - 360; };
if (vobTRotZ > 360) { vobTRotZ = vobTRotZ - 360; };
};
};
Geändert von F a w k e s (25.12.2020 um 18:47 Uhr)
Grund: Added AI_TurnToVob piece + check for vobTPtr = 0 .
-
I want to use this system in Gothic 2... I paste your code into a new file and added the missing G2 constats (oCMobLadder_vtbl and cZVob_vtbl). After that I added "Game_KeyEventInit()" and "FF_ApplyOnce(FrameHandler_VobTransport)" to my init_global... But I can't activate the transport mode... Did I miss something?
-
Ok it was my fault... works like a charm in g2!
-
Fawkes, this is amazing!
It would be nice to add some spell effect. will looks more in Gothic style.
Geändert von pawbuj (18.03.2019 um 08:32 Uhr)
-
Say, since when do you work at this moving vob feature? I got it in my mod since about 2016 and it was one of my best features... until you released this script for everyone. I don't wanna say that I'm pissed. I'm just slightly... no theres no better word. I AM pissed. All the hard work and now everyone has it.
"Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
-Korallenkette
-
Zitat von Bisasam
Say, since when do you work at this moving vob feature? I got it in my mod since about 2016 and it was one of my best features... until you released this script for everyone. I don't wanna say that I'm pissed. I'm just slightly... no theres no better word. I AM pissed. All the hard work and now everyone has it.
Hi Bisasam,
I started on 10th of March and finished what I wanted to have in it on 14th of March. I believe in open-source, that's why I shared my code, hoping it can be helpful to others.
-
Zitat von Bisasam
Say, since when do you work at this moving vob feature? I got it in my mod since about 2016 and it was one of my best features... until you released this script for everyone. I don't wanna say that I'm pissed. I'm just slightly... no theres no better word. I AM pissed. All the hard work and now everyone has it.
Ich kann ja verstehen, dass dich das ein bisschen ärgert, aber du kannst da F a w k e s nicht wirklich einen Vorwurf machen, meine ich. Er hat das Feature ja wohl völlig unabhängig von dir entwickelt. Ich weiß jetzt gar nicht, ob du das mal öffentlich außerhalb von deinen Tests präsentiert hast. Wie hätte F a w k es denn dieses Feature „stehlen“ sollen?
Geändert von Moe (24.03.2019 um 13:59 Uhr)
-
Zitat von Bisasam
Say, since when do you work at this moving vob feature? I got it in my mod since about 2016 and it was one of my best features... until you released this script for everyone. I don't wanna say that I'm pissed. I'm just slightly... no theres no better word. I AM pissed. All the hard work and now everyone has it.
Modding is not a competition. It should be a way to express your ideas and create a wonderful and interesting experience for others. Feeling upset is okay, but expressing this anger openly (and feeling justified to do that!) just because someone decided to share his work with the community is despicable. How would you feel if Sektenspinner or Gottfried and me* never shared our work? Your feature relies on the spirit of open source as well, don't forget that.
*Increasingly often I get the feeling I should simply license LeGo under the GPL to be done with this high school drama.
-
Das hier ist ein Forum, oder? Warum kann ich nicht schreiben, wie ich mich fühle und warum? Ich habe ihn nicht beleidigt. Es ist nur so, dass das (in meinen Augen) häufiger vorkommt. Letztens hat Mud-Freak ja meinen kompletten Taschendiebstahlscode neu geschrieben. Ich sage nicht, dass ich die Arbeit daran schlecht finde (zumal er ja auch noch gesagt hat, dass er lieber meinen Namen drunter stehen hätte weil er weiß, wie viel Arbeit da reingeflossen ist), es geht eher darum, dass mir oft das Gefühl gegeben wird, dass jeder alles besser kann als ich. Und das frustriert. Wieso werde ich denn gleich so angefahren, wenn ich das mal anspreche? Ich bin keine Heilige, ich habe Gefühle und die würde ich gern an- und aussprechen statt sie in mich reinzufressen.
Im Moment komme ich mir so vor, als würde ich eine Wissenschaftliche Arbeit verfassen und jedes Mal, wenn ich etwas beinahe releasefertig habe, bringt jemand anderes es früher raus, wodurch ich wie der Abkupferer aussehe. Dabei soll das hier doch kein Wettbewerb sein. Warum fühlt es sich nur so an?
Das Feature wurde übrigens schon in diesem Video öffentlich vorgestellt: https://www.youtube.com/watch?v=lve0nNTqFPs (letzte 5 Minuten) Soweit ich weiß gabs da auch ne News zu.
"Das erinnert doch sehr erfreulich an das, was man sich als Gothicfan wünscht!"
-Korallenkette
Geändert von Bisasam (26.03.2019 um 21:24 Uhr)
-
Apprentice
Hey Siemekk, thanks for the ani scripts!
Zitat von Siemekk
Because i finished work in Ikarus and now i'm using AST(Agama Script Tools) i decided to share my scripts
Some Engine scripts:
Code:
func void SetAsPlayer (var C_NPC slf)
{
const int oCNpc__SetAsPlayer = 7612064;
CALL__thiscall (MEM_InstToPtr (slf), oCNpc__SetAsPlayer);
};
func int Menu_ReadInt(var string category, var string name) //int
{
var string value; value = Mem_GetGothOpt(category, name);
return STR_ToInt(value);
};
func void Menu_WriteInt(var string category, var string name, var int value)
{
MEM_SetGothOpt(category,name, IntToString(value));
};
func int oCNpc_GetModel(var int npc) //zCModel*
{
const int oCNpc__GetModel = 7571232;
CALL__thiscall(MEM_InstToPtr(npc), oCNpc__GetModel);
return CALL_RetValAsInt();
};
func int AniIsActive(var c_npc slf, var string aniname) //BOOL
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel_AniIsActive = 5727888;//0x00576690
CALL_zStringPtrParam(Str_Upper(aniname));
CALL__thiscall(ptr,zCModel_AniIsActive);
return CALL_RetValAsInt();
};
func int zCVisual_LoadVisual(var string vis) //zCVisual*
{
const int zCVisual__LoadVisual = 6318800; //0x00606AD0
CALL_zStringPtrParam(STR_Upper(vis));
CALL__cdecl(zCVisual__LoadVisual);
return CALL_RetValAsInt();
};
func int StringIsEmpty(var string str) //BOOL
{
if(STR_Len(str)>=1)
{
return true;
};
return false;
};
func void Set_ItemVisual(var int itm, var string vis)
{
const int oCItem__SetVisual = 7411984; //0x00711910
CALL_PtrParam(zCVisual_LoadVisual(vis));
CALL__thiscall(MEM_InstToPtr(itm),oCItem__SetVisual);
};
func int zCModel_SearchNode(var int model, var string node) //zCModelNodeInst*
{
CALL_zStringPtrParam(Str_Upper(node));
CALL__thiscall(model, zCModel__SearchNode);
return CALL_RetValAsInt();
};
func void Ext_PutInSlot(var int pnpc, var string node, var string visual)
{
const int zCModel__SetNodeVisual = 5739168;
var int model; model = oCNpc_GetModel(pnpc);
var int vis; vis = zCVisual_LoadVisual(visual);
var int nde; nde = zCModel_SearchNode(model,node);
CALL_IntParam(1); //3 param
CALL_PtrParam(vis); //2 param - vis
CALL_PtrParam(nde); //1 param get node
CALL__thiscall(model, zCModel__SetNodeVisual);
};
func void Ext_PutInSlot2(var int pnpc, var string node, var int vob) //Used to mounts system (hero, "NODE", her.focus_vob)
{
var int model; model = oCNpc_GetModel(pnpc);
var int nde; nde = zCModel_SearchNode(model,node);
CALL_PtrParam(1); //1 param get node
var int vb; vb = MEM_InstGetOffset(vob);
CALL_PtrParam(MEM_ReadInt(vb+200)); //2 param - vis
CALL_PtrParam(nde); //1 param get node
CALL__thiscall(model, zCModel__SetNodeVisual);
};
func int Get_AniIDFromAniName(var int slf, var string aniName) //int
{
const int zCModel__AniIDFromAniName = 6365296; //0x00612070
var int model; model = oCNpc_GetModel(slf);
CALL_zStringPtrParam(Str_Upper(aniName));
CALL__thiscall(model,zCModel__AniIDFromAniName);
return CALL_RetValAsInt();
};
func int GetAniFromAniID(var c_npc slf, var string aniName) //zCModelAni*
{
const int zCModel__GetAniFromAniID = 4665168; //0x00472F50
var int model; model = oCNpc_GetModel(slf);
var int ani; ani = Get_AniIDFromAniName(slf,aniName);
CALL_PtrParam(ani);
CALL__thiscall(model,zCModel__GetAniFromAniID);
return CALL_RetValAsInt();
};
func void Set_AniFPS(var c_npc slf, var string aniName, var int FPS)
{
var int ptr;
ptr = GetAniFromAniID(slf, aniName);
MEM_WriteInt(ptr+176, mkf(FPS));
};
func int GetNodeBBox3D(var int slf, var string bone) //Get Node BBox - Hitboxes or Check collision
{
var int model; model = oCNpc_GetModel(slf);
var int node; node = zCModel_SearchNode(model,bone);
CALL_PtrParam(node);
CALL_RetValIsStruct(24); //6*4
CALL__thiscall(model,zCModel__GetBBox3DNodeWorld);
return CALL_RetValAsPtr();
};
func oCItem Hlp_GetItem(var int inst) //oCItem*
{
var zCPar_Symbol symb; symb = _^(MEM_GetSymbolByIndex(inst));
_^(symb.offset);
};
I changed your ani functions a bit and made some more.
Your scripts:
Code:
/**
* get pointer to model object
* @param npc pointer to npc object
*/
func int oCNpc_GetModel(var int npc) //zCModel*
{
const int oCNpc__GetModel = 7571232;
CALL__thiscall(MEM_InstToPtr(npc), oCNpc__GetModel);
return CALL_RetValAsInt();
};
/**
* checks if ani with given name is currently active
* @param slf npc
* @param aniname name of ani
*/
func int zCModel_AniIsActive(var c_npc slf, var string aniname) //BOOL
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel_AniIsActive = 5727888;//0x00576690
CALL_zStringPtrParam(Str_Upper(aniname));
CALL__thiscall(ptr,zCModel_AniIsActive);
return CALL_RetValAsInt();
};
/**
* get pointer to ani object with given name of ani
* @param slf npc
* @param aniname name of ani
*/
func int zCModel_AniFromAniName(var c_npc slf, var string aniName) //zCModelAni*
{
const int zCModel__AniIDFromAniName = 6365296; //0x00612070
const int zCModel__GetAniFromAniID = 4665168; //0x00472F50
var int model; model = oCNpc_GetModel(slf);
// get ani id
CALL_zStringPtrParam(Str_Upper(aniName));
CALL__thiscall(model,zCModel__AniIDFromAniName);
var int id; id = CALL_RetValAsInt();
// get ani object ptr
CALL_PtrParam(id);
CALL__thiscall(model,zCModel__GetAniFromAniID);
// return ptr to ani object
return CALL_RetValAsInt();
};
And my new functions:
Code:
// Active ani functions
/**
* get progress of given ani as float (0.0 to 1.0)
* given ani should be active (check first)
* @param slf npc
* @param aniName name of the ani
*/
func int zCModel_GetProgressPercent(var c_npc slf, var string aniName) // float
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel__GetProgressPercent = 5763728; // 0x0057F290
CALL_RetValIsFloat(); // method returns float
CALL_zStringPtrParam(Str_Upper(aniName));
CALL__thiscall(ptr,zCModel__GetProgressPercent);
return CALL_RetValAsFloat();
};
/**
* get pointer to active ani object
* @param slf npc
* @param zCModelAniPtr pointer to ani object
*/
func int zCModel_GetActiveAni(var c_npc slf, var int zCModelAniPtr) // zCModelAniActive*
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel__GetActiveAni = 5745568; // 0x0057ABA0
CALL_PtrParam(zCModelAniPtr);
CALL__thiscall(ptr,zCModel__GetActiveAni);
return CALL_RetValAsInt();
};
/**
* get the progress of current active ani as float (0.0 to 1.0)
* @param zCModelAniActivePtr pointer to active ani object
*/
func int zCModelAniActive_GetProgressPercent(var int zCModelAniActivePtr) // float
{
const int zCModelAniActive__GetProgressPercent = 5729376; // 0x00576C60
CALL_RetValIsFloat(); // method returns float
CALL__thiscall(zCModelAniActivePtr,zCModelAniActive__GetProgressPercent);
return CALL_RetValAsFloat();
};
// Model Ani
/**
* check if ani object is active
* @param slf npc
* @param zCModelAniPtr pointer to ani object
*/
func int zCModel_IsAniActive(var c_npc slf, var int zCModelAniPtr) //BOOL
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel__IsAniActive = 4665232; //0x00472F90
CALL_PtrParam(zCModelAniPtr);
CALL__thiscall(ptr,zCModel__IsAniActive);
return CALL_RetValAsInt();
};
/**
* get pointer to ani with given id
* @param slf npc
* @param id id of ani
*/
func int zCModel_GetAniFromAniID(var c_npc slf, var int id) //zCModelAni*
{
const int zCModel__GetAniFromAniID = 4665168; //0x00472F50
var int model; model = oCNpc_GetModel(slf);
CALL_IntParam(id);
CALL__thiscall(model,zCModel__GetAniFromAniID);
return CALL_RetValAsInt();
};
/**
* get name of ani
* @param zCModelAniPtr pointer to ani object
*/
func string zCModel_GetAniName(var int zCModelAniPtr) //zSTRING&
{
const int zCModelAni__GetAniName = 5886304; //0x0059D160
CALL__thiscall(zCModelAniPtr,zCModelAni__GetAniName);
return CALL_RetValAszStringPtr();
};
/**
* recursive function to find the current active animation
* @param aniIdLoop current point of search (should be 0 at start)
* @param endLoop ending point of search
*/
func int GetAniID(var int aniIdLoop, var int endLoop) //zCModelAni*
{
if (aniIdLoop <= endLoop)
{
var int zCModelAniPtr;
zCModelAniPtr = zCModel_GetAniFromAniID(hero, aniIdLoop);
// check if ani is active
if (zCModelAniPtr > 0 && zCModel_IsAniActive(hero, zCModelAniPtr))
{
return zCModelAniPtr; // found the ani!
} else {
return GetAniID(aniIdLoop + 1, endLoop); // recursive call
};
} else {
return -1; // failed to find current ani (shouldn't happen)
};
};
zCModel_GetProgressPercent() and zCModelAniActive_GetProgressPercent() returning the same float value as int. Don't forget to cast the int values to floats with the scripts in float.d (castFromIntf(floatnumber) ).
@Sektenspinner könntest du noch Zerxes Liste in dein Ikarus Paket mit aufnehmen? Wäre ganz praktisch, da ich erst das halbe Forum durchforsten musste, bis ich loslegen konnte.
Link: https://forum.worldofplayers.de/foru...7#post17631567
Geändert von Migos (31.03.2019 um 18:03 Uhr)
-
Zitat von Migos
@Sektenspinner [...]
Hey Mann, neu hier? [Bild: mud.png]
Sektenspinner ist soweit ich weiß lange nicht mehr aktiv. Ich denke eine Verlinkung im Ikarus-Startpost könnte nicht schaden. Direkt in Ikarus mit aufnehmen halte ich aber nicht für sinnvoll.
@Bisasam: Ich kann das nachvollziehen. Es ist ärgerlich, dass dieses Feature möglicherweise in deiner Mod nun nicht mehr so innovativ wirkt. Allerdings auch nur, wenn jemand eine Mod mit dem Feature vor deiner veröffentlicht. Selbst dann denke ich aber, dass deine Mod, die du von Beginn an (oder zumindest seit langem) um dieses Feature herum aufgebaut hast, viel mehr Tiefe bietet als das jede andere Mod könnte, die das Feature jetzt einfach noch irgendwie quer reinschlägt einfach nur "weil es ein cooles Feature" ist.
Das Gefühl, dass "jeder alles besser kann", kannst du deshalb auch in größerem Kontext betrachten. Solange es funktioniert, ist dem Spieler völlig egal, wie ein Feature nun in einer Mod implementiert ist. Was aber nicht egal ist und wo es viel wichtiger ist "gut" drin zu sein, ist es wie man eine Geschichte erzählt und eben solche Features in Quests einbindet.
-
Grundsätzlich kann ich natürlich den Unmut oder die Frustration über die Geschehnisse verstehen, allerdings möchte ich eben verhindern, dass sich jemand aus diesen Gründen mit der Veröffentlichung von Scripten o.ä. zurückhält, z.B. um dir oder jemand anderem nicht auf die Füße zu treten. Denn das wäre wahrlich ein trauriger Verlust - unsere Community ist bereits jetzt klein genug und die meisten sind mit ihren eigenen Projekten beschäftigt, so dass nur wenige etwas beitragen, von dem wirklich alle Modder profitieren können. Ebenso glücklicher bin ich, dass der ScriptBin hier relativ gut angenommen wurde (und von mir in der nächsten Zeit auch mal aktualisiert wird - versprochen).
Davon abgesehen würde ich gerne an mud-freaks Post verweisen, der das besser in Worte gefasst hat als ich es könnte. Technische Features mögen zwar eine Grundlage für Mods bieten, aber der eigentliche Erfolg - also eine gute Mod - kommt erst durch gutes Storywriting und eine immersive/interaktive Welt (und das weißt du doch eigentlich auch ).
Dass es dir als (annähernde?) Allrounderin so vorkommt, als wären 'alle' besser als du ist nicht weiter verwunderlich - ich (und einige andere) haben sich die Freiheit genommen, nur das zu tun, was wir wirklich gut und gerne machen ((Feature-)Scripting in meinem Fall). Wenn ich mich mit dir im Spacern, 3D-Editing oder Story-/Questwriting vergleichen würde, bräuchte es keine 5 Minuten um jedem klarzumachen, dass ich den Kürzeren ziehen werde. Nach diesem Maßstab wärst du also sogar dreimal so gut wie ich
Zitat von Migos
Abgesehen von dem, was mud-freak sagt, findet man den Link dazu auch im LeGo-Wiki (unter Sonstiges -> EngineFunktionen). Hilft dir jetzt natürlich nicht mehr viel
-
Apprentice
Zitat von mud-freak
Hey, für WoG Verhältnisse wahrscheinlich schon Aber Gothic spiele ich schon weitaus länger
Zitat von mud-freak
Sektenspinner ist soweit ich weiß lange nicht mehr aktiv. Ich denke eine Verlinkung im Ikarus-Startpost könnte nicht schaden. Direkt in Ikarus mit aufnehmen halte ich aber nicht für sinnvoll.
Ah schade, aber ja, so eine Verlinkung würde schon ausreichen. Mein Vorschlag war eher diese Funktionen schon als fertig aufrufbare Scripts zu implementieren und in das Ikarus Paket aufzunehmen. Wenn man dann noch nach und nach dokumentieren würde, was die Funktionen genau machen, würde das denke ich mal immens beim modden helfen.
@Thora: Sehe das im SP Bereich halb so wild. Du hast ja nicht wirklich Konkurrenz hier, ganz im Gegensatz zu den MP Projekten, wo es schnell zum Problem wird wenn du nicht genügend Spieler auf dem Server hast
Ich weiß noch, wie wir damals für CK nächtelang geforscht haben was alles GMP tauglich ist und was nicht. #Wetterwanze
Letztendlich war die Lösung für den synchronen Regen einfach nur das Verstellen der Engine-Zeit auf 16:30 Uhr, weil es am ersten Tag genau um diese Uhrzeit immer regnet. Mittlerweile aber total nutzlos, weil es viel bessere Methoden gibt und der GMP auch weiter entwickelt wird. Was ich damit sagen will: man muss immer mit der Zeit gehen und auch erwarten, dass andere dasselbe machen. Also Kopf hoch und weitermachen.
-
Zitat von Migos
Hey, für WoG Verhältnisse wahrscheinlich schon Aber Gothic spiele ich schon weitaus länger
Ah schade, aber ja, so eine Verlinkung würde schon ausreichen. Mein Vorschlag war eher diese Funktionen schon als fertig aufrufbare Scripts zu implementieren und in das Ikarus Paket aufzunehmen. Wenn man dann noch nach und nach dokumentieren würde, was die Funktionen genau machen, würde das denke ich mal immens beim modden helfen.
Das sind mehrere tausend Funktionen, wenn ich mich nicht irre. Da der Daedalus-Compiler keine Optimierungen vornimmt, landen die dann immer auch in der Gothic.dat. Ich würde schätzen, dass das die Anzahl der Symbole um 5-10x erhöhen würde. Theoretisch ist das nicht schlimm (außer der Codestack hat eine maximale Größe?), aber praktisch sollte man das vermutlich lieber vermeiden.
-
G1 Disable damage animations and interruptions
Hello folks,
Fingers crossed that no one will be pissed off this time.
I would like to share code, which will improve your Gothic 1 combat experience. So far I did not encounter any issues with it, I will appreciate every feedback if you see anything. If player is in fighting mode, this will disable 2 things - animations which are played when damage is inflicted and function oCNpc__Interrupt. In case that player was swarmed by NPCs (Molerats are great example) each attack would interrupt player's action. Which was incredibly annoying and frustrating.
@Lehona - big thank you, I have used your code (original post below) as a starting point, and adapted it for G1:
https://forum.worldofplayers.de/foru...1#post24744467
Required:
class definition for oSDamageDescriptor (from Lehona):
https://forum.worldofplayers.de/foru...1#post19002341
Code:
/***
Gothic 1
Function will disable/enable oCNpc__Interrupt
***/
FUNC VOID NPC_Interrupt_SetEnabled (var int enabled)
{
//00692830 .text Debug data ?Interrupt@oCNpc@@QAEXH@Z
const int oCNpc__Interrupt = 6891568;
MemoryProtectionOverride (oCNpc__Interrupt, 3);
//RAM hex values @ h 00692830
//83 EC 10 53 56 8B F1 8B 9E B4 09 00 00 ...
if (enabled) {
//Restore original values
MEM_WriteByte (oCNpc__Interrupt, 131); //83
MEM_WriteByte (oCNpc__Interrupt + 1, 236); //EC
MEM_WriteByte (oCNpc__Interrupt + 2, 16); //10
} else {
//Taken from LeGo 2.5.1 ReplaceEngineFuncI -> write return instruction at the beginning of a function
MEM_WriteByte (oCNpc__Interrupt, 194);
MEM_WriteByte (oCNpc__Interrupt + 1, 4);
MEM_WriteByte (oCNpc__Interrupt + 2, 0);
};
};
/***
Gothic 1
Hook below will disable animation & function oCNpc__Interrupt - both would interrupt player while fighting.
***/
FUNC VOID _HOOK_DMG_ONDMG_ANIMATION ()
{
var C_NPC slf;
slf = _^ (ECX);
var oSDamageDescriptor dmgDescriptor;
dmgDescriptor = _^ (MEM_ReadInt (ESP + 4));
//Enable by default (seems like oCNpc__Interrupt is called right after oCNpc__OnDamage_Anim)
NPC_Interrupt_SetEnabled (TRUE);
//If damage was inflicted by Barrier (no attackerNpc) player was not thrown away
if (!dmgDescriptor.attackerNpc) { return; };
if (C_NPC_IsPlayer (slf))
{
//If player is not in fight mode, we can apply animations and interruption
if (!NPC_IsInFightMode (slf, FMODE_FIST))
&& (!NPC_IsInFightMode (slf, FMODE_MELEE))
&& (!NPC_IsInFightMode (slf, FMODE_FAR))
&& (!NPC_IsInFightMode (slf, FMODE_MAGIC)) {
return;
};
//We need to find out damageType
var int damageType; damageType = 0;
var C_NPC oth;
oth = _^ (dmgDescriptor.attackerNpc);
//Spell
if (dmgDescriptor.spellID != 0)
&& (dmgDescriptor.spellID != -1) {
//Seems like damageType = dmgDescriptor.spellLevel
damageType = dmgDescriptor.spellLevel;
};
var C_Item weapon;
//Weapon
if (dmgDescriptor.itemWeapon != 0) {
weapon = _^ (dmgDescriptor.itemWeapon);
//Ranged weapon has spellID == -1
//In case of ranged weapon dmgDescriptor.itemWeapon returns amunition
//So we have to check either Readied weapon or Equipped weapon (fingers crossed NPC didn't switch these that fast)
if (dmgDescriptor.spellID == -1) {
if (NPC_IsInFightMode(oth, FMODE_FAR)) {
weapon = NPC_GetReadiedWeapon (oth);
} else if (NPC_HasEquippedRangedWeapon (oth)) {
weapon = NPC_GetEquippedRangedWeapon (oth);
};
};
//Get weapon damageType
damageType = weapon.damageType;
//Fist mode - get NPC damageType
} else {
damageType = oth.damageType;
};
//If damage was inflicted by Troll (DAM_FLY) player was not thrown away - so don't do anything here
if (damageType & DAM_FLY) { return; };
if (damageType != 0) {
//EAX = 0 will disable animation T_STUMBLE / T_STUMBLEB / T_GOTHIT / (maybe more animations ?)
EAX = 0;
//Disable interruption for player
NPC_Interrupt_SetEnabled (FALSE);
};
};
};
Hook it with:
Code:
//I am sure this address is from Lehona as well :)
HookEngine (7609592, 9, "_HOOK_DMG_ONDMG_ANIMATION");
-
Many thanks for ur efforts. Looks like not many G1 bugs left.
I heard about some problem with ice-wave spell (not tested!). Also haste potions needs to be fixed after save/load game.
-
G1 SPL_ICECUBE, SPL_ICEWAVE, SPL_FEAR fix
Zitat von pawbuj
Many thanks for ur efforts Fawkes. Looks like not many G1 bugs left.
I heard about some problem with ice-wave spell. Also haste potions needs to be fixed after save/load game.
Hi pawbuj,
You can fix these spells: SPL_ICECUBE, SPL_ICEWAVE, SPL_FEAR (maybe more of them, I noticed these were trouble-makers) within hook for damage calculation. When these spells will hit NPC, their respective B_AssessMagic* functions will be called -> you can remove their B_AssessMagic* functions from func void B_AssessMagic ().
If you don't have such hook, you can even use this one from my previous post _HOOK_DMG_ONDMG_ANIMATION:
Code:
FUNC VOID _HOOK_DMG_ONDMG_ANIMATION ()
{
var C_NPC slf;
slf = _^ (ECX);
var oSDamageDescriptor dmgDescriptor;
dmgDescriptor = _^ (MEM_ReadInt (ESP + 4));
//Enable by default (seems like oCNpc__Interrupt is called right after oCNpc__OnDamage_Anim)
NPC_Interrupt_SetEnabled (TRUE);
//If damage was inflicted by Barrier (no attackerNpc) player was not thrown away
if (!dmgDescriptor.attackerNpc) { return; };
var C_NPC oth;
oth = _^ (dmgDescriptor.attackerNpc);
//--- fix for spells SPL_ICECUBE, SPL_ICEWAVE, SPL_FEAR
if (dmgDescriptor.spellID != 0)
&& (dmgDescriptor.spellID != -1) {
var C_NPC self_backup;
var C_NPC other_backup;
//--- Backup self & other
self_backup = Hlp_GetNPC (self);
other_backup = Hlp_GetNPC (other);
/***
Call B_AssessMagic functions
self = victim & other = attacker within B_AssessMagic
***/
self = Hlp_GetNPC (slf);
other = Hlp_GetNPC (oth);
if (dmgDescriptor.spellID == SPL_ICECUBE)
|| (dmgDescriptor.spellID == SPL_ICEWAVE) {
MEM_Call (B_AssessMagic_IceCube);
};
if (dmgDescriptor.spellID == SPL_FEAR) {
MEM_Call (B_AssessMagic_Fear);
};
//Restore self & other
self = Hlp_GetNPC (self_backup);
other = Hlp_GetNPC (other_backup);
};
//---
if (C_NPC_IsPlayer (slf))
{
//If player is not in fight mode, we can apply animations and interruption
if (!NPC_IsInFightMode (slf, FMODE_FIST))
&& (!NPC_IsInFightMode (slf, FMODE_MELEE))
&& (!NPC_IsInFightMode (slf, FMODE_FAR))
&& (!NPC_IsInFightMode (slf, FMODE_MAGIC)) {
return;
};
//We need to find out damageType
var int damageType; damageType = 0;
//Spell
if (dmgDescriptor.spellID != 0)
&& (dmgDescriptor.spellID != -1) {
//Seems like damageType = dmgDescriptor.spellLevel
damageType = dmgDescriptor.spellLevel;
};
var C_Item weapon;
//Weapon
if (dmgDescriptor.itemWeapon != 0) {
weapon = _^ (dmgDescriptor.itemWeapon);
//Ranged weapon has spellID == -1
//In case of ranged weapon dmgDescriptor.itemWeapon returns amunition
//So we have to check either Readied weapon or Equipped weapon (fingers crossed NPC didn't switch these that fast)
if (dmgDescriptor.spellID == -1) {
if (NPC_IsInFightMode(oth, FMODE_FAR)) {
weapon = NPC_GetReadiedWeapon (oth);
} else if (NPC_HasEquippedRangedWeapon (oth)) {
weapon = NPC_GetEquippedRangedWeapon (oth);
};
};
//Get weapon damageType
damageType = weapon.damageType;
//Fist mode - get NPC damageType
} else {
damageType = oth.damageType;
};
//If damage was inflicted by Troll (DAM_FLY) player was not thrown away - so don't do anything here
if (damageType & DAM_FLY) { return; };
if (damageType != 0) {
//EAX = 0 will disable animation T_STUMBLE / T_STUMBLEB / T_GOTHIT / (maybe more animations ?)
EAX = 0;
//Disable interruption for player
NPC_Interrupt_SetEnabled (FALSE);
};
};
};
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|
|