Skip to content

Commit

Permalink
Fix #182 add extended NPC turning fix
Browse files Browse the repository at this point in the history
  • Loading branch information
szapp committed Oct 16, 2017
1 parent 7c3c7ee commit 8a1297e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 49 deletions.
34 changes: 23 additions & 11 deletions _work/data/Scripts/Content/GFA/_intern/controls.d
Original file line number Diff line number Diff line change
Expand Up @@ -173,12 +173,9 @@ func void GFA_SetControlSchemeRanged(var int scheme) {
MEM_Info(ConcatStrings(" OPT: GFA: Ranged-ctrl-scheme=", IntToString(scheme))); // To zSpy in style as options
if (scheme > 0) {
// Control scheme override: Skip jump to Gothic 2 controls
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+4, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+5, ASMINT_OP_nop);
repeat(i, 6); var int i;
MEM_WriteByte(oCAIHuman__BowMode_g2ctrlCheck+i, ASMINT_OP_nop);
end;

if (scheme == 2) {
// Gothic 2 controls enabled: Mimic the Gothic 1 controls but change the keys
Expand Down Expand Up @@ -352,11 +349,9 @@ func void GFA_DisableMagicDuringStrafing(var int on) {

if (on) {
// Disable magic combat during default strafing
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat, ASMINT_OP_nop); // Remove call to oCNpc::FightAttackMagic()
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+1, ASMINT_OP_nop);
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+2, ASMINT_OP_nop);
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+3, ASMINT_OP_nop);
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+4, ASMINT_OP_nop);
repeat(i, 5); var int i;
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+i, ASMINT_OP_nop); // Remove call to oCNpc::FightAttackMagic()
end;
} else {
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat, /*E8*/ 232); // Revert to default call
MEM_WriteByte(oCNpc__EV_Strafe_magicCombat+1, /*A0*/ 160);
Expand Down Expand Up @@ -487,6 +482,23 @@ func void GFA_FixOpenInventory() {
};


/*
* Modify the attack run turning to only allow it for the player. This function hooks oCNpc::EV_AttackRun() at an offset
* where the player can turn while performing an attack run. This function is only called for Gothic 2.
*/
func void GFA_FixNpcAttackRun() {
var C_Npc slf; slf = _^(ESI);
if (Npc_IsPlayer(slf)) {
const int call = 0; var int zero;
if (CALL_Begin(call)) {
CALL_IntParam(_@(zero));
CALL__thiscall(_@(ECX), oCAIHuman__PC_Turnings);
call = CALL_End();
};
};
};


/*
* Reset spell FX when interrupting investing/casting by the default strafing. This function hooks oCNpc::EV_Strafe() at
* an offset where the fight mode is checked. oCNpc::EV_Strafe() is only called for the player.
Expand Down
81 changes: 43 additions & 38 deletions _work/data/Scripts/Content/GFA/_intern/init.d
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,9 @@ func void GFA_InitFeatureFreeAiming() {

// Aiming condition (detect aiming onset and overwrite aiming condition if GFA_STRAFING)
MemoryProtectionOverride(oCAIHuman__BowMode_aimCondition, 5);
MEM_WriteByte(oCAIHuman__BowMode_aimCondition, ASMINT_OP_nop); // Erase standing condition to make room for hook
MEM_WriteByte(oCAIHuman__BowMode_aimCondition+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_aimCondition+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_aimCondition+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIHuman__BowMode_aimCondition+4, ASMINT_OP_nop);
repeat(i, 5); var int i;
MEM_WriteByte(oCAIHuman__BowMode_aimCondition+i, ASMINT_OP_nop); // Erase condition to make room for hook
end;
HookEngineF(oCAIHuman__BowMode_aimCondition, 5, GFA_RangedAimingCondition); // Replace condition with own

// Gothic 2 controls
Expand Down Expand Up @@ -163,13 +161,9 @@ func void GFA_InitFeatureCustomCollisions() {
HookEngineF(oCAIArrow__ReportCollisionToAI_hitChc, 6, GFA_CC_ProjectileCollisionWithNpc); // Hit reg/coll on NPCs
if (GOTHIC_BASE_VERSION == 1) {
MemoryProtectionOverride(oCAIArrow__ReportCollisionToAI_destroyPrj, 7); // Disable destroying of projectiles
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj, ASMINT_OP_nop); // Disable fixed destruction
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+4, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+5, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+6, ASMINT_OP_nop);
repeat(i, 7); var int i;
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_destroyPrj+i, ASMINT_OP_nop); // Disable fixed destruction
end;
HookEngineF(oCAIArrow__ReportCollisionToAI_collAll, 8, GFA_CC_ProjectileCollisionWithWorld); // Collision world
MemoryProtectionOverride(oCAIArrow__ReportCollisionToAI_keepPlyStrp, 2); // Keep poly strip after coll
MEM_WriteByte(oCAIArrow__ReportCollisionToAI_keepPlyStrp, /*EB*/ 235); // jmp
Expand All @@ -178,20 +172,12 @@ func void GFA_InitFeatureCustomCollisions() {
// Gothic 2
MemoryProtectionOverride(oCAIArrowBase__ReportCollisionToAI_PFXon1, 7); // Prevent too early setting of dust PFX
MemoryProtectionOverride(oCAIArrowBase__ReportCollisionToAI_PFXon2, 7);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1, ASMINT_OP_nop); // First occurrence
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+4, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+5, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+6, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2, ASMINT_OP_nop); // Second occurrence
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+4, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+5, ASMINT_OP_nop);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+6, ASMINT_OP_nop);
repeat(i, 7);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon1+i, ASMINT_OP_nop); // First occurrence
end;
repeat(i, 7);
MEM_WriteByte(oCAIArrowBase__ReportCollisionToAI_PFXon2+i, ASMINT_OP_nop); // Second occurrence
end;
HookEngineF(oCAIArrowBase__ReportCollisionToAI_collVob, 5, GFA_CC_ProjectileCollisionWithWorld); // Vobs
HookEngineF(oCAIArrowBase__ReportCollisionToAI_collWld, 5, GFA_CC_ProjectileCollisionWithWorld); // Static world
MemoryProtectionOverride(oCAIArrowBase__ReportCollisionToAI_collNpc, 2); // Set collision behavior on NPCs
Expand Down Expand Up @@ -252,13 +238,9 @@ func void GFA_InitDamageBehavior() {
func void GFA_InitFixDroppedProjectileAI() {
MEM_Info("Initializing dropped projectiles AI bug fix.");
MemoryProtectionOverride(oCAIVobMove__DoAI_stopMovement, 7); // First erase a call, to make room for hook
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+1, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+2, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+3, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+4, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+5, ASMINT_OP_nop);
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+6, ASMINT_OP_nop);
repeat(i, 7); var int i;
MEM_WriteByte(oCAIVobMove__DoAI_stopMovement+i, ASMINT_OP_nop);
end;
HookEngineF(oCAIVobMove__DoAI_stopMovement, 7, GFA_FixDroppedProjectileAI); // Re-write what has been overwritten
};

Expand All @@ -269,15 +251,35 @@ func void GFA_InitFixDroppedProjectileAI() {
func void GFA_InitFixOpenInventory() {
MEM_Info("Initializing open inventory bug fix.");
MemoryProtectionOverride(oCGame__HandleEvent_openInvCheck, 5); // First erase a call, to make room for hook
MEM_WriteByte(oCGame__HandleEvent_openInvCheck, ASMINT_OP_nop);
MEM_WriteByte(oCGame__HandleEvent_openInvCheck+1, ASMINT_OP_nop);
MEM_WriteByte(oCGame__HandleEvent_openInvCheck+2, ASMINT_OP_nop);
MEM_WriteByte(oCGame__HandleEvent_openInvCheck+3, ASMINT_OP_nop);
MEM_WriteByte(oCGame__HandleEvent_openInvCheck+4, ASMINT_OP_nop);
repeat(i, 5); var int i;
MEM_WriteByte(oCGame__HandleEvent_openInvCheck+i, ASMINT_OP_nop);
end;
HookEngineF(oCGame__HandleEvent_openInvCheck, 5, GFA_FixOpenInventory); // Re-write what has been overwritten
};


/*
* Prevent the player from controlling the turning of NPCs that are performing an attack run. This inherent Gothic 2 bug
* becomes very obvious with free aiming and thus needs to be fixed.
* To still allow the player to turn while performing an attack run, the solution from the link below is extended, to
* squeeze in a check whether the character in question is the player.
*
* Inspired by: http://forum.worldofplayers.de/forum/threads/879891?p=14886885
*/
func void GFA_InitFixNpcAttackRun() {
if (GOTHIC_BASE_VERSION != 2) {
return;
};

MEM_Info("Initializing NPC attack-run turning bug fix.");
MemoryProtectionOverride(oCNpc__EV_AttackRun_playerTurn, 7); // Erase call to oCAIHuman::PC_Turnings()
repeat(i, 7); var int i;
MEM_WriteByte(oCNpc__EV_AttackRun_playerTurn+i, ASMINT_OP_nop);
end;
HookEngineF(oCNpc__EV_AttackRun_playerTurn, 7, GFA_FixNpcAttackRun); // Re-write what has been overwritten
};


/*
* Initializations to perform only once every session. This function overwrites memory protection at certain addresses,
* and registers hooks and console commands, all depending on the selected features (see config\settings.d). The
Expand Down Expand Up @@ -332,6 +334,9 @@ func int GFA_InitOnce() {
// Fix open inventory bug
GFA_InitFixOpenInventory();

// Fix player turning NPCs on attack run
GFA_InitFixNpcAttackRun();

// };

// Successfully initialized
Expand Down
2 changes: 2 additions & 0 deletions _work/data/Scripts/Content/GFA/_intern/offsets_G1.d
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const int oCAIHuman__BowMode_g2ctrlCheck = 0;
const int oCAIHuman__BowMode_shootingKey = 6359374; //0x61094E // Not used for Gothic 1
const int oCAIHuman__MagicMode_turnToTarget = 4641584; //0x46D330
const int oCAIHuman__PC_ActionMove_aimingKey = 6373222; //0x613F66 // Not used for Gothic 1
const int oCAIHuman__PC_Turnings = 6375424; //0x614800 // Not used for Gothic 1
const int zCCollObjectLevelPolys__s_oCollObjClass = 8861152; //0x8735E0

const int zCWorld__AdvanceClock = 6257280; //0x5F7A80 // Hook len 10
Expand Down Expand Up @@ -144,6 +145,7 @@ const int oCNpc__OnDamage_Anim_stumbleAniName = 7620508; //0x74479C // H
const int oCNpc__OnDamage_Anim_gotHitAniName = 7620670; //0x74483E // Hook len 5
const int oCNpc__SetWeaponMode_player = 6907265; //0x696581 // Hook len 6
const int oCNpc__SetWeaponMode2_walkmode = 6905437; //0x695E5D // Hook len 6
const int oCNpc__EV_AttackRun_playerTurn = 0; // Does not exist in Gothic 1
const int oCNpc__EV_Strafe_commonOffset = 7661795; //0x74E8E3 // Hook len 5
const int oCNpc__EV_Strafe_g2ctrl = 0; // Does not exist in Gothic 1
const int oCNpc__Interrupt_stopAnis = 6891924; //0x692994 // Hook len 5
Expand Down
2 changes: 2 additions & 0 deletions _work/data/Scripts/Content/GFA/_intern/offsets_G2.d
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ const int oCAIHuman__BowMode_g2ctrlCheck = 6905643; //0x695F2B
const int oCAIHuman__BowMode_shootingKey = 6906610; //0x6962F2
const int oCAIHuman__MagicMode_turnToTarget = 0; // Does not exist in Gothic 2
const int oCAIHuman__PC_ActionMove_aimingKey = 6922427; //0x69A0BB
const int oCAIHuman__PC_Turnings = 6924608; //0x69A940
const int zCCollObjectLevelPolys__s_oCollObjClass = 9274192; //0x8D8350

const int zCWorld__AdvanceClock = 6447328; //0x6260E0 // Hook len 10
Expand Down Expand Up @@ -144,6 +145,7 @@ const int oCNpc__OnDamage_Anim_stumbleAniName = 6784975; //0x6787CF // H
const int oCNpc__OnDamage_Anim_gotHitAniName = 6785116; //0x67885C // Hook len 5
const int oCNpc__SetWeaponMode_player = 7575921; //0x739971 // Hook len 6
const int oCNpc__SetWeaponMode2_walkmode = 7574116; //0x739264 // Hook len 6
const int oCNpc__EV_AttackRun_playerTurn = 7674197; //0x751955 // Hook len 7
const int oCNpc__EV_Strafe_commonOffset = 6831608; //0x683DF8 // Hook len 5
const int oCNpc__EV_Strafe_g2ctrl = 6832857; //0x6842D9 // Hook len 6
const int oCNpc__Interrupt_stopAnis = 7560261; //0x735C45 // Hook len 5
Expand Down

0 comments on commit 8a1297e

Please sign in to comment.