Files
sfall/artifacts/mods/gl_partycontrol.ssl
T
NovaRain f48fce3274 Fixed a rounding error in Glovz's damage formula
Minor edit to gl_partycontrol script.
Updated Russian and Germen translations.
2021-10-15 10:06:02 +08:00

207 lines
7.2 KiB
Plaintext

/*
NPC Combat Control
Allows to take control of your party member or other NPCs during combat
NOTE: this script requires compiler from sfall modderspack with -s option
(short circuit evaluation)
version 1.2
*/
#include "..\headers\define.h"
//#include "..\headers\command.h"
#include "main.h"
#define OBJ_DATA_LIGHT_DISTANCE (0x6C)
#define OBJ_DATA_LIGHT_INTENSITY (0x70)
#define PID_PLAYER (16777216)
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;
variable
controlMode,
noCheckArray,
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;
//display_msg("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 return;
if (status == 1) then begin
set_dude_obj(critter);
//display_msg("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; // dude control
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
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
set_dude_obj(0); // w/o redraw interface bar
//display_msg("Return control to real dude!");
end
if (status < 0) then begin
set_dude_obj(real_dude_obj);
call SetLight(dude_obj, dudeLightInt, dudeLightDist); //obj_set_light_level(dude_obj, 100, 4);
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 start begin
if (game_loaded and sfall_ver_major >= 4) then begin
//variable configSection := "CombatControl";
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
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
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
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);
end else begin
exit;
end
end
end