noita_entangled_worlds/quant.ew/init.lua

445 lines
16 KiB
Lua
Raw Normal View History

2024-04-29 22:14:22 +03:00
dofile_once("mods/quant.ew/NoitaPatcher/load.lua")
2024-08-09 13:13:08 +03:00
np = require("noitapatcher")
2024-04-29 22:14:22 +03:00
package.cpath = package.cpath .. ";./mods/quant.ew/?.dll"
package.path = package.path .. ";./mods/quant.ew/?.lua"
print(package.cpath)
2024-04-29 22:14:22 +03:00
dofile_once( "data/scripts/lib/utilities.lua" )
dofile_once("mods/quant.ew/files/system/player/player_cosmetics.lua")
2024-04-29 22:14:22 +03:00
np.InstallShootProjectileFiredCallbacks()
np.EnableGameSimulatePausing(false)
np.InstallDamageDetailsPatch()
np.SilenceLogs("Warning - streaming didn\'t find any chunks it could stream away...\n")
ewext = require("ewext0")
2024-09-23 19:48:56 +03:00
2024-08-09 13:13:08 +03:00
-- Make some stuff global, as it's way too annoying to import each time.
ctx = dofile_once("mods/quant.ew/files/core/ctx.lua")
player_fns = dofile_once("mods/quant.ew/files/core/player_fns.lua")
net = dofile_once("mods/quant.ew/files/core/net.lua")
util = dofile_once("mods/quant.ew/files/core/util.lua")
inventory_helper = dofile_once("mods/quant.ew/files/core/inventory_helper.lua")
2024-08-13 14:18:45 +03:00
constants = dofile_once("mods/quant.ew/files/core/constants.lua")
2024-05-20 01:01:35 +03:00
2024-08-07 17:11:55 +03:00
local perk_fns = dofile_once("mods/quant.ew/files/core/perk_fns.lua")
2024-05-20 01:01:35 +03:00
2024-05-23 21:02:39 +03:00
local version = dofile_once("mods/quant.ew/files/version.lua") or "unknown (dev build)"
print("Noita EW version: "..version)
2024-06-20 15:53:01 +03:00
dofile_once("data/scripts/lib/coroutines.lua")
2024-08-07 17:21:25 +03:00
ModLuaFileAppend("data/scripts/gun/gun.lua", "mods/quant.ew/files/resource/append/gun.lua")
ModLuaFileAppend("data/scripts/gun/gun_actions.lua", "mods/quant.ew/files/resource/append/action_fix.lua")
2024-05-12 15:31:08 +03:00
ModMagicNumbersFileAdd("mods/quant.ew/files/magic.xml")
np.CrossCallAdd("ew_per_peer_seed", function()
return tonumber(string.sub(ctx.my_id, 8, 12), 16), tonumber(string.sub(ctx.my_id, 12), 16)
end)
np.CrossCallAdd("ew_spectator", function()
if ctx.spectating_over_peer_id == nil then
return ctx.my_player.entity or EntityGetWithTag("player_unit")[1]
else
return ctx.players[ctx.spectating_over_peer_id].entity
end
end)
2024-06-06 15:25:01 +03:00
local function load_modules()
2024-09-23 19:48:56 +03:00
ctx.load_system("ewext_init")
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/item_sync.lua")
2024-08-13 02:54:44 -04:00
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/player_sync.lua")
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/enemy_sync.lua")
2024-08-07 15:05:38 +03:00
if ctx.proxy_opt.game_mode == "shared_health" then
ctx.load_system("damage")
ctx.load_system("heart_pickups")
2024-08-07 15:05:38 +03:00
ctx.load_system("patch_meat_biome")
ctx.load_system("kivi_patch")
end
if ctx.proxy_opt.game_mode == "local_health" then
ctx.load_system("local_health")
2024-08-09 11:31:16 +03:00
ctx.load_system("notplayer_ai")
2024-08-27 19:54:54 +03:00
ctx.load_system("spectator_helps")
ctx.load_system("end_fight")
2024-08-07 15:05:38 +03:00
end
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/nickname.lua")
2024-06-21 15:45:55 +03:00
2024-07-18 13:15:21 +03:00
if ctx.proxy_opt.debug then
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/debug.lua")
2024-06-21 15:45:55 +03:00
end
2024-08-13 02:54:44 -04:00
ctx.load_system("fungal_shift")
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/weather_sync.lua")
ctx.load_system("polymorph")
2024-06-06 15:25:01 +03:00
2024-08-25 14:45:47 +03:00
ctx.load_system("world_sync")
ctx.load_system("spawn_hooks")
2024-08-07 17:11:55 +03:00
ctx.dofile_and_add_hooks("mods/quant.ew/files/system/proxy_info.lua")
ctx.load_system("perk_patches")
2024-07-02 01:32:51 +03:00
2024-07-18 13:15:21 +03:00
if ctx.proxy_opt.player_tether then
ctx.load_system("player_tether")
2024-07-02 01:32:51 +03:00
end
2024-07-14 12:19:26 +03:00
ctx.load_system("kolmi")
ctx.load_system("ending")
ctx.load_system("spell_patches")
2024-07-18 16:27:28 +03:00
ctx.load_system("enemy_scaling")
2024-08-06 14:28:37 +03:00
ctx.load_system("patch_dragon_boss")
2024-08-05 16:38:55 +03:00
ctx.load_system("player_arrows")
2024-08-19 08:45:35 -04:00
ctx.load_system("player_ping")
ctx.load_system("extra_genomes")
2024-08-19 22:36:26 +03:00
ctx.load_system("game_effect_sync")
2024-08-21 14:25:12 +03:00
ctx.load_system("orb_sync")
2024-08-21 21:15:22 +03:00
ctx.load_system("flag_sync")
2024-08-22 15:41:13 +03:00
ctx.load_system("essence_sync")
ctx.load_system("spectate")
2024-09-03 09:03:59 -04:00
ctx.load_system("effect_data_sync")
ctx.load_system("gen_sync")
2024-09-22 09:56:48 -04:00
ctx.load_system("karl")
ctx.load_system("remove_wand_sound")
if ctx.proxy_opt.randomize_perks then
ctx.load_system("randomize_perks")
end
2024-10-02 20:42:56 +03:00
ctx.load_system("streaming_sync")
2024-10-03 20:30:06 -04:00
ctx.load_system("random_start")
ctx.load_system("worms")
ctx.load_system("wand_charm")
ctx.load_system("stevari")
ctx.load_system("angry_ghost_memory")
ctx.load_system("gate_boss")
ctx.load_system("tapion")
ctx.load_system("world_sync_cuts")
2024-06-06 15:25:01 +03:00
end
local function load_extra_modules()
print("Starting to load extra stuff")
for _, file in ipairs(ModLuaFileGetAppends("mods/quant.ew/files/api/extra_modules.lua")) do
ctx.dofile_and_add_hooks(file)
end
end
2024-05-12 16:23:28 +03:00
function OnProjectileFired(shooter_id, projectile_id, initial_rng, position_x, position_y, target_x, target_y, send_message,
2024-05-02 20:24:27 +03:00
unknown1, multicast_index, unknown3)
2024-06-14 23:55:25 +03:00
ctx.hook.on_projectile_fired(shooter_id, projectile_id, initial_rng, position_x, position_y, target_x, target_y, send_message, unknown1, multicast_index, unknown3)
2024-05-12 15:31:08 +03:00
if not EntityHasTag(shooter_id, "player_unit") and not EntityHasTag(shooter_id, "ew_client") then
return -- Not fired by player, we don't care about it (for now?)
end
2024-06-14 20:40:38 +03:00
EntityAddTag(projectile_id, "ew_no_enemy_sync")
2024-05-12 15:31:08 +03:00
local projectileComponent = EntityGetFirstComponentIncludingDisabled(projectile_id, "ProjectileComponent")
local entity_that_shot
if projectileComponent == nil then
entity_that_shot = GameGetWorldStateEntity()
else
entity_that_shot = ComponentGetValue2(projectileComponent, "mEntityThatShot")
end
2024-05-12 15:31:08 +03:00
2024-05-12 16:23:28 +03:00
local shooter_player_data = player_fns.get_player_data_by_local_entity_id(shooter_id)
local rng = 0
-- Was shot locally
2024-06-14 01:32:58 +03:00
if shooter_id == ctx.my_player.entity then
2024-05-12 16:23:28 +03:00
-- If it was an initial shot by host
if (entity_that_shot == 0 and multicast_index ~= -1 and unknown3 == 0) then
rng = initial_rng
table.insert(shooter_player_data.projectile_rng_init, rng)
else
2024-08-21 17:46:01 -04:00
rng = (shooter_player_data.projectile_seed_chain[entity_that_shot] or 0) + 25
2024-05-12 16:23:28 +03:00
end
else
if (entity_that_shot == 0 and multicast_index ~= -1 and unknown3 == 0) then
if #shooter_player_data.projectile_rng_init > 0 then
2024-05-12 16:23:28 +03:00
rng = table.remove(shooter_player_data.projectile_rng_init, 1)
else
-- Shouldn't happen
rng = 0
end
else
2024-06-29 18:33:19 +03:00
rng = (shooter_player_data.projectile_seed_chain[entity_that_shot] or 0) + 25
2024-05-12 16:23:28 +03:00
end
end
shooter_player_data.projectile_seed_chain[projectile_id] = rng
2024-05-12 15:31:08 +03:00
np.SetProjectileSpreadRNG(rng)
2024-05-02 20:24:27 +03:00
end
function OnProjectileFiredPost(shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message,
unknown1, multicast_index, unknown3)
end
function OnPausedChanged(paused, is_wand_pickup)
ctx.is_wand_pickup = is_wand_pickup
local players = EntityGetWithTag("player_unit") or {}
if (players[1]) then
np.RegisterPlayerEntityId(players[1])
--local inventory_gui = EntityGetFirstComponentIncludingDisabled(players[1], "InventoryGuiComponent")
local controls_component = EntityGetFirstComponentIncludingDisabled(players[1], "ControlsComponent")
if (paused) then
--EntitySetComponentIsEnabled(players[1], inventory_gui, false)
np.EnableInventoryGuiUpdate(false)
np.EnablePlayerItemPickUpper(false)
ComponentSetValue2(controls_component, "enabled", true)
else
--EntitySetComponentIsEnabled(players[1], inventory_gui, true)
np.EnableInventoryGuiUpdate(true)
np.EnablePlayerItemPickUpper(true)
ComponentSetValue2(controls_component, "enabled", true)
end
end
2024-05-02 20:24:27 +03:00
end
2024-04-29 22:14:22 +03:00
function OnWorldInitialized() -- This is called once the game world is initialized. Doesn't ensure any world chunks actually exist. Use OnPlayerSpawned to ensure the chunks around player have been loaded or created.
2024-08-06 14:28:37 +03:00
if ctx.is_host then
GameAddFlagRun("ew_flag_this_is_host")
else
GameRemoveFlagRun("ew_flag_this_is_host")
end
ctx.hook.on_world_initialized()
2024-04-29 22:14:22 +03:00
end
2024-05-12 15:31:08 +03:00
2024-04-29 22:14:22 +03:00
function OnPlayerSpawned( player_entity ) -- This runs when player entity has been created
2024-06-14 17:03:34 +03:00
print("Initial player entity: "..player_entity)
2024-08-13 02:54:44 -04:00
if GlobalsGetValue("ew_player_count", "") == "" then
GlobalsSetValue("ew_player_count", "1")
end
2024-05-15 16:50:59 +03:00
local x, y = EntityGetTransform(player_entity)
ctx.initial_player_pos = {x=x, y=y}
2024-06-14 01:32:58 +03:00
local my_player = player_fns.make_playerdata_for(player_entity, ctx.my_id)
2024-05-02 20:24:27 +03:00
ctx.players[ctx.my_id] = my_player
2024-05-12 16:23:28 +03:00
ctx.player_data_by_local_entity[player_entity] = my_player
2024-05-02 20:24:27 +03:00
ctx.ready = true
ctx.my_player = my_player
2024-05-07 23:46:15 +03:00
2024-07-16 12:48:40 +03:00
EntityAddTag(player_entity, "ew_peer")
2024-08-09 15:43:56 +03:00
if not GameHasFlagRun("ew_flag_notplayer_active") then
EntityAddComponent2(player_entity, "LuaComponent", {script_wand_fired = "mods/quant.ew/files/resource/cbs/count_times_wand_fired.lua"})
end
2024-05-12 15:31:08 +03:00
net.send_welcome()
local item_pick = EntityGetFirstComponentIncludingDisabled(player_entity, "ItemPickUpperComponent")
ComponentSetValue2(item_pick, "is_immune_to_kicks", true)
2024-05-26 00:49:53 +03:00
ctx.hook.on_local_player_spawn(my_player)
2024-05-27 19:53:29 +03:00
ctx.hook.on_should_send_updates()
2024-05-26 00:49:53 +03:00
GamePrint("Noita Entangled Worlds version "..version)
OnPausedChanged(false, false)
2024-08-13 02:54:44 -04:00
2024-05-29 23:55:34 +03:00
print("Game state entity: "..GameGetWorldStateEntity())
2024-08-13 02:54:44 -04:00
if not GameHasFlagRun("ew_flag_notplayer_active") then
player_cosmetics(player_entity)
player_color(player_entity)
else
EntityInflictDamage(player_entity, 1000000, "DAMAGE_CURSE", "dont rejoin", "NONE", 0, 0, GameGetWorldStateEntity())
GameAddFlagRun("ew_kill_player")
end
if ctx.host_id == ctx.my_id then
np.MagicNumbersSetValue("STREAMING_CHUNK_TARGET", ctx.proxy_opt.chunk_target)
end
2024-08-25 17:53:29 -04:00
local controls_component = EntityGetFirstComponentIncludingDisabled(player_entity, "ControlsComponent")
ComponentSetValue2(controls_component, "enabled", true)
2024-04-29 22:14:22 +03:00
end
2024-10-04 20:17:12 -04:00
local function change_homing(x, y)
for _, proj in pairs(EntityGetInRadiusWithTag(x, y, 512, "player_projectile")) do
local homing = EntityGetFirstComponentIncludingDisabled(proj, "HomingComponent")
if homing ~= nil then
local projcom = EntityGetFirstComponentIncludingDisabled(proj, "ProjectileComponent")
if projcom ~= nil then
local whoshot = ComponentGetValue2(projcom, "mWhoShot")
if EntityHasTag(whoshot, "ew_notplayer") or GameHasFlagRun("ending_game_completed") then
2024-10-04 20:17:12 -04:00
ComponentSetValue2(homing, "target_tag", "ew_peer")
end
end
end
end
end
2024-05-12 15:31:08 +03:00
local function on_world_pre_update_inner()
if ctx.my_player == nil or ctx.my_player.entity == nil then return end
2024-05-10 22:17:45 +03:00
2024-05-12 15:31:08 +03:00
GlobalsSetValue("ew_player_rng", tostring(GameGetFrameNum()))
2024-05-13 15:18:52 +03:00
2024-05-02 20:24:27 +03:00
net.update()
2024-05-11 18:06:48 +03:00
2024-06-14 01:32:58 +03:00
local inventory_gui_comp = EntityGetFirstComponentIncludingDisabled(ctx.my_player.entity, "InventoryGuiComponent")
2024-06-14 20:40:38 +03:00
if inventory_gui_comp and inventory_gui_comp ~= 0 then
local inventory_open = ComponentGetValue2(inventory_gui_comp, "mActive")
if ctx.is_inventory_open and not inventory_open then
ctx.events.inventory_maybe_just_changed = true
end
ctx.is_inventory_open = inventory_open
2024-05-15 16:50:59 +03:00
end
if GameGetFrameNum() % 120 == 0 and not ctx.run_ended then
player_fns.respawn_if_necessary()
end
2024-06-14 01:32:58 +03:00
if ctx.events.new_player_just_connected or ctx.events.inventory_maybe_just_changed or (GameGetFrameNum() % 5 == 0 and inventory_helper.has_inventory_changed(ctx.my_player)) then
local inventory_state = player_fns.serialize_items(ctx.my_player)
if inventory_state ~= nil then
net.send_player_inventory(inventory_state)
end
2024-05-15 16:50:59 +03:00
end
-- Perk sync
if GameGetFrameNum() % 120 == 0 and not ctx.run_ended then
2024-05-07 23:46:15 +03:00
local perk_data = perk_fns.get_my_perks()
2024-05-10 22:17:45 +03:00
if perk_data ~= nil then
net.send_player_perks(perk_data)
end
2024-05-03 23:38:40 +03:00
end
if not ctx.run_ended then
if ctx.is_host then
ctx.hook.on_world_update_host()
else
ctx.hook.on_world_update_client()
end
ctx.hook.on_world_update()
2024-05-20 01:01:35 +03:00
end
2024-06-20 15:53:01 +03:00
2024-10-04 20:17:12 -04:00
if GameGetFrameNum() % 4 == 0 then
local x, y = EntityGetTransform(ctx.my_player.entity)
2024-10-05 06:12:44 -04:00
if x ~= nil then
change_homing(x, y)
end
2024-10-04 20:17:12 -04:00
elseif GameGetFrameNum() % 4 == 1 then
local x, y = EntityGetTransform(ctx.my_player.entity)
local cx, cy = GameGetCameraPos()
2024-10-05 06:12:44 -04:00
if x ~= nil and cx ~= nil then
if math.abs(x - cx) > 256 or math.abs(y - cy) > 256 then
change_homing(cx, cy)
end
end
end
2024-06-20 15:53:01 +03:00
wake_up_waiting_threads(1)
2024-04-29 22:14:22 +03:00
end
2024-05-12 15:31:08 +03:00
function OnWorldPreUpdate() -- This is called every time the game is about to start updating the world
if net.connect_failed then
if GameGetFrameNum() % 180 == 0 then
GamePrint("Entangled Worlds mod is enabled, but it couldn't connect to proxy!")
GamePrint("You need to start the proxy and join the lobby first.")
GamePrint("If you want to play singleplayer, disable the mod and start a new game.")
end
return
end
2024-05-12 15:31:08 +03:00
util.tpcall(on_world_pre_update_inner)
end
local function on_world_post_update_inner()
if ctx.my_player == nil or ctx.my_player.entity == nil then return end
2024-05-25 22:20:43 +03:00
if not ctx.run_ended then
ctx.hook.on_world_update_post()
end
2024-05-25 22:20:43 +03:00
2024-05-12 15:31:08 +03:00
local times_wand_fired = tonumber(GlobalsGetValue("ew_wand_fired", "0"))
GlobalsSetValue("ew_wand_fired", "0")
if times_wand_fired > 0 then
local inventory_component = EntityGetFirstComponentIncludingDisabled(ctx.my_player.entity, "Inventory2Component")
if inventory_component == nil then
return
end
local last_switch = ComponentGetValue2(inventory_component, "mLastItemSwitchFrame")
local switched_now = last_switch == GameGetFrameNum()
2024-08-13 02:54:44 -04:00
2024-05-12 15:31:08 +03:00
local special_seed = tonumber(GlobalsGetValue("ew_player_rng", "0"))
2024-06-14 01:32:58 +03:00
local fire_data = player_fns.make_fire_data(special_seed, ctx.my_player)
2024-05-12 15:31:08 +03:00
if fire_data ~= nil then
if switched_now then
fire_data.switched_now = true
end
2024-05-12 15:31:08 +03:00
net.send_fire(fire_data)
end
end
end
function OnWorldPostUpdate() -- This is called every time the game has finished updating the world
if net.connect_failed then
return
end
util.tpcall(on_world_post_update_inner)
2024-05-15 16:50:59 +03:00
ctx.events = {}
net.proxy_send("flush", "")
2024-05-12 15:31:08 +03:00
end
2024-04-29 22:14:22 +03:00
function register_localizations(translation_file, clear_count)
clear_count = clear_count or 0
local loc_content = ModTextFileGetContent("data/translations/common.csv") -- Gets the original translations of the game
local append_content = ModTextFileGetContent(translation_file) -- Gets my own translations file
-- Split the append_content into lines
local lines = {}
for line in append_content:gmatch("[^\n]+") do
table.insert(lines, line)
end
-- Remove the first clear_count lines
for i = 1, clear_count do
table.remove(lines, 1)
end
-- Reconstruct append_content after removing clear_count lines
local new_append_content = table.concat(lines, "\n")
-- if loc_content does not end with a new line, add one
if not loc_content:match("\n$") then
loc_content = loc_content .. "\n"
end
-- Concatenate loc_content and new_append_content without extra newline character
local new_content = loc_content .. new_append_content .. "\n"
-- Set the new content to the file
ModTextFileSetContent("data/translations/common.csv", new_content)
end
function OnModPreInit()
register_localizations("mods/quant.ew/translations.csv", 1)
2024-05-02 20:24:27 +03:00
ctx.init()
net.init()
2024-08-06 14:28:37 +03:00
if not net.connect_failed then
load_modules()
print("Entangled worlds init ok")
end
2024-04-29 22:14:22 +03:00
end
function OnModInit()
load_extra_modules()
end
2024-06-14 17:03:34 +03:00
2024-09-11 12:38:20 +03:00
function OnModPostInit()
ctx.hook.on_late_init()
end
2024-04-29 22:14:22 +03:00
2024-08-07 16:37:54 +03:00
function OnPlayerDied(player_entity)
ctx.hook.on_player_died(player_entity)
print("player died")
end