| 07-24-2007, 06:11 AM | #1 | |
Screenie: Foreword: This is my second Jass spell made for a request. Hopefully you (users) do post good or bad comments, because it will make me happy in knowing that people are looking at this thread. Plus Don't talk about Dota thanks. The Spell: What this spell does is creates a Web when within the web you'll gain a regeneration bonus and permenant invisibility. This spell follows the JESP format. Web Description: Dota and this The main differences between this and Dota is that this is open source. This spell does not cast permenant webs yet they create timed ones instead. This is coded with vJass and yet again it follows the JESP standard. Implementing this spell is easy for JASS and GUI users alike as there is a implemention readme to help you out, since it is JESP its even easier. And the ability the add un-limited spells through a simple setup trigger which is commented to help you out when adding some of your own abilities, this is the closest you can get for the Dota's "Web" spell. Requries: - JASSHelper easiest way to get this is through JASSNewGenPack Credits: - Vexorian for JASSHelper - Anitarf for his pointers and how to fix stuff - moyack, cohadar, Rising_Dusk for their help in some way
Web code:scope Web // Web v5.00 Fourth and final Release By Av3n // // Please visit [url]www.wc3campaigns.net[/url] for more updates of this spell // // Requires // - JASSHelper preprocessor by Vexorian // // Credits to moyack, cohadar, blu_da_noob, Rising_Dusk and Anitarf // for the suggestions that changed my spell. globals private integer sid = 'A002' // Web's spell rawcode, based on the Healing Ward ability private integer aid = 'A001' // Web's aura rawcode, based on the Devotion Aura ability private integer wid = 'e000' // Web's summoned unit rawcode, based on the Wisp unit private integer bid = 'B001' // Web's aura buff rawcode, the buff comes from Web's aura rawcode private real AoE = 150. // This variable should match Web's AoE on both aura and spell AoE's // Note: AoE stands for Area of Effect private real cr = 0.1 // Web's timer execution rate // Below are important are not to be touched private integer array spells private integer amount = 0 endglobals private function Setup_Abi takes nothing returns nothing set spells[1] = 'A000' //Web (Regen) set spells[2] = 'A003' //Web (Perm Invisbility) // Set your abilities you want to add to the caster when it's under the effects of Web here // An example to add a new ability is like this // set spells[3] = 'A005' // then set amount = 3. Remember that every ability you have, go in a increment of 1 and don't start at 0 // i.e // set spells[1] = 'A001' // set spells[2] = 'A002' // set spells[3] = 'A005' // set amount = 2 // The 'amount' specifies how much spells are added so any number after the 'amount' won't be added set amount = 2 endfunction globals private timer webTimer private integer index private integer array indexes private integer tempInt endglobals private struct Web unit c unit w integer l static method removeAbilities takes unit who returns nothing set tempInt = 0 loop exitwhen tempInt > amount call UnitRemoveAbility(who,spells[tempInt]) set tempInt = tempInt + 1 endloop endmethod static method onLoop takes nothing returns nothing local Web W local integer i = index loop exitwhen i < 0 set W = Web(indexes[i]) if GetWidgetLife(W.w) < 0.405 then call Web.removeAbilities(W.c) call W.destroy() set indexes[i] = indexes[index] set index = index - 1 elseif GetUnitAbilityLevel(W.c,bid) > 0 or IsUnitInRange(W.c,W.w,AoE) then set tempInt = 0 loop exitwhen tempInt > amount call UnitAddAbility(W.c,spells[tempInt]) call SetUnitAbilityLevel(W.c,spells[tempInt],W.l) set tempInt = tempInt + 1 endloop else call Web.removeAbilities(W.c) endif set i = i - 1 endloop if index < 0 then call PauseTimer(webTimer) endif endmethod static method create takes nothing returns Web local Web a = Web.allocate() set a.c = GetSummoningUnit() set a.w = GetSummonedUnit() set a.l = GetUnitAbilityLevel(a.c,sid) call UnitAddAbility(a.w,aid) set index = index + 1 set indexes[index] = integer(a) if index == 0 then call TimerStart(webTimer,cr,true,function Web.onLoop) endif return a endmethod endstruct private function Conditions takes nothing returns boolean return GetUnitTypeId(GetSummonedUnit()) == wid endfunction function InitTrig_Web takes nothing returns nothing set gg_trg_Web = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_Web, EVENT_PLAYER_UNIT_SUMMON) call TriggerAddCondition(gg_trg_Web, Condition( function Conditions ) ) call TriggerAddAction(gg_trg_Web, function Web.create ) call Setup_Abi() set webTimer = CreateTimer() set index = -1 endfunction endscope -Av3n |
| 07-24-2007, 12:59 PM | #2 |
I didn't have downloaded your spell, but checking the code, I think we can improve some stuff. We can improve the constant value usage replacing those long functions with private globals. Something like this: Improved constant definition:globals private constant integer Web_id = 'A001' //Web spell id based on Channel private constant integer Web_dummy = 'e000' //Web's dummy unit private constant integer Web_timerbuff = 'BTLF' //Web's timer buff which is showed when clicking on the web Example: // '|||Water Elemantal| |' will be showed the UI when Water Elemental clicked on private constant integer Web_permhide = 'A003' //Web Permenant Invisiblity id. Also this could be any ability. private constant integer Web_regen = 'A000' //Web Regeneration id. Also this could be any ability. private constant integer Web_looprate = .1 //Loop rate for checking if the caster within the web endglobals As you can see, it takes less written space and is more readable. You are using a loop with PolledWait, why use this when you have something more accurate which is the timer itself?? I suggest to add a conditional at the end of the timer loop code that checks if the dummy is alive. Other thing that I noticed is that you use GetUnitState(d,UNIT_STATE_LIFE) == 0 by GetWidgetLife(d) <= 0.405, it's faster. I'll do a complete review later, but you can do this changes meanwhile |
| 07-25-2007, 04:44 AM | #3 |
I'll go and change it then and reformat the thread a little bit. -Av3n UPDATE: I done abit of things to the code so that. The Timer function kills off the trigger. Hopefully Im disposing the struct correctly though... |
| 07-28-2007, 05:57 AM | #4 |
Bump? -Av3n |
| 07-28-2007, 09:25 PM | #5 |
Steps: Summon more than one web Stand at a point out of range of any one (or more) of your webs, but inside another web Watch your hero not become invisible Bug fix :) |
| 07-28-2007, 09:37 PM | #6 |
Ok, I'll fix that when I've time (Going out today... when I've have homework), I might have to do a few scaling stuff as well and such to fit the radius. Thanks for pointing things out. Multiple Web problems? Ok thats something new... -Av3n |
| 07-29-2007, 11:08 AM | #7 |
It's because each web checks if the hero is in range and removes the ability if it is not. So you're in range of one, it adds the ability, then the second web runs and sees that you aren't so it removes the ability. |
| 08-05-2007, 04:42 AM | #8 |
Well BUMP! and it isn't over a week so it still ok... But straight to the point I've fixed it thanks to Anitarf that is. There's one more bug. Im gonna check it a few more times, it says it hit the limit op or something, its happens when the web dies. So this version is very unstable. Any ideas how to fix it? -Av3n UPDATE: Don't worry fixed it. Just trying to pause the timer correctly now UPDATE: All fixed! |
| 08-07-2007, 01:33 AM | #9 |
Ok Av3n, I've checked your spell, and...well, I think that in this moment it has too many stuff that is unnecessary to the spell purpose and it can be done in a simpler way. Let's review the spell idea. In general you propose a spell which gives some abilities to the caster if it is in the range of the web (aka dummy unit with a kind of triggered aura.) Now we should see how the web should behave:
JASS:struct Web unit caster // it saves the unit which will be beneficed by the aura unit dummy // it stores the dummy unit which will center the triggered aura endstruct With this we can ensure that this spell will be MUI because we're linking the caster with the dummy unit. Now because this spell summons a dummy unit and gives a benefit to the caster, we should select an appropriate base spell to develop it, in this case Healing Ward would be the perfect base spell. Why?? let's see:
Now we should make the trigger activates when the caster summon the web, so the init_trigger function should be in this way: JASS:function InitTrig_Web takes nothing returns nothing //Not part of the scope! local trigger t //Creating an local trigger creating it then nulling it. No global trigger //varibles are needed set t = CreateTrigger() call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SUMMON ) call TriggerAddCondition(t, Condition( function Web_Conditions ) ) call TriggerAddAction(t, function Web_Actions ) set t = null endfunction The Web_Conditions function should detect if the kind of unit is the required, something like this: JASS:public function Conditions takes nothing returns boolean return GetUnitTypeId(GetSummonedUnit()) == SummonedID endfunction And the Web_Actions function should be in this way: JASS:public function Actions takes nothing returns nothing // all the highlighted vars are private globals local timer t = NewTimer() local Web W = Web.create() set W.caster = GetSummoningUnit() set W.dummy = GetSummonedUnit() call SetHandleInt(t, "Webdata", W) call TimerStart(t, dt, true, function webloop) set t = null endfunction now we need to know how to make the periodic evaluation. First we need that the spell detects if the caster is inside the web, if it's true, then add the abilities (if the caster doesn't have them), else, remove them (if the caster has the abilities). One suggestion in this part: I'd add one ability based on spellbook, so you spell can be customized in this part by editing the data in the dummy ability. Doing this in that way, we only have to check if the caster has the spellbook ability only. Now let's see how the loop code will look. JASS:// the hightlited parts are private globals to add function webloop takes nothing returns nothing local timer t = GetExpiredTimer() local Web W = Web( GetHandleInt(t, "Webdata") ) if IsUnitInRange(W.caster, W.dummy, AOE) and GetUnitAbilityLevel(W.caster, SpellBookAbil) < 1 then call UnitAddAbility(W.caster, SpellBookAbil) endif if not IsUnitInRange(W.caster, W.dummy, AOE) and GetUnitAbilityLevel(W.caster, SpellBookAbil) > 0 then call UnitRemoveAbility(W.caster, SpellBookAbil) endif if GetWidgetLife(W.dummy) < 0.405 then // kills the timer loop call FlushHandleLocals(t) call ReleaseTimer(t) call W.destroy() endif set t = null endfunction As you can see, this spell is very efficient, it uses few functions and achieves the same result. I'm afraid that you were too worried for specific stuff and suddenly you lost the general idea. Remember that doing an efficient spell is not only coding, it implies to have clear the idea of your spell, how configurable should it be, and how it should look in game. Remember this: if your spell is too long, is because it's becoming into a system or in something unnecessarily complex and buggy. I hope it can help you to improve this spell and other spells in this activity. |
| 08-07-2007, 05:41 AM | #10 |
I got a feeling that the same problem is gonig to happen again with multiple webs, so I'll have to use a global web var. Anitarf is doing the exact opposite to your idea having it only use 1 timer and a list of web's summoned etc. But I do agree about using a AoE indicator ability ,using spellbooks and about long code. But if I was to do it this way, I'll have to do it someway that I can access all the web's the caster summonned (Using HandleVars) and check them if the caster is within the web etc. -Av3n |
| 08-07-2007, 08:09 AM | #11 |
I suggest you use ABC system for your web. Now this suggestion is probably seen as biased, but think of this: You are using loopings in global arrays to support your web structs. That is exactly what ABC does, and instead of using those loop1 and loop2 that garble your code you could simply use SetStructA, GetStructA, ClearStructA. Try rewriting your code with ABC and you will realize that it is simpler, more readable and easier that way. Just look at the slide spell inside ABC demo map, and you will get the idea really fast. |
| 08-07-2007, 09:19 PM | #12 | |
Some corrections from my previous post: loop function:private function webloop takes nothing returns nothing local timer t = GetExpiredTimer() local Web W = Web( GetHandleInt(t, "Webdata") ) if IsUnitInRange(W.caster, W.dummy, AOE) and GetUnitAbilityLevel(W.caster, SpellBookAbil) < 1 then call UnitAddAbility(W.caster, SpellBookAbil) endif if not IsUnitInRange(W.caster, W.dummy, AOE) and GetUnitAbilityLevel(W.caster, SpellBookAbil) > 0 then call UnitRemoveAbility(W.caster, SpellBookAbil) endif if GetWidgetLife(W.dummy) < 0.405 then // kills the timer loop if GetUnitAbilityLevel(W.caster, SpellBookAbil) > 0 then call UnitRemoveAbility(W.caster, SpellBookAbil) endif call FlushHandleLocals(t) call ReleaseTimer(t) call W.destroy() endif set t = null endfunction init_trigger function:function InitTrig_WebMoyack takes nothing returns nothing local trigger t = CreateTrigger()//Creating an local trigger creating it then nulling it. No global trigger //varibles are needed local integer i = 0 loop // Disables to all players the spell container ability // so it can't display in the command card. exitwhen i > 15 call SetPlayerAbilityAvailable(Player(i), SpellBookAbil, false) set i = i + 1 endloop call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SUMMON ) call TriggerAddCondition(t, Condition( function WebM_Conditions ) ) call TriggerAddAction(t, function WebM_Actions ) set t = null endfunction Quote:
Please use all that can help you, and to make things clear, it is not an obligation to follow my comments. If you consider that your spell is right as is, there won't be any problem with me. If you need any help, I'm gladly help you as best as possible. |
| 08-08-2007, 02:44 AM | #13 |
I do appreciate your comment guys. I'll try update it with shorter code like moyack suggested. I want to try moyack's way first. If it does work I'll adjust my spell using moyack's way. It will be ready hopefully by sunday. -Av3n |
| 08-09-2007, 06:39 PM | #14 | |
Well it will work, his idea is good. It uses one timer per web, and attaches spelldata to that timer, it can't get more MUI than that. But it could be somewhat inneficient if there are lots of units that cast web, because if there are 100 webs there will be 100 timers with .1 period. But I doubt anyone wants to make a map with 100 webs :D @moyack: Quote:
Where did you get that 0.405 constant ? |
| 08-09-2007, 08:51 PM | #15 | |
Quote:
|
