• 🏆 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!

Hey Nestharus you owe me 200$

Status
Not open for further replies.
Level 7
Joined
Apr 1, 2010
Messages
289
:ogre_haosis:just joking. Nestharus cancelled it anyway .http://www.hiveworkshop.com/forums/requests-341/morale-system-willing-pay-200-a-204902/?highlight=Morale i have made something that kinda fits the requirements, the morale part works(other then sometimes not looping through the units)

So why didn't i just say, I need help with a morale system,
1st Lolz
2nd you're reading this aren't you?

How this Morale system is by using an RPS(region positioning system) which creates a lot of regions, and records the number of units in each one, using enters/leaves.

I have not added something for dying units(oh, it clears the references too them but they "remain" in the region(for the morale system anyway), but thats not a big deal i already have come up with a way to handle that and i would like to improve things in the code before i implement it)

here is the code
JASS:
function Trig_System_Perodic takes nothing returns boolean
    local unit u

    local integer UnitH
    local integer i = 0

    local real addition    
    local real r

    //local integer t
    local integer reduce = udg_InCombatCount
    local integer sign = 1
    local integer id 

    local real x
    local real y
    local real x1
    local real y1
    local real a

    local real morale
    
    local group g = CreateGroup()
    call GroupAddGroup(udg_InCombat,g)
    
    loop
       loop
          set u =FirstOfGroup(g)
          call GroupRemoveUnit(g,u)// this is a first of group loop
          exitwhen null != u
       endloop


       set UnitH =GetHandleId(u)
       set i = i +1
       if not IsUnitType(u, UNIT_TYPE_DEAD) then// checking to see if the unit is dead


          set morale = LoadReal(udg_RPS,UnitH,1)
 
          set udg_RegionH = LoadInteger(udg_RPS,UnitH,0)// this is determine which region to load the values from
          set udg_Player = GetOwningPlayer(u)//the owning player
          set udg_Friend = 0
          set udg_Enemy  = 0
             
          set id =0
          loop
           
             if udg_Player == Player(id) or IsPlayerAlly(udg_Player,Player(id)) then
                set udg_Friend = udg_Friend+LoadInteger(udg_RPS,udg_RegionH,id)
             else
                set udg_Enemy = udg_Enemy+LoadInteger(udg_RPS,udg_RegionH,id)
             endif
                
             set id = id+1
             exitwhen id == 15
          endloop        
             

          set r = I2R(udg_Friend-udg_Enemy )



          if 0 > r then
             set sign = -1
             set r = -r
          else 
            set sign = 1
          endif
                 
          set addition = (r/(r+5))*10
          set addition = (addition*sign)+morale
             
             
          //call KillUnit(u)         


          if 100 < addition then
            set addition = 100
          elseif -200 > addition then
            set addition = -200
          endif


          if IsUnitSelected(u,Player(0)) then
            call CreateTextTagUnitBJ( I2S(R2I(addition)),u , 35, 10, 100, 100, 100, 0 )
            call SetTextTagPermanentBJ( GetLastCreatedTextTag(), false )// note yes, i know you can use natives instead, this is just for the test!!
            call SetTextTagLifespanBJ( GetLastCreatedTextTag(), 0.50 )   
          endif
       
          if addition < -100 and not IsUnitInGroup(u,udg_Running) then//checking morale of unit
            call SaveReal(udg_RPS,UnitH,3,GetUnitX(u))
            call SaveReal(udg_RPS,UnitH,4,GetUnitY(u))
            call GroupAddUnit(udg_Running,u)//adding unit to flee group
            call UnitAddAbility(u,'A000')// preventing unit attacks
            call UnitAddAbility(u,'A001')
            
          elseif IsUnitInGroup(u,udg_Running) then 
              if addition > -50 then
                 call GroupRemoveUnit(udg_Running,u)
                 call UnitRemoveAbility(u,'A000')
                 call UnitRemoveAbility(u,'A001')
                 //call DisplayTextToPlayer(Player(0),0,0,"removing ability")
              else
                 set x = LoadReal(udg_RPS,UnitH,3)
                 set y = LoadReal(udg_RPS,UnitH,4)
                 set x1 = GetUnitX(u)
                 set y1 = GetUnitY(u)
                 set a = Atan2(y1-y,x1-x)
                 set x = Cos(a)*500
                 set y = Sin(a)*500
                 call IssuePointOrder(u,"move",x1+x,y1+y)
              endif
                 
          endif


          //call SaveInteger(udg_RPS,UnitH,2,t)// saving the time its been in combat
          call SaveReal(udg_RPS,UnitH,1,addition)// saving its "morale"
             
       else
          set reduce = reduce - 1                 // removing the unit from the unit group
          call FlushChildHashtable(udg_RPS,UnitH) // clearing the hashtable
          call GroupRemoveUnit(udg_InCombat,u)    // removing unit
       endif  
       
       exitwhen i == udg_InCombatCount       
    endloop

    set udg_InCombatCount = reduce
    set u = null
    call DestroyGroup(g)
    set g = null
    return false
endfunction

function Trig_System_Actions takes nothing returns nothing
    local unit d = GetTriggerUnit()
    local unit a = GetAttacker()
    if not IsUnitInGroup(d,udg_InCombat) then
       call GroupAddUnit(udg_InCombat,d)
       set udg_InCombatCount =udg_InCombatCount+1
    endif
    if not IsUnitInGroup(a,udg_InCombat) then
       call GroupAddUnit(udg_InCombat,d)
       set udg_InCombatCount =udg_InCombatCount+1
    endif
    call SaveInteger(udg_RPS,GetHandleId(d),2,0)
    call SaveInteger(udg_RPS,GetHandleId(a),2,0)
endfunction

//===========================================================================
function InitTrig_System takes nothing returns nothing
    set gg_trg_System = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_System, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddAction( gg_trg_System, function Trig_System_Actions )
    
    set udg_RPS_Per = CreateTrigger(  )
    call TriggerRegisterTimerEvent(udg_RPS_Per,.5, true)
    call TriggerAddCondition(udg_RPS_Per,Condition(function Trig_System_Perodic))
endfunction

JASS:
function RPS_LeaveLarge takes nothing returns boolean
   local region r       = GetTriggeringRegion()
   local integer hand   = GetHandleId(r)
   local integer int    = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
   local integer i      = LoadInteger(udg_RPS,hand,int)-1

   if i < 0 then
      set i =0
   endif

   call SaveInteger(udg_RPS,hand,int,i)
   
   set r = null
   return false
endfunction

function RPS_EnterLarge takes nothing returns boolean
   local region r       = GetTriggeringRegion()
   local integer hand   = GetHandleId(r)
   local integer int    = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
   call SaveInteger(udg_RPS,hand,int,LoadInteger(udg_RPS,hand,int)+1)
   set r = null
   return false
endfunction

function RPS_EnterSmall takes nothing returns boolean
   call SaveInteger(udg_RPS,GetHandleId(GetTriggerUnit()),0,LoadInteger(udg_RPS,GetHandleId(GetTriggeringRegion()),0))
   return false
endfunction

function Trig_RPS_Actions takes nothing returns boolean
   local unit u = GetTriggerUnit()
   if not IsUnitInGroup(u,udg_InCombat) then
      call GroupAddUnit(udg_InCombat,u)
      set udg_InCombatCount = udg_InCombatCount+1
   endif
   return false
endfunction

//===========================================================================
function InitTrig_RPS takes nothing returns nothing
    local rect tr         =  GetPlayableMapRect()
    local rect lr         = Rect(-udg_CellSize/2*3,-udg_CellSize/2*3,udg_CellSize/2*3,udg_CellSize/2*3)
    local region sr
    local region br
    local trigger E          =  CreateTrigger()
    local trigger L          =  CreateTrigger()
    local trigger EnterSmall =  CreateTrigger()

    local real h          =  GetRectMinY(tr)-300
    local real minx       =  GetRectMinX(tr)-300
    local integer row     =  R2I((300+GetRectMaxY(tr) - h)/udg_CellSize)+1
    local integer col     =  R2I((GetRectMaxX(tr)+300 - minx)/udg_CellSize)+1
    local integer i1      =  0
    local integer i2      =  0
    local real step       =  udg_CellSize

    local real w          =  minx

    set udg_RPS           =  InitHashtable()

    set udg_AntiAttack    = 'A000'

    call SetRect(tr, -udg_CellSize/2,-udg_CellSize/2,udg_CellSize/2,udg_CellSize/2)

    loop
      set i1  = i1 + 1
        
        loop
          set i2 = i2 +1
          
          call MoveRectTo(lr,w,h)
          set br = CreateRegion()
          call RegionAddRect(br,lr)
          call TriggerRegisterEnterRegion(E,br,null)
          call TriggerRegisterLeaveRegion(L,br,null)  



          call MoveRectTo(tr,w,h)
          set sr = CreateRegion()
          call RegionAddRect(sr,tr)
          call TriggerRegisterEnterRegion(EnterSmall,sr,null)

          call SaveInteger(udg_RPS,GetHandleId(sr),0,GetHandleId(br)) 

          //call CreateUnit(Player(0),'hfoo',w,h,0)           
          set w = w+step
          exitwhen i2 == col
        endloop
        set h = h+step
        set i2 = 0
        set w = minx
      exitwhen i1 == row      
    endloop

    call TriggerAddCondition(E,Condition(function RPS_EnterLarge))
    call TriggerAddCondition(L,Condition(function RPS_LeaveLarge))
    
    call TriggerAddCondition(EnterSmall,Condition(function RPS_EnterSmall))
 
    call RemoveRect(lr)
    call RemoveRect(tr)

    set br     = null
    set sr     = null
    set tr     = null
    set L      = null
    set lr     = GetWorldBounds()
    set sr     = CreateRegion()
    call RegionAddRect(sr,lr)   

    set gg_trg_RPS = CreateTrigger(  )
    call TriggerRegisterEnterRegion(gg_trg_RPS,sr,null)
    call TriggerAddCondition( gg_trg_RPS, Condition(function Trig_RPS_Actions ))

    call RemoveRect(lr)
    set lr     = null
    set sr     = null
endfunction
Problems that i have noted

Problem1 when the number of the units exceeds 300, it skips some of them(i think)
Problem 2, my unit group looping could probably be improved
Problem 3, my routing system stinketh.

I could use help fixing all bugs, etc.
please note saying use vJass, etc... is not help(ful)
 

Attachments

  • MoraleSystem 0.0.0.1Beta.w3x
    23.8 KB · Views: 46
Level 7
Joined
Apr 1, 2010
Messages
289
yeah i completely agree with you that WC3's game engine isn't the best. How many can your comp support without the system running?

also i just noticed something on this it doesn't quite make 600, it starts having problems after +/-400 units (it starts ignoring later units)
hmm, i think I am going to change the unit group to a Unit Array see if that clears up some of the bugs.

Edit:updated
JASS:
// Allocate

function Mrl_allocate takes nothing returns integer
    // allocate it
    local integer this
    if udg_Mrl_instanceRecycle == 0 then
        set udg_Mrl_instanceCount = udg_Mrl_instanceCount + 1
        set this = udg_Mrl_instanceCount
    else
        set this = udg_Mrl_instanceRecycle
        set udg_Mrl_instanceRecycle = udg_Mrl_recycleNext[this]
    endif
    // add it to the list
    set udg_Mrl_next[this] = 0
    set udg_Mrl_prev[this] = udg_Mrl_prev[0]
    set udg_Mrl_next[udg_Mrl_prev[0]] = this
    set udg_Mrl_prev[0] = this
    // return the new instance
    return this
endfunction

// deallocate:
function Mrl_deallocate takes integer this returns nothing
    // deallocate it
    if this == 0 then
    else
       set udg_Mrl_recycleNext[this] = udg_Mrl_instanceRecycle
       set udg_Mrl_instanceRecycle = this
       // remove it from the list
       set udg_Mrl_next[udg_Mrl_prev[this]] = udg_Mrl_next[this]
       set udg_Mrl_prev[udg_Mrl_next[this]] = udg_Mrl_prev[this]
       set udg_Mrl_U[this] = null
    endif
endfunction














//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Region Positioning system                                                      +
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
function RPS_LeaveLarge takes nothing returns boolean
   local region r       = GetTriggeringRegion()
   local integer hand   = GetHandleId(r)
   local integer int    = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
   local integer i      = LoadInteger(udg_RPS,hand,int)-1

   if i < 0 then
      set i =0
   endif

   call SaveInteger(udg_RPS,hand,int,i)
   
   set r = null
   return false
endfunction

function RPS_EnterLarge takes nothing returns boolean
   local region r       = GetTriggeringRegion()
   local integer hand   = GetHandleId(r)
   local integer int    = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
   call SaveInteger(udg_RPS,hand,int,LoadInteger(udg_RPS,hand,int)+1)
   set r = null
   return false
endfunction

function RPS_EnterSmall takes nothing returns boolean
   call SaveInteger(udg_RPS,GetHandleId(GetTriggerUnit()),0,LoadInteger(udg_RPS,GetHandleId(GetTriggeringRegion()),0))
   return false
endfunction

function Trig_RPS_Actions takes nothing returns boolean
   local unit u = GetTriggerUnit()
   if not IsUnitInGroup(u,udg_InCombat) then
      call GroupAddUnit(udg_InCombat,u)
      set udg_Mrl_U[Mrl_allocate()]=u
   endif
   set u = null
   return false
endfunction

//===========================================================================
function InitTrig_RPS takes nothing returns nothing
    local rect tr         =  GetPlayableMapRect()
    local rect lr         = Rect(-udg_CellSize/2*3,-udg_CellSize/2*3,udg_CellSize/2*3,udg_CellSize/2*3)
    local region sr
    local region br
    local trigger E          =  CreateTrigger()
    local trigger L          =  CreateTrigger()
    local trigger EnterSmall =  CreateTrigger()
    local trigger t          = CreateTrigger()


    local real h          =  GetRectMinY(tr)-300
    local real minx       =  GetRectMinX(tr)-300
    local integer row     =  R2I((300+GetRectMaxY(tr) - h)/udg_CellSize)+1
    local integer col     =  R2I((GetRectMaxX(tr)+300 - minx)/udg_CellSize)+1
    local integer i1      =  0
    local integer i2      =  0
    local real step       =  udg_CellSize

    local real w          =  minx

    set udg_RPS           =  InitHashtable()

    set udg_AntiAttack    = 'A000'

    call SetRect(tr, -udg_CellSize/2,-udg_CellSize/2,udg_CellSize/2,udg_CellSize/2)

    loop
      set i1  = i1 + 1
        
        loop
          set i2 = i2 +1
          
          call MoveRectTo(lr,w,h)
          set br = CreateRegion()
          call RegionAddRect(br,lr)
          call TriggerRegisterEnterRegion(E,br,null)
          call TriggerRegisterLeaveRegion(L,br,null)  



          call MoveRectTo(tr,w,h)
          set sr = CreateRegion()
          call RegionAddRect(sr,tr)
          call TriggerRegisterEnterRegion(EnterSmall,sr,null)

          call SaveInteger(udg_RPS,GetHandleId(sr),0,GetHandleId(br)) 

          //call CreateUnit(Player(0),'hfoo',w,h,0)           
          set w = w+step
          exitwhen i2 == col
        endloop
        set h = h+step
        set i2 = 0
        set w = minx
      exitwhen i1 == row      
    endloop

    call TriggerAddCondition(E,Condition(function RPS_EnterLarge))
    call TriggerAddCondition(L,Condition(function RPS_LeaveLarge))
    
    call TriggerAddCondition(EnterSmall,Condition(function RPS_EnterSmall))
 
    call RemoveRect(lr)
    call RemoveRect(tr)

    set br     = null
    set sr     = null
    set tr     = null
    set L      = null
    set lr     = GetWorldBounds()
    set sr     = CreateRegion()
    call RegionAddRect(sr,lr)   

    call TriggerRegisterEnterRegion(t,sr,null)
    call TriggerAddCondition( t, Condition(function Trig_RPS_Actions ))

    call RemoveRect(lr)
    set lr     = null
    set sr     = null
endfunction
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\\
//                     End of region Positioning service                           \\
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\\









//
//
//
//


function Trig_System_Perodic takes nothing returns boolean
    local unit u

    local integer UnitH
    local integer this = udg_Mrl_next[0]

    local real addition    
    local real r

    //local integer t
    local integer sign = 1
    local integer id 

    local real x
    local real y
    local real x1
    local real y1
    local real a

    local real morale
    
    
    loop
       
       set u =udg_Mrl_U[this]
       exitwhen this == 0

       

       set UnitH =GetHandleId(u)
       
       if not IsUnitType(u, UNIT_TYPE_DEAD) then// checking to see if the unit is dead


          set morale = LoadReal(udg_RPS,UnitH,1)
 
          set udg_RegionH = LoadInteger(udg_RPS,UnitH,0)// this is determine which region to load the values from
          set udg_Player = GetOwningPlayer(u)//the owning player
          set udg_Friend = 0
          set udg_Enemy  = 0
             
          set id =0
          loop
           
             if udg_Player == Player(id) or IsPlayerAlly(udg_Player,Player(id)) then
                set udg_Friend = udg_Friend+LoadInteger(udg_RPS,udg_RegionH,id)
             else
                set udg_Enemy = udg_Enemy+LoadInteger(udg_RPS,udg_RegionH,id)
             endif
                
             set id = id+1
             exitwhen id == 15
          endloop        
             

          set r = I2R(udg_Friend-udg_Enemy )



          if 0 > r then
             set sign = -1
             set r = -r
          else 
            set sign = 1
          endif
                 
          set addition = (r/(r+5))*10
          set addition = (addition*sign)+morale
             
             
          //call KillUnit(u)         


          if 100 < addition then
            set addition = 100
          elseif -200 > addition then
            set addition = -200
          endif


          if IsUnitSelected(u,Player(0)) then
            call CreateTextTagUnitBJ( I2S(R2I(addition)),u , 35, 10, 100, 100, 100, 0 )
            call SetTextTagPermanentBJ( GetLastCreatedTextTag(), false )// note yes, i know you can use natives instead, this is just for the test!!
            call SetTextTagLifespanBJ( GetLastCreatedTextTag(), 0.50 )   
          endif
       
          if addition < -100 and not IsUnitInGroup(u,udg_Running) then//checking morale of unit
            call SaveReal(udg_RPS,UnitH,3,GetUnitX(u))
            call SaveReal(udg_RPS,UnitH,4,GetUnitY(u))
            call GroupAddUnit(udg_Running,u)//adding unit to flee group
            call UnitAddAbility(u,'A000')// preventing unit attacks
            call UnitAddAbility(u,'A001')
            
          elseif IsUnitInGroup(u,udg_Running) then 
              if addition > -50 then
                 call GroupRemoveUnit(udg_Running,u)
                 call UnitRemoveAbility(u,'A000')
                 call UnitRemoveAbility(u,'A001')
                 //call DisplayTextToPlayer(Player(0),0,0,"removing ability")
              else
                 set x = LoadReal(udg_RPS,UnitH,3)
                 set y = LoadReal(udg_RPS,UnitH,4)
                 set x1 = GetUnitX(u)
                 set y1 = GetUnitY(u)
                 set a = Atan2(y1-y,x1-x)
                 set x = Cos(a)*500
                 set y = Sin(a)*500
                 call IssuePointOrder(u,"move",x1+x,y1+y)
              endif
                 
          endif


          //call SaveInteger(udg_RPS,UnitH,2,t)// saving the time its been in combat
          call SaveReal(udg_RPS,UnitH,1,addition)// saving its "morale"
             
       else

          call FlushChildHashtable(udg_RPS,UnitH) // clearing the hashtable
          call GroupRemoveUnit(udg_InCombat,u)    // removing unit
          call Mrl_deallocate(this)
       endif  
       
       set this = udg_Mrl_next[this]
    endloop

    set u = null
    return false
endfunction

function Trig_System_Actions takes nothing returns nothing
    local unit d = GetTriggerUnit()
    local unit a = GetAttacker()
    if not IsUnitInGroup(d,udg_InCombat) then
       call GroupAddUnit(udg_InCombat,d)
       set udg_InCombatCount =udg_InCombatCount+1
    endif
    if not IsUnitInGroup(a,udg_InCombat) then
       call GroupAddUnit(udg_InCombat,d)
       set udg_InCombatCount =udg_InCombatCount+1
    endif
    call SaveInteger(udg_RPS,GetHandleId(d),2,0)
    call SaveInteger(udg_RPS,GetHandleId(a),2,0)
endfunction

//===========================================================================
function InitTrig_System takes nothing returns nothing
    set gg_trg_System = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_System, EVENT_PLAYER_UNIT_ATTACKED )
    call TriggerAddAction( gg_trg_System, function Trig_System_Actions )
    
    set udg_RPS_Per = CreateTrigger(  )
    call TriggerRegisterTimerEvent(udg_RPS_Per,.5, true)
    call TriggerAddCondition(udg_RPS_Per,Condition(function Trig_System_Perodic))
    call InitTrig_RPS()
endfunction
switched to indexing, it works perfectly for 300 units, but
:wconfused: it ignores all units after that can anyone help me fix this problem?
 

Attachments

  • MoraleSystem 0.0.0.1BetaA.w3x
    23.4 KB · Views: 33
Last edited:
Level 7
Joined
Apr 1, 2010
Messages
289
could be that wc3 skips code when it reaches it's operation limit?

yeah, i was wondering if it is something like that, maybe i should only have it loop through 200 units at a time :ogre_frown: which i don't wan't to have too do.

You can't support 600+ with something like a linked list or an indexed array. You need something really fast. Even a binary search tree can't help you here (I'm talking about speed, not application)
well i am not doing a linked list(other then the one for looping through the unit index's). what i am doing is loading 15 integer values from a hashtable per unit, plus a real, not doing any counting using enum group, is unit inrange etc... all of the counting is done when a unit enters/leaves region which are created at map init in the current setup used by my test map it creates regions that are 600 by 600, it also creates a larger region 1800 by 1800 on top of the smaller region which contains a count, the smaller region is pointer to the larger one, telling the unit where it is(so what region to get the count from.


Besides there isn't any lag(well other then from having that many units on the map at the same time) to have it be that problem, it just doesn't loop through the units after the ~310 mark(will work on getting a more accurate number).
 
Level 13
Joined
Sep 13, 2010
Messages
550
Here is my template. Pretty unfinished, just a bone. Fast, cause 53000 > loop done in one second while it is ~60 FPS and 10-15 % Cpu used( 4 threaded processor ). Tested at 730 units. Use if you want to, and continue.
JASS:
library Test initializer Beta

    globals
        constant integer UNIT_REFRESH_TIMEOUT = 10
        real Current_Speed
        constant timer UnitTimer = CreateTimer( )
        integer Current = 0
        integer Current_ID = 0
        unit array UArray
        real array ED
    endglobals
    
    function Loop takes nothing returns nothing
        local integer i = 0
        local unit u
        local unit u2
        local real dx
        local real dy
        set Current_ID = Current_ID + 1
        if Current_ID > Current then
            set Current_ID = 1
        endif
        set u = Current_ID:UArray
        loop
            exitwhen i == Current
            set i = i + 1
            if Current_ID != i then
                set u2 = i:UArray
                set dx = GetUnitX( u ) - GetUnitX( u2 )
                set dy = GetUnitY( u ) - GetUnitY( u2 )
                /* Here needs formula */set i:ED = i:ED + 100 / SquareRoot(dx * dx + dy * dy)
            endif
        endloop
        call SetUnitState( u , UNIT_STATE_LIFE , GetUnitState( u , UNIT_STATE_LIFE ) - Current_ID:ED )
        set Current_ID:ED = 0.0
        call TimerStart( UnitTimer , Current_Speed , false , null )
        set u = null
        set u2 = null
    endfunction
    
    function AutoAdd takes nothing returns nothing
        set Current = Current + 1
        set Current:UArray = GetEnumUnit( )
        set Current:ED = 0.0
        set Current_Speed = I2R( UNIT_REFRESH_TIMEOUT ) / I2R( Current )
    endfunction
    
    function AutoClear takes nothing returns nothing
        //--
    endfunction
    
    function InitUnits takes nothing returns nothing
        set Current = Current + 1
        set Current:UArray = GetEnumUnit( )
        set Current:ED = 0.0
    endfunction
    
    function Beta takes nothing returns nothing
        local trigger T = CreateTrigger( )
        local trigger T2 = CreateTrigger( )
        local trigger T3 = CreateTrigger( )
        local region r = CreateRegion( )
        local group g = CreateGroup( )
        call RegionAddRect( r , GetWorldBounds( ) )
        call TriggerRegisterEnterRegion( T , r , null )
        //call TriggerRegisterLeaveRegion( T2 , r , null )
        call TriggerRegisterTimerExpireEvent( T3 , UnitTimer )
        call TriggerAddAction( T , function AutoAdd )
        call TriggerAddAction( T2 , function AutoClear )
        call TimerStart( UnitTimer , 0.0 , false , null )
        call TriggerAddAction( T3 , function Loop )
        call GroupEnumUnitsInRect( g , GetWorldBounds( ) , null )
        call ForGroup( g , function InitUnits )
        set Current_Speed = I2R( UNIT_REFRESH_TIMEOUT ) / I2R( Current )
        call DestroyGroup( g )
        call RemoveRegion( r )
        set g = null
        set r = null
        set T = null
        set T2 = null
        set T3 = null
    endfunction

endlibrary

Ofc, results can be different on other computer performance.
 
Level 7
Joined
Apr 1, 2010
Messages
289
Here is my template. Pretty unfinished, just a bone. Fast, cause 53000 > loop done in one second while it is ~60 FPS and 10-15 % Cpu used( 4 threaded processor ). Tested at 730 units. Use if you want to, and continue.
JASS:
library Test initializer Beta

    globals
        constant integer UNIT_REFRESH_TIMEOUT = 10
        real Current_Speed
        constant timer UnitTimer = CreateTimer( )
        integer Current = 0
        integer Current_ID = 0
        unit array UArray
        real array ED
    endglobals
    
    function Loop takes nothing returns nothing
        local integer i = 0
        local unit u
        local unit u2
        local real dx
        local real dy
        set Current_ID = Current_ID + 1
        if Current_ID > Current then
            set Current_ID = 1
        endif
        set u = Current_ID:UArray
        loop
            exitwhen i == Current
            set i = i + 1
            if Current_ID != i then
                set u2 = i:UArray
                set dx = GetUnitX( u ) - GetUnitX( u2 )
                set dy = GetUnitY( u ) - GetUnitY( u2 )
                /* Here needs formula */set i:ED = i:ED + 100 / SquareRoot(dx * dx + dy * dy)
            endif
        endloop
        call SetUnitState( u , UNIT_STATE_LIFE , GetUnitState( u , UNIT_STATE_LIFE ) - Current_ID:ED )
        set Current_ID:ED = 0.0
        call TimerStart( UnitTimer , Current_Speed , false , null )
        set u = null
        set u2 = null
    endfunction
    
    function AutoAdd takes nothing returns nothing
        set Current = Current + 1
        set Current:UArray = GetEnumUnit( )
        set Current:ED = 0.0
        set Current_Speed = I2R( UNIT_REFRESH_TIMEOUT ) / I2R( Current )
    endfunction
    
    function AutoClear takes nothing returns nothing
        //--
    endfunction
    
    function InitUnits takes nothing returns nothing
        set Current = Current + 1
        set Current:UArray = GetEnumUnit( )
        set Current:ED = 0.0
    endfunction
    
    function Beta takes nothing returns nothing
        local trigger T = CreateTrigger( )
        local trigger T2 = CreateTrigger( )
        local trigger T3 = CreateTrigger( )
        local region r = CreateRegion( )
        local group g = CreateGroup( )
        call RegionAddRect( r , GetWorldBounds( ) )
        call TriggerRegisterEnterRegion( T , r , null )
        //call TriggerRegisterLeaveRegion( T2 , r , null )
        call TriggerRegisterTimerExpireEvent( T3 , UnitTimer )
        call TriggerAddAction( T , function AutoAdd )
        call TriggerAddAction( T2 , function AutoClear )
        call TimerStart( UnitTimer , 0.0 , false , null )
        call TriggerAddAction( T3 , function Loop )
        call GroupEnumUnitsInRect( g , GetWorldBounds( ) , null )
        call ForGroup( g , function InitUnits )
        set Current_Speed = I2R( UNIT_REFRESH_TIMEOUT ) / I2R( Current )
        call DestroyGroup( g )
        call RemoveRegion( r )
        set g = null
        set r = null
        set T = null
        set T2 = null
        set T3 = null
    endfunction

endlibrary

Ofc, results can be different on other computer performance.

first off
please note saying use vJass, etc... is not help(ful)

secondly, is this counting the units in range of the unit?(it doesn't look like it)
which is what a morale system needs too do in some way, manner or form.... and all code does is get the distance between one unit and all the other units that are beneath it(in the array).... Or at least thats what i see/read.Minor Edit: While that could be used to determine a count, it cannot do 300 units a second because that would mean 300!(ie, 3.06057512216*10614 also entitled a really big number)
My system only needs to loop 45200 times for all of the units yours needs too do 45000 so your system can do the first 300 in one second and to do a total of 720 it takes 4.89057 seconds double that and then it will take 19.5623 seconds this of course assuming you limited the number of loops it did too 53000 per second.
also the number of loops you gave is an average number is an average. As each unit will take one more loop then the previous one did.

thirdly, where is the duration of the timer set?

So even though it is a good idea, it will get bogged down way too fast, my system(if it didn't drop units) would be able to do 18000 units in the number of loops it takes yours too do 720(although my one uses hashtables, isn't as accurate and won't be able to support more then 2000 units a second (supposing i managed to fix the dropping problem)

@Mageridon96 thanks for your comments, how would you use trigger evals?(as i have never used them before)
 
Last edited:
Level 31
Joined
Jul 10, 2007
Messages
6,306
Ok, so the reason I said that this was impossible was because to get the full implementation requires a Kd-Tree, which is a 2D Binary Tree, for nearest neighbor searches. Even without the Kd-Tree (using a simple linked list and calculating infinitesimally small morale values), it would require iterating over every single unit for every single unit. This means that every unit requires unit count - 1 iterations. If you do the loop in the best manner possible and you have 600 units, it's 600*(600+1)/2 iterations (summation from 1 to 600), which is 180300, and that is running 32x a second. The full featured thing is absolutely impossible to accomplish without lag =P.


Now, what you can do is split the 600 by 32 and run through the full for each unit, which turns into 11232 iterations per period, but that would still be unfeasible I believe =). Furthermore, wc3 typically runs its periods at like .1 intervals, or .3 or something, so once a second on the split into 32 isn't quite acceptable ^)^.


Also, keep in mind that using the region method requires massive amounts of memory for larger maps and isn't very accurate with 600x600 rects. 32x32 would be much better, but again would require enormous amounts of memory. Furthermore, the region approach would cause major FPS issues as it would fire off masses of triggers while all 600 units are moving, making the timer approach faster.


Now, if someone manages to prove me wrong and makes a morale system that is highly accurate with all features supported that does not have a FPS drop with all 600 units moving around the map, I will gladly pay the $200 as a reward =P.
 
Level 13
Joined
Sep 13, 2010
Messages
550

VJass is Jass -> Jass is the Warcraft coding language, it is the pure coding language -> Jass can be faster than vJass...

With the 53000 I meant: every unit gots looped in every 10 seconds. I tested with 730 units so 73 units looping. In the loop it runs every other units to make effect on them, using the distance between them, not used unit groups to get the close units. So 73*729 ~ 53000.

The time set in the initialization and when a new unit enters map.
 
Status
Not open for further replies.
Top