- Joined
- Mar 14, 2009
- Messages
- 98
So I had some spare time and thought, "Hey, you know what would be cool? Diablo 2's Frozen Orb spell in Warcraft 3." So I made one. I'm just having one problem, at the very end, the spell doesn't create missiles that shoot in every direction (like diablo 2's Frozen Orb does). I can't find the reason for the problem. Anyone wanna help out? +Rep to whomever can find the solution.
P.S. This includes a missile system (and attachment system) I've made just today. No vJASS, sorry. I haven't bothered to learn it yet.
Attached is the test map I made. It's not much.
P.S. This includes a missile system (and attachment system) I've made just today. No vJASS, sorry. I haven't bothered to learn it yet.
JASS:
globals
real MAX_MISSILE_MOVE_DISTANCE = 50
unit array FrozenOrbMissiles[8192]
timer array FrozenOrbTimers[8192]
real array FrozenOrbSpeed[8192]
real array FrozenOrbDistanceTraveled[8192]
real array FrozenOrbDistanceMax[8192]
real array FrozenOrbCollisionSize[8192]
integer array FrozenOrbLevel[8192]
integer array FrozenOrbSpell[8192]
integer array FrozenOrbSpellOrderID[8192]
boolean udg_GroupEmptyCheck
player udg_CollisionPlayer
endglobals
function H2I takes handle H returns integer
return H
return 0
endfunction
function MainOrbFilter takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)
endfunction
function CollisionFilter takes nothing returns boolean
return IsUnitEnemy(GetFilterUnit(), udg_CollisionPlayer)
endfunction
//GroupEmptyCheck and GroupEmptyCheck2 is for seeing if a group is empty.
function GroupEmptyCheck2 takes nothing returns nothing
set udg_GroupEmptyCheck = false
endfunction
function GroupEmptyCheck takes group g returns boolean
set udg_GroupEmptyCheck = true
call ForGroup(g, function GroupEmptyCheck2)
return udg_GroupEmptyCheck
endfunction
//This function simplifies making dummy units to cast spells.
function UnitCastSpellOnTarget takes player whichPlayer, widget whichUnit, integer whichSpell, integer spellLevel, integer orderID returns nothing
local unit Caster = CreateUnit(whichPlayer, 'n000', GetWidgetX(whichUnit), GetWidgetY(whichUnit), 0)
call SetUnitVertexColor(Caster, 255, 255, 255, 0)
call UnitAddAbility(Caster, whichSpell)
call SetUnitAbilityLevel(Caster, whichSpell, spellLevel)
call UnitApplyTimedLife(Caster, 'BTLF', 0.50)
call IssueTargetOrderById(Caster, orderID, whichUnit)
set Caster = null
endfunction
//Timer function for the missile. It moves the missile a certain amount, then checks if
//there is anything the missile should be hitting around it. If it does, then it creates a
//dummy unit and casts a spell on it. If not, then it checks if the missile has traveled
//its maximum distance. If the missile has traveled far enough, then it destroys the
//missile and frees the "struct".
function SingleTargetMissileTimerFunction takes nothing returns nothing
local integer index = ModuloInteger(H2I(GetExpiredTimer()), 8192)
local group g = CreateGroup()
local real CurrentX = GetUnitX(FrozenOrbMissiles[index])
local real CurrentY = GetUnitY(FrozenOrbMissiles[index])
local boolexpr filter
if GetUnitTypeId(FrozenOrbMissiles[index]) == 'ball' then
set filter = Filter(function MainOrbFilter)
else
set filter = Filter(function CollisionFilter)
endif
call SetUnitPosition(FrozenOrbMissiles[index], CurrentX+Cos(Deg2Rad(GetUnitFacing(FrozenOrbMissiles[index])))*FrozenOrbSpeed[index], CurrentY+Sin(Deg2Rad(GetUnitFacing(FrozenOrbMissiles[index])))*FrozenOrbSpeed[index])
set FrozenOrbDistanceTraveled[index] = FrozenOrbDistanceTraveled[index] + FrozenOrbSpeed[index]
set udg_CollisionPlayer = GetOwningPlayer(FrozenOrbMissiles[index])
call GroupEnumUnitsInRange(g, CurrentX, CurrentY, FrozenOrbCollisionSize[index], filter)
if GroupEmptyCheck(g) then
if FrozenOrbDistanceTraveled[index] >= FrozenOrbDistanceMax[index] then
call RemoveUnit(FrozenOrbMissiles[index])
set FrozenOrbMissiles[index] = null
call DestroyTimer(FrozenOrbTimers[index])
set FrozenOrbTimers[index] = null
endif
else
call UnitCastSpellOnTarget(GetOwningPlayer(FrozenOrbMissiles[index]), FirstOfGroup(g), FrozenOrbSpell[index], FrozenOrbLevel[index], FrozenOrbSpellOrderID[index] )
call RemoveUnit(FrozenOrbMissiles[index])
set FrozenOrbMissiles[index] = null
call DestroyTimer(FrozenOrbTimers[index])
set FrozenOrbTimers[index] = null
endif
call DestroyGroup(g)
set g = null
call DestroyBoolExpr(filter)
set filter = null
endfunction
//This function takes a whole bunch of stuff. Most of it is pretty self-explanatory,
//boolean followRange checks if the missile should stop where the spell was cast or if it
//should go with maxRange. The ability stuff is for what happens when the missile hits
//something.
function LaunchSingleTargetMissileAtPoint takes player missileOwner, integer missileType, real speed, location origin, location destination, real maxRange, boolean followRange, real collisionSize, integer abilityToCast, integer abilityLevel, integer abilityOrderID returns unit
local integer index
local timer Temp
loop
set Temp = CreateTimer()
exitwhen FrozenOrbTimers[ModuloInteger(H2I(Temp), 8192)] == null
call DestroyTimer(Temp)
endloop
set index = ModuloInteger(H2I(Temp), 8192)
set FrozenOrbTimers[index] = Temp
set FrozenOrbMissiles[index] = CreateUnit(missileOwner, missileType, GetLocationX(origin), GetLocationY(origin), AngleBetweenPoints(origin, destination))
call SetUnitPathing(FrozenOrbMissiles[index], false)
call SetUnitPosition(FrozenOrbMissiles[index], GetLocationX(origin), GetLocationY(origin))
call SetUnitFacing(FrozenOrbMissiles[index], AngleBetweenPoints(origin, destination))
if followRange then
set FrozenOrbDistanceMax[index] = maxRange
else
set FrozenOrbDistanceMax[index] = DistanceBetweenPoints(origin, destination)
endif
set FrozenOrbDistanceTraveled[index] = 0
set FrozenOrbCollisionSize[index] = collisionSize
set FrozenOrbLevel[index] = abilityLevel
set FrozenOrbSpell[index] = abilityToCast
set FrozenOrbSpellOrderID[index] = abilityOrderID
if speed/25 < MAX_MISSILE_MOVE_DISTANCE then
set FrozenOrbSpeed[index] = speed/25
call TimerStart(FrozenOrbTimers[index], 0.04, true, function SingleTargetMissileTimerFunction)
else
set FrozenOrbSpeed[index] = 50
call TimerStart(FrozenOrbTimers[index], 50/speed, true, function SingleTargetMissileTimerFunction)
endif
set Temp = null
set origin = null
set destination = null
set missileOwner = null
return FrozenOrbMissiles[index]
endfunction
JASS:
globals
integer FROZEN_ORB_MAIN_ID = 'ball'
integer FROZEN_ORB_SHARD_ID = 'shrd'
integer FROZEN_ORB_SHARD_SPELL = 'ewan'
real FROZEN_ORB_SHARD_COLLISION_SIZE = 64
real FROZEN_ORB_MAIN_COLLISION_SIZE = 64
real FROZEN_ORB_MAIN_SPEED = 500
real FROZEN_ORB_SHARD_SPEED = 700
real FROZEN_ORB_FINAL_SHARD_SPEED = 900
real FROZEN_ORB_MAIN_RANGE = 1000
real FROZEN_ORB_SHARD_RANGE = 1200
integer FROZEN_ORB_SHARD_SPELL_ORDER_ID = 852230
unit array FrozenOrbMain[8192]
timer array FrozenOrbMainTimers[8192]
real array FrozenOrbMainAngle[8192]
integer array FrozenOrbCastedLevel[8192]
location array FrozenOrbLastLoc[8192]
endglobals
function Trig_Frozen_Orb_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'FOrb'
endfunction
//This one is the action for the timer created whenever the spell is cast. It makes more
//missiles come out from the Main Orb. Basically, it checks if the missile is still alive. If it
//is, then it shoots another missile from the Main Orb. If it's not then it's supposed to
//shoot several missiles in all directions from where the Main Orb last was, then clear
//the "structs" related to the Main Orb. The else action works perfectly fine, but the
//missiles don't appear. That's the problem.
function FrozenOrbShards takes nothing returns nothing
local integer index = ModuloInteger(H2I(GetExpiredTimer()), 8192)
local location origin
local location destination
if GetUnitState(FrozenOrbMain[index], UNIT_STATE_LIFE) > 0.405 then
set origin = GetUnitLoc(FrozenOrbMain[index])
set destination = Location(GetLocationX(origin)+Cos(FrozenOrbMainAngle[index])*900, GetLocationY(origin)+Sin(FrozenOrbMainAngle[index])*900)
call LaunchSingleTargetMissileAtPoint(GetOwningPlayer(FrozenOrbMain[index]), FROZEN_ORB_SHARD_ID , FROZEN_ORB_SHARD_SPEED, origin, destination, FROZEN_ORB_SHARD_RANGE, true, FROZEN_ORB_SHARD_COLLISION_SIZE, FROZEN_ORB_SHARD_SPELL, FrozenOrbCastedLevel[index], FROZEN_ORB_SHARD_SPELL_ORDER_ID)
call RemoveLocation(destination)
set FrozenOrbMainAngle[index] = FrozenOrbMainAngle[index] + GetRandomReal(0.85, 0.15)
if FrozenOrbLastLoc[index] != null then
call RemoveLocation(FrozenOrbLastLoc[index])
endif
set FrozenOrbLastLoc[index] = origin
else
set FrozenOrbMainAngle[index] = 0
set origin = FrozenOrbLastLoc[index]
loop
set destination = Location(GetLocationX(origin)+Cos(FrozenOrbMainAngle[index])*900, GetLocationY(origin)+Sin(FrozenOrbMainAngle[index])*900)
call LaunchSingleTargetMissileAtPoint(GetOwningPlayer(FrozenOrbMain[index]), FROZEN_ORB_SHARD_ID , FROZEN_ORB_FINAL_SHARD_SPEED, origin, destination, FROZEN_ORB_SHARD_RANGE, true, FROZEN_ORB_SHARD_COLLISION_SIZE, FROZEN_ORB_SHARD_SPELL, FrozenOrbCastedLevel[index], FROZEN_ORB_SHARD_SPELL_ORDER_ID)
call RemoveLocation(destination)
set FrozenOrbMainAngle[index] = FrozenOrbMainAngle[index] + 0.52
exitwhen FrozenOrbMainAngle[index] >= 6.24
endloop
call RemoveLocation(FrozenOrbLastLoc[index])
call DestroyTimer(GetExpiredTimer())
set FrozenOrbMain[index] = null
set FrozenOrbMainTimers[index] = null
set FrozenOrbLastLoc[index] = null
set FrozenOrbMainAngle[index] = 0
endif
set origin = null
set destination = null
endfunction
//This initializes the "struct" for the Main Orb and creates the Main Orb, which is itself a
//missile.
function Trig_Frozen_Orb_Actions takes nothing returns nothing
local location origin = GetUnitLoc(GetTriggerUnit())
local location destination = GetSpellTargetLoc()
local timer Temp
local integer index
loop
set Temp = CreateTimer()
exitwhen FrozenOrbMainTimers[ModuloInteger(H2I(Temp), 8192)] == null
call DestroyTimer(Temp)
endloop
set index = ModuloInteger(H2I(Temp), 8192)
set FrozenOrbMainTimers[index] = Temp
set FrozenOrbMain[index] = LaunchSingleTargetMissileAtPoint(GetTriggerPlayer(), FROZEN_ORB_MAIN_ID, FROZEN_ORB_MAIN_SPEED, origin, destination, FROZEN_ORB_MAIN_RANGE, true, FROZEN_ORB_MAIN_COLLISION_SIZE, 0, 0, 0)
set FrozenOrbMainAngle[index] = GetRandomReal(0, bj_PI*2)
set FrozenOrbCastedLevel[index] = GetUnitAbilityLevel(GetTriggerUnit(), GetSpellAbilityId())
call TimerStart(FrozenOrbMainTimers[index], 0.08, true, function FrozenOrbShards)
call RemoveLocation(origin)
call RemoveLocation(destination)
set Temp = null
set origin = null
set destination = null
endfunction
//===========================================================================
function InitTrig_Frozen_Orb takes nothing returns nothing
set gg_trg_Frozen_Orb = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Frozen_Orb, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Frozen_Orb, Condition(function Trig_Frozen_Orb_Conditions))
call TriggerAddAction( gg_trg_Frozen_Orb, function Trig_Frozen_Orb_Actions )
endfunction
Attached is the test map I made. It's not much.
Attachments
Last edited: