[Gameplay] - Lightening Rod is Lazy


Ridley

Recommended Posts

Bug Submission:

Category: Gameplay
Issue Title: Lightening Rod is Lazy
Issue Description: After teleporting a Wx78 to my base using the telefocus ( I debug spawned one in for the sake of newcomers ), it seems lightening rods do not work all the time. The storm caused from that teleport created lightening that targeted players, igniting them, or started zapping plants. Three lightening rods are now in the general area and this keeps rarely happening.

Once the storm blew over, it feels like the storms randomly decide to obey lightening rods or not. Sometimes there is never a problem, sometimes I am running around on fire.
Steps to Reproduce: 1. Create lightening rod near telefocus setup.
2. Have a Wx78 join.
3. Use the telestaff on him
4. Lightening will zap the rod as a storm kicks in.
4. See if you can be around Wx78, telefocus, and the lightening rod without lightening getting funky.

Link to comment
Share on other sites

The bug don't seem to be related to the telefocus. I have the same problem in my server without gived item. 


First time, 2 players join (wx78 and Wilson) and rain start. 1 min later,  I was harvesting my berryfarm and a lighthing fall to destruct my 36 berrybushs. ;(   Even if I have 2 lightening rod in the zone. 

Then the two players leave  and y start harvesting my twyks farm.  An other lightening fall on me and burn everything...  Rhaaaaaaa!

I play with Wx78 and I was using an umbrella for the rain.  Wx78 is more attractive than the lightening rod?

 

Link to comment
Share on other sites

I did some code poking and I think I figured out why and when this occurs. I'm not 100% though, this code is a bit tricky to read/run through in my head.
 
So the code in weather.lua after it's picked a player and chosen a location around that player to send a lightning strike, and is then searching for lightning rods or WXs to strike, if present:

    local target = nil    local isrod = false    local mindistsq = nil    local pos0 = pos    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, 40, nil, nil, { "lightningrod", "lightningtarget" })    for k, v in pairs(ents) do        local visrod = v:HasTag("lightningrod")        local vpos = Vector3(v.Transform:GetWorldPosition())        local vdistsq = distsq(pos0, vpos)        if target == nil or ((visrod or not isrod) and vdistsq < mindistsq) then            target = v            isrod = visrod            pos = vpos            mindistsq = vdistsq        end    end

I think the problem is that ents comes back by default sorted in order of closest-to-furthest, so when it's iterating through it with the for loop, it looks at the closest entities first.
 
My interpretation of the last condition:

        if target == nil                       -- this is the first rod/WX being considered so far            or ((visrod or not isrod)          -- this current potential target is a rod or we haven't found a rod yet                 and vdistsq < mindistsq) then -- and this target is closer than the last one that qualified for the strike

Since ents is sorted from closest to furthest already, the first ent is checked and approved because it's the first. This sets a mindistsq that no other ent can beat. It goes through and checks the others, but either they are disqualified because they're not lightning rods, or because the first ent was a lightning rod, or because they are further away. The problem is that if it's a lightning rod and it hasn't found a rod yet, then it should be checking it anyway, even though it's further away than the one before (which must've been a WX for the other conditions to be true).
 
I think if we just remove all of the distance-tracking stuff, it would be fixed. It's already checking things in order of closest to furthest, so if the first target found was a WX, then it will go on to check for a lightning rod in range. Once a lightning rod is found, all other things are ignored (which is okay because they're all further than the things that have been checked already).

    local target = nil    local isrod = false    local pos0 = pos    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, 40, nil, nil, { "lightningrod", "lightningtarget" })    for k, v in pairs(ents) do        local visrod = v:HasTag("lightningrod")        local vpos = Vector3(v.Transform:GetWorldPosition())        if target == nil or ((visrod and not isrod)) then            target = v            isrod = visrod            pos = vpos        end    end

Alternatively, we could iterate through the list the other way, going from furthest to closest:

    local target = nil    local isrod = false    local mindistsq = nil    local pos0 = pos    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, 40, nil, nil, { "lightningrod", "lightningtarget" })    for i=#ents,1,-1 do        local v = ents[i]        local visrod = v:HasTag("lightningrod")        local vpos = Vector3(v.Transform:GetWorldPosition())        local vdistsq = distsq(pos0, vpos)        if target == nil or ((visrod or not isrod) and vdistsq < mindistsq) then            target = v            isrod = visrod            pos = vpos            mindistsq = vdistsq        end    end

I think you could technically leave out the whole distance-tracking stuff (mindistsq and everything it's interacting with) here as well, since it will always settle on the closest rod if present, or the closest WX if not.

 

Edit: Yet another way to fix it that wouldn't change as much of the current flow would be to only update mindistsq if the current entity is a lightning rod, rather than a WX. To do this we have to assign a starting value to mindistsq, which is fine because the entities shouldn't be further than 40 away anyway:

    local target = nil    local isrod = false    local mindistsq = 50*50 -- 50 is outside of the 40 range, square because this is distance squared    local pos0 = pos    local ents = TheSim:FindEntities(pos.x, pos.y, pos.z, 40, nil, nil, { "lightningrod", "lightningtarget" })    for k, v in pairs(ents) do        local visrod = v:HasTag("lightningrod")        local vpos = Vector3(v.Transform:GetWorldPosition())        local vdistsq = distsq(pos0, vpos)        if target == nil or ((visrod or not isrod) and vdistsq < mindistsq) then            target = v            isrod = visrod            pos = vpos            if visrod then                mindistsq = vdistsq            end        end    end
Link to comment
Share on other sites

Just want to say it's not just the robot (Wx78) that gets hit. I don't know if having a robot causes it?

But I was watching Geeky_Greekys twitch stream and I saw he was the robot, but the guy that got hit was Wilson. They even had two lightning rods on the same screen, at the time he got hit.

 

Also, they did not have a telefocus thing.

Just F.Y.I

 

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

Please be aware that the content of this thread may be outdated and no longer applicable.