Here is a new script you can use in only one script entity and it will check all the maps of your dungeon:
Code: Select all
interval = 1
index = 0
track = {}
function check()
local levels = Dungeon.getMaxLevels()
index = index % levels + 1
local map = Dungeon.getMap(index)
local old, new = track[index] or {}, {}
local X, Y, dt = map:getWidth()-1, map:getHeight()-1, interval * levels
for e in map:allEntities() do
if e.projectile and
((e.facing == 0 and e.y == 0) or
(e.facing == 1 and e.x == X) or
(e.facing == 2 and e.y == Y) or
(e.facing == 3 and e.x == 0)) then
local t = old[e.id] and old[e.id]+dt or 0
--local w = e:getWorldPosition()
--hudPrint(e.name.." at map("..e.x..", "..e.y..") world("..w.x..", "..w.y..", "..w.z..") for "..t.." seconds")
if t >= 60 then e:destroy() else new[e.id] = t end
end
end
track[index] = new
delayedCall(self.go.id, interval, "check")
end
check()
Also, if you wish you can change its interval, set to 1 second in this code. The two commented lines can be uncommented to see what it does. Each interval, one different map is checked.
To comment on the side effects, performance and general elegance:
- From my experience, the delayedCall function is very inefficient. If you use it for example to delay hundreds of function calls which will trigger at the same time, or if you use frequently short delays, the result will be very nasty, compared to a timer component. But if you call the same hundreds of functions grouped into only one delayedCall, performance will be good. So with my first script replicated in many maps, in a mod heavily using other delayedCalls, maybe it could have had an impact. The new script resolves this, as it stands alone so the delayedCall is strictly minimal.
- Timer components do not behave at all like the delayedCall function. First, it seems they are more efficient, especially for short intervals like every frames calls. Also, their interval is raised up by A LOT when they belong to an entity not in the current map. On the other hand, the delayedCall function always uses the interval you give to it, so with the first script I gave, all maps would be checked frequently even if non current maps generally change very slowly. The new one also checks all maps with the same frequency, but do so one map at a time. It could be argued that it should perhaps check the current map more often than the others. To have a timer always in the current map, I could have added it to the party, but did not feel like it to keep the code minimal and not too much spread.
- I tested the colliders creation idea, but I think it really is far from ideal. Perhaps it is more efficient, I don't know it depends entirely on the game engine and I don't have the source, so it would need deeper testing. More efficient than my first script running in several maps, yes that seems legit, but more efficient than checking coordinates ? I'm not convinced ! The real problem is it does in no way reproduce the behavior of the script. Colliders on the map borders are like invisible walls so even if they are good from a technical point of view, they are absolutely terrible from a player point of view. Launching a fire ball to have it instantly explode in your face for no visible reason is bad game design. I even tried to place those colliders farther from the borders of the map, and still the result is not acceptable; the collision occurs away from the party, but again for no visible reason and this time with no sound, you then take the damage of the explosion !