• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Unsolved Script

Status
Not open for further replies.
Im new in vJASS but i have a problem with my script:
[jass=] //TESH.alwaysfold=0
scope LightningGrapple initializer OnInit
// requires TimerUtils, DummyCaster, GroupUtils, Knockback3D

// -----------------------------------------------------------------------------------------------------
// CALIBRATION SECTION
// -----------------------------------------------------------------------------------------------------

globals
private constant integer GrappleAbilityId = 'A000' // Rawcode for Lightning Grapple
private constant integer BuffAbilityId = 'A001' // Rawcode for AS/MS bonus ability

private constant real Timer = 0.025 // Period of timer for movement

private constant real AllyPickUpAoE= 128. // Area of effect allies within the caster can be dragged

// Effects
private constant string AoEEx = "Abilities\\Weapons\\FarseerMissile\\FarseerMissile.mdx" // Created at target point
private constant string TargetEx = "Abilities\\Weapons\\Bolt\\BoltImpact.mdx" // Created on damaged units.
private constant string TargetAttachment = "origin" // Attachment point of TARGET_EFFECT.

// Damage constants
private constant attacktype AttackType = ATTACK_TYPE_NORMAL
private constant damagetype DamageType = DAMAGE_TYPE_MAGIC
private constant weapontype WeaponType = null

private constant string LightningCode = "FORK"
private constant real LightningHeight = 45.
// Lightning ID's
// (thanks to PurgeandFire111):
//
// LIGHTNING_CHAIN_LIGHTNING_PRIMARY = "CLPB"
// LIGHTNING_CHAIN_LIGHTNING_SECONDARY = "CLSB"
// LIGHTNING_DRAIN = "DRAB"
// LIGHTNING_DRAIN_LIFE = "DRAL"
// LIGHTNING_DRAIN_MANA = "DRAM"
// LIGHTNING_FINGER_OF_DEATH = "AFOD"
// LIGHTNING_FORKED_LIGHTNING = "FORK"
// LIGHTNING_HEALING_WAVE_PRIMARY = "HWPB"
// LIGHTNING_HEALING_WAVE_SECONDARY = "HWSB"
// LIGHTNING_LIGHTNING_ATTACK = "CHIM"
// LIGHTNING_MAGIC_LEASH = "LEAS"
// LIGHTNING_MANA_BURN = "MBUR"
// LIGHTNING_MANA_FLARE = "MFPB"
// LIGHTNING_SPIRIT_LINK = "SPLK"
endglobals

private keyword grapple // ignore this

// What units are affected at the end of the charge?
// By default it is ALL units, in adherance to
// the request description:

// QUOTE:
// "After the Caster reaches the point,all units within 300 AoE will be knockbacked
// for 400 distance at 2 seconds and will take 300/400/500 damage."
//
private function IsTargetValid takes unit whichUnit returns boolean
return IsUnitEnemy(whichUnit, grapple.TempData.owningPlayer)
endfunction

// The maximum number of allies that can be affected in the Lightning Grapple
private constant function MaxAllies takes integer level returns integer
return 1 + level * 1
endfunction

// The duration of the knockback for units at the end of charge
private constant function KB_Duration takes integer level returns real
return 2.
endfunction

// The distance of the knockback for units at the end of charge
private constant function KB_Distance takes integer level returns real
return 400.
endfunction

// The area of effect to affect units at the end of charge
private constant function DamageAoE takes integer level returns real
return 300.
endfunction

// The damage dealt to units at the end of charge
private constant function DamageDealt takes integer level returns real
return level * 100. + 200.
endfunction

// The speed at which the caster grapples in Warcraft III units
private constant function GrappleSpeed takes integer level returns real
return 1250.
endfunction
//
// END OF CALIBRATION SECTION
// -----------------------------------------------------------------------------------------------------

private struct grapple
unit caster // caster of lightning grapple
player owningPlayer // owner of caster for lightning grapple
integer level // level at the time of cast
real damage // damage dealt to units at end of charge
real kbDist // knockback distance
real kbDur // knockback duration

real distance // distance from cast point to target point
real speed // distance moved per timer period
real cos
real sin

// Lightning variables
lightning lightning

// Lightning coordinates
real x1
real y1
real z1
real x2
real y2
real z2

// Allied picking up
integer unitCount
integer maxUnits
group alliedHeroes

// Timer for motion
timer timer

// Static variables
static thistype TempData // Used for group actions
private static location TempLoc = Location(0., 0.) // Location used to get a unit's Z
private static boolexpr AllyHeroFilter // Filter() stored into boolexpr for efficiency
private static boolexpr EnemyUnitFilter // Filter() stored into boolexpr for efficiency

private static method enemyUnitFilter takes nothing returns boolean
local unit u = GetFilterUnit()
if IsTargetValid(u) then
call UnitDamageTarget(.TempData.caster, u, .TempData.damage, true, false, AttackType, DamageType, WeaponType)
call DestroyEffect(AddSpecialEffectTarget(TargetEx, u, TargetAttachment))
call Knockback3D_add(u,kbDist,Atan2(GetUnitY(u) - .TempData.y2, GetUnitX(u) - .TempData.x2),0)
endif

set u = null
return false
endmethod

private static method allyHeroFilter takes nothing returns boolean
local unit u = GetFilterUnit()
if .TempData.unitCount < .TempData.maxUnits and not IsUnitInGroup(u, .TempData.alliedHeroes) and u != .TempData.caster and IsUnitAlly(u, .TempData.owningPlayer) and IsUnitType(u, UNIT_TYPE_HERO) and not IsUnitType(u, UNIT_TYPE_DEAD) then
call GroupAddUnit(.TempData.alliedHeroes, u)
set .TempData.unitCount = .TempData.unitCount + 1
call DestroyEffect(AddSpecialEffectTarget(TargetEx, u, TargetAttachment))
endif
set u = null
return false
endmethod

private static method bloodlustAllies takes nothing returns nothing
call IssueTargetOrder(DUMMY, "bloodlust", GetEnumUnit())
endmethod

private static method moveAlliedHeroes takes nothing returns nothing
local unit u = GetEnumUnit()
call SetUnitX(u, GetUnitX(u) + .TempData.cos)
call SetUnitY(u, GetUnitY(u) + .TempData.sin)
set u = null
endmethod

private static method timerCallback takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
local real castx = GetUnitX(.caster) + .cos
local real casty = GetUnitY(.caster) + .sin
local real castz

call SetUnitX(.caster, castx)
call SetUnitY(.caster, casty)
call MoveLocation(.TempLoc, castx, casty)
set castz = GetLocationZ(.TempLoc) + GetUnitFlyHeight(.caster) + LightningHeight

call MoveLightningEx(.lightning, false, castx, casty, castz, .x2, .y2, .z2)

call DestroyEffect(AddSpecialEffect(AoEEx, .x2, .y2))

set .TempData = this
if .unitCount < .maxUnits then
call GroupEnumUnitsInArea(ENUM_GROUP, castx, casty, AllyPickUpAoE, thistype.AllyHeroFilter)
endif

call ForGroup(.alliedHeroes, function thistype.moveAlliedHeroes)

set .distance = .distance - .speed
if .distance <= 0. then // end of charge actions
call DestroyLightning(.lightning)

// Add bloodlust to dummy unit
call UnitAddAbility(DUMMY, BuffAbilityId)
call SetUnitAbilityLevel(DUMMY, BuffAbilityId, .level)
call IssueTargetOrder(DUMMY, "bloodlust", .caster)
call ForGroup(.alliedHeroes, function thistype.bloodlustAllies)
call UnitRemoveAbility(DUMMY, BuffAbilityId)

// Damage and knockback enemy units
set .TempData = this
call GroupEnumUnitsInArea(ENUM_GROUP, .x2, .y2, DamageAoE(.level), thistype.EnemyUnitFilter)

// Cleanup
call ReleaseGroup(.alliedHeroes)
call ReleaseTimer(.timer)
call .deallocate()
endif
endmethod

static method create takes nothing returns thistype
local thistype this = thistype.allocate()
local real castx
local real casty
local real castz
local real angle

// Unit variables
set .caster = GetTriggerUnit()
set .owningPlayer = GetTriggerPlayer()
set .level = GetUnitAbilityLevel(.caster, GrappleAbilityId)

// Caster coordinates
set castx = GetUnitX(.caster)
set casty = GetUnitY(.caster)
call MoveLocation(.TempLoc, castx, casty)
set castz = GetLocationZ(.TempLoc) + GetUnitFlyHeight(.caster) + LightningHeight

// Target point coordinates
set .x2 = GetSpellTargetX()
set .y2 = GetSpellTargetY()
call MoveLocation(.TempLoc, .x2, .y2)
set .z2 = GetLocationZ(.TempLoc) + LightningHeight
set .distance = SquareRoot((.x2 - castx) * (.x2 - castx) + (.y2 - casty) * (.y2 - casty))

// Movement variables
set angle = Atan2(.y2 - casty, .x2 - castx)
set .speed = GrappleSpeed(.level) * Timer
set .cos = .speed * Cos(angle)
set .sin = .speed * Sin(angle)

// Stats
set .damage = DamageDealt(.level)
set .kbDist = KB_Distance(.level)
set .kbDur = KB_Duration(.level)

// Look for allies to drag along
set .unitCount = 0
set .maxUnits = MaxAllies(.level)
set .alliedHeroes = NewGroup()
set .TempData = this
call GroupEnumUnitsInArea(ENUM_GROUP, castx, casty, AllyPickUpAoE, thistype.AllyHeroFilter)

// Lightning itself
set .lightning = AddLightningEx(LightningCode, false, castx, casty, castz, .x2, .y2, .z2)

// Timer
set .timer = NewTimerEx(this)
call TimerStart(.timer, Timer, true, function thistype.timerCallback)

return this
endmethod

private static method onInit takes nothing returns nothing
set thistype.AllyHeroFilter = Filter(function thistype.allyHeroFilter)
set thistype.EnemyUnitFilter = Filter(function thistype.enemyUnitFilter)
endmethod
endstruct

private function OnSpellEffect takes nothing returns boolean
if GetSpellAbilityId() == GrappleAbilityId then
call grapple.create()
endif
return false
endfunction

private function OnInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function OnSpellEffect))
endfunction

endscope
[/code]
the problem is that i have not declared a variable this.
it always view this line
[jass=]call Knockback3D_add(u,kbDist,Atan2(GetUnitY(u) - .TempData.y2, GetUnitX(u) - .TempData.x2),0)[/code]

Testmap:
 

Attachments

  • Lightning Grapple v1.0.w3x
    58.2 KB · Views: 46
It shouldn't compile.

The problem is that there is no "this" in that method. static methods are not associated with an instance, therefore you cannot use this without declaring it first. The fix would be to use a temporary variable when you are doing your GroupEnum function.

For example:
JASS:
struct A
    private static group g = CreateGroup()
    private static thistype temp
    private real x

    private static method filter takes nothing returns nothing
        local thistype this = thistype.temp // retrieve the instance like this
        set this.x = 6
    endmethod

    private static method onInit takes nothing returns nothing
        local thistype this = thistype.create()
        set this.x = 5
        set thistype.temp = this // set the variable here
        call GroupEnumUnitsInRange(g, 0, 0, 150, Filter(function thistype.filter)) 
    endmethod
endstruct

The reason why you can do this is because GroupEnumUnits() is an instant function. Therefore, you can just use a global normally without having to worry about any MUI issues. However, the function that is passed for Filter() or for ForGroup() cannot have parameters, so that is why we use a static method and a global variable for the instance.
 
Level 16
Joined
Aug 7, 2009
Messages
1,406
Oh that is true. I guess I read it as a non-static.

I did the same, so it's cool :) But I wanted to make sure it ain't static so I looked it up and figured out that it actually WAS static.

I'd always recommend using the this.name and thistype.name syntax over the shortened one - not only makes it easier to read the code, but you can also avoid these kind of problems.
 
Level 5
Joined
Aug 27, 2010
Messages
79
umm....problem might be in "kbDist" ??

JASS:
call Knockback3D_add(u,kbDist,Atan2(GetUnitY(u) - .TempData.y2, GetUnitX(u) - .TempData.x2),0)

to

JASS:
call Knockback3D_add(u,.TempData.kbDist,Atan2(GetUnitY(u) - .TempData.y2, GetUnitX(u) - .TempData.x2),0)

i dont have access to WE right now...so didnt test this...
 
Status
Not open for further replies.
Top