Lawful Evil


Fully customizable reaction system, applying actions and custom scripts during various events with filters. Players, admins can propose, pass, and revoke laws. The mod is suitable for changing gameplay of game, providing automatic protection system against griefers, rewards for certain actions etc. Has support of mods, especially economic ones. Author: Luke Perkin. Modified by ZwerOxotnik and pliesveld. Anyone can translate the mod on Crowdin.

Utilities
a month ago
0.17 - 2.0
752

b [FIXED?] Law=nil. Reaching outside of table range.

2 years ago
(updated 2 years ago)

Game crashes for me inside "CheckVotes()" because law=nil.

It happened when I was testing out mod and I accepted,rejected some random laws that I made.

I think it happens when rejected law is not last one on list, because in code :

local function CheckVotes()
    local laws = global.laws
    for i=1, #laws do
        law = laws[i]
        if not law.passed and not law.linked_law and game.tick >= law.vote_end_tick then
            local votes = GetLawVotes(law)
            if votes.ayes > votes.noes then
                game.print({"lawful-evil.messages.law-is-passed", law.title, votes.ayes, votes.noes})
                PassLaw(law)
            else
                game.print({"lawful-evil.messages.law-is-not-passed", law.title, votes.ayes, votes.noes})
                RevokeLaw(law, law.index)
            end
        end
    end

    -- Refresh Lawful Gui.
    RefreshAllLawfulEvilGui()
end

Function RevokeLaw removes item from table, causing "for loop" to operate in invalid range.

After adding 2 lines of code in loop :
game.print("law : " .. i)
game.print("total : " .. #laws)
I got crash right after game prints "law : 4 total : 3"

I tried deep-copying global.laws instead of assigning reference, but then it caused passed laws to not get passed.

I thought of several other solutions, but I went for simple one (though maybe not elegant)

local function CheckVotes()
    local laws = global.laws
    local i=1;
    while i<=#laws do
        law = laws[i]
        i=i+1
        if not law.passed and not law.linked_law and game.tick >= law.vote_end_tick then
            local votes = GetLawVotes(law)
            if votes.ayes > votes.noes then
                game.print({"lawful-evil.messages.law-is-passed", law.title, votes.ayes, votes.noes})
                PassLaw(law)
            else
                game.print({"lawful-evil.messages.law-is-not-passed", law.title, votes.ayes, votes.noes})
                RevokeLaw(law, law.index) --we change count of laws table elements(!)
                i=i-1 --table is now 1 smaller.
            end
        end
    end

    -- Refresh Lawful Gui.
    RefreshAllLawfulEvilGui()
end

More elegant solution, that I thought about : don't delete law from global.laws in RevokeLaw function. Instead mark it as rejected and delete it.... Somewhere later. Ideally RevokeLaw shouldn't care about law.index and law shouldn't store it's index.

Another "elegant" solution : start for loop on last element and move backwards (for i=#laws,1,-1)? That way you don't shift table when you remove element.

But I only tested if game doesn't crash now. I guess it should just work well, unless I misunderstand how things work in this mod ( I just glanced at code )

2 years ago
(updated 2 years ago)

Oh, probably, I should iterate it in reverse order in RevokeLaw, thanks.

2 years ago

Eh, perhaps, I should refactor it, but it'll take too much time.

2 years ago
(updated 2 years ago)

I think RevokeLaw() is perfectly fine. Game crashed in CheckVotes() on line1036, because assignment in line 1035 :

Error while running event m-lawful-evil::on_nth_tick(60)
__m-lawful-evil__/control.lua:1036: attempt to index global 'law' (a nil value)
stack traceback:
    __m-lawful-evil__/control.lua:1036: in function 'CheckVotes'
    __m-lawful-evil__/control.lua:1094: in function <__m-lawful-evil__/control.lua:1093>

When testing I also made it check for new laws every second, instead of minutes : )

Yeah, I think if it works, it works. I think iterating backwards is the best.

2 years ago
(updated 2 years ago)

I uploaded a new version.

2 years ago
(updated 2 years ago)

Hm... it seems like linking of laws had been broken in general.

2 years ago

I wanted to test and review whole mod and setup some multiplayer game with it, but it's too big to review, as I also don't have time :/ Time is always biggest problem...

I think I will just not consider this mod for my server.

I understand you have a lot of mods on head, and many of those are continuation of someone's else's mod, so don't fix it, if you don't feel like it :) keep up good job, I like many of your mods.

2 years ago

In short, perhaps https://mods.factorio.com/mod/useful_book can be useful or it will be useful, although I can't promise anything right now.

New response