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

Is this recursion prevent well done?

Status
Not open for further replies.
Level 24
Joined
Jun 26, 2020
Messages
1,853
Some of you maybe know I did a Bouty System, but something I didn't notice until very recently is I didn't prevent the recursion, exm:
  • Get money
    • Events
      • Game - BountyDeadEvent becomes Equal to 1.00
    • Conditions
    • Actions
    • Make a unit kill another unit
The BountyDeadEvent fires if a unit kills a unit so add the action to a unit kill another unit will call this trigger again
If there are not conditions this yes or yes will cause a infinite loop (if there are infinite units because this will stop if the unit to kill is not alive)
I know this is something nobody shouldn't do if there are not conditions, but if there are, I made the system to you can edit the values and when it ends the values are cleared, but if in this case the recursion will cause the system is called again so the values are cleared before the first call starts to work
To solve that I did this simple thing
vJASS:
function system takes nothing returns nothing
    local type prevValue=udg_Value

    Fire the event

    call "The Actual System"

    set udg_Value=prevValue
endfunction
And if you wanna directly call "The Actual System" you can edit the values before and then call it like this:
  • Set Bounty = Your value
  • Set BountyUnitPos = Your unit
  • Set BountyPlayer = Your player
  • Player Group - Add BountyPlayer to BountyWhoSee
  • Trigger - Run BountyText (ignoring conditions)
But the BountyText runs the event BountyEvent so in a trigger like this:
  • Get money
    • Events
      • Game - BountyEvent becomes Equal to 1.00
    • Conditions
    • Actions
      • Set Bounty = Your value
      • Set BountyUnitPos = Your unit
      • Set BountyPlayer = Your player
      • Player Group - Add BountyPlayer to BountyWhoSee
      • Trigger - Run BountyText (ignoring conditions)
If there are not conditions this yes or yes will cause an infinite loop, if there are conditions and not an infinite loop, the values of the previous call (that the fires the BountyEvent) will overwrite the values of the call you are doing now (those that you are not editing) so to prevent that I added the BountyClear function, so the correct way to do that is
  • Get money
    • Events
      • Game - BountyEvent becomes Equal to 1.00
    • Conditions
      • There must be a condition
    • Actions
      • Trigger - Run BountyClear (ignoring conditions)
      • Set Bounty = Your value
      • Set BountyUnitPos = Your unit
      • Set BountyPlayer = Your player
      • Player Group - Add BountyPlayer to BountyWhoSee
      • Trigger - Run BountyText (ignoring conditions)
And to not double clear the values I added a boolean Bountie.Cleared[Bountie.Recursion] to check if the values weren't cleared before.

Since I notice this recently I'm note sure if what I did is well done, so can you tell me if is it?, here is the new system (the function that runs when a unit dies is called "UnitBounty" and the function that is the actual system is called "BountyText"):

vJASS:
/******************************************************************************************************/
/*************************************Bounty Controller by HerlySQR************************************/
/******************************************************************************************************/
//
//    https://www.hiveworkshop.com/threads/jass-lua-bounty-controller-gui-friendly.332114/
//
//    This library was made to have almost every control of the Bountie.s of the units
//    Important is have deactivated the Bountie.s (this system do that, but don't active them)
//    and you have to set the values of the Bountie.s manually, only requires JassHelper.
//! novjass
//////If you wanna set the default value of the bounty of the units, first use the event "BountyEvent becomes Equal to 2.00"
//    (If you wanna do it in the map initialization) and then you must use these functions:
          SetBountyBase("'ID of the unit'","Bounty: Base")
          SetBountyDice("'ID of the unit'","Bounty: Number of dice")
          SetBountySides("'ID of the unit'","Bounty: Sides per dice")
//    or to do it all in once use this function:
          BOUNTY("'ID of the unit'","Bounty: Base","Bounty: Number of dice","Bounty: Sides per dice")
//    to get a posible bounty from a unit use the function:
          GetBountyFromUnitType("'ID of the unit'")
//    to get the individual values of the bounty use these functions:
          GetBountyBase("'ID of the unit'")
          GetBountyDice("'ID of the unit'")
          GetBountySides("'ID of the unit'")
//   
//////Is also posible do it in GUI, doing this steps
        SetBountyBase:
              Set BountyUnitID = "Unit-Type of you unit"
              Set BountyBase = "Bounty: Base"
              Trigger - Run BountySetBase (Ignoring conditions)
          SetBountyDice:
              Set BountyUnitID = "Unit-Type of you unit"
              Set BountyDice = "Bounty: Number of dice"
              Trigger - Run BountySetDice (Ignoring conditions)
          SetBountySides:
              Set BountyUnitID = "Unit-Type of you unit"
              Set BountySides = "Bounty: Sides per dice"
              Trigger - Run BountySetBase (Ignoring conditions)
          BOUNTY:
              Set BountyUnitID = "Unit-Type of you unit"
              Set BountyBase = "Bounty: Base"
              Set BountyDice = "Bounty: Number of dice"
              Set BountySides = "Bounty: Sides per dice"
              Trigger - Run BountySet (Ignoring conditions)
//
//////The variables used are cleaned automatically, and to get the values do:
          GetBountyBase:
              Set BountyUnitID = "Unit-Type of you unit"
              Trigger - Run BountyGetBase (Ignoring conditions)
              The variable "BountyBase" has the value wanted.
          GetBountyDice:
              Set BountyUnitID = "Unit-Type of you unit"
              Trigger - Run BountyGetDice (Ignoring conditions)
              The variable "BountyDice" has the value wanted.
          GetBountySides:
              Set BountyUnitID = "Unit-Type of you unit"
              Trigger - Run BountyGetBase (Ignoring conditions)
              The variable "BountySides" has the value wanted.
          GetBountyFromUnitType:
              Set BountyUnitID = "Unit-Type of you unit"
              Trigger - Run BountyGet (Ignoring conditions)
              The variable "Bounty" has the value wanted.
//
//////To edit the values of a bounty when a unit dies you must have
//    a trigger with the event "BountyDeadEvent becomes Equal to 1.00", this event happens when
//    a unit dies and the function "BountyText" will be called (That is called it doesn't mean the text will be displayed
//    and the bounty will be given to the player, only those two will happen if all the rest of values are valid)
//    the variables that you can edit are:
          "Bounty": The quantity of gold or lumber that you will receive (it can be negative).
          "BountyTextTag": The texttag that will be displayed.
          "BountyPermanent": This allows erase it (care, if this value is true and you don't use the texttag later it can be an object leak)
          "BountyColor": The color of the text (if is not set, the color of the text will have the default values depending of the state).
          "BountySize": The size of the text.
          "BountyLifeSpan": The lifetime of the text (if "BountyPermanent" is true this value is useless).
          "BountyFadePoint": How many seconds the text will fade after the lifespan.
          "BountySpeed": The speed of the text.
          "BountyDirection": The direction to the texttag will move.
          "BountyHeight": How many distance the text will be from the floor.
          "BountyShow": To show the text or not.
          "BountyShowNothing": If the Bounty is 0 by default the text is not showed, if you set this to true, the text will be showed even if the bounty is 0.
          "BountyAllowFriendFire": By default the bounty only will happen if the dying unit is enemy of the killing unit, if you set this to true, the bounty will happen even if they weren't enemies.
          "BountyEffect": The effect that will be displayed (In the same place of the text)
          "BountyShowEffect": The effect will be displayed if this value is true.
          "BountyPlayer": The player how will receive the bounty.
          "BountyPlayerState": What type of bounty the player will receive (only "gold" and "lumber" are valid).
          "BountyUnitPos": The position of the text and the effect (If is a unit)
          "BountyLocPos": The position of the text and the effect (If is a location, this have more priority than BountyUnitPos, and is removed with the clear function to prevent object leak, of course only if "BountyNotClear" is not true, and for this reason don't set it to a variable that you gonna use later)
          "BountyPosX", "BountyPosY", "BountyPosZ": The coords of the texttag when is displayed (they are only to read them, and only accesible with the event "BountyEvent becomes Equal to 1.00").
          "BountyWhoSee": The players who can see the text.
          "BountyData": Is an integer that you can store (Since the process is practically instant there is no much point on storing a value, but you can use it to add an extra "condition").
/*    To reffering the killing unit use the variable */"BountyKillingUnit"/* and to the dying unit, */"BountyDyingUnit"/*
//    and when the bounty is given an (maybe) the text displayed you can use the event */"BountyEvent becomes Equal to 1.00"/*
//    You can't edit the values with this (except BountyNotClear), because it happens after the process ends, but you can get them.
//    If you wanna use the */function BountyText/* with a trigger with the*/"BountyEvent"/* (only with this) you have to clear manually the values (and maybe
//    to prevent recursion) using "Trigger - Run BountyClear (Ignoring conditions)" or in Jass just */call BountyClear()/*
//   
//    (Note: If you wanna change the variable */"BountyPlayer"/*, to show him the text you have to (maybe) remove the previous player
//    and add the new player to the player group */"BountyWhoSee"/*, but in Jass you can use the */function ChangeBountyPlayer(player newPlayer, boolean removePrevious, boolean addNew)/*.)
//
//////If you wanna have your own bounty with another event or function just set some of the variables previously seen
//    there are neccesary values like */"Bounty"/*, */"BountyPlayer"/*, */"BountyWhoSee"/* (You have to add manually the */BountyPlayer/* in this case),
//    */"BountyUnitPos or BountyLocPos"/*, because they not have default values different than nothing
//    and then add in GUI */"Trigger - Run BountyText (Ignoring conditions)"/* or in Jass */call BountyText()/*
//    But in Jass you can use the function */BountyCall(integer bounty, unit unitpos, player bountyPlayer, boolean addplayer, boolean permanent)/*.
//
//////If you wanna have access to the texttag use the variable */"BountyTextTag"/*, but you have to know how, you can only do it with the event */"BountyEvent"/*
//    if you use this when you use manually the */function BountyText/* better do */set Temp=BountyText()/* or */set Temp=BountyCall(...)/*.
//
//    And if you wanna keep the changes of the previous instance (included */"BountyTextTag"/*), set the variable */"BountyNotClear"/* to true, and you have to do it every instance
//    you do if you wanna still saving the changes because this value is returned to false, but carefully, because the next instance can have
//    unwanted changes.
//
//    Additionally it has the variable */LocalPlayer/* to not use */GetLocalPlayer()/* everytime, if you don't like it,
//    just uncoment the "private" before of it in the global section.
*/
//////If you wanna deactive the system do "Trigger - Turn off Bounty Controller <gen>"
//   
//////You can use the functions
        RegisterBountyDeadEvent(code func)
        RegisterBountyEvent(code func)
//    To replace
        set mytrigger=CreateTrigger()
        call TriggerRegisterVariableEvent(mytrigger,"udg_BountyDeadEvent",EQUAL,1.00)
        call TriggerAddAction(mytrigger,function Actions)
//    For
        call RegisterBountyDeadEvent(function Actions)
//    To only use a single trigger that use these custom events and make it more easy to code and to reffer to the principal trigger use:
        GetNativeBountyDeadEventTrigger()
        GetNativeBountyEventTrigger()

//! endnovjass
//=====================================================================================================


library BountyController initializer Init /*
    */requires /*
    */optional Table, /*https://www.hiveworkshop.com/threads/snippet-new-table.188084/
    */optional RegisterNativeEvent /*https://www.hiveworkshop.com/threads/snippet-registerevent-pack.250266/ */
   
    globals
        /*private*/ player LocalPlayer
        //This constants can be edited (obviously only valid values)
        private constant string DEF_COLOR_GOLD="ffcc00"
        private constant string DEF_COLOR_LUMBER="32cd32"
        private constant integer DEF_SIZE=10
        private constant real DEF_LIFE_SPAN=3.50
        private constant real DEF_SPEED=64
        private constant real DEF_DIRECTION=90
        private constant real DEF_FADE_POINT=2.50
        private constant string DEF_STATE="gold"
        private constant real DEF_HEIGHT=0
        private constant boolean DEF_SHOW=true
        private constant boolean DEF_SHOW_NOTHING=false
        private constant boolean DEF_ALLOW_FRIEND_FIRE=false
        private constant string DEF_EFFECT="UI\\Feedback\\GoldCredit\\GoldCredit.mdl"
        private constant boolean DEF_SHOW_EFFECT=true
        private constant boolean DEF_PERMANENT=false
        private constant integer LIMIT_RECURSION=16 //If a loop caused by recursion is doing in porpouse you can edit the tolerance of how many calls can do
    endglobals
   
    private struct Bountie extends array
        static force ForceEnum
        static integer Recursion=0
        static boolean array Cleared
        static boolean array ByKill
        static if LIBRARY_Table then
            static Table array s[2]
        else
            static hashtable s=InitHashtable()
        endif
        static if LIBRARY_RegisterNativeEvent then
            static integer UNIT_BOUNTY_DEAD_EVENT
            static integer UNIT_BOUNTY_EVENT
        else
            static trigger t1=CreateTrigger()
            static trigger t2=CreateTrigger()
        endif
    endstruct
   
    //The functions to set the bounty stats
   
    function SetBountyBase takes integer id, integer base returns nothing
        static if LIBRARY_Table then
            set Bountie.s[0].integer[id]=base
        else
            call SaveInteger(Bountie.s,0,id,base)
        endif
    endfunction
   
    function SetBountyDice takes integer id, integer dice returns nothing
        static if LIBRARY_Table then
            set Bountie.s[1].integer[id]=dice
        else
            call SaveInteger(Bountie.s,1,id,dice)
        endif
    endfunction
   
    function SetBountySides takes integer id, integer sides returns nothing
        static if LIBRARY_Table then
            set Bountie.s[2].integer[id]=sides
        else
            call SaveInteger(Bountie.s,2,id,sides)
        endif
    endfunction
   
    function BOUNTY takes integer id, integer base, integer dice, integer side returns nothing
        call SetBountyBase(id,base)
        call SetBountyDice(id,dice)
        call SetBountySides(id,side)
    endfunction
   
    //The functions to get the bounty stats (that you set before)
   
    function GetBountyBase takes integer id returns integer
        static if LIBRARY_Table then
            return Bountie.s[0].integer[id]
        else
            return LoadInteger(Bountie.s,0,id)
        endif
    endfunction
   
    function GetBountyDice takes integer id returns integer
        static if LIBRARY_Table then
            return Bountie.s[1].integer[id]
        else
            return LoadInteger(Bountie.s,1,id)
        endif
    endfunction
   
    function GetBountySides takes integer id returns integer
        static if LIBRARY_Table then
            return Bountie.s[2].integer[id]
        else
            return LoadInteger(Bountie.s,2,id)
        endif
    endfunction
   
    function GetBountyFromUnitType takes integer id returns integer
        return GetBountyBase(id)+GetRandomInt(0,GetBountyDice(id)*GetBountySides(id))
    endfunction
   
    //This function is runned at the map initialization, if you wanna use it to set your Bountie.s, you can do it
   
    private function SetData takes nothing returns nothing
        local integer i
       
        static if LIBRARY_Table then
            set Bountie.s[0]=Table.create()
            set Bountie.s[1]=Table.create()
            set Bountie.s[2]=Table.create()
        endif
       
        /*Peasant*/   call BOUNTY('hpea',35,6,3)
       
        set i=0
        loop
            exitwhen i>PLAYER_NEUTRAL_AGGRESSIVE
            call SetPlayerFlagBJ(PLAYER_STATE_GIVES_BOUNTY,false,Player(i))
            set i=i+1
        endloop
       
        set i=0
        loop
            exitwhen i>LIMIT_RECURSION
            set Bountie.Cleared[i]=false
            set Bountie.ByKill[i]=false
            set i=i+1
        endloop
    endfunction
   
    //To clear the data
    function BountyClear takes nothing returns nothing
        if not udg_BountyNotClear then
            set udg_BountyTextTag=null
            set udg_BountyColor=null
            set udg_BountySize=DEF_SIZE
            set udg_BountyLifeSpan=DEF_LIFE_SPAN
            set udg_BountyFadePoint=DEF_FADE_POINT
            set udg_BountySpeed=DEF_SPEED
            set udg_BountyDirection=DEF_DIRECTION
            set udg_BountyPlayerState=DEF_STATE
            set udg_BountyHeight=DEF_HEIGHT
            set udg_BountyShow=DEF_SHOW
            set udg_BountyShowNothing=DEF_SHOW_NOTHING
            set udg_BountyAllowFriendFire=DEF_ALLOW_FRIEND_FIRE
            set udg_BountyEffect=DEF_EFFECT
            set udg_BountyShowEffect=DEF_SHOW_EFFECT
            set udg_BountyPermanent=DEF_PERMANENT
            set udg_BountyPlayer=null
            set udg_BountyUnitPos=null
            set udg_BountyPosX=0.00
            set udg_BountyPosY=0.00
            set udg_Bounty=0
            set udg_BountyData=0
            call ForceClear(udg_BountyWhoSee)
            if udg_BountyLocPos!=null then
                call RemoveLocation(udg_BountyLocPos)
                set udg_BountyLocPos=null
            endif
            set udg_BountyKillingUnit=null
            set udg_BountyDyingUnit=null
        endif
        set Bountie.Cleared[Bountie.Recursion]=true
        set udg_BountyNotClear=false
    endfunction
   
    //This is to check the sign of the bounty
    private function Sign takes integer i returns string
        if i<0 then
            return ""
        endif
        return "+"
    endfunction
   
    //The function that runs the bounty and the texttag
    function BountyText takes nothing returns texttag
        local playerstate state
        local texttag tt
   
        set Bountie.Recursion=Bountie.Recursion+1
       
        if Bountie.Recursion>LIMIT_RECURSION then //If there is recursion that don't stop soon, the system stops automatically
            call BJDebugMsg("There is a recursion with the Bounty system, check if you are not creating a infinite loop.")
            call BountyClear()
            set Bountie.Cleared[Bountie.Recursion]=false
            set Bountie.Recursion=Bountie.Recursion-1
            return null
        endif
       
        if udg_BountyPlayerState=="gold" then
            set state=PLAYER_STATE_RESOURCE_GOLD
        elseif udg_BountyPlayerState=="lumber" then
            set state=PLAYER_STATE_RESOURCE_LUMBER
        else
            if not Bountie.ByKill[Bountie.Recursion] then
                call BountyClear()
            endif
            set Bountie.Cleared[Bountie.Recursion]=false
            set Bountie.Recursion=Bountie.Recursion-1
            return null //If the state is not valid, the process stop
        endif
       
        if udg_Bounty==0 and not udg_BountyShowNothing then
            set udg_BountyShow=false
            set udg_BountyShowEffect=false
        endif
       
        call AdjustPlayerStateSimpleBJ(udg_BountyPlayer,state,udg_Bounty)
       
        if udg_BountyColor==null then
            if udg_BountyPlayerState=="gold" then
                set udg_BountyColor=DEF_COLOR_GOLD
            elseif udg_BountyPlayerState=="lumber" then
                set udg_BountyColor=DEF_COLOR_LUMBER
            endif
        endif
       
        if udg_BountyLocPos!=null then
            set udg_BountyPosX=GetLocationX(udg_BountyLocPos)
            set udg_BountyPosY=GetLocationY(udg_BountyLocPos)
        elseif udg_BountyUnitPos!=null then
            set udg_BountyPosX=GetUnitX(udg_BountyUnitPos)
            set udg_BountyPosY=GetUnitY(udg_BountyUnitPos)
        else
            set udg_BountyShow=false
            set udg_BountyShowEffect=false //If there is no position to the text, the text and the effect won't show
        endif
       
        set udg_BountyTextTag=CreateTextTag()
        call SetTextTagPermanent(udg_BountyTextTag,udg_BountyPermanent)
        call SetTextTagText(udg_BountyTextTag,"|cff"+udg_BountyColor+Sign(udg_Bounty)+I2S(udg_Bounty)+"|r",TextTagSize2Height(udg_BountySize))
        call SetTextTagVisibility(udg_BountyTextTag,IsPlayerInForce(LocalPlayer,udg_BountyWhoSee) and udg_BountyShow)
        call SetTextTagPos(udg_BountyTextTag,udg_BountyPosX,udg_BountyPosY,udg_BountyHeight)
        call SetTextTagFadepoint(udg_BountyTextTag,udg_BountyFadePoint)
        call SetTextTagLifespan(udg_BountyTextTag,udg_BountyLifeSpan)
        call SetTextTagVelocityBJ(udg_BountyTextTag,udg_BountySpeed,udg_BountyDirection)
       
        if udg_BountyShowEffect then
            call DestroyEffect(AddSpecialEffect(udg_BountyEffect,udg_BountyPosX,udg_BountyPosY))
        endif
       
        set udg_BountyEvent=0.00
        set udg_BountyEvent=1.00
        set udg_BountyEvent=0.00
       
        set tt=udg_BountyTextTag
       
        if not Bountie.Cleared[Bountie.Recursion] and not Bountie.ByKill[Bountie.Recursion] then
            call BountyClear()
        endif
        set Bountie.Cleared[Bountie.Recursion]=false
        set Bountie.Recursion=Bountie.Recursion-1
       
        return tt
    endfunction

    private function ForceAddForce takes nothing returns nothing
        call ForceAddPlayer(Bountie.ForceEnum,GetEnumPlayer())
    endfunction

    private function CopyForce takes force princ returns force
        set Bountie.ForceEnum=CreateForce()
        call ForForce(princ,function ForceAddForce)
        return Bountie.ForceEnum
    endfunction
   
    private function UnitBounty takes nothing returns nothing
        //This is to prevent overwrite in case you add a function that kills a unit inside a trigger with the bountydead's event
        local string prevColor=udg_BountyColor
        local real prevSize=udg_BountySize
        local real prevLifeSpan=udg_BountyLifeSpan
        local real prevFadePoint=udg_BountyFadePoint
        local real prevSpeed=udg_BountySpeed
        local real prevDirection=udg_BountyDirection
        local string prevPlayerState=udg_BountyPlayerState
        local real prevHeight=udg_BountyHeight
        local boolean prevShow=udg_BountyShow
        local boolean prevShowNothing=udg_BountyShowNothing
        local boolean prevAllowFriendFire=udg_BountyAllowFriendFire
        local string prevEffect=udg_BountyEffect
        local boolean prevShowEffect=udg_BountyShowEffect
        local boolean prevPermanent=udg_BountyPermanent
        local player prevPlayer=udg_BountyPlayer
        local unit prevUnitPos=udg_BountyUnitPos
        local integer prevBounty=udg_Bounty
        local force prevForce=CopyForce(udg_BountyWhoSee)
        local location prevLocPos=udg_BountyLocPos
        local unit prevKillingUnit=udg_BountyKillingUnit
        local unit prevDyingUnit=udg_BountyDyingUnit
        local boolean prevNotClear=udg_BountyNotClear
        local integer prevData=udg_BountyData
       
        call BountyClear()
       
        set udg_BountyKillingUnit=GetKillingUnit()
        set udg_BountyDyingUnit=GetDyingUnit()
        set udg_Bounty=GetBountyFromUnitType(GetUnitTypeId(udg_BountyDyingUnit))
       
        set udg_BountyPlayer=GetOwningPlayer(udg_BountyKillingUnit)
        call ForceAddPlayer(udg_BountyWhoSee,udg_BountyPlayer)
        set udg_BountyUnitPos=udg_BountyDyingUnit
       
        set udg_BountyDeadEvent=0.00
        set udg_BountyDeadEvent=1.00
        set udg_BountyDeadEvent=0.00
       
        if IsUnitEnemy(udg_BountyDyingUnit,udg_BountyPlayer) or udg_BountyAllowFriendFire then
            set Bountie.ByKill[Bountie.Recursion+1]=true
            call BountyText()
            set Bountie.ByKill[Bountie.Recursion+1]=false
        endif
   
        set udg_BountyColor=prevColor
        set udg_BountySize=prevSize
        set udg_BountyLifeSpan=prevLifeSpan
        set udg_BountyFadePoint=prevFadePoint
        set udg_BountySpeed=prevSpeed
        set udg_BountyDirection=prevDirection
        set udg_BountyPlayerState=prevPlayerState
        set udg_BountyHeight=prevHeight
        set udg_BountyShow=prevShow
        set udg_BountyShowNothing=prevShowNothing
        set udg_BountyAllowFriendFire=prevAllowFriendFire
        set udg_BountyEffect=prevEffect
        set udg_BountyShowEffect=prevShowEffect
        set udg_BountyPermanent=prevPermanent
        set udg_BountyPlayer=prevPlayer
        set udg_BountyUnitPos=prevUnitPos
        set udg_Bounty=prevBounty
        call ForceClear(udg_BountyWhoSee)
        set Bountie.ForceEnum=udg_BountyWhoSee
        call ForForce(prevForce,function ForceAddForce)
        set udg_BountyLocPos=prevLocPos
        set udg_BountyKillingUnit=prevKillingUnit
        set udg_BountyDyingUnit=prevDyingUnit
        set udg_BountyNotClear=prevNotClear
        set udg_BountyData=prevData
   
        set prevPlayer=null
        set prevUnitPos=null
        set prevForce=null
        set prevLocPos=null
        set prevKillingUnit=null
        set prevDyingUnit=null
    endfunction
   
    private function UnitBountyCheck takes nothing returns boolean
        return GetKillingUnit()!=null //If there is not killing unit then the process stop
    endfunction
   
    //Functions to short the Jass process
    function BountyCall takes integer bounty, unit pos, player myplayer, boolean addplayer, boolean permanent returns texttag
        set udg_Bounty=bounty
        set udg_BountyUnitPos=pos
        set udg_BountyPlayer=myplayer
        if addplayer then
            call ForceAddPlayer(udg_BountyWhoSee,udg_BountyPlayer)
        endif
        set udg_BountyPermanent=permanent
        return BountyText()
    endfunction
   
    function ChangeBountyPlayer takes player newPlayer, boolean removePrevious, boolean addNew returns nothing
        if removePrevious then
            call ForceRemovePlayer(udg_BountyWhoSee,udg_BountyPlayer)
        endif
        set udg_BountyPlayer=newPlayer
        if addNew then
            call ForceAddPlayer(udg_BountyWhoSee,udg_BountyPlayer)
        endif
    endfunction
   
    function RegisterBountyDeadEvent takes code func returns nothing
        static if LIBRARY_RegisterNativeEvent then
            if RegisterNativeEventTrigger(0,Bountie.UNIT_BOUNTY_DEAD_EVENT) then
                call TriggerRegisterVariableEvent(GetIndexNativeEventTrigger(0,Bountie.UNIT_BOUNTY_DEAD_EVENT),"udg_BountyDeadEvent",EQUAL,1.00)
            endif
            call RegisterIndexNativeEvent(0,Bountie.UNIT_BOUNTY_DEAD_EVENT,func)
        else
            call TriggerAddCondition(Bountie.t1,Condition(func))
        endif
    endfunction
   
    function GetNativeBountyDeadEventTrigger takes nothing returns trigger
        static if LIBRARY_RegisterNativeEvent then
            return GetIndexNativeEventTrigger(0,Bountie.UNIT_BOUNTY_DEAD_EVENT)
        else
            return Bountie.t1
        endif
    endfunction
   
    function RegisterBountyEvent takes code func returns nothing
        static if LIBRARY_RegisterNativeEvent then
            if RegisterNativeEventTrigger(0,Bountie.UNIT_BOUNTY_EVENT) then
                call TriggerRegisterVariableEvent(GetIndexNativeEventTrigger(0,Bountie.UNIT_BOUNTY_EVENT),"udg_BountyEvent",EQUAL,1.00)
            endif
            call RegisterIndexNativeEvent(0,Bountie.UNIT_BOUNTY_EVENT,func)
        else
            call TriggerAddCondition(Bountie.t2,Condition(func))
        endif
    endfunction
   
    function GetNativeBountyEventTrigger takes nothing returns trigger
        static if LIBRARY_RegisterNativeEvent then
            return GetIndexNativeEventTrigger(0,Bountie.UNIT_BOUNTY_EVENT)
        else
            return Bountie.t2
        endif
    endfunction
   
    //The functions are runned using the triggers
   
    private function callBounty takes nothing returns nothing
        call BOUNTY(udg_BountyUnitID,udg_BountyBase,udg_BountyDice,udg_BountySides)
        set udg_BountyUnitID=0
        set udg_BountyBase=0
        set udg_BountyDice=0
        set udg_BountySides=0
    endfunction
   
    private function callBountyBase takes nothing returns nothing
        call SetBountyBase(udg_BountyUnitID,udg_BountyBase)
        set udg_BountyUnitID=0
        set udg_BountyBase=0
    endfunction
   
    private function callBountyDice takes nothing returns nothing
        call SetBountyDice(udg_BountyUnitID,udg_BountyDice)
        set udg_BountyUnitID=0
        set udg_BountyDice=0
    endfunction
   
    private function callBountySides takes nothing returns nothing
        call SetBountySides(udg_BountyUnitID,udg_BountySides)
        set udg_BountyUnitID=0
        set udg_BountySides=0
    endfunction
   
    private function callBountyGet takes nothing returns nothing
        set udg_Bounty=GetBountyFromUnitType(udg_BountyUnitID)
        set udg_BountyUnitID=0
    endfunction
   
    private function callBountyBaseGet takes nothing returns nothing
        set udg_BountyBase=GetBountyBase(udg_BountyUnitID)
        set udg_BountyUnitID=0
    endfunction
   
    private function callBountyDiceGet takes nothing returns nothing
        set udg_BountyDice=GetBountyDice(udg_BountyUnitID)
        set udg_BountyUnitID=0
    endfunction
   
    private function callBountySidesGet takes nothing returns nothing
        set udg_BountySides=GetBountySides(udg_BountyUnitID)
        set udg_BountyUnitID=0
    endfunction
   
    //The clear function doesn't run in the initialization, so I used a timer
    private function InitClear takes nothing returns nothing
        call BountyClear()
        call DestroyTimer(GetExpiredTimer())
        set udg_BountyEvent=0.00
        set udg_BountyEvent=2.00
        set udg_BountyEvent=0.00
    endfunction
   
    private function Init takes nothing returns nothing
        //The trigger that runs when a unit dies
        set gg_trg_Bounty_Controller=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(gg_trg_Bounty_Controller,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(gg_trg_Bounty_Controller,Condition(function UnitBountyCheck))
        call TriggerAddAction(gg_trg_Bounty_Controller,function UnitBounty)
        //(For GUI users) The trigger that shows the text
        set udg_BountyText=CreateTrigger()
        call TriggerAddAction(udg_BountyText,function BountyText)
        //(For GUI users) The triggers that set the default bounty of a unit
        set udg_BountySet=CreateTrigger()
        call TriggerAddAction(udg_BountySet,function callBounty)
        set udg_BountySetBase=CreateTrigger()
        call TriggerAddAction(udg_BountySetBase,function callBountyBase)
        set udg_BountySetDice=CreateTrigger()
        call TriggerAddAction(udg_BountySetDice,function callBountyDice)
        set udg_BountySetSides=CreateTrigger()
        call TriggerAddAction(udg_BountySetSides,function callBountySides)
        //(For GUI users) The triggers that get the bounty values of a unit (that you set before)
        set udg_BountyGet=CreateTrigger()
        call TriggerAddAction(udg_BountyGet,function callBountyGet)
        set udg_BountyGetBase=CreateTrigger()
        call TriggerAddAction(udg_BountyGetBase,function callBountyBaseGet)
        set udg_BountyGetDice=CreateTrigger()
        call TriggerAddAction(udg_BountyGetDice,function callBountyDiceGet)
        set udg_BountyGetSides=CreateTrigger()
        call TriggerAddAction(udg_BountyGetSides,function callBountySidesGet)
        //(For GUI users) to clear manually the values
        set udg_BountyClear=CreateTrigger()
        call TriggerAddAction(udg_BountyClear,function BountyClear)
        //To register the bounty events
        static if LIBRARY_RegisterNativeEvent then
            set Bountie.UNIT_BOUNTY_DEAD_EVENT=CreateNativeEvent()
            set Bountie.UNIT_BOUNTY_EVENT=CreateNativeEvent()
        else
            call TriggerRegisterVariableEvent(Bountie.t1,"udg_BountyDeadEvent",EQUAL,1.00)
            call TriggerRegisterVariableEvent(Bountie.t2,"udg_BountyEvent",EQUAL,1.00)
        endif
        //Last details
        set LocalPlayer=GetLocalPlayer()
        call SetData()
        call TimerStart(CreateTimer(),0.00,false,function InitClear)
    endfunction
   
endlibrary
 
Last edited:
Level 24
Joined
Jun 26, 2020
Messages
1,853
I edited the system a bit, I added Bountie.ByKill[Bountie.Recursion] to only clear the values if the function BountyText was not called when a unit kills another, because in that case the values are returned to its previous values after BountyText was called, so it would be a double clear.
 
Status
Not open for further replies.
Top