HOOK_MOVECOST (#496)

This commit is contained in:
Mike Klaas
2026-06-17 06:11:08 +00:00
committed by GitHub
parent c6818f0849
commit 26d7b632fc
5 changed files with 107 additions and 4 deletions
+1 -1
View File
@@ -106,8 +106,8 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
| UseObj | `HOOK_USEOBJ` | ✅ | CE notes an sfall-matching inconsistency around return code `2` behavior between interface contexts. |
| RemoveInvenObj | `HOOK_REMOVEINVENOBJ` | 🚫 | - |
| BarterPrice | `HOOK_BARTERPRICE` | ✅ | - |
| MoveCost | `HOOK_MOVECOST` | 🚫 | - |
| ItemDamage | `HOOK_ITEMDAMAGE` | ✅ | - |
| MoveCost | `HOOK_MOVECOST` | ✅ | - |
| AmmoCost | `HOOK_AMMOCOST` | ✅ | Requires `check_weapon_ammo_cost=1` if you want pre-attack ammo validation to respect per-shot/per-round overrides. |
| KeyPress | `HOOK_KEYPRESS` | ✅ | Third hook arg is currently `0`; CE doesn't use VK codes. |
| MouseClick | `HOOK_MOUSECLICK` | ✅ | - |
+70
View File
@@ -0,0 +1,70 @@
#include "sfall.h"
#include "dik.h"
variable movecost_mode := 0;
procedure movecost_mode_name(variable mode) begin
variable name := "unknown";
if (mode == 0) then name := "engine";
else if (mode == 1) then name := "plus_per_hex";
else if (mode == 2) then name := "double";
return name;
end
procedure cycle_movecost_mode begin
if (movecost_mode == 0) then movecost_mode := 1;
else if (movecost_mode == 1) then movecost_mode := 2;
else movecost_mode := 0;
display_msg(string_format1("movecost mode=%s", movecost_mode_name(movecost_mode)));
end
procedure movecost_handler begin
variable
args := get_sfall_args,
critter := args[0],
distance := args[1],
defaultCost := args[2],
modeName := movecost_mode_name(movecost_mode),
newCost := defaultCost;
if (critter != dude_obj) then return;
display_msg(string_format3("movecost dist=%d default=%d mode=%s",
distance,
defaultCost,
modeName));
if (movecost_mode == 1) then begin
newCost := defaultCost + distance;
end else if (movecost_mode == 2) then begin
newCost := defaultCost * 2;
end else begin
return;
end
set_sfall_return(newCost);
end
procedure keypress_handler begin
variable
pressed := get_sfall_arg_at(0),
key := get_sfall_arg_at(1);
if (not pressed) then return;
if (key != DIK_M) then return;
call cycle_movecost_mode;
end
procedure start begin
if (not game_loaded) then return;
display_msg("movecost manual test ready: enter combat, hover a tile, then move");
display_msg("press M to cycle hook override: engine -> plus_per_hex -> double");
register_hook_proc(HOOK_KEYPRESS, keypress_handler);
register_hook_proc(HOOK_MOVECOST, movecost_handler);
end
+6 -3
View File
@@ -1359,13 +1359,16 @@ int critterGetMovementPointCostAdjustedForCrippledLegs(Object* critter, int dist
}
int flags = critter->data.critter.combat.results;
int actionPoints = 0;
if ((flags & DAM_CRIP_LEG_LEFT) != 0 && (flags & DAM_CRIP_LEG_RIGHT) != 0) {
return 8 * distance;
actionPoints = 8 * distance;
} else if ((flags & DAM_CRIP_LEG_ANY) != 0) {
return 4 * distance;
actionPoints = 4 * distance;
} else {
return distance;
actionPoints = distance;
}
return scriptHooks_MoveCost(critter, distance, actionPoints);
}
// 0x42E66C critterIsOverloaded
+29
View File
@@ -570,6 +570,35 @@ int scriptHooks_CalcApCost(Object* critter, int hitMode, bool aiming, int action
return hook.getReturnValueAt(0).asInt();
}
/*
Runs when calculating the AP cost of movement.
The engine calls this both for full-path AP previews and for per-hex AP
deduction during movement animation. In practice, arg1 may therefore be the
full path length or 1, depending on the caller. Non-linear overrides can make
the UI preview diverge from the AP actually spent.
Critter arg0 - The critter doing the moving
int arg1 - The number of hexes being moved
int arg2 - The original AP cost
int ret0 - The new AP cost
*/
int scriptHooks_MoveCost(Object* critter, int distance, int actionPoints)
{
if (scriptHooks[HOOK_MOVECOST].empty()) {
return actionPoints;
}
ScriptHookCall hook(HOOK_MOVECOST, 1, { critter, distance, actionPoints });
hook.call();
if (hook.numReturnValues() <= 0) {
return actionPoints;
}
return hook.getReturnValueAt(0).asInt();
}
/*
Runs before moving items between inventory slots in dude interface. You can override the action.
+1
View File
@@ -302,6 +302,7 @@ bool scriptHooks_CombatTurnEnd(Object* critter, int turnResult, bool reloadedDur
void scriptHooks_CombatTurnCombatEnd(Object* critter);
PerceptionResult scriptHooks_WithinPerception(Object* watcher, Object* target, PerceptionType type, PerceptionResult result);
int scriptHooks_CalcApCost(Object* critter, int hitMode, bool aiming, int actionPoints, Object* weapon);
int scriptHooks_MoveCost(Object* critter, int distance, int actionPoints);
int scriptHooks_ToHit(Object* attacker, Object* defender, int tile, int hitMode, int hitLocation, int hitChance, int hitChanceUncapped, bool useDistance);
int scriptHooks_AfterHitRoll(Object* attacker, Object** defenderPtr, int* hitLocationPtr, int hitChance, int roll);
void scriptHooks_DeathAnim(Object* attacker, Object* defender, Object* weapon, int damage, int* anim);