Skip to content

Commit

Permalink
Remove FF dependency in gravity timer
Browse files Browse the repository at this point in the history
  • Loading branch information
szapp committed Sep 16, 2018
1 parent 95e610b commit fb108a3
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 46 deletions.
6 changes: 4 additions & 2 deletions _work/data/Scripts/Content/GFA/_intern/collectable.d
Expand Up @@ -46,8 +46,10 @@ func void GFA_RP_KeepProjectileInWorld() {
};

// Always keep the projectile alive, set infinite life time
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, -1082130432); // -1
projectile._zCVob_visualAlpha = FLOATONE; // Fully visible
if (gef(MEM_ReadInt(arrowAI+oCAIArrowBase_lifeTime_offset), FLOATNULL)) {
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE_NEG);
projectile._zCVob_visualAlpha = FLOATONE; // Fully visible
};

// Check if the projectile stopped moving
if (!(projectile._zCVob_bitfield[0] & zCVob_bitfield0_physicsEnabled)) {
Expand Down
13 changes: 6 additions & 7 deletions _work/data/Scripts/Content/GFA/_intern/collision.d
Expand Up @@ -121,11 +121,8 @@ func void GFA_CC_ProjectileStuck(var int projectilePtr) {
* It is called for both Gothic 1 and Gothic 2.
*/
func void GFA_CC_ProjectileDestroy(var int arrowAI) {
if (GOTHIC_BASE_VERSION == 1) {
MEM_WriteInt(arrowAI+oCAIArrow_destroyProjectile_offset, 1); // Gothic 1
} else {
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATNULL); // Gothic 2
};
MEM_WriteInt(arrowAI+oCAIArrow_destroyProjectile_offset, 1);
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATNULL);
};


Expand Down Expand Up @@ -227,7 +224,9 @@ func void GFA_CC_ProjectileCollisionWithNpc() {
if (collision == DEFLECT) {
var oCItem projectile; projectile = _^(MEM_ReadInt(arrowAI+oCAIArrowBase_hostVob_offset));
GFA_CC_ProjectileDeflect(projectile._zCVob_rigidBody);
MEM_WriteInt(arrowAI+oCAIArrow_destroyProjectile_offset, -1); // Mark as deflecting, such that it is ignored
if (GFA_Flags & GFA_REUSE_PROJECTILES) {
MEM_WriteInt(arrowAI+oCAIArrow_destroyProjectile_offset, -1); // Mark as deflecting to ignored it
};
} else {
MEM_WriteInt(arrowAI+oCAIArrow_destroyProjectile_offset, 1); // Destroy projectile on impact
};
Expand Down Expand Up @@ -495,7 +494,7 @@ func void GFA_CC_FadeProjectileVisibility() {
if (!(projectile.bitfield[0] & zCVob_bitfield0_physicsEnabled)) {
var int arrowAI; arrowAI = ESI; // oCAIArrow*
var int lifeTime; lifeTime = MEM_ReadInt(arrowAI+oCAIArrowBase_lifeTime_offset);
if (lifeTime == -1082130432) { // -1
if (lifeTime == FLOATONE_NEG) {
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE);
};
};
Expand Down
6 changes: 4 additions & 2 deletions _work/data/Scripts/Content/GFA/_intern/const.d
Expand Up @@ -31,10 +31,11 @@

const string GFA_VERSION = "Gothic Free Aim v1.0.1";
const int GFA_LEGO_FLAGS = LeGo_HookEngine // For initializing all hooks
| LeGo_FrameFunctions // For projectile gravity
| LeGo_ConsoleCommands // For console commands and debugging
| LeGo_View // For drawing reticle
| LeGo_Random // For scattering and other uses of random numbers
| LeGo_Draw3D; // For debug visualizations
| LeGo_Draw3D // For debug visualizations (may be removed)
| LeGo_FrameFunctions; // For hitmarker in config (may be removed)

var int GFA_Flags; // Flags for initialization of GFA
const int GFA_RANGED = 1<<0; // Free aiming for ranged combat (bow and crossbow)
Expand Down Expand Up @@ -156,6 +157,7 @@ var int GFA_DebugBoneOBBox; // Handle of bone or

/* Numerical constants */

const int FLOATONE_NEG = -1082130432; // -1 as float
const int FLOAT1C = 1120403456; // 100 as float
const int FLOAT3C = 1133903872; // 300 as float
const int FLOAT1K = 1148846080; // 1000 as float
9 changes: 5 additions & 4 deletions _work/data/Scripts/Content/GFA/_intern/init.d
Expand Up @@ -47,6 +47,10 @@ func void GFA_InitFeatureFreeAiming() {
HookEngineF(oCAIHuman__BowMode_notAiming, 6, GFA_RangedIdle); // Fix focus collection while not aiming
HookEngineF(oCAIHuman__BowMode_interpolateAim, 5, GFA_RangedAiming); // Interpolate aiming animation
HookEngineF(oCAIArrow__SetupAIVob, 6, GFA_SetupProjectile); // Setup projectile trajectory (shooting)
writeNOP(oCAIArrowBase__DoAI_setLifeTime, 7);
MEM_WriteByte(oCAIArrowBase__DoAI_setLifeTime, /*85*/ 133); // test eax, eax
MEM_WriteByte(oCAIArrowBase__DoAI_setLifeTime+1, /*C0*/ 192);
HookEngineF(oCAIArrowBase__DoAI_setLifeTime, 7, GFA_EnableProjectileGravity); // Enable gravity after some time
HookEngineF(oCAIArrow__ReportCollisionToAI_collAll, 8, GFA_ResetProjectileGravity); // Reset gravity on impact
HookEngineF(oCAIArrow__ReportCollisionToAI_hitChc, 6, GFA_OverwriteHitChance); // Manipulate hit chance
MemoryProtectionOverride(oCAIHuman__CheckFocusVob_ranged, 1); // Prevent toggling focus in ranged combat
Expand Down Expand Up @@ -304,13 +308,10 @@ func int GFA_InitOnce() {


/*
* Initializations to perfrom on every game start, level change and loading of saved games. This function is called from
* Initializations to perform on every game start, level change and loading of saved games. This function is called from
* GFA_Init().
*/
func void GFA_InitAlways() {
// Pause frame functions when in menu
Timer_SetPauseInMenu(1);

// Retrieve trace ray interval: Recalculate trace ray intersection every x ms
GFA_AimRayInterval = STR_ToInt(MEM_GetGothOpt("GFA", "focusUpdateIntervalMS"));
if (GFA_AimRayInterval > 500) {
Expand Down
1 change: 1 addition & 0 deletions _work/data/Scripts/Content/GFA/_intern/offsets_G1.d
Expand Up @@ -129,6 +129,7 @@ const int oCAIArrow__DoAI_rtn = 6395210; //0x61954A // H
const int oCAIArrow__ReportCollisionToAI_collAll = 6395474; //0x619652 // Hook len 8
const int oCAIArrow__ReportCollisionToAI_hitChc = 6395775; //0x61977F // Hook len 6
const int oCAIArrow__ReportCollisionToAI_damage = 6395861; //0x6197D5 // Hook len 7
const int oCAIArrowBase__DoAI_setLifeTime = 6393028; //0x618CC4 // Hook len 7
const int oCAIArrowBase__ReportCollisionToAI_hitNpc = 6395866; //0x6197DA // Hook len 5
const int oCAIArrowBase__ReportCollisionToAI_hitVob = 0; // Does not exist in Gothic 1
const int oCAIArrowBase__ReportCollisionToAI_hitWld = 0; // Does not exist in Gothic 1
Expand Down
3 changes: 2 additions & 1 deletion _work/data/Scripts/Content/GFA/_intern/offsets_G2.d
Expand Up @@ -129,6 +129,7 @@ const int oCAIArrow__DoAI_rtn = 6952073; //0x6A1489 // H
const int oCAIArrow__ReportCollisionToAI_collAll = 6949315; //0x6A09C3 // Hook len 8
const int oCAIArrow__ReportCollisionToAI_hitChc = 6953482; //0x6A1A0A // Hook len 6
const int oCAIArrow__ReportCollisionToAI_damage = 6953711; //0x6A1AEF // Hook len 7
const int oCAIArrowBase__DoAI_setLifeTime = 6949017; //0x6A0899 // Hook len 7
const int oCAIArrowBase__ReportCollisionToAI_hitNpc = 6949832; //0x6A0BC8 // Hook len 5
const int oCAIArrowBase__ReportCollisionToAI_hitVob = 6949929; //0x6A0C29 // Hook len 5
const int oCAIArrowBase__ReportCollisionToAI_hitWld = 6949460; //0x6A0A54 // Hook len 5
Expand Down Expand Up @@ -193,7 +194,7 @@ const int oCAIArrowBase_hostVob_offset = 60; //0x003C
const int oCAIArrowBase_creatingImpactFX_offset = 64; //0x0040
const int oCAIArrowBase_hasHit_offset = 84; //0x0054
const int oCAIArrow_origin_offset = 92; //0x005C
const int oCAIArrow_destroyProjectile_offset = 96; //0x0060 // Not used for Gothic 2
const int oCAIArrow_destroyProjectile_offset = 96; //0x0060

const int zCRigidBody_mass_offset = 0; //0x0000
const int zCRigidBody_xPos_offset = 80; //0x0050
Expand Down
103 changes: 73 additions & 30 deletions _work/data/Scripts/Content/GFA/_intern/rangedShooting.d
Expand Up @@ -387,8 +387,11 @@ func void GFA_SetupProjectile() {
// Calculate the air time at which to apply the gravity, by the maximum air time GFA_TRAJECTORY_ARC_MAX. Because
// drawForce is a percentage, GFA_TRAJECTORY_ARC_MAX is first multiplied by 100 and later divided by 10000
var int dropTime; dropTime = (drawForce*(GFA_TRAJECTORY_ARC_MAX*100))/10000;
// Create a timed frame function to apply the gravity to the projectile after the calculated air time
FF_ApplyOnceExtData(GFA_EnableProjectileGravity, dropTime, 1, rBody);
if (dropTime < 2) {
dropTime = 2; // Timer value should not be 1 or 0, otherwise gravity is never applied
};
// Use life time to apply gravity after the calculated air time, see GFA_EnableProjectileGravity()
MEM_WriteInt(ECX+oCAIArrowBase_lifeTime_offset, negf(mkf(dropTime)));
// Set the gravity to the projectile. Again: The gravity does not take effect until it is activated
MEM_WriteInt(rBody+zCRigidBody_gravity_offset, mulf(castToIntf(GFA_PROJECTILE_GRAVITY), gravityMod));

Expand Down Expand Up @@ -493,31 +496,72 @@ func void GFA_SetupProjectile() {


/*
* This is a frame function timed by draw force and is responsible for applying gravity to a projectile after a certain
* air time as determined in GFA_SetupProjectile(). The gravity is merely turned on, the gravity strength itself is set
* in GFA_SetupProjectile().
* This function applies gravity to a projectile after a certain air time as determined in GFA_SetupProjectile(). The
* gravity is merely turned on, the gravity strength itself is set in GFA_SetupProjectile(). This function hooks
* oCAIArrowBase::DoAI() at an address where the life time and projectile visibility is decreased. With EAX it is
* later determined whether to decrease the life timer and visibility.
*/
func void GFA_EnableProjectileGravity(var int rigidBody) {
if (!rigidBody) {
return;
};

// Check validity of the zCRigidBody pointer by its first class variable (value is always 10.0). This is necessary
// for loading a saved game, as the pointer will not point to a zCRigidBody address anymore.
if (roundf(MEM_ReadInt(rigidBody+zCRigidBody_mass_offset)) != 10) {
func void GFA_EnableProjectileGravity() {
var int projectilePtr; projectilePtr = EBP;
if (!projectilePtr) {
EAX = TRUE;
return;
};

// Do not add gravity if projectile already stopped moving
if (MEM_ReadInt(rigidBody+zCRigidBody_velocity_offset) == FLOATNULL) // zCRigidBody.velocity[3]
&& (MEM_ReadInt(rigidBody+zCRigidBody_velocity_offset+4) == FLOATNULL)
&& (MEM_ReadInt(rigidBody+zCRigidBody_velocity_offset+8) == FLOATNULL) {
return;
var zCVob projectile; projectile = _^(projectilePtr); // oCItem*

var int arrowAI; arrowAI = ESI; // oCAIArrow*
var int lifeTime; lifeTime = MEM_ReadInt(arrowAI+oCAIArrowBase_lifeTime_offset);
// Gravity counter: lifeTime < -1
// Mid-flight: lifeTime = -1
// Visibility counter: 0 <= lifeTime <= 1

if (gef(lifeTime, FLOATNULL)) {
// lifeTime >= 0: Decrease visibility?
if (MEM_ReadInt(arrowAI+oCAIArrow_destroyProjectile_offset) == 1)
|| (!(GFA_Flags & GFA_REUSE_PROJECTILES)) {
// Yes (destroy or no collectable feature)
if (gf(lifeTime, FLOATONE)) {
// Reset life time to 1
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE);
};
// Decrease life time and visibility (default behavior)
EAX = TRUE;
} else {
// No (collectable feature). Reset life time to -1
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE_NEG);
EAX = FALSE;
};
} else if (!(projectile.bitfield[0] & zCVob_bitfield0_physicsEnabled)) {
// Stopped moving: Decrease visibility?
if (GFA_Flags & GFA_REUSE_PROJECTILES) {
// No (collectable feature). Reset life time to -1
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE_NEG);
EAX = FALSE;
} else {
// Yes (no collectable feature). Reset life time to 1
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE);
// Decrease life time and visibility (default behavior)
EAX = TRUE;
};
} else if (lf(lifeTime, FLOATONE_NEG)) {
// lifeTime < -1: Continue counting flight time until gravity drop
lifeTime = addf(lifeTime, MEM_Timer.frameTimeFloat);
if (gef(lifeTime, FLOATONE_NEG)) {
lifeTime = FLOATONE_NEG;
// Apply gravity. Reset life time to -1
var int rigidBody; rigidBody = projectile.rigidBody; // zCRigidBody*
if (rigidBody) {
var int bitfield; bitfield = MEM_ReadByte(rigidBody+zCRigidBody_bitfield_offset);
MEM_WriteByte(rigidBody+zCRigidBody_bitfield_offset, bitfield | zCRigidBody_bitfield_gravityActive);
};
};
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, lifeTime);
// Do not decrease visibility
EAX = FALSE;
} else { // Mid-flight: lifeTime == -1.0
// Do not decrease visibility
EAX = FALSE;
};

// Turn on gravity
var int bitfield; bitfield = MEM_ReadByte(rigidBody+zCRigidBody_bitfield_offset);
MEM_WriteByte(rigidBody+zCRigidBody_bitfield_offset, bitfield | zCRigidBody_bitfield_gravityActive);
};


Expand All @@ -530,18 +574,17 @@ func void GFA_EnableProjectileGravity(var int rigidBody) {
func void GFA_ResetProjectileGravity() {
var int arrowAI; arrowAI = MEMINT_SwitchG1G2(ESI, ECX);
var oCItem projectile; projectile = _^(MEM_ReadInt(arrowAI+oCAIArrowBase_hostVob_offset));
if (!projectile._zCVob_rigidBody) {
return;
};
var int rigidBody; rigidBody = projectile._zCVob_rigidBody;

// Better safe than writing to an invalid address
if (FF_ActiveData(GFA_EnableProjectileGravity, rigidBody)) {
FF_RemoveData(GFA_EnableProjectileGravity, rigidBody);
if (!rigidBody) {
return;
};

// Reset projectile gravity (zCRigidBody.gravity) after collision (oCAIArrow.collision) to default
MEM_WriteInt(rigidBody+zCRigidBody_gravity_offset, FLOATONE);
if (lf(MEM_ReadInt(arrowAI+oCAIArrowBase_lifeTime_offset), FLOATONE_NEG)) {
// Reset gravity timer
MEM_WriteInt(arrowAI+oCAIArrowBase_lifeTime_offset, FLOATONE_NEG);
};

// Remove trail strip FX
if (GOTHIC_BASE_VERSION == 1) {
Expand Down

0 comments on commit fb108a3

Please sign in to comment.