- Joined
- Mar 29, 2016
- Messages
- 688
The mentioned spell is mow moved here.
Last edited:
(3 ratings)
static if LIBRARY_DummyRecycler then
set dummy = GetRecycledDummyAnyAngle(.centerX, .centerY, 0)
call DummyAddRecycleTimer(dummy, DUMMY_DURATION)
else
set dummy = CreateUnit(DUMMY_OWNER, DUMMY_ID, .centerX, .centerY, 0) // <-- undeclared variable DUMMY_ID
call UnitApplyTimedLife(dummy, 'BTLF', DUMMY_DURATION)
endif
*/boolean selfFilter /* Determines if the <caster> unit is allowed as target
*/boolean allyFilter /* Determines if allies of the <caster> unit are allowed as targets
*/boolean structureFilter /* Determines if structures are allowed as targets
*/boolean mechanicalFilter /* Determines if mechanical units are allowed as targets
*/boolean magicImmuneFilter /* Determines if magic immune units are allowed as targets
*/boolean etherealFilter /* Determines if ethereal units are allowed as targets
*/boolean illusionFilter /* Determines if illusions are allowed as targets
*/boolean deadFilter /* Determines if dead units are allowed as targets
Torrent.target_allowed = UnitAlive(Torrent.instance.u) or/and etc;
for example. The function can be called with ForForce
.I think I've found the cause of this, I'm not sure though.For some reason peasants get stuck in midair which seems to happen only when dead units/corpses are in the AOE of the spell as well.
I think I'll leave the damage on landing part to the users (They can use the custom callback handlers).In my opinion the damage should be done when the explosion happens and on the landing/crashing (falling from a great height) instead of the damage over time.
Will fix thisWhen DummyRecycler is disabled (because its optional) Torrent doesn't compile:
If I understood correctly, that would mean that I can only have 1 type of unit filters for all torrent instances. What I mean is that you can't make it so that Torrent(1) only targets allies while Torrent(2) only targets enemies.instead of a taking a single function that receivesTorrent.instance (as a global) and sets Torrent.target_allowed = UnitAlive(Torrent.instance.u)[/COLOR] or/and etc;
for example. The function can be called withForForce
.
If I understood correctly, that would mean that I can only have 1 type of unit filters for all torrent instances. What I mean is that you can't make it so that Torrent(1) only targets allies while Torrent(2) only targets enemies.
library TargetAllowedDemo initializer init
struct TargetAllowed
static force ta_force
static thistype instance
static unit target
static boolean target_allowed
boolexpr filter_func
private static method onInit takes nothing returns nothing
set ta_force = CreateForce()
call ForceAddPlayer(ta_force, Player(15))
endmethod
static method create takes code filter_func returns thistype
local thistype this = allocate()
set this.filter_func = Filter(filter_func)
return this
endmethod
method test takes unit u returns boolean
if u == null then
return false
endif
// call filter_func with TargetAllowed.instance and TargetAllowed.target as globals
// the result is expected to be stored in TargetAllowed.target_allowed
set instance = this
set target = u
call ForceEnumPlayers(ta_force, this.filter_func)
return target_allowed
endmethod
endstruct
globals
TargetAllowed tauren_or_giant
TargetAllowed undead_and_alive
TargetAllowed ta_active
endglobals
function ta_tauren_or_giant takes nothing returns boolean
local TargetAllowed ta = TargetAllowed.instance
set ta.target_allowed = /*
*/ IsUnitType(ta.target, UNIT_TYPE_GIANT) /*
*/ or IsUnitType(ta.target, UNIT_TYPE_TAUREN)
return false
endfunction
// Filter(function that_doesnt_return_boolean) seems to work although it might not =)
function ta_undead_and_alive takes nothing returns nothing // boolean
local TargetAllowed ta = TargetAllowed.instance
set ta.target_allowed = /*
*/ IsUnitType(ta.target, UNIT_TYPE_UNDEAD) /*
*/ and not IsUnitType(ta.target, UNIT_TYPE_DEAD)
// return false
endfunction
function on_unit_selected takes nothing returns nothing
local unit u = GetTriggerUnit()
local string un = GetUnitName(u)
if ta_active == tauren_or_giant then
if ta_active.test(u) then
call BJDebugMsg(un + " is a tauren or a giant")
else
call BJDebugMsg(un + " is not a tauren nor a giant")
endif
elseif ta_active == undead_and_alive then
if ta_active.test(u) then
call BJDebugMsg(un + " is an alive undead unit")
else
call BJDebugMsg(un + " is either dead or not an undead unit")
endif
endif
set u = null
endfunction
private function init takes nothing returns nothing
local trigger t
set tauren_or_giant = TargetAllowed.create(function ta_tauren_or_giant)
set undead_and_alive = TargetAllowed.create(function ta_undead_and_alive)
set ta_active = tauren_or_giant
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SELECTED)
call TriggerAddAction(t, function on_unit_selected)
endfunction
endlibrary
EDIT:
I think the cause of the tossed units getting stuck midair is that at some cases, the timer is prematurely paused. But I still need to confirm this.
EDIT: Tested. Doesn't seem like it is the cause of the problem.
private function A takes nothing returns nothing
//local unit u = GetTriggerUnit()
//call CreateUnit( GetOwningPlayer( u ), GetUnitTypeId( u ), GetRandomReal( I2R(WorldBounds.minX), I2R(WorldBounds.maxX) ), GetRandomReal( I2R(WorldBounds.minY), I2R(WorldBounds.maxY) ), GetRandomReal( 0, 360 ) )
//call TriggerSleepAction( 10 )
//call RemoveUnit( u )
//set u = null
endfunction
call GroupAddGroup(g, tempGroup)
loop
set u = FirstOfGroup(tempGroup)
exitwhen u == null
call GroupRemoveUnit(tempGroup, u)
//actions
endloop
null
, thus, causing the loop to exit prematurely. Hence why Captain Griffen from wc3c made a GroupRefresh snippet.I now know exactly what's the problem =). It's because of the RemoveUnit(). Removed units aren't automatically removed from the group, they remain but they become null, thus, causing the loop to exit prematurely. Hence why Captain Griffen from wc3c made a GroupRefresh snippet.
FirstOfGroup
returns null on removed (explicitly via RemoveUnit or implicitly via unit decay) units.UnitSuspendDecay(u, true)
while doing so and UnitSuspendDecay(u, false)
when done. Of course this would only work for implicitly removed units, i.e calling RemoveUnit on a dead unit would still be problematic. */method onTorrentExplode takes boolexpr expr returns nothing/*
- Adds a boolexpr of the code that will run upon the Torrent's explosion
*/method onTorrentVanish takes boolexpr expr returns nothing/*
- Adds a boolexpr of the code that will run upon the Torrent's disappearance, after tossed units are landed
- This will not run when <tossUnits> is false
/* Check if this torrent tosses its targets
If yes, make sure it has finished its business
before destroying */
if duration >= 2*TIMEOUT and .elapsed < duration then
loop
call DestroyEffect(LoadEffectHandle(table, this, count))
exitwhen count == 0
set count = count - 1
endloop
set owner = GetOwningPlayer(caster)
this.
inside loop?set table = TableArray[0x2000]
, but yeh.. your preference weights more I believe.speed
to speed_x
or something alike./* Implement map bounds */
static if LIBRARY_WorldBounds then
if centerX < WorldBounds.minX then
set centerX = WorldBounds.minX
elseif centerX > WorldBounds.maxX then
set centerX = WorldBounds.maxX
endif
if centerY < WorldBounds.minY then
set centerY = WorldBounds.minY
elseif centerY > WorldBounds.maxY then
set centerY = WorldBounds.maxY
endif
else
if centerX < minX then
set centerX = minX
elseif centerX > maxX then
set centerX = maxX
endif
if centerY < minY then
set centerY = minY
elseif centerY > maxY then
set centerY = maxY
endif
endif
x = normalize/regulate(x)
)Yes they are both the submissions. TorrentSystem is a system that allows you to easily create uhm well... Torrents (sorry I just borrowed the term from a spell in DotA but I guess not everyone is familiar with it so I need to add a better description soon) while TorrentArray is a spell that summons Torrents in a fancy way (atleast for me =)) using the TorrentSystem. KILLCIDE suggested to put them in two different bundles under 1 resource thread but I find it awkward to do so since the bundle for TorrentArray would also contain TorrentSystem since it is its requirement which would make a separate bundle for TorrentSystem redundant. So yeah, it might be confusing, should I revert both their version numbers to 1 or what can you suggest?TorrentSystem and TorrentArray are both the main submission here? (It's not very clear to me because of the submission name and version numbers)
Indeed, will include them in the update.Why not applying a filter func in config instead of providing all specific bools? (or it can be instance specific, if needed)
Though, the filters seem to cover most common cases by default already, but maybe the limitation is not needed.
They register callback functions, onTorrentExplode() registers a code that will run when a torrent explodes (i.e., when explode() method is called internally) while onTorrentVanish() registers a code that will run when tossed units land.^From docu I don't very understand this. Does it instantly fire the mentioned event(s), or does it only register code to it?
Yes, calling destroy should make the torrent instantly vanish/disappear for the user however, it should not be the case for its effects upon the tossed units because doing so would break the mechanics, that's why the system waits for the all the units to land and leaves the deallocation part to the periodic method later instead.What is the functional meaning? If the condtion doesn't met, then it won't be deallocated in the destroy call? - but the dummy will be recycled?
It is because the loops need to run <number of borders> + 1 times since I put the model of the Torrent itself in the same hashtable with 0 as its key. If I will move it to the top the condition must be == -1 instead of 0.t seems usually better if a exit loop condition is on very top, or is there a reason why it is not?
Well owner isn't declared as instance member, only caster or did you mean it's better to make owner an instance member instead?^Seems it could be avoided when declaring owner as instance member.
Ah right, this one. It is done when I was still addicted of micro-optimizations =), I stored them in locals so that the loop will not have to read arrays (instance members) repeatedly since the loop will run > 1 times on average (since the loop is a unitgroup iteration, it could possibly run many times depending on the aoe). But right now, yeah I think it would be cleaner and shorter if I haven't done those plus I don't think it would really tax on performance that much so I could let those locals go =).Why is there a usage of locals for attackty/damagetype and other members, if we already have access to the data with
this.
inside loop?
Maybe zSpeed because it is along z (height) axisSuggestion to rename speed to speed_x or something alike.
Nice catch, will do next update.Torrent <->DummyUnit relation is 1:1, each torrent is associated by the unit. UnitIndex of the dummyunit could be used instead of allocation method.
Will doCould you add a description of what the system exactly is?
The API needs to explain the variable types next to the names.
I'll try to use Nes's listsMaybe a list can be be required as external system, if you prefer.
It seems doubled but it actually is not because 1 torrentarray contains 1 or more torrents but the user only have access to the torrentarray members and not the individual composing torrent's members, which means that the individual torrent's members should be based/copied from the torrentarray, not the torrentarray basing its data from the torrents.Why are all members doubled that a TorrentSystem already provides? Like Damage/Attacktype, etc. A torrent array, should only take usage of it, and can additionaly have new members, but at it's best it should not double anything.
//config
torrentarray.data1 = <set by user>
torrentarray.data2 = <set by user>
//...
//internal (loop through all torrents)
torrent1.data1 = torrentarray.data1
torrent1.data2 = torrentarray.data2
//...
torrent2.data1 = torrentarray.data1
torrent2.data2 = torrentarray.data2
//...
torrentN.data1 = torrentarray.data1
torrentN.data2 = torrentarray.data2
//...
Hmm, if I'd make it a separate function, It would still be of the same length because I only use them once in each lib.Such logics, only to get good x/y onCast. Maybe requring some libs is good for the code, or making an extra function to regulate the correct value.
Right, pause might not be so good as it would have some unwanted side-effects, but I prefer if there would not be a stun special effect attached overhead the units =). How about setting both propwindow and turnrate to 0.00? I'm not so sure how exactly it mimics stun, I imagine they can still use abilities. But if there are no other alternative, then I'll use the stun.Why not stunning a unit instead of pause?
Could we maybe rename it to registerOnTorrentExplode or so? I mean I have read the texts actually... but onTorrentExplode somehow sounds like some event to me as itself.They register callback functions, onTorrentExplode() registers a code that will run when a torrent explode
Ah ok, I didn't reaylize it.^^ Maybe yes.Maybe zSpeed because it is along z (height) axis
But so there's no hard destroy? Like it instantly finished everything. Sorry maybe it's no too clever question, I dont have all scenarios in mind atm, if it makes sense for you not to allow a instant destroy then it maybe makes sense.Yes, calling destroy should make the torrent instantly vanish/disappear for the user however, it should not be the case for its effects upon the tossed units because doing so would break the mechanics, that's why the system waits for the all the units to land and leaves the deallocation part to the periodic method later instead.
Yeh it only tries to disable movement. Maybe a stun system is good, I'm currently not sure which is the 'best'.. though.setting both propwindow and turnrate to 0.00?
You mean separate submissions, or bundle?I personaly would maybe also tend to do TorrentSystem submission, and then TorrentArray as new submission
Right, I also find some of my old namings a bit off, will change it.Could we maybe rename it to registerOnTorrentExplode or so? I mean I have read the texts actually... but onTorrentExplode somehow sounds like some event to me as itself.
Hmm, I'm actually thinking of one way to destroy the effects completely and not break the mechanics, that is, to drop all tossed units instantly.But so there's no hard destroy? Like it instantly finished everything.