Skip to content

Commit

Permalink
Introduce flags for initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
szapp committed Aug 13, 2017
1 parent b149a0c commit 1a9ac0f
Show file tree
Hide file tree
Showing 12 changed files with 58 additions and 72 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,14 @@ A [setup](http://github.com/szapp/GothicFreeAim/releases/latest) is available to
it, and all scripts should be fully working (originals will be backed up). Alternatively, you can do these following
steps manually.

1. Make sure Ikarus and LeGo are installed and initialized with *FrameFunctions* and *ConsoleCommands*.
1. Make sure Ikarus and LeGo are installed and parsed with _work\data\Scripts\Content\Gothic.src`.
2. Copy all files from this repository into your Gothic II installation. Mind the relative paths. Do not forget the
binary files (textures) that come with the [release](http://github.com/szapp/GothicFreeAim/releases/latest).
3. Have the files parsed:
1. Add the line `FREEAIM\freeAim.src` to `_work\data\Scripts\Content\Gothic.src` somewhere **after** Ikarus, LeGo
and `AI\AI_INTERN\FOCUS.D`.
2. Add the line `camera\caminstfreeaim.d` to the end of `_work\data\Scripts\System\Camera.src`.
3. Add the line `Pfx\PfxInstFreeAim.d` to the end of `_work\data\Scripts\System\PFX.src`.
3. Add the line `Pfx\PfxInstFreeAim_G2.d` to the end of `_work\data\Scripts\System\PFX.src`.
4. Add the line `sfx\sfxinstfreeaim.d` to the end of `_work\data\Scripts\System\SFX.src`.
5. Add the line `visualfx\visualfxfreeaim.d` to the end of `_work\data\Scripts\System\VisualFX.src`.
6. Add the line `menu\menu_opt_game_freeaim.d` to `_work\data\Scripts\System\Menu.src` between `_intern\menu.d` and
Expand All @@ -92,8 +92,8 @@ steps manually.
const int MENU_ID_GFA = 7; // Next available Y-spot in the menu
```

7. Finally initialize free aim by adding the line `GFA_Init();` in to the function `INIT_GLOBAL()` in
`_work\data\Scripts\Content\Story\Startup.d` somewhere after Ikarus and LeGo.
7. Finally initialize free aim by adding the line `GFA_Init(GFA_ALL);` in to the function `INIT_GLOBAL()` in
`_work\data\Scripts\Content\Story\Startup.d` either somewhere *after* Ikarus and LeGo or instead of them.

> Again: The [setup](http://github.com/szapp/GothicFreeAim/releases/latest) will perform all these steps for you.
Expand Down
8 changes: 4 additions & 4 deletions _work/data/Scripts/Content/freeAim/_intern/activate.d
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func void GFA_UpdateSettings(var int on) {

if (on) {
// Turn free aiming on
if (GFA_RANGED) {
if (GFA_Flags & GFA_RANGED) {
// Set stricter focus collection
Focus_Ranged.npc_azi = 15.0;

Expand All @@ -45,7 +45,7 @@ func void GFA_UpdateSettings(var int on) {

};

if (GFA_SPELLS) {
if (GFA_Flags & GFA_SPELLS) {
// New camera mode (does not affect Gothic 1)
MEM_WriteString(zString_CamModMagic, STR_Upper(GFA_CAMERA));
};
Expand Down Expand Up @@ -149,7 +149,7 @@ func void GFA_IsActive() {
// Check fight mode
if (her.fmode == FMODE_MAGIC) {
// Check if free aiming for spells is disabled
if (!GFA_SPELLS) {
if (!(GFA_Flags & GFA_SPELLS)) {
GFA_DisableAutoTurning(0);
GFA_SetCameraModes(0);
GFA_ACTIVE = 1;
Expand Down Expand Up @@ -191,7 +191,7 @@ func void GFA_IsActive() {

} else if (her.fmode >= FMODE_FAR) { // Greater or equal: Crossbow has different fight mode!
// Check if free aiming for ranged combat is disabled
if (!GFA_RANGED) {
if (!(GFA_Flags & GFA_RANGED)) {
GFA_DisableAutoTurning(0);
GFA_SetCameraModes(0);
GFA_ACTIVE = 1;
Expand Down
4 changes: 2 additions & 2 deletions _work/data/Scripts/Content/freeAim/_intern/auxiliary.d
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func MEMINT_HelperClass GFA_GetActiveSpellInst(var C_Npc npc) {
* spells. For new spells, adjust THEIR properties accordingly.
*/
func int GFA_IsSpellEligible(var C_Spell spell) {
// Exit if free aiming is disabled for spells or if the spell instance is invalid
if (!GFA_SPELLS) || (!_@(spell)) {
// Exit if the spell instance is invalid
if (!_@(spell)) {
return FALSE;
};

Expand Down
16 changes: 8 additions & 8 deletions _work/data/Scripts/Content/freeAim/_intern/ccommands.d
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func string GFA_DebugTraceRay(var string command) {
* When entered in the console, the current shooting statistics are displayed as the console output.
*/
func string GFA_GetShootingStats(var string command) {
if (!GFA_ACTIVE) || (!GFA_RANGED) {
if (!GFA_ACTIVE) || (!(GFA_Flags & GFA_RANGED)) {
return "Shooting statistics not available. (Requires free aiming for ranged weapons)";
};

Expand All @@ -93,7 +93,7 @@ func string GFA_GetShootingStats(var string command) {
SB(STR_Prefix(toStringf(pAccuracy), 4));
SB("%");

if (GFA_CRITICALHITS) {
if (GFA_Flags & GFA_CRITICALHITS) {
SBc(13); SBc(10);
SB("Critical hits: ");
SBi(GFA_StatsCriticalHits);
Expand Down Expand Up @@ -154,13 +154,13 @@ func string GFA_GetInfo(var string command) {
SBc(13); SBc(10);

SB("Free aiming: ");
SB(MEM_ReadStatStringArr(onOff, GFA_ACTIVE));
SB(MEM_ReadStatStringArr(onOff, GFA_ACTIVE > 0));
if (GFA_ACTIVE) {
SB(" for");
if (GFA_RANGED) {
if (GFA_Flags & GFA_RANGED) {
SB(" (ranged)");
};
if (GFA_SPELLS) {
if (GFA_Flags & GFA_SPELLS) {
SB(" (spells)");
};

Expand All @@ -171,15 +171,15 @@ func string GFA_GetInfo(var string command) {
SBc(13); SBc(10);

SB("Reusable projectiles: ");
SB(MEM_ReadStatStringArr(onOff, GFA_REUSE_PROJECTILES));
SB(MEM_ReadStatStringArr(onOff, (GFA_Flags & GFA_REUSE_PROJECTILES) > 0));
SBc(13); SBc(10);

SB("Custom collision behaviors: ");
SB(MEM_ReadStatStringArr(onOff, GFA_CUSTOM_COLLISIONS));
SB(MEM_ReadStatStringArr(onOff, (GFA_Flags & GFA_CUSTOM_COLLISIONS) > 0));
SBc(13); SBc(10);

SB("Criticial hit detection: ");
SB(MEM_ReadStatStringArr(onOff, GFA_CRITICALHITS));
SB(MEM_ReadStatStringArr(onOff, (GFA_Flags & GFA_CRITICALHITS) > 0));

var string ret; ret = SB_ToString();
SB_Destroy();
Expand Down
6 changes: 3 additions & 3 deletions _work/data/Scripts/Content/freeAim/_intern/collision.d
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* function is called from GFA_CC_ProjectileCollisionWithNpc() to update the collision behavior for each projectile.
*/
func void GFA_CC_SetProjectileCollisionWithNpc(var int setting) {
if (GOTHIC_BASE_VERSION != 2) || (!GFA_CUSTOM_COLLISIONS) {
if (GOTHIC_BASE_VERSION != 2) {
return;
};

Expand Down Expand Up @@ -234,7 +234,7 @@ func void GFA_CC_ProjectileCollisionWithNpc() {
MEM_WriteInt(hitChancePtr, MEMINT_SwitchG1G2(FLOATNULL, 0)); // G1: float, G2: integer

// Update shooting statistics (decrement, if shot was supposed to hit, see GFA_OverwriteHitChance())
if (Npc_IsPlayer(shooter)) && (GFA_ACTIVE) && (GFA_RANGED) {
if (Npc_IsPlayer(shooter)) && (GFA_ACTIVE) && (GFA_Flags & GFA_RANGED) {
GFA_StatsHits -= 1;
};
};
Expand Down Expand Up @@ -524,7 +524,7 @@ func void GFA_CC_SetDamageBehavior() {
const int INSTANT_KNOCKOUT = 2; // One shot knockout (HP = 1)
const int INSTANT_KILL = 3; // One shot kill (HP = 0)
var int dmgBehavior;
if (GFA_CUSTOM_COLLISIONS) {
if (GFA_Flags & GFA_CUSTOM_COLLISIONS) {
dmgBehavior = GFA_CC_GetDamageBehavior_(targetNpc);
} else {
dmgBehavior = DO_NOT_KNOCKOUT;
Expand Down
9 changes: 9 additions & 0 deletions _work/data/Scripts/Content/freeAim/_intern/const.d
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ const int GFA_LEGO_FLAGS = LeGo_HookEngine // For initializing
| LeGo_Random // For scattering and other uses of random numbers
| LeGo_PrintS; // To be safe (in case it is used in critical hit event)

var int GFA_Flags; // Flags for initialization of GFA
const int GFA_BUGFIXES = 0<<0; // Misc Gothic bug fixes, applied always (pseudo flag)
const int GFA_RANGED = 1<<0; // Free aiming for ranged combat (bow and crossbow)
const int GFA_SPELLS = 1<<1; // Free aiming for spell combat (spells)
const int GFA_REUSE_PROJECTILES = 1<<2; // Enable collection and re-using of shot projectiles
const int GFA_CUSTOM_COLLISIONS = 1<<3; // Custom collision/damage behaviors and hit registration
const int GFA_CRITICALHITS = 1<<4; // Critical hits for ranged combat (e.g. head shots)
const int GFA_ALL = (1<<5) - 1; // Initialize all features

const int GFA_DRAWTIME_READY = 650; // Time (ms) for readying the bow. Fixed by animation
const int GFA_DRAWTIME_RELOAD = 1110; // Time (ms) for reloading the bow. Fixed by animation
var int GFA_BowDrawOnset; // Time onset of drawing the bow
Expand Down
6 changes: 3 additions & 3 deletions _work/data/Scripts/Content/freeAim/_intern/controls.d
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func void GFA_DisableAutoTurning(var int on) {
* This function is called from GFA_UpdateStatus() if the menu settings change.
*/
func void GFA_UpdateSettingsG2Ctrl(var int on) {
if (GOTHIC_BASE_VERSION != 2) || (!GFA_RANGED) {
if (GOTHIC_BASE_VERSION != 2) || (!(GFA_Flags & GFA_RANGED)) {
return;
};

Expand Down Expand Up @@ -258,8 +258,8 @@ func void GFA_PreventFocusCollectionBodystates() {
};

var oCNpc her; her = Hlp_GetNpc(hero);
if ((her.fmode == FMODE_FAR) || (her.fmode == FMODE_FAR+1)) && (GFA_RANGED) // Bow or crossbow
|| ((her.fmode == FMODE_MAGIC) && (GFA_SPELLS)) { // Spell
if ((her.fmode == FMODE_FAR) || (her.fmode == FMODE_FAR+1)) && (GFA_Flags & GFA_RANGED) // Bow or crossbow
|| ((her.fmode == FMODE_MAGIC) && (GFA_Flags & GFA_SPELLS)) { // Spell
GFA_SetFocusAndTarget(0);

// With Gothic 2 controls, the reticle is still visible
Expand Down
4 changes: 2 additions & 2 deletions _work/data/Scripts/Content/freeAim/_intern/criticalHit.d
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func void GFA_CH_StartCriticalHitEvent_(var C_Npc target) {
var C_Item weapon; weapon = _^(weaponPtr);

// Start an event from config
GFA_StartCriticalHitEvent(target, weapon, (GFA_ACTIVE && GFA_RANGED));
GFA_StartCriticalHitEvent(target, weapon, (GFA_ACTIVE && (GFA_Flags & GFA_RANGED)));
};


Expand Down Expand Up @@ -130,7 +130,7 @@ func void GFA_CH_DetectCriticalHit() {
if (Hlp_StrCmp(weakspot.node, "")) {
criticalHit = 0;
debugInfo = "No weak spot defined in config";
} else if (!GFA_ACTIVE) || (!GFA_RANGED) {
} else if (!GFA_ACTIVE) || (!(GFA_Flags & GFA_RANGED)) {
// Critical hits cause an advantage when playing with free aiming enabled compared to auto aim. This is, because
// there are no critical hits for ranged combat in Gothic 2. Here, they are introduced for balancing reasons.
// Note: Gothic 1 already has critical hits for auto aiming. This is replaced here.
Expand Down
30 changes: 18 additions & 12 deletions _work/data/Scripts/Content/freeAim/_intern/init.d
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func void GFA_InitFeatureFreeAiming() {
HookEngineF(oCNpc__OnDamage_Anim_getModel, 9, GFA_DisableDamageAnimation); // Disable damage animation while aiming

// Free aiming for ranged combat (aiming and shooting)
if (GFA_RANGED) {
if (GFA_Flags & GFA_RANGED) {
MEM_Info("Initializing free aiming for ranged combat.");
HookEngineF(oCAIHuman__BowMode_notAiming, 6, GFA_RangedIdle); // Fix focus collection while not aiming
HookEngineF(oCAIHuman__BowMode_interpolateAim, 5, GFA_RangedAiming); // Interpolate aiming animation
Expand All @@ -59,7 +59,7 @@ func void GFA_InitFeatureFreeAiming() {
};

// Free aiming for spells
if (GFA_SPELLS) {
if (GFA_Flags & GFA_SPELLS) {
MEM_Info("Initializing free aiming for spell combat.");
HookEngineF(oCAIHuman__MagicMode, 7, GFA_SpellAiming); // Manage focus collection and reticle
HookEngineF(oCSpell__Setup_initFallbackNone, 6, GFA_SetupSpell); // Set spell FX trajectory (shooting)
Expand Down Expand Up @@ -232,32 +232,37 @@ func int GFA_InitOnce() {
MEM_Info("");

// FEATURE: Free aiming
if ((GFA_RANGED) || (GFA_SPELLS)) {
if (GFA_Flags & GFA_RANGED) || (GFA_Flags & GFA_SPELLS) {
GFA_InitFeatureFreeAiming();
};

// FEATURE: Custom collision behaviors
if (GFA_CUSTOM_COLLISIONS) {
if (GFA_Flags & GFA_CUSTOM_COLLISIONS) {
GFA_InitFeatureCustomCollisions();
};

// FEATURE: Critical hits
if (GFA_CRITICALHITS) {
if (GFA_Flags & GFA_CRITICALHITS) {
GFA_InitFeatureCriticalHits();
};

// FEATURE: Reusable projectiles
if (GFA_REUSE_PROJECTILES) {
if (GFA_Flags & GFA_REUSE_PROJECTILES) {
// Because of balancing issues, this is feature is stored as a constant and not a variable. It should not be
// enabled/disabled during the game. That would cause too many/too few projectiles
GFA_InitFeatureReuseProjectiles();
};

// Fix knockout by ranged weapon bug (also allow customization if GFA_CUSTOM_COLLISIONS == TRUE)
GFA_InitDamageBehavior();
// Remaining initialization also done with no flags/features set (pseudo flag GFA_BUGFIXES)
// if (GFA_Flags & GFA_BUGFIXES) { // Would actually be false, because GFA_BUGFIXES == 0

// Fix dropped projectile AI bug
GFA_InitFixDroppedProjectileAI();
// Fix knockout by ranged weapon bug (also allow customization with GFA_CUSTOM_COLLISIONS)
GFA_InitDamageBehavior();

// Fix dropped projectile AI bug
GFA_InitFixDroppedProjectileAI();

// };

// Register console commands
MEM_Info("Initializing console commands.");
Expand Down Expand Up @@ -289,7 +294,7 @@ func void GFA_InitAlways() {
};

// Reset/reinitialize free aiming settings every time to prevent crashes
if ((GFA_RANGED) || (GFA_SPELLS)) {
if (GFA_Flags & GFA_RANGED) || (GFA_Flags & GFA_SPELLS) {
// On level change, Gothic does not maintain the focus instances (see Focus.d), nor does it reinitialize them.
// The focus instances are, however, critical for enabling/disabling free aiming: Reinitialize them by hand.
if (!_@(Focus_Ranged)) {
Expand Down Expand Up @@ -321,7 +326,7 @@ func void GFA_InitAlways() {
* Initialize GFA framework. This function is called in Init_Global(). It includes registering hooks, console commands
* and the retrieval of settings from the INI-file and other initializations.
*/
func void GFA_Init() {
func void GFA_Init(var int flags) {
// Ikarus and LeGo need to be initialized first
const int INIT_LEGO_NEEDED = 0; // Set to 1, if LeGo is not initialized by user (in INIT_Global())
if (!_LeGo_Init) {
Expand All @@ -340,6 +345,7 @@ func void GFA_Init() {
};

MEM_Info(ConcatStrings(ConcatStrings("Initialize ", GFA_VERSION), "."));
GFA_Flags = flags;

// Perform only once per session
const int INITIALIZED = 0;
Expand Down
4 changes: 2 additions & 2 deletions _work/data/Scripts/Content/freeAim/config/collectable.d
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@


/*
* When collecting projectiles is enabled (GFA_REUSE_PROJECTILES == 1), this function is called whenever a projectile
* (arrows and bolts) hits an NPC or stops in the world. It is useful to replace the projectile or to remove it.
* When collecting projectiles is enabled (GFA_REUSE_PROJECTILES), this function is called whenever a projectile (arrows
* and bolts) hits an NPC or stops in the world. It is useful to replace the projectile or to remove it.
* Return value is an item instance. When returning zero, the projectile is destroyed.
* The parameter 'inventoryNpc' holds the NPC in whose inventory it will be put, or is empty if it landed in the world.
*
Expand Down
2 changes: 1 addition & 1 deletion _work/data/Scripts/Content/freeAim/config/collision.d
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
func int GFA_GetCollisionWithNpc(var C_Npc shooter, var C_Npc target, var C_Item weapon, var int material) {
// Valid return values are:
const int DESTROY = 0; // No hit registration (no damage), projectile vanishes
const int DAMAGE = 1; // Positive hit registration, projectile is put into inventory if GFA_REUSE_PROJECTILES == 1
const int DAMAGE = 1; // Positive hit registration (projectile is put into inventory with GFA_REUSE_PROJECTILES)
const int DEFLECT = 2; // No hit registration (no damage), projectile bounces off

// Disable friendly-fire for the player
Expand Down
33 changes: 2 additions & 31 deletions _work/data/Scripts/Content/freeAim/config/settings.d
Original file line number Diff line number Diff line change
@@ -1,39 +1,10 @@
/*
* This file contains all basic settings and allows enabling and disabling the features of this script package.
* Values deviating too far from the default values should either be avoided or tested thoroughly.
*/


/*
* These are the features that can be independently enabled and disabled. It is possible to not use free aiming at all,
* but still make use of the other features. Any combination of features is possible, while completely disabling the
* others.
* This file contains the basic settings of this script package, based on the different features.
*
* If GFA_RANGED and GFA_SPELLS are both set to false, the free aiming feature is completely disabled, not affecting
* the other features, however.
*
* Note: The recommended setting is to enable all features, optionally with re-usable projectiles.
*
* A list to the config files that correspond to each feature and offer more in-depth customization. It is recommended
* to read the header comments of the functions in all config files, prior to a decision whether to keep or disable a
* feature, because there is a lot of information regarding each feature.
* ranged.d GFA_RANGED
* spell.d GFA_SPELLS
* reticle.d GFA_RANGED and GFA_SPELLS
* collectable.d GFA_REUSE_PROJECTILES
* collision.d GFA_CUSTOM_COLLISIONS
* criticalHit.d GFA_CRITICALHITS
* Values deviating too far from the default values should either be avoided or tested thoroughly!
*/
const int GFA_RANGED = TRUE; // Free aiming for ranged combat (bow and crossbow)
const int GFA_SPELLS = TRUE; // Free aiming for spell combat (spells)
const int GFA_REUSE_PROJECTILES = TRUE; // Enable collection and re-using of shot projectiles
const int GFA_CUSTOM_COLLISIONS = TRUE; // Custom collision behaviors, hit registration and damage behaviors
const int GFA_CRITICALHITS = TRUE; // Critical hits for ranged combat (e.g. head shots)


/*
* Adjustable settings (depending on the above features)
*/
// GFA_RANGED
const int GFA_TRUE_HITCHANCE = TRUE; // Enable accuracy scattering (true) or use Gothic default hit chance
const int GFA_DRAWTIME_MAX = 1200; // Maximum draw time (ms): When is the bow fully drawn
Expand Down

0 comments on commit 1a9ac0f

Please sign in to comment.