| 12-11-2008, 10:09 AM | #1 |
MindFlay is a spell of WoW, which works like life drain (and i based it on lifedrain therefore), but additionally slows the target while casting .. It would be nice if someone could look through my triggers and tell me if i could improve anything... uses Table-System tried without worked pretty well, but if units walked out of mindflay range, the debuff was not removed so i added Table stuff Start Trigger: JASS:globals Table MindFlayArr endglobals function MindFlayStartCond takes nothing returns boolean return ( GetSpellAbilityId() == 'A000' ) //MindFlay Spell id endfunction function Trig_Mind_Flay_Start_Actions takes nothing returns nothing local unit caster=GetTriggerUnit() local unit target=GetSpellTargetUnit() local location l=GetUnitLoc(target) local player p=GetOwningPlayer(caster) local unit cdummy=CreateUnitAtLoc(p,'u000',l,0.) call IssueTargetOrder(cdummy,"slow",target) call UnitApplyTimedLife( cdummy, 'BTLF', 3.00) set MindFlayArr[H2I(caster)]=H2I(target) //=========================================================================== //cleanup set caster=null set target=null set cdummy=null set l=null call RemoveLocation(l) endfunction //=========================================================================== function InitTrig_Mind_Flay_Start takes nothing returns nothing local integer index set gg_trg_Mind_Flay_Start = CreateTrigger( ) set index = 0 loop call TriggerRegisterPlayerUnitEvent(gg_trg_Mind_Flay_Start, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null) set index = index + 1 exitwhen index == 9 endloop call TriggerAddAction( gg_trg_Mind_Flay_Start, function Trig_Mind_Flay_Start_Actions ) call TriggerAddCondition( gg_trg_Mind_Flay_Start, Condition( function MindFlayStartCond )) endfunction MindFlay End Trigger JASS:function InitTrig_Mind_Flay_Canceled takes nothing returns nothing local integer index set gg_trg_Mind_Flay_Canceled = CreateTrigger( ) set index = 0 loop call TriggerRegisterPlayerUnitEvent(gg_trg_Mind_Flay_Canceled, Player(index), EVENT_PLAYER_UNIT_SPELL_ENDCAST, null) call TriggerRegisterPlayerUnitEvent(gg_trg_Mind_Flay_Canceled, Player(index), EVENT_PLAYER_UNIT_SPELL_FINISH, null) set index = index + 1 exitwhen index == 9 endloop call TriggerAddCondition( gg_trg_Mind_Flay_Canceled, Condition( function MindFlayCancelCond ) ) call TriggerAddAction( gg_trg_Mind_Flay_Canceled, function Trig_Mind_Flay_Actions ) endfunction any critics ?? Thanks ;) |
| 12-13-2008, 09:57 PM | #2 |
bump any suggestions...any way around table stuff, attachments ..? |
| 12-13-2008, 11:13 PM | #3 |
The end trigger is just an Init_Trig... Also, function TriggerRegisterAnyUnitEventBJ <--- okay to use You should know that EVENT_PLAYER_UNIT_SPELL_ENDCAST fires when the spell is canceled AND when it is finished. So, if you register both taht and SPELL_FINISH, you will be running an action twice if he actually finishes the spell. It could all be compiled into one trigger, for one. If you're using vJass, then lets stop this atrocity of code: JASS:scope MindFlay globals private HandleTable T endglobals private function startconditions takes nothing returns boolean return ( GetSpellAbilityId() == 'A000' ) //MindFlay Spell id endfunction private function oncast takes nothing returns nothing local unit caster=GetTriggerUnit() local unit target=GetSpellTargetUnit() local location l=GetUnitLoc(target) local player p=GetOwningPlayer(caster) local unit cdummy=CreateUnitAtLoc(p,'u000',l,0.) call IssueTargetOrder(cdummy,"slow",target) call UnitApplyTimedLife( cdummy, 'BTLF', 3.00) //I'm not sure what this is used for, but it looks unsafe :< set T[caster]=H2I(target) //cleanup //note that we destroy the location, THEN null it. //otherwise, we are destroying a null location. call RemoveLocation(l) set l=null //however, a location isn't even necessary, and //could be replaced with reals (x and y). set caster=null set target=null set cdummy=null endfunction private function onfinish takes nothing returns nothing //whatever you are doing here endfunction private function cancelconditions takes nothing returns boolean //some condition here endfunction private function init takes nothing returns nothing local trigger t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(t,Condition(function startconditions)) call TriggerAddAction(t,function oncast) set t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddCondition(t,Condition(function cancelconditons)) call TriggerAddAction(t,function onfinish) set T=Table.create() endfunction endscope |
| 12-13-2008, 11:31 PM | #4 |
im currently on a holiday weekend with some other guys (=im drunk) i will check this tomorrow or so .. anyway thanks for your answer |
| 12-14-2008, 07:31 PM | #5 |
This is what i come up with today: JASS:scope MindFlay initializer init globals private HandleTable MF endglobals private function SpellId takes nothing returns boolean return ( GetSpellAbilityId() == 'A000' ) //MindFlay Spell id endfunction private function oncast takes nothing returns nothing local unit caster=GetTriggerUnit() local unit target=GetSpellTargetUnit() local location l=GetUnitLoc(target) local player p=GetOwningPlayer(caster) local unit cdummy=CreateUnitAtLoc(p,'u000',l,0.) call IssueTargetOrder(cdummy,"slow",target) call UnitApplyTimedLife( cdummy, 'BTLF', 3.00) set MF[caster]=H2I(target) call RemoveLocation(l) set l=null set caster=null set target=null set cdummy=null endfunction private function onfinish takes nothing returns nothing local unit caster=GetTriggerUnit() local unit target=GetSpellTargetUnit() if(target==null)and(MF.exists(caster)) then set target=I2U(MF[caster]) endif if not( target==null) then call UnitRemoveAbility(target, 'B000') endif call MF.flush(caster) set caster=null set target=null endfunction private function init takes nothing returns nothing local trigger t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddAction(t,function oncast) call TriggerAddCondition(t,Condition(function SpellId)) set t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddAction(t,function onfinish) call TriggerAddCondition(t,Condition(function SpellId)) set MF=Table.create() endfunction endscope set T[caster]=H2I(target) //I'm not sure what this is used for, but it looks unsafe Here i save the target unit, for the onfinish trigger, where i remove the buff. JASS:
local unit target=GetSpellTargetUnit()
if(target==null)and(MF.exists(caster)) then
set target=I2U(MF[caster])
endif
if not( target==null) then //dunno if i still need that if.. here
call UnitRemoveAbility(target, 'B000')
endif
when the spell is canceled (e.g. owner of unit cancels it, or casting unit gets stunned) local unit target=GetSpellTargetUnit() will get the target unit. However, when the spell finishes normally, target will be null... so i get the unit from the table, where i saved the unitid of the target in trigger oncast... hmm i just thought about this once a again and i come to the conclusion, i dont need this... I just need to adjust Duration of my dummy-slow-spell to normal duration of Mindflay, so i only need to cover any cancel effect, so i can get rid of the table stuff... EDIT: GetSpellTargetUnit() will return the target unit for most cancels, but not if the target unit walks out of range, so i still need the attachment stuff thanks Here-b-Trollz PS: you forgot to add initializer to your scope :> |
| 12-14-2008, 08:12 PM | #6 |
Don't use table in this manner. Use a struct or array indexing via Cohadar's PUI or something like it, and Here-b-Trollz is correct in that use of a table like that is unsafe, especially since you are using I2U which is an outdated and dangerous way of typecasting. EDIT: You should also indent properly and space out sections of your code so it's more readable for other people. |
| 12-14-2008, 08:15 PM | #7 |
a struct for 1 unit ...seems a bit odd for me dunno... JASS:struct unit oddunit endstruct well how does the background of structs work then ?? does it use global unit arrays or what ? and what should be used to typecast these days then ? (i want pointers and references :/ Jass is so friggin limited) |
| 12-14-2008, 08:25 PM | #8 |
What you really want is a unit array of targets, you can typecast using H2I for the caster's memory address but it will return the target unit. I'll edit this post and tell you more about structs. Struct refers to structure, or a custom object type that arrays each of its members. Each of these members becomes a global array, whose individual indexes hold the data that pertains to each struct instance. When you "create" a struct instance you are allocating the data for each arrayed member of that instance. So when you declare a local "struct", you're really just declaring the index that pertains to a certain set of struct members. Make sense? I'll show you what I mean about the global unit array: JASS:scope MindFlay initializer init globals private unit array targets[8190] private constant integer MIN_HANDLE_ID=0x100000 endglobals private function H2I takes handle h returns integer return h return 0 endfunction private function oncast takes nothing returns nothing local unit caster=GetTriggerUnit() local unit target=GetSpellTargetUnit() local unit cdummy=CreateUnit(GetOwningPlayer(caster), 'u000', GetUnitX(target), GetUnitY(target), 0.) call IssueTargetOrder(cdummy,"slow",target) call UnitApplyTimedLife( cdummy, 'BTLF', 3.00) set targets[H2I(caster)-MIN_HANDLE_ID]=target set caster=null set target=null set cdummy=null endfunction private function onfinish takes nothing returns nothing call UnitRemoveAbility(targets[H2I(GetTriggerUnit())-MIN_HANDLE_ID], 'B000') endfunction private function SpellId takes nothing returns boolean return ( GetSpellAbilityId() == 'A000' ) //MindFlay Spell id endfunction private function init takes nothing returns nothing local trigger t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddAction(t,function oncast) call TriggerAddCondition(t,Condition(function SpellId)) set t=CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddAction(t,function onfinish) call TriggerAddCondition(t,Condition(function SpellId)) endfunction endscope And I ended up rewriting the whole script for you. Does it make sense? What I showed you I think is not a totally safe way of indexing your target, especially since the indices aren't getting recycled. That's where PUI's GetUnitIndex would come in. |
| 12-14-2008, 08:59 PM | #9 |
Thanks... well but doesnt this leak a unit: call UnitRemoveAbility(targets[H2I(GetTriggerUnit())-MIN_HANDLE_ID], 'B000') ... GetTriggerUnit()..? hmm question: what is when H2I(GetTriggerUnit())-MIN_HANDLE_ID is greater than 8190 ? is that possible ? i dont know how unitids work...if i lets say 8190 units ...the next one should have id 8191 ? ...and then i remove 100 units...and create another one ...will it have id 8091 or something like that ? |
| 12-14-2008, 09:45 PM | #10 |
No that does not leak a unit, it merely gives you a pointer to the triggering unit. I think you are getting confused with locations, where if you refer to GetSpellTargetLoc or the like you are actually creating a new location every time, which needs to be removed and nulled. All handles are assigned a memory address, the 8191'th handle created at a certain point in the game will have that memory address. Subtracting the minimum handle ID drastically lowers the integer and lets you put it into a regularly sized array, that's why I (and Vexorian, whom I imitated) did it. Unit ID's aren't memory addresses, they refer to the type of unit. 'u000' is a Unit ID. It refers to the first custom undead unit you made in the editor. You're thinking that units have their own table of memory addresses, but I believe all handle addresses are lumped into one giant hash table for the game, which is why you subtract the mind handle id... |
| 12-14-2008, 09:50 PM | #11 |
so i could use GetTriggerUnit (and GetSpellTargetUnit and so on) as often as i would like and it would not leak ? ..thats good to hear :> but i assume those function calls are slow and when i use those functions more then once (or twice ...?) local units are better speed-wise ? i did not meant something like 'u000' but something like H2I(unit)...with unit ids ...hmm maybe my wording was a lil bit unclear :> |
| 12-14-2008, 10:10 PM | #12 |
Yes, 2 or more uses of a function like those pretty much necessitate using a local. That's what I'm trying to say, you're mixing terminologies. u000 is a unit ID, and you're thinking of memory addresses. |
| 12-15-2008, 04:33 AM | #13 | |
i would rather call something like 'u000' unittype id, because it doesnt specify a specific unit, but an unittype ... what should i call H2I(handle) then ? for this is a identifier of a handle (unit) so i called it unitid -.- i didnt got this question answered,yet :( Quote:
|
| 12-15-2008, 04:47 AM | #14 | |
That array limit will be reached when your map has more than 8190 handles altogether existing at the same time, and your question was a bit vague at first. If you removed 100 units from the game and then created no handles after that point in time, the next unit's memory address would probably be 8091, yes. But that's a shitload of handles. Quote:
Think of the "unit ID" as an integer pointer assigned to that unit, though these integers are not just assigned to units, they are assigned consecutively to all handles created during the course of the game. That's what I mean by memory address. |
| 12-15-2008, 10:22 AM | #15 |
H2I's give memory address for handles. These memory address's are theoritically reused in a stack like manner (i.e. if a unit is removed that handle is recycled and a new one is used). 8190 is the limit for arrays, not for handles. Im not sure what limit handles has, but its probably as many as you're computer can handle. Unit ID's are just an identification of a unit (i.e. the type of unit) and has nothing to do with handles specifically |
