• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

CR - Movement

JASS:
library Movement requires MISC, MissilesDatabase, VectorLib, MainEngine

//globals
    private Missile MStack[MAX]
    private int Current = 0
    private int TempId
    private timer UpdateTimer = CT
    private group TemporaryGroup = CG
    

define {
    private PERIOD = 0.025
    private MAX = 250
    private DUMMY = 'h000'
}

    struct Missile
        Vector v
        group in_range = CG
        unit owner, from
        int id, skill_id
        real radius, step = 0., limit, dist
        
        void Remove(bool flag){
            if StringLength(MissileHitSound[this.id]) > 0 
            { AddSound(MissileHitSound[this.id], Gx(this.owner), Gy(this.owner)) }
                if flag { KillUnit(this.owner) }
                else { RemoveUnit(this.owner) }
            GC(this.in_range)
            DG(this.in_range)
            this.in_range = null
            this.owner = null
            this.from = null
            this.v.destroy()
            this.destroy()
        }
        
    endstruct
    
// func
    private bool AOEFilter(){
        return (GetHp(GetFilterUnit()) > 0.045 and IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(ForFilter1)) and GetUnitAbilityLevel(GetFilterUnit(), 'Avul') == 0)
    }
    
    private void WeaponDamageGroup(){
        Missile m = MStack[TempId]
        UD ud = GetData(m.from)
        int status
            if ud.current_weapon.magic_damage {
                status = MagicalDamage(m.from, GetEnumUnit(), Power[UsedEffect[m.skill_id]], true, false, UsedEffect[m.skill_id])
                BroadcastDamage(status, Last_Damage, GetEnumUnit())
            }
            else {
                status = PhysicalDamage(m.from, GetEnumUnit(), Power[UsedEffect[m.skill_id]], true, true, false, true, UsedEffect[m.skill_id])
                BroadcastDamage(status, Last_Damage, GetEnumUnit())
            }
    }
    
    private void MissileDamageGroup(){
        Missile m = MStack[TempId]
        int status
            if DamageType[UsedEffect[m.skill_id]] {
                status = PhysicalDamage(m.from, GetEnumUnit(), Power[UsedEffect[m.skill_id]], true, true, false, true, UsedEffect[m.skill_id])
                BroadcastDamage(status, Last_Damage, GetEnumUnit())
            }
            else {
                status = MagicalDamage(m.from, GetEnumUnit(), Power[UsedEffect[m.skill_id]], true, false, UsedEffect[m.skill_id])
                BroadcastDamage(status, Last_Damage, GetEnumUnit())
            }
    }
//Пиначет: безалкогольное пиво - как секс с сестрой. ощущения похожи, но это неправильно!
    private void MovementUpdate(){
        int c = 0
        real x, y, z = 0.
            while(c++ < Current){
                ForFilter1 = MStack[c].from
                GroupEnumUnitsInRange(MStack[c].in_range, Gx(MStack[c].owner), Gy(MStack[c].owner), MStack[c].radius, Filter(function AOEFilter))
                if CountGroup(MStack[c].in_range) > 0 {
                    if MStack[Current].skill_id == 0 {
                        TempId = c
                        ForGroup(MStack[c].in_range, function WeaponDamageGroup)
                    }
                    elseif Power[UsedEffect[MStack[Current].skill_id]][GetUnitAbilityLevel(MStack[c].from, SkillId[MStack[Current].skill_id])] > 0 {
                        if AreaOfEffect[UsedEffect[MStack[Current].skill_id]][GetUnitAbilityLevel(MStack[c].from, SkillId[MStack[Current].skill_id])] > 0. {
                            ApplyEffect(MStack[c].from, null, Gx(MStack[c].owner), Gy(MStack[c].owner), UsedEffect[MStack[Current].skill_id], GetUnitAbilityLevel(MStack[c].from, SkillId[MStack[Current].skill_id]))
                        }
                        else {
                            ApplyEffect(MStack[c].from, FirstOfGroup(MStack[c].in_range), 0., 0., UsedEffect[MStack[Current].skill_id], GetUnitAbilityLevel(MStack[c].from, SkillId[MStack[Current].skill_id]))
                        }
                    }
                    MStack[c].Remove(true)
                    MStack[c] = MStack[Current]
                    Current--
                }
                else {
                    x = Gx(MStack[c].owner)
                    y = Gy(MStack[c].owner)
                    if (GetHp(MStack[c].owner) < 0.045 or \
                    (x > GetRectMaxX(bj_mapInitialPlayableArea) or \
                    x < GetRectMinX(bj_mapInitialPlayableArea) or \
                    y > GetRectMaxY(bj_mapInitialPlayableArea) or \
                    y < GetRectMinY(bj_mapInitialPlayableArea)) or GetUnitFlyHeight(MStack[c].owner) <= 0.1) {
                        MStack[c].Remove(true)
                        MStack[c] = MStack[Current]
                        Current--
                    }
                    else {
                        z = GetUnitFlyHeight(MStack[c].owner)
                        if (Abs(GetZ(x + MStack[c].v.vx * PERIOD, y + MStack[c].v.vy * PERIOD) - GetZ(x, y)) > 0) {
                            z = z - GetZ(x + MStack[c].v.vx * PERIOD, y + MStack[c].v.vy * PERIOD) + GetZ(x, y)
                        }
                        SetUnitX(MStack[c].owner, x + MStack[c].v.vx * PERIOD)
                        SetUnitY(MStack[c].owner, y + MStack[c].v.vy * PERIOD)
                        SetUnitFlyHeight(MStack[c].owner, (z + MStack[c].v.vz * PERIOD), 0.)
                        //msg(R2S(z))
                    }
                }
            }
    }

    void PushMissile(unit from, int skill_id, real start_x, real start_y, real end_z){
        int id = UsedMissile[GetSkillCell(skill_id)]
        real angle = ABUC(from, start_x, start_y)
        real end_x = start_x + Rx(MaxDistance[id], angle), end_y = start_y + Ry(MaxDistance[id], angle)
        real z = GetZ(start_x, start_y) + GetUnitFlyHeight(from) + MissileStartZ[id]
        real distance = SquareRoot((end_x-start_x)*(end_x-start_x) + (end_y-start_y)*(end_y-start_y) + (end_z - z)*(end_z - z))
            //msg(R2S(end_z))
            if skill_id < 0 { return }
                if distance > MaxDistance[id] { distance = MaxDistance[id] }
            end_z = end_z + MissileStartZ[id]
            Current++
            MStack[Current] = Missile.create()
            MStack[Current].from = from
            MStack[Current].owner = CreateUnit(GetOwningPlayer(from), DUMMY, start_x, start_y, angle)
            SetUnitX(MStack[Current].owner,start_x)
            SetUnitY(MStack[Current].owner,start_y)
            SetUnitFlyHeight(MStack[Current].owner, z, 0.)
            AddSpecialEffectTarget(MissileModel[id], MStack[Current].owner, "origin")
            SetUnitScale(MStack[Current].owner, MissileScale[id], MissileScale[id], MissileScale[id])
            if StringLength(MissileLaunchSound[id]) > 0 
            { AddSound(MissileLaunchSound[id], Gx(MStack[Current].owner), Gy(MStack[Current].owner)) }
            MStack[Current].radius = MissieRadius[id]
            //MStack[Current].limit = MissileArc[MStack[Current].id]
            MStack[Current].dist = distance / 10.
            MStack[Current].id = id
            MStack[Current].skill_id = GetSkillCell(skill_id)
            MStack[Current].v.GetFrom2Loc(start_x, start_y, z, end_x, end_y, end_z)
            MStack[Current].v.vx = (end_x - start_x) / distance * MissileSpeed[id]
            MStack[Current].v.vy = (end_y - start_y) / distance * MissileSpeed[id]
            MStack[Current].v.vz = (end_z - z) / distance * MissileSpeed[id]
                if Current == 1 {
                    TimerStart(UpdateTimer, PERIOD, true, function MovementUpdate)
                }
    }

    void FireWeaponShell(unit source, real x, real y){
        UD ud = GetData(source)
        real start_x = Gx(source), start_y = Gy(source), z = GetZ(x, y) + 60.
        real start_z = GetZ(start_x, start_y) + GetUnitFlyHeight(source) + 60.
        real distance, distance_to_point = DBC(source, x, y), angle = ABUC(source, x, y)
        x = x + Rx(ud.current_weapon.range, angle); y = y + Ry(ud.current_weapon.range, angle)
        distance = SquareRoot((x-start_x)*(x-start_x) + (y-start_y)*(y-start_y) + (z - start_z)*(z - start_z))
            //if distance > ud.current_weapon.range { distance = ud.current_weapon.range }
            Current++
            MStack[Current] = Missile.create()
            MStack[Current].from = source
            MStack[Current].owner = CreateUnit(GetOwningPlayer(source), DUMMY, start_x, start_y, angle)
            SetUnitX(MStack[Current].owner,start_x)
            SetUnitY(MStack[Current].owner,start_y)
            MStack[Current].radius = ud.current_weapon.shell_size
            SetUnitFlyHeight(MStack[Current].owner, start_z, 0.)
            AddSpecialEffectTarget(ud.current_weapon.model, MStack[Current].owner, "origin")
            //MStack[Current].limit = ud.current_weapon.shell_limit_z
            MStack[Current].dist = distance_to_point / 10.
            MStack[Current].id = 0
            MStack[Current].skill_id = 0
            MStack[Current].v.GetFrom2Loc(start_x, start_y, start_z, x, y, z)
            MStack[Current].v.vx = (x - start_x) / distance * ud.current_weapon.shell_speed
            MStack[Current].v.vy = (y - start_y) / distance * ud.current_weapon.shell_speed
            MStack[Current].v.vz = (z - start_z) / distance * ud.current_weapon.shell_speed
                if Current == 1 {
                    TimerStart(UpdateTimer, PERIOD, true, function MovementUpdate)
                }
    }

endlibrary
Top