--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