| 11-18-2008, 09:48 AM | #1 |
Hey guys, I've been working on a real-time aggro system since I haven't really seen one around. Thought I'd toss it up here first before submitting it to see what you guys thought of it, and if there's anything you think needs to be changed! EDIT: Made some new functions to get information easier. Also added a RemoveAggroUnit() command to remove a unit from the system. EDIT2: Made the system auto auto-update aggro internally, fixed some AI issues too. JASS:library UAS initializer SystemUpdate //================================================================================================================ // UAS - Unit Aggro System 1.0 // Created by Dustin "TEC_Ghost" Hendrickson // // 1.) WHAT DOES IT DO? // This is a system designed for realtime aggro management, giving your computer players a // system in which they target units. // // 2.) WHAT DOES IT REQUIRE? // vJass // PUI // A basic understanding of jass. // // 3.) HOW DO I USE IT? // Just copy and paste the library into a custom text trigger. // The system automatically updates aggro and sorting. // All you have to do is setup the unit to put it in the system. // // There are also a few functions you'll need to use... // // SetupAggro(Unit) // - You'll need to run this for every unit you want in the system. // // RemoveAggroUnit(Unit) // - Removes the unit from the system. // // ApplyAggro(UnitA,UnitB,Ammount,Boolean) // - This function applys aggro to UnitA from UnitB, the Ammount is how much aggro to apply, // how much aggro to apply, True if you want it to apply to non computers, False if you want // to apply to only computers. // // RemoveAggro(UnitA,UnitB,Ammount,Boolean) // - Same as the ApplyAggro() function, but removes instead of adds. // // ClearAggro(UnitA,UnitB) // - Does the same as RecycleAggro() but is for manual purposes incase you want to remove all // of a units aggro from a certain other unit. Clears UnitB's aggro from UnitA. // // //--------------------------------------------------------------------------------------- // Some other variables that can be used for displaying information are as follows... //--------------------------------------------------------------------------------------- // // GetAggroSlotUnit(Unit,Integer)returns Unit // - The array for the sorted aggro list "integer" 1 would be the highest aggro, 2 would be lower // 3 would be lower yet. "Unit" is the the unit you're pulling the array for. Returns // a unit. // // GetAggroSlotAmmount(Unit,Integer)returns Integer // - Same as the above, but returns the aggro ammount for the particular slot. // // TotalUnits // - Returns an integer for the total number of units in the system. // // // //================================================================================================================ // SCRIPT IS BELOW - DO NOT MODIFY ANY OF THIS UNLESS YOU KNOW WHAT YOU'RE DOING! //================================================================================================================ globals private constant real INTERVAL = .30 // Interval for the system to update Recyciling and aggro sorting. UnitAggroArray array UnitAggro // Struct array for the system. private integer TotalUnits = 0 // Keeps track of the max units in the system for updates. private trigger UpdateCycle // SystemUpdate trigger. endglobals struct UnitAggroArray unit Unit // The unit. unit Target // The current target. unit array unit_AggroTable[150] // Unit Refrence. integer array ammount_AggroTable[150] // Aggro Ammount. unit array sortedunits_AggroTable[150] // The array for sorted units. integer array sortedaggroammount_AggroTable[150] // The array for aggro totals of sorted slots. group group_AggroTable // Group of all units aggroed. boolean FlaggedForRemoval // Boolean set to remove unit from system. endstruct //============================================ //Setup Struct for unit. ---> SetupAggro(Unit) //============================================ function SetupAggro takes unit U returns nothing local integer Index = GetUnitIndex(U) set UnitAggro[Index] = UnitAggroArray.create() set UnitAggro[Index].Unit = U set UnitAggro[Index].Target = null set UnitAggro[Index].group_AggroTable = CreateGroup() set TotalUnits = TotalUnits + 1 endfunction //================================================================================================= //Gets the unit in a certain slot from a units aggro table. ---> GetAggroSlotUnit(Unit,Integer)Unit //================================================================================================= function GetAggroSlotUnit takes unit U, integer I returns unit local integer Index = GetUnitUserData(U) return UnitAggro[Index].sortedunits_AggroTable[i] endfunction //==================================================================================================================== //Gets the ammount of aggro in a certain slot from a unit's aggro table. ---> GetAggroSlotAmmount(Unit,Integer)Integer //==================================================================================================================== function GetAggroSlotAmmount takes unit U, integer I returns integer local integer Index = GetUnitUserData(U) return UnitAggro[Index].sortedaggroammount_AggroTable[i] endfunction //================================================================================================== //Checks the precise slot of UnitB in UnitA's aggro table. ---> GetUnitAggroSlot(UnitA,UnitB)Integer //================================================================================================== function GetUnitAggroSlot takes unit Ua, unit Ub returns integer local integer Index = GetUnitUserData(Ua) local integer l = 1 local integer Total = CountUnitsInGroup(UnitAggro[Index].group_AggroTable) loop exitwhen l > Total if UnitAggro[Index].sortedunits_AggroTable[l] == Ub then return l endif set l = l + 1 endloop return 0 endfunction //=================================================== //Clear UnitB aggro from UnitA. ---> ClearAggro(Unit) //=================================================== function ClearAggro takes unit Ua, unit Ub returns nothing local integer IndexA = GetUnitUserData(Ua) local integer IndexB = GetUnitUserData(Ub) local integer Index = 0 set Index = GetUnitAggroSlot(Ua,Ub) set UnitAggro[IndexA].unit_AggroTable[IndexB] = null set UnitAggro[IndexA].ammount_AggroTable[IndexB] = 0 set UnitAggro[IndexA].sortedunits_AggroTable[Index] = null set UnitAggro[IndexA].sortedaggroammount_AggroTable[Index] = 0 call GroupRemoveUnit(UnitAggro[IndexB].group_AggroTable,Ua) endfunction //================================================================================= //Checks if any units are dead and removes them from the group. ---> RecycleAggro() //================================================================================= function RecycleAggro takes nothing returns nothing local integer Index = 1 local integer TempIndex = 0 local integer Total = TotalUnits local group Group = CreateGroup() local unit Unit = null loop exitwhen Index > Total call GroupAddGroup(UnitAggro[Index].group_AggroTable,Group) loop set Unit = FirstOfGroup(Group) exitwhen Unit == null if GetUnitState(Unit, UNIT_STATE_LIFE) <= 0 or UnitAggro[GetUnitUserData(Unit)].FlaggedForRemoval == true then set TempIndex = GetUnitUserData(Unit) set UnitAggro[TempIndex].Unit = null set UnitAggro[TempIndex].Target = null call ClearAggro(UnitAggro[Index].Unit,Unit) call GroupRemoveUnit(UnitAggro[Index].group_AggroTable,Unit) set UnitAggro[TempIndex].FlaggedForRemoval = false endif call GroupRemoveUnit(Group,Unit) endloop set Index = Index + 1 endloop endfunction //============================================== //Remove unit from system. ---> RemoveUnit(Unit) //============================================== function RemoveAggroUnit takes unit U returns nothing local integer Index = GetUnitIndex(U) set UnitAggro[Index].FlaggedForRemoval = true call DestroyGroup(UnitAggro[Index].group_AggroTable) call RecycleAggro() endfunction //============================================================= //Sorts aggro into table based on ammount. ---> SortAggro(Unit) //============================================================= function SortAggro takes unit U returns nothing local integer Index = GetUnitUserData(U) local integer Rows = CountUnitsInGroup(UnitAggro[Index].group_AggroTable) local unit Tempunit = null local group Tempgroup = CreateGroup() local group Tempgroup2 = CreateGroup() local integer l = 1 call GroupAddGroup(UnitAggro[Index].group_AggroTable,Tempgroup) set l = 1 loop exitwhen l > Rows loop set Tempunit = FirstOfGroup(Tempgroup) exitwhen Tempunit == null if UnitAggro[Index].ammount_AggroTable[GetUnitUserData(Tempunit)] > UnitAggro[Index].sortedaggroammount_AggroTable[l] then set UnitAggro[Index].sortedunits_AggroTable[l] = Tempunit set UnitAggro[Index].sortedaggroammount_AggroTable[l] = UnitAggro[Index].ammount_AggroTable[GetUnitUserData(Tempunit)] endif call GroupAddUnit(Tempgroup2,Tempunit) call GroupRemoveUnit(Tempgroup,Tempunit) endloop call GroupRemoveUnit(Tempgroup2,UnitAggro[Index].sortedunits_AggroTable[l]) call GroupAddGroup(Tempgroup2,Tempgroup) call GroupClear(Tempgroup2) set l=l+1 endloop endfunction //============================================================================================================================= //Apply aggro to Unit A from Unit B. Allow user controlled players to be affected. ---> ApplyAggro(UnitA,UnitB,Ammount,Boolean) //============================================================================================================================= function ApplyAggro takes unit Ua, unit Ub, integer Ammount, boolean AllowUser returns nothing local integer IndexA = GetUnitIndex(Ua) local integer IndexB = GetUnitIndex(Ub) local boolean NewAdd = false if AllowUser == false then if GetPlayerController(GetOwningPlayer(Ua)) == MAP_CONTROL_USER then return endif endif if IsUnitInGroup(Ub,UnitAggro[IndexA].group_AggroTable) == true then set UnitAggro[IndexA].ammount_AggroTable[IndexB] = UnitAggro[IndexA].ammount_AggroTable[IndexB] + Ammount else call GroupAddUnit(UnitAggro[IndexA].group_AggroTable,Ub) set UnitAggro[IndexA].unit_AggroTable[IndexB] = Ub set UnitAggro[IndexA].ammount_AggroTable[IndexB] = UnitAggro[IndexA].ammount_AggroTable[IndexB] + Ammount endif endfunction //========================================================================= //Remove aggro on Unit A from Unit B. ---> RemoveAggro(UnitA,UnitB,Ammount,Boolean) //========================================================================= function RemoveAggro takes unit Ua, unit Ub, integer Ammount, boolean AllowUser returns nothing local integer IndexA = GetUnitIndex(Ua) local integer IndexB = GetUnitIndex(Ub) if IsUnitInGroup(Ub,UnitAggro[IndexA].group_AggroTable) == true then set UnitAggro[IndexA].ammount_AggroTable[IndexB] = UnitAggro[IndexA].ammount_AggroTable[IndexB] - Ammount else call GroupAddUnit(UnitAggro[IndexA].group_AggroTable,Ub) set UnitAggro[IndexA].unit_AggroTable[IndexB] = Ub set UnitAggro[IndexA].ammount_AggroTable[IndexB] = UnitAggro[IndexA].ammount_AggroTable[IndexB] - Ammount endif endfunction //======================================================= //Updates the aggro table with target. ---> UpdateAggro() //======================================================= function UpdateAggro takes nothing returns nothing local integer Total = TotalUnits local integer Index = 1 loop exitwhen Index > Total if Index != 0 then call SortAggro(UnitAggro[Index].Unit) set UnitAggro[Index].Target = UnitAggro[Index].sortedunits_AggroTable[1] if IsUnitInRange(UnitAggro[Index].Target,UnitAggro[Index].Unit,500) == true then call IssueTargetOrder(UnitAggro[Index].Unit,"attack",UnitAggro[Index].Target) else call IssueTargetOrder(UnitAggro[Index].Unit,"move",UnitAggro[Index].Target) endif endif set Index = Index + 1 endloop endfunction //============== //System Update. //============== function UpdateCycle_Actions takes nothing returns nothing call UpdateAggro() call RecycleAggro() endfunction function SystemUpdate takes nothing returns nothing set UpdateCycle = CreateTrigger( ) call TriggerRegisterTimerEventPeriodic( UpdateCycle, INTERVAL) call TriggerAddAction( UpdateCycle, function UpdateCycle_Actions ) endfunction endlibrary |
| 11-18-2008, 10:13 AM | #2 | |
Awesome, I was meaning to get round to writing one myself. You should make most of those global variables private. And seeing as we have to use SetupUnit(unit), you should implement RemoveUnit(unit). Wouldn't it be sensible to check if targets change when you run Apply/Remove/ClearAggro? For instance, I can see myself using it like this: Quote:
|
| 11-18-2008, 07:37 PM | #3 | |
Quote:
Ya im updating it as we speak, I'll upload the new version in a bit. But ya I did it this way as to not force people to update date it when I wanted it to, so there's some more freedom, you're perfectly able to add the update function to the apply aggro function if you want :) |
