Our first concern was making wards more tangible within the code. The original way we did them was to create an infinite timer for ward "pulses". Within this timer, it would check every possible ward to see if it was "active" and trigger its pulse. This is ugly for two reasons. One, because the code has to look at EVERY ward every time the timer fires off. And two, because it meant wards could only pulse at set intervals (unless we did some even more ugly workarounds). So we scrapped that and came up with a new way to handle wards. At ward creation, a handle to the ward pulse timer is generated and stored. If the ward duration is finite, we create another timer to kill the pulse timer. This means that every ward now has a unique pulse timer, and can thus have unique properties associated with it. No more looping through every ward, and no more fixed pulse intervals.
Our second concern was abstractly separating the idea of a ward from any particular type of ward. We've seen damaging wards and healing wards, but there can be so many different types of wards with different effects. We wanted to make it easy for people to not only implement custom ward behavior, but to reuse that behavior without resorting to copy/paste. I've worked with making wards before and I can tell you how annoying it is. So we scrapped our fixed-behavior wards and created a system for developing and registering custom ward behaviors with the war3 system. The idea is remarkably similar to race creation.
So what does all of this amount to? 14 new natives and 4 new forwards, with room for expansion.
Let's talk about ward creation.
Relevant natives:
Code:
_:War3_CreateWard(client, Float:location[], radius, Float:duration, Float:pulseInterval, String:behavior[], any:data[]={0}, bool:selfInflict=false, War3WardAffinity:affinity=ENEMIES);
_:War3_GetWardBehavior(wardindex);
War3_GetWardLocation(wardindex, Float:location[]);
Float:War3_GetWardInterval(wardindex);
_:War3_GetWardRadius(wardindex);
_:War3_GetWardOwner(wardindex);
War3_GetWardData(wardindex, any:data[]);
_:War3_GetWardBehavior(wardindex);
War3_GetWardLocation(wardindex, Float:location[]);
Float:War3_GetWardInterval(wardindex);
_:War3_GetWardRadius(wardindex);
_:War3_GetWardOwner(wardindex);
War3_GetWardData(wardindex, any:data[]);
When you call the War3_CreateWard function, a ward index is returned, which will be used extensively for other functions. Notice the parameters for ward creation. You need an owner id, location, radius, duration, pulse interval, and a behavior shortname. Optional parameters are data, selfInflict, and affinity. Data is specialized parameterization that is sent to ward behaviors to determine things like damage or heal amount. The selfInflict and affinity parameters determine what the ward will target. If selfInflict=true, it will trigger on its owner in addition to its targeting affinity. The possible affinities are ENEMIES, ALLIES, ALL, and SELF_ONLY. Note that if you do selfInflict=false and affinity=SELF_ONLY, this ward will not trigger on anybody. This can be used as a special type of ward that doesn't need to target anything.
So let's talk about ward behaviors.
Relevant natives:
Code:
_:War3_CreateWardBehavior(String:shortname[],String:name[],String:desc[]);
_:War3_GetWardBehaviorsLoaded();
War3_GetWardBehaviorName(id,String:retstr[],maxlen);
War3_GetWardBehaviorShortname(id,String:retstr[],maxlen);
War3_GetWardBehaviorDesc(id,String:retstr[],maxlen);
_:War3_GetWardBehaviorByShortname(String:shortname[]);
_:War3_GetWardBehaviorsLoaded();
War3_GetWardBehaviorName(id,String:retstr[],maxlen);
War3_GetWardBehaviorShortname(id,String:retstr[],maxlen);
War3_GetWardBehaviorDesc(id,String:retstr[],maxlen);
_:War3_GetWardBehaviorByShortname(String:shortname[]);
When War3_CreateWardBehavior is called, a behavior index is generated to identify that behavior. You'll need this index to identify your behavior throughout a ward's lifetime. By ward lifetime, I am, of course, referring to the forwarded ward events.
Forwards:
Code:
OnWardCreated(wardindex,behaviorID);
OnWardPulse(wardindex,behaviorID);
OnWardTrigger(wardindex,victim,owner,behaviorID);
OnWardExpire(wardindex,owner,behaviorID);
OnWardPulse(wardindex,behaviorID);
OnWardTrigger(wardindex,victim,owner,behaviorID);
OnWardExpire(wardindex,owner,behaviorID);
These forwards should be pretty self explanatory, so I'll be brief. When a ward "pulses" it fires off an OnWardPulse event. This is where you will want to implement the visual effects for your custom ward behaviors. When a ward pulses with a potential target in range, it will fire off an OnWardTrigger event. This is where you will want to implement the physical effects for your custom ward behaviors. Whenever a ward is removed from the map, an OnWardExpire event is fired off. Because the ward information is lost upon ward death, this one sends the owner's id and the behaviorID so that you can actually work with it. I may need to add additional information to this forward, so this probably won't be the end result of my labors.
Well that was a loooooong post. Thanks for reading, and I hope you're just as excited about this new feature as I am!





Logged


DarkEnergy


