| 03-23-2008, 05:46 PM | #1 |
History This spell was made specifically for the tenth wc3c spell session, with the theme of aimed spells. Requires JassNewGenPack v4d, or later Credits Vexorian: JassHelper, GetPathability PipeDream: Grimoire PitzerMike: PJass Description The Blademaster goes into a focused berserk around a controllable point of balance, damaging enemy units with his dance. More damage is done at higher speeds. The point around which the hero "oscillates" can be moved by the player, so the direction and speed can be constantly adjusted to suit the situation.
Complies with the JESP standard. Read Me Read Me://==================================================================================// // READ ME: HARMONIC BERSERK BY: ALEXANDER244 // //==================================================================================// //==========================================================================// // IMPLEMENTING: // //==========================================================================// Requirements: * JassNewGenPack v4c or newer ([url]www.wc3campaigns.net[/url]) * Pathability Library (Copy from this map) * HarmonicBerserk Scope (Copy from this map) * Harmonic Berserk Ability (Copy from this map) * Magic Immunity Spellbook Ability (Copy from this map) * Equilibrium Unit (Copy from this map) Implementing: * Save the map * SPELL_ID in the config section set to Harmonic Berserk Ability custom value * DUMMY_ID in the config section set to Equilibrium Unit custom value * MAGIC_IMMUNE_ID in the config section set to Magic Immunity Spellbook custom value * Make sure that the Magic Immunity Spellbook contains a valid spell immunity ability * Update other config values * Test //==========================================================================// // RANDOM INFO: // //==========================================================================// OBJECT EDITOR EDITS: COMMENTS: Caster Pitch Angle I suggest you set this to zero, or the spell can look strange on slopping terrain The globals for the spell triggers are: <SCOPE_NAME>_SPELL_EFFECT //Trigger to detect spell effect <SCOPE_NAME>_OBJECT_ORDER //Trigger to detect orders for caster and equilibrium //==========================================================================// // CREDITS: // //==========================================================================// Vexorian: GetPathability and JassHelper PipeDream: Grimoire PitzerMike: PJass Rising_Dusk, Szythe, Ignitedstar and Toadcop: Suggestions //==========================================================================// // UPDATES: // //==========================================================================// //**************************************************************************// // VERSION: 1.3 // //**************************************************************************// * Fixed a few spelling mistakes (Thanks Rising_Dusk) * the onDestroy in the spelldata struct is now private (Thanks Rising_Dusk) * Added several config options to give more control over the hero and the equilibrium * Recoded a few sections to support these new options * Fixed a bug where if the target widget of the equilibrium died, the equilibrium moved randomly //**************************************************************************// // VERSION: 1.2 // //**************************************************************************// * Added option for equilibrium to be vulnerable (Thanks Ignitedstar) * Cleaned up the configuration section a bit * Several minor tweaks * Possibly fixed a supposed divide by zero error experienced by Anitarf (Not sure about this) //**************************************************************************// // VERSION: 1.1 // //**************************************************************************// * Equilibrium unit now selected on spell cast, and if the equilibrium unit is selected by the player at the end of the spell, the hero is reselected. (Thanks Szythe) * Added an expiration bar to the equilibrium unit. * The equilibrium unit experiences changes in alpha colouring depending on the distance between it and the caster. * Equilibrium unit now has triggered movement; higher movement speeds can be set, blizzard pathing is no longer an annoyance and the lightning attach height is correct on all terrain levels. * Stopped the caster becoming stuck on collision with unpathable terrain (and several other issues caused by this fix). * Restricted spell area to make the spell more controllable (Thanks Toadcop). * Made the spell easier to configure. * Reduced the ability to abuse centripetal motion for high speeds (this can be configured) * The spell now only uses one group (I realised before I was using up to 800 per sec...) //==========================================================================// Spell Code Spell Code://==================================================================================// // SPELL: HARMONIC BERSERK BY: ALEXANDER244 // // VERSION: 1.3 // //==================================================================================// scope HarmonicBerserk private keyword spelldata //==========================================================================// // CONFIGURATION SECTION: // //==========================================================================// // BASIC // //--------------------------------------------------------------------------// // SPELL_ID = ID of the spell ability in the object editor // EQUIL_ID = ID of the equilibrium unit in the object editor // MAGIC_IMMUNE_ID = ID of a spellbook containing spell immunity. The spellbook will be disabled. // NUMBER_LEVELS = How many levels are there in the spell (so constants can be precalculated) // SPELL_ORDERID = OrderId of the spell ability, can be found in the object editor // LIGHTNING_ID = ID of the lightning between the hero and equilibrium point // CASTER_ANIMATION = Animation the caster should play for the spell duration // ANIM_SPEED_MULTIPLIER = Speed multiplier of caster animation // TIMER_PERIOD = Rate at which the effect loop executes, effects appearance and performance // MAX_MOVESTEP = Max distance the caster can move at once; used to prevent jumping over unpathable terrain // & jaggedy movement. MAX movespeed = this value/timer period. // ATTACH_HEIGHT_CASTER = Height of the connecting lightning on the caster // ATTACH_HEIGHT_EQUIL = Height of the connecting lightning on the equilibrium unit // EQUIL_FLYHEIGHT = Fly height of the equilibrium unit // DAMPING_PER_SEC = Speed decrease as percentage per sec, if moving in a CIRCLULAR-ish motion // above max distance, this is to prevent abuse of centripetal motion for high speeds // 100 == no damping, 0 == instant stop // EQUIL_INVULNERABLE = Should the equilibrium unit be invulnerable (if it dies, spell ends) // CASTER_INVULNERABLE = Should the caster be invulnerable (if it dies, spell ends // EQUIL_CONTROLLABLE = Should the equilibrium unit be controllable // CASTER_CONTROLLABLE = Should the caster be controllable (can order out of channeling the ability) // EQUIL_MAGIC_IMMUNE = Should the equilibrium unit be immune to magic // CASTER_MAGIC_IMMUNE = Should the caster be immune to magic (cannot be disabled while casting) // if CASTER_MAGIC_IMMUNE == false, CASTER_CONTROLLABLE needs to be true, or stunning // abilities will fail to stun the caster. // DAMAGE_TYPE = Damage type of berserk damage // ATTACK_TYPE = Attack type of berserk damage // DAMAGE_XXX = If target is XXX, should it be damaged? true/false // other DAMAGE_XXX options can easily be added under the advanced section globals private constant integer SPELL_ID = 'A000' private constant integer EQUIL_ID = 'h000' private constant integer MAGIC_IMMUNE_ID = 'A002' private constant integer NUMBER_LEVELS = 3 private constant string SPELL_ORDERID = "berserk" private constant string LIGHTNING_ID = "LEAS" private constant string CASTER_ANIMATION = "Attack Walk Stand Spin" private constant real ANIM_SPEED_MULTIPLIER = 1. private constant real TIMER_PERIOD = 0.025 private constant real MAX_MOVESTEP = 32. private constant real ATTACH_HEIGHT_CASTER = 100. private constant real ATTACH_HEIGHT_EQUIL = 180. private constant real EQUIL_FLYHEIGHT = 10. private constant real DAMPING_PER_SEC = 75.0 private constant boolean EQUIL_INVULNERABLE = true private constant boolean CASTER_INVULNERABLE = false private constant boolean EQUIL_CONTROLLABLE = true private constant boolean CASTER_CONTROLLABLE = false private constant boolean EQUIL_MAGIC_IMMUNE = false private constant boolean CASTER_MAGIC_IMMUNE = true endglobals globals private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL private constant boolean DAMAGE_ENEMY = true private constant boolean DAMAGE_ALLY = false private constant boolean DAMAGE_AIR = false private constant boolean DAMAGE_GROUND = true private constant boolean DAMAGE_STRUCTURE = true private constant boolean DAMAGE_MAGICIMMUME = true private constant boolean DAMAGE_MECHANICAL = true private constant boolean DAMAGE_ETHEREAL = false endglobals //Duration of the spell //If the caster is controllable, this must be the same as in the object editor private constant function DURATION takes integer lvl returns real return 20. endfunction //Time it takes for one oscillation, assuming equilibrium unit stationary and no path blocks private constant function OSCILLATION_PERIOD takes integer lvl returns real return 4.2 - .2*lvl endfunction //If this value is exceeded, the caster will experience massive acceleration towards the equilibrium //This value will also effect the max speed that can be achieved within the max range, so approx the correct //OSCILLATION_PERIOD is achieved. Lower values make the spell more controllable by the player private constant function MAX_DISTANCE takes integer lvl returns real return 200. + 20. * lvl endfunction //Movement speed of the equilibrium unit (this movement is triggered, so set as high as you like) private constant function EQUIL_MOVESPEED takes integer lvl returns real return 300 + 50.*lvl endfunction //Area around hero that receives damage private constant function AOE takes integer lvl returns real return 220. endfunction //Damage delt to enemies in area every second private constant function DAMAGE takes integer lvl returns real return 5. + lvl * 10. endfunction //Extra Damage done at max speed per sec, this is a linear increase from zero speed //Max speed occurs by the equilibrium when max distance is achieved, and can also be achieved //by the player spinning the caster in a circle. //Note that although damage per sec is higher, contact time per unit will be less. private constant function MAX_SPEED_BONUS_DAM takes integer lvl returns real return 10. + lvl * 20. endfunction // ADVANCED // //--------------------------------------------------------------------------// //Check if onDamage function should be called for target private function DamageFilter takes player caster, unit target returns boolean local boolean b = true set b = b and GetWidgetLife(target) > 0.405 set b = b and not (not DAMAGE_ENEMY and IsPlayerEnemy(GetOwningPlayer(target), caster)) set b = b and not (not DAMAGE_ALLY and IsPlayerAlly(GetOwningPlayer(target), caster)) set b = b and not (not DAMAGE_GROUND and IsUnitType(target, UNIT_TYPE_GROUND)) set b = b and not (not DAMAGE_AIR and IsUnitType(target, UNIT_TYPE_FLYING)) set b = b and not (not DAMAGE_STRUCTURE and IsUnitType(target, UNIT_TYPE_STRUCTURE)) set b = b and not (not DAMAGE_MAGICIMMUME and IsUnitType(target, UNIT_TYPE_MAGIC_IMMUNE)) set b = b and not (not DAMAGE_MECHANICAL and IsUnitType(target, UNIT_TYPE_MECHANICAL)) set b = b and not (not DAMAGE_ETHEREAL and IsUnitType(target, UNIT_TYPE_ETHEREAL)) return b endfunction //onDamage function; do stuff with caster and target private function onDamage takes unit caster, unit target, real damage returns nothing call UnitDamageTarget(caster, target, damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS) endfunction //onFinish of spell; do stuff with caster and affected units //group targets will be destroyed after this function, so no waits if you want to use it. private function onFinish takes unit caster, group targets returns nothing //maybe caster gets temp bonus, related to number of units affected etc. endfunction //==========================================================================// // MAIN SECTION: // //==========================================================================// // GLOBAL DECLARATIONS // //--------------------------------------------------------------------------// globals public trigger SPELL_EFFECT = CreateTrigger() public trigger OBJECT_ORDER = CreateTrigger() private integer SPELLDATA_TOTAL = 0 private spelldata array SPELLDATA_ARRAY private timer SPELL_TIMER = CreateTimer() private group TEMPGROUP = CreateGroup() private location TEMPLOC = Location(0,0) private boolexpr BOOL_TRUE private real minX private real maxX private real minY private real maxY private real array EQUILSPEED private real array MAXSPEED private real array ACCELERATION_CONST private real DAMPING_FACTOR = Pow((DAMPING_PER_SEC/100), TIMER_PERIOD) endglobals // UTILITY FUNCTIONS // //--------------------------------------------------------------------------// private function BOOLEXPR_TRUE takes nothing returns boolean return true endfunction private function MakeFlyable takes unit u returns nothing call UnitAddAbility(u, 'Amrf') call UnitRemoveAbility(u, 'Amrf') endfunction // STRUCT DECLARATIONS // //--------------------------------------------------------------------------// private struct spelldata //General readonly player owner readonly integer lvl readonly group targets = CreateGroup() boolean dest = false //Caster readonly unit caster real cvx = 0. real cvy = 0. //Equilibrium readonly unit equil real evx = 0. real evy = 0. string order = "stop" boolean temp = true widget etw = null real etx = 0. real ety = 0. real epx = 0. real epy = 0. //Lightning readonly lightning ltng static method create takes unit caster, real tx, real ty returns spelldata local spelldata sd = spelldata.allocate() local real hx = GetUnitX(caster) local real hy = GetUnitY(caster) local real hz local real tz call MoveLocation(TEMPLOC, hx, hy) set hz = GetLocationZ(TEMPLOC) call MoveLocation(TEMPLOC, tx, ty) set tz = GetLocationZ(TEMPLOC) //General set sd.owner = GetOwningPlayer(caster) set sd.lvl = GetUnitAbilityLevel(caster, SPELL_ID) //Caster set sd.caster = caster if CASTER_MAGIC_IMMUNE then call UnitAddAbility(caster, MAGIC_IMMUNE_ID) endif call PauseUnit(caster, not CASTER_CONTROLLABLE) call SetUnitInvulnerable(caster, CASTER_INVULNERABLE) call SetUnitAnimation(caster, CASTER_ANIMATION) call SetUnitTimeScale(caster, ANIM_SPEED_MULTIPLIER) //Equilibrium set sd.equil = CreateUnit(sd.owner, EQUIL_ID, tx, ty, 0.) if EQUIL_MAGIC_IMMUNE then call UnitAddAbility(sd.equil, MAGIC_IMMUNE_ID) endif call MakeFlyable(sd.equil) call SetUnitFlyHeight(sd.equil, EQUIL_FLYHEIGHT, 0.) call UnitApplyTimedLife(sd.equil, 'BTLF', DURATION(sd.lvl)+TIMER_PERIOD) call SetUnitInvulnerable(sd.equil, EQUIL_INVULNERABLE) call PauseUnit(sd.equil, not EQUIL_CONTROLLABLE) //Lightning set sd.ltng = AddLightningEx(LIGHTNING_ID, true, hx, hy, hz + ATTACH_HEIGHT_CASTER, tx, ty, tz + ATTACH_HEIGHT_EQUIL) //Selection if GetLocalPlayer() == sd.owner then call SelectUnit(sd.caster, false) call SelectUnit(sd.equil, true) endif return sd endmethod private method onDestroy takes nothing returns nothing local unit caster = .caster call onFinish(caster, .targets) if GetWidgetLife(caster) > 0.405 then call SetUnitPosition(caster, GetUnitX(caster), GetUnitY(caster)) call SetUnitAnimation(caster, "Stand") if IsUnitSelected(.equil, .owner) then if GetLocalPlayer() == .owner then call SelectUnit(.equil, false) call SelectUnit(caster, true) endif endif else call SetUnitAnimation(caster, "Death") endif if GetWidgetLife(.equil) > 0.405 then call KillUnit(.equil) endif call DestroyGroup(.targets) call DestroyLightning(.ltng) call PauseUnit(caster, false) call UnitRemoveAbility(caster, MAGIC_IMMUNE_ID) call SetUnitTimeScale(caster, 1.) set caster = null endmethod endstruct // PERIODIC FUNCTIONS // //--------------------------------------------------------------------------// private function SpellLoop takes nothing returns nothing local integer i = 0 local unit caster local unit equil local unit target local spelldata sd local string order local real hx local real hy local real hz local real tx local real ty local real tz local real t2x local real t2y local real angle local real theta local real acc local real s local real dist local real dam local boolean b //Go through all running instances of the spell loop exitwhen i == SPELLDATA_TOTAL set sd = SPELLDATA_ARRAY[i] //Get Basic Info set caster = sd.caster set equil = sd.equil set hx = GetUnitX(caster) set hy = GetUnitY(caster) call MoveLocation(TEMPLOC, hx, hy) set hz = GetLocationZ(TEMPLOC) set tx = GetUnitX(equil) set ty = GetUnitY(equil) call MoveLocation(TEMPLOC, tx, ty) set tz = GetLocationZ(TEMPLOC) set order = sd.order //Update Lightning call MoveLightningEx(sd.ltng, true, hx, hy, hz + ATTACH_HEIGHT_CASTER, tx, ty, tz + ATTACH_HEIGHT_EQUIL) //Woking out new velocity of equilibrium //If equilibrium has a widget target: if not (sd.etw == null) then set t2x = GetWidgetX(sd.etw) - tx set t2y = GetWidgetY(sd.etw) - ty //if the equil not at widgets location if t2y*t2y+t2x*t2x > EQUILSPEED[sd.lvl]*EQUILSPEED[sd.lvl] then set angle = Atan2(t2y, t2x) set sd.evx = Cos(angle) * EQUILSPEED[sd.lvl] set sd.evy = Sin(angle) * EQUILSPEED[sd.lvl] else set sd.evx = 0. set sd.evy = 0. endif if GetWidgetLife(sd.etw) < 0.405 then call IssueImmediateOrder(equil, "stop") endif //If equilibrium is not moving but has a movement order: elseif (sd.evx == 0. and sd.evy == 0. and (order == "move" or order == "smart" or order == "patrol")) then set t2x = sd.etx - tx set t2y = sd.ety - ty //if the equil not at target point if t2y*t2y+t2x*t2x > EQUILSPEED[sd.lvl] * EQUILSPEED[sd.lvl] then set angle = Atan2(t2y, t2x) set sd.evx = Cos(angle) * EQUILSPEED[sd.lvl] set sd.evy = Sin(angle) * EQUILSPEED[sd.lvl] //If it is at target point, and has patrol order elseif order == "patrol" then set t2x = sd.epx - tx set t2y = sd.epy - ty set angle = Atan2(t2y, t2x) set sd.evx = Cos(angle) * EQUILSPEED[sd.lvl] set sd.evy = Sin(angle) * EQUILSPEED[sd.lvl] endif //If equilibrium is moving: elseif not (sd.evx == 0. and sd.evy == 0.) then set t2x = sd.etx - tx set t2y = sd.ety - ty //If equil has reached target point if t2y*t2y+t2x*t2x < EQUILSPEED[sd.lvl] * EQUILSPEED[sd.lvl] then if not (order == "patrol") then call IssueImmediateOrder(equil, "stop") else set sd.evx = 0. set sd.evy = 0. endif elseif order == "patrol" then set t2x = sd.epx - tx set t2y = sd.epy - ty //If equil has reached patrol target if t2y*t2y+t2x*t2x < EQUILSPEED[sd.lvl] * EQUILSPEED[sd.lvl] then set sd.evx = 0. set sd.evy = 0. endif endif endif //Move equilibrium + pathing checks if not (sd.evx == 0. and sd.evy == 0.) then set tx = tx + sd.evx set ty = ty + sd.evy if tx > maxX then set tx = maxX elseif tx < minX then set tx = minX endif if ty > maxY then set ty = maxY elseif ty < minY then set ty = minY endif call SetUnitX(equil, tx) call SetUnitY(equil, ty) endif //Working out new velocity of caster set b = true set ty = ty - hy set tx = tx - hx set angle = Atan2(ty, tx) set dist = SquareRoot(ty*ty + tx*tx) set acc = ACCELERATION_CONST[sd.lvl] * dist if dist > MAX_DISTANCE(sd.lvl) then set sd.cvx = sd.cvx + Cos(angle) * 2 * acc * acc set sd.cvy = sd.cvy + Sin(angle) * 2 * acc * acc set s = SquareRoot(sd.cvx * sd.cvx + sd.cvy * sd.cvy) if s > MAX_MOVESTEP then set sd.cvx = (MAX_MOVESTEP * sd.cvx) / s set sd.cvy = (MAX_MOVESTEP * sd.cvy) / s set b = false endif //theta is the angle between motion vector and caster-equil vector if not (s == 0.) then set theta = Acos((tx*sd.cvx+ty*sd.cvy)/(SquareRoot(tx*tx+ty*ty)*s)) if not (theta < bj_PI*0.25 or theta > bj_PI*0.75) then set sd.cvx = sd.cvx * DAMPING_FACTOR set sd.cvy = sd.cvy * DAMPING_FACTOR endif endif set dist = MAX_DISTANCE(sd.lvl) //so equilibrium alpha does not exceed 100% else set sd.cvx = sd.cvx + Cos(angle) * acc set sd.cvy = sd.cvy + Sin(angle) * acc set s = sd.cvx * sd.cvx + sd.cvy * sd.cvy if s > MAXSPEED[sd.lvl] * MAXSPEED[sd.lvl] then set s = SquareRoot(s) set sd.cvx = (MAXSPEED[sd.lvl] * sd.cvx) / s set sd.cvy = (MAXSPEED[sd.lvl] * sd.cvy) / s endif endif //Move caster + pathing checks etc. set tx = hx + sd.cvx set ty = hy + sd.cvy if Pathability_Check(tx, ty) then call SetUnitX(caster, tx) call SetUnitY(caster, ty) else if not Pathability_Check(tx, hy) then if b then if sd.cvx < 0. then call SetUnitX(caster, hx + 4.) else call SetUnitX(caster, hx - 4.) endif endif set sd.cvx = 0 endif if not Pathability_Check(hx, ty) then if b then if sd.cvy < 0. then call SetUnitY(caster, hy + 4.) else call SetUnitY(caster, hy - 4.) endif endif set sd.cvy = 0 endif endif //Update Effects call SetUnitVertexColor(equil, 255, 255, 255, R2I(255*(dist/MAX_DISTANCE(sd.lvl)))) call SetUnitAnimation(caster, CASTER_ANIMATION) //Damages enemies in berserk area call GroupClear(TEMPGROUP) call GroupEnumUnitsInRange(TEMPGROUP, tx, ty, AOE(sd.lvl), BOOL_TRUE) if not (FirstOfGroup(TEMPGROUP) == null) then set dam = DAMAGE(sd.lvl) * TIMER_PERIOD set s = sd.cvx*sd.cvx+sd.cvy*sd.cvy if s < MAXSPEED[sd.lvl]*MAXSPEED[sd.lvl] then set s = SquareRoot(s)/MAXSPEED[sd.lvl] else set s = 1 endif set dam = dam + s * TIMER_PERIOD * MAX_SPEED_BONUS_DAM(sd.lvl) endif loop set target = FirstOfGroup(TEMPGROUP) exitwhen target == null call GroupRemoveUnit(TEMPGROUP, target) if DamageFilter(sd.owner, target) then call onDamage(caster, target, dam) call GroupAddUnit(sd.targets, target) endif endloop //If spell ended (due to a unit death or caster order), destroy the spell instance if (GetWidgetLife(caster) < 0.405 or GetWidgetLife(equil) < 0.405 or sd.dest) then set SPELLDATA_TOTAL = SPELLDATA_TOTAL - 1 set SPELLDATA_ARRAY[i] = SPELLDATA_ARRAY[SPELLDATA_TOTAL] call sd.destroy() set i = i - 1 endif set i = i + 1 endloop //Pause the timer if there are no spell instances if SPELLDATA_TOTAL == 0 then call PauseTimer(SPELL_TIMER) endif set caster = null set equil = null endfunction // SPELL EFFECT FUNCTIONS // //--------------------------------------------------------------------------// private function SpellEffectCondition takes nothing returns boolean return GetSpellAbilityId() == SPELL_ID endfunction private function SpellEffectAction takes nothing returns nothing local location l = GetSpellTargetLoc() set SPELLDATA_ARRAY[SPELLDATA_TOTAL] = spelldata.create(GetSpellAbilityUnit(), GetLocationX(l), GetLocationY(l)) set SPELLDATA_TOTAL = SPELLDATA_TOTAL + 1 //If no other spell instances active the timer will need starting if SPELLDATA_TOTAL == 1 then call TimerStart(SPELL_TIMER, TIMER_PERIOD, true, function SpellLoop) endif call RemoveLocation(l) set l = null endfunction // OBJECT ORDER FUNCTIONS // //--------------------------------------------------------------------------// private function ObjectOrder takes nothing returns boolean local unit u = GetTriggerUnit() local spelldata sd local integer i = 0 local widget w local string s //If the equilibrium is controllable, see if it was issued an order if EQUIL_CONTROLLABLE and GetUnitTypeId(u) == EQUIL_ID then //Get the spell data the equilibrium is part of, if none, return loop if i == SPELLDATA_TOTAL then set u = null return false endif set sd = SPELLDATA_ARRAY[i] exitwhen sd.equil == u set i = i + 1 endloop //temp is used so that stop can be ordered without causing loops if sd.temp then //'null' all previous order data set sd.evx = 0. set sd.evy = 0. set sd.etw = null set sd.etx = 0. set sd.ety = 0. set sd.epx = 0. set sd.epy = 0. //find what order was issued and do appropriate set w = GetOrderTarget() set s = OrderId2String(GetIssuedOrderId()) set sd.order = s if not (w == null) then set sd.etw = w set w = null elseif s == "patrol" then set sd.epx = GetUnitX(u) set sd.epy = GetUnitY(u) set sd.etx = GetOrderPointX() set sd.ety = GetOrderPointY() elseif s == "smart" or s == "move" then set sd.etx = GetOrderPointX() set sd.ety = GetOrderPointY() endif //Stop the effects of the actual order occuring set sd.temp = false call PauseUnit(u, true) call IssueImmediateOrder(u, "stop") call PauseUnit(u, false) set sd.temp = false else set sd.temp = true endif //If the caster is controllable, see if it was issued an order elseif CASTER_CONTROLLABLE then //Check if the ordered unit is part of a spelldata loop if i == SPELLDATA_TOTAL then set u = null return false endif set sd = SPELLDATA_ARRAY[i] exitwhen sd.caster == u set i = i + 1 endloop //if the caster was issued an order, set spell to be destroyed set sd.dest = true endif set u = null return false endfunction // INITIALIZATION // //--------------------------------------------------------------------------// public function InitTrig takes nothing returns nothing local integer i = 0 //The triggers loop call TriggerRegisterPlayerUnitEvent(SPELL_EFFECT, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, null) call TriggerRegisterPlayerUnitEvent(OBJECT_ORDER, Player(i), EVENT_PLAYER_UNIT_ISSUED_ORDER, null) call TriggerRegisterPlayerUnitEvent(OBJECT_ORDER, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null) call TriggerRegisterPlayerUnitEvent(OBJECT_ORDER, Player(i), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null) call SetPlayerAbilityAvailable(Player(i), MAGIC_IMMUNE_ID, false) set i = i + 1 exitwhen i == 16 endloop call TriggerAddCondition(SPELL_EFFECT, Condition(function SpellEffectCondition)) call TriggerAddCondition(OBJECT_ORDER, Condition(function ObjectOrder)) call TriggerAddAction(SPELL_EFFECT, function SpellEffectAction) //Some Constants that need setting post global decleration or are array values set minX = GetRectMinX(bj_mapInitialPlayableArea) set maxX = GetRectMaxX(bj_mapInitialPlayableArea) set minY = GetRectMinY(bj_mapInitialPlayableArea) set maxY = GetRectMaxY(bj_mapInitialPlayableArea) set BOOL_TRUE = Filter(function BOOLEXPR_TRUE) set i = 0 loop set i = i + 1 exitwhen i > NUMBER_LEVELS set EQUILSPEED[i] = EQUIL_MOVESPEED(i) * TIMER_PERIOD set MAXSPEED[i] = 4 * bj_PI * MAX_DISTANCE(i) * TIMER_PERIOD / OSCILLATION_PERIOD(i) set ACCELERATION_CONST[i] = (2 * bj_PI * (1 / OSCILLATION_PERIOD(i))) * TIMER_PERIOD set ACCELERATION_CONST[i] = ACCELERATION_CONST[i] * ACCELERATION_CONST[i] endloop endfunction endscope |
| 03-23-2008, 06:44 PM | #2 |
In your spelldata struct, your onDestroy method should be private. Otherwise, I can find absolutely nothing wrong other than the fact that you spelled "Declarations" as "Declerations" and that it's "Berserk" and not "Beserk". :p |
| 03-23-2008, 06:58 PM | #3 | |
Quote:
Ok, I think I got all of them... updated Edit: arg, missed one (in the game start message)... updated |
| 03-23-2008, 07:02 PM | #4 |
Yeah, it looks really good now. I'll let another submissions person look it over before moving it over in case I missed something. |
| 03-24-2008, 04:08 AM | #5 |
It's fine; I've checked it. 'proved! |
| 04-07-2008, 12:10 PM | #6 |
really cool! and funny |
