/* Example algorithm of how the game engine calculates combat damage */ #include "..\headers\define.h" #include "..\headers\command.h" #include "..\headers\sfall\sfall.h" #include "..\headers\sfall\define_extra.h" procedure start; procedure compute_damage_F2; procedure item_w_damage_hook; procedure item_w_subtype(variable weapon, variable hit_mode); procedure get_ammo_value(variable weapon, variable param); variable item_w_damage; procedure start begin if game_loaded then begin register_hook_proc(HOOK_COMBATDAMAGE, compute_damage_F2); register_hook_proc(HOOK_ITEMDAMAGE, item_w_damage_hook); end end procedure compute_damage_F2 begin variable dmg_type, weapon_perk, dmg_thresh, dmg_resist, weapon_subtype, bonus_ranged, difficulty, i, dmg_mult, dmg_div, damage; variable target, flags, knockback, amount; variable ctdTarget := get_sfall_arg, ctdSource := get_sfall_arg, amountTarget := get_sfall_arg, amountSource := get_sfall_arg, flagsTarget := get_sfall_arg, flagsSource := get_sfall_arg, weapon := get_sfall_arg, bodypart := get_sfall_arg, damageMultiplier := get_sfall_arg, rounds := get_sfall_arg, amountKnockback := get_sfall_arg, hit_mode := get_sfall_arg; if (flagsSource bwand DAM_HIT) then begin target := ctdTarget; flags := flagsTarget; knockback := 1; end else begin target := ctdSource; flags := flagsSource; knockback := 0; end //amount := 0; if target and (obj_type(target) == OBJ_TYPE_CRITTER) then begin if weapon then begin dmg_type := weapon_dmg_type(weapon); weapon_perk := get_proto_data(obj_pid(weapon), PROTO_WP_PERK); end else begin dmg_type := DMG_normal_dam; weapon_perk := -1; end dmg_thresh := get_critter_stat(target, STAT_dmg_thresh + dmg_type); dmg_resist := get_critter_stat(target, STAT_dmg_resist + dmg_type); if (flags bwand DAM_BYPASS) and (dmg_type != DMG_emp) then begin dmg_thresh := dmg_thresh * 20 / 100; dmg_resist := dmg_resist * 20 / 100; end else begin if (weapon_perk == PERK_weapon_penetrate) or (hit_mode == ATKTYPE_PALMSTRIKE or hit_mode == ATKTYPE_PIERCINGSTRIKE or hit_mode == ATKTYPE_HOOKKICK or hit_mode == ATKTYPE_PIERCINGKICK) then dmg_thresh := dmg_thresh * 20 / 100; if ctdSource == dude_obj and has_trait(TRAIT_TRAIT, ctdSource, TRAIT_finesse) then dmg_resist += 30; end weapon_subtype := item_w_subtype(weapon, hit_mode); // item_w_subtype_ if (ctdSource != dude_obj) or (weapon_subtype != WEAPON_TYPE_GUNS) then bonus_ranged := 0; else bonus_ranged := has_trait(TRAIT_PERK, ctdSource, PERK_bonus_ranged_damage) * 2; difficulty := 100; if (has_trait(TRAIT_OBJECT, ctdSource, OBJECT_TEAM_NUM) != has_trait(TRAIT_OBJECT, dude_obj, OBJECT_TEAM_NUM)) then begin if (combat_difficulty == 0) then difficulty := 75; else if (combat_difficulty == 2) then difficulty := 125; end // F2 default start // Damage = (1 - (DR_armor + DR_ammo_adjust) * (((raw_damage * (dmg_mult * damageMultiplier)) / dmg_div) - dmg_thresh) dmg_resist += get_ammo_value(weapon, PROTO_AM_DR_MOD); // item_w_dr_adjust_ (DR Adjust %) if (dmg_resist < 100) then begin if (dmg_resist < 0) then dmg_resist := 0; dmg_mult := damageMultiplier * get_ammo_value(weapon, PROTO_AM_DMG_MULT); // item_w_dam_mult_ (Dmg mod A) dmg_div := get_ammo_value(weapon, PROTO_AM_DMG_DIV); // item_w_dam_div_ (Dmg mod B) for (i := 1; i <= rounds; i++) begin damage := (item_w_damage + bonus_ranged) * dmg_mult; // item_w_damage_ (raw_damage) if dmg_div then damage /= dmg_div; damage := (((damage / 2) * difficulty) / 100) - dmg_thresh; if (damage > 0) then begin damage := damage - ((damage * dmg_resist) / 100); // reduce damage by the percentage of DR_armor + DR_Ammo if (damage > 0) then amount += damage; end end end // F2 default end if (ctdSource == dude_obj) then begin if has_trait(TRAIT_PERK, ctdSource, PERK_living_anatomy_perk) and (critter_kill_type(ctdTarget) != KILL_TYPE_robot_kills) and (critter_kill_type(ctdTarget) != KILL_TYPE_alien_kills) then amount += 5; if has_trait(TRAIT_PERK, ctdSource, PERK_pyromaniac_perk) and (dmg_type == DMG_fire) then amount += 5; end if knockback and ((get_flags(target) bwand FLAG_MULTIHEX) == 0) and (dmg_type == DMG_explosion or weapon == 0 or weapon_subtype == WEAPON_TYPE_MELEE) and ((get_proto_data(obj_pid(target), PROTO_CR_FLAGS) bwand CFLG_NOKNOCKDOWN) == 0) then begin // critter_flag_check_ damage := 0; if (target == dude_obj) and has_trait(TRAIT_PERK, target, PERK_stonewall_perk) then begin damage := 1; if (random(0, 100) < 50) then knockback := 0; end if knockback then begin if (weapon_perk == PERK_weapon_knockback) then amountKnockback := amount / 5; else amountKnockback := amount / 10; if damage then amountKnockback /= 2; end end end if (flagsSource bwand DAM_HIT) then begin display_msg("amountTarget = " + amountTarget+ ", amount = " + amount); amountTarget := amount; flagsTarget := flags; end else begin display_msg("amountSource = " + amountSource+ ", amount = " + amount); amountSource := amount; flagsSource := flags; end set_sfall_return(amountTarget); set_sfall_return(amountSource); set_sfall_return(flagsTarget); set_sfall_return(flagsSource); set_sfall_return(amountKnockback); end procedure item_w_damage_hook begin variable item_w_damage_min := get_sfall_arg, item_w_damage_max := get_sfall_arg; //weapon := get_sfall_arg, //source := get_sfall_arg, //hit_mode := get_sfall_arg, //isMelee := get_sfall_arg; item_w_damage := (item_w_damage_min + (item_w_damage_max - item_w_damage_min) / 2); display_msg("item_w_damage_ = " + item_w_damage); set_sfall_return(item_w_damage); end procedure item_w_subtype(variable weapon, variable hit_mode) begin variable attack_mode, type := WEAPON_TYPE_UNARMED; if weapon and (hit_mode <= ATKTYPE_RWEP2) then begin attack_mode := (get_proto_data(obj_pid(weapon), PROTO_IT_FLAGS)); if (hit_mode == ATKTYPE_LWEP2) or (hit_mode == ATKTYPE_RWEP2) then attack_mode := (attack_mode bwand 0xF0) / 16; // shift 4 bits to the right else attack_mode := (attack_mode bwand 0x0F); if (attack_mode > ATKMODE_PRI_THROW) then type := WEAPON_TYPE_GUNS; else if (attack_mode == ATKMODE_PRI_THROW) then type := WEAPON_TYPE_THROWN; else if (attack_mode > ATKMODE_PRI_KICK) then type := WEAPON_TYPE_MELEE; end return type; end procedure get_ammo_value(variable weapon, variable param) begin variable pid := -1, value := 0; // default DR value if weapon then begin pid := get_weapon_ammo_pid(weapon); if (pid > -1) then value := get_proto_data(pid, param); end if (pid == -1 and param != PROTO_AM_DR_MOD) then value := 1; // default value for Mult/Div return value; end