#1: Use [code=jass] Tags not code tags:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId()==’A000’
endfunction
//=============================================================
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance
local real CurrentDistance
local location CurrentLoc
local location StartLoc
local unit Bullet
local group G
local real Direction
local player OwnerOfBullet
local boolean Hit
local unit Shooter
set Shooter = GetSpellAbilityUnit()
set CurrentDistance = 0
set EndDistance = 1200
set StartLoc = GetUnitLoc(GetSpellAbilityUnit())
set OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
set Direction = GetUnitFacing(GetSpellAbilityUnit())
call CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
set Bullet = GetLastCreatedUnit()
loop
exitwhen CurrentDistance >= EndDistance
call TriggerSleepAction(.01)
call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
set CurrentLoc = GetUnitLoc(Bullet)
set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
if (CountUnitsInGroup(G) >= 1)
then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
call RemoveUnit(Bullet)
endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set CurrentDistance = null
set EndDistance = null
set StartLoc = null
set OwnerOfBullet = null
set G = null
set Direction = null
set Bullet = null
set CurrentLoc =null
endfunction
//==== Init Trigger NewTrigger =============================
function InitTrig_Shoot takes nothing returns nothing
set gg_trg_Shoot = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
#2:
return GetSpellAbilityId()==’A000’
its ' not `, thus:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
#3: Indent your code please... you indent if, else, elseif, loop, function, pretty much every code block.
#4: You can initialize locals like so:
JASS:
local real EndDistance = 1200
local real CurrentDistance = 0
local location CurrentLoc
local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
local unit Bullet
local group G
local real Direction = GetUnitFacing(GetSpellAbilityUnit())
local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
local boolean Hit
local unit Shooter = GetSpellAbilityUnit()
#5:
JASS:
call CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
set Bullet = GetLastCreatedUnit()
#5.1: GetLastCreatedUnit() only works with blizzard.j unit creation functions. that is a native one.
#5.2: CreateUnitAtLoc() returns the created unit.
#5.3: Again, local initialization. Thus:
JASS:
local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
Because StatLoc is declared before Bullet, we can use it like that.
#6:
JASS:
set Shooter = null
set CurrentDistance = null
set EndDistance = null
set StartLoc = null
set OwnerOfBullet = null
set G = null
set Direction = null
set Bullet = null
set CurrentLoc =null
You only have to null types which extend from the handle type, and you only have to null locals that will contain a handle that will eventually be destroyed. thus:
JASS:
set Shooter = null
set StartLoc = null
set G = null
set Bullet = null
set CurrentLoc = null
So heres what where up to:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
//=============================================================
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance = 1200
local real CurrentDistance = 0
local location CurrentLoc
local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
local real Direction = GetUnitFacing(GetSpellAbilityUnit())
local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
local group G
local boolean Hit
local unit Shooter = GetSpellAbilityUnit()
loop
exitwhen CurrentDistance >= EndDistance
call TriggerSleepAction(.01)
call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
set CurrentLoc = GetUnitLoc(Bullet)
set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
if (CountUnitsInGroup(G) >= 1)
then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
call RemoveUnit(Bullet)
endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set StartLoc = null
set G = null
set Bullet = null
set CurrentLoc = null
endfunction
#7:
JASS:
if (CountUnitsInGroup(G) >= 1)
then
#7.1: if condition then, all on one line.
#7.2: You don't need the outermost parenthesis. thus:
JASS:
if CountUnitsInGroup(G) >= 1 then
#8: This line is just completely wrong:
JASS:
set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, (((GetUnitTypeId(Bullet)) != (GetUnitTypeId(GetFilterUnit()))) And (IsUnitEnemy(GetFilterUnit())
#8.1: GetUnitsInRangeOfLocMatching() is a BJ function. (
Blizzard.
J) BJ's are coded in JASS, whereas natives are coded in C++ within the game. Natives are always preferable, especially considering most blizzard.j functions are so poorly coded.
JASS:
function GetUnitsInRangeOfLocMatching takes real radius, location whichLocation, boolexpr filter returns group
local group g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, filter)
call DestroyBoolExpr(filter)
return g
endfunction
#8.1.1: Don't destroy boolexprs.
#8.1.2: Don't use locations. Use
real
x and y coordinated.
#8.2: A boolexpr is a pointer to a function that returns a boolean type value. You create a boolexpr with the Condition() or Filter() functions as such:
Condition(function YourFunctionName)
YourFunctionName is the name of a function which takes nothing and returns a boolean. Thus, ignoring the BJ function so far and just using a proper boolexpr:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Shoot_Filter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance = 1200
local real CurrentDistance = 0
local location CurrentLoc
local location StartLoc = GetUnitLoc(GetSpellAbilityUnit())
local player OwnerOfBullet = GetOwningPlayer(GetSpellAbilityUnit())
local real Direction = GetUnitFacing(GetSpellAbilityUnit())
local unit Bullet = CreateUnitAtLoc(OwnerOfBullet, 'H000', StartLoc, Direction)
local group G
local boolean Hit
local unit Shooter = GetSpellAbilityUnit()
loop
exitwhen CurrentDistance >= EndDistance
call TriggerSleepAction(.01)
call SetUnitPositionLoc(Bullet, PolarProjectionBJ( GetUnitLoc(Bullet), 20, Direction ))
set CurrentLoc = GetUnitLoc(Bullet)
set CurrentDistance = DistanceBetweenPoints(StartLoc, CurrentLoc)
set G = GetUnitsInRangeOfLocMatching(45, CurrentLoc, Condition(function Shoot_Filter))
if CountUnitsInGroup(G) >= 1 then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
call RemoveUnit(Bullet)
endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set StartLoc = null
set G = null
set Bullet = null
set CurrentLoc = null
endfunction
//==== Init Trigger NewTrigger =============================
function InitTrig_Shoot takes nothing returns nothing
set gg_trg_Shoot = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
#9: You use locations... which you don't have to do. Switching to using X and Y coordinates, and inlining the GetUnitsInRangeOfLocMatching() BJ and a few others, we end up with:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Shoot_Filter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction
function Trig_Shoot_Actions takes nothing returns nothing
local real EndDistance = 1200
local real CurrentDistance = 0
local unit Shooter = GetTriggerUnit() // TriggerUnit == GetSpellAbilityUnit()
local player OwnerOfBullet = GetOwningPlayer(Shooter)
local real Direction = GetUnitFacing(Shooter)
local real StartX = GetUnitX(Shooter)
local real StartY = GetUnitY(Shooter)
local real CurrentX
local real CurrentY
local unit Bullet = CreateUnit(OwnerOfBullet, 'H000', StartX, StartY, Direction)
local group G
loop
exitwhen CurrentDistance >= EndDistance
call TriggerSleepAction(.01)
// Polar projection:
set CurrentX = GetUnitX(Bullet) + 20 * Cos(Direction * bj_DEGTORAD)
set CurrentY = GetUnitY(Bullet) + 20 * Sin(Direction * bj_DEGTORAD)
call SetUnitPosition(Bullet, CurrentX, CurrentY)
set CurrentDistance = SquareRoot(CurrentX*StartX + CurrentY*StartY)
set G = CreateGroup()
call GroupEnumUnitsInRange(G, CurrentX, CurrentY, 45, Condition(function Shoot_Filter))
if CountUnitsInGroup(G) >= 1 then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
call RemoveUnit(Bullet)
endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set G = null
set Bullet = null
endfunction
function InitTrig_Shoot takes nothing returns nothing
set gg_trg_Shoot = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
#10:
if CountUnitsInGroup(G) >= 1 then
CountUnitsInGroup() is a BJ. a not completely useless one, however: FirstOfGroup() will return null if a group is empty, so:
JASS:
if FirstOfGroup(G) != null then
#11:
JASS:
if FirstOfGroup(G) != null then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
call RemoveUnit(Bullet)
endif
A minor logic error: If the bullet is removed before its out of distance, then the loop will continue iterating. Adding an
exitwhen true
fixes that. Also, if you're editing the loop, you don't need to remove the unit here, as its done after the loop anyway.
So, heres what we have:
JASS:
function Trig_Shoot_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Trig_Shoot_Filter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) != 'H000' and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetTriggerUnit()))
endfunction
function Trig_Shoot_Actions takes nothing returns nothing
local unit Shooter = GetTriggerUnit() // TriggerUnit == GetSpellAbilityUnit()
local real Direction = GetUnitFacing(Shooter)
local real StartX = GetUnitX(Shooter)
local real StartY = GetUnitY(Shooter)
local real CurrentX
local real CurrentY
local real CurrentDistance = 0
local real EndDistance = 1200
local unit Bullet = CreateUnit(GetOwningPlayer(Shooter), 'H000', StartX, StartY, Direction)
local group G
loop
exitwhen CurrentDistance >= EndDistance
call TriggerSleepAction(.01)
// Polar projection:
set CurrentX = GetUnitX(Bullet) + 20 * Cos(Direction * bj_DEGTORAD)
set CurrentY = GetUnitY(Bullet) + 20 * Sin(Direction * bj_DEGTORAD)
call SetUnitPosition(Bullet, CurrentX, CurrentY)
set CurrentDistance = SquareRoot(CurrentX*StartX + CurrentY*StartY)
set G = CreateGroup()
call GroupEnumUnitsInRange(G, CurrentX, CurrentY, 45, Condition(function Shoot_Filter))
if FirstOfGroup(G) != null then
call UnitDamageTarget(Shooter, FirstOfGroup(G), 100, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL, null)
exitwhen true
endif
endloop
call RemoveUnit(Bullet)
set Shooter = null
set G = null
set Bullet = null
endfunction
function InitTrig_Shoot takes nothing returns nothing
set gg_trg_Shoot = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Shoot, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Shoot, Condition(function Trig_Shoot_Conditions))
call TriggerAddAction(gg_trg_Shoot, function Trig_Shoot_Actions)
endfunction
Theres more problems with this code that I'm too lazy to go over right now:
- It uses TriggerSleepAction() instead of a timer
- The exitwhen it based on a distance between points calculation, whereas it could be optimized to work on a static number of iterations. (As you're always moving at most 1500 units, you can just iterate 1500/20 times.)
- There are constant values like the speed of 20 and unit rawcodes all over. You can use constant functions which only return a value to get them all in one place. eg:
JASS:
constant function Shoot_GetBulletSpeed takes nothing returns real
return 20
endfunction
Hope this helps...
Edit: Oh, and if you have any JASS questions and want some real-time help, drop by the chat room:
http://www.hiveworkshop.com/resources_new/chat/ the link to it is also at the top of every THW page