Jump to content

Kept getting "attempt to compare number with nil" warning


Recommended Posts

I wanted to add critical hit perk to my character and found @SuperDavid 's post. For the code below, all credit goes to @IronHunter.

This is in the modmain, I kept getting compare number to nil warning from the underlined line. And the line above it worked fine. Problem seems to be the self.inst.critChance but it was declared in the same way as self.inst.gcp_c in the character's prefab. I'm now confused, need some help. Thanks.

Spoiler

AddComponentPostInit("combat", function(Combat)
    local OldCalcDamage = Combat.CalcDamage
    Combat.CalcDamage = function(self, target, weapon, ...)
        local old_damage = nil
        -- local crit = self.inst.critChance
        -- local critdmg = self.inst.critDmg
        local critdmg = 1.5
        -- if math.random() <= 0.5 and target and self.inst.prefab == "hisoka" and self.inst.gcp_c >= 3 then 
        if math.random() <= self.inst.critChance and target and self.inst.prefab == "hisoka" and self.inst.gcp_c >= 3 then 
            if weapon then -- if its a weapon
                old_damage = weapon.components.weapon.damage
                weapon.components.weapon.damage = old_damage * critdmg
                self.inst.components.health:DoDelta(weapon.components.weapon.damage/2)
            else -- if we attack with something not using the weapon component
                old_damage = self.defaultdamage
                self.defaultdamage = old_damage * critdmg
                self.inst.components.health:DoDelta(self.defaultdamage/2)
            end
            -- visual effects and other stuff you can add
            local fx = SpawnPrefab("explode_small")
            local x, y, z = target.Transform:GetWorldPosition()
            fx.Transform:SetPosition(x, y, z)
        end
        local ret = OldCalcDamage(self, target, weapon, ...)
        if old_damage then-- reseting back to non crit damage
            if weapon then
                weapon.components.weapon.damage = old_damage
            else
                self.defaultdamage = old_damage
            end
        end
        return ret
    end
end)

 

hisoka7-3.zip

Link to comment
Share on other sites

Where are you setting critChance? I presume you define it in hisoka's prefab constructor function. In any case the problem is quite simple: critChance has not been defined, therefore it is nil. Note that the component postinit will be executed for every prefab that the combat component, not just hisoka. So the solution would be to switch around the check as follows;

 if self.inst.prefab == "hisoka" and math.random() <= self.inst.critChance and self.inst.gcp_c >= 3 then

This works because of the way the interpreter resolves logical operators. If the condition is X and Y, then both X and Y must be true in order for the condition to be true. So if X is false, then there is no reason to evaluate Y, so it is skipped and the condition as a whole returns false. Your mistake was to not take advantage of this property of logical operators, so self.inst.critChance was evaluated before the interpreter reached the hisoka check, throwing an error when the instance was not hisoka. In short, the order matters!

You could also make the postinit less dependent on hisoka and allow other prefabs to use this function as well, by simply checking if critChance exists and in that case proceed:

 if self.inst.critChance and math.random() <= self.inst.critChance and self.inst.gcp_c >= 3 then

This is a more robust version, so I would prefer this version over the previous version. You could still restrict it to just hisoka (by only setting critChance for hisoka), but writing generic code is generally good practice, especially if it doesn't increase complexity like in this situation.

Edited by Joachim
Link to comment
Share on other sites

@Joachim

It worked, thank you so much! You are amazing! Although if I use 

 if self.inst.critChance and math.random() <= self.inst.critChance and self.inst.gcp_c >= 3 then

It would crash. Have to execute the perfab postinit before any self.variable I guess.

Link to comment
Share on other sites

1 minute ago, nicknightyx said:

@Joachim

It worked, thank you so much! You are amazing! Although if I use 


 if self.inst.critChance and math.random() <= self.inst.critChance and self.inst.gcp_c >= 3 then

It would crash. Have to execute the perfab postinit before any self.variable I guess.

This is because it runs for all entities with the combat component that runs this function. Hence why the prefab check is really important as the swamp wars will proc and crash this. Alternatively you can check to make sure critchance isn't nil.

I have released my personal modified version of the crit code that I use in my mods for others to use as they wish. It doesn't require any modifications. As it allows greater compatibility amongst characters.

Crit Code

Link to comment
Share on other sites

15 hours ago, IronHunter said:

This is because it runs for all entities with the combat component that runs this function. Hence why the prefab check is really important as the swamp wars will proc and crash this. Alternatively you can check to make sure critchance isn't nil.

I have released my personal modified version of the crit code that I use in my mods for others to use as they wish. It doesn't require any modifications. As it allows greater compatibility amongst characters.

Crit Code

Thanks for the explanation! I finally understand. 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...