HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

MUI... I have no clue

03-08-2008, 03:28 PM#1
TheSecretArts
I haven't a clue on how to make MUI work for my spells. Can anyone point in the right direction on making MUI. I know it uses arrays and globals that manage how many instances are in each array, but I have no idea on how to handle them and make sure the right ones are moving.
Here is my code
Collapse JASS:
library UserDecFunctions
    function Expiration takes nothing returns nothing
        call KillUnit(CascadingCatacylsm.ProjDummy)
    endfunction
    //Functions used in the structs (IE, Collision functions) made by you go here
    function TenSeconds takes nothing returns nothing
        local unit u = udg_TEMPUnit
        local effect e = udg_TEMPEffect
        local integer x = 0
        loop
            exitwhen x==10
            call PolledWait(1)
            if (IsUnitAliveBJ(u)== false) then
                call UnitRemoveAbility(u,'A002')
                call DestroyEffect(e)
                return
            endif
            set x = x+1
            endloop
        call UnitRemoveAbility(u,'A002')
        call DestroyEffect(e)
    endfunction
    function IsNotCascading takes nothing returns boolean
        if (GetUnitTypeId(GetEnumUnit())=='u000') then
            return false
        else
            return true
        endif
    endfunction
    function CollisionEx takes nothing returns nothing
        if (UnitHasBuffBJ(GetEnumUnit(),'B000')==false) then
            if (IsUnitAliveBJ(GetEnumUnit())==true) then
                call SetUnitState((GetEnumUnit()), UNIT_STATE_LIFE, GetUnitState(GetEnumUnit(),UNIT_STATE_LIFE)-CascadingCatacylsm.Damage)
                set CascadingCatacylsm.Size = CascadingCatacylsm.Size+.1
                call SetUnitScale(CascadingCatacylsm.ProjDummy,CascadingCatacylsm.Size,CascadingCatacylsm.Size,CascadingCatacylsm.Size)
                set CascadingCatacylsm.Damage = CascadingCatacylsm.Damage+25+(R2I((CascadingCatacylsm.Level/3))*25)
                set CascadingCatacylsm.ObjectCollisionSize = CascadingCatacylsm.ObjectCollisionSize+.75
                call TimerStart( udg_CascCataTimer, ( TimerGetRemaining(udg_CascCataTimer) + 0.25 ), false,function Expiration )
                set udg_TEMPEffect = AddSpecialEffectTarget("Abilities\\Spells\\Items\\OrbDarkness\\OrbDarkness.mdl",GetEnumUnit(),"overhead")
                call UnitAddAbility(GetEnumUnit(),'A002')
                set udg_TEMPUnit = GetEnumUnit()
                call ExecuteFunc("TenSeconds")
            endif
        else
        endif    
endfunction
    function OnUnitCollision takes nothing returns nothing
        local group g
        set g = GetUnitsInRangeOfLocMatching(CascadingCatacylsm.ObjectCollisionSize,GetUnitLoc(CascadingCatacylsm.ProjDummy), Condition(function IsNotCascading))
        call ForGroup(g, function CollisionEx)
    endfunction
endlibrary


library VectorLib
////////////////////////////////////
//This is TheSecretArts'          //
//WIP Basic Vector System         //
//Only for use in Spell Making    //
//Contest #10.  Only TheSecretArts//
//can use this system.            //
////////////////////////////////////
    globals
        Vector GRAVITYVECTOR
        Vector MathVector
        trigger initialization
    endglobals
    struct Vector
        real x //This detirmines where the vector 'is'
        real y //This detirmines where the vector 'is'
        real z //This detirmines where the vector 'is'
        real Fx //These values are counterintuitive from what you might think        
        real Fy //These are based on planes, rather than force, a negative is backwards, thats why there is no directional value       
        real Fz //This way, it requires less math and is easier and less taxing if many events are happening at once       
        //the force values should be speed/sec.  
        method SetX takes real x returns nothing
            set this.x = x
        endmethod
        method SetY takes real y returns nothing
            set this.y = y
        endmethod
        method SetZ takes real z returns nothing
            set this.z = z
        endmethod
        method SetFx takes real m returns nothing
            set this.Fx = m
        endmethod         
        method SetFy takes real m returns nothing
            set this.Fy = m
        endmethod
        method SetFz takes real m returns nothing
            set this.Fz = m
        endmethod
        static method create takes real X, real Y, real Z, real FX, real FY, real FZ returns Vector
            local Vector Vec = Vector.allocate()
            set Vec.x = X
            set Vec.y = Y
            set Vec.z = Z
            set Vec.Fz = FZ
            set Vec.Fy = FY
            set Vec.Fx = FX
            return Vec
        endmethod
    endstruct
    function VectorNull takes Vector A returns Vector
        set MathVector.x = A.x
        set MathVector.y = A.y
        set MathVector.z = A.z
        set MathVector.Fx = 0
        set MathVector.Fy = 0
        set MathVector.Fz = 0
        return MathVector
    endfunction
//    function VectorNormal takes Vector A returns Vector
//        local Vector v2 = Vector.create(A.x,A.y,A.z,1,1,1)      VectorNormal requires some trig and stuff i don't understand
//        return v2
//    endfunction
    function VectorAdd takes Vector A, Vector B returns Vector
        set MathVector.Fx = A.Fx + B.Fx
        set MathVector.Fy = A.Fy + B.Fy
        set MathVector.Fz = A.Fz + B.Fz
        return MathVector
    endfunction
    function VectorSubtract takes Vector A, Vector B returns Vector
        set MathVector.Fx = A.Fx - B.Fx
        set MathVector.Fy = A.Fy - B.Fy
        set MathVector.Fz = A.Fz - B.Fz
        return MathVector
    endfunction
    function VectorMultiply takes Vector A, Vector B returns Vector
        set MathVector.Fx = A.Fx * B.Fx
        set MathVector.Fy = A.Fy * B.Fy
        set MathVector.Fz = A.Fz * B.Fz
        return MathVector
    endfunction
    function VectorDivide takes Vector A, Vector B returns Vector
        set MathVector.Fx = A.Fx / B.Fx
        set MathVector.Fy = A.Fy / B.Fy
        set MathVector.Fz = A.Fz / B.Fz
        return MathVector
    endfunction
    function SYSTEMINIT takes nothing returns nothing //MUST BE CALLED ON INITIALIZATION, I CAN'T STRESS THIS ENOUGH.
        set MathVector = Vector.create(0,0,0,0,0,0)
        set GRAVITYVECTOR = Vector.create(0,0,0,0,0,-9.8)
        set GRAVITYVECTOR.Fz = 0 //(I've modified it so that my projectiles won't fall.)
    endfunction
    
endlibrary


library ProjSyst needs VectorLib, UserDecFunctions
///////////////////////////////////////
//This is TheSecretArts' WIP         //
//projectile system.                 //
//This version is for use with       //
//Spell Making Contest #10 ONLY      //
//Only TheSecretArts can use this WIP//
///////////////////////////////////////
globals
    Projectile CascadingCatacylsm
endglobals
struct Projectile
    real TimeLife
    private real BaseTerrainLevel // This is used when FollowsTerrainHeight is FALSE, this stands as the base terrain level
//    real Cd //This is the drag coefficient, this effects how air drag effects the projectile
//    real RA //This is the reference area, this is used in calculating drag
    real ObjectCollisionSize //Say the unit has a proximity effect, this would allow control over that proximity size
//    real Mass // To make a projectile that doesnt fall, set mass to zero
    location TargetPoint
    unit Target //More or less for homing projectiles
    unit ProjDummy
    integer Level
    real Damage
    real Size
    real TimeStep
//    boolean EffectedByWind //At the moment this does not effect the unit, but when wind is implemented, spells that create wind or natural wind will not effect the projectile, for most objects this should probably be used.
//    boolean HitsCliffs //this could be toggled false so that it floats through cliffs
    boolean HitsUnits
//    boolean ExplodesOnGround                                                         
//    boolean FollowsTerrainHeight //This is a big one, this determines wether the unit's z is based off terrain height, or a base level (the base level is intially based of terrain height, but then becomes independed of terrain height)
//    boolean HitsCaster //If the spell rebounds back by some means, can it hit the caster
//    boolean HitsAllies
//    string CasterCollision //Function name to run on caster collision
//    string AllyCollision //Function name to run on allied collision
    string UnitCollision //Function name to run on unit collision, will check if you hit allies and if this unit can hit allies.
//    string GroundCollision //Function name to run on Ground collision
//    string CliffCollision //Function name to run on cliff collision
    Vector Ve=0
    method Initialization takes real x, real y, real z, real Fx, real Fy, real Fz returns nothing
        set this.Ve = Vector.create(x,y,z,Fx,Fy,Fz)
        set this.Ve.x = x
        set this.Ve.y = y
        set this.Ve.z = z
        set this.Ve.Fx = Fx
        set this.Ve.Fy = Fy
        set this.Ve.Fz = Fz
    endmethod 
    method DetectCliffCollision takes nothing returns nothing
        // Placeholder
    endmethod
    method DetectUnitCollision takes nothing returns nothing
        local boolean TFBool = this.CheckCollision()
        if (TFBool==TRUE) then
            call ExecuteFunc(this.UnitCollision)
        endif
    endmethod
    method SetFacingAngleToTargetedPoint takes nothing returns nothing
        call SetUnitFacing(this.ProjDummy,3.14159/180.0 * Atan2(GetLocationY(this.TargetPoint) - GetLocationY(GetUnitLoc(this.ProjDummy)), GetLocationX(this.TargetPoint) - GetLocationX(GetUnitLoc(this.ProjDummy))))
    endmethod
    method SetFacingAngleToTargetedUnit takes nothing returns nothing // This allows a 'homing' projectile
        call SetUnitFacing(this.ProjDummy,3.14159/180.0 * Atan2(GetLocationY(GetUnitLoc(this.Target)) - GetLocationY(GetUnitLoc(this.ProjDummy)), GetLocationX(GetUnitLoc(this.Target)) - GetLocationX(GetUnitLoc(this.ProjDummy))))
    endmethod
//    method GetGravForce takes nothing returns real
//        return (this.Mass * GLOBALMASS) //Placeholder for actual grav formula
//    endmethod
    method SetNewXYZ takes nothing returns nothing //Doesnt move unit, just sets the values to prepare movement.  Has a use for debugging
        set this.Ve.x = this.Ve.x + (this.Ve.Fx * this.TimeStep)
        set this.Ve.y = this.Ve.y + (this.Ve.Fy * this.TimeStep)
  //      if (this.FollowsTerrainHeight == TRUE) then
            call VectorAdd(this.Ve,GRAVITYVECTOR)
   //         set this.Ve.z = this.Ve.Fz + this.Ve.z
  //      else
            // ((z-grav*X)*TS)
 //           call VectorAdd(v,GRAVITYVECTOR)
//            set this.Ve.Fz = (TERRAINHEIGHT-this.BaseTerrainLevel)
            set this.Ve.z = this.Ve.Fz + this.Ve.z
 
  //     endif
    endmethod
    method MoveToXYZ takes nothing returns nothing
        call SetUnitPosition(this.ProjDummy,this.Ve.x,this.Ve.y)
        call UnitAddAbility(this.ProjDummy,'Amrf')
        call SetUnitFlyHeight(this.ProjDummy,this.Ve.z,0)
        call UnitRemoveAbility(this.ProjDummy,'Amrf')
    endmethod
    method SmartMove takes nothing returns nothing // this pretty much combines MovetoXYZ and SetNewXYZ
        set this.Ve.x = this.Ve.x + (this.Ve.Fx * this.TimeStep)
        set this.Ve.y = this.Ve.y + (this.Ve.Fy * this.TimeStep)
 //       if (this.FollowsTerrainHeight == TRUE) then
        call VectorAdd(this.Ve,GRAVITYVECTOR)
 //       set this.Ve.z = this.Ve.Fz + this.Ve.z
 //       else
            // ((z-grav*X)*TS)
 //           call VectorAdd(this.Ve,GRAVITYVECTOR)
//            set this.Ve.Fz = (TERRAINHEIGHT-this.BaseTerrainLevel)
            set this.Ve.z = this.Ve.Fz + this.Ve.z
  //      endif
        call SetUnitPosition( this.ProjDummy , this.Ve.x , this.Ve.y )
        call UnitAddAbility( this.ProjDummy , 'Amrf' )
        call SetUnitFlyHeight( this.ProjDummy , this.Ve.z , 0 )
        call UnitRemoveAbility( this.ProjDummy , 'Amrf' )
        call this.DetectUnitCollision()
    endmethod      
    method CheckCollision takes nothing returns boolean
        local group g = GetUnitsInRangeOfLocAll(this.ObjectCollisionSize,GetUnitLoc(this.ProjDummy))
        if (CountUnitsInGroup(g)>0) then
            return TRUE
        else
            return FALSE
        endif
    endmethod
endstruct
endlibrary


library CascadingCataclysm needs ProjSyst
///////////////////////////////////////////
//This is spell making contest #10       //
//entry: Cascading Cataclysm             //
//Also check the Library UserDecFunctions//
//for it also contains part of this spell//
//that is used by my system.             //
///////////////////////////////////////////
globals
    trigger Move
    trigger CheckCast
    trigger CheckExpire
    trigger Master
endglobals
function MoveConditions takes nothing returns boolean
    if (R2I(TimerGetRemaining(udg_CascCataTimer)) > 0 ) then
        return true
    endif
    return false
endfunction
function MoveActions takes nothing returns nothing
    call CascadingCatacylsm.SmartMove()
endfunction
function Trig_OnCast_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A001' ) ) then
        return false
    endif
    return true
endfunction
function CalculateForceX takes unit u returns real
    local location p = PolarProjectionBJ(GetUnitLoc(u), 1000.00, GetUnitFacing(u))
    local real XMX //X minus X to find total X change
    local real XC //X over (distance/speed) 1000/200=5
    set XMX = GetLocationX(p)-GetLocationX(GetUnitLoc(u))
    set XC = (XMX/2)
    return XC
endfunction
function CalculateForceY takes unit u returns real
    local location p = PolarProjectionBJ(GetUnitLoc(u), 1000.00, GetUnitFacing(u))
    local real YMY //Y minus Y
    local real YC //Y over (distance/speed)
    set YMY = GetLocationY(p)-GetLocationY(GetUnitLoc(u))
    set YC = (YMY/2)
    return YC
endfunction
function Casted takes nothing returns nothing
    local unit U 
    call CreateNUnitsAtLocFacingLocBJ( 1, 'u000', Player(0), GetUnitLoc(GetTriggerUnit()), OffsetLocation(GetSpellTargetLoc(), 0, 0) )
    set U = GetLastCreatedUnit()
    set CascadingCatacylsm = Projectile.create()
    call CascadingCatacylsm.Initialization(GetUnitX(U),GetUnitY(U),100,CalculateForceX(GetTriggerUnit()),CalculateForceY(GetTriggerUnit()),0)
    set CascadingCatacylsm.Level = GetUnitAbilityLevel(GetTriggerUnit(),'A001')
    set CascadingCatacylsm.ObjectCollisionSize =75
    set CascadingCatacylsm.Size = 1
    set CascadingCatacylsm.Damage = ((25*(CascadingCatacylsm.Level)))+25
    set CascadingCatacylsm.ProjDummy = U
    set CascadingCatacylsm.TimeStep = .01    
    set CascadingCatacylsm.TimeLife = ((.5*(CascadingCatacylsm.Level)))+1.5
    set CascadingCatacylsm.HitsUnits = TRUE
    set CascadingCatacylsm.UnitCollision = "OnUnitCollision"
    call SetUnitFacing(CascadingCatacylsm.ProjDummy,GetUnitFacing(GetTriggerUnit()))
    set CascadingCatacylsm.TargetPoint = PolarProjectionBJ(GetUnitLoc(GetTriggerUnit()), 1000.00, GetUnitFacing(GetTriggerUnit()))
    call TimerStart( udg_CascCataTimer, CascadingCatacylsm.TimeLife, false, function Expiration )
endfunction
endlibrary
03-10-2008, 12:27 PM#2
TheSecretArts
bump, are there any make-a-spell MUI tutorials at all or any tutorials that could help me?
03-10-2008, 03:39 PM#3
moyack
MUI is not a system, is more related in the way you code. If you want to make your spells MUI, you must code in such way that if you have 20 units and they cast at the same time a triggered spell, the code and the behavior of the spell won't be affected among them.

So, the test is easy: put several units with the spell in the map, and then put them to cast the spell at the same time on a target, if the spell behavior is affected in a bad way, then your spell is not MUI.

How to ensure your spell is MUI? use local vars, and if you need to transfer data from one function to another (aka send data to a timer or trigger) then use handlevars, ABC, etc.
03-10-2008, 03:53 PM#4
TheSecretArts
I do send data to a function with a trigger, but it uses a global... so I might need to do a little recoding.
I think I'll just create a couple arrays for the struct, the timer, and an index variable and just destroy everything on expiration and re-initialize and creation... that should make it MUI.
I already know my spell isn't MUI. What I'd imagine would happen is that one would stop moving.