Advanced Missile System requests

AgentChaos

New Member
Reaction score
1
:)There are many missile systems had been created,Why would it be a new?
http://www.hiveworkshop.com/forums/...34600/?prev=search=Magma%20Spirit&d=list&r=20
The above skills in a very complex missile skills, is not the missile system, :)so I hope someone create that kind of missile system?

:)Maybe some people lazy, so I copy the code up


JASS:
scope DuskySoul initializer Init

globals
    private constant integer Spell            = 'A005'
        //Dark Soul Spell 
        
    private constant integer Summon           = 'n001'
        //Summoned unit (Dark Soul)
        
    private constant integer AttackDummy      = 'h002'
        //An Attack dummy to fake an attack at the target
        
    private constant integer AttackProjectile = 'h003'
        //Projectile of the Dark Soud
        
    private constant integer DummyVertex      = 170
        //Vertex the Summon has
        
    private constant integer DummyDarkness    = 255
        //How dark the summon is

    private constant real    TimerPeriod      = 0.0225
        //Timer Interval of the custom projectiles
        
    private constant real    TimerPeriodDsys  = 0.1    
        //Timer Interval for the Attack dummys locaation adjust (moves the dummy to the target to faake an attack)
        
    private constant real    CrueltyDamage    = 0.14
        //Percentage damage of hp missing 
        
    private constant real    HitRange         = 30
        //Range in which the projectiles hit an enemy
        
    private constant real    HitHeight        = 45
        //Height in which the projectiles will reach the target (flying heigh wwill be additional)

    private constant real    ProjectileSpeed  = 18
        //Speed the Projectiles got, also affaectey by the timer period
        
    private constant real    ProjectileStartX = -12
        // X Offset of the Projectile Creation (look at the model you used)
        
    private constant real    ProjectileStartY = 100
        // Y Offset of the Projectile Creation (look at the model you used) 
        
    private constant real    ProjectileStartZ = 130
        // Z Offset of the Projectile Creation (look at the model you used) 
        
    private constant real    ProjectileSway   = 0.15
        //Defines the amplitude of the projectiles movement (their distance to each other increaes while flying like a parabula
        // 0.15 means the amplitube will be 15% of the flying distance
        
    private constant real    GrowSpeed        = 7
        //Rate the summon will grow and shring (played when creating it)
        
    private constant real    DummySize        = 1.15
        //The normal size of the Summon (needed for the grow/shrink)
    
    private constant string  AttackEffect     = "Abilities\\Weapons\\SentinelMissile\\SentinelMissile.mdl"
        //The effects displayed the the darksould hands when releasing a missile
        
    private constant string AOEeffect         = "Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl"
        // AOE effect when hitting a target with Inner Blaze
    
    private constant string  StartAnimation   = "Spell"
        //The animation the dummy plays when being created
        
    private constant boolean KillDS           = false //Sets the action if the hero casts the ability while he already got one Dark soul summoned
        //True = Kiling the current Dark Sould when casting it again
        //False = Odering the caster to stop
        

///////////////////////////////////Globals that should not be changed////////////////////////////

    private trigger array tr  //Trigger for each hero casting and having the summoned unit to protect any damage
    private trigger array tr2 //Trigger to get the damage of each attack dummy and create missiles then
    private integer trin = 0  //Trigger index , how many Summoned units are ingame which use this custom system (equals number of dummies and current triggers Tr1 and Tr2)
    private unit array ds     //Dark soul (with trin index)
    private unit array ad     //Attack Dummy (with trin index)
    private unit array targ   //Target of each Dark sould (with trin index)
    private unit array hero   //Corrensponding hero (with trin index)
    private timer t2 = CreateTimer()
    private boolean cb = false // boolean if any callbacls should run
    private boolexpr filter  
    private timer t = CreateTimer()
endglobals

/////////////////////////////////////////Function modifications////////////////////////////////////////////////////////

private function RunCondition takes nothing returns boolean
    return GetSpellAbilityId() == Spell
    //The condition if the spell is casted
endfunction

private constant function Duration takes integer level returns real
    return 75.00
endfunction

private function DamageTarget takes real damage, unit target, unit dealer returns nothing
        //Sets which function is used to deal the damage, now it is dependent on the IFDamage function in Inner Blaze which will cause its damage to splash if the unit got the buff
        //If you dont want it to splash, replace it, e.g. with the one below or whichever you want
    call IFDamage(damage,target,dealer,AOEeffect,"chest")
    //call UnitDamageTarget(dealer,target,damage,true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS)
endfunction

function DisplayDamage takes real damage, unit u returns nothing
    //Displays the bonus damage of the Dark Soul
    local texttag tt = null
    if R2I(damage) != 0 then // does not display "+0" damage
        set tt = CreateTextTag()
        call SetTextTagText(tt, "|c00ff5656+"+I2S(R2I(damage))+"|r", 0.023)
            //The color is set here 
            
        //Any other things you may want to modify or not
        call SetTextTagPos(tt, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u))
        call SetTextTagColor(tt,255,255,255,255)
        call SetTextTagVisibility(tt, true)
        call SetTextTagFadepoint(tt,3.00)
        call SetTextTagPermanent(tt,false)
        call SetTextTagVelocity(tt,  0, 0.0355)
        call SetTextTagLifespan(tt, 4.00)
        set tt = null
    endif
endfunction

////////////////////////////////////////Main Script /////////////////////////////////////////////////////////////

private constant function NullFilter takes nothing returns boolean
    return true
endfunction

private function GetHeroIndex takes unit a returns integer
    local integer ret = -1
    local integer i = 0 
    // Gets the trin of the hero to find its correnspoding summon ect
    loop 
        exitwhen i == trin
        if a == hero<i> then
            set ret = i
        endif
        set i = i + 1
    endloop
    return ret
endfunction

private function GetTargIndex takes unit a returns integer
    local integer ret = -1
    local integer i = 0 
    // Gets the trin of a targeted unit to check if a unit s attacking it (cuz the attack dummy stay and else it would be still &quot;attacked&quot;)
    loop 
        exitwhen i == trin
        if a == targ<i> then
            set ret = i
        endif
        set i = i + 1
    endloop
    return ret
endfunction

private function GetDSIndex takes unit a returns integer
    local integer ret = -1
    local integer i = 0 
    /// Gets the trin of a Dark sould to let the hero deal the damage (needs to be for Inner Blaze cuz he has the ability)
    loop 
        exitwhen i == trin
        if a == ds<i> then
            set ret = i
        endif
        set i = i + 1
    endloop
    return ret
endfunction

private function GetDummyIndex takes unit a returns integer
    local integer ret = -1
    local integer i = 0 
    // Gets the trin of a Dummy unit
    loop 
        exitwhen i == trin
        if a == ad<i> then
            set ret = i
        endif
        set i = i + 1
    endloop
    return ret
endfunction

private function GetUnitsAngle takes unit a, unit b returns real
    //angle between units, from a to b
    return Atan2(GetUnitY(b) - GetUnitY(a), GetUnitX(b) - GetUnitX(a))
endfunction

function GetUnitDistance takes unit a, unit b returns real
    //Distance between 2 units
    return SquareRoot((GetUnitX(a) - GetUnitX(b)) * (GetUnitX(a) - GetUnitX(b)) + (GetUnitY(a) - GetUnitY(b)) * (GetUnitY(a) - GetUnitY(b)))
endfunction

///////////////////////////////////////CallBack//////////////////////////////////////////////

private function Callback takes nothing returns nothing
    local integer i = 0
    local real db
    
    //looping through each dark Sould (creation grow)
    loop
        exitwhen i &gt;= DS.Index
        if DS.Data<i>.inc == -1 and DS.Data<i>.size == DummySize then
            set DS.Data<i>.c = null  
            set DS.Data<i>.Ds = null
            call DS.destroy(DS.Data<i>)
            set DS.Index = DS.Index - 1
            set DS.Data<i> = DS.Data[DS.Index]
        else
            call DS.Data<i>.grow()
            set i = i + 1
        endif
    endloop
    
    
    set i = 0
    //looping through each Projectile to move it
    loop
        exitwhen i &gt;= Pr.Index
        if GetUnitDistance(Pr.Data<i>.pr[0],Pr.Data<i>.target) &lt;= HitRange then
            //Here is defined if aa Projectile hits its target
            set db = (GetUnitState(Pr.Data<i>.target,UNIT_STATE_MAX_LIFE)-GetWidgetLife(Pr.Data<i>.target)) * CrueltyDamage
            call UnitDamageTarget(Pr.Data<i>.ca,Pr.Data<i>.target,0.001,true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS)
            call DamageTarget(Pr.Data<i>.dmg+db,Pr.Data<i>.target,Pr.Data<i>.ma)
            call DisplayDamage(db,Pr.Data<i>.target)
            call KillUnit(Pr.Data<i>.pr[0])
            call KillUnit(Pr.Data<i>.pr[1])
            call KillUnit(Pr.Data<i>.pr[2])
            set Pr.Data<i>.pr[0] = null  
            set Pr.Data<i>.pr[1] = null  
            set Pr.Data<i>.pr[2] = null  
            set Pr.Data<i>.ca = null  
            set Pr.Data<i>.target = null  
            call Pr.destroy(Pr.Data<i>)
            set Pr.Index = Pr.Index - 1
            set Pr.Data<i> = Pr.Data[Pr.Index]
        else
            call Pr.Data<i>.move()
            set i = i + 1
        endif
    endloop
    
    if DS.Index &gt; 0 or Pr.Index &gt; 0 then
         call TimerStart(t, TimerPeriod, false, function Callback)
    else
        set cb = false
    endif        
endfunction

////////////////////////////////////////Summon Projectile////////////////////////////////////////////

struct Pr //Projectile
    static integer Index = 0
    static Pr array Data
    unit target//Missile dummy
    unit ca //&quot;Caster&quot; , means its the attacking summon
    unit ma //&quot;Master&quot; of the summon, the corrensponding hero 
    real maxd //Distance when creating the missile
    real dmg //dmage stored
    unit array pr [3] // the 3 Proectiles

   static method create takes unit ca, unit ta, real damage returns Pr
   
        local Pr data = Pr.allocate()
        local real a = GetUnitsAngle(ca,ta)
        local integer i = 0
        local real x = GetUnitX(ca) + (Cos(a) * ProjectileStartY) + (Sin(a) * ProjectileStartX)
        local real y = GetUnitY(ca) + (Cos(a) * ProjectileStartX) + (Sin(a) * ProjectileStartY)
        local integer index = GetDSIndex(ca)
        set Pr.Data[Pr.Index] = data
        set data.ma = hero[index]
        
        //Creating the 3 projectiles
        loop
            exitwhen i == 3
            set data.pr<i> = CreateUnit(GetOwningPlayer(ca),AttackProjectile,x,y,a)
            call SetUnitFlyHeight(data.pr<i>,ProjectileStartZ,0)
            set i = i + 1
        endloop
        
        set data.maxd = GetUnitDistance(ta,data.pr[1]) * 1.05 // lil bit bigger cuz else its amplitude will not be 0 at the end
        set data.ca = ca
        set data.target = ta    
        set data.dmg = damage
        
        if cb == false then
            call TimerStart(t, TimerPeriod,false, function Callback)
            set cb = true
        endif
        
        set Pr.Index = Pr.Index + 1
        return data
    endmethod 
    
    method move takes nothing returns nothing
        local integer i = 0
        local real a = GetUnitsAngle(this.pr[1],this.target)
        local real d = (ProjectileSpeed+GetUnitDistance(this.target,this.pr[1]))/this.maxd
        local real offset = Sin(3.14159*d) * ProjectileSway * this.maxd
        
        //Moving all 3 Missiles (refers to pr[1]?s x and y because its not affected by the amplitide
        call SetUnitX(this.pr[1],GetUnitX(this.pr[1])+ProjectileSpeed*Cos(a))
        call SetUnitY(this.pr[1],GetUnitY(this.pr[1])+ProjectileSpeed*Sin(a))
        call SetUnitFlyHeight(this.pr[1],ProjectileStartZ + offset + (GetUnitFlyHeight(this.target)  - ProjectileStartZ + HitHeight) * (1-d) ,0)
        call SetUnitX(this.pr[0],GetUnitX(this.pr[1])+offset*Cos(a + (3.14159/2)) )
        call SetUnitY(this.pr[0],GetUnitY(this.pr[1])+offset*Sin(a + (3.14159/2)) )
        call SetUnitFlyHeight(this.pr[0],ProjectileStartZ + (GetUnitFlyHeight(this.target)  - ProjectileStartZ + HitHeight) * (1-d) ,0)
        call SetUnitX(this.pr[2],GetUnitX(this.pr[1])+offset*Cos(a - (3.14159/2)) )
        call SetUnitY(this.pr[2],GetUnitY(this.pr[1])+offset*Sin(a - (3.14159/2)) )
        call SetUnitFlyHeight(this.pr[2],ProjectileStartZ + (GetUnitFlyHeight(this.target)  - ProjectileStartZ + HitHeight) * (1-d) ,0)
    endmethod
    
    
endstruct

////////////////////////////////////////Damage System////////////////////////////////////////////////

function AdjustTarget takes nothing returns nothing
    //If a summon gets aa new target its set here any the dummy is moved
    local unit b = GetAttacker()
    local integer index = GetDSIndex(b)
    local unit a = GetTriggerUnit()
    local real angle = GetUnitsAngle(b,ad[index])
    if GetUnitTypeId(a) != AttackDummy and ad[index] != a then
        set targ[index] = a
        //Need to do this senseless crap here, else the Summons attack animation is not played properly (but i wonder why, it just gets the order to attack another unit)
        // I &lt;3 Blizzard logic
        call SetUnitPosition(ad[index],GetUnitX(a),GetUnitY(a))
        call IssueImmediateOrder(b, &quot;stop&quot; ) 
        call PauseUnit(b,true)
        call PauseUnit(b,false)
        call IssueTargetOrder( b, &quot;attack&quot;, ad[index])
    endif
    set b = null
    set a = null
endfunction

function UnitDies takes nothing returns nothing
    //If a unit dies which is &quot;ttacked&quot; by a summon it gets the stor order 8stopt attacking the neutral dummy
    //Then it searched a new target
    local unit u = GetTriggerUnit()
    local integer i = GetTargIndex(u)
    
    if i != -1 then
        call IssueImmediateOrder(ds<i>, &quot;stop&quot; ) 
    endif
    
    set u = null
endfunction

function InitDeath takes nothing returns nothing
    local trigger d = CreateTrigger(  )
    local integer index = 0
    // Creates a trigger to check if a target dies 
        
    loop
        call TriggerRegisterPlayerUnitEvent(d, Player(index), EVENT_PLAYER_UNIT_DEATH , filter)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( d, function UnitDies )
endfunction

function MoveDummy takes nothing returns nothing
    local integer i = 0
    //periodicly movinge the dummy to the real targets location
    loop
        exitwhen i &gt; trin
        call SetUnitX(ad<i>,GetUnitX(targ<i>))
        call SetUnitY(ad<i>,GetUnitY(targ<i>))
        set i = i + 1
    endloop
    
    if trin &gt; 0 then
         call TimerStart(t2, TimerPeriodDsys, false, function MoveDummy)
    endif   
endfunction

function StartMissile takes nothing returns nothing
    //Event is when a dummy gets damage, then (due the attck of the sumon is instant) its damage is stored and projectiles are creted
    local integer index = GetDummyIndex(GetTriggerUnit())
    call DestroyEffect(AddSpecialEffectTarget(AttackEffect,GetEventDamageSource(),&quot;hand, left&quot;))
    call DestroyEffect(AddSpecialEffectTarget(AttackEffect,GetEventDamageSource(),&quot;hand, right&quot;))
    call Pr.create(GetEventDamageSource(),targ[index],GetEventDamage())
endfunction

function RightDamager takes nothing returns boolean
    //Condition that a summon damaged thee dummy, could also happen with AOE spells 
    return GetUnitTypeId(GetEventDamageSource()) == Summon
endfunction

function InitGetDamage takes unit dummy returns nothing
    //Initializing the Trigger when a Dummy takes damage
    set tr2[trin] = CreateTrigger()
    if trin == 0 then
        call TimerStart(t2, TimerPeriodDsys, true, function MoveDummy)
    endif 
    call TriggerRegisterUnitEvent( tr2[trin], dummy, EVENT_UNIT_DAMAGED )
    call TriggerAddAction( tr2[trin], function StartMissile )
    call TriggerAddCondition( tr2[trin], Condition( function RightDamager ) )
endfunction

function RightAttacker takes nothing returns boolean
    //Condition that its a Summon which targets the dummy
    return GetUnitTypeId(GetAttacker()) == Summon
endfunction

function InitDsys takes nothing returns nothing
    local integer index = 0
    local trigger trig = CreateTrigger(  ) 
    //Generally initializing the system with creating the trigger to get the point a dummy is attacked
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(index), EVENT_PLAYER_UNIT_ATTACKED, filter)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( trig, function AdjustTarget )
    call TriggerAddCondition( trig, Condition( function RightAttacker ) )
endfunction

/////////////////////////////////////////////Damage Protection//////////////////////////////////

function ProtectDamage takes nothing returns nothing

    local unit c = GetTriggerUnit()
    local integer index = GetHeroIndex(c)
    //Protects damage from the casting hero , event is that it takes damage, 
    call SetWidgetLife(c,GetWidgetLife(c) + GetEventDamage())
    //Damages the summon instead
    call UnitDamageTarget(GetEventDamageSource(),ds[index],GetEventDamage(),true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_NORMAL , WEAPON_TYPE_WHOKNOWS)
    set c = null
endfunction

function InitDamageProtect takes unit c, unit s returns nothing

    //Initializing the damage protection for the hero
    set tr[trin] = CreateTrigger()
    set ds[trin] = s
    set ad[trin] = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),AttackDummy,0,0,0)
    set hero[trin] = c
    
    call TriggerRegisterUnitEvent( tr[trin], c, EVENT_UNIT_DAMAGED )
    call TriggerAddAction( tr[trin], function ProtectDamage )
    call InitGetDamage(ad[trin])
    set trin = trin + 1
endfunction

/////////////////////////////////////////////////////////////////////////////////////////////////

function DestroyTr takes nothing returns nothing
    local integer index = GetDSIndex(GetTriggerUnit())
    
    //Destroying all triggers and the dummy which are not needed anymore when a Summon dies
    call RemoveUnit(ad[index])
    set ds[index] = null
    set hero[index] = null
    set ad[index] = null
    set targ[index] = null
    call DestroyTrigger(tr[index])
    set tr[index] = null
    call DestroyTrigger(tr2[index])
    set tr2[index] = null
    set trin = trin - 1
    set tr[index] = tr[trin]
    set ds[index] = ds[trin]
    set hero[index] = hero[trin]
    set ad[index] = ad[trin]
    set targ[index] = targ[trin]
    
endfunction

private function UnitDeath takes nothing returns boolean
    //Condition that it should be a summon which dies to destroy its correspoding dummy and trigger
    return GetUnitTypeId(GetTriggerUnit()) == Summon
endfunction

function DestroyTrInit takes nothing returns nothing
    local integer index = 0
    local trigger trig = CreateTrigger(  )
    //Initializes the destruction of the dummy and the trigger if a summons dies
    
    loop
        call TriggerRegisterPlayerUnitEvent(trig, Player(index), EVENT_PLAYER_UNIT_DEATH, filter)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddAction( trig,function DestroyTr )
    call TriggerAddCondition( trig, Condition( function UnitDeath ) )
endfunction

struct DS  //Dark Sould struct
    static integer Index = 0
    static DS array Data
    unit c //Hero 
    unit Ds //Dark Soul
    integer level //level of the spell
    real size = DummySize //Current size
    integer inc = 1 //Defines if the unit is groing or shrinking 
    unit ad //Attackdummy
    
    static method create takes unit a, integer level returns DS
        //Creates the Dark soul
        local DS data = DS.allocate()
        set data.c = a
        set data.Ds = CreateUnit(GetOwningPlayer(a),Summon,GetUnitX(a),GetUnitY(a),GetUnitFacing(a))
        call InitDamageProtect(a,data.Ds)
        call SetUnitPathing(data.Ds,false)
        call PauseUnit(data.Ds,true)
        call SetUnitX(data.Ds,GetUnitX(a))
        call SetUnitY(data.Ds,GetUnitY(a))
        call SetUnitAnimation(data.Ds, StartAnimation)
        call SetUnitVertexColor(data.Ds,255-DummyDarkness,255-DummyDarkness,255-DummyDarkness,DummyVertex)
        set DS.Data[DS.Index] = data
        
        if cb == false then
            call TimerStart(t, TimerPeriod, true, function Callback)
            set cb = true
        endif
        
        set data.Index = data.Index + 1
        return data
    endmethod
    
    method grow takes nothing returns nothing
        local real vertex = DummyVertex - (75*(this.size + (GrowSpeed * this.inc * 0.01) - DummySize) )
        set this.size = this.size + (GrowSpeed * this.inc * 0.01)
        
        if vertex &lt;= 0.0 then 
            //Vertex reached 0, setting it to increase again
            set this.inc = -1
            call SetUnitPathing(this.Ds,true)
            call SetUnitPosition(this.Ds,GetUnitX(this.c),GetUnitY(this.c))
            call SetUnitAnimation(this.Ds, StartAnimation)
        endif
        
        if this.inc == -1 and this.size &lt;= DummySize then
            //Unit has its normal size again and animation is finished
            set this.size = DummySize 
            set vertex = DummyVertex
            call PauseUnit(this.Ds,false)
            call UnitApplyTimedLife(this.Ds,0,Duration(this.level))
        endif
        
        call SetUnitScale(this.Ds,this.size,this.size,this.size)
        call SetUnitVertexColor(this.Ds,255-DummyDarkness,255-DummyDarkness,255-DummyDarkness,R2I(vertex))
        
    endmethod
    
endstruct    
    
function Actions takes nothing returns nothing
    local integer check = GetHeroIndex(GetTriggerUnit())
    if check == -1 then
        call DS.create(GetTriggerUnit(),GetUnitAbilityLevel(GetTriggerUnit(),Spell))
    else
        if KillDS == true then
            call KillUnit(ds[check])
            call DS.create(GetTriggerUnit(),GetUnitAbilityLevel(GetTriggerUnit(),Spell))
        else
            call IssueImmediateOrder(GetTriggerUnit(), &quot;stop&quot; )  
        endif
       //A hero cannot have more than one Dark Soul a the same time
    endif
endfunction

private function Init takes nothing returns nothing
    local trigger tr = CreateTrigger()
    local integer index = 0
    
    //Preloading the Units
    local unit preload =  CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),AttackProjectile,0,0,0)
    local unit preload2 =  CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),AttackDummy,0,0,0)
    call KillUnit(preload)
    call KillUnit(preload2)
    //Preloading Effects
    call Preload(AttackEffect)
    call Preload(AOEeffect)
    
    set filter = Filter(function NullFilter)
    //Initializing the 3 systems
    call DestroyTrInit() //General thing if a Summon dies / removing dummy + destroying other triggers
    call InitDeath() //General thing if a target dies
    call InitDsys() //General Damage System with custom projectiles
    
    loop
        call TriggerRegisterPlayerUnitEvent(tr, Player(index), EVENT_PLAYER_UNIT_SPELL_CAST, filter)
        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    
    call TriggerAddCondition( tr, Condition( function RunCondition ) )
    call TriggerAddAction( tr, function Actions )
    set preload = null
endfunction

endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
 

AgentChaos

New Member
Reaction score
1
That missle system is good one,but it use too much lab.
I still want a three missiles system, look much cooler.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top