Files
scummvm-cursorfix/devtools/create_ultima/files/ultima6/scripts/u6/init.lua
2026-02-02 04:50:13 +01:00

575 lines
13 KiB
Lua

local lua_file = nil
--load common functions
lua_file = nuvie_load("common/common.lua"); lua_file();
SFX_BLOCKED = 0
SFX_HIT = 1
SFX_FOUNTAIN = 2
SFX_DEATH = 3
SFX_RUBBER_DUCK = 4
SFX_BROKEN_GLASS = 5
SFX_BELL = 6
SFX_FIRE = 7
SFX_CLOCK = 8
SFX_PROTECTION_FIELD = 9
SFX_WATER_WHEEL = 10
SFX_MISSLE = 11
SFX_EXPLOSION = 12
SFX_ATTACK_SWING = 13
SFX_SUCCESS = 14
SFX_FAILURE = 15
SFX_CORPSER_DRAGGED_UNDER = 16
SFX_CORPSER_REGURGITATE = 17
SFX_CASTING_MAGIC_P1 = 18
SFX_CASTING_MAGIC_P1_2 = 19
SFX_CASTING_MAGIC_P1_3 = 20
SFX_CASTING_MAGIC_P1_4 = 21
SFX_CASTING_MAGIC_P1_5 = 22
SFX_CASTING_MAGIC_P1_6 = 23
SFX_CASTING_MAGIC_P1_7 = 24
SFX_CASTING_MAGIC_P1_8 = 25
SFX_CASTING_MAGIC_P2 = 26
SFX_CASTING_MAGIC_P2_2 = 27
SFX_CASTING_MAGIC_P2_3 = 28
SFX_CASTING_MAGIC_P2_4 = 29
SFX_CASTING_MAGIC_P2_5 = 30
SFX_CASTING_MAGIC_P2_6 = 31
SFX_CASTING_MAGIC_P2_7 = 32
SFX_CASTING_MAGIC_P2_8 = 33
SFX_AVATAR_DEATH = 34
SFX_KAL_LOR = 35
SFX_SLUG_DISSOLVE = 36
SFX_HAIL_STONE = 37
SFX_EARTH_QUAKE = 39
FADE_COLOR_RED = 12
FADE_COLOR_BLUE = 9
TIMER_LIGHT = 0
TIMER_INFRAVISION = 1
TIMER_STORM = 13
TIMER_TIME_STOP = 14
TIMER_ECLIPSE = 15
OBJLIST_OFFSET_VANISH_OBJ = 0x1c13
OBJLIST_OFFSET_MOONSTONES = 0x1c1b
OBJLIST_OFFSET_KEG_TIMER = 0x1c4b
g_vanish_obj = {["obj_n"] = 0, ["frame_n"] = 0}
g_keg_timer = 0
g_armageddon = false
g_avatar_died = false -- used so we don't keep casting once Avatar is dead
function is_avatar_dead()
return g_avatar_died
end
--used with triple crossbow and magic wind spells.
g_projectile_offset_tbl =
{
{
4,5,5,5,5,6,6,6,6,6,6,
4,4,5,5,5,6,6,6,6,6,7,
4,4,4,5,5,6,6,6,6,7,7,
4,4,4,4,5,6,6,6,7,7,7,
4,4,4,4,4,6,6,7,7,7,7,
4,4,4,4,4,0,0,0,0,0,0,
3,3,3,3,2,2,0,0,0,0,0,
3,3,3,2,2,2,1,0,0,0,0,
3,3,2,2,2,2,1,1,0,0,0,
3,2,2,2,2,2,1,1,1,0,0,
2,2,2,2,2,2,1,1,1,1,0
},
{
2,2,2,2,2,2,3,3,3,3,4,
1,2,2,2,2,2,3,3,3,4,4,
1,1,2,2,2,2,3,3,4,4,4,
1,1,1,2,2,2,3,4,4,4,4,
1,1,1,1,2,2,4,4,4,4,4,
0,0,0,0,0,0,4,4,4,4,4,
0,0,0,0,0,6,6,5,5,5,5,
0,0,0,0,7,6,6,6,5,5,5,
0,0,0,7,7,6,6,6,6,5,5,
0,0,7,7,7,6,6,6,6,6,5,
0,7,7,7,7,6,6,6,6,6,6
}
}
--moonstone data is loaded from objlist in load_game()
g_moonstone_loc_tbl =
{
{x=0x3A7, y=0x106, z=0},
{x=0x1F7, y=0x166, z=0},
{x=0x9F, y=0x3AE, z=0},
{x=0x127, y=0x26, z=0},
{x=0x33F, y=0x0A6, z=0},
{x=0x147, y=0x336, z=0},
{x=0x17, y=0x16, z=1},
{x=0x397, y=0x3A6, z=0}
}
g_show_stealing = config_get_boolean_value("config/ultima6/show_stealing")
-- some common functions
function set_g_show_stealing(stealing)
g_show_stealing = stealing
end
function dbg(msg_string)
--io.stderr:write(msg_string)
end
function alignment_is_evil(align)
if align == ALIGNMENT_EVIL or align == ALIGNMENT_CHAOTIC then return true end
return false
end
function advance_game_time(nturns)
if nturns == 0 then return end
coroutine.yield("adv_game_time", nturns);
end
function get_obj_from_inventory(actor)
local obj = coroutine.yield("inv_obj", actor)
return obj
end
function get_obj()
local obj = coroutine.yield("obj")
return obj
end
function actor_talk(actor)
coroutine.yield("talk", actor)
return
end
function get_spell()
local spell_num = coroutine.yield("spell")
return spell_num
end
function obj_new(obj_n, frame_n, status, qty, quality, x, y, z)
local obj = {}
obj["obj_n"] = obj_n or 0
obj["frame_n"] = frame_n or 0
obj["status"] = status or 0
obj["qty"] = qty or 0
obj["quality"] = quality or 0
obj["x"] = x or 0
obj["y"] = y or 0
obj["z"] = z or 0
return obj
end
--FIXME need a better way of doing this. Remove need for deprecated setfenv() function.
function run_script(script)
local t = {};
setmetatable(t, {__index = _G});
local body = nuvie_load(script);
setfenv(body, t);
body();
end
function look_obj(obj)
print("Thou dost see " .. obj.look_string);
local weight = obj.weight; --FIXME this could be a problem if we want to change Lua_number type to int.
if weight ~= 0 then
if obj.qty > 1 and obj.stackable then
print(". They weigh");
else
print(". It weighs");
end
print(string.format(" %.1f", weight).." stones");
end
--FIXME usecode look description should be lua code.
if usecode_look(obj) then
print("\n")
return false
end
local dmg = weapon_dmg_tbl[obj.obj_n];
if dmg ~= nil then
if weight ~= 0 then
print(" and")
else
print(". It")
end
print(" can do "..dmg.." point")
if dmg > 1 then print("s") end
print(" of damage")
end
local ac = armour_tbl[obj.obj_n]
if ac ~= nil then
if weight ~= 0 or dmg ~= 0 then
print(" and")
else
print(". It")
end
print(" can absorb "..ac.." point")
if ac > 1 then print("s") end
print(" of damage")
end
print(".\n");
local player_loc = player_get_location();
if g_show_stealing == true and obj.getable == true and player_loc.z == 0 and obj.ok_to_take == false then
if math.abs(player_loc.x - obj.x) > 1 or math.abs(player_loc.y - obj.y) > 1 then
print("PRIVATE PROPERTY\n")
else
print("PRIVATE PROPERTY")
end
end
return true
end
function player_subtract_karma(k)
local karma = player_get_karma() - k
if karma < 0 then karma = 0 end
player_set_karma(karma)
end
function player_add_karma(k)
local karma = player_get_karma() + k
if karma >= 100 then karma = 99 end
player_set_karma(karma)
end
function party_heal()
for actor in party_members() do
actor.asleep = false
actor.poisoned = false
actor.paralyzed = false
actor_remove_charm(actor)
actor.hp = actor.max_hp
end
end
function explosion(tile_num, x, y)
play_sfx(SFX_EXPLOSION)
return explosion_start(tile_num, x, y)
end
function projectile(tile_num, start_x, start_y, end_x, end_y, speed, spin)
if spin == nil then spin = 0 end
local rotate_offset = 0
local src_tile_y_offset = 0
if tile_num == 547 then --spear
rotate_offset = 45
elseif tile_num == 566 then --bow
rotate_offset = 90
src_tile_y_offset = 4
elseif tile_num == 567 then --crossbow
rotate_offset = 90
src_tile_y_offset = 3
end
play_sfx(SFX_MISSLE)
projectile_anim(tile_num, start_x, start_y, end_x, end_y, speed, false, rotate_offset, spin, src_tile_y_offset)
end
function fade_obj_blue(obj)
fade_obj(obj, FADE_COLOR_BLUE, 20)
end
function fade_actor_blue(actor)
Actor.black_fade_effect(actor, FADE_COLOR_BLUE, 20)
end
function fade_obj_out(obj)
obj.invisible = true
fade_tile(obj.x, obj.y, obj.z, obj.tile_num)
obj.invisible = false
end
function fade_obj_in(obj)
obj.invisible = true
fade_tile(obj.x, obj.y, obj.z, nil, obj.tile_num)
obj.invisible = false
end
function fade_actor_in(actor)
local new_tile_num = actor.tile_num
actor.visible = false
fade_tile(actor.x, actor.y, actor.z, nil, new_tile_num)
actor.visible = true
end
--tile_num, readied location
local g_readiable_objs_tbl = {
[0x200] = 0, [0x201] = 0, [0x202] = 0, [0x203] = 0, [0x204] = 0, [0x205] = 0, [0x206] = 0, [0x207] = 0,
[0x219] = 1, [0x250] = 1, [0x251] = 1, [0x252] = 1, [0x217] = 1, [0x101] = 1,
[0x220] = 2, [0x221] = 2, [0x223] = 2, [0x224] = 2, [0x225] = 2, [0x226] = 2, [0x227] = 2, [0x22A] = 2,
[0x22F] = 2, [0x230] = 2, [0x238] = 2, [0x254] = 2, [0x256] = 2, [0x255] = 2, [0x259] = 2, [0x262] = 2,
[0x263] = 2, [0x264] = 2, [0x270] = 2, [0x271] = 2, [0x272] = 2, [0x273] = 2, [0x274] = 2, [0x275] = 2,
[0x279] = 2, [0x27D] = 2, [0x27E] = 2, [0x27F] = 2, [0x280] = 2, [0x281] = 2, [0x28C] = 2, [0x28E] = 2,
[0x29D] = 2, [0x2A2] = 2, [0x2A3] = 2, [0x2B9] = 2,
[0x210] = 4, [0x211] = 4, [0x212] = 4, [0x213] = 4, [0x214] = 4, [0x215] = 4, [0x216] = 4, [0x218] = 4,
[0x219] = 4, [0x28c] = 4, [0x28e] = 4, [0x29d] = 4, [0x257] = 4,
[0x208] = 5, [0x209] = 5, [0x20a] = 5, [0x20b] = 5, [0x20c] = 5, [0x20d] = 5, [0x20e] = 5, [0x20f] = 5,
[0x222] = 5,
[0x21a] = 7, [0x21b] = 7,
[0x228] = 8, [0x229] = 8, [0x231] = 8, [0x235] = 8, [0x22b] = 8, [0x22c] = 8, [0x22d] = 8, [0x22e] = 8,
[0x258] = 9, [0x37d] = 9, [0x37e] = 9, [0x37f] = 9
}
function actor_is_readiable_obj(actor)
if g_readiable_objs_tbl[actor.tile_num] ~= nil then
return true
end
return false
end
function obj_is_readiable(obj)
if g_readiable_objs_tbl[obj.tile_num] ~= nil then
return true
end
return false
end
function is_time_stopped()
if timer_get(TIMER_TIME_STOP) ~= 0 then return true end
return false
end
function load_game()
objlist_seek(OBJLIST_OFFSET_VANISH_OBJ)
local tmp_obj_dat = objlist_read2()
local obj_n = tmp_obj_dat
local frame_n = 0
if tmp_obj_dat > 1023 then
frame_n = tmp_obj_dat - 1023
obj_n = tmp_obj_dat - frame_n
end
g_vanish_obj.obj_n = obj_n
g_vanish_obj.frame_n = frame_n
--Load moonstone locations.
objlist_seek(OBJLIST_OFFSET_MOONSTONES)
for i=1,8 do
local x = objlist_read2()
local y = objlist_read2()
local z = objlist_read2()
dbg("moonstone["..i.."] at ("..x..","..y..","..z..")\n")
g_moonstone_loc_tbl[i] = {x=x, y=y, z=z}
end
objlist_seek(OBJLIST_OFFSET_KEG_TIMER)
g_keg_timer = objlist_read2()
set_g_armageddon(false)
g_avatar_died = false
end
function save_game()
objlist_seek(OBJLIST_OFFSET_VANISH_OBJ)
local tmp_obj_dat = g_vanish_obj.obj_n
local frame_n = g_vanish_obj.frame_n
if frame_n > 0 then
tmp_obj_dat = tmp_obj_dat + (frame_n + 1023)
end
objlist_write2(tmp_obj_dat)
--Save moonstone locations
objlist_seek(OBJLIST_OFFSET_MOONSTONES)
for i=1,8 do
local loc = g_moonstone_loc_tbl[i]
objlist_write2(loc.x)
objlist_write2(loc.y)
objlist_write2(loc.z)
end
objlist_seek(OBJLIST_OFFSET_KEG_TIMER)
objlist_write2(g_keg_timer)
end
function moonstone_set_loc(phase, x, y, z)
if phase < 1 or phase > 8 then return false end
g_moonstone_loc_tbl[phase] = {x=x, y=y, z=z}
return true
end
function moonstone_get_loc(phase)
if phase < 1 or phase > 8 then return nil end
return g_moonstone_loc_tbl[phase]
end
function update_moongates(show_moongates)
local i, loc
for i,loc in ipairs(g_moonstone_loc_tbl) do
local moongate = map_get_obj(loc.x, loc.y, loc.z, 0x55) --moongate
if show_moongates == true then
if moongate == nil and loc.x ~= 0 then
moongate = Obj.new(0x55, 1)
Obj.moveToMap(moongate, loc)
end
else --hide moongate
if moongate ~= nil then
map_remove_obj(moongate)
end
end
end
end
function use_keg(obj)
if obj.frame_n ~= 0 then
print("\nNo effect\n")
return
end
if g_keg_timer > 0 then
print("\nNot now\n")
else
obj.frame_n = 1
print("\nPowder lit!\n")
g_keg_timer = 3
end
end
function explode_keg()
--try to find lit keg on the current game map.
local loc = player_get_location()
for obj in find_obj(loc.z, 223, 1) do --keg obj, frame_n = 1
if obj ~= nil then
explode_obj(obj)
end
end
--try to explode lit kegs in the party's inventory
local party_actor
for party_actor in party_members() do
local obj = Actor.inv_get_obj_n(party_actor, 223, 1) --keg with frame_n = 1
if obj ~= nil then
explode_obj(obj, party_actor)
end
end
end
function explode_obj(obj, actor)
dbg("Exploding "..obj.name.."\n")
local x, y, z
if actor ~= nil then
x = actor.x
y = actor.y
z = actor.z
else
x = obj.x
y = obj.y
z = obj.z
end
Obj.removeFromEngine(obj)
local hit_items = explosion(0x189, x, y)
local random = math.random
local k, v
for k,v in pairs(hit_items) do
if v.luatype == "actor" then
actor_hit(v, random(1, 0x3c))
end
if g_avatar_died == true then
explode_surrounding_objects(x, y, z)
actor_avatar_death(Actor.get(1))
return -- don't keep exploding once Avatar is dead
end
end
explode_surrounding_objects(x, y, z)
end
function explode_surrounding_objects(x, y, z)
--blow up doors and other kegs
for x = x - 2,x + 2 do
for y = y - 2,y + 2 do
local map_obj = map_get_obj(x, y, z, 223)
if map_obj ~= nil then
explode_obj(map_obj)
end
map_obj = map_get_obj(x, y, z, 0x12c) --steel door
if map_obj == nil or map_obj.frame_n == 0xc then
map_obj = map_get_obj(x, y, z, 0x129) --oaken door
if map_obj == nil or map_obj.frame_n == 0xc then
map_obj = map_get_obj(x, y, z, 0x12a) --windowed door
if map_obj == nil or map_obj.frame_n == 0xc then
map_obj = map_get_obj(x, y, z, 0x12b) --cedar door
end
end
end
if map_obj ~= nil and map_obj.frame_n <= 0xc then
Obj.removeFromEngine(map_obj)
print("\nThe door is blown up!\n")
end
end
end
end
function set_g_armageddon(val)
g_armageddon = val
set_armageddon(val)
end
function create_object_needs_quan(obj_n)
-- obj.stackable is already checked
return false
end
--load actor functions
actor_load = nuvie_load("u6/actor.lua");
if type(actor_load) == "function" then
actor_load()
else
if type(actor_load) == "string" then
io.stderr:write(actor_load);
end
end
-- init magic
magic_init = nuvie_load("u6/magic.lua"); magic_init();
-- init usecode
usecode_init = nuvie_load("u6/usecode.lua"); usecode_init();
player_init = nuvie_load("u6/player.lua"); player_init();