530 lines
16 KiB
Lua
530 lines
16 KiB
Lua
-- [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
|