Files
sfall/artifacts/mods/gl_npcarmor.ssl
T

223 lines
7.3 KiB
Plaintext
Raw Normal View History

/*
NPC Armor Appearance mod
Used to replace the scripted part of B-Team mod.
Appropriate graphics are required for this mod to work.
Can be adopted to any mod by adjusting armor PIDs, allowed weapon anim codes, NPC PIDs and NPC FIDs in INI file.
NOTE: this script requires compiler from sfall modderspack with -s option
(short circuit evaluation)
version 1.1
*/
#include "main.h"
2019-10-11 00:45:46 +08:00
#define IS_ARMOR(item) (obj_type(item) == OBJ_TYPE_ITEM and obj_item_subtype(item) == item_type_armor)
#define IS_WEAPON(item) (obj_type(item) == OBJ_TYPE_ITEM and obj_item_subtype(item) == item_type_weapon)
2019-10-11 00:45:46 +08:00
#define FID_OBJ_CRITTER (0x01000000)
procedure update_armor_apperance;
variable
modIni := "npcarmor.ini",
defaultFids,
armorPidMap, // maps armor PID to it's "type" - leather armor, metal, power armor, etc.
npcMap,
altWeapon,
unWieldWeapon;
2019-10-11 00:45:46 +08:00
/*
Returns the FID value set in the config settings for party member armor: Jacket, Leather, etc.
*/
procedure check_armor_change(variable critter, variable armor, variable isWield) begin
variable npc, armorType, fid;
2019-10-11 00:45:46 +08:00
npc := npcMap[obj_pid(critter)];
if (npc) then begin
if (isWield == false) then begin
// display_msg("No armor fid: " + npc["Default"]);
return npc["Default"];
2019-10-11 00:45:46 +08:00
end else if (armor) then begin
armorType := armorPidMap[obj_pid(armor)];
fid := npc[armorType] or defaultFids[armorType];
if (fid == 0 or fid == -1) then fid := npc["Default"];
// display_msg("Change fid: " + fid + ", npc: " + npc[armorType] + ", default:" + defaultFids[armorType]);
return fid;
end
end
2019-10-11 00:45:46 +08:00
return -1; // engine default
end
2019-10-11 00:45:46 +08:00
/*
Checks if a party member can use the offered weapon
*/
procedure check_weapon_change(variable critter, variable weapon, variable isWield) begin
variable npc, newWeaponAnim, weaponAnimList, i;
2019-10-11 00:45:46 +08:00
npc := npcMap[obj_pid(critter)];
if (npc) then begin
if (isWield) then begin
newWeaponAnim := get_proto_data(obj_pid(weapon), PROTO_WP_ANIM);
if newWeaponAnim then begin // anim code 0 - none/unarmed
2019-10-11 00:45:46 +08:00
weaponAnimList := npc["WeaponAnims"];
if (weaponAnimList != 0) then begin
foreach (i in string_split(weaponAnimList, ",")) begin
if (newWeaponAnim == atoi(i)) then return -1; // can use (engine default)
end
end
2019-10-11 00:45:46 +08:00
return 0; // can't use
end
end else begin
2019-10-11 00:45:46 +08:00
unWieldWeapon := obj_pid(weapon);
end
end
2019-10-11 00:45:46 +08:00
return -1; // engine default
end
2019-10-11 00:45:46 +08:00
/*
Finds the first weapon which can be used by the party member in the inventory
*/
procedure search_alt_weapon(variable critter) begin
variable obj, res, i := 0;
obj := inven_ptr(critter, 0);
while (obj) do begin
if (obj_item_subtype(obj) == item_type_weapon) then begin
if (unWieldWeapon == 0 or unWieldWeapon != obj_pid(obj)) then begin
res := check_weapon_change(critter, obj, 1);
if (res == -1) then begin
altWeapon := obj;
wield_obj_critter(critter, obj);
altWeapon := 0;
break;
end
end
end
i++;
obj := inven_ptr(critter, i);
end
unWieldWeapon := 0;
end
// for NPCs when they change armor/weapon themselves
procedure invenwield_handler begin
2019-10-11 00:45:46 +08:00
variable critter, item, fid, slot, isWield, canWield;
critter := get_sfall_arg;
2019-10-11 00:45:46 +08:00
item := get_sfall_arg;
slot := get_sfall_arg;
isWield := get_sfall_arg;
2019-10-11 00:45:46 +08:00
if (/*critter and*/ item and slot == INVEN_TYPE_WORN) then begin
fid := check_armor_change(critter, item, isWield);
if (fid != -1) then begin
2019-03-16 08:47:37 +08:00
if art_exists(fid) then begin
art_change_fid_num(critter, fid);
end else begin
2019-10-11 00:45:46 +08:00
debug_msg("[Error] NPC armor mod: Invenwield missing FID: " + fid);
2019-03-16 08:47:37 +08:00
end
end
2019-10-11 00:45:46 +08:00
end else if (/*critter and*/ item and slot == INVEN_TYPE_RIGHT_HAND) then begin
if (altWeapon == item) then return;
2019-10-11 00:45:46 +08:00
canWield := check_weapon_change(critter, item, isWield);
set_sfall_return(canWield);
if (canWield != -1) then begin
2019-10-11 00:45:46 +08:00
call search_alt_weapon(critter); // wield weapon by script
end
end
end
// when changing armor from inventory while controlling other NPCs
procedure adjustfid_handler begin
2019-10-11 00:45:46 +08:00
variable fid, armor, weapAnim, currFid, newFid;
if (dude_obj != real_dude_obj) then begin
2019-10-11 00:45:46 +08:00
currFid := get_sfall_arg;
if ((currFid bwand 0x0F000000) != FID_OBJ_CRITTER) then return;
armor := critter_inven_obj(dude_obj, INVEN_TYPE_WORN);
fid := check_armor_change(dude_obj, armor, armor != 0);
if (fid != -1) then begin
2019-10-11 00:45:46 +08:00
weapAnim := currFid bwand 0xF000;
newFid := fid bwand 0xFFFF0FFF bwor weapAnim;
2019-03-16 08:47:37 +08:00
if art_exists(newFid) then begin
set_sfall_arg(0, newFid);
2019-03-16 08:47:37 +08:00
set_sfall_return(newFid);
end else begin
2019-10-11 00:45:46 +08:00
debug_msg("[Error] NPC armor mod: Adjust FID missing: " + newFid);
2019-03-16 08:47:37 +08:00
end
end
end
end
// when changing weapon from inventory while controlling other NPCs
procedure inventorymove_handler begin
variable slot, item, canWield;
slot := get_sfall_arg;
item := get_sfall_arg;
if (dude_obj != real_dude_obj) then begin
2019-10-11 00:45:46 +08:00
if ((slot == INVEN_TYPE_RIGHT_HAND or slot == INVEN_TYPE_LEFT_HAND) and IS_WEAPON(item)) then begin
canWield := check_weapon_change(dude_obj, item, item != 0);
set_sfall_return(canWield);
end
end
end
procedure start begin
variable sect, sects, armorTypes, armorType, npc, pid, pids, i;
if game_loaded and (sfall_ver_major >= 4) then begin
armorTypes := get_ini_section(modIni, "ArmorTypes");
2019-10-11 00:45:46 +08:00
armorPidMap := create_array_map;
foreach (armorType: pids in armorTypes) begin
pids := string_split(pids, ",");
foreach (pid in pids) begin
armorPidMap[atoi(pid)] := armorType;
end
end
2019-10-11 00:45:46 +08:00
defaultFids := get_ini_section(modIni, "Default");
fix_array(defaultFids);
foreach (armorType: i in defaultFids) begin
defaultFids[armorType] := atoi(i);
end
npcMap := create_array_map;
i := 1;
sect := get_ini_section(modIni, ""+i);
while (sect.PID) do begin
npc := create_array_map;
npc["WeaponAnims"] := sect["WeaponAnims"];
npc["Default"] := atoi(sect["Default"]);
foreach (armorType: pids in armorTypes) begin
if (sect[armorType]) then begin
npc[armorType] := atoi(sect[armorType]);
end
end
npcMap[atoi(sect.PID)] := npc;
i += 1;
sect := get_ini_section(modIni, ""+i);
end
2019-10-11 00:45:46 +08:00
call update_armor_apperance;
register_hook_proc(HOOK_INVENWIELD, invenwield_handler);
register_hook_proc(HOOK_ADJUSTFID, adjustfid_handler);
register_hook_proc(HOOK_INVENTORYMOVE, inventorymove_handler);
debug_msg("NPC armor appearance mod: Done.");
end
end
2019-10-11 00:45:46 +08:00
procedure update_armor_apperance begin
variable npc, arItem, fid;
foreach (npc in party_member_list_critters) begin
if (npc == dude_obj) then continue;
arItem := critter_inven_obj(npc, INVEN_TYPE_WORN);
if (arItem) then begin
fid := check_armor_change(npc, arItem, true);
if (fid == -1 or art_exists(fid) == false) then continue;
art_change_fid_num(npc, fid);
end
end
end