Files
scummvm/devtools/create_ultima/files/ultima6/scripts/md/actor.lua
T

1686 lines
50 KiB
Lua

--io.stderr:write("actor.lua get here\n")
--Worktypes
WT_NOTHING = 0x0 --do nothing
WT_FOLLOW = 0x1 --follow avatar (in party)
WT_PLAYER = 0x2 --player mode
WT_SLEEP = 0x91
ACTOR_STAT_DMG = 7
--Actor stats table
--[obj_num] = {str,dex,int,hp,alignment,,damage??,,,,,,,,,,,,,,,,}
actor_tbl = {
--OBJ_YOURSELF5
[343] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_YOURSELF6
[344] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_POOR_MONK
[342] = {22,22,22,60,ALIGNMENT_EVIL,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_SCIENTIST
[345] = {15,15,25,30,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_YOUNG_WOMAN
[346] = {18,18,22,60,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_COWBOY
[347] = {20,25,18,60,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_GENTLEMAN
[348] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_UNIFORMED_MAN
[349] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_ADVENTURER
[350] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_COMMON_FELLOW
[351] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_MAN
[352] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_MAN_IN_WHITE
[353] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_LADY
[354] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_WOMAN
[355] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_ADVENTURESS
[356] = {25,25,25,90,ALIGNMENT_GOOD,0,6,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_METAL_WOMAN1
[357] = {25,25,25,90,ALIGNMENT_GOOD,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_MECHANICAL_MAN
[358] = {25,15,10,40,ALIGNMENT_GOOD,4,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_MARTIAN
[369] = {15,15,20,30,ALIGNMENT_NEUTRAL,0,6,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_SEXTELLEGER
[359] = {20,20,10,45,ALIGNMENT_CHAOTIC,4,35,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_BUSHALO
[360] = {25,12,11,35,ALIGNMENT_NEUTRAL,8,20,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0},
--OBJ_PLANTELLOPE
[361] = {15,22,9,20,ALIGNMENT_NEUTRAL,1,12,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_ROCKWORM2
[372] = {20,15,10,40,ALIGNMENT_CHAOTIC,8,25,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_WISP
[377] = {20,20,20,80,ALIGNMENT_NEUTRAL,3,30,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0},
--OBJ_AIRSQUID
[378] = {10,20,15,10,ALIGNMENT_EVIL,0,6,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0},
--OBJ_AIRSQUID1
[380] = {15,15,8,30,ALIGNMENT_EVIL,4,20,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_GIANT_MAW
[373] = {30,10,9,100,ALIGNMENT_CHAOTIC,3,30,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_TENTACLE1
[362] = {20,20,9,10,ALIGNMENT_CHAOTIC,2,20,1,1,1,0,0,0,0,0,1,0,1,0,0,0,0,0},
--OBJ_CREEPING_CACTUS
[383] = {20,12,3,30,ALIGNMENT_CHAOTIC,4,25,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_AMMONOID
[363] = {15,15,3,20,ALIGNMENT_CHAOTIC,10,12,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_PROTO_MARTIAN
[364] = {20,19,10,20,ALIGNMENT_EVIL,2,10,0,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0},
--OBJ_MONSTER_FOOTPRINTS
[145] = {20,19,10,20,ALIGNMENT_EVIL,2,12,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0},
--OBJ_POD_DEVIL
[384] = {15,18,3,25,ALIGNMENT_CHAOTIC,4,12,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_JUMPING_BEAN
[385] = {10,22,10,10,ALIGNMENT_CHAOTIC,1,4,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_HEDGEHOG
[365] = {17,12,8,20,ALIGNMENT_CHAOTIC,3,20,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_CREEPER
[374] = {15,15,3,20,ALIGNMENT_CHAOTIC,1,16,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_AGROBOT
[376] = {29,18,10,30,ALIGNMENT_CHAOTIC,10,20,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
--OBJ_CANAL_WORM
[379] = {20,20,15,30,ALIGNMENT_CHAOTIC,5,25,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0},
--OBJ_DUST_DEVIL
[381] = {30,30,30,255,ALIGNMENT_NEUTRAL,99,60,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
--OBJ_SAND_TRAPPER
[386] = {25,25,10,40,ALIGNMENT_CHAOTIC,4,18,1,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0},
--OBJ_OXY_LEECH
[375] = {10,25,12,20,ALIGNMENT_CHAOTIC,1,10,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_CAVE_WORM
[366] = {15,15,15,30,ALIGNMENT_EVIL,2,15,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_JANITOR
[367] = {20,15,10,30,ALIGNMENT_CHAOTIC,10,20,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0},
--OBJ_BUSHRAT
[387] = {10,25,10,20,ALIGNMENT_EVIL,2,12,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_PLANTHER
[368] = {15,22,12,20,ALIGNMENT_CHAOTIC,4,20,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_MINOTAUR
[398] = {20,18,8,90,ALIGNMENT_NEUTRAL,2,15,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0},
--OBJ_YOUR_MOTHER
[391] = {12,20,15,255,ALIGNMENT_CHAOTIC,9,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0},
--OBJ_TREE
[408] = {25,18,5,90,ALIGNMENT_NEUTRAL,3,12,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_SOMETHING_YOU_SHOULDNT2
[424] = {25,18,5,90,ALIGNMENT_NEUTRAL,3,12,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0},
--OBJ_HUGE_RED_SPOT
[403] = {20,20,10,255,ALIGNMENT_EVIL,99,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
}
function is_actor_stat_bit_set(obj_n, bit_number)
local stats = actor_tbl[obj_n]
if stats ~= nil then
if stats[23 - bit_number] == 1 then
return true
end
end
return false
end
g_party_is_warm = false
-- Berry logic
function actor_is_affected_by_purple_berries(actor_num)
if actor_num < 16 and timer_get(actor_num*3) > 0 then
return true
end
return false
end
function actor_is_affected_by_green_berries(actor_num)
if actor_num < 16 and timer_get(actor_num*3+1) > 0 then
return true
end
return false
end
function actor_is_affected_by_brown_berries(actor_num)
if actor_num < 16 and timer_get(actor_num*3+2) > 0 then
return true
end
return false
end
function actor_get_purple_berry_count(actor_num)
if actor_num < 16 then
return timer_get(actor_num*3)
end
return 0
end
function actor_get_green_berry_count(actor_num)
if actor_num < 16 then
return timer_get(actor_num*3+1)
end
return 0
end
function actor_get_brown_berry_count(actor_num)
if actor_num < 16 then
return timer_get(actor_num*3+2)
end
return 0
end
function actor_decrement_berry_counter(actor, berry_type)
local actor_num = actor.actor_num
local count = timer_get(actor_num*3+berry_type)
if count > 0 and math.random(1, actor_int_adj(actor) * 4) == 1 then
timer_set(actor_num*3+berry_type, count - 1)
if (actor_num == 0 and g_in_dream_mode) or
(actor_num ~= 0 and g_in_dream_mode == false) then
play_md_sfx(0x32)
printl("A_PSYCHIC_POWER_FADES")
end
end
end
function actor_decrement_berry_counters(actor)
actor_decrement_berry_counter(actor, 0) --purple
actor_decrement_berry_counter(actor, 1) --green
actor_decrement_berry_counter(actor, 2) --brown
end
function actor_increment_berry_counter(actor_num, berry_type)
local count = timer_get(actor_num*3+berry_type)
if actor_num < 16 and count < 10 then
timer_set(actor_num*3+berry_type, count + 1)
end
end
function actor_increment_purple_berry_count(actor_num)
actor_increment_berry_counter(actor_num, 0)
end
function actor_increment_green_berry_count(actor_num)
actor_increment_berry_counter(actor_num, 1)
end
function actor_increment_brown_berry_count(actor_num)
actor_increment_berry_counter(actor_num, 2)
end
function actor_get_blue_berry_counter()
return timer_get(16*3)
end
function actor_set_blue_berry_counter(new_value)
timer_set(16*3, new_value)
end
function actor_clear_berry_counters(actor_num)
timer_set(actor_num*3, 0)
timer_set(actor_num*3+1, 0)
timer_set(actor_num*3+2, 0)
end
function actor_get_damage(actor)
local stat = actor_tbl[actor]
if stat ~= nil then
return stat[ACTOR_STAT_DMG]
end
return nil
end
--
-- actor_init(actor)
--
function actor_init(actor, alignment)
local actor_base = actor_tbl[actor.obj_n]
if actor_base ~= nil then
actor.str = actor_randomise_stat(actor_base[1])
actor.dex = actor_randomise_stat(actor_base[2])
actor.int = actor_randomise_stat(actor_base[3])
actor.hp = actor_randomise_stat(actor_base[4])
actor.level = 0
actor.align = actor_base[5]
else
actor.str = 15
actor.dex = 15
actor.int = 15
actor.hp = 30
actor.level = 1
actor.align = ALIGNMENT_CHAOTIC
end
if alignment ~= nil and alignment ~= ALIGNMENT_DEFAULT then
actor.align = alignment
end
actor.wt = 8
actor.combat_mode = 8
actor.mpts = actor.dex
actor.exp = 0
end
function subtract_map_movement_pts(actor)
local points = map_get_impedence(actor.x, actor.y, actor.z, false) + 5
subtract_movement_pts(actor, points)
end
function actor_divide(actor)
local random = math.random
local from_x, from_y, from_z = actor.x, actor.y, actor.z
for i=1,8 do
local new_x = wrap_coord(random(1, 2) + from_x - 1, from_z)
local new_y = wrap_coord(random(1, 2) + from_y - 1, from_z)
if map_can_put(new_x, new_y, from_z) then
--FIXME need to call sub_2C657 which I think updates the existing actor
Actor.clone(actor, new_x, new_y, from_z)
printfl("ACTOR_DIVIDES", actor.name)
return
end
end
end
function defender_update_alignment(attacker, defender, damage)
if defender.luatype ~= "actor" then
return
end
if defender.align == ALIGNMENT_NEUTRAL and defender.in_party == false and (defender.wt <= 0x10 or defender.wt >= 0x80) then
if attacker.wt == WT_PLAYER and is_actor_stat_bit_set(defender.obj_n, 14) and damage > 0 then
printfl("ACTOR_ATTACKS", defender.name)
end
if defender.actor_num >= 0xc0 or defender.wt < 0x80 then
if attacker.align == ALIGNMENT_GOOD and defender.align ~= ALIGNMENT_EVIL and defender.wt ~= ALIGNMENT_CHAOTIC then
defender.align = ALIGNMENT_EVIL
end
if defender.wt >= 0xc0 then
defender.wt = 8
end
else
if attacker.wt == WT_PLAYER then
defender.wt = 0xa0
end
end
end
end
function canal_worm_eat_body(worm_actor)
--FIXME
--only eat if a body was created when the actor was killed.
end
function actor_handle_damage(defender)
if defender.obj_n == 370 or defender.hp == 0 then --OBJ_ROCKWORM_BASE
return
end
local hp_level = math.floor(((defender.hp * 4) / defender.max_hp))
if hp_level == 0 then
printfl("ACTOR_CRITICAL", defender.name)
--FIXME giant_maw check
local wt = defender.wt
if wt == 0xd then
defender.wt = 0x11
--FIXME if actor qaul ~= 0 then set actor.get(qual).wt = 0x11
elseif wt ~= 6 and wt ~= 0xe and wt ~= 2 and wt ~= 1 and wt ~= 0 and wt ~= 0x11 and wt ~= 0x19
and ( is_actor_stat_bit_set(defender.obj_n, 7) or is_actor_stat_bit_set(defender.obj_n, 14) ) then
if actor_int_adj(defender) >= 5 and defender.obj_n ~= 145 then --OBJ_MONSTER_FOOTPRINTS
defender.wt = 7
end
end
elseif hp_level < 4 then
local suffix
if is_actor_stat_bit_set(defender.obj_n, 14) and is_actor_stat_bit_set(defender.obj_n, 7) then
suffix = i18n("DAMAGED")
else
suffix = i18n("WOUNDED")
end
local damage_type
if hp_level == 1 then
damage_type = i18n("HEAVILY")
elseif hp_level == 2 then
damage_type = i18n("LIGHTLY")
elseif hp_level == 3 then
damage_type = i18n("BARELY")
end
printfl("ACTOR_HIT_MESSAGE", defender.name, damage_type, suffix)
end
end
function actor_take_hit(attacker, defender, max_dmg, damage_mode)
if max_dmg == -1 then
max_dmg = 1
elseif max_dmg > 1 and max_dmg < 255 then
max_dmg = math.random(1, max_dmg)
end
local armour_value = 0
if damage_mode ~= 2 then
if defender.luatype == "actor" then
armour_value = actor_get_ac(defender)
elseif defender.obj_n == 388 and defender.frame_n == 0 then --OBJ_GLOW_WORM
armour_value = 2
end
end
if armour_value > 0 and max_dmg < 255 then
max_dmg = max_dmg - math.random(1, armour_value)
end
if max_dmg > 0 then
if (attacker.align == ALIGNMENT_EVIL or attacker.align == ALIGNMENT_CHAOTIC)
and defender.luatype == "actor" and defender.in_party
and party_is_in_combat_mode() == false
and player_is_in_solo_mode() == false then
party_set_combat_mode(true)
end
attacker.exp = attacker.exp + actor_hit(defender, max_dmg, damage_mode)
else
--FIXME call either sub_19088 or sub_18F7D
printfl("ACTOR_GRAZED", defender.name)
end
if defender.luatype == "actor" then
--FIXME only call if defender == selected obj
defender_update_alignment(attacker, defender, max_dmg)
if defender.hp == 0 then
if attacker.obj_n == 379 then --OBJ_CANAL_WORM
canal_worm_eat_body(attacker)
end
else
if is_actor_stat_bit_set(attacker.obj_n, 2) and math.random(0, 3) == 0 and actor_immune_to_dmg(defender) == false then
printfl("ACTOR_PARALYZED", defender.name)
defender.paralyzed = true
end
if defender.alive and max_dmg > 0 then
actor_handle_damage(defender)
end
end
end
end
function actor_immune_to_dmg(actor)
local actor_num = actor.actor_num
local obj_n = actor.obj_n
if obj_n == 381 or obj_n == 390 or obj_n == 391 or obj_n == 358 or obj_n == 382 then
return true
end
if actor_num == 0x5c or actor_num == 0x5d or actor_num == 0x59 or actor_num == 0x5a or actor_num == 0x54 or actor_num == 0x52
or actor_num == 0x6d or actor_num == 0x68 or actor_num == 0x67 or actor_num == 0x69 or actor_num == 0x77 or actor_num == 0x78
or actor_num == 0x40 or actor_num == 0x3c then
return true
end
return false
end
function actor_print_custom_hit_message(actor)
local actor_num = actor.actor_num
if actor_num == 0x69 then
printfl("ACTOR_CRITICAL", Actor.get(0x19).name)
elseif actor_num == 0x3c then
printfl("ACTOR_CRITICAL", actor.name)
elseif actor_num == 0x52 then
printfl("ACTOR_HIT_MESSAGE", actor.name, i18n("HEAVILY"), i18n("WOUNDED"))
elseif actor_num == 0x68 then
if Actor.get_talk_flag(actor, 2) then
printfl("ACTOR_CRITICAL", actor.name)
else
printfl("ACTOR_HIT_MESSAGE", actor.name, i18n("HEAVILY"), i18n("WOUNDED"))
end
Actor.set_talk_flag(actor, 5)
Actor.talk(actor)
else
printl("IT_HAS_NO_EFFECT")
end
end
local RED_HIT_TILE = 257
local BLUE_HIT_TILE = 258
function hit_target(target, hit_tile)
if map_is_on_screen(target.xyz) then
if target.luatype == "actor" and target.in_party then
play_md_sfx(1, PLAY_ASYNC)
else
play_md_sfx(2, PLAY_ASYNC)
end
hit_anim(target.x, target.y) --FIXME need to apply hit colour tile param here.
end
if target.luatype == "actor" then
--FIXME
-- les bx, objlist_unk_1af1_ptr
-- mov al, es:[bx+si]
-- or al, 8
-- mov es:[bx+si], al
if target.asleep then
target.asleep = false
end
end
end
-- Hit an actor or object
function actor_hit(defender, max_dmg, damage_mode)
local defender_obj_n = defender.obj_n
local exp_gained = 0
local player_loc = player_get_location()
if defender.z ~= player_loc.z or max_dmg < 0 then
return 0
end
if defender.luatype == "actor" then
print("actor_hit("..defender.actor_num..")\n")
if defender.actor_num == 0 and defender.hp <= max_dmg and g_current_dream_stage == 0xe0 then
max_dmg = defender.hp - 1
end
if damage_mode == 1 then
hit_target(defender, BLUE_HIT_TILE)
else
hit_target(defender, RED_HIT_TILE)
end
if actor_immune_to_dmg(defender) then
actor_print_custom_hit_message(defender)
defender.hp = 0xff
if defender_obj_n == 391 then --OBJ_YOUR_MOTHER
local gender_title = ""
if player_get_gender() == 0 then
gender_title = i18n("MAN")
else
gender_title = i18n("WOMAN")
end
printfl("HOW_DARE_YOU_YOUNG_PERSON", gender_title)
actor_take_hit(defender, Actor.get(0), 45, 0)
actor_take_hit(defender, Actor.get(0), 45, 0)
actor_take_hit(defender, Actor.get(0), 45, 0)
elseif defender.actor_num == 0x6d or defender.actor_num == 0x67 then
Actor.set_talk_flag(Actor.get(0x6b), 3)
local dream_actor = Actor.get(0)
Actor.move(dream_actor, g_prev_player_x, g_prev_player_y, dream_actor.z)
elseif defender.actor_num == 0x40 then --Rasputin
--FIXME attack_rasputin()
end
else
if damage_mode == 3 and is_actor_stat_bit_set(defender_obj_n, 3) then
printl("IT_HAS_NO_EFFECT")
return 0
end
if is_actor_stat_bit_set(defender_obj_n, 4) then
max_dmg = max_dmg * 2
end
if (damage_mode == 0 and actor_num ~= 0) or g_current_dream_stage ~= 0xe0 then --or word_41184 ~= 0xe0
if math.random(6, 0x64) <= max_dmg then
--FIXME actor_add_blood()
end
local hp = defender.hp
if hp <= max_dmg then
--FIXME exp_gained = kill_actor()
else
defender.hp = hp - max_dmg
if defender.wt == 9 or defender.wt == 11 then
defender.wt = 8
elseif defender.wt == 10 or defender.wt == 12 then
defender.wt = 0x1b
end
if is_actor_stat_bit_set(defender_obj_n, 6) then
actor_divide(defender)
end
end
end
end
else
actor_hit_obj(defender, max_dmg, damage_mode)
end
return exp_gained
end
function attack_bucket(bucket, damage_mode)
if damage_mode == 3 and bucket.frame_n == 2 then
printl("THE_ICE_THAWS")
bucket.frame_n = 1
elseif damage_mode == 1 and bucket.frame_n == 1 then
printl("THE_WATER_FREEZES")
bucket.frame_n = 2
end
end
function actor_hit_obj(obj, dmg, damage_mode)
if obj.qty == 0 or not is_obj_attackable(obj) then
if obj.obj_n == 160 then --OBJ_BUCKET
attack_bucket(obj, damage_mode)
end
return
end
if damage_mode == 0 or damage_mode == 3 or is_plant_obj(obj) then
if damage_mode == 1 then
hit_target(obj, BLUE_HIT_TILE)
else
hit_target(obj, RED_HIT_TILE)
end
if damage_mode == 3 and is_obj_burnable(obj) then
dmg = obj.qty
end
if obj.qty <= dmg then
if obj.obj_n == 217 then --OBJ_GLASS_PITCHER
play_md_sfx(0x1a)
obj.obj_n = 218 --OBJ_BROKEN_CRYSTAL
obj.frame_n = 0
if g_in_dream_mode and g_current_dream_stage == 0x44 then
local pitcher
for tmp_obj in find_obj_from_area(0x21, 0x33, 2, 0x1c, 0x10) do
if tmp_obj.obj_n == 217 then --OBJ_GLASS_PITCHER
pitcher = tmp_obj
end
end
if pitcher == nil then
Actor.set_talk_flag(0x54, 6)
end
end
else
play_md_sfx(0)
Obj.removeFromEngine(obj)
end
else
if obj.obj_n == 307 then --OBJ_DEVIL_POD
printl("THE_POD_SPLITS_OPEN")
local pod_devil = Actor.new(384, obj.x, obj.y, obj.z)
actor_init(pod_devil)
Actor.move(pod_devil, obj.x, obj.y, obj.z)
Obj.removeFromEngine(obj)
else
if obj.obj_n == 388 then --OBJ_GLOW_WORM
obj.frame_n = 0
obj.quality = math.random(0xb, 0x12)
play_md_sfx(0x22)
end
obj.qty = obj.qty - dmg
end
end
end
end
function actor_move(actor, direction, flag)
----dgb("actor_move("..actor.name..", "..direction_string(direction)..", "..flag..") actor("..actor.x..","..actor.y..")\n");
local x,y,z = actor.x, actor.y, actor.z
if direction == DIR_NORTH then y = y - 1 end
if direction == DIR_SOUTH then y = y + 1 end
if direction == DIR_EAST then x = x + 1 end
if direction == DIR_WEST then x = x - 1 end
if actor.obj_n ~= 382 then --COKER FIXME need to have an update frame function here.
actor.direction = direction
end
local did_move = Actor.move(actor, x, y, z)
--FIXME need more logic here.
--footprints, bots etc.
if did_move then
subtract_map_movement_pts(actor)
----dgb("actor_move() did move actor("..actor.x..","..actor.y..")\n");
end
return did_move
end
function actor_move_diagonal(actor, x_direction, y_direction)
local x,y,z = actor.x, actor.y, actor.z
local direction
if y_direction == DIR_NORTH then
y = y - 1
direction = x_direction == DIR_EAST and DIR_NORTHEAST or DIR_NORTHWEST
end
if y_direction == DIR_SOUTH then
y = y + 1
direction = x_direction == DIR_EAST and DIR_SOUTHEAST or DIR_SOUTHWEST
end
if x_direction == DIR_EAST then
x = x + 1
direction = y_direction == DIR_NORTH and DIR_NORTHEAST or DIR_SOUTHEAST
end
if x_direction == DIR_WEST then
x = x - 1
direction = y_direction == DIR_NORTH and DIR_NORTHWEST or DIR_SOUTHWEST
end
----dgb("actor_move_diagonal("..actor.name..", "..direction_string(direction)..")\n");
actor.direction = y_direction
local did_move = Actor.move(actor, x, y, z)
if did_move then
subtract_map_movement_pts(actor)
end
return did_move and 1 or 0
end
function actor_update_frame(actor, direction)
local obj_n = actor.obj_n
--actor.direction = direction
if obj_n >= 342 or obj_n <= 358 then --human actors
--print("actor: "..actor.actor_num.."("..actor.x..","..actor.y..","..actor.z..")")
for obj in objs_at_loc(actor.x, actor.y, actor.z) do
if obj ~= nil then
local tmp_obj_n = obj.obj_n
--print("actor:"..actor.actor_num.." obj: " .. tmp_obj_n)
if tmp_obj_n == 406 or (tmp_obj_n == 407) or tmp_obj_n == 216 or tmp_obj_n == 289 then
--sit here
if tmp_obj_n == 406 then -- OBJ_BENCH
actor.frame_n = 3
elseif tmp_obj_n == 407 then -- OBJ_COUCH
actor.frame_n = 4 + 3
elseif tmp_obj_n == 289 then -- OBJ_DREAM_MACHINE2
actor.frame_n = 8 + 3
else
actor.frame_n = math.floor(direction/2) * 4 + 3
end
return
end
end
end
--standing
end
end
function revive_avatar()
if g_in_dream_mode == true then
--FIXME died in dream world. old_player_x == 0
--FIXME respawn into dreamworld
else
-- normal avatar death
avatar_falls_unconscious()
end
end
function actor_resurrect(actor)
--FIXME do we need to do anything here?
end
function avatar_falls_unconscious()
printl("OVERCOME_BY_YOUR_WOUNDS_YOU_FALL_UNCONSCIOUS")
fade_out()
local input
while input == nil do
--canvas_update()
input = input_poll()
if input ~= nil then
break
end
end
local location
local target
if Actor.get_talk_flag(0x46, 3) then
location = i18n("THE_OLYMPUS_MINE")
target={x=0xa4,y=0xc3,z=4}
else
location = i18n("THE_SPACE_CAPSULE")
target={x=0x19d,y=0x278,z=0}
end
printfl("YOU_AWAKEN_BACK_AT_FEELING_RESTORED", location)
input_select(nil, true)
party_resurrect_dead_members()
for actor in party_members() do
actor.hp = actor.max_hp
actor.mpts = actor_dex_adj(actor)
end
party_move(target)
local hour = clock_get_hour()
local minutes = clock_get_minute()
minutes = 60 - minutes
if hour < 7 then
hour = 6 - hour
else
hour = 24 - (hour + 1) + 7
end
clock_inc(hour * 60 + minutes + math.random(0,59)) --advance time to between 7am and 8am on the next day
update_watch_tile()
advance_time(0)
party_update_leader()
party_set_combat_mode(false)
party_set_party_mode()
local blood = Actor.get(0x12)
if blood.alive then
Actor.set_talk_flag(blood, 5)
Actor.talk(blood)
end
fade_in()
end
function party_update()
local avatar = Actor.get(1)
if avatar.hp == 0 or (g_in_dream_mode == true and Actor.get(0).alive == false) then
if g_in_dream_mode == true then
g_objlist_1d22_unk = 0
if g_prev_player_x == 0 then
printl("YOU_SHAKE_YOURSELF_AWAKE_FROM_THE_NIGHTMARE")
wake_from_dream()
else
local avatar = Actor.get(1)
local dream_actor = Actor.get(0)
dream_actor.hp = avatar.max_hp
dream_actor.poisoned = false
Actor.move(dream_actor, g_prev_player_x, g_prev_player_y, dream_actor.z)
party_set_combat_mode(false)
printl("YOU_FEEL_YOUR_DREAM_CONSCIOUSNESS_RETURNING")
if g_current_dream_stage == 0xc0 then
if not Actor.get_talk_flag(0x66, 2)
and Actor.get_talk_flag(0x66, 3)
and Actor.get_talk_flag(0x66, 4)
and not Actor.get_talk_flag(0x66, 5)
then
for i=0,0xff do
local maw = Actor.get(i)
if maw.obj_n == 373 and maw.wt == 0x12 and maw.x == 0x87 and maw.y == 0x17 then
Actor.kill(maw, false)
end
end
if map_get_obj(0x7f, 0x18, dream_actor.z, 224) == nil then --OBJ_BRIDGE
local bridge = Obj.new(224, 3)
Obj.moveToMap(bridge, 0x7f, 0x18, dream_actor.z)
end
end
Actor.set_talk_flag(0x66, 7)
local raxachk = Actor.get(0x66)
Actor.talk(raxachk)
end
end
else
revive_avatar()
end
end
end
function actor_update_all()
party_update()
--pathfinding here.
local actor
local selected_actor
repeat
selected_actor = nil
local di = 0
local dex_6 = 1
repeat
local player_loc = player_get_location()
local var_C = (player_loc.x - 16) - (player_loc.x - 16) % 8
local var_A = (player_loc.y - 16) - (player_loc.y - 16) % 8
for actor in party_members() do
if actor.wt == WT_FOLLOW and actor.mpts < 0 then
actor.mpts = 0
end
end
local player_z = player_loc.z
for i=0,0xff do
local actor = Actor.get(i)
--FIXME need to check 11000b not zero on obj_flags
if actor.obj_n ~= 0 and actor.z == player_z and actor.mpts > 0 and actor.paralyzed == false and (actor.asleep == false or actor.wt == 0x80) and actor.wt ~= WT_NOTHING and actor.alive == true then
--FIXME need to check map wrapping here.
if abs(actor.x - var_C) > 0x27 or abs(actor.y - var_A) > 0x27 then
if actor.wt >= 0x83 and actor.wt <= 0x86 then
--move actor to schedule location if it isn't on screen
local sched_loc = actor.sched_loc
if map_is_on_screen(sched_loc.x, sched_loc.y, sched_loc.z) == false then
Actor.move(actor, sched_loc.x, sched_loc.y, sched_loc.z)
actor_wt_walk_to_location(actor) --this will cancel the pathfinder and set the new worktype
subtract_movement_pts(actor, 10)
----dgb("\nActor SCHEDULE TELEPORT "..actor.actor_num.." to ("..sched_loc.x..","..sched_loc.y..","..sched_loc.z..")\n")
end
end
else
if actor.wt ~= WT_FOLLOW then
if actor.wt == 0x80 then
-- actor_set_worktype_from_schedule(actor)
actor.wt = actor.sched_wt
end
local dex_adjusted = actor_dex_adj(actor)
local dx = (actor.mpts * dex_6) - dex_adjusted * di
if actor.mpts >= dex_adjusted or dx > 0 or dx == 0 and dex_adjusted > dex_6 then
selected_actor = actor
di = actor.mpts
dex_6 = dex_adjusted
end
if dex_adjusted <= actor.mpts then
break
end
end
end
end
end
if di <= 0 then
for i=0,0xff do
local actor = Actor.get(i)
local dex_adjusted = actor_dex_adj(actor)
if actor.mpts >= 0 then
actor.mpts = dex_adjusted
else
actor.mpts = actor.mpts + dex_adjusted
end
end
advance_time(1)
end
until di > 0
if selected_actor.wt ~= WT_PLAYER and selected_actor.wt ~= WT_FOLLOW then
--print("perform_worktype("..selected_actor.name.."("..selected_actor.actor_num..") dex = "..selected_actor.dex.." mpts = "..selected_actor.mpts..").\n")
perform_worktype(selected_actor)
party_update()
if selected_actor.wt > 1 and selected_actor.wt < 0x1b then
--FIXME targetting?? do *(&bjlist_unk_19f1_ptr + actor_num) = actor_num
end
end
until selected_actor.obj_n ~= 0 and selected_actor.wt == WT_PLAYER
if selected_actor ~= nil then --swap player to next party member with 'command' combat worktype.
local old_player = Actor.get_player_actor()
player_set_actor(selected_actor)
old_player.wt = WT_PLAYER --reset worktype to player as it gets changed to follow in Player::set_actor() :-(
end
display_prompt(true)
end
local projectile_weapon_tbl = --FIXME weed sprayer and spray gun
{
--obj_n = {tile_num, initial_tile_rotation, speed, rotation_amount} --FIXME: all untested
[40] = {575, 90,4, 0}, -- Cupid's bow and arrows
[41] = {259, 90,4, 0}, -- derringer --FIXME: tile_num, rot, speed, amount
[42] = {259, 90,4, 0}, -- revolver --FIXME: rot, speed, amount
[43] = {262, 90,4, 0}, -- shotgun --FIXME: rot, speed, amount
[44] = {259, 90,4, 0}, -- rifle --FIXME: rot, speed, amount
[45] = {259, 90,4, 0}, -- Belgian combine rifle --FIXME: rot, speed, amount (has 3 modes)
--[45] = {262, 90,4, 0}, -- Belgian combine spread(has two) --FIXME: rot, speed, amount
[46] = {259, 90,4, 0}, -- elephant gun --FIXME: tile_num, rot, speed, amount
[47] = {398, 0, 2, 0}, -- sling --FIXME: tile_num, rot, speed, amount
[48] = {575, 90,4, 0}, -- bow
[241] = {334, 90,4, 0}, -- heat ray gun --FIXME: rot, speed, amount (has 3 modes)
[242] = {335, 90,4, 0}, -- freeze ray gun --FIXME: rot, speed, amount (has 3 modes)
[313] = {267, 90,4, 0}, -- M60 machine gun --FIXME: rot, speed, amount (if even used)
}
armour_tbl =
{
--[1] = 0, --cap
--[2] = 0, --cowboy hat
[3] = 1, --pith helmet
[4] = 2, --military helmet
--[5] = 0, --derby
--[6] = 0, --kerchief
--[7] = 0, --silk scarf
--[8] = 0, --muffler
--[9] = 0, --man's shoes
--[10] = 0, --woman's shoes
[11] = 1, --riding boots
--[12] = 0, --ruby slippers
[13] = 2, --thigh boots
[14] = 3, --hip boots
--[15] = 0, --winged shoes
--[17] = 0, --cloth jacket
--[18] = 0, --wool sweater
--[19] = 0, --cape
--[20] = 0, --duster
[21] = 1, --wool overcoat
[22] = 2, --sheepskin jacket
[23] = 2, --arctic parka
--[25] = 0, --cotton pants
--[26] = 0, --cotton dress
[27] = 1, --denim jeans
--[28] = 0, --wool pants
--[29] = 0, --wool dress
[30] = 3, --chaps and jeans
--[31] = 0, --man's shoes
--[33] = 0, --lady's silk gloves
[34] = 1, --driving gloves
--[35] = 0, --cotton work gloves
[36] = 2, --work gloves
--[37] = 0, --wool mittens
[38] = 1, --rubber gloves
[39] = 3, --welding gloves
--[90] = 0, --electric belt?
--[234] = 0, --martian jewelry
}
function actor_get_ac(actor)
local ac = 0
for obj in actor_inventory(actor) do
if obj.readied then
local armour = armour_tbl[obj.obj_n]
if armour ~= nil then
ac = ac + armour
end
end
end
return ac
end
local clothing_warmth_tbl = {
[1] = 1, -- OBJ_CAP
[2] = 2, -- OBJ_COWBOY_HAT
[3] = 3, -- OBJ_PITH_HELMET
[4] = 3, -- OBJ_MILITARY_HELMET
[5] = 2, -- OBJ_DERBY
[6] = 1, -- OBJ_KERCHIEF
[7] = 1, -- OBJ_SILK_SCARF
[8] = 2, -- OBJ_MUFFLER
[9] = 1, -- OBJ_MANS_SHOES
[10] = 1, -- OBJ_WOMANS_SHOES
[11] = 2, -- OBJ_RIDING_BOOTS
[14] = 4, -- OBJ_HIP_BOOTS
[13] = 3, -- OBJ_THIGH_BOOTS
[17] = 2, -- OBJ_CLOTH_JACKET
[18] = 3, -- OBJ_WOOL_SWEATER
[19] = 3, -- OBJ_CAPE
[20] = 4, -- OBJ_DUSTER
[21] = 4, -- OBJ_WOOL_OVERCOAT
[22] = 3, -- OBJ_SHEEPSKIN_JACKET
[23] = 5, -- OBJ_ARCTIC_PARKA
[90] = 12, -- OBJ_ELECTRIC_BELT
[25] = 2, -- OBJ_COTTON_PANTS
[26] = 2, -- OBJ_COTTON_DRESS
[27] = 2, -- OBJ_DENIM_JEANS
[28] = 3, -- OBJ_WOOL_PANTS
[29] = 3, -- OBJ_WOOL_DRESS
[30] = 3, -- OBJ_CHAPS_AND_JEANS
[33] = 1, -- OBJ_LADYS_SILK_GLOVES
[34] = 1, -- OBJ_DRIVING_GLOVES
[35] = 1, -- OBJ_COTTON_WORK_GLOVES
[36] = 2, -- OBJ_WORK_GLOVES
[37] = 3, -- OBJ_WOOL_MITTENS
[38] = 1, -- OBJ_RUBBER_GLOVES
[39] = 3, -- OBJ_WELDING_GLOVES
}
function clothing_get_warmth_rating(obj)
local rating = clothing_warmth_tbl[obj.obj_n]
if rating == nil then
rating = 0
end
return rating
end
local lit_lightsource_tbl = {
[110] = 1, -- OBJ_LIT_TORCH
[112] = 1, -- OBJ_LIT_CANDLE
[114] = 1, -- OBJ_LIT_CANDELABRA
[116] = 1, -- OBJ_LIT_OIL_LAMP
[118] = 1, -- OBJ_LIT_LANTERN
}
function is_lit_lightsource(obj)
if lit_lightsource_tbl[obj.obj_n] ~= nil then
return true
end
return false
end
function actor_str_adj(actor)
local actor_num = actor.actor_num
local str = actor.str
if actor.hypoxia then
str = str - 3
end
if actor_is_affected_by_purple_berries(actor_num) then
str = str - 3
end
if actor.frenzy then
str = str + 3
if str > 30 then
str = 30
end
end
if str <= 3 then
return 1
end
return str
end
function actor_dex_adj(actor)
local dex = actor.dex
if actor.hypoxia then
if dex <= 3 then
dex = 1
else
dex = dex - 3
end
end
if actor.frenzy then
dex = dex + 3
if dex >= 30 then
dex = 30
end
end
if actor.asleep then
dex = 1
end
return dex
end
function actor_int_adj(actor)
local int = actor.int
if actor.hypoxia == true or (actor.frenzy and actor.actor_num ~= 1) then
int = int - 3
end
if int < 1 then int = 1 end
return int
end
function actor_map_dmg(actor, map_x, map_y, map_z)
local obj_n = actor.obj_n
local actor_type = actor_tbl[obj_n]
local player_loc = player_get_location()
if is_actor_stat_bit_set(obj_n, 8) or is_actor_stat_bit_set(obj_n, 10)
or actor.z ~= player_loc.z
or actor_find_max_wrapped_xy_distance(actor, player_loc.x, player_loc.y) > 40 then
return
end
if actor.alive == false or actor.hit_flag == true then
return
end
--print("actor_map_dmg("..actor.actor_num..")\n")
for obj in objs_at_loc(actor.x, actor.y, actor.z) do
local tile_num = obj.tile_num_original
if tile_get_flag(tile_num, 3, 2) == false and tile_get_flag(tile_num, 1, 3) == true then --force passable and damaging
actor_take_damage_from_obj(actor, obj)
end
end
actor_update_frame(actor, actor.direction)
end
function actor_take_damage_from_obj(actor, obj)
if actor_immune_to_dmg(actor) or actor.alive == false then
return
end
local obj_n = obj.obj_n
local damage = 0
local damage_mode = 0
if obj_n == 168 then --OBJ_PORCUPOD
damage = math.random(1, 0x14)
elseif obj_n == 209 then --OBJ_STEAM_LEAK
damage_mode = 3
if actor.actor_num ~= 6 then
damage = math.random(math.floor(actor.hp / 2), math.floor(actor.max_hp / 2))
end
elseif obj_n == 215 then --OBJ_POWER_CABLE1
play_md_sfx(0x15)
damage = math.random(1, 0x14) + math.random(1, 0x14)
elseif obj_n == 381 then --OBJ_DUST_DEVIL
damage = math.random(1, 0xa) + math.random(1, 0xa)
elseif obj_n == 463 then --hidden effect obj
--FIXME here
end
actor_hit(actor, damage, damage_mode)
end
function actor_remove_charm(actor)
actor.charmed = false;
actor.align = actor.old_align
if actor.in_party then
actor.align = ALIGNMENT_GOOD
end
if party_is_in_combat_mode() then
actor.wt = actor.combat_mode
else
if player_is_in_solo_mode() then
actor.wt = WT_NOTHING
else
actor.wt = WT_FOLLOW
end
end
party_update_leader()
end
function advance_time(num_turns)
--FIXME
local rand = math.random
local hour = clock_get_hour()
local quake = Actor.get_talk_flag(0x46, 3) --rasputin
if quake then
if rand(0, 4) == 0 then
quake_start(1, 200)
end
end
local max_light = 0
local actor_num
for actor_num=0,0xff do
local actor = Actor.get(actor_num)
if actor.alive then
if g_in_dream_mode == false and actor.in_party and actor_num ~= 0 then
if num_turns > 0 and actor.asleep == false then --FIXME I think we also need to check distance < 0x27 from either mapwindow or player.
if actor_num == 6 or Actor.get_talk_flag(0x10, 5) == false or Actor.inv_has_obj_n(actor, 131) then --OBJ_BLOB_OF_OXIUM
if actor.hypoxia then
actor.hypoxia = false
printfl("BREATHES_EASIER", actor.name)
end
else
if actor.hypoxia == false then
actor.hypoxia = true
printfl("GASPS_FOR_AIR", actor.name)
end
end
local warmth_rating = 0
local obj
for obj in actor_inventory(actor) do
if obj.readied then
warmth_rating = warmth_rating + clothing_get_warmth_rating(obj)
if is_lit_lightsource(obj) then
if rand(0, 1) == 1 then
if obj.quality <= num_turns then
if obj.obj_num == 116 --OBJ_LIT_OIL_LAMP
or obj.obj_num == 118 then --OBJ_LIT_LANTERN
if obj.obj_num == 116 then --OBJ_LIT_OIL_LAMP
obj.obj_n = 115 --OBJ_OIL_LAMP
else --OBJ_LIT_LANTERN
obj.obj_n = 117--OBJ_LANTERN
end
obj.quality = 0
printfl("THE_IS_OUT_OF_FUEL", obj.name)
else
printfl("WENT_OUT", obj.look_string)
Obj.removeFromEngine(obj)
end
else
obj.quality = obj.quality - num_turns
end
end
--FIXME update max_light here. probably not needed as light is updated elsewhere in nuvie.
--if max_light < obj.light then
--max_light = obj.light
--end
end
end
end
if g_party_is_warm or actor.z ~= 0 then
if actor.cold then
actor.cold = false
printfl("FEELS_WARMER", actor.name)
end
else
local cold_status = 0
if hour <= 3 or hour >= 22 then
if warmth_rating >= 10 then
cold_status = 1
else
cold_status = 2
end
elseif hour <= 6 or hour >= 18 then
if warmth_rating < 10 then
cold_status = 1
end
end
if actor_num == 6 then
cold_status = 0
end
if cold_status == 0 then
if actor.cold then
actor.cold = false
printfl("FEELS_WARMER", actor.name)
end
else
if actor.cold == false then
actor.cold = true
printfl("IS_FREEZING", actor.name)
end
if num_turns ~= 0 then
for i=1,num_turns do
if rand(0, 1) == 0 then
if cold_status == 2 then
printfl("IS_FREEZING", actor.name)
actor_hit(actor, rand(1, 2))
end
else
printfl("IS_FREEZING", actor.name)
actor_hit(actor, rand(1, 2))
if cold_status == 2 then
actor_hit(actor, rand(1, 2))
end
end
end
end
end
end
end
end
if num_turns ~= 0 then
for i=1,num_turns do
--FIXME what does word_4E6FA do?
--remove battle frenzy from actor when the party exits combat mode
if actor.frenzy and not party_is_in_combat_mode() then
actor.frenzy = false
end
if actor.poisoned then
if rand(0, 25) == 0 then
actor.poisoned = false
end
end
if actor.charmed and rand(0, 0x19) == 0 then
actor_remove_charm(actor)
end
if actor.paralyzed then
if actor_num == 6 or (rand(0, 3) == 0 and actor.str >= rand(1, 0x1e)) then --FIXME used adjusted str
actor.paralyzed = false
end
end
if actor.asleep and actor.wt ~= WT_SLEEP and (not g_party_is_warm or not actor.in_party) then
--FIXME check sub_2B0EC(actor.x,actor.y,actor.z)
if rand(0,0x14) == 0 then
actor.asleep = false
--FIXME bit 3 set on 1af1 flags
end
end
if actor.poisoned and actor_num ~= 6 and rand(0, 7) == 0 then
actor_hit(actor, 1)
end
if actor_num < 8 then
actor_decrement_berry_counters(actor)
for obj in actor_inventory(actor, true) do
local obj_n = obj.obj_n
if obj_n == 160 and obj.frame_n > 1 then --OBJ_EMPTY_BUCKET with ice
if rand(0, 100) < 10 then
printl("SOME_ICE_HAS_MELTED")
obj.frame_n = 1
end
elseif obj_n == 256 then --OBJ_CHUNK_OF_ICE
if rand(0, 100) < 10 then
printl("SOME_ICE_HAS_MELTED")
Obj.removeFromEngine(obj)
end
elseif obj_n == 448 or (obj_n == 449 and actor_num ~= 6 and actor.poisoned == false) then --OBJ_BLOCK_OF_RADIUM, OBJ_CHIP_OF_RADIUM
if obj.in_container == false or obj.parent.obj_n ~= 139 then --OBJ_LEAD_BOX
printfl("IS_POISONED", actor.name)
actor.poisoned = true
end
end
end
end
end
end
actor_map_dmg(actor, actor.x, actor.y, actor.z)
actor.hit_flag = false
end
end
local minute = clock_get_minute()
clock_inc(num_turns)
if minute + num_turns >= 60 then
update_watch_tile()
update_actor_schedules()
if g_hours_till_next_healing > 0 then
g_hours_till_next_healing = g_hours_till_next_healing - 1
end
update_lamp_posts()
local blue_berry_counter = actor_get_blue_berry_counter()
if blue_berry_counter > 0 then
actor_get_blue_berry_counter(blue_berry_counter - 1)
end
if not g_party_is_warm and not g_in_dream_mode and Actor.get_talk_flag(0x10, 5) then
for actor in party_members() do
if actor.actor_num ~= 6 and not actor.asleep then
local oxium = Actor.inv_get_obj_n(actor, 131) --OBJ_BLOB_OF_OXIUM
if oxium ~= nil then
if oxium.qty > 1 then
oxium.qty = oxium.qty - 1
if actor.hypoxia then
actor.hypoxia = false
printfl("BREATHES_EASIER", actor.name)
end
else
Obj.removeFromEngine(oxium)
if Actor.inv_get_obj_n(actor, 131) ~= nil then
if actor.hypoxia then
actor.hypoxia = false
printfl("BREATHES_EASIER", actor.name)
end
else
if actor.hypoxia == false then
actor.hypoxia = true
printfl("GASPS_FOR_AIR", actor.name)
end
end
end
else
if actor.hypoxia == false then
actor.hypoxia = true
printfl("GASPS_FOR_AIR", actor.name)
end
end
end
end
end
end
end
function can_get_obj_override(obj)
return false
end
function subtract_movement_pts(actor, points)
if actor.actor_num < 16 then
if party_is_in_combat_mode() == false then
points = points - 2
end
end
if points < 1 then
points = 1
end
actor.mpts = actor.mpts - points
end
function actor_radiation_check(actor, obj)
if obj.obj_n == 448 or obj.obj_n == 449 then --OBJ_BLOCK_OF_RADIUM, OBJ_CHIP_OF_RADIUM
local actor_num = actor.actor_num
if actor_num == 6
or actor_is_affected_by_purple_berries(actor_num) -- purple berries protect against radiation
or Actor.inv_get_readied_obj_n(actor, ARM) == 136 --OBJ_TONGS
or Actor.inv_get_readied_obj_n(actor, ARM_2) == 136 then
return
end
actor.poisoned = true
printl("OUCH_IT_IS_VERY_HOT")
end
end
function actor_get_obj(actor, obj, container) -- FIXME need to limit inventory slots
--FIXME handle getting into container.
if obj.getable == false then
printnl("THAT_IS_NOT_POSSIBLE")
return false
end
if actor_find_max_wrapped_xy_distance(actor, obj.x, obj.y) > 1 then
play_md_sfx(0x32)
projectile_anim(obj.tile_num, obj.x, obj.y, actor.x, actor.y, 4, false, 0)
end
if Actor.can_carry_obj_weight(actor, obj) == false then
printl("THE_TOTAL_IS_TOO_HEAVY")
return false
end
if not Actor.can_carry_obj(actor, obj) then
printnl("YOU_ARE_CARRYING_TOO_MUCH_ALREADY")
return false
end
subtract_movement_pts(actor, 3)
actor_radiation_check(actor, obj)
if obj.obj_n == 256 then -- OBJ_CHUNK_OF_ICE
printnl("THE_ICE_IS_MELTING")
end
if obj.obj_n == 110 -- OBJ_LIT_TORCH
or obj.obj_n == 112
or obj.obj_n == 114
or obj.obj_n == 116
or obj.obj_n == 118 then
if not actor_has_free_arm(actor) then
printl("YOUR_HANDS_ARE_FULL")
return false
end
Obj.moveToInv(obj, actor.actor_num)
Actor.inv_ready_obj(actor, obj)
if obj.obj_n == 110 then -- OBJ_LIT_TORCH
obj.quality = 0xb4
end
advance_time(0)
return true
end
if obj.obj_n == 411 -- OBJ_SWITCH_BAR
or obj.obj_n == 458 -- OBJ_PANEL
or obj.obj_n == 314 -- OBJ_TRACKING_MOTOR
or obj.obj_n == 206 then -- OBJ_TIFFANY_LENS
if obj.quality % 2 == 0 then
printnl("WONT_BUDGE")
return false
end
end
Obj.moveToInv(obj, actor.actor_num)
return true
end
function actor_get_max_hp(actor)
if actor.actor_num == 6 then
return 0xf0
end
if actor.in_party then
return actor.str * 2 + actor.level * 24
end
--FIXME return actor max hp from stat table.
return 1;
end
--function actor_take_hit(actor, damage)
-- local hp = actor.hp
-- if damage >= hp and actor.actor_num == 1 then
-- hit_anim(actor.x, actor.y)
-- actor.hp = 0
-- else
-- Actor.hit(actor, damage)
-- end
--end
function kill_actor(actor)
actor.hp=0
actor_dead(actor)
end
function actor_dead(actor)
--FIXME
end
function get_portrait_number(actor)
local NO_PORTRAIT = 255
local idx = actor.actor_num
if idx >= 0xa and idx <= 0xf then
idx = 0x51
end
if idx >= 0xbf then
return NO_PORTRAIT
end
if idx <= 1 then
if player_get_gender() == 1 then
idx = 0
else
idx = 1
end
elseif idx == 6 and Actor.get_talk_flag(actor, 1) then
idx = 0x16
elseif actor.obj_flag_0 then
if player_get_gender() == 1 then
idx = 0x73
else
idx = 0x72
end
elseif idx == 0x21 and not Actor.get_talk_flag(actor, 2) then
idx = 0x61
elseif idx == 0x15 or (idx >= 0x47 and idx <= 0x4a) or idx == 0x4e then
idx = 0x14
elseif idx >= 0x4b and idx <= 0x4d then
idx = 0x16
elseif idx == 0x1e then
idx = 0x18
elseif idx == 0x46 then
idx = 0x40
elseif idx >= 0x50 and idx <= 0x57 then
idx = idx - 0x26
elseif idx == 0x5e then
idx = 0x6
elseif idx == 0x68 or idx == 0x77 or idx == 0x78 then
idx = 0x67
elseif idx == 0x69 then
idx = 0x19
elseif idx == 0x6d then
idx = 0x2
end
return idx
end
function find_rockworm_actor(obj)
if obj ~= nil then
if obj.obj_n == 371 or obj.obj_n == 370 then --OBJ_ROCKWORM1, OBJ_ROCKWORM_BASE
local actor = Actor.get(obj.quality)
if actor.alive then
return actor
end
end
end
return obj
end