![]() |
#1 | |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() NOTE: You have been redirected in order for our attachments to be made available to you. This will only last two minutes; these measures where taken to avoid hotlinking and bandwidth theft. To avoid these restrictions Log in or Register This spell creates a big ball of incredibly dense matter which draws nearby units into it. After holding them there spinning around for some time, it explodes, dealing damage to every unit which has been pulled into it and sending them flying. Requirements: Jass NewGen Pack for vJass Rising_Dusk's Knockback (And all of its requirements, all made by Rising_Dusk) Grim_001's ListModule Vexorian's Table Ammorth's LinkedList NOTE: the test map uses a custom model which I feel makes the spell look much better. Credits to RightField for that. I believe it is fully MUI and leak-free but please let me know if you find a leak! Read the "How to Import" trigger for detailed instructions on how to import the spell. Please give credits to me (Element of Water) if you use it in your map. Oh, and please don't give stupid comments like "OMG WAY TOO IMBA" because you can make it less "IMBA" by configuring the constants... ![]() ////////////////////////////////////////////////////////////////////////// // Gravity Stone // // A spell by: // // Element of Water // ////////////////////////////////////////////////////////////////////////// library GravityStone initializer Init requires Knockback, ListModule, Table, LinkedList ///////////////////////////////////////// // EDITABLE DATA // // Change these to suit your needs // ///////////////////////////////////////// globals //how far per second units are knocked back at the end of the spell private constant real KNOCKBACK_SPEED = 500. //how much the knockback speed is reduced by each second private constant real KNOCKBACK_DECREMENT = 250. //the special effect which plays when the spell ends private constant string SFX = "Objects\\Spawnmodels\\NightElf\\NEDeathMedium\\NEDeath.mdl" //this is the rawcode of the dummy unit private constant integer DUMMY_ID = 'dum0' //this is the rawcode of the spell private constant integer SPELL_ID = 'A000' //the maximum distance units can be from the ball private constant real MAX_DIST = 250.0 //how fast the units spin round the ball private constant real ORBIT_SPEED = 150.0 //the maximum height of the units when pulled into the ball private constant real MAX_HEIGHT = 750. //the attack type of the damage - determines how much damage is dealt to different kinds of armour private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC //the damage type of the damage - determines which units are immune to the damage. private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC //the weapon type of the damage - determines the sound played based on the armour type of the target //WEAPON_TYPE_WHOKNOWS or null plays no sound private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS //the duration of the timer, AKA how often the places the units move to are updated private constant real TIMER_INTERVAL = 0.1 //the interval at which units' positions are updated when being pulled into the Gravity Stone //lower values give smoother movement, whilst higher values give better performance private constant real PULL_INTERVAL = 0.035 //the higher this is, the more slowly units will be pulled into the gravity stone private constant real PULL_WEIGHT = 15 //the speed the units are pulled into the gravity stone is multiplied by this, giving an effect like friction private constant real PULL_DRAG = 0.975 endglobals //A helper function - SpellLevel(u) returns the spell level of Gravity Stone for the unit private function SpellLevel takes unit u returns integer return GetUnitAbilityLevel(u, SPELL_ID) endfunction //How long the spell lasts private function Duration takes unit u returns real return 2.5 + SpellLevel(u) * 2.5 endfunction //how much damage the spell deals private function Damage takes unit u returns real return 250. + SpellLevel(u) * 250. endfunction //how many units the gravity ball can pull in at once private function MaxUnits takes unit u returns integer return 5 + SpellLevel(u) * 15 endfunction //the range at which the gravity stone pulls in enemy units private function AoE takes unit u returns real return 250. + SpellLevel(u) * 250. endfunction ///////////////////////////////////////// // END EDITABLE DATA // ///////////////////////////////////////// globals private constant integer FLY_HACK = 'Amrf' private location TempLoc = Location(0., 0.) endglobals private struct PullUnit implement List private static timer tim = CreateTimer() //Pulled unit's position vector real xU real yU real zU //Target point's (or unit's) position vector real xT = 0. real yT = 0. real zT = 0. //Offset vector real xO = 0. real yO = 0. real zO = 0. //Velocity vector real xV = 0. real yV = 0. real zV = 0. //Pulled unit unit u real startHeight = 0. real angle = 0. //Private stuff private boolean running = false static HandleTable tbl delegate Link link static method create takes unit whichUnit, List l returns PullUnit local PullUnit p = 0 if .tbl[whichUnit] == 0 then set p = PullUnit.allocate() set p.link = Link.create(l, p) set p.u = whichUnit set p.xU = GetUnitX(p.u) set p.yU = GetUnitY(p.u) set p.zU = GetUnitFlyHeight(p.u) call UnitAddAbility(p.u, FLY_HACK) call UnitRemoveAbility(p.u, FLY_HACK) set .tbl[whichUnit] = p endif return p endmethod static method execute takes nothing returns nothing local PullUnit this = PullUnit.getFirst() loop exitwhen this == 0 set this.xV = this.xV + (this.xT+this.xO-this.xU)/(PULL_WEIGHT/PULL_INTERVAL) set this.yV = this.yV + (this.yT+this.yO-this.yU)/(PULL_WEIGHT/PULL_INTERVAL) set this.zV = this.zV + (this.zT+this.zO-this.zU)/(PULL_WEIGHT/PULL_INTERVAL) set this.xV = this.xV * PULL_DRAG set this.yV = this.yV * PULL_DRAG set this.zV = this.zV * PULL_DRAG set this.xU = this.xU + this.xV set this.yU = this.yU + this.yV set this.zU = this.zU + this.zV call MoveLocation(TempLoc, this.xU, this.yU) call SetUnitX(this.u, this.xU) call SetUnitY(this.u, this.yU) call SetUnitFlyHeight(this.u, this.zU + .startHeight - GetLocationZ(TempLoc), 0.00) set this = this.getNext() endloop endmethod method start takes nothing returns nothing if not .running then set .running = true if .getLength() == 0 then call TimerStart(.tim, PULL_INTERVAL, true, function PullUnit.execute) endif call .addList() call PauseUnit(.u, true) call MoveLocation(TempLoc, .xT, .yT) set .startHeight = GetLocationZ(TempLoc) endif endmethod method stop takes nothing returns nothing if .running then set .running = false call .removeList() if .getLength() == 0 then call PauseTimer(.tim) endif call PauseUnit(.u, false) endif endmethod private method onDestroy takes nothing returns nothing call .stop() set .tbl[.u] = 0 endmethod static method getData takes unit u returns PullUnit return .tbl[u] endmethod private static method onInit takes nothing returns nothing set .tbl = HandleTable.create() endmethod endstruct globals private timer tim = CreateTimer() private boolexpr UnitEnumFilter = null private player TempPlayer = null private group TempGroup = CreateGroup() endglobals private function PolarProjectionX takes real startX, real dist, real angle returns real return startX + dist * Cos(angle * bj_DEGTORAD) endfunction private function PolarProjectionY takes real startY, real dist, real angle returns real return startY + dist * Sin(angle * bj_DEGTORAD) endfunction private function UnitEnum takes nothing returns boolean local unit u = GetFilterUnit() local boolean array b set b[0] = IsUnitEnemy(u, TempPlayer) set b[1] = not IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE) set b[2] = not IsUnitType(u, UNIT_TYPE_STRUCTURE) set b[3] = GetWidgetLife(u) > 0.405 set b[4] = PullUnit.getData(u) == 0 return b[0] and b[1] and b[2] and b[3] and b[4] endfunction private struct Data implement List real x real y real time real maxdist real maxspeed real maxheight real damage unit dummy unit caster real aoe integer numUnits = 0 integer maxUnits List pulledUnits boolean ended = false private method pullMore takes nothing returns nothing local unit u local PullUnit p if .numUnits < .maxUnits then set TempPlayer = GetOwningPlayer(.caster) call GroupEnumUnitsInRange(TempGroup, .x, .y, .aoe, UnitEnumFilter) loop set u = FirstOfGroup(TempGroup) exitwhen u == null or .numUnits == .maxUnits set p = PullUnit.create(u, .pulledUnits) set .numUnits = .numUnits + 1 set p.xT = .x set p.yT = .y call p.start() call GroupRemoveUnit(TempGroup, u) endloop call GroupClear(TempGroup) endif set u = null endmethod private static method execute takes nothing returns nothing local Data this = .getFirst() local PullUnit p local real dist loop exitwhen this == 0 call this.pullMore() set p = this.pulledUnits.first.data loop exitwhen p == 0 set p.angle = p.angle+GetRandomReal(-this.maxspeed/2, this.maxspeed) if p.angle >= 360 then set p.angle = p.angle-360 elseif p.angle <= 0 then set p.angle = p.angle + 360 endif set dist = GetRandomReal(0., this.maxdist) set p.xO = dist * Cos(p.angle * bj_DEGTORAD) set p.yO = dist * Sin(p.angle * bj_DEGTORAD) set p.zO = GetRandomReal(0.0, this.maxheight) set p = p.next.data endloop set this.time = this.time - TIMER_INTERVAL if this.time <= 0 then call this.destroy() endif set this = this.getNext() endloop endmethod static method create takes unit caster, real duration, real x, real y, real damage, integer maxUnits, real range, real dist, real orbitspeed, real height returns Data local Data this = Data.allocate() set this.x = x set this.y = y set this.time = duration set this.damage = damage set this.aoe = range set this.dummy = CreateUnit(Player(12), DUMMY_ID, x, y, 0.00) set this.caster = caster set this.maxUnits = maxUnits set this.pulledUnits = List.create() call this.pullMore() set this.maxdist = dist set this.maxspeed = orbitspeed set this.maxheight = height if .getLength() == 0 then call TimerStart(tim, TIMER_INTERVAL, true, function Data.execute) endif call this.addList() return this endmethod method onDestroy takes nothing returns nothing local PullUnit p = PullUnit(.pulledUnits.first.data) set .ended = true loop exitwhen p == 0 call KnockbackTarget(this.caster, p.u, p.angle, KNOCKBACK_SPEED, KNOCKBACK_DECREMENT, true, false, false) call UnitDamageTarget(.caster, p.u, .damage, false, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE) call SetUnitFlyHeight(p.u, GetUnitDefaultFlyHeight(p.u), KNOCKBACK_SPEED * KNOCKBACK_SPEED / KNOCKBACK_DECREMENT) set p = PullUnit(p.next.data) endloop call .pulledUnits.destroy() call DestroyEffect(AddSpecialEffect(SFX, GetUnitX(.dummy), GetUnitY(.dummy))) call .removeList() if this.getLength() == 0 then call PauseTimer(tim) endif call KillUnit(.dummy) set this.dummy = null set this.caster = null endmethod endstruct private function SpellActions takes nothing returns boolean local unit u local real x local real y local real dur local real rad local real dmg local integer units if GetSpellAbilityId() == SPELL_ID then set u = GetTriggerUnit() set dur = Duration(u) set x = GetSpellTargetX() set y = GetSpellTargetY() set dmg = Damage(u) set units = MaxUnits(u) set rad = AoE(u) call Data.create(GetTriggerUnit(), dur, x, y, dmg, units, rad, MAX_DIST, ORBIT_SPEED*TIMER_INTERVAL, MAX_HEIGHT) endif return false endfunction private function DeathActions takes nothing returns boolean local PullUnit p = PullUnit.getData(GetTriggerUnit()) if p != 0 then call SetUnitFlyHeight(p.u, GetUnitDefaultFlyHeight(p.u), KNOCKBACK_SPEED * KNOCKBACK_SPEED / KNOCKBACK_DECREMENT) call p.destroy() endif return false 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 SpellActions)) set t = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH) call TriggerAddCondition(t, Condition(function DeathActions)) call Preload(SFX) set UnitEnumFilter = Condition(function UnitEnum) endfunction endlibrary
A screenshot of RightField's permission to use his model is attached. Last edited by Element of Water : 09-09-2009 at 09:14 PM. |
|
![]() |
![]() |
Sponsored Links - Login to hide this ad! |
|
![]() |
#2 |
User
Join Date: Jan 2007
Posts: 528
![]() ![]() |
![]() nc spell.
good that they actually have some inertia thing and dont just get moved to the center. but the ground below caught - then flying - units remains unpathable. give them the flying type? edit: sometimes the units dont approach the ball sideways. this might be because they collide. maybe turn this off too, along with pathing. also, i dont think this site approves of resources that use unapproved resources. i dont think PullUnit is approved here so this spell might not be admitted for that. maybe you should get that admitted first or 'sneak it in' by putting the code in that library in library of the spell. Last edited by fX_ : 09-01-2009 at 04:57 PM. |
![]() |
![]() |
![]() |
#3 | |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() Quote:
Anyway, thanks for the feedback. I'll turn off the collision like you suggested. EDIT: Weird, I can't seem to be able to disable the units' collision. I couldn't work out how to make the unit's movement type flying - I don't think it's possible - and SetUnitPathing(u, false) didn't work. I also tried giving the unit the ghost (visible) ability but that also failed. Any ideas anyone? Last edited by Element of Water : 09-01-2009 at 06:02 PM. |
|
![]() |
![]() |
![]() |
#4 | |
Obscurity, the Art
|
![]() You will need to include your spell's code in the first post to facilitate the approval process.
__________________Quote:
|
|
![]() |
![]() |
![]() |
#6 | |
Obscurity, the Art
|
![]() Quote:
|
|
![]() |
![]() |
![]() |
#7 |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() Ok, then, I'll change that. Currently I'm recoding the PullUnit library in the spell so it works on its own, but when I'm done with that I'll fix it so it's approvable here.
|
![]() |
![]() |
![]() |
#8 |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() *Update*
Fixed all that was requested + made a few minor efficiency improvements. Is it approveable now? |
![]() |
![]() |
![]() |
#10 |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() Ok, sorry. Done.
|
![]() |
![]() |
![]() |
#11 |
User
Join Date: Feb 2009
Posts: 203
![]() ![]() |
![]() This spell is bugged. Try casting few of those balls without any enemy units around you, and see what happens.
__________________Also, you should probably use those new GetSpellTargetX & GetSpellTargetY natives. |
![]() |
![]() |
![]() |
#12 | |
Obscurity, the Art
|
![]() Well, first of all, that PullUnit library is again not an approved resource in our database. Your submitted spells cannot require other libraries that are not approved. If you are attempting to submit that library, then you will need to submit it in its own topic and get it approved before this spell can be considered for approval.
__________________Quote:
|
|
![]() |
![]() |
![]() |
#14 |
User
Join Date: Mar 2009
Posts: 147
![]() |
![]() @ Viikuna
Ok, I see the problem, I loop through the picked units even if there are none, added a check for that in the new version. Also, the spell was made originally ages before the 1.24 patch, and I haven't gone through and checked it all since then. I'll change that now. @ Rising_Dusk The PullUnit library is just part of the spell. Yes I made it usable on its own, but it's not meant to be a resource, just part of the spell. I thought wc3c was all for modularity; the fact I used a separate library for it should be a good thing right? Anyway, do you think it's approveable on its own? I don't think so. It doesn't have enough features to be really useful. EDIT: Updated. Last edited by Element of Water : 09-02-2009 at 04:26 PM. |
![]() |
![]() |
![]() |
#15 | ||
Obscurity, the Art
|
![]() Quote:
Modularity without common sense is as useless as no modularity at all. If you want to use PullUnit, submit it individually and get it approved first. If you can simplify the PullUnit math (Really, friction? Just use a knockback in a different direction!) then do so and embed it. Those are the rules. Quote:
|
||
![]() |
![]() |
![]() |
Thread Tools | Search this Thread |
|
|