Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Ban Perks feature with support for GLASS_CANNON #193

Merged
merged 7 commits into from
Sep 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/deploy-linux-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ jobs:
run: |
mkdir ${{ github.workspace }}/build
cp ./latest-linux.yml ${{ github.workspace }}/build/latest-linux.yml
cp ./*.AppImage ${{ github.workspace }}/build/
- name: Upload files to release
uses: svenstaro/upload-release-action@v2
with:
Expand Down
176 changes: 168 additions & 8 deletions noita_mod/core/files/append/perk.lua
Original file line number Diff line number Diff line change
@@ -1,18 +1,178 @@
local _create_all_player_perks = create_all_player_perks

-- NT_DONT_SHARE - Prevent nullification altar perks from being shared
function create_all_player_perks(x, y)
local _perk_spawn = perk_spawn
perk_spawn = function( x, y, perk_id, dont_remove_other_perks_ )
local perk_entity = _perk_spawn(x, y, perk_id, dont_remove_other_perks_ )
perk_spawn = function(x, y, perk_id, dont_remove_other_perks_)
local perk_entity = _perk_spawn(x, y, perk_id, dont_remove_other_perks_)
if (perk_entity ~= nil) then
EntityAddComponent( perk_entity, "VariableStorageComponent",
{
name = "NT_DONT_SHARE",
value_string = "",
} )
EntityAddComponent(perk_entity, "VariableStorageComponent",
{
name = "NT_DONT_SHARE",
value_string = "",
})
end
return perk_entity
end
_create_all_player_perks(x, y)
perk_spawn = _perk_spawn
end
end

-- NT_ban_perks --
dofile_once("mods/noita-together/files/scripts/ban_perks.lua")

-- NT_ban_perks - Remove bannned perks from perk spawn order
local _perk_get_spawn_order = perk_get_spawn_order
function perk_get_spawn_order(ignore_these_)
local ignore_these = ignore_these_ or {}
if (GameHasFlagRun("NT_ban_perks")) then
for _, _perk_id in ipairs(BannedPerksTable()) do
table.insert(ignore_these, _perk_id)
end
end
return _perk_get_spawn_order(ignore_these)
end

-- NT_ban_perks - Overwrite the base game perk_spawn to handle spawning different xml entities and adding LuaComponent items for switching between entities.
function perk_spawn(x, y, perk_id, dont_remove_other_perks_)
local perk_data = get_perk_with_id(perk_list, perk_id)
-- Leave base game print_error and print statements for logging
if (perk_data == nil) then
print_error("spawn_perk( perk_id ) called with'" .. perk_id .. "' - no perk with such id exists.")
return
end
print("spawn_perk " .. tostring(perk_id) .. " " .. tostring(x) .. " " .. tostring(y))

local perk_xml_path
local perk_image_file_path
local is_banned_perk = IsBannedPerkId(perk_id)
local is_bannable_perk = ISBannablePerkId(perk_id)
if is_banned_perk then
perk_xml_path = "mods/noita-together/files/entities/perks/banned_perk.xml"
perk_image_file_path = "mods/noita-together/files/items_gfx/banned_perks/" .. perk_id .. ".png"
else
perk_xml_path = "data/entities/items/pickup/perk.xml"
perk_image_file_path = perk_data.perk_icon
end

local entity_id = EntityLoad(perk_xml_path, x, y)
if (entity_id == nil) then
return
end

local dont_remove_other_perks = dont_remove_other_perks_ or false

-- init perk item
EntityAddComponent(entity_id, "SpriteComponent",
{
image_file = perk_image_file_path or "data/items_gfx/perk.xml",
offset_x = "8",
offset_y = "8",
update_transform = "1",
update_transform_rotation = "0",
})

EntityAddComponent(entity_id, "UIInfoComponent",
{
name = perk_data.ui_name,
})

-- Only add ItemComponent which allows item pickup for non-banned perks
if not is_banned_perk then
EntityAddComponent(entity_id, "ItemComponent",
{
item_name = perk_data.ui_name,
ui_description = perk_data.ui_description,
ui_display_description_on_pick_up_hint = "1",
play_spinning_animation = "0",
play_hover_animation = "0",
play_pick_sound = "0",
})
end

EntityAddComponent(entity_id, "SpriteOffsetAnimatorComponent",
{
sprite_id = "-1",
x_amount = "0",
x_phase = "0",
x_phase_offset = "0",
x_speed = "0",
y_amount = "2",
y_speed = "3",
})

EntityAddComponent(entity_id, "VariableStorageComponent",
{
name = "perk_id",
value_string = perk_data.id,
})

if dont_remove_other_perks then
EntityAddComponent(entity_id, "VariableStorageComponent",
{
name = "perk_dont_remove_others",
value_bool = "1",
})
end

-- Add LuaComponent to all bannable perks
-- script_source_file with a arbitrarily large execute_every_n_frame are used for performance considerations
if is_bannable_perk then
EntityAddComponent(entity_id, "LuaComponent",
{
script_source_file = "mods/noita-together/files/scripts/bannable_perk_check.lua",
execute_every_n_frame = "300"
})
end

return entity_id
end

-- NT_ban_perks - Do not allow banned perks to be picked up
--[[
Banned perks may exist in world from:
Being spawned in world while the gameflag is off
Handling of banned perks being toggled on may have removed a players existing perks and placed them into the world.
]]
local _perk_pickup = perk_pickup
function perk_pickup(entity_item, entity_who_picked, item_name, do_cosmetic_fx, kill_other_perks, no_perk_entity_)
if (not GameHasFlagRun("NT_ban_perks")) then
_perk_pickup(entity_item, entity_who_picked, item_name, do_cosmetic_fx, kill_other_perks, no_perk_entity_)
else
-- fetch perk info ---------------------------------------------------
local no_perk_entity = no_perk_entity_ or false
local pos_x, pos_y

if no_perk_entity then
pos_x, pos_y = EntityGetTransform(entity_who_picked)
else
pos_x, pos_y = EntityGetTransform(entity_item)
end

local perk_id = ""

if no_perk_entity then
perk_id = item_name
else
edit_component(entity_item, "VariableStorageComponent", function(comp, vars)
perk_id = ComponentGetValue(comp, "value_string")
end)
end

if IsBannedPerkId(perk_id) then
--[[
It should only be possible to enter this state if:
A perk is forcibly applied through cheats
The user attempts to pickup a perk, after NT_ban_perks is turned on, but before the next script execution of
a perk entity which can be banned updates the perk entity
]]
GamePrint("$noitatogether_banned_perk_pickup")
local dont_remove_other_perks = not kill_other_perks
EntityKill(entity_item)
EntityLoad("data/entities/particles/polymorph_explosion.xml", pos_x, pos_y)
perk_spawn(pos_x, pos_y, perk_id, dont_remove_other_perks)
else
_perk_pickup(entity_item, entity_who_picked, item_name, do_cosmetic_fx, kill_other_perks, no_perk_entity_)
end
end
end
30 changes: 12 additions & 18 deletions noita_mod/core/files/append/perk_pickup.lua
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
dofile_once("mods/noita-together/files/store.lua")
dofile_once("mods/noita-together/files/scripts/json.lua")
dofile_once("data/scripts/perks/perk.lua")
-- NT_ban_perks --
dofile_once("mods/noita-together/files/scripts/ban_perks.lua")

local _item_pickup = item_pickup

function item_pickup( entity_item, entity_who_picked, item_name )
function item_pickup(entity_item, entity_who_picked, item_name)
local list = dofile("mods/noita-together/files/scripts/perks.lua")
local perk_id = ""
local blocked = false
local components = EntityGetComponent( entity_item, "VariableStorageComponent" )
if ( components ~= nil ) then
for key,comp_id in pairs(components) do
local var_name = ComponentGetValue( comp_id, "name" )
if( var_name == "perk_id") then
perk_id = ComponentGetValue2( comp_id, "value_string" )
end
if (var_name == "NT_DONT_SHARE") then
blocked = true
end
end
end
if (GameHasFlagRun("NT_GAMEMODE_CO_OP") and not blocked) then
local key_perk_components = GetKeyPerkComponents(entity_item)
local perk_id = key_perk_components.perk_id
local blocked = key_perk_components.nt_dont_share
local banned_perk = IsBannedPerkId(perk_id)

if (GameHasFlagRun("NT_GAMEMODE_CO_OP") and not blocked and not banned_perk) then
if ((GameHasFlagRun("NT_team_perks") and list[perk_id] == true) or GameHasFlagRun("NT_sync_perks")) then
local queue = json.decode(NT.wsQueue)
table.insert(queue, {event="CustomModEvent", payload={name="TeamPerk", id=perk_id}})
table.insert(queue, { event = "CustomModEvent", payload = { name = "TeamPerk", id = perk_id } })
NT.wsQueue = json.encode(queue)
GamePrint("$noitatogether_teamperk_was_shared")
end
end
_item_pickup( entity_item, entity_who_picked, item_name )
_item_pickup(entity_item, entity_who_picked, item_name)
end
1 change: 1 addition & 0 deletions noita_mod/core/files/entities/perks/banned_perk.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<Entity tags="teleportable_NOT,perk,item_perk"></Entity>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 68 additions & 0 deletions noita_mod/core/files/scripts/ban_perks.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
-- Returns a table of all possible banned perk_list.id string values
function AllPotentialBannedPerksTable()
local banned_perks = {
"GLASS_CANNON"
}
return banned_perks
end

-- Returns a table of banned perk_list.id string values
-- Separated to allow for potential selections or sets changes via app events in future
function BannedPerksTable()
-- Table of perk_list.id strings to be banned.
local banned_perks = {
"GLASS_CANNON"
}
return banned_perks
end

-- Returns if a perk_id is currently banned
function IsBannedPerkId(perk_id)
if (not GameHasFlagRun("NT_ban_perks")) then
return false
end
for _, _perk_id in ipairs(BannedPerksTable()) do
if _perk_id == perk_id then
return true
end
end
return false
end

-- Returns is a perk_id could be banned
function ISBannablePerkId(perk_id)
for _, _perk_id in ipairs(AllPotentialBannedPerksTable()) do
if _perk_id == perk_id then
return true
end
end
return false
end

-- Returns all repeatedly utilized VariableStorageComponent values to avoid multiple iterations across components
function GetKeyPerkComponents(entity_item)
local components = EntityGetComponent(entity_item, "VariableStorageComponent")
local perk_id
local dont_remove_other_perks
local nt_dont_share
if (components ~= nil) then
for key, comp_id in pairs(components) do
local var_name = ComponentGetValue(comp_id, "name")
if (var_name == "perk_id") then
perk_id = ComponentGetValue2(comp_id, "value_string")
end
if (var_name == "perk_dont_remove_others") then
dont_remove_other_perks = ComponentGetValue2(comp_id, "value_bool")
end
if (var_name == "NT_DONT_SHARE") then
nt_dont_share = true
end
end
end
local perk_components = {
perk_id = perk_id,
dont_remove_other_perks = dont_remove_other_perks,
nt_dont_share = nt_dont_share
}
return perk_components
end
Loading