-- [objectnum] = range local range_weapon_tbl = { [41] = 4, [42] = 5, [43] = 4, [44] = 9, [45] = 9, [46] = 9, [47] = 4, [48] = 5, [240] = 6, [241] = 6, [129] = 2, [261] = 2, [313] = 9, [40] = 6, [366] = 3, [386] = 4, [364] = 3, [384] = 2, } function get_weapon_range(weapon) local range = range_weapon_tbl[weapon.obj_n] if range == nil then range = 1 end return range end local weapon_dmg_tbl = { [16] = 30, --bloody saber [40] = 1, --Cupid's bow and arrows (charms) [41] = 15, --derringer [42] = 18, --revolver [43] = 20, --shotgun [44] = 30, --rifle [45] = 30, --Belgian combine [46] = 45, --elephant gun [47] = 8, --sling [48] = 12, --bow [49] = 15, --hatchet [50] = 20, --axe [51] = 10, --ball-peen hammer [52] = 25, --sledge hammer [54] = 10, --knife [55] = 20, --machete [56] = 25, --saber [65] = 15, --pick [66] = 8, --shovel [67] = 10, --hoe [68] = 10, --rake [69] = 15, --pitchfork [70] = 12, --cultivator [71] = 20, --scythe [72] = 10, --saw [102] = 12, --pry bar --[109] = 1, --torch --[110] = 1, --lit torch --[111] = 1, --candlestick --[112] = 1, --lit candle --[113] = 1, --candelabra --[114] = 1, --lit andelabra --[115] = 1, --oil lamp --[116] = 1, --lit oil lamp --[117] = 1, --lantern --[118] = 1, --lit lantern [129] = 60, --weed sprayer -- FIXME: no damage normally. Only effects plants? --[136] = 1, --tongs [241] = 20, --heat ray gun [242] = 10, --freeze ray gun --[243] = 1, --martian ritual pod knife [261] = 60, --spray gun -- FIXME: no damage normally. Only effects plants? [263] = 10, --martian hoe (couldn't be equipped in original) [264] = 20, --martian scythe (couldn't be equipped in original) [265] = 15, --martian pitchfork (couldn't be equipped in original) [266] = 10, --martian rake (couldn't be equipped in original) [267] = 8, --martian shovel (couldn't be equipped in original) [313] = 254, --M60 machine gun (scripted to only attack and kill the big bad) [327] = 15, --martian pick (couldn't be equipped in original) [401] = 12, --pool cue } function get_weapon_damage(weapon) local dmg if weapon.luatype == "actor" then dmg = actor_get_damage(weapon) else dmg = weapon_dmg_tbl[weapon.obj_n] end if dmg == nil then dmg = -1 end return dmg end function sub_1B432(attacker, target) end function actor_get_weapon(attacker, target) local int_test = false local selected_weapon = attacker if not actor_has_bad_alignment(attacker) then if math.random(1, 0x1e) <= actor_int_adj(attacker) then int_test = true end end local range = actor_get_combat_range(attacker, target.x, target.y) for obj in actor_inventory(actor) do if get_weapon_damage(obj) > 0 and get_weapon_range(obj) >= range then if (obj.obj_n ~= 129 and obj.obj_n ~= 261) --OBJ_WEED_SPRAYER, OBJ_SPRAY_GUN or (obj.quality ~= 0 and obj.invisible) or (obj.quality == 0 and (is_plant_obj(target) or (target.luatype=="actor" and (is_actor_stat_bit_set(target.obj_n, 7) and not is_actor_stat_bit_set(target.obj_n, 14))))) then local weapon_requires_int = false if obj.obj_n == 240 --OBJ_HEAT_RAY_GUN or obj.obj_n == 241 --OBJ_FREEZE_RAY_GUN or obj.obj_n == 45 then weapon_requires_int = true end --if int_test == true and weapon_requires_int == true or obj.obj_n == 43 and not sub_1B432(attacker, target) then --OBJ_SHOTGUN end end end end function attack_dex_saving_throw(attacker, defender, weapon) if defender == nil or defender.luatype == "obj" then return true end local attacker_value if weapon.luatype == "actor" and is_actor_stat_bit_set(weapon.obj_n, 5) then attacker_value = actor_str_adj(attacker) else attacker_value = actor_dex_adj(attacker) end local defender_value = actor_dex_adj(defender) if math.random(1, 30) >= math.floor((defender_value + 30 - attacker_value) / 2) then return true end return false end function out_of_ammo(attacker, weapon, print_message) -- untested function local weapon_obj_n = weapon.obj_n if ((weapon_obj_n == 41 or weapon_obj_n == 42) and Actor.inv_has_obj_n(attacker, 57) == false) --derringer, revolver, pistol rounds or (weapon_obj_n == 43 and Actor.inv_has_obj_n(attacker, 58) == false) --shotgun, shotgun shell or (weapon_obj_n == 44 and Actor.inv_has_obj_n(attacker, 59) == false) --rifle, rifle round or (weapon_obj_n == 45 and weapon.quality == 0 and (Actor.inv_has_obj_n(attacker, 58) == false or Actor.inv_has_obj_n(attacker, 59) == false)) --belgian combine (combine), shotgun shell, rifle round or (weapon_obj_n == 45 and weapon.quality == 1 and Actor.inv_has_obj_n(attacker, 59) == false) --belgian combine (rifle), rifle round or (weapon_obj_n == 45 and weapon.quality == 2 and Actor.inv_has_obj_n(attacker, 58) == false) --belgian combine (shotgun), shotgun shell or (weapon_obj_n == 46 and Actor.inv_has_obj_n(attacker, 60) == false) --elephant gun, elephant gun round or (weapon_obj_n == 47 and Actor.inv_has_obj_n(attacker, 63) == false) --sling, sling stone or ((weapon_obj_n == 240 or weapon_obj_n == 241 or weapon_obj_n == 129 or weapon_obj_n == 261) and weapon.qty == 0) then --heat ray gun, freeze ray gun, weed sprayer, spray gun if(print_message) then printl("OUT_OF_AMMUNITION") play_md_sfx(5) end return true end if weapon_obj_n == 48 and Actor.inv_has_obj_n(attacker, 64) == false then --bow, arrows if(print_message) then printl("OUT_OF_ARROWS") play_md_sfx(5) end return true end return false end function attack_with_freezeray(actor, target_actor, damage) if actor_tbl[target_actor.obj_n] ~= nil and (is_actor_stat_bit_set(target_actor.obj_n, 14) or is_actor_stat_bit_set(target_actor.obj_n, 7)) then target_actor.paralyzed = true printfl("ACTOR_PARALYZED", target_actor.name) if not is_actor_stat_bit_set(target_actor.obj_n, 7) or is_actor_stat_bit_set(target_actor.obj_n, 14) then hit_target(target_actor, BLUE_HIT_TILE) else actor_take_hit(actor, target_actor, damage, 1) end else printl("IT_HAS_NO_EFFECT") end end function check_ammo(actor, weapon) local obj_n = weapon.obj_n if obj_n == 47 and not Actor.inv_has_obj_n(actor, 63) then --OBJ_SLING, OBJ_SLING_STONE return 1 end if (obj_n == 41 or obj_n == 42) and not Actor.inv_has_obj_n(actor, 57) then --OBJ_DERRINGER, OBJ_REVOLVER, OBJ_PISTOL_ROUND return 1 end if obj_n == 46 and not Actor.inv_has_obj_n(actor, 60) then --OBJ_ELEPHANT_GUN, OBJ_ELEPHANT_GUN_ROUND return 1 end if obj_n == 44 and not Actor.inv_has_obj_n(actor, 59) then --OBJ_RIFLE, OBJ_RIFLE_ROUND return 1 end if obj_n == 43 and not Actor.inv_has_obj_n(actor, 58) then --OBJ_SHOTGUN, OBJ_SHOTGUN_SHELL return 1 end if (obj_n == 129 or obj_n == 261) and weapon.qty ~= 0 then --OBJ_WEED_SPRAYER, OBJ_SPRAY_GUN return 1 end return 0 end function attack_target_with_weapon(actor, target_x, target_y, weapon) local target_range = actor_get_combat_range(actor, target_x, target_y) local weapon_range = get_weapon_range(weapon) if target_range > weapon_range then return 2 --out of range end local ret = check_ammo(actor, weapon) if ret ~= 0 then return ret end local obj_n = weapon.obj_n local var_10 = 0 local var_12 = 0 --OBJ_HEAT_RAY_GUN --OBJ_FREEZE_RAY_GUN --OBJ_BELGIAN_COMBINE if obj_n == 240 or obj_n == 241 or obj_n == 45 then if weapon.quality < 2 then var_10= 1 end if weapon.quality ~= 1 then var_12 = 1 end if obj_n == 45 then --OBJ_BELGIAN_COMBINE if var_10 ~= 0 then if not Actor.inv_has_obj_n(actor, 59) then --OBJ_RIFLE_ROUND var_10 = 0 end end if var_12 ~= 0 then if not Actor.inv_has_obj_n(actor, 58) then --OBJ_SHOTGUN_SHELL var_12 = 0 end end else if weapon.qty == 0 then return 1 end if weapon.qty < (var_12 * 4) + var_10 then var_12 = 0 end end if var_10 == 0 and var_12 == 0 then return 1 end else if obj_n == 43 then --OBJ_SHOTGUN var_10 = 0 var_12 = 1 else var_10 = 1 var_12 = 0 end end local damage_mode = 0 if obj_n == 240 then --OBJ_HEAT_RAY_GUN damage_mode = 3 end if obj_n == 241 then --OBJ_FREEZE_RAY_GUN damage_mode = 1 end g_attack_target = g_selected_obj if var_10 == 0 then spread_weapon_damage(actor, target_x, target_y, weapon) return 0 end local is_ranged_attack = false if target_range > 1 then is_ranged_attack = true end if (obj_n >= 40 and obj_n <= 48) --OBJ_CUPIDS_BOW_AND_ARROWS, OBJ_BOW or obj_n == 129 --OBJ_WEED_SPRAYER or obj_n == 261 --OBJ_SPRAY_GUN or obj_n == 240 --OBJ_HEAT_RAY_GUN or obj_n == 241 --OBJ_FREEZE_RAY_GUN then is_ranged_attack = true end local damage if weapon.luatype == "actor" then damage = actor_get_damage(actor) if damage == nil then damage = 1 end else damage = get_weapon_damage(weapon) if damage < 0 then damage = 1 end end local does_damage local target = find_rockworm_actor(g_attack_target) if target ~= nil and target.luatype == "actor" and obj_n ~= 129 --OBJ_WEED_SPRAYER and obj_n ~= 261 then --OBJ_SPRAY_GUN does_damage = attack_dex_saving_throw(actor, target, weapon) end if is_ranged_attack then fire_range_based_weapon(actor, target_x, target_y, weapon) end target = find_rockworm_actor(g_attack_target) if not is_ranged_attack and map_is_on_screen(actor.xyz) then play_md_sfx(0) end if does_damage == nil then does_damage = true if target ~= nil and target.luatype == "actor" and obj_n ~= 129 --OBJ_WEED_SPRAYER and obj_n ~= 261 then --OBJ_SPRAY_GUN does_damage = attack_dex_saving_throw(actor, target, weapon) end end if not does_damage then play_md_sfx(3) end if does_damage and target ~= nil and (target.luatype == "obj" or target.actor_num ~= actor.actor_num) then if obj_n == 241 then --OBJ_FREEZE_RAY_GUN if target.obj_n == 160 and target.frame_n == 1 then printl("THE_WATER_FREEZES") target.frame_n = 2 else if target.luatype == "actor" then attack_with_freezeray(actor, target, damage) end end elseif obj_n == 129 or obj_n == 261 then --OBJ_WEED_SPRAYER, OBJ_SPRAY_GUN if weapon.quality ~= 0 then if target.luatype == "actor" and target.obj_n == 145 then --OBJ_MONSTER_FOOTPRINTS target.obj_n = 364 --OBJ_PROTO_MARTIAN printfl("BECOMES_VISIBLE", target.name) elseif target.luatype == "obj" and target.invisible then target.invisible = false printfl("BECOMES_VISIBLE", target.name) else printl("IT_HAS_NO_EFFECT") end else if actor_tbl[target.obj_n] ~= nil and not is_actor_stat_bit_set(target.obj_n, 14) and is_actor_stat_bit_set(target.obj_n, 7) then actor_take_hit(actor, target, damage, 2) else printl("IT_HAS_NO_EFFECT") end end elseif obj_n == 40 then --OBJ_CUPIDS_BOW_AND_ARROWS if target.luatype == "actor" and target.align ~= ALIGNMENT_GOOD then target.old_align = target.align target.align = ALIGNMENT_GOOD target.charmed = true printfl("ACTOR_CHARMED", target.name) end else actor_take_hit(actor, target, damage, damage_mode) end end if var_12 ~= 0 then spread_weapon_damage(actor, target_x, target_y, weapon) end return 0 end local spread_weapon_sfx_tbl = { [0x2b]=8, [0x2d]=8, [0xf0]=0xa, [0xf1]=0xa, } local spread_weapon_tile_num_tbl = { [0x2b]=0x106, [0x2d]=0x106, [0xf0]=0x14e, [0xf1]=0x14f, } local spread_weapon_damage_tbl = { [0x2b]=0x14, [0x2d]=0x14, [0xf0]=0x19, [0xf1]=0xa, } function spread_weapon_damage(actor, target_x, target_y, weapon) if spread_weapon_sfx_tbl[weapon.obj_n] ~= nil then play_md_sfx(spread_weapon_sfx_tbl[weapon.obj_n]) end --FIXME spread weapon anim here. local hit_items = projectile_anim_multi (spread_weapon_tile_num_tbl[weapon.obj_n], actor.x, actor.y, {{x=target_x, y=target_y, z=actor.z}, {x=target_x+1, y=target_y-1, z=actor.z}}, 2, 1, 0) local k, v for k,v in pairs(hit_items) do if weapon.obj_n == 241 then --OBJ_FREEZE_RAY_GUN if v.obj_n == 160 and v.frame_n == 1 then --OBJ_EMPTY_BUCKET printl("THE_WATER_FREEZES") v.frame_n = 2 elseif v.luatype == "actor" then if math.random(1, 0x2d) > actor_dex_adj(v) then attack_with_freezeray(actor, v, 10) else printfl("ACTOR_DODGES", v.name) play_md_sfx(3) end end elseif v.luatype == "obj" or math.random(1, 0x2d) > actor_dex_adj(v) then local dmg_mode = 0 if weapon.obj_n == 240 then --OBJ_HEAT_RAY_GUN dmg_mode = 3 end actor_take_hit(actor, v, spread_weapon_damage_tbl[weapon.obj_n], dmg_mode) else printfl("ACTOR_DODGES", v.name) play_md_sfx(3) end end if weapon.obj_n == 43 or weapon.obj_n == 45 then --OBJ_SHOTGUN, OBJ_BELGIAN_COMBINE Actor.inv_remove_obj_qty(actor, 58, 1) --OBJ_SHOTGUN_SHELL else weapon.qty = weapon.qty - 4 if weapon.qty < 0 then weapon.qty = 0 end end end local projectile_tbl = { [41]={tile_num=0x103, sfx_id=7, ammo_obj_n=57}, [42]={tile_num=0x103, sfx_id=7, ammo_obj_n=57}, [44]={tile_num=0x103, sfx_id=8, ammo_obj_n=59}, [45]={tile_num=0x103, sfx_id=8, ammo_obj_n=59}, [46]={tile_num=0x103, sfx_id=8, ammo_obj_n=60}, [47]={tile_num=0x23E, sfx_id=6, ammo_obj_n=63}, [48]={tile_num=0x23F, sfx_id=6, ammo_obj_n=64}, [40]={tile_num=0x23F, sfx_id=6, ammo_obj_n=-3}, [240]={tile_num=0x16B, sfx_id=10, ammo_obj_n=-2}, [241]={tile_num=0x16A, sfx_id=10, ammo_obj_n=-2}, [129]={tile_num=0x10A, sfx_id=6, ammo_obj_n=-2}, [261]={tile_num=0x10A, sfx_id=6, ammo_obj_n=-2}, [313]={tile_num=0x10B, sfx_id=50, ammo_obj_n=-3}, [366]={tile_num=0x16F, sfx_id=34, ammo_obj_n=-3}, [386]={tile_num=0x16C, sfx_id=34, ammo_obj_n=-3}, [364]={tile_num=0x16D, sfx_id=6, ammo_obj_n=-3}, [384]={tile_num=0x16E, sfx_id=6, ammo_obj_n=-3}, } function fire_range_based_weapon(attacker, target_x, target_y, weapon) local projectile_info = projectile_tbl[weapon.obj_n] if projectile_info == nil then projectile_info = {tile_num=weapon.tile_num, sfx_id=0, ammo_obj_n=-1 } end play_md_sfx(projectile_info.sfx_id) projectile_anim(projectile_info.tile_num, attacker.x, attacker.y, target_x, target_y, 4, false, 0) if projectile_info.ammo_obj_n > 0 then Actor.inv_remove_obj_qty(attacker, projectile_info.ammo_obj_n, 1) elseif projectile_info.ammo_obj_n == -2 then weapon.qty = weapon.qty - 1 elseif projectile_info.ammo_obj_n == -1 and actor_get_combat_range(attacker, target_x, target_y) > 1 then if is_open_water_at_loc(target_x, target_y, attacker.z) then Obj.removeFromEngine(weapon) else Obj.moveToMap(weapon, target_x, target_y, attacker.z) end --FIXME original updated readied weapons here. We might also need to do that. end end