Added NPC combat control mod to example mods

Updated item highlighting mod and NPC armor mod.
This commit is contained in:
NovaRain
2023-07-03 15:35:03 +08:00
parent 2148650313
commit 2941157174
13 changed files with 405 additions and 37 deletions
@@ -1,11 +1,13 @@
/**
Item Highlight mod (Lite version)
Item Highlighting mod (Lite version)
A cut-down version of the mod included in sfall 4.x, offers a bit more features than the built-in function.
A cut-down version of the mod included in sfall 4.x, offering more features than the built-in function.
Features:
- highlighting items, containers (optional) and lootable corpses (optional) on the ground
- highlights items, containers (optional) and lootable corpses (optional) on the ground
- highlights critters using the same rules as combat mode highlighting (optional)
- configurable hotkey is used to trigger highlight
- hotkey can be pressed and held to continuously update highlighted objects based on current position
- only objects in direct line-of-sight of player are highlighted (optional)
- motion scanner is required to enable highlight (optional)
- motion scanner charges are decreased on each use (optional)
@@ -15,7 +17,7 @@
NOTE: this script requires compiler from sfall modderspack with -s option
(short circuit evaluation)
version 1.1
version 1.2
**/
@@ -24,6 +26,7 @@
#define CRITTER_IS_DEAD (1)
#define PID_MOTION_SENSOR (59)
#define REPEAT_FRAMES (10)
#define NO_HIGHLIGHT(obj) (get_flags(obj) bwand FLAG_NOHIGHLIGHT)
#define NO_STEAL(obj) (get_proto_data(obj_pid(obj), PROTO_CR_FLAGS) bwand CFLG_NOSTEAL)
@@ -32,36 +35,70 @@ variable highlightKey;
variable isHighlight;
variable alsoContainer;
variable alsoCorpse;
variable alsoCritter;
variable checkLOS;
variable outlineColor;
variable motionScanner;
variable highlightFailMsg1;
variable highlightFailMsg2;
procedure ToggleHighlightObject(variable obj, variable enable) begin
if obj and (not enable or not checkLOS or not obj_blocking_line(dude_obj, tile_num(obj), BLOCKING_TYPE_SHOOT)) then begin
if (alsoContainer and obj_item_subtype(obj) == item_type_container) or (not NO_HIGHLIGHT(obj)) then begin
if (enable) then set_outline(obj, outlineColor);
else set_outline(obj, 0);
procedure DudeCanSee(variable obj) begin
variable block := obj_blocking_line(dude_obj, tile_num(obj), BLOCKING_TYPE_SHOOT);
return not block or block == obj;
end
procedure DudeCanHear(variable obj) begin
variable hearDist := dude_perception * 5;
if (get_flags(obj) bwand FLAG_TRANSGLASS) then
hearDist /= 2;
return tile_distance_objs(dude_obj, obj) <= hearDist;
end
procedure GetOutlineColor(variable obj, variable isCritter) begin
if isCritter then begin
if get_team(obj) == get_team(dude_obj) then return OUTLINE_GREEN_GLOW;
if not DudeCanSee(obj) then begin
if (DudeCanHear(obj)) then return OUTLINE_DARK_YELLOW;
return 0;
end
return OUTLINE_RED_GLOW;
end
if checkLOS and not DudeCanSee(obj) then
return 0;
return outlineColor;
end
procedure ToggleHighlightObject(variable obj, variable enable, variable isCritter) begin
if (not alsoContainer or obj_item_subtype(obj) != item_type_container) and NO_HIGHLIGHT(obj) then return;
set_outline(obj, GetOutlineColor(obj, isCritter) if enable else 0);
end
procedure ToggleHighlight(variable enable) begin
variable obj;
variable obj, isCorpse;
foreach obj in list_as_array(LIST_GROUNDITEMS) begin
if obj != outlined_object then begin
call ToggleHighlightObject(obj, enable);
if obj and obj != outlined_object then begin
call ToggleHighlightObject(obj, enable, false);
end
end
if (alsoCorpse) then begin
if (alsoCorpse or alsoCritter) then begin
foreach obj in list_as_array(LIST_CRITTERS) begin
if critter_state(obj) == CRITTER_IS_DEAD and not NO_STEAL(obj) then begin
call ToggleHighlightObject(obj, enable);
if obj and obj != dude_obj then begin
isCorpse := critter_state(obj) == CRITTER_IS_DEAD;
if (alsoCritter and not isCorpse) or (isCorpse and not NO_STEAL(obj)) then begin
call ToggleHighlightObject(obj, enable, not isCorpse);
end
end
end
end
tile_refresh_display;
if (checkLOS or alsoCritter) and enable != isHighlight then begin
set_global_script_repeat(REPEAT_FRAMES if enable else 0);
end
isHighlight := enable;
end
procedure KeyPressHandler begin
@@ -71,7 +108,7 @@ procedure KeyPressHandler begin
if scanCode == highlightKey and not(get_game_mode bwand (INTFACELOOT bwor BARTER)) then begin
if pressed then begin
isHighlight := true;
set_global_script_repeat(REPEAT_FRAMES);
if motionScanner then begin
scanner := obj_carrying_pid_obj(dude_obj, PID_MOTION_SENSOR);
if scanner then begin
@@ -94,16 +131,21 @@ procedure KeyPressHandler begin
call ToggleHighlight(true);
end
end else begin
isHighlight := false;
call ToggleHighlight(false);
end
end
end
// visual glitch fix - for 3.8.29+
// visual glitch fix, turn off highlight when entering combat - for 3.8.40+
procedure CombatTurnHandler begin
if isHighlight then begin
call ToggleHighlight(false);
end
end
// visual glitch fix, turn off highlight when opening loot/barter screens - for 3.8.29+
procedure GameModeChangeHandler begin
if isHighlight and (get_game_mode bwand (INTFACELOOT bwor BARTER)) then begin
isHighlight := false;
call ToggleHighlight(false);
end
end
@@ -114,12 +156,15 @@ procedure InventoryMoveHandler begin
end
procedure start begin
if game_loaded and (sfall_ver_major < 4 and sfall_ver_build >= 12) then begin
if game_loaded then begin
if (sfall_ver_major >= 4 or sfall_ver_build < 12) then return;
call InitConfigs;
highlightKey := GetConfig(configSection, "Key", 0);
alsoContainer := GetConfig(configSection, "Containers", 0);
alsoCorpse := GetConfig(configSection, "Corpses", 0);
alsoCritter := GetConfig(configSection, "Critters", 0);
checkLOS := GetConfig(configSection, "CheckLOS", 0);
outlineColor := GetConfig(configSection, "OutlineColor", 16);
if (outlineColor < 1) then outlineColor := 64;
@@ -129,7 +174,13 @@ procedure start begin
highlightFailMsg2 := Translate("HighlightFail2", "Your motion sensor is out of charge.");
register_hook_proc(HOOK_KEYPRESS, KeyPressHandler);
register_hook_proc(HOOK_COMBATTURN, CombatTurnHandler);
register_hook_proc(HOOK_GAMEMODECHANGE, GameModeChangeHandler);
register_hook_proc(HOOK_INVENTORYMOVE, InventoryMoveHandler);
set_global_script_type(1);
end else begin
if isHighlight and not(get_game_mode bwand (INTFACELOOT bwor BARTER)) then begin
call ToggleHighlight(true);
end
end
end
@@ -12,7 +12,7 @@
#include "..\scripting\headers\lib.inven.h"
*/
variable ini := "sfall-mods.ini";
variable ini := "mods\\sfall-mods.ini";
variable translationIni;
// Gets the integer value from the specified ini
@@ -1,9 +1,9 @@
Item Highlight mod (Lite version) for sfall 3.8.x
-------------------------------------------------
Item Highlighting mod (Lite version) for sfall 3.8.x
----------------------------------------------------
A cut-down version of the mod included in sfall 4.x, offers a bit more features than the built-in function.
A cut-down version of the mod included in sfall 4.x, offers more features than the built-in function.
Features:
- highlighting items, containers (optional) and lootable corpses (optional) on the ground
- highlights items, containers (optional) and lootable corpses (optional) on the ground
- configurable hotkey is used to trigger highlight
- only objects in direct line-of-sight of player are highlighted (optional)
- motion scanner is required to enable highlight (optional)
@@ -12,10 +12,10 @@ Features:
Requires sfall 3.8.12 or higher.
To use, copy gl_highlighting_lite.int to your scripts folder, and copy sfall-mods.ini to the same directory as sfall.
Also, you should disable the built-in function in ddraw.ini (ToggleItemHighlightsKey=0).
To use, copy gl_highlighting_lite.int to your scripts folder and sfall-mods.ini to the mods folder in the same directory as sfall.
Create the mods folder if it does not exist. Also, you should disable the built-in function in ddraw.ini (ToggleItemHighlightsKey=0).
Note that due to the lack of newer game hooks in sfall 3.8.x, there are some minor visual glitches in the lite version:
- items will be kept highlighted when entering combat while holding the highlight key.
- when you pick up items while holding the highlight key, they will be kept highlighted if you drop them on the ground (fixed for 3.8.18+).
- items will be kept highlighted when entering combat while holding the highlight key (fixed in 3.8.40+).
- when you pick up items while holding the highlight key, they will be kept highlighted if you drop them on the ground (fixed in 3.8.18+).
Both glitches can bo solved by pressing and releasing the highlight key again.
@@ -9,10 +9,13 @@ Containers=0
; Set to 1 to also highlight lootable corpses
Corpses=0
; Set to 1 to only highlight objects in the player's line-of-sight
CheckLOS=0
; Set to 1 to also highlight critters, with the same rules as in combat
Critters=0
; Set the color of outlines, available colors:
; Set to 1 to only highlight objects in the player's line-of-sight
CheckLOS=1
; Set the color of outlines for items, corpses, and containers; available colors:
; 1 - glowing red
; 2 - red
; 4 - grey
@@ -20,7 +23,7 @@ CheckLOS=0
; 16 - bright yellow
; 32 - dark yellow
; 64 - purple
; You can set a custom color from the game palette by multiplying the color index value by 256 (available since sfall 4.2.7)
; You can set a custom color from the game palette by multiplying the color index value by 256 (in 3.8.27 or later)
OutlineColor=16
; Motion Scanner mode:
@@ -28,3 +31,37 @@ OutlineColor=16
; 1 - requires Motion Scanner present in player inventory to activate highlighting
; 2 - requires Motion Scanner and also requires 1 charge on every use (depleted scanner will not work anymore)
MotionScanner=0
[CombatControl]
;Allows you to control other critters directly in combat
;Set to 0 to disable
;Set to 1 to control all critters in combat (allowed only in sfall debugging mode)
;Set to 2 to control all party members
;Set to 3 to let you use the command cursor to specify targets for party members to attack in combat
Mode=0
;If you want to control only specific critters, uncomment the PIDList line and set a comma delimited list of PIDs
;PIDList=62,89,97,107,160,161
;Set a comma delimited list of perk IDs for perks to be inherited from the player during the combat control
PerksList=0,73
;Set to 1 to allow the player to gain a positive reputation when killing NPCs while controlling other critters
GainReputation=0
;Choose a notification box to display the name of the controlled critter above the interface bar
;Must be between 5 and (4 + the value of BoxBarCount in ddraw.ini)
;For sfall 4.1.6+ the number for the notification box is set automatically, so just use any value
;Set to 0 to disable
DisplayName=0
;Set the color of display name, available colors:
;0 - green
;1 - red
;2 - white
;3 - yellow
;4 - dark yellow
;5 - blue
;6 - purple
;7 - dull pink
DisplayNameColor=0
@@ -23,6 +23,7 @@
#define FID_OBJ_CRITTER (0x01000000)
procedure update_armor_apperance;
procedure canuseweapon_handler;
variable
modIni := "npcarmor.ini",
@@ -165,7 +166,9 @@ end
procedure start begin
variable sect, sects, armorTypes, armorType, npc, pid, pids, i;
if game_loaded and (sfall_ver_major < 4 and sfall_ver_build >= 29) then begin
if game_loaded then begin
if (sfall_ver_major >= 4 or sfall_ver_build < 29) then return;
armorTypes := get_ini_section(modIni, "ArmorTypes");
armorPidMap := create_array_map;
foreach (armorType: pids in armorTypes) begin
@@ -205,6 +208,7 @@ procedure start begin
register_hook_proc(HOOK_INVENWIELD, invenwield_handler);
register_hook_proc(HOOK_ADJUSTFID, adjustfid_handler);
register_hook_proc(HOOK_INVENTORYMOVE, inventorymove_handler);
register_hook_proc_spec(HOOK_CANUSEWEAPON, canuseweapon_handler);
debug_msg("NPC armor appearance mod: Done.");
end
@@ -222,3 +226,16 @@ procedure update_armor_apperance begin
end
end
end
// prevent NPCs from equipping "unusable" weapons - for 3.8.40+
procedure canuseweapon_handler begin
variable critter, canUse;
critter := get_sfall_arg;
if (critter != dude_obj and get_sfall_arg_at(3)) then begin
canUse := check_weapon_change(critter, get_sfall_arg, true);
if (canUse == false) then begin
set_sfall_arg(3, 0);
set_sfall_return(0); // overrides the result of engine function. Any non-zero value allows using the weapon
end
end
end
@@ -8,10 +8,10 @@ Can be adopted to any mod by adjusting armor PIDs, allowed weapon anim codes, NP
Requires sfall 3.8.29 or higher.
To use, copy gl_npcarmor_lite.int to your scripts folder, and copy npcarmor.ini to the same directory as sfall.
To use, copy gl_npcarmor_lite.int to your scripts folder and copy npcarmor.ini to the same directory as sfall.
The default npcarmor.ini is set up for Restoration Project 2.3.3.
Check the included "npcarmor - vanilla.ini" for an example that does not require any new graphics.
Note that due to the lack of newer game hooks in sfall 3.8.x, there is a minor glitch in the lite version:
- in combat, NPCs can pick up and try to equip weapons with anim codes that are not allowed in INI file but supported by their appearance.
- in combat, NPCs can pick up and try to equip weapons with anim codes that are not allowed in INI file but supported by their appearance (fixed in 3.8.40+).
@@ -0,0 +1,246 @@
/*
NPC Combat Control (Lite version)
A script-based mod of the removed built-in ControlCombat option, offering more features and improvements.
Features:
- allows you to take control of your party members or other NPCs during combat
(unlike in newer 4.x versions, controlled critters cannot use Sneak skill in combat)
- configurable list of perk IDs for perks being inherited from the player (optional, not all perks can work)
- allows the player to gain a positive reputation when killing NPCs while controlling other critters (optional)
- a notification box to display the name of the controlled critter above the interface bar (optional)
NOTE: this script requires compiler from sfall modderspack with -s option
(short circuit evaluation)
Requires sfall 3.8.40 or higher
version 1.3
*/
#include "..\headers\global.h"
#include "..\headers\critrpid.h"
#include "main.h"
#ifndef DEBUG
#define DEBUGMSG(x)
#else
#define DEBUGMSG(x) debug_msg(x);
#endif
procedure start;
procedure AllowControl(variable pid);
procedure SetLight(variable critter, variable int, variable dist);
procedure CombatTurn_Handler;
procedure GameModeChange_Handler;
procedure InventoryMove_Handler;
procedure InvenWield_Handler;
procedure SetGlobalVar_Handler;
variable
controlMode,
pidList, perksList,
lightInt, lightDist, npcControl,
displayName, displayNameColor, isShowTag,
inControl := false,
dudeLightInt, dudeLightDist;
procedure AllowControl(variable pid) begin
return ((pidList == 0 or scan_array(pidList, pid bwand 0xFFFFFF) != -1) and (party_member_obj(pid)));
end
procedure SetLight(variable critter, variable lInt, variable lDist) begin
if (lInt) then lInt := round((lInt / 65536.0) * 100); // calc percent of intensity
obj_set_light_level(critter, lInt, lDist); // TODO: make sfall obj_set_light_level function
end
procedure CombatTurn_Handler begin
variable
status := get_sfall_arg,
critter := get_sfall_arg,
pid, perkID, level;
DEBUGMSG("Combat Turn: " + status + ", by " + obj_name(critter) + "/" + critter + ", arg3: " + get_sfall_arg)
pid := obj_pid(critter);
if (pid == PID_PLAYER and inControl == false) then return;
if (pid != PID_PLAYER and controlMode != 1 and AllowControl(pid) == false) then begin
DEBUGMSG("Skip control.")
if (npcControl) then begin
npcControl := 0;
set_dude_obj(real_dude_obj);
call SetLight(dude_obj, dudeLightInt, dudeLightDist); // restore dude light
move_to(dude_obj, dude_tile, dude_elevation);
DEBUGMSG("Set dude after NPC control.")
end
return;
end
if (status == 1) then begin
set_dude_obj(critter);
DEBUGMSG("Take control of: " + obj_name(critter))
if (critter != real_dude_obj) then begin
if (npcControl == 0) then begin
dudeLightDist := get_object_data(real_dude_obj, OBJ_DATA_LIGHT_DISTANCE);
dudeLightInt := get_object_data(real_dude_obj, OBJ_DATA_LIGHT_INTENSITY);
obj_set_light_level(real_dude_obj, 0, 0); // dude off light
end
npcControl := critter;
lightDist := get_object_data(critter, OBJ_DATA_LIGHT_DISTANCE);
lightInt := get_object_data(critter, OBJ_DATA_LIGHT_INTENSITY);
// set perks (only work with 4.1.8+)
foreach (perkID in perksList) begin
level := has_trait(TRAIT_PERK, real_dude_obj, perkID);
if (level) then critter_add_trait(critter, TRAIT_PERK, perkID, level);
end
intface_redraw;
obj_set_light_level(critter, 100, 4);
inControl := true;
end else if (npcControl) then begin
call SetLight(dude_obj, dudeLightInt, dudeLightDist); // restore dude light
npcControl := 0; // for dude control
intface_redraw;
end
if (inControl) then begin
// check preference setting _combat_highlight
if (read_byte(0x56D38C)) then set_outline(critter, OUTLINE_GREY); // TODO: replace read_byte with normal function
// center the screen on the controlled critter/dude and remove roof tiles
move_to(dude_obj, dude_tile, dude_elevation);
if (displayName and critter != real_dude_obj) then begin
set_iface_tag_text(displayName, obj_name(critter), displayNameColor);
show_iface_tag(displayName);
isShowTag := true;
end
end
end else begin
if (npcControl) then begin
call SetLight(critter, lightInt, lightDist); // restore light for controlled NPC
end
if (isShowTag) then begin
hide_iface_tag(displayName);
isShowTag := false;
end
// remove perks before switching control (only work with 4.1.8+)
if (dude_obj != real_dude_obj) then begin
DEBUGMSG("Remove perks after NPC control.")
foreach (perkID in perksList) begin
level := has_trait(TRAIT_PERK, real_dude_obj, perkID);
if (level) then critter_rm_trait(critter, TRAIT_PERK, perkID, level);
end
end
if (status < 0) then begin
set_dude_obj(real_dude_obj);
call SetLight(dude_obj, dudeLightInt, dudeLightDist);
end
end
end
procedure GameModeChange_Handler begin
if (inControl and (get_game_mode bwand COMBAT) == 0) then begin
inControl := false;
npcControl := 0;
move_to(dude_obj, dude_tile, dude_elevation);
end
end
procedure InventoryMove_Handler begin
if (npcControl and get_sfall_arg == 3) then begin // armor slot
if (obj_pid(dude_obj) == PID_MARCUS or proto_data(obj_pid(dude_obj), cr_body_type) != CR_BODY_BIPED) then begin
display_msg(message_str_game(GAME_MSG_PROTO, 675));
set_sfall_return(true);
end
end
end
procedure InvenWield_Handler begin
variable
critter := get_sfall_arg,
item := get_sfall_arg,
slot := get_sfall_arg,
event := get_sfall_arg;
// Fix weapon duplication when equipping in combat
if (event and slot == INVEN_TYPE_RIGHT_HAND and AllowControl(obj_pid(critter))) then begin
set_flags(item, get_flags(item) bwand bwnot(FLAG_LEFT_HAND));
end
end
procedure SetGlobalVar_Handler begin
if (npcControl and get_sfall_arg == GVAR_PLAYER_REPUTATION and obj_pid(dude_obj) != PID_PLAYER) then begin
variable value := global_var(GVAR_PLAYER_REPUTATION);
if (get_sfall_arg > value) then begin
set_sfall_arg(1, value);
set_sfall_return(value);
end
end
end
procedure start begin
if game_loaded then begin
if (sfall_ver_major >= 4 or sfall_ver_build < 40) then return;
controlMode := GetConfig("CombatControl", "Mode", 0);
if (controlMode >= 3) then begin
if (controlMode == 3) then metarule3(999, 0, 0, 0); // enable feature: order party members to attack a specified target
controlMode := 0;
end else if (controlMode == 1 and GetIniConfig("Debugging", "Enable", 0, "ddraw.ini") == 0) then begin
controlMode := 2;
end
if (controlMode > 0) then begin
displayName := GetConfig("CombatControl", "DisplayName", 0);
if (displayName) then begin
variable nameTag := add_iface_tag;
debug_msg("NPC control - added new box: " + nameTag);
if (nameTag <= 0) then begin // box added?
variable maxBoxCount := get_ini_setting("ddraw.ini|Misc|BoxBarCount");
if (maxBoxCount < 0) then maxBoxCount := 9;
else maxBoxCount += 4;
if (displayName < 5 or displayName > maxBoxCount) then displayName := 0;
end else begin
displayName := nameTag;
end
displayNameColor := GetConfig("CombatControl", "DisplayNameColor", 0);
end
set_perk_ranks(PERK_gecko_skinning_perk, 1);
set_perk_level(PERK_gecko_skinning_perk, 999); // prevent it from appearing in the perk selection window
pidList := GetConfigListInt("CombatControl", "PIDList");
if (len_array(pidList) > 0) then
fix_array(pidList);
else
pidList := 0;
perksList := GetConfigListInt("CombatControl", "PerksList");
fix_array(perksList);
register_hook_proc(HOOK_COMBATTURN, CombatTurn_Handler);
register_hook_proc(HOOK_GAMEMODECHANGE, GameModeChange_Handler);
register_hook_proc(HOOK_INVENTORYMOVE, InventoryMove_Handler);
register_hook_proc(HOOK_INVENWIELD, InvenWield_Handler);
if (GetConfig("CombatControl", "GainReputation", 0) == 0) then begin
register_hook_proc(HOOK_SETGLOBALVAR, SetGlobalVar_Handler);
end
end else begin
exit;
end
end
end
@@ -0,0 +1,16 @@
NPC Combat Control mod (Lite version) for sfall 3.8.x
-----------------------------------------------------
A script-based mod of the removed built-in ControlCombat option, offering more features and improvements.
Features:
- allows you to take control of your party members or other NPCs during combat
(unlike in newer 4.x versions, controlled critters cannot use Sneak skill in combat)
- configurable list of perk IDs for perks being inherited from the player (optional, not all perks can work)
- allows the player to gain a positive reputation when killing NPCs while controlling other critters (optional)
- a notification box to display the name of the controlled critter above the interface bar (optional)
Requires sfall 3.8.40 or higher.
To use, copy gl_partycontrol_lite.int to your scripts folder and sfall-mods.ini (in ItemHighlight_Lite) to the mods folder in the same directory as sfall.
Create the mods folder if it does not exist.
@@ -356,6 +356,7 @@ There are several changes in this version of sslc which may result in problems f
- fixed optimizer not treating `call string_variable` as variable use
- fixed unused arguments in a procedure being removed incorrectly by the optimizer
- fixed unused string literals in an optimized-out procedure not being removed by the optimizer
- fixed `get_array` syntax not working for exported variables
**sfall 4.2.9:**
- added support for additional universal opcodes `sfall_func7` and `sfall_func8`
+1 -1
View File
@@ -907,7 +907,7 @@ sfall_funcX metarule functions
----
#### string_format
`string sfall_func2("string_format", string format, any val1)`
`string sfall_func2("string_format", string format, any val1)`\
`string sfall_funcX("string_format", string format, any val1, any val2, ...)`
- Formats given values using standard syntax of C `printf` function (google "printf" for format details). However, it is limited to formatting up to 7 values
- The format string is limited to 1024 characters