Files
2026-02-02 04:50:13 +01:00

2461 lines
62 KiB
Lua

local USE_EVENT_USE = 0x01
local USE_EVENT_MOVE = 0x40
local USE_EVENT_READY = 0x0100
function search_container(obj)
local child
for child in container_objs(obj) do
Obj.moveToMap(child, obj.x, obj.y, obj.z)
end
end
function use_door(obj, actor)
if bit32.btest(obj.quality, 0x80) then
printl("IT_IS_LOCKED")
return
end
if map_get_actor(obj.x, obj.y, obj.z) ~= nil then
printl("BLOCKED")
return
end
obj.frame_n = bit32.bxor(obj.frame_n, 2)
end
function use_crate(obj, target_obj, actor)
if target_obj.frame_n == 2 then
target_obj.frame_n = 1
printl("YOU_PRIED_THE_NAILS_OUT_OF_THE_CRATE")
else
if target_obj.frame_n == 1 and obj.obj_n == 273 then
target_obj.frame_n = 2
printl("YOU_NAIL_THE_CRATE_SHUT")
else
printl("IT_HAS_NO_EFFECT")
end
end
end
function use_container(obj, actor)
if obj.frame_n == 2 then
if obj.obj_n == 86 or obj.obj_n == 284 then
printl("IT_IS_NAILED_SHUT")
else
printl("IT_IS_LOCKED")
end
else
if obj.frame_n == 1 then
obj.frame_n = 0
search_container(obj)
else
obj.frame_n = 1
end
end
end
function use_hammer_on_oxium_geode(obj, target_obj, actor)
if target_obj.frame_n ~= 0 then
printl("IT_HAS_NO_EFFECT")
return
end
play_md_sfx(0x20)
target_obj.frame_n = 1 --break the geode open
if target_obj.on_map then
local oxium = Obj.new(131) --OBJ_BLOB_OF_OXIUM
oxium.qty = math.random(1, 50) + math.random(1, 50)
Obj.moveToMap(oxium, target_obj.x, target_obj.y, target_obj.z)
else
--FIXME add to actor's inventory
local oxium = Actor.inv_get_obj_n(actor, 131) --OBJ_BLOB_OF_OXIUM
local qty = math.random(1, 50) + math.random(1, 50)
if oxium ~= nil then
oxium.qty = oxium.qty + qty
else
oxium = Obj.new(131, 0, 0, qty) --OBJ_BLOB_OF_OXIUM
Actor.inv_add_obj(actor, oxium)
end
end
end
function use_prybar_on_hatch(obj, target_obj, actor)
if actor.actor_num ~= 1 then
printfl("IS_NOT_STRONG_ENOUGH", actor.name)
return
end
local tesla = Actor.get(16)
if Actor.get_talk_flag(tesla, 4) == false then
Actor.set_talk_flag(tesla, 2)
Actor.talk(tesla)
else
play_midgame_sequence(1)
Actor.set_talk_flag(tesla, 5)
target_obj.obj_n = 428
target_obj.frame_n = 0;
target_obj.x = target_obj.x + 1
target_obj.y = target_obj.y + 1
local blood = Actor.get(18)
Actor.set_talk_flag(blood, 3)
Actor.set_talk_flag(blood, 6)
Actor.talk(blood)
end
end
function use_sextant(obj, actor)
if actor.z ~= 0 then
printl("NOT_WHILE_UNDERGROUND")
return
end
local lat_str = "N"
local long_str = "W"
local lat = math.modf(((actor.y - 512) * 240) / 1024)
local long = math.modf(((actor.x - 512) * 360) / 1024)
if lat > 0 then
lat_str = "S"
else
if lat == 0 then
lat_str = " "
end
end
if long == 180 or long == -180 or long == 0 then
long_str = " "
else
if long < 0 then
long_str = "E"
end
end
lat = math.abs(lat)
long = 180 - math.abs(long)
printl("YOU_ARE_SOMEWHERE_NEAR")
print(" \nLat:" ..lat.." "..lat_str.."\nLong:"..long.." "..long_str.."\n")
end
function use_berry(obj, actor)
local actor_num = actor.actor_num
if actor_num == 6 then
printl("A_MECHANICAL_PERSON_CANT_EAT_BERRIES")
return
end
play_md_sfx(0x32)
local berry_type = obj.obj_n - 73 --OBJ_BERRY
local first_berry = true
if (berry_type == 0 and actor_is_affected_by_purple_berries(actor_num))
or (berry_type == 1 and actor_is_affected_by_green_berries(actor_num))
or (berry_type == 2 and actor_is_affected_by_brown_berries(actor_num)) then
printl("YOU_EAT_A_MARTIAN_BERRY_YOU_FEEL_AN_INCREASE_IN_THE_STRANGE")
else
printl("YOU_EAT_A_MARTIAN_BERRY_YOU_FEEL_A_STRANGE")
end
if berry_type == 0 then
printl("RELATIONSHIP_WITH_THINGS_AROUND_YOU")
actor_increment_purple_berry_count(actor_num)
elseif berry_type == 1 then
printl("SENSITIVITY_TO_THE_FEELINGS_OF_OBJECTS_AROUND_YOU")
actor_increment_green_berry_count(actor_num)
elseif berry_type == 2 then
printl("SENSE_OF_YOUR_SPATIAL_LOCATION")
actor_increment_brown_berry_count(actor_num)
elseif berry_type == 3 then
printl("SUDDEN_FLUSH_DIZZINESS_AND_NAUSEA")
actor.poisoned = false
Actor.hit(actor, math.random(5, 0x14) + math.random(5, 0x14))
local counter = actor_get_blue_berry_counter()
actor_set_blue_berry_counter(counter + math.random(1, 2))
end
if obj.qty == 1 then
Obj.removeFromEngine(obj)
else
obj.qty = obj.qty - 1
end
end
function use_misc_text(obj)
local obj_n = obj.obj_n
if obj_n == 65 or obj_n == 66 or obj_n == 67 or obj_n == 263 or obj_n == 267 or obj_n == 327 then
printl("YOU_CANT_DIG_ANY_DEEPER")
elseif obj_n == 427 then
printl("IT_IS_STUCK")
elseif obj_n == 288 then
printl("THE_CONTROL_PANEL_OPERATES_THE_DREAM_MACHINE")
elseif obj_n == 199 then
printl("YOU_NEED_TO_USE_PLIERS_TO_ATTACH_THE_CABLE")
elseif obj_n == 131 then
printl("YOU_WILL_CHEW_IT_INSTINCTIVELY")
elseif obj_n == 184 then
printl("THE_PLATE_IN_THE_CAMERA_HAS_ALREADY_BEEN_EXPOSED")
elseif obj_n == 442 or obj_n == 443 or obj_n == 444 then
printl("YOU_MUST_USE_A_SHOVEL_TO_MOVE_THAT")
elseif obj_n == 293 then
printl("YOU_CANT_DETERMINE_HOW_TO_READ_THE_TIME")
elseif obj_n == 77 or obj_n == 78 then
printl("THE_BERRIES_ARE_NOT_EDIBLE")
elseif obj_n == 323 then
printl("YOU_DONT_KNOW_HOW_IT_WORKS")
else
printl("IT_HAS_NO_EFFECT")
end
end
function get_pile_obj_num(map_tile)
if (map_tile >= 32 and map_tile <= 36) or map_tile == 12 or map_tile == 13 or (map_tile >= 40 and map_tile <= 63) then
return 258 --OBJ_DIRT_PILE
elseif map_tile == 124 or map_tile == 125 or map_tile == 127 then
return 256 --OBJ_CHUNK_OF_ICE
end
return 0 --CANNOT DIG HERE
end
function get_free_location_around_actor(actor)
local x_tbl = {-1,0,1,1,1,0,-1,-1}
local y_tbl = {-1,-1,-1,0,1,1,1,0}
local pos = {}
local i
pos.z = actor.z
for i=1,8 do
pos.x = actor.x + x_tbl[i]
pos.y = actor.y + y_tbl[i]
if map_can_put(pos.x,pos.y,pos.z) == true and map_get_obj(pos.x,pos.y,pos.z) == nil then
return pos
end
end
return nil
end
function use_tool_on_ground(obj, target_obj, actor, target_x, target_y, target_z)
if target_obj ~= nil then
--check tile flag here.
printl("THE_GROUND_IS_NOT_CLEAR_FOR_DIGGING")
return
end
local map_tile = map_get_tile_num(target_x, target_y, target_z)
local pile_obj_num = get_pile_obj_num(map_tile)
if pile_obj_num == 0 then
printl("IT_HAS_NO_EFFECT")
return
end
local hole_obj_num = 257
if pile_obj_num == 256 then
hole_obj_num = 255
end
local hole = Obj.new(hole_obj_num)
hole.temporary = true
Obj.moveToMap(hole, target_x, target_y, target_z)
local loc = get_free_location_around_actor(actor)
if loc ~= nil then
local pile = Obj.new(pile_obj_num)
pile.temporary = true
Obj.moveToMap(pile, loc.x, loc.y, loc.z)
else
Obj.removeFromEngine(hole)
printl("YOU_CANT_DIG_HERE")
end
end
function use_shovel_on_pile_to_hole(obj, target_obj, to_obj, actor)
Obj.removeFromEngine(target_obj)
Obj.removeFromEngine(to_obj)
play_md_sfx(0x1b)
play_md_sfx(0x1b)
printl("YOU_FILLED_IN_THE_HOLE")
end
function use_shovel_on_ore_to_container(obj, target_obj, to_obj, actor)
print("\n")
local ore_quality = get_ore_container_quality(target_obj.obj_n)
if to_obj.obj_n == 268 then --OBJ_MARTIAN_WHEEL_BARROW
if to_obj.qty ~= 1 then
play_md_sfx(0x1b)
to_obj.qty = 1
to_obj.quality = ore_quality
printfl("YOU_PUT_THE_ORE_INTO_THE_WHEELBARROW", target_obj.name)
Obj.removeFromEngine(target_obj)
else
printl("THERE_IS_NO_MORE_ROOM")
play_md_sfx(5)
return false
end
elseif to_obj.obj_n == 410 then --OBJ_RAIL_CAR
local qty = to_obj.qty
if to_obj.qty < 7 then
if to_obj.qty > 0 and to_obj.quality ~= ore_quality then
printl("YOU_CANT_MIX_DIFFERENT_THINGS_IN_THE_SAME_LOAD")
play_md_sfx(5)
return false
else
to_obj.quality = ore_quality
to_obj.qty = to_obj.qty + 1
if to_obj.qty == 1 or to_obj.qty == 7 then
to_obj.frame_n = to_obj.frame_n + 2
end
printfl("YOU_PUT_THE_ORE_INTO_THE_RAIL_CAR", target_obj.name)
Obj.removeFromEngine(target_obj)
end
else
printl("THERE_IS_NO_MORE_ROOM")
play_md_sfx(5)
return false
end
end
return true
end
function use_shovel_to_unload_container(obj, target_obj, to_obj, actor)
if target_obj.qty == 0 then
printl("THERE_IS_NOTHING_TO_UNLOAD")
play_md_sfx(5)
return
end
local ore = Obj.new(get_obj_num_from_ore_quality(target_obj.quality))
--FIXME if to_obj == nil do something
local success_flag = false
if to_obj.obj_n == 268 or to_obj.obj_n == 410 then --OBJ_MARTIAN_WHEEL_BARROW
success_flag = use_shovel_on_ore_to_container(obj, ore, to_obj, actor)
elseif to_obj.obj_n == 233 then --OBJ_FURNACE
success_flag = use_shovel_on_ore_to_furnace(obj, ore, to_obj, actor)
elseif to_obj.obj_n == 257 then --OBJ_HOLE
--FIXME need to wire up this logic.
else
--FIXME need to implement burying logic
end
if success_flag then
target_obj.qty = target_obj.qty - 1
if target_obj.obj_n == 410 then --OBJ_RAIL_CAR
if target_obj.qty == 6 or target_obj.qty == 0 then
target_obj.frame_n = target_obj.frame_n - 2
end
end
end
end
function use_shovel_on_ore_to_furnace(obj, target_obj, to_obj, actor)
local obj_n = target_obj.obj_n
play_md_sfx(0x1b)
Obj.removeFromEngine(target_obj)
if obj_n == 444 then --OBJ_PILE_OF_COAL
if to_obj.frame_n < 4 then
activate_power_system()
end
else
printl("IT_HAS_NO_EFFECT")
end
return true
end
function activate_power_system()
printl("THE_COAL_BEGINS_MOVING_DOWN_THE_BELT")
Actor.set_talk_flag(0x73, 2)
Actor.set_talk_flag(0x71, 3)
activate_power_update_tiles()
update_conveyor_belt(false)
end
function activate_power_update_tiles()
anim_play(9)
anim_play(10)
anim_play(11)
anim_play(12)
local loc = player_get_location()
for obj in find_obj(loc.z, 208) do --OBJ_CRACK
if obj ~= nil then
if map_get_obj(obj.x, obj.y, obj.z, 209) == nil then
local steam = Obj.new(209, 1)
Obj.moveToMap(steam, obj.x, obj.y+1, obj.z)
end
end
end
for obj in find_obj(loc.z, 233) do --OBJ_FURNACE
if obj ~= nil then
local frame_n = obj.frame_n
if frame_n == 1 or frame_n == 3 then
obj.frame_n = frame_n + 4
end
end
end
for obj in find_obj(loc.z, 154) do --OBJ_LAMP
if obj ~= nil then
obj.frame_n = 1
end
end
for obj in find_obj(4, 154) do --OBJ_LAMP
if obj ~= nil then
obj.frame_n = 1
end
end
end
function shutdown_power_update_tiles()
anim_stop(9)
anim_stop(10)
anim_stop(11)
anim_stop(12)
local loc = player_get_location()
for obj in find_obj(loc.z, 209) do --OBJ_STEAM_LEAK
if obj ~= nil then
Obj.removeFromEngine(obj)
end
end
for obj in find_obj(loc.z, 233) do --OBJ_FURNACE
if obj ~= nil then
local frame_n = obj.frame_n
if frame_n == 5 or frame_n == 7 then
obj.frame_n = frame_n - 4
end
end
end
for obj in find_obj(loc.z, 154) do --OBJ_LAMP
if obj ~= nil then
obj.frame_n = 0
end
end
for obj in find_obj(4, 154) do --OBJ_LAMP
if obj ~= nil then
obj.frame_n = 0
end
end
end
function update_conveyor_belt(can_stop)
if Actor.get_talk_flag(0x73, 2) == false then
return
end
local player_loc = player_get_location()
if player_loc.z ~= 5 then
return
end
--NOTE. The original game used generalised logic to search for conveyors.
-- I haven't used that here as there is only one conveyor in the game.
local x = 0x3c
local y = 0x63
local z = 5
local conveyor = map_get_obj(x, y, z, 188) --OBJ_CONVEYOR_BELT
while conveyor ~= nil do
if conveyor.frame_n == 2 then
local seam = map_get_obj(x, y, z, 189) --OBJ_CONVEYOR_BELT1
if seam ~= nil then
Obj.removeFromEngine(seam)
end
elseif conveyor.frame_n == 0 then
if conveyor.qty == 0 then
local seam = Obj.new(189)
Obj.moveToMap(seam, x, y, z)
conveyor.qty = 4
end
conveyor.qty = conveyor.qty - 1
end
local seam = map_get_obj(x, y, z, 189) --OBJ_CONVEYOR_BELT1
if seam ~= nil then
seam.x = seam.x + 1
end
for obj in objs_at_loc(x, y, z) do
if obj.obj_n == 447 or obj.weight > 0 then --OBJ_HUGE_LUMP_OF_COAL
obj.x = obj.x + 1
end
end
local actor = map_get_actor(x, y, z)
if actor ~= nil then
Actor.move(actor, x+1, y, z)
end
x = x - 1
conveyor = map_get_obj(x, y, z, 188) --OBJ_CONVEYOR_BELT
end
if can_stop and Actor.get_talk_flag(0x71, 3) then
if math.random(0, 6) == 0 then
printl("THE_CONVEYOR_BELT_STOPS")
Actor.clear_talk_flag(0x73, 2)
Actor.clear_talk_flag(0x71, 3)
shutdown_power_update_tiles()
end
end
end
function midgame_cutscene_2()
play_midgame_sequence(2)
for tower in find_obj(0, 201) do --OBJ_TOWER_TOP
if tower.x >= 0x3d0 and tower.x <= 0x3f0 and tower.y >= 0x1d0 and tower.y <= 0x1e7 then
tower.frame_n = 4 + (tower.frame_n % 4)
end
end
for cable in find_obj(0, 214) do --OBJ_POWER_CABLE
if cable.x >= 0x3d0 and cable.x <= 0x3f0 and cable.y >= 0x1d0 and cable.y <= 0x1e7 then
cable.obj_n = 215
end
end
end
function use_fixed_belt_on_bare_rollers(obj, target_obj, actor)
local start_obj = nil
local rollers = target_obj
while rollers ~= nil do
if rollers.frame_n == 0 then
start_obj = rollers
break
end
rollers = map_get_obj(rollers.x-1,rollers.y,rollers.z, rollers.obj_n)
end
if start_obj == nil then
printl("OOOPS_THESE_ROLLERS_CAN_NEVER_BE_FIXED")
return
end
rollers = start_obj
local i = 4
while rollers ~= nil do
rollers.obj_n = 188
if i == 0 then
i = 4
local belt_join_obj = Obj.new(189)
Obj.moveToMap(belt_join_obj, rollers.x, rollers.y, rollers.z)
else
i = i - 1
end
rollers = map_get_obj(rollers.x+1,rollers.y,rollers.z, 192) --OBJ_BARE_ROLLERS
end
Obj.removeFromEngine(obj)
Actor.set_talk_flag(0x72, 2)
end
function use_ruby_slippers(obj, actor)
if obj.readied == false then
--FIXME check that we can ready this object.
Obj.removeFromEngine(obj)
Actor.inv_ready_obj(actor, obj)
return
end
if obj.quality == 2 then
printl("YOU_MAY_USE_THE_RUBY_SLIPPERS_TO_GO_HOME")
local input = input_select("yn", false)
if input == "Y" then
play_end_sequence()
else
play_midgame_sequence(13)
end
else
printl("CLICK")
obj.quality = obj.quality + 1
end
end
function foes_are_nearby()
local loc = player_get_location()
local i
for i=1,0xff do
local actor = Actor.get(i)
if actor.alive and (actor.align == ALIGNMENT_EVIL or actor.align == ALIGNMENT_CHAOTIC) and actor.z == loc.z then
if get_wrapped_dist(actor.x, loc.x) < 40 and get_wrapped_dist(actor.y, loc.y) < 40 then
return true
end
end
end
return false
end
function is_target_visible_to_actor(actor, target)
--FIXME
return true
end
function npcs_are_nearby()
local loc = player_get_location()
local i
local player = Actor.get_player_actor()
for i=1,0xff do
local actor = Actor.get(i)
if actor.alive and actor.asleep == false and actor.in_party == false and actor.z == loc.z then
if get_wrapped_dist(actor.x, loc.x) < 6 and get_wrapped_dist(actor.y, loc.y) < 6 and is_target_visible_to_actor(player, actor) then
return actor
end
end
end
return nil
end
function is_actor_able_to_talk_to_player(actor)
local player = Actor.get_player_actor()
local loc = player_get_location()
if actor.alive and actor.asleep == false and actor.z == loc.z then
if get_wrapped_dist(actor.x, loc.x) < 6 and get_wrapped_dist(actor.y, loc.y) < 6 and is_target_visible_to_actor(player, actor) then
return true
end
end
return false
end
function rest_heal_party(hours_to_rest)
local actor
for actor in party_members() do
local hp = math.random(3,8) + math.random(3,8) * math.floor(hours_to_rest / 2)
local max_hp = actor_get_max_hp(actor)
if actor.hp + hp > max_hp then
actor.hp = max_hp
else
actor.hp = actor.hp + hp
end
end
end
function rest_level_up_actor(actor)
if actor.actor_num > 15 then
return
end
local exp_level_tbl = {
[0] = 0,
[1] = 100,
[2] = 200,
[3] = 400,
[4] = 800,
[5] = 1600,
[6] = 3200,
[7] = 6400,
[8] = 32767,
}
if actor.exp <= exp_level_tbl[actor.level] then
return
end
actor.level = actor.level + 1
local max_hp = actor_get_max_hp(actor)
if actor.hp + 30 > max_hp then
actor.hp = max_hp
else
actor.hp = actor.hp + 30
end
Actor.show_portrait(actor)
local obj_n = actor.obj_n
local gender = math.random(0,1)
if obj_n == 342 or obj_n == 343 or obj_n == 345 or (obj_n >= 347 and obj_n <= 353) then
gender = 0
elseif obj_n == 344 or obj_n == 346 or (obj_n >= 354 and obj_n <= 357) then
gender = 1
end
local gender_pronoun = "He"
if gender == 1 then
gender_pronoun = "She"
end
printfl("HAS_A_DREAM", actor.name)
printfl("SEES_THREE_STONE_OBELISKS", gender_pronoun)
printfl("FEELS_DRAWN_TO_ONE_OF_THE_OBELISKS", gender_pronoun)
printfl("DOES_TOUCH_THE_OBELISK", actor.name)
printl("WHICH_BHS")
local answer = input_select("bhs", false)
if answer == "B" then
if actor.int < 30 then
actor.int = actor.int + 1
end
elseif answer == "H" then
if actor.dex < 30 then
actor.dex = actor.dex + 1
end
elseif answer == "S" then
if actor.str < 30 then
actor.str = actor.str + 1
end
end
end
function use_tent(obj, actor)
if player_is_in_solo_mode() then
printl("NOT_WHILE_IN_SOLO_MODE")
play_md_sfx(5)
return
end
if g_in_dream_mode then
printl("YOU_CANT_SLEEP_IN_A_DREAM")
play_md_sfx(5)
return
end
local tent_loc = {}
if obj.on_map then
tent_loc.x = obj.x
tent_loc.y = obj.y
tent_loc.z = obj.z
else
tent_loc = player_get_location()
end
local x, y
for y = tent_loc.y - 2, tent_loc.y do
for x = tent_loc.x - 1, tent_loc.x + 1 do
local map_obj = map_get_obj(x,y,tent_loc.z)
if map_obj ~= nil and map_obj.obj_n ~= 106 then
if tile_get_flag(map_obj.tile_num, 3, 4) == false then
printfl("TENT_OBJ_IN_THE_WAY", map_obj.name)
play_md_sfx(5)
return
end
end
end
end
for y = tent_loc.y - 2, tent_loc.y do
for x = tent_loc.x - 1, tent_loc.x + 1 do
if tile_get_flag(map_get_tile_num(x,y,tent_loc.z), 1, 1) == true then --if map tile is impassible
printl("THE_GROUND_IS_NOT_FLAT_ENOUGH")
play_md_sfx(5)
return
end
end
end
printl("REST")
if party_is_in_combat_mode() then
print(" - ")
printl("NOT_WHILE_IN_COMBAT_MODE")
play_md_sfx(5)
return
end
if foes_are_nearby() then
printl("NOT_WHILE_FOES_ARE_NEAR")
play_md_sfx(5)
return
end
local npc = npcs_are_nearby()
if npc ~= nil then
printfl("IS_TOO_NEAR_TO_SETUP_CAMP", npc.name)
play_md_sfx(5)
return
end
--poison check
local actor
local poisoned = false
for actor in party_members() do
if actor.poisoned then
poisoned = true
printfl("IS_POISONED", actor.name)
end
end
if poisoned then
printl("DO_YOU_REALLY_WANT_TO_SLEEP")
local answer = input_select("yn", false)
if answer == "N" or answer == "n" then
return
end
end
local party_is_using_berries = false
for actor in party_members() do
local actor_num = actor.actor_num
local green = actor_is_affected_by_green_berries(actor_num)
local brown = actor_is_affected_by_brown_berries(actor_num)
if brown or green then
party_is_using_berries = true
if brown and green then
printfl("COMPLAINS_OF_TOO_MUCH_LIGHT_AND_INANIMATE", actor.name)
elseif brown then
printfl("COMPLAINS_OF_TOO_MUCH_LIGHT", actor.name)
else --green
printfl("COMPLAINS_OF_INANIMATE_THINGS_TALKING", actor.name)
end
end
end
if party_is_using_berries then
if party_get_size() == 1 then
printl("YOU_CANT_SLEEP")
else
printl("NOBODY_CAN_SLEEP")
end
return
end
local player = Actor.get_player_actor()
player.x = tent_loc.x
player.y = tent_loc.y
local tent = Obj.new(134, 3)
Obj.moveToMap(tent, player.x, player.y-1, player.z)
tent = Obj.new(134, 5)
Obj.moveToMap(tent, player.x+1, player.y-1, player.z)
tent = Obj.new(134, 6)
Obj.moveToMap(tent, player.x-1, player.y, player.z)
tent = Obj.new(134, 9)
Obj.moveToMap(tent, player.x+1, player.y, player.z)
tent = Obj.new(134, 8)
Obj.moveToMap(tent, player.x, player.y, player.z)
party_move(player.x, player.y, player.z)
script_wait(500)
party_hide_all()
tent.frame_n = 7
local hour = clock_get_hour()
local time
local hours_to_rest
if hour < 7 or hour > 16 then
time = i18n("SUNRISE")
if hour < 7 then
hours_to_rest = 7 - hour
else
hours_to_rest = 24 - hour + 7
end
elseif hour <= 16 then
time = i18n("SUNSET")
hours_to_rest = 18 - hour
end
printfl("REST_UNTIL", time)
local answer = input_select("yn", false)
if answer == "N" or answer == "n" then
printl("HOW_MANY_HOURS")
hours_to_rest = input_select_integer("0123456789", true)
end
g_party_is_warm = true
if g_hours_till_next_healing == 0 and hours_to_rest > 4 then
rest_heal_party(hours_to_rest)
g_hours_till_next_healing = 6
end
local can_level_up = false
if hours_to_rest * 3 > party_get_size() then
can_level_up = true
end
local i
for i=0,hours_to_rest*3-1 do
advance_time(20)
script_wait(100)
if i < party_get_size() then
local actor = party_get_member(i)
rest_level_up_actor(actor)
end
end
local actor
local poisoned = false
for actor in party_members() do
if actor.poisoned then
if math.random(1, 8) + math.random(1, 8) >= 15 then
actor.poisoned = false
printfl("FEELS_BETTER", actor.name)
else
if actor.hp < hours_to_rest * 2 + 5 then
actor.hp = 5
else
actor.hp = actor.hp - (hours_to_rest * 2 + 5)
end
end
end
end
tent.frame_n = 8 --Open the tent flap
party_show_all()
party_move(player.x, player.y + 1, player.z)
script_wait(500)
--remove tent from map
local z = player.z
for tent in find_obj(z, 134) do
if tent ~= nil and
((tent.x == tent_loc.x and tent.y == tent_loc.y-1) or
(tent.x == wrap_coord(tent_loc.x+1,z) and tent.y == tent_loc.y-1) or
(tent.x == wrap_coord(tent_loc.x-1,z) and tent.y == tent_loc.y) or
(tent.x == wrap_coord(tent_loc.x+1,z) and tent.y == tent_loc.y) or
(tent.x == tent_loc.x and tent.y == tent_loc.y))
then
Obj.removeFromEngine(tent)
end
end
g_party_is_warm = false
end
function use_red_berry(obj, actor)
if not party_is_in_combat_mode() then
printl("THAT_WOULD_BE_A_WASTE_OUTSIDE_OF_COMBAT")
return
end
if actor.frenzy == false then
printfl("ENTERS_A_BATTLE_FRENZY", actor.name)
play_md_sfx(0x32)
end
actor.frenzy = true
local qty = obj.qty
if qty > 1 then
obj.qty = qty - 1
else
Obj.removeFromEngine(obj)
end
end
function use_spittoon(obj, actor)
if not actor.hypoxia then
printl("YOU_SPIT_INTO_THE_SPITTOON")
else
printl("YOUR_MOUTH_IS_TOO_DRY")
end
end
function use_gong(obj, target_obj, actor)
printl("GONG")
play_md_sfx(0xf)
end
function use_musical_instrument(obj, actor)
local obj_n = obj.obj_n
if obj_n == 280 then --OBJ_CYMBALS
printl("CHING")
play_md_sfx(0x36)
elseif obj_n == 281 then --OBJ_TAMBORINE
printl("SHING")
play_md_sfx(0x35)
elseif obj_n == 282 then --OBJ_DRUM
printl("THUMP_THUMP")
play_md_sfx(0x34)
script_wait(100)
play_md_sfx(0x34)
elseif obj_n == 283 then --OBJ_ACCORDION
printl("WHEEEEZE")
play_md_sfx(0x37)
else
printfl("YOU_PLAY_THE", obj.name)
end
end
function use_wrench_on_switchbar(obj, target_obj, actor)
if target_obj.quality == 1 then
if target_obj.on_map then
local turntable = map_get_obj(target_obj.x-1, target_obj.y-1, target_obj.z, 413)
if turntable ~= nil then
target_obj.frame_n = turntable.frame_n
target_obj.quality = 0
printl("THE_SWITCH_IS_FASTENED")
play_md_sfx(0x1f)
return
end
end
printl("THIS_SWITCH_CANNOT_BE_FIXED")
play_md_sfx(0x5)
else
printl("THE_SWITCH_IS_LOOSE")
play_md_sfx(0x1f)
target_obj.quality = 1
end
end
function use_wrench_on_drill(obj, target_obj, actor)
local drill_cart
if target_obj.on_map then
drill_cart = map_get_obj(target_obj.x, target_obj.y, target_obj.z, 439)
end
if drill_cart ~= nil then
local drill = Obj.new(441,1) --assembled drill
Obj.moveToMap(drill, target_obj.x, target_obj.y, target_obj.z)
Obj.removeFromEngine(target_obj)
Obj.removeFromEngine(drill_cart)
printl("THE_DRILLS_POWER_IS_CONNECTED")
play_md_sfx(0x1f)
else
printl("THE_DRILL_MUST_BE_INSTALLED_ONTO_A_DRILL_CART")
end
end
function use_wrench_on_panel(obj, target_obj, actor)
if target_obj.on_map == false then
printl("IT_HAS_NO_EFFECT")
return
end
local quality = target_obj.quality
local panel_qty = target_obj.qty
if quality == 0 then
target_obj.quality = 1
printl("THE_PANEL_IS_LOOSE")
play_md_sfx(0x1f)
elseif bit32.btest(quality, 2) then
printl("IT_MUST_BE_REPAIRED_FIRST")
play_md_sfx(0x5)
else
local cabinet = map_get_obj(target_obj.x, target_obj.y, target_obj.z, 457)
if cabinet == nil then
printl("PANELS_ARE_ONLY_INSTALLED_ONTO_CABINETS")
play_md_sfx(0x5)
else
quality = cabinet.quality
if (quality == 0 and panel_qty ~= 0) or
(quality ~= 0 and quality <= 3 and panel_qty == 0 and target_obj.frame_n ~= (quality - 1) ) or
(quality ~= 0 and (quality > 3 or panel_qty ~= 0) and quality ~= panel_qty) then
printl("THIS_CABINET_REQUIRES_A_DIFFERENT_TYPE_OF_PANEL")
play_md_sfx(0x5)
else
target_obj.quality = target_obj.quality - 1
printl("THE_PANEL_IS_FASTENED")
play_md_sfx(0x1f)
if target_obj.quality == 3 then
Actor.set_talk_flag(0x74, 3)
if Actor.get_talk_flag(0x74, 0) then
Actor.set_talk_flag(0x60, 2)
end
end
end
end
end
end
function use_oxium_bin(obj, actor)
if map_can_reach_point (actor.x, actor.y, obj.x, obj.y, obj.z) == false then
printl("BLOCKED")
return
end
local oxium = Obj.new(131) --OBJ_BLOB_OF_OXIUM
oxium.qty = 20
if Actor.can_carry_obj(actor, oxium) then
Actor.inv_add_obj(actor, oxium, STACK_OBJECT_QTY)
printl("YOU_GET_TWO_HANDFULS_OF_OXIUM_FROM_THE_BIN")
Actor.set_talk_flag(0x12, 4)
else
printl("YOU_ARE_CARRYING_TOO_MUCH_ALREADY")
end
end
function use_sledge_hammer_on_replacement_track_to_broken_track(obj, target_obj, to_obj, actor)
play_md_sfx(0x20)
printl("WHICH_SECTION_OF_RAIL_NEEDS_FIXING")
Obj.removeFromEngine(target_obj)
to_obj.obj_n = 414 --OBJ_TRACK
end
function use_pliers_on_spool_to_tower(obj, target_obj, to_obj, actor)
if actor_find_max_wrapped_xy_distance(actor, to_obj.x, to_obj.y) > 1 then
printl("THE_WORK_IS_TO_PRECISE_TO_PERFORM_TELEKINETICALLY")
return
end
if Actor.get_talk_flag(0x73, 2) == false or Actor.get_talk_flag(0x71, 3) == true then
printl("THE_CABLE_DOES_NOT_NEED_REPLACEMENT")
return
end
if actor_is_holding_obj(actor, 38) == false then --OBJ_RUBBER_GLOVES
Actor.hit(actor, math.random(0, math.floor(actor.max_hp/2)))
local spector = Actor.get(2)
if is_actor_able_to_talk_to_player(spector) then
Actor.set_talk_flag(spector, 2)
Actor.talk(spector)
end
else
play_md_sfx(0x1f)
Obj.removeFromEngine(target_obj)
Actor.set_talk_flag(0x73, 4)
play_midgame_sequence(3)
for obj in find_obj_from_area(0x3d0, 0x1d0, 0, 32, 17) do
if obj.obj_n == 215 then -- OBJ_POWER_CABLE1
obj.obj_n = 214 -- OBJ_POWER_CABLE
end
end
for obj in find_obj(0, 315) do --OBJ_CHAMBER1
Obj.removeFromEngine(obj)
end
end
end
function use_gate(obj, actor)
if bit32.btest(obj.quality, 128) == true then
printl("IT_IS_APPARENTLY_LOCKED")
return
end
local frame_n = obj.frame_n
if frame_n == 0 or frame_n == 1 then
obj.frame_n = 3
obj.x = obj.x - 1
elseif frame_n == 2 or frame_n == 3 then
obj.frame_n = 1
obj.x = obj.x + 1
elseif frame_n == 4 or frame_n == 5 then
obj.frame_n = 7
elseif frame_n == 6 or frame_n == 7 then
obj.frame_n = 5
end
end
function use_switch_bar(obj, actor)
if obj.frame_n == 0 then
obj.frame_n = 1
else
obj.frame_n = 0
end
if obj.on_map == false or map_get_obj(obj.x-1,obj.y-1,obj.z, 413) == nil then
printl("IT_HAS_NO_EFFECT")
return
end
if obj.quality == 1 then
printl("IT_TURNS_LOOSELY")
return
end
local turntable = map_get_obj(obj.x-1,obj.y-1,obj.z, 413)
turntable.frame_n = obj.frame_n
local railcar = map_get_obj(obj.x-1,obj.y-1,obj.z, 410)
if railcar ~= nil then
railcar.frame_n = railcar.frame_n - (railcar.frame_n % 2)
railcar.frame_n = railcar.frame_n + turntable.frame_n
end
end
function use_reading_material(obj, actor)
if obj.quality == 0 then
local signatures = ""
if Actor.get_talk_flag(5, 3) == true then
signatures = signatures .. " Richard Sherman"
end
signatures = signatures .. "\n"
if Actor.get_talk_flag(0x19, 3) == true then
signatures = signatures .. " Capt. Gregory Duprey"
end
signatures = signatures .. "\n"
if Actor.get_talk_flag(0x1a, 3) == true then
signatures = signatures .. " Doctor David Yellin"
end
signatures = signatures .. "\n"
display_text_in_scroll_gump(i18nf("AFFIDAVIT", player_get_name(), signatures))
else
local text = load_text_from_lzc("mdtext.lzc", obj.quality - 1)
if text ~= nil then
display_text_in_scroll_gump(text)
else
printl("YOU_CANT_READ_IT")
end
end
end
function use_pool_table(obj, actor)
if Actor.inv_get_readied_obj_n(actor, ARM) ~= 401 then --OBJ_POOL_CUE
printl("YOU_NEED_A_POOL_CUE")
return
end
local pool_table1 = map_get_obj(wrap_coord(obj.x - 1, obj.z), obj.y, obj.z, 400) -- OBJ_UNK_400
local rand = math.random
if pool_table1 == nil then
pool_table1 = Obj.new(400, rand(0, 6))
Obj.moveToMap(pool_table1, wrap_coord(obj.x - 1, obj.z), obj.y, obj.z)
end
local pool_table2 = map_get_obj(obj.x, obj.y, obj.z, 400) -- OBJ_UNK_400
if pool_table2 == nil then
pool_table2 = Obj.new(400, rand(0, 6))
Obj.moveToMap(pool_table2, wrap_coord(obj.x - 1, obj.z), obj.y, obj.z)
end
for i=1,10 do
if i~= 1 then
script_wait(rand(200,500))
end
play_md_sfx(0x1c + rand(0, 2))
script_wait(rand(10,200))
play_md_sfx(0x1c + rand(0, 2))
pool_table1.frame_n = rand(0, 6)
pool_table2.frame_n = rand(0, 6)
if rand(0, 40) >= actor_dex_adj(actor) then
break
end
end
if rand(0, 40) < actor_dex_adj(actor) then
printl("GOOD_SHOT_OLD_BEAN")
end
end
function use_ready_obj(obj, actor)
if not Actor.can_carry_obj(actor, obj) then
printl("YOU_ARE_CARRYING_TOO_MUCH_ALREADY")
return
end
if obj.readied == true then
return
end
Obj.removeFromEngine(obj)
Obj.moveToInv(obj, actor.actor_num)
Actor.inv_ready_obj(actor, obj)
end
function use_heartstone_on_metal_woman(obj, target_obj, actor)
if target_obj.quality == 1 then
printl("THE_ROBOT_ALREADY_HAS_A_HEARTSTONE")
else
target_obj.quality = 1
Obj.removeFromEngine(obj)
play_md_sfx(0x1f)
printl("THE_HEARTSTONE_IS_INSTALLED")
end
end
function use_manuscript_on_mailbox(obj, target_obj, actor)
local twain = Actor.get(0x57)
finish_dream_quest(twain)
Actor.set_talk_flag(twain, 6)
Actor.talk(twain)
wake_from_dream()
end
function use_assembled_drill(obj, actor)
play_md_sfx(0x10)
local x = obj.x
local y = obj.y
local z = obj.z
if obj.frame_n == 1 then
x = x - 1
elseif obj.frame_n == 3 then
y = y - 1
elseif obj.frame_n == 4 then
y = y + 1
else
x = x + 1
end
local target_obj
for obj in objs_at_loc(x, y, z) do
if obj.obj_n == 445 --OBJ_IRON_ORE
or obj.obj_n == 446 -- OBJ_VEIN_OF_COAL
or obj.obj_n == 213 then --OBJ_CAVE_IN
target_obj = obj
break
end
end
if target_obj == nil then
target_obj = map_get_obj(x, y, z, 213, true)
end
local drilled_matterial
if target_obj == nil then
if can_drill_at_loc(x, y, z) == true then
drilled_matterial = 442 --OBJ_PILE_OF_ROCKS
else
local target_actor = map_get_actor(x, y, z)
if target_actor ~= nil then
--FIXME attack actor here. 40 points of damage
else
printl("THERE_IS_NOTHING_TO_DRILL_INTO")
end
return
end
elseif target_obj.obj_n == 445 then --OBJ_IRON_ORE
drilled_matterial = 443 --OBJ_PILE_OF_IRON_ORE
elseif target_obj.obj_n == 446 then --OBJ_VEIN_OF_COAL
drilled_matterial = 444 --OBJ_PILE_OF_COAL
end
if drilled_matterial ~= nil then
local spoil_location = get_free_location_around_drill(obj)
if spoil_location ~= nil then
local spoil_obj = Obj.new(drilled_matterial)
Obj.moveToMap(spoil_obj, spoil_location)
else
printl("THERE_IS_NO_ROOM_LEFT_FOR_THE_ORE")
end
end
if target_obj then
if target_obj.quality > 1 then
target_obj.quality = target_obj.quality - 1
else
Obj.removeFromEngine(target_obj)
end
end
if drilled_matterial == nil then
Obj.removeFromEngine(target_obj)
end
end
function get_free_location_around_drill(drill)
local x_tbl = {-1,0,1,1,1,0,-1,-1}
local y_tbl = {-1,-1,-1,0,1,1,1,0}
local pos = {}
local i
pos.z = drill.z
for i=1,8 do
pos.x = drill.x + x_tbl[i]
pos.y = drill.y + y_tbl[i]
local obj = map_get_obj(pos.x, pos.y, pos.z)
if obj == nil or is_blood(obj.obj_num) then
if tile_get_flag(map_get_tile_num(pos), 1, 1) == false then --not blocked.
return pos
end
end
end
return nil
end
function get_ore_container_quality(ore_obj_num)
local tbl = {[258]=1,[442]=2,[443]=3,[444]=4} --OBJ_DIRT_PILE, OBJ_PILE_OF_ROCKS, OBJ_PILE_OF_IRON_ORE, OBJ_PILE_OF_COAL
local quality = tbl[ore_obj_num]
if quality == nil then
quality = 1
end
return quality
end
function get_obj_num_from_ore_quality(ore_quality)
if ore_quality == 2 then
return 442 --OBJ_PILE_OF_ROCKS
elseif ore_quality == 3 then
return 443 --OBJ_PILE_OF_IRON_ORE
elseif ore_quality == 4 then
return 444 --OBJ_PILE_OF_COAL
end
return 258 --OBJ_DIRT_PILE
end
function can_drill_at_loc(x,y,z)
local tile_num = map_get_tile_num(x, y, z)
if tile_num >= 0xf0 and tile_num <= 0xfb then
return true
end
return false
end
local use_shovel_on_tbl = {
--on
[255]=use_misc_text,
[257]=use_misc_text,
[258]={[257]=use_shovel_on_pile_to_hole},
[268]={
[233]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_MARTIAN_WHEEL_BARROW to OBJ_FURNACE
[257]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_MARTIAN_WHEEL_BARROW to OBJ_HOLE
[268]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_MARTIAN_WHEEL_BARROW to OBJ_MARTIAN_WHEEL_BARROW
[410]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_MARTIAN_WHEEL_BARROW to OBJ_RAIL_CAR
},
[410]={
[233]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_RAIL_CAR to OBJ_FURNACE
[257]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_RAIL_CAR to OBJ_HOLE
[268]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_RAIL_CAR to OBJ_MARTIAN_WHEEL_BARROW
[410]=use_shovel_to_unload_container, --use OBJ_SHOVEL on OBJ_RAIL_CAR to OBJ_RAIL_CAR
},
[442]={
[268]=use_shovel_on_ore_to_container, --use OBJ_SHOVEL on OBJ_PILE_OF_ROCKS to OBJ_MARTIAN_WHEEL_BARROW
[410]=use_shovel_on_ore_to_container}, --use OBJ_SHOVEL on OBJ_PILE_OF_ROCKS to OBJ_RAIL_CAR
[443]={
[268]=use_shovel_on_ore_to_container, --use OBJ_SHOVEL on OBJ_PILE_OF_IRON_ORE to OBJ_MARTIAN_WHEEL_BARROW
[410]=use_shovel_on_ore_to_container}, --use OBJ_SHOVEL on OBJ_PILE_OF_IRON_ORE to OBJ_RAIL_CAR
[444]={
[268]=use_shovel_on_ore_to_container, --use OBJ_SHOVEL on OBJ_PILE_OF_COAL to OBJ_MARTIAN_WHEEL_BARROW
[410]=use_shovel_on_ore_to_container}, --use OBJ_SHOVEL on OBJ_PILE_OF_COAL to OBJ_RAIL_CAR
[0]=use_tool_on_ground, --hole in ice, hole
}
function use_oil_on_door(obj, target_obj, actor)
if obj.obj_n == 235 and obj.frame_n ~= 4 then
printl("IT_HAS_NO_EFFECT")
return
end
if target_obj ~= nil then
if bit32.band(target_obj.quality, 0x80) == 0 then
printl("THIS_DOOR_IS_NOT_RUSTED")
else
target_obj.quality = bit32.band(target_obj.quality, 0x7f) --unset bit 7
printl("THE_DOOR_IS_UNSTUCK")
play_md_sfx(4)
if obj.stackable then
if obj.qty == 1 then
Obj.removeFromEngine(obj)
else
obj.qty = obj.qty - 1
end
else
Obj.removeFromEngine(obj)
end
end
end
end
function use_oil_on_dream_door(obj, target_obj, actor, target_x, target_y, target_z)
if map_get_tile_num(target_x, target_y, target_z) == 8 then
local melies = Actor.get(0x51)
Actor.set_talk_flag(melies, 6)
Actor.talk(melies)
finish_dream_quest(melies)
wake_from_dream()
else
printl("IT_HAS_NO_EFFECT")
end
end
function use_hand_mirror(obj, actor)
if actor.x >= 0x76 and actor.x <= 0x78 and actor.y >= 0xca and actor.y <= 0xcc and actor.z == 2 then
local lowell = Actor.get(0x50)
Actor.set_talk_flag(lowell, 6)
Actor.talk(lowell)
finish_dream_quest(lowell)
wake_from_dream()
else
printl("YOU_SEE_YOURSELF")
end
end
function use_radium(obj, target_obj, actor)
actor_radiation_check(actor, obj)
if obj.obj_n == 448 then --OBJ_BLOCK_OF_RADIUM
if target_obj.obj_n == 448 and target_obj.on_map then
local power_unit = map_get_obj(obj.x, obj.y, obj.z, 290) --OBJ_POWER_UNIT
if power_unit ~= nil then
target_obj = power_unit
end
end
if target_obj.obj_n == 290 then --OBJ_POWER_UNIT
if target_obj.frame_n == 1 then
printl("RADIUM_HAS_ALREADY_BEEN_INSTALLED")
else
Obj.removeFromEngine(obj)
play_md_sfx(4)
printl("THE_RADIUM_HAS_BEEN_INSTALLED")
target_obj.frame_n = 1
Actor.set_talk_flag(0x74, 2)
if Actor.get_talk_flag(0x74, 0) then
Actor.set_talk_flag(0x60, 2)
end
end
else
printl("IT_HAS_NO_EFFECT")
end
elseif obj.obj_n == 449 then --OBJ_CHIP_OF_RADIUM
if target_obj.qty < 0xf0 then
local qty = input_select_obj_qty(obj)
if qty == 0 then
return
end
if target_obj.qty + qty * 30 > 0xf0 then
qty = math.ceil((0xf0 - target_obj.qty) / 30)
printfl("THE_OBJ_ONLY_NEEDED_N_RADIUM_BLOCKS", target_obj.name, qty)
printfl("THE_OBJ_IS_FULLY_CHARGED", target_obj.name)
target_obj.qty = 0xf0
else
target_obj.qty = target_obj.qty + qty * 30
end
if obj.qty == qty then
Obj.removeFromEngine(obj)
else
obj.qty = obj.qty - qty
end
else
printfl("THE_OBJ_IS_FULLY_CHARGED", target_obj.name)
end
end
end
function use_head_gear(obj, target_obj, actor)
local machine
if target_obj.obj_n == 289 then --OBJ_DREAM_MACHINE2
local machine = map_get_obj(target_obj.x, target_obj.y, target_obj.z, 288)
if machine == nil then
printl("IT_HAS_NO_EFFECT")
return
end
else
machine = target_obj
end
local loc = machine.xyz
machine = Obj.new(100)
machine.frame_n = 1
Obj.moveToMap(machine, loc)
printl("THE_HEADGEAR_IS_INSTALLED")
Actor.set_talk_flag(0x74, 4)
if Actor.get_talk_flag(0x74, 0) then
Actor.set_talk_flag(0x60, 2)
end
end
function use_dream_machine(panel_obj)
if Actor.get_talk_flag(0x46, 3) then
printl("THE_DREAM_MACHINES_SEEM_TO_HAVE_CEASED_FUNCTIONING")
return
end
local z = panel_obj.z
local power_unit
local dream_quality
local headgear_installed = false
local seat_x, seat_y
for obj in find_obj_from_area(panel_obj.x - 5, panel_obj.y - 5, z, 11, 11) do
local obj_n = obj.obj_n
if obj_n == 290 and obj.frame_n == 1 then --OBJ_POWER_UNIT
power_unit = obj
elseif obj_n == 100 then --OBJ_DREAM_MACHINE
headgear_installed = true
elseif obj_n == 289 then --OBJ_DREAM_MACHINE2
seat_x = obj.x
seat_y = obj.y
elseif obj_n == 288 then --OBJ_DREAM_MACHINE2
dream_quality = obj.quality
end
end
local actor_in_seat = map_get_actor(seat_x, seat_y, z)
if power_unit == nil or dream_quality == nil or not headgear_installed then
printl("THE_MACHINE_DOES_NOT_WORK")
return
end
local martian_obj = map_get_obj(seat_x, seat_y, z, 291) --OBJ_UNCONSCIOUS_MARTIAN
if martian_obj ~= nil then
if Actor.get_talk_flag(0x21, 2) or not Actor.get_talk_flag(0x61, 4) then
printl("IT_HAS_NO_EFFECT")
else
play_midgame_sequence(5)
local martian = Actor.get(0x21)
Actor.talk(martian)
Actor.set_talk_flag(martian, 2)
martian.x = seat_x
martian.y = seat_y + 1
martian.z = panel_obj.z
kill_actor(martian)
Obj.removeFromEngine(martian_obj)
end
return
end
local metal_woman_obj = map_get_obj(seat_x, seat_y, z, 287) --OBJ_METAL_WOMAN
if metal_woman_obj ~= nil then
if metal_woman_obj.quality == 0 then
printl("IT_HAS_NO_EFFECT")
else
--FIXME implement metal woman activation logic
end
elseif actor_in_seat ~= nil then
if z ~= 0 then
wake_from_dream()
else
if dream_quality < 2 then
Actor.set_talk_flag(0x60, 3)
end
if dream_quality == 3 then
if Actor.get_talk_flag(0x46, 0) then
--FIXME call sub_3F624
else
printl("THE_MACHINE_DOES_NOT_WORK")
end
else
actor_use_dream_machine(actor_in_seat, dream_quality)
end
end
else
printl("THERE_IS_NOBODY_SITTING_IN_THE_MACHINE")
end
end
function use_sprayer_system(panel_obj)
end
function use_lens_controls(panel_obj)
end
function use_pump_controls(panel_obj)
end
local use_panel_tbl = {
[0]=function() printl("YOU_ARE_COMPLETELY_UNSURE_WHAT_YOU_JUST_DID") end,
[1]=function() printl("YOU_ACTUATE_THE_MECHANISM_TO_NO_APPARENT_EFFECT") end,
[2]=function() printl("STATUS_LIGHTS_CHANGE_BUT_YOU_SEE_NO_OTHER_EFFECT") end,
[3]=function() printl("LIGHTS_FLASH_AND_CHANGE_COLOR_BUT_NOTHING_ELSE_HAPPENS") end,
[4]=use_dream_machine,
[5]=use_sprayer_system,
[6]=use_lens_controls,
[7]=use_pump_controls,
}
function use_panel(obj, actor)
if bit32.band(obj.quality, 2) ~= 0 then
printl("THE_PANEL_IS_BROKEN")
return
end
if bit32.band(obj.quality, 1) ~= 0 then
printl("THE_PANEL_IS_NOT_INSTALLED")
return
end
local cabinet = map_get_obj(obj.x, obj.y, obj.z, 457) --OBJ_CABINET
if cabinet == nil then
printl("PANELS_ARE_ONLY_INSTALLED_ONTO_CABINETS")
return
end
local quality = cabinet.quality
if use_panel_tbl[quality] ~= nil then
use_panel_tbl[quality](obj)
else
printl("IT_HAS_NO_EFFECT")
end
end
function has_minotaur_left_the_shop(cur_z)
for i=1,0xff do
local actor = Actor.get(i)
if actor.obj_n == 398 then --OBJ_MINOTAUR
if actor.z == cur_z and not Actor.get_talk_flag(0x54, 6)
and actor.x >= 0x37 and actor.y <= 0x37 then
return true
end
end
end
return false
end
function use_switch(obj, actor)
local switch_qty = obj.qty
local switch_quality = obj.quality
local target_obj
local num_switches = 0
local switches = {}
for obj in find_obj_from_area(obj.x - 32, obj.y - 32, obj.z, 64, 64) do
if obj.obj_n == 179 or obj.obj_n == 227 then --OBJ_CLOSED_DOOR, OBJ_DOOR3
if bit32.band(obj.quality, 0x7f) == switch_qty then
target_obj = obj
end
elseif (obj.obj_n == 311 or obj.obj_n == 312 or obj.obj_n == 196) then --and obj.quality < 2 then
if num_switches < 4 then
num_switches = num_switches + 1
switches[num_switches] = obj
end
end
end
if target_obj == nil then
printl("STRANGELY_NOTHING_HAPPENS")
return
end
if num_switches == 0 then
printl("STRANGELY_IT_DOESNT_MOVE")
return
end
local frame_n = 0
if switch_quality == 1 then
if bit32.band(target_obj.quality, 0x80) == 0 then
target_obj.quality = bit32.bor(target_obj.quality, 0x80)
else
target_obj.quality = bit32.band(target_obj.quality, 0x7f)
frame_n = 1
end
else
local old_frame_n = target_obj.frame_n
target_obj.frame_n = bit32.band(old_frame_n, 2) + 5
play_door_sfx()
if old_frame_n < 4 then
target_obj.frame_n = bit32.band(old_frame_n, 2) + 9
frame_n = 1
else
target_obj.frame_n = bit32.band(old_frame_n, 2) + 1
if g_in_dream_mode and g_current_dream_stage == 0x44 and has_minotaur_left_the_shop(target_obj.z) then
complete_tiffany_stage()
return
end
end
play_door_sfx()
end
for i=1,num_switches do
switches[i].frame_n = frame_n
end
play_md_sfx(0x11)
end
function use_drawbridge_lever(obj, actor)
--FIXME
end
function use_cheat_lever(obj, actor)
--FIXME
end
function use_cheat_lever2(obj, actor)
--FIXME
end
local switch_qual_tbl = {
[1] = use_switch,
[2] = use_switch,
[10] = use_drawbridge_lever,
[20] = use_cheat_lever,
[21] = use_cheat_lever2,
}
function use_switch_device(obj, actor)
if switch_qual_tbl[obj.quality] ~= nil then
switch_qual_tbl[obj.quality](obj, actor)
else
printl("WHAT_AN_ODD_LEVER")
end
end
function use_dreamstuff(obj, actor)
printl("YOU_IMAGINE")
for item in container_objs(obj) do
if item.obj_n < 342 then -- OBJ_POOR_MONK
--object
print(item.look_string.."\n")
if obj.on_map then
Obj.moveToMap(item, obj.xyz)
else
local parent = obj.parent
if parent.luatype == "actor" then
Obj.moveToInv(item, parent.actor_num)
else
Obj.moveToCont(item, parent)
end
end
else
--actor
print(item.name.."\n")
local spawned_actor = Actor.new(item.obj_n, actor.x, actor.y, actor.z)
actor_init(spawned_actor, obj.quality + 1) -- alignment
toss_actor(spawned_actor, actor.x, actor.y, actor.z)
spawned_actor.wt = item.quality
end
Obj.removeFromEngine(obj)
return
end
printl("NOTHING")
end
function use_obj_on_spray_gun(obj, target_obj, actor)
if obj.obj_n == 119 and target_obj.quality == 0 then --OBJ_BOTTLE_OF_GREEN_PAINT
target_obj.quality = 1
target_obj.qty = 20
printl("SPRAY_GUN_GREEN_PAINT")
elseif obj.obj_n == 128 and target_obj.quality ~= 0 then --OBJ_WEED_KILLER
target_obj.quality = 0
target_obj.qty = 10
printl("SPRAY_GUN_WEED_KILLER")
else
local spray_gun_qty = target_obj.qty + 10
if spray_gun_qty > 0x1e then
spray_gun_qty = 0x1e
end
target_obj.qty = spray_gun_qty
printl("SPRAY_GUN_10_MORE_CHARGES")
end
Obj.removeFromEngine(obj)
end
function use_spray_gun(obj, target_obj, actor)
if obj.qty == 0 then
printl("THERE_IS_NOTHING_IN_THE_GUN")
return
end
if obj.quality ~= 0 then
obj.qty = obj.qty - 1
if target_obj.luatype == "actor" and target_obj.obj_n == 145 then --OBJ_MONSTER_FOOTPRINTS
target_obj.obj_n = 364 --OBJ_PROTO_MARTIAN
printfl("BECOMES_VISIBLE", target_obj.name)
else
if target_obj.luatype == "actor" and not target_obj.visible then
target_obj.visible = true
printfl("BECOMES_VISIBLE", target_obj.name)
elseif target_obj.luatype == "obj" and target_obj.invisible then
target_obj.invisible = false
printfl("BECOMES_VISIBLE", target_obj.name)
else
printl("IT_HAS_NO_EFFECT")
end
end
elseif target_obj.luatype == "actor" then
attack_target_with_weapon(actor, target_obj.x, target_obj.y, obj)
elseif is_plant_obj(target_obj) then
hit_target(target_obj, RED_HIT_TILE)
printl("YOU_KILLED_THE_PLANT")
if target_obj.obj_n == 205 then --OBJ_VINE
Actor.set_talk_flag(0x30, 7)
Obj.removeFromEngine(target_obj)
elseif target_obj.obj_n == 408 then --OBJ_TREE
target_obj.obj_n = 166 --OBJ_DEAD_TREE
else
Obj.removeFromEngine(target_obj)
end
else
obj.qty = obj.qty - 1
printl("IT_HAS_NO_EFFECT")
end
end
local usecode_table = {
--OBJ_RUBY_SLIPPERS
[12]=use_ruby_slippers,
--OBJ_RUBBER_GLOVES
[38]=use_ready_obj,
--OBJ_SLEDGE_HAMMER
[52]={
--on
[404]={ --OBJ_REPLACEMENT_TRACK
--to
[405]=use_sledge_hammer_on_replacement_track_to_broken_track
}
},
--OBJ_PLIERS
[53]={
--on
[199]={--OBJ_CABLE_SPOOL
--to
[201]=use_pliers_on_spool_to_tower, --OBJ_TOWER_TOP
[215]=use_pliers_on_spool_to_tower, --OBJ_POWER_CABLE1
}
},
--OBJ_PICK
[65]={[255]=use_misc_text,[257]=use_misc_text}, --hole in ice, hole
--OBJ_SHOVEL
[66]=use_shovel_on_tbl,
--OBJ_HOE
[67]={[255]=use_misc_text,[257]=use_misc_text}, --hole in ice, hole
--OBJ_BERRY
[73]=use_berry,
--OBJ_BERRY1
[74]=use_berry,
--OBJ_BERRY2
[75]=use_berry,
--OBJ_BERRY3
[76]=use_berry,
--OBJ_BERRY4
[77]=use_red_berry,
--OBJ_CLUMP_OF_ROUGE_BERRIES
[78]=use_misc_text,
[86]=use_container,
[87]=use_container,
--OBJ_MANUSCRIPT
[88]={
--on
[84]=use_manuscript_on_mailbox, --OBJ_MAILBOX
},
[96]=use_sextant,
[102]={[86]=use_crate,[427]=use_prybar_on_hatch},
[104]=use_container,
--OBJ_FOLDED_TENT
[106]=use_tent,
--OBJ_BOTTLE_OF_GREEN_PAINT
[119]={
--on
--OBJ_WEED_SPRAYER
[129]=use_obj_on_spray_gun,
--OBJ_SPRAY_GUN
[261]=use_obj_on_spray_gun,
},
--OBJ_CAN_OF_LAMP_OIL
[124]={
--on
--OBJ_CLOSED_DOOR
[179]=use_oil_on_door,
--OBJ_DOOR3
[227]=use_oil_on_door,
--OBJ_CLOSED_HATCH
[421]=use_oil_on_door,
--OBJ_DOOR
[152]=use_oil_on_door,
--OBJ_DOOR1
[219]=use_oil_on_door,
--OBJ_DOOR2
[222]=use_oil_on_door,
[0]=use_oil_on_dream_door,
},
--OBJ_WEED_KILLER
[128]={
--on
--OBJ_WEED_SPRAYER
[129]=use_obj_on_spray_gun,
--OBJ_SPRAY_GUN
[261]=use_obj_on_spray_gun,
},
--OBJ_WEED_SPRAYER
[129]={
--on
[0]=use_spray_gun
},
--OBJ_BLOB_OF_OXIUM
[131]=use_misc_text,
--OBJ_WRENCH
[135]={
--on
[411]=use_wrench_on_switchbar,
[440]=use_wrench_on_drill,
[458]=use_wrench_on_panel
},
--OBJ_TONGS
[136]=use_ready_obj,
--OBJ_REPAIRED_BELT
[144]={
--on
[192]=use_fixed_belt_on_bare_rollers,
},
--OBJ_HAND_MIRROR
[147]=use_hand_mirror,
--OBJ_BOOK
[148]=use_reading_material,
--OBJ_NOTE
[151]=use_reading_material,
--OBJ_DOOR
[152]=use_door,
[181]=use_gate,
--OBJ_CAMERA
[184]=use_misc_text,
--OBJ_LEVER
[196]=use_switch_device,
--OBJ_CABLE_SPOOL
[199]=use_misc_text,
[212]=use_oxium_bin,
[222]=use_door,
--OBJ_GONG_HAMMER
[231]={
--on
[130]=use_hammer_on_oxium_geode, --OBJ_OXIUM_GEODE
[298]=use_gong, --OBJ_GONG
--FIXME OBJ_BRASS_CHEST, OBJ_OBSIDIAN_BOX, OBJ_STEAMER_TRUNK, OBJ_OPEN_BRASS_TRUNK use_crate
},
--OBJ_POTASH (this is actually oil when frame_n == 4)
[235]={
--on
--OBJ_CLOSED_DOOR
[179]=use_oil_on_door,
--OBJ_DOOR3
[227]=use_oil_on_door,
--OBJ_CLOSED_HATCH
[421]=use_oil_on_door,
--OBJ_DOOR
[152]=use_oil_on_door,
--OBJ_DOOR1
[219]=use_oil_on_door,
--OBJ_DOOR2
[222]=use_oil_on_door,
[0]=use_oil_on_dream_door,
},
--OBJ_SCROLL
[243]=use_reading_material,
--OBJ_SPRAY_GUN
[261]={
--on
[0]=use_spray_gun
},
--OBJ_MARTIAN_HOE
[263]={[255]=use_misc_text,[257]=use_misc_text}, --hole in ice, hole
--OBJ_MARTIAN_SHOVEL
[267]=use_shovel_on_tbl,
[273]={[86]=use_crate}, --Hammer needs more codes
--OBJ_CYMBALS
[280]=use_musical_instrument,
--OBJ_TAMBORINE
[281]=use_musical_instrument,
--OBJ_DRUM
[282]=use_musical_instrument,
--OBJ_ACCORDION
[283]=use_musical_instrument,
[284]=use_container,
--OBJ_SPITTOON
[286]=use_spittoon,
--OBJ_DREAM_MACHINE1
[288]=use_misc_text,
--OBJ_MARTIAN_CLOCK
[293]=use_misc_text,
--OBJ_HEADGEAR
[296]={
--on
[288]=use_head_gear, --OBJ_DREAM_MACHINE1
[289]=use_head_gear, --OBJ_DREAM_MACHINE2
},
--OBJ_SWITCH
[311]=use_switch_device,
--OBJ_SWITCH1
[312]=use_switch_device,
--OBJ_OXYGENATED_AIR_MACHINE
[323]=use_misc_text,
--OBJ_MARTIAN_PICK
[327]={[255]=use_misc_text,[257]=use_misc_text}, --hole in ice, hole
[331]=use_dreamstuff,
[399]=use_pool_table,
--OBJ_POOL_QUE
[401]=use_ready_obj,
[411]=use_switch_bar,
--OBJ_CLOSED_HATCH
[421]=use_door,
--OBJ_HEART_STONE
[426]={
--on
[287]= use_heartstone_on_metal_woman, --OBJ_METAL_WOMAN
},
[427]=use_misc_text,
--OBJ_ASSEMBLED_DRILL
[441]=use_assembled_drill,
--OBJ_PILE_OF_ROCKS
[442]=use_misc_text,
--OBJ_PILE_OF_IRON_ORE
[443]=use_misc_text,
--OBJ_PILE_OF_COAL
[444]=use_misc_text,
--OBJ_BLOCK_OF_RADIUM
[448]={
--on
[290]=use_radium, --OBJ_POWER_UNIT
[448]=use_radium, --OBJ_BLOCK_OF_RADIUM
},
--OBJ_CHIP_OF_RADIUM
[449]={
--on
[240]=use_radium, --OBJ_HEAT_RAY_GUN
[241]=use_radium, --OBJ_FREEZE_RAY_GUN
},
--OBJ_PANEL
[458]=use_panel,
}
function ready_winged_shoes(obj, actor)
local player_loc = player_get_location()
if player_loc.z == 2 then
local bridge = Obj.new(146)
bridge.temporary = false
Obj.moveToMap(bridge, 0xc9, 0x9b, 2)
end
return true
end
function ready_tongs(obj, actor)
printl("THE_TONGS_WILL_NOW_PROTECT_YOUR_HANDS")
return true
end
function ready_throw_rug(obj, actor)
obj.obj_n = 162 --Change to red cape
return true
end
local usecode_ready_obj_table = {
[15]=ready_winged_shoes,
[136]=ready_tongs,
[161]=ready_throw_rug,
}
function unready_winged_shoes(obj, actor)
printl("THEY_WONT_COME_OFF")
return false
end
local usecode_unready_obj_table = {
[15]=unready_winged_shoes,
}
function move_drill(obj, rel_x, rel_y)
if rel_x ~= 0 and rel_y ~= 0 then
return false
end
if rel_x < 0 then
obj.frame_n = 1
elseif rel_x > 0 then
obj.frame_n = 4
elseif rel_y < 0 then
obj.frame_n = 3
elseif rel_y > 0 then
obj.frame_n = 5
end
return true
end
function move_wheelbarrow(obj, rel_x, rel_y)
if rel_x ~= 0 and rel_y ~= 0 then
return false
end
if rel_x < 0 then
obj.frame_n = 3
elseif rel_x > 0 then
obj.frame_n = 1
elseif rel_y < 0 then
obj.frame_n = 0
elseif rel_y > 0 then
obj.frame_n = 2
end
return true
end
function move_rail_cart(obj, rel_x, rel_y)
local frame_n = obj.frame_n
if rel_x ~= 0 and rel_y ~= 0 then
printl("IT_WONT_GO_IN_THAT_DIRECTION")
return false
end
if (rel_x < 0 or rel_x > 0) and (frame_n == 1 or frame_n == 3 or frame_n == 5) then
printl("IT_WONT_GO_IN_THAT_DIRECTION")
return false
end
if (rel_y < 0 or rel_y > 0) and (frame_n == 0 or frame_n == 2 or frame_n == 4) then
printl("IT_WONT_GO_IN_THAT_DIRECTION")
return false
end
if check_for_track(obj, rel_x, rel_y) == false then
printl("IT_WONT_GO_IN_THAT_DIRECTION")
return false
end
move_car_obj(obj, rel_x, rel_y)
return false
end
function check_for_track(car, rel_x, rel_y)
local x = car.x + rel_x
local y = car.y + rel_y
for obj in objs_at_loc(x, y, car.z) do
if (obj.obj_n >= 412 and obj.obj_n <= 414) or obj.obj_n == 419 or obj.obj_n == 175 or obj.obj_n == 163 then --track object
local track_frame_n = obj.frame_n
if (car.frame_n % 2) == track_frame_n or track_frame_n == 2 or obj.obj_n == 412 or obj.obj_n == 175 or obj.obj_n == 163 then
return true
else
return false
end
elseif is_blood(obj.obj_n) == false and obj.obj_n ~= 417 then --MARTIAN_BARGE
return false
end
end
if map_get_obj(x, y, car.z, 175, true) then
return true
end
if map_get_obj(x, y, car.z, 412, true) then
return true
end
local tile_num = map_get_tile_num(x,y, car.z)
if is_track_tile(tile_num) then
return true
end
return false
end
function move_car_obj(obj, rel_x, rel_y)
obj.x = obj.x + rel_x
obj.y = obj.y + rel_y
return true
end
function move_plank(obj, rel_x, rel_y)
obj.x = obj.x + rel_x
obj.y = obj.y + rel_y
return true
end
function is_track_tile(tile_num)
if tile_num == 108 or tile_num == 109 or tile_num == 110 or tile_num == 77 or tile_num == 79 then
return true
end
return false
end
local usecode_move_obj_table = {
[268]=move_wheelbarrow,
[395]=move_plank,
[410]=move_rail_cart,
[441]=move_drill,
}
function has_usecode(obj, usecode_type)
--print("has_usecode("..obj.obj_n..", "..usecode_type..")\n")
if usecode_type == USE_EVENT_USE and usecode_table[obj.obj_n] ~= nil then
return true
elseif usecode_type == USE_EVENT_READY and (usecode_ready_obj_table[obj.obj_n] ~= nil or usecode_unready_obj_table[obj.obj_n] ~= nil)then
return true
elseif usecode_type == USE_EVENT_MOVE and usecode_move_obj_table[obj.obj_n] ~= nil then
return true
end
return false
end
function use_obj_on_to(obj, target_obj, actor, use_to_tbl)
local dir = get_direction(i18n("TO"))
if dir == nil then
printl("NOTHING")
return
end
local to_x, to_y = direction_get_loc(dir, actor.x, actor.y)
local to_obj = map_get_obj(to_x, to_y, actor.z)
if to_obj ~= nil then
print(to_obj.name.."\n\n")
local func = use_to_tbl[to_obj.obj_n]
if func ~= nil then
func(obj, target_obj, to_obj, actor)
end
else
printl("SOMETHING")
end
end
function use_obj_on(obj, actor, use_on_tbl)
local dir = get_direction(i18n("ON"))
if dir == nil then
printl("NOTHING")
return
end
local target_x, target_y = direction_get_loc(dir, actor.x, actor.y)
local target_entity = map_get_actor(target_x, target_y, actor.z)
if target_entity == nil then
target_entity = map_get_obj(target_x, target_y, actor.z)
end
if target_entity ~= nil then
print(target_entity.name.."\n\n")
local on = use_on_tbl[target_entity.obj_n]
if on ~= nil then
if type(on) == "function" then
local func = on
func(obj, target_entity, actor)
else
use_obj_on_to(obj, target_entity, actor, on)
end
else
local func = use_on_tbl[0]
if func ~= nil then
func(obj, target_entity, actor)
else
printl("NO_EFFECT")
end
end
else
local func = use_on_tbl[0]
if func ~= nil then
func(obj, nil, actor, target_x, target_y, actor.z)
else
printl("NOTHING")
end
end
end
function can_interact_with_obj(actor, obj)
if obj.on_map then
--FIXME get_combat_range()
local distance = actor_find_max_wrapped_xy_distance(actor, obj.x, obj.y)
if actor_is_affected_by_purple_berries(actor.actor_num) and distance <= actor.level then
return true
end
if distance > 1 then
printl("OUT_OF_RANGE")
return false
end
end
return true
end
function use_obj(obj, actor)
if not can_interact_with_obj(actor, obj) then
return
end
if type(usecode_table[obj.obj_n]) == "function" then
local func = usecode_table[obj.obj_n]
if func ~= nil then
print("\n")
func(obj, actor)
end
else
use_obj_on(obj, actor, usecode_table[obj.obj_n])
end
update_objects_around_party()
end
function ready_obj(obj, actor)
if type(usecode_ready_obj_table[obj.obj_n]) == "function" and obj.readied == false then
local func = usecode_ready_obj_table[obj.obj_n]
if func ~= nil then
print("\n")
return func(obj, actor)
end
end
if type(usecode_unready_obj_table[obj.obj_n]) == "function" and obj.readied == true then
local func = usecode_unready_obj_table[obj.obj_n]
if func ~= nil then
print("\n")
return func(obj, actor)
end
end
return true
end
function move_obj(obj, rel_x, rel_y)
if usecode_move_obj_table[obj.obj_n] ~= nil then
return usecode_move_obj_table[obj.obj_n](obj, rel_x, rel_y)
end
return true
end
function is_ranged_select(operation)
return actor_is_affected_by_purple_berries(Actor.get_player_actor().actor_num)
end