• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • 🏆 Hive's 6th HD Modeling Contest: Mechanical is now open! Design and model a mechanical creature, mechanized animal, a futuristic robotic being, or anything else your imagination can tinker with! 📅 Submissions close on June 30, 2024. Don't miss this opportunity to let your creativity shine! Enter now and show us your mechanical masterpiece! 🔗 Click here to enter!

[vJASS] Dealing damage per Object

Status
Not open for further replies.
Level 8
Joined
Jun 13, 2008
Messages
346
hi guys...how can I make a projectile to deal damage? I mean, lets just say that I launch two fireballs...if just one hits the target, it deals some specific damage I defined...and the other one hits another target it deals same damage to that target too....but I just couldn't manage where two projectile hits the same target....I doesn't deal the total damage of two projectile, it does only one projectile's damage....how can I achieve this?
 
Level 8
Joined
Jun 13, 2008
Messages
346
ok here's the whole spell...it uses periodic method stuff called T32 system and event system Gtrigger(GT)

JASS:
scope Heatvision

    native UnitAlive takes unit id returns boolean

    globals
        private constant integer    RAWCODE     = 'A00Y'            //~Spell Rawcode
        private constant integer    DUMMY       = 'h007'            //~Shadow Dummy Rawcode
        
        private constant string     L_FX        = "HVIS"            //~The lightning effect
        private constant string     L_FX2       = "Abilities\\Weapons\\LavaSpawnMissile\\LavaSpawnMissile.mdl"           //~The effect on the happy trails
        //private constant string     L_FX3       = "Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl"//~The effect on hit
        //private constant string     L_FX3       =  "Abilities\\Spells\\Demon\\DemonBoltImpact\\DemonBoltImpact.mdl"
        private constant string     L_FX3       = "Abilities\\Weapons\\DemolisherFireMissile\\DemolisherFireMissile.mdl" //~The effect on hit
        private constant string     ANIMATION   = "spell third"     //The animation of the shadow
        
        private constant real       L_HEIGHT    = 375               //~Height of lightning.  Just right for Balnazzar :D
        private constant real       AOE         = 75               //~AoE of lightning
        private constant real       DURATION    = .75               //~DURATION OF SPELL ^___^
        private constant real       SHADOWLIFE  = 2.5               //~The duration of the shadow
        
        private constant attacktype ATK_TYPE    = ATTACK_TYPE_CHAOS  //~Attack type
        private constant damagetype DMG_TYPE    = DAMAGE_TYPE_FIRE //~Damage type
    endglobals
    
    private function RANGE takes integer lvl returns real
        return 1000. + (lvl * 500.)
    endfunction
    
    private function DMG takes integer lvl returns real
        return lvl * 75.
    endfunction
    
//Do not touch the remaining part, or else you will be a victim of a killer.

    
    private struct Data
    
        private static group            GROUP   = CreateGroup()
        private static thistype         this
        private static conditionfunc    cf
        
        unit caster
        unit shadow
        player p
        group dmgUnits
        real x
        real x1
        real y
        real y1
        real z
        real z1
        real tx
        real tx1
        real ty
        real ty1
        real tz
        real tz1
        real angle
        real angle2
        real range
        real speed
        real dmg
        real cos
        real sin
        integer lvl
        integer ticks
        lightning l
        lightning l2
        
        private static method DoDamage takes nothing returns boolean
            local thistype  this    = thistype.this
            local unit      u       = GetFilterUnit()
            if IsUnitEnemy(u,.p) and UnitAlive(u) and not IsUnitInGroup(u,.dmgUnits) then
                call UnitDamageTarget(.caster,u,.dmg,true,false,ATK_TYPE,DMG_TYPE,null)
                call DestroyEffect(AddSpecialEffectTarget(L_FX3,u,"origin"))
                call GroupAddUnit(.dmgUnits,u)
            endif
            return false
        endmethod
        
        private method periodic takes nothing returns nothing
            if .ticks >= T32_Tick then
                set .tx = .tx + .cos
                set .tx1 = .tx1 + .cos
                set .ty = .ty + .sin
                set .ty1 = .ty1 + .sin
                set .tz = GetLocationZ(Location(.tx,.ty))
                set .tz1 = GetLocationZ(Location(.tx1,.ty1))
                if UnitAlive(.caster) then
                    call MoveLightningEx(.l,true,.x,.y,.z,.tx,.ty,.tz)
                    call MoveLightningEx(.l2,true,.x1,.y1,.z1,.tx1,.ty1,.tz1)
                    call DestroyEffect(AddSpecialEffect(L_FX2,.tx,.ty))
                    call DestroyEffect(AddSpecialEffect(L_FX2,.tx1,.ty1))
                    call PlaySoundAtPointBJ(gg_snd_LightningBolt,100,Location(.x,.y),.z) 
                    call PlaySoundAtPointBJ(gg_snd_LightningBolt,100,Location(.x1,.y1),.z1) 
                    set thistype.this = this
                    call GroupEnumUnitsInRange(thistype.GROUP,.tx,.ty,AOE,thistype.cf)
                    call GroupEnumUnitsInRange(thistype.GROUP,.tx1,.ty1,AOE,thistype.cf)
                else
                    call DestroyLightning(.l)
                    call DestroyLightning(.l2)
                endif
            else
                call DestroyLightning(.l)
                call DestroyLightning(.l2)
                call .stopPeriodic()
                call Group.release(.dmgUnits)
                set .caster = null
                set .l = null
                set .l2 = null
            endif
        
        endmethod
        
        implement T32x
        
        private static method Action takes nothing returns boolean
            local thistype this = thistype.create()

            set .caster     = GetTriggerUnit()
            set .p          = GetOwningPlayer(.caster)
            set .x          = GetUnitX(.caster)-10*Sin(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .x1         = GetUnitX(.caster)+10*Sin(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .y          = GetUnitY(.caster)+10*Cos(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .y1         = GetUnitY(.caster)-10*Cos(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .z          = GetLocationZ(Location(.x,.y)) + L_HEIGHT + GetUnitFlyHeight(.caster)
            set .z1         = GetLocationZ(Location(.x1,.y1)) + L_HEIGHT + GetUnitFlyHeight(.caster)
            set .tx         = GetSpellTargetX()-10*Sin(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .tx1        = GetSpellTargetX()+10*Sin(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .ty         = GetSpellTargetY()+10*Cos(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .ty1        = GetSpellTargetY()-10*Cos(GetUnitFacing(.caster)*bj_DEGTORAD)
            set .tz         = GetLocationZ(Location(.tx,.ty))
            set .tz1        = GetLocationZ(Location(.tx1,.ty1))
            set .lvl        = GetUnitAbilityLevel(.caster,RAWCODE)
            set .angle      = Atan2(.ty-.y,.tx-.x)
            set .angle2      = Atan2(.ty1-.y1,.tx1-.x1)
            set .range      = RANGE(.lvl)
            set .speed      = .range / R2I(DURATION/T32_PERIOD)
            set .dmg        = DMG(.lvl)
            set .cos        = .speed * Cos(.angle)
            set .sin        = .speed * Sin(.angle)
            set .l          = AddLightningEx(L_FX,true,.x,.y,.z,.x,.y,.tz)
            set .l2          = AddLightningEx(L_FX,true,.x1,.y1,.z1,.x1,.y1,.tz1)
            set .ticks      = T32_Tick + R2I(DURATION/T32_PERIOD)
            set .dmgUnits   = Group.get()
            set .tx         = .x
            set .tx1         = .x1
            set .ty         = .y
            set .ty1         = .y1
            
            call .startPeriodic()
            

            return false
        endmethod
        
        private static method Action2 takes nothing returns boolean
            local thistype this = thistype.create()
            set .caster         = GetTriggerUnit()
            set .p              = GetOwningPlayer(.caster)
            set .x              = GetUnitX(.caster)
            set .x1              = GetUnitX(.caster)
            set .y              = GetUnitY(.caster)
            set .y1              = GetUnitY(.caster)
            set .tx             = GetSpellTargetX()
            set .ty             = GetSpellTargetY()
            set .tx1             = GetSpellTargetX()
            set .ty1             = GetSpellTargetY()
            set .angle          = Atan2(.ty-.y,.tx-.x)
            set .angle2          = Atan2(.ty1-.y1,.tx1-.x1)
            set .shadow         = CreateUnit(.p,DUMMY,.x,.y,.angle*bj_RADTODEG)
            
            call SetUnitAnimation(.shadow,ANIMATION)
            call SetUnitVertexColor(.shadow,100,100,100,50)
            call SetUnitScale(.shadow,1.5,1.5,1.5)
            call UnitApplyTimedLife(.shadow,'BTLF',SHADOWLIFE)
            call UnitAddAbility(.shadow,'Amrf')
            call UnitRemoveAbility(.shadow,'Amrf')
            call SetUnitFlyHeight(.shadow,GetUnitFlyHeight(.caster),0)
            
            //Optional only.==========================================================//
            call PlaySoundAtPointBJ(gg_snd_MarkOfChaos,100,Location(.x,.y),.z)         
            //========================================================================//
            
            set .shadow         = null
            set .caster         = null
            return false
        endmethod

        private static method onInit takes nothing returns nothing
            call GT_AddStartsEffectAction(function thistype.Action,RAWCODE)
            call GT_AddBeginsCastingAction(function thistype.Action2,RAWCODE)
            
            set thistype.cf = Condition(function thistype.DoDamage)
        endmethod

    endstruct
    
endscope

as you can see, there are coordinates and stuff defined for two lightning objects that goes from hero....doDamage method looks alright....but those two lightning deals same damage as one does if both hit the same target...not the 2 times the damage that is writing right there.
 
Last edited:
I'll just drop this here. I think with this hint you will find the problem yourself, then slam your head against the wall for not noticing it earlier... ;)

JASS:
            if IsUnitEnemy(u,.p) and UnitAlive(u) and not IsUnitInGroup(u,.dmgUnits) then
                 call UnitDamageTarget(.caster,u,.dmg,true,false,ATK_TYPE,DMG_TYPE,null)
                 call DestroyEffect(AddSpecialEffectTarget(L_FX3,u,"origin"))
                 call GroupAddUnit(.dmgUnits,u)
             endif
 
Level 8
Joined
Jun 13, 2008
Messages
346
don't be so sure then I looked here long enough and couldn't see what you've seen:)....I know its supposed to be easy to notice but sometimes brain just locks itself.

needlessness of unit in group check:).....its done now thanks Zwiebelchen....can I ask you one more thing?...is it possible to start that lightning from unit's head?....like finger of death's lightnings starting from archimonde's right hand? because without attaching that lightning to head and doing it with points makes it look ugly if hero is not on a flat platform. I need something to attach the starting point of lightning to head instead of using GetUnitX(.caster) and GetUnitY(.caster)
 
Last edited:
don't be so sure then I looked here long enough and couldn't see what you've seen:)....I know its supposed to be easy to notice but sometimes brain just locks itself.
In the block I copied, you check if the unit isn't in the group, then add it to the group.
The group is for excluding targets that have already been hit.
As both missiles share the same group, what has been hit by missile 1 can not be hit by missile 2 anymore.

So basicly, you require two seperate .dmgUnits groups.

Then, do this in your doDamage function:

JASS:
local boolean a = not IsUnitInGroup(u,.dmgUnits1)
local boolean b = not IsUnitInGroup(u,.dmgUnits2)
if IsUnitEnemy(u,.p) and UnitAlive(u) and (a or b) then
      call UnitDamageTarget(.caster,u,.dmg,true,false,ATK_TYPE,DMG_TYPE,null)
      call DestroyEffect(AddSpecialEffectTarget(L_FX3,u,"origin"))
      if a then
          call GroupAddUnit(.dmgUnits1,u)
      else
          call GroupAddUnit(.dmgUnits2,u)
      endif
endif
 
Level 8
Joined
Jun 13, 2008
Messages
346
thanks again....but what about lightning's starting from unit's head?...I hope its not machine coded and possible to assign a attachment point of unit to point?...I searched almost all JASS manuals and couldn't find anything useful about this.
 
thanks again....but what about lightning's starting from unit's head?...I hope its not machine coded and possible to assign a attachment point of unit to point?...I searched almost all JASS manuals and couldn't find anything useful about this.
You can not create lightnings based on an attachment point. In that case, you need dummy abilities that have a lightning sfx (like chain lightning or finger of death). And even those won't be able to attach to points directly; but at least they select their impact-z based on the size of the unit.
 
Level 8
Joined
Jun 13, 2008
Messages
346
It makes sense and seems like the only way but doing something like this would cost to change almost entire code structure of the spell. But I might try to do that later apart from this spell. Thanks again for your help:)
 
Status
Not open for further replies.
Top