Skip to content

Commit

Permalink
Returning Boomerangs
Browse files Browse the repository at this point in the history
- Add new mechanic to gl_throwing_bonus for returning Boomerangs
- Return on successful roll vs Throwing skill regardless of hit/miss
- On return to dude, new message is displayed
  • Loading branch information
phobos2077 committed May 15, 2024
1 parent a492d1e commit 92ff373
Show file tree
Hide file tree
Showing 10 changed files with 141 additions and 18 deletions.
2 changes: 2 additions & 0 deletions root/data/text/english/game/pbs_combat.msg
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# stealth
{100}{}{You caught %s off guard with unexpected attack.}

# boomerang
{120}{}{You manage to catch a %s on return.}

# destroy weapon - male
{200}{}{%s damaged his %s beyond repair.}
Expand Down
2 changes: 2 additions & 0 deletions root/data/text/russian/game/pbs_combat.msg
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# stealth
{100}{}{�� ������� %s �������� ����������� ������.}

# boomerang
{120}{}{��� ������� ������� %s �� �������� ����������.}

# destroy weapon - �������
{200}{}{%s �������� ���� %s �� ��������������.}
Expand Down
6 changes: 6 additions & 0 deletions root/mods/ecco/combat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ bonus_crit_chance_luck_mult=3
; Set 1 to add Melee Damage to max damage for melee-based throwing weapons, just like Melee/Unarmed.
apply_melee_dmg=1

; List of weapon PIDs that will return to thrower at the end of his turn, if roll vs Throwing skill is successfull
return_weapon_pids=637

; Skill mod for catching Boomerang on return
return_catch_skill_mod=-20


[CRITTER_LOOT]
;set to 1 to enable weapons dropping to the ground on death, set to 0 to disable
Expand Down
2 changes: 2 additions & 0 deletions scripts_src/_pbs_headers/ecco.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#include "../sfall/define_extra.h"

#include "ecco_ids.h"
#include "ecco_ini.h"
#include "ecco_log.h"
#include "ecco_msg.h"


#define dude_skill(x) (has_skill(dude_obj, x))
Expand Down
6 changes: 4 additions & 2 deletions scripts_src/_pbs_headers/ecco_ini.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef ECCO_INI_H
#define ECCO_INI_H

#include "../sfall/lib.strings.h"

#define INI_SFALL "ddraw.ini"
#define INI_COMBAT "ecco\\combat.ini"
#define INI_ECONOMY "ecco\\barter.ini"
Expand All @@ -9,13 +11,13 @@
#define get_int_from_ini(name, section, setting) get_ini_setting(name + "|" + section + "|" + setting)
#define get_str_from_ini(name, section, setting) get_ini_string(name + "|" + section + "|" + setting)
#define get_float_from_ini(name, section, setting) atof(get_ini_string(name + "|" + section + "|" + setting))
#define get_int_list_from_ini(name, section, setting) string_split_ints(get_ini_string(name + "|" + section + "|" + setting), ",")
#define get_int_list_from_ini(name, section, setting) string_split_ints(get_ini_string(name + "|" + section + "|" + setting), ",")

#define int_from_ini_file(name, file, section) ini_##name := get_int_from_ini(file, section, #name)
#define str_from_ini_file(name, file, section) ini_##name := get_str_from_ini(file, section, #name)
#define float_from_ini_file(name, file, section) ini_##name := get_float_from_ini(file, section, #name)

#define int_list_from_ini_file(name, file, section) ini_##name := get_int_list_from_ini(file, section, #name)
#define int_list_from_ini_file(name, file, section) ini_##name := array_fixed(get_int_list_from_ini(file, section, #name))
#define int_from_ini_file_clamped(name, file, section, min, max) ini_##name := math_clamp(get_int_from_ini(file, section, #name), min, max)
#define float_from_ini_file_clamped(name, file, section, min, max) ini_##name := math_clamp(get_float_from_ini(file, section, #name), min, max)

Expand Down
2 changes: 1 addition & 1 deletion scripts_src/_pbs_main/gl_melee_gore_unlock.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ procedure deathanim2_handler begin
damageType := get_proto_data(weaponPID, PROTO_WP_DMG_TYPE),
wpnAnim := get_proto_data(weaponPID, PROTO_WP_ANIM);

display_msg(string_format("weapon %d mode = %d, dmgType = %d, atkType = %d, violence filter = %d", weaponPID, weaponMode, damageType, attackType, violence_filter_setting));
//display_msg(string_format("weapon %d mode = %d, dmgType = %d, atkType = %d, violence filter = %d", weaponPID, weaponMode, damageType, attackType, violence_filter_setting));
if ((weaponMode == ATTACK_MODE_PUNCH and damageType == DMG_normal_dam)
or weaponMode == ATTACK_MODE_KICK
or weaponMode == ATTACK_MODE_THRUST
Expand Down
2 changes: 1 addition & 1 deletion scripts_src/_pbs_main/gl_pbs_critter_loot.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ procedure reduce_item_count(variable invenobj, variable item, variable newCount)
#define load_ini_int(name) int_from_ini_file(name, INI_COMBAT, INI_SECTION)
#define load_ini_str(name) str_from_ini_file(name, INI_COMBAT, INI_SECTION)
#define load_ini_int_clamped(name, min, max) int_from_ini_file_clamped(name, INI_COMBAT, INI_SECTION, min, max)
#define load_ini_int_list(name) int_list_from_ini_file(name, INI_COMBAT, INI_SECTION); fix_array(ini_##name)
#define load_ini_int_list(name) int_list_from_ini_file(name, INI_COMBAT, INI_SECTION)

/*
HOOK_ONDEATH
Expand Down
99 changes: 98 additions & 1 deletion scripts_src/_pbs_main/gl_throwing_bonus.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
INI-configurable throwing weapons buffs:
- Damage bonus based on Throwing Skill
- Flat crit-chance bonus + Luck-based bonus
- Returning Boomerang mechanic
*/

#define SCRIPT_REALNAME "gl_throwing_bonus"
Expand All @@ -13,31 +14,46 @@
#include "../sfall/lib.arrays.h"
#include "../sfall/lib.math.h"
#include "../sfall/lib.inven.h"
#include "../sfall/lib.obj.h"

#include "../_pbs_headers/ecco.h"

variable
ini_damage_bonus_skill_mult,
ini_bonus_crit_chance,
ini_bonus_crit_chance_luck_mult,
ini_apply_melee_dmg;
ini_apply_melee_dmg,
ini_return_weapon_pids,
ini_return_catch_skill_mod,
thrown_owner,
thrown_items;

procedure start;
procedure itemdamage_handler;
procedure rollcheck_handler;
procedure combatturn_handler;
procedure removeinvenobj_handler;

procedure start begin
if game_loaded then begin
float_from_ini_file_clamped(damage_bonus_skill_mult, INI_COMBAT, INI_SECTION, 0.0, 10.0);
int_from_ini_file_clamped(bonus_crit_chance, INI_COMBAT, INI_SECTION, 0, 100);
int_from_ini_file_clamped(bonus_crit_chance_luck_mult, INI_COMBAT, INI_SECTION, 0, 100);
int_from_ini_file(apply_melee_dmg, INI_COMBAT, INI_SECTION);
int_list_from_ini_file(return_weapon_pids, INI_COMBAT, INI_SECTION);
int_from_ini_file(return_catch_skill_mod, INI_COMBAT, INI_SECTION);

if (ini_apply_melee_dmg > 0 or ini_damage_bonus_skill_mult > 0.01) then begin
register_hook_proc(HOOK_ITEMDAMAGE, itemdamage_handler);
end
if (ini_bonus_crit_chance > 0) then begin
register_hook_proc(HOOK_ROLLCHECK, rollcheck_handler);
end

if (len_array(ini_return_weapon_pids) > 0) then begin
register_hook_proc(HOOK_COMBATTURN, combatturn_handler);
register_hook_proc(HOOK_REMOVEINVENOBJ, removeinvenobj_handler);
end
end
end

Expand Down Expand Up @@ -159,3 +175,84 @@ procedure itemdamage_handler begin
end
end
end

/*procedure return_thrown_item begin
//display_msg("Timed called at "+game_time);
if (thrown_item and thrown_owner) then begin
debug_log_fmt("Returning thrown weapon %s back to %s", obj_name(thrown_item), obj_name(thrown_owner));
add_obj_to_inven(thrown_owner, thrown_item);
wield_obj_critter(thrown_owner, thrown_item);
end
end*/


/*
Runs before and after each turn in combat (for both PC and NPC).

int arg0 - event type:
1 - start of turn
0 - normal end of turn
-1 - combat ends abruptly (by script or by pressing Enter during PC turn)
-2 - combat ends normally (hook always runs at the end of combat)
Critter arg1 - critter doing the turn
int arg2 - 1 at the start/end of the player's turn after loading a game saved in combat mode, 0 otherwise

int ret0 - pass 1 at the start of turn to skip the turn, pass -1 at the end of turn to force end of combat
*/
procedure combatturn_handler begin
variable
eventType := get_sfall_arg,
critter := get_sfall_arg,
item, isFirst;

if (critter == thrown_owner and thrown_items and eventType <= 0) then begin
isFirst := true;
foreach (item in thrown_items) begin
if (not is_success(roll_vs_skill(critter, SKILL_THROWING, ini_return_catch_skill_mod))) then continue;

debug_log_fmt("Returning thrown weapon %s back to %s", obj_name(item), obj_name(thrown_owner));
add_obj_to_inven(thrown_owner, item);
if (isFirst) then begin
if (critter == dude_obj) then begin
display_msg(sprintf(mstr_ecco_combat(120), obj_name(item)));
end
if (not get_active_weapon(critter)) then
wield_obj_critter(thrown_owner, item);
isFirst = false;
end
end
end
thrown_owner := 0;
if (thrown_items) then
clear_array(thrown_items);
end


/*
Runs when an object is removed from a container or critter's inventory for any reason.

Obj arg0 - the owner that the object is being removed from
Item arg1 - the item that is being removed
int arg2 - the number of items to remove
int arg3 - The reason the object is being removed (see RMOBJ_* constants)
Obj arg4 - The destination object when the item is moved to another object, 0 otherwise
*/
procedure removeinvenobj_handler begin
variable
owner := get_sfall_arg,
item := get_sfall_arg,
num := get_sfall_arg,
reason := get_sfall_arg;

//display_msg(string_format("removeinvenobj %s(%d) from %s (reason: %d, flag: %x)", obj_name(item), num, obj_name(owner), reason, get_object_data(item, OBJ_DATA_FLAGS)));
// Return thrown Boomerangs back to owner
if (reason == RMOBJ_THROW and is_in_array(obj_pid(item), ini_return_weapon_pids) and num == 1) then begin
if (not thrown_items) then
thrown_items := create_array_list(0);
thrown_owner := owner;
call array_push(thrown_items, item);
//thrown_flags := get_object_data(item, OBJ_DATA_FLAGS);
//call return_thrown_item in 3; // very unreliable, needs to happen after attack ends, but animation length varies...
//display_msg("Called scheduled at "+game_time);
end
end
19 changes: 14 additions & 5 deletions scripts_src/_pbs_main/tests/gl_cheat_enemyspawner.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
#define ENEMY_GECKO (8)
#define ENEMY_BOSS (9)
#define ENEMY_DEATHCLAW (10)
#define ENEMY_THROWER (11)

variable enemy_types;

#define is_throwing_weapon_pid(pid) (weapon_attack_mode1(pid) == ATTACK_MODE_THROW)

procedure spawn_enemy(variable type, variable tile) begin
variable critter, pid, sid, weaponPid, weapon, ammoPid, stimpaks, female;
switch (type) begin
Expand All @@ -40,7 +43,7 @@ procedure spawn_enemy(variable type, variable tile) begin
weaponPid := PID_DESERT_EAGLE; // DE
case ENEMY_FARMER:
pid := PID_MALE_FARMER + random(0, 1);
sid := SCRIPT_DCPEASNT;
sid := SCRIPT_ECFARMER;
weaponPid := PID_SAWED_OFF_SHOTGUN;
case ENEMY_EYEBOT:
pid := PID_EYEBALL;
Expand All @@ -61,6 +64,12 @@ procedure spawn_enemy(variable type, variable tile) begin
case ENEMY_DEATHCLAW:
pid := PID_MOTHER_DEATHCLAW; // PID_TOUGH_DEATHCLAW;
sid := SCRIPT_ECDTHCLW;
case ENEMY_THROWER:
female := random(0, 1);
pid := PID_AGILE_GUARD_MALE + female;
sid := SCRIPT_ECRAIDER;
stimpaks := random(1, 3);
weaponPid := array_random_value([PID_THROWING_KNIFE, PID_PBS_BOOMERANG] if female else [PID_PBS_THROWING_AXE]);
case ENEMY_MELEE:
female := random(0, 1);
pid := PID_MELEE_GUARD_MALE + female;
Expand All @@ -73,7 +82,7 @@ procedure spawn_enemy(variable type, variable tile) begin

critter := create_object_sid(pid, tile, dude_elevation, sid);
if (weaponPid) then begin
weapon := add_item_pid(critter, weaponPid);
weapon := add_items_pid(critter, weaponPid, 3 if is_throwing_weapon_pid(weaponPid) else 1);
//wield_obj_critter(critter, weapon);
ammoPid := get_proto_data(weaponPid, PROTO_WP_AMMO_PID);
if (ammoPid > 0) then
Expand Down Expand Up @@ -112,7 +121,7 @@ procedure keypress_handler begin
//display_msg("key pressed "+keyCode);
if (keyCode == DIK_5) then begin
//call spawn_enemy(ENEMY_BOSS, tile_under_cursor);
call spawn_enemies_circle(ENEMY_ENCLAVE, 2);
call spawn_enemies_circle(ENEMY_FARMER, 2);
end
if (keyCode == DIK_6) then begin
variable crit := spawn_enemy(ENEMY_DEATHCLAW, tile_under_cursor);
Expand All @@ -122,9 +131,9 @@ procedure keypress_handler begin
reg_anim_end();
end
if (keyCode == DIK_7) then
call spawn_enemy(ENEMY_FARMER, tile_under_cursor);
call spawn_enemy(ENEMY_ENCLAVE, tile_under_cursor);
if (keyCode == DIK_8) then
call spawn_enemy(ENEMY_EYEBOT, tile_under_cursor);
call spawn_enemy(ENEMY_THROWER, tile_under_cursor);
if (keyCode == DIK_9) then
call spawn_enemies_circle(ENEMY_ALIEN, 1);
end
Expand Down
19 changes: 11 additions & 8 deletions scripts_src/_pbs_main/tests/gl_test.ssl
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,17 @@ procedure keypress_hook begin
end
end
if (key == DIK_F3) then begin
move_to(dude_obj, tile_under_cursor, dude_elevation);
if (get_cursor_mode == 1 and obj_under_cursor(true, false)) then begin
//obj := obj_under_cursor(true, false);
//variable tile := tile_num(obj);
//destroy_object(obj);
//obj := create_object_sid(16777224, tile, dude_elevation, 1313);
//set_script(obj, 1049); // NIBASDOR
//display_msg(string_format("Set script for %s to %d", obj_name(obj), 1049));
if (get_cursor_mode == 1) then begin
if (obj_under_cursor(true, false)) then begin
obj := obj_under_cursor(true, false);
//variable tile := tile_num(obj);
destroy_object(obj);
//obj := create_object_sid(16777224, tile, dude_elevation, 1313);
//set_script(obj, 1049); // NIBASDOR
//display_msg(string_format("Set script for %s to %d", obj_name(obj), 1049));
end
end else begin
move_to(dude_obj, tile_under_cursor, dude_elevation);
end
//variable block := obj_blocking_line(Greeting_Watcher, tile_under_cursor, BLOCKING_TYPE_SHOOT);
//display_msg(string_format("%s blocking: %s", obj_name_safe(Greeting_Watcher), obj_name_safe(block)));
Expand Down

0 comments on commit 92ff373

Please sign in to comment.