Problem with bounty system

Level 12
Joined
Jun 26, 2020
Messages
912
I create this system to control almost everything about the bouties and can edit it with external triggers, and use it with another events more than when you kill a unit, is uncompleted and I wanna add more stuff.
vJASS:
library BountyController initializer Init

    globals
        private hashtable Bounties=InitHashtable()
        private unit Dead
        private integer Id
        private real PosX
        private real PosY
        private boolean array PlayerNotSee
        private boolean Cleared=false
        player LocalPlayer
        private constant string DEF_COLOR="ffcc00"
        private constant integer DEF_SIZE=10
        private constant real DEF_LIFE_SPAN=3.50
        private constant real DEF_SPEED=64
        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
    endglobals
  
    function BOUNTY takes integer id, integer base, integer dice, integer side returns nothing
        call SaveInteger(Bounties,0,id,base)
        call SaveInteger(Bounties,1,id,dice)
        call SaveInteger(Bounties,2,id,side)
    endfunction
  
    //Here is to determine the normal bounties
    //you just have to add: BOUNTY("'ID of the unit'","Bounty: Base","Bounty: Number of dice","Bounty: Sides per dice")
    //or you can do it outside the code when you consider it
    //there is to write it /**/ BOUNTY("''","","","")
  
    private function SetData takes nothing returns nothing
        local integer i
      
        /*Vigilante draeniano (Nivel 1)*/   call BOUNTY('n002',35,6,3)
        /*Vigilante draeniano (Nivel 2)*/   call BOUNTY('n005',35,6,3)
        /*Vigilante draeniano (Nivel 3)*/   call BOUNTY('n00Q',35,6,3)
        /*Draenei Mage (Nivel 2)*/          call BOUNTY('n00B',35,6,3)
        /*Draenei Mage (Nivel 3)*/          call BOUNTY('n003',35,6,3)
        /*Defense Tower (Draenei)*/         call BOUNTY('o00H',100,5,5)
        /*Grunt orco fel (Nivel 1)*/        call BOUNTY('n00D',35,6,3)
        /*Grunt orco fel (Nivel 2)*/        call BOUNTY('n00F',35,6,3)
        /*Grunt orco fel (Nivel 3)*/        call BOUNTY('n00S',35,6,3)
        /*Brujo orco fel (Nivel 2)*/        call BOUNTY('n017',35,6,3)
        /*Brujo orco fel (Nivel 3)*/        call BOUNTY('n00R',35,6,3)
        /*Defense Tower (Demons)*/          call BOUNTY('o00I',100,5,5)
        /*Defense Tower (Dummy)*/           call BOUNTY('u00K',100,5,5)
        /*Renegade Draenei*/                call BOUNTY('ndrp',25,1,3)
        /*Wild Dragon*/                     call BOUNTY('n00O',25,1,3)
      
        set i=0
        loop
            exitwhen i>PLAYER_NEUTRAL_AGGRESSIVE
            call SetPlayerFlagBJ(PLAYER_STATE_GIVES_BOUNTY,false,Player(i))
            set i=i+1
        endloop
    endfunction
  
    private function Clear takes nothing returns nothing
        if not Cleared then
            set udg_BountyColor=DEF_COLOR
            set udg_BountySize=DEF_SIZE
            set udg_BountyLifeSpan=DEF_LIFE_SPAN
            set udg_BountyFadePoint=DEF_FADE_POINT
            set udg_BountySpeed=DEF_SPEED
            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_BountyPlayer=null
            set udg_BountyUnitPos=null
            set udg_BountyLocPos=null
            set udg_Bounty=-1
            set Dead=null
            set Id=0
            call ForceClear(udg_BountyWhoSee)
        endif
    endfunction

    function BountyText takes nothing returns nothing
        local texttag tt=null
        local playerstate state=null
      
        if udg_BountyPlayerState=="gold" then
            set state=PLAYER_STATE_RESOURCE_GOLD
        elseif udg_BountyPlayerState=="lumber" then
            set state=PLAYER_STATE_RESOURCE_LUMBER
        else
            call Clear()
            return //If the state is not valid, the process stop
        endif
      
        call AdjustPlayerStateSimpleBJ(udg_BountyPlayer,state,udg_Bounty)
        set state=null
      
        if udg_BountyLocPos!=null then
            set PosX=GetLocationX(udg_BountyLocPos)
            set PosY=GetLocationY(udg_BountyLocPos)
            call RemoveLocation(udg_BountyLocPos)
        elseif udg_BountyUnitPos!=null then
            set PosX=GetUnitX(udg_BountyUnitPos)
            set PosY=GetUnitY(udg_BountyUnitPos)
        else
            call Clear()
            return //If there is no position to the text, the text won't show
        endif
      
        if udg_BountyShow then //If this is true, it will show the text
            set tt=CreateTextTag()
            call SetTextTagPermanent(tt,false)
            call SetTextTagText(tt,"|cff"+udg_BountyColor+"+"+I2S(udg_Bounty)+"|r",TextTagSize2Height(udg_BountySize))
            call SetTextTagVisibility(tt,IsPlayerInForce(LocalPlayer,udg_BountyWhoSee))
            call SetTextTagPos(tt,PosX,PosY,udg_BountyHeight)
            call SetTextTagFadepoint(tt,udg_BountyFadePoint)
            call SetTextTagLifespan(tt,udg_BountyLifeSpan)
            call SetTextTagVelocityBJ(tt,udg_BountySpeed,90)
            set tt=null
        endif
        call Clear()
    endfunction
  
    private function UnitBounty takes nothing returns boolean
        set Dead=GetDyingUnit()
        set Id=GetUnitTypeId(Dead)
        //Check if the value of bounty didn't get affected
        if udg_Bounty==-1 then
            set udg_Bounty=IMaxBJ(0,LoadInteger(Bounties,0,Id)+GetRandomInt(0,LoadInteger(Bounties,1,Id)*LoadInteger(Bounties,2,Id)))
        elseif udg_Bounty<0 then
            set udg_Bounty=IMaxBJ(0,LoadInteger(Bounties,0,Id)+GetRandomInt(0,LoadInteger(Bounties,1,Id)*LoadInteger(Bounties,2,Id)))*udg_Bounty*-1
        endif
        //Check if the player didn't get affected
        if udg_BountyPlayer==null then
            set udg_BountyPlayer=GetOwningPlayer(GetKillingUnit())
        endif
        //Check if the visibility of the owner of killing unit didn't get affected
        if not PlayerNotSee[GetPlayerId(udg_BountyPlayer)] then
            call ForceAddPlayer(udg_BountyWhoSee,udg_BountyPlayer)
        else
            set PlayerNotSee[GetPlayerId(udg_BountyPlayer)]=false
        endif
        //Check if the unit position of the text didn't get affected
        if udg_BountyUnitPos==null then
            set udg_BountyUnitPos=Dead
        endif
      
        if IsUnitEnemy(Dead,udg_BountyPlayer) or udg_BountyAllowFriendFire then //By default, there only can be bounty if the dying unit is enemy of the killing unit
            if udg_Bounty!=0 or udg_BountyShowNothing then //By default, if the bounty is 0, so the process don't happen
                set Cleared=true
                call BountyText()
            endif
        endif
        set Cleared=false
        call Clear()
      
        return false
    endfunction
  
    function CheckPlayer takes force f, player p returns nothing
        if f==udg_BountyWhoSee then
            set PlayerNotSee[GetPlayerId(p)]=true
        endif
    endfunction
  
    function CheckPlayerBJ takes player p, force f returns nothing
        call CheckPlayer(f,p)
    endfunction
  
    hook ForceRemovePlayer CheckPlayer
    hook ForceRemovePlayerSimple CheckPlayerBJ
  
    private function Init takes nothing returns nothing
        //The trigger that runs when a unit dies
        set udg_BountyDie=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(udg_BountyDie,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(udg_BountyDie,Condition(function UnitBounty))
        //The trigger that shows the text
        set udg_BountyText=CreateTrigger()
        call TriggerAddAction(udg_BountyText,function BountyText)
        set LocalPlayer=GetLocalPlayer()
        call SetData()
        call Clear()
    endfunction
  
endlibrary
And surpringsly it works because for some reason all actions of external triggers happens before this trigger runs the function "Bounty Text" if it had the event of unit death, but my problems are:
  1. For some reason the clear function doesn't work fine, it always remains a previous edit in the next instance but in the next of that is cleared.
  2. Because of all actions of external triggers happens before this trigger runs the function "Bounty Text", the variables to the Bounty and the Player who receive it is not asigned yet, so it will have the default value, and because of that the unique edit the variable "Bounty" can be by multiplications and an especific value and not another that depends of the original Bounty.
  3. If I wanna allow negative bounties, what should be the default value of "Bounty"?
  4. If the solution is using custom events, can you teach me how to it works for I wanna do?
 
Last edited:

Dr Super Good

Spell Reviewer
Level 57
Joined
Jan 18, 2005
Messages
26,448
For some reason the clear function doesn't work fine, it always remains a previous edit in the next instance but in the next of that is cleared.
That sounds like it could be that the instance logic runs before the clear is run. Make sure the order the functions execute in is what you expect. You can test this with debug messages as those will be generated in the order the code is run.
 
Level 12
Joined
Jun 26, 2020
Messages
912
That sounds like it could be that the instance logic runs before the clear is run. Make sure the order the functions execute in is what you expect. You can test this with debug messages as those will be generated in the order the code is run.
Maybe, but there is something more that I didn't mentioned, but the first time the systems runs, never work, the next instance works, I say this because I think is related with that.
 
Level 12
Joined
Jun 26, 2020
Messages
912
Well I used debug messages and I noticed I was wrong, the actions pf the triggers with the unit die event don't happen before calling the function BountyText, they happen after, so I opted for custom events, I didn't notice that because the function BountyText never worked the first time, and that happened because the function Clear didn't run in the Init function, so instead I run it with a 0.00 timer and now works fine.

By the way, I think my system works fine now, so thank you for your suggestions.
 
Level 12
Joined
Jun 26, 2020
Messages
912
After doing much work, this the result, what do you think?
vJASS:
/******************************************************************************************************/
/*************************************Bounty Controller by HerlySQR************************************/
/******************************************************************************************************/
//
//    This library was made to have almost every control of the bounties of the units
//    Important is have deactivated the bounties (this system do that, but don't active them)
//    and you have to set the values of the bounties manually, only requires JassHelper.
// 
//////If you wanna set the default value of the bounty of the units 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: Base"
//            Trigger - Run BountySetBase (Ignoring conditions)
//        BOUNTY:
//            Set BountyUnitID = "Unit-Type of you unit"
//            Set BountyBase = "Bounty: Sides per dice"
//            Set BountyDice = "Bounty: Number of dice"
//            Set BountySides = "Bounty: Base"
//            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).
//        "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.
//        "BountyFadePoint": How many seconds the text will fade after the lifespan.
//        "BountySpeed": The speed of the text.
//        "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 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)
//        "BountyWhoSee": The players who can see the text.
//    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 text or the bounty because with this, because it happens after the process ends, but you can get the values
//
//////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()"
//
//    And if you wanna keep the changes of the previous instance, 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 will have
//    those changes.
//
//    Additionally it has the variable LocalPlayer to not use GetLocalPlayer() everytime, if you don't like it,
//    just add "private" before of it in the global section.
//
//=====================================================================================================


library BountyController initializer Init
    globals
        private hashtable Bounties=InitHashtable()
        private real PosX
        private real PosY
        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_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
    endglobals
  
    //The functions to set the bounty stats
  
    function SetBountyBase takes integer id, integer base returns nothing
        call SaveInteger(Bounties,0,id,base)
    endfunction
  
    function SetBountyDice takes integer id, integer dice returns nothing
        call SaveInteger(Bounties,1,id,dice)
    endfunction
  
    function SetBountySides takes integer id, integer sides returns nothing
        call SaveInteger(Bounties,2,id,sides)
    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
        return LoadInteger(Bounties,0,id)
    endfunction
  
    function GetBountyDice takes integer id returns integer
        return LoadInteger(Bounties,1,id)
    endfunction
  
    function GetBountySides takes integer id returns integer
        return LoadInteger(Bounties,2,id)
    endfunction
  
    function GetBountyFromUnitType takes integer id returns integer
        return GetBountyBase(id)+GetRandomInt(0,GetBountyDice(id)*GetBountySides(id))
    endfunction
  
    //Here is to determine the normal bounties
    //You can use the functions SetBaseBounty, SetNumberOfDiceBounty and SetSidePerDiceBounty, or if you wanna set the 3 elements
    //you just have to use: BOUNTY("'ID of the unit'","Bounty: Base","Bounty: Number of dice","Bounty: Sides per dice")
    //or you can do it outside the code when you consider it
    //there is to write it /**/ call BOUNTY("''","","","")
  
    private function SetData takes nothing returns nothing
        local integer i
      
        /*Vigilante draeniano (Nivel 1)*/   call BOUNTY('n002',35,6,3)
        /*Vigilante draeniano (Nivel 2)*/   call BOUNTY('n005',35,6,3)
        /*Vigilante draeniano (Nivel 3)*/   call BOUNTY('n00Q',35,6,3)
        /*Draenei Mage (Nivel 2)*/          call BOUNTY('n00B',35,6,3)
        /*Draenei Mage (Nivel 3)*/          call BOUNTY('n003',35,6,3)
        /*Defense Tower (Draenei)*/         call BOUNTY('o00H',100,5,5)
        /*Grunt orco fel (Nivel 1)*/        call BOUNTY('n00D',35,6,3)
        /*Grunt orco fel (Nivel 2)*/        call BOUNTY('n00F',35,6,3)
        /*Grunt orco fel (Nivel 3)*/        call BOUNTY('n00S',35,6,3)
        /*Brujo orco fel (Nivel 2)*/        call BOUNTY('n017',35,6,3)
        /*Brujo orco fel (Nivel 3)*/        call BOUNTY('n00R',35,6,3)
        /*Defense Tower (Demons)*/          call BOUNTY('o00I',100,5,5)
        /*Defense Tower (Dummy)*/           call BOUNTY('u00K',100,5,5)
        /*Death Tower*/                     call BOUNTY('n00I',30,8,3)
        /*Death Tower (Level 2)*/           call BOUNTY('n00L',20,8,3)
        /*Death Tower (Level 3)*/           call BOUNTY('n00M',20,8,3)
        /*Renegade Draenei*/                call BOUNTY('ndrp',25,1,3)
        /*Wild Dragon*/                     call BOUNTY('n00O',25,1,3)
      
        set i=0
        loop
            exitwhen i>PLAYER_NEUTRAL_AGGRESSIVE
            call SetPlayerFlagBJ(PLAYER_STATE_GIVES_BOUNTY,false,Player(i))
            set i=i+1
        endloop
    endfunction
  
    //To clear the data
    private function Clear takes nothing returns nothing
        if not udg_BountyNotClear then //If the player wanna save previous changes to the next instance, this variable is set to true
            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_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_BountyPlayer=null
            set udg_BountyUnitPos=null
            set udg_BountyLocPos=null
            set udg_Bounty=0
            call ForceClear(udg_BountyWhoSee)
        endif
        set udg_BountyDyingUnit=null
        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 null
        else
            return "+"
        endif
    endfunction
  
    //The function that runs the bounty and the texttag
    function BountyText takes nothing returns nothing
        local texttag tt=null
        local playerstate state=null
      
        if udg_BountyPlayerState=="gold" then
            set state=PLAYER_STATE_RESOURCE_GOLD
        elseif udg_BountyPlayerState=="lumber" then
            set state=PLAYER_STATE_RESOURCE_LUMBER
        else
            call Clear()
            return //If the state is not valid, the process stop
        endif
      
        call AdjustPlayerStateSimpleBJ(udg_BountyPlayer,state,udg_Bounty)
        set state=null
      
        if udg_BountyColor==null then //If the color didn't get edited, the color of the text will have the default value depending of the state
            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 PosX=GetLocationX(udg_BountyLocPos)
            set PosY=GetLocationY(udg_BountyLocPos)
        elseif udg_BountyUnitPos!=null then
            set PosX=GetUnitX(udg_BountyUnitPos)
            set PosY=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
      
        if udg_BountyShow then //If this is true, it will show the text
            set tt=CreateTextTag()
            call SetTextTagPermanent(tt,false)
            call SetTextTagText(tt,"|cff"+udg_BountyColor+Sign(udg_Bounty)+I2S(udg_Bounty)+"|r",TextTagSize2Height(udg_BountySize))
            call SetTextTagVisibility(tt,IsPlayerInForce(LocalPlayer,udg_BountyWhoSee))
            call SetTextTagPos(tt,PosX,PosY,udg_BountyHeight)
            call SetTextTagFadepoint(tt,udg_BountyFadePoint)
            call SetTextTagLifespan(tt,udg_BountyLifeSpan)
            call SetTextTagVelocityBJ(tt,udg_BountySpeed,90)
            set tt=null
        endif
      
        if udg_BountyShowEffect then //To show the effect, only if this value is true
            call DestroyEffect(AddSpecialEffect(udg_BountyEffect,PosX,PosY))
        endif
      
        set udg_BountyEvent=0.00
        set udg_BountyEvent=1.00
        set udg_BountyEvent=0.00
      
        call Clear()
    endfunction
  
    private function UnitBounty takes nothing returns boolean
        set udg_BountyKillingUnit=GetKillingUnit()
        if udg_BountyKillingUnit==null then //If there is not killing unit so the process stop
            return false
        endif
      
        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 //By default, there only can be bounty if the dying unit is enemy of the killing unit
            if udg_Bounty!=0 or udg_BountyShowNothing then //By default, if the bounty is 0, so the process don't happen
                call BountyText()
            endif
        endif
      
        return false
    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
  
    private function InitClear takes nothing returns nothing
        call Clear()
        call DestroyTimer(GetExpiredTimer())
    endfunction
  
    private function Init takes nothing returns nothing
        //The trigger that runs when a unit dies
        set udg_BountyDie=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(udg_BountyDie,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(udg_BountyDie,Condition(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)
        //Last details
        set LocalPlayer=GetLocalPlayer()
        call SetData()
        call TimerStart(CreateTimer(),0.00,false,function InitClear)
    endfunction
  
endlibrary
 
Last edited:

Dr Super Good

Spell Reviewer
Level 57
Joined
Jan 18, 2005
Messages
26,448
Some of the comments are unnecessary. For example...
if udg_BountyShowEffect then //To show the effect, only if this value is true
The code already says what the comment says since that is fundamentally how conditional statements work. In such a case I would rather put a comment above that marks that section of the code as handling bounty visual effects as that would help explain to readers/maintainers the high level flow of the code.
 
Level 12
Joined
Jun 26, 2020
Messages
912
Well, I changed some comments, in reality I don't know what things can be necessary to mention and what not.
vJASS:
/******************************************************************************************************/
/*************************************Bounty Controller by HerlySQR************************************/
/******************************************************************************************************/
//
//    This library was made to have almost every control of the bounties of the units
//    Important is have deactivated the bounties (this system do that, but don't active them)
//    and you have to set the values of the bounties manually, only requires JassHelper.
//
//////If you wanna set the default value of the bounty of the units 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).
//        "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.
//        "BountyFadePoint": How many seconds the text will fade after the lifespan.
//        "BountySpeed": The speed of the text.
//        "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 who 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)
//        "BountyWhoSee": The players who can see the text.
//    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 text or the bounty because with this, because it happens after the process ends, but you can get the values
//    (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".)
//
//////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()"
//
//    And if you wanna keep the changes of the previous instance, 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.
//
//=====================================================================================================


library BountyController initializer Init
    globals
        private hashtable Bounties=InitHashtable()
        private real PosX
        private real PosY
        /*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_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
    endglobals

    //The functions to set the bounty stats

    function SetBountyBase takes integer id, integer base returns nothing
        call SaveInteger(Bounties,0,id,base)
    endfunction

    function SetBountyDice takes integer id, integer dice returns nothing
        call SaveInteger(Bounties,1,id,dice)
    endfunction

    function SetBountySides takes integer id, integer sides returns nothing
        call SaveInteger(Bounties,2,id,sides)
    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
        return LoadInteger(Bounties,0,id)
    endfunction

    function GetBountyDice takes integer id returns integer
        return LoadInteger(Bounties,1,id)
    endfunction

    function GetBountySides takes integer id returns integer
        return LoadInteger(Bounties,2,id)
    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 bounties, you can do it

    private function SetData takes nothing returns nothing
        local integer i

        /*Vigilante draeniano (Nivel 1)*/   call BOUNTY('n002',35,6,3)
        /*Vigilante draeniano (Nivel 2)*/   call BOUNTY('n005',35,6,3)
        /*Vigilante draeniano (Nivel 3)*/   call BOUNTY('n00Q',35,6,3)
        /*Draenei Mage (Nivel 2)*/          call BOUNTY('n00B',35,6,3)
        /*Draenei Mage (Nivel 3)*/          call BOUNTY('n003',35,6,3)
        /*Defense Tower (Draenei)*/         call BOUNTY('o00H',100,5,5)
        /*Grunt orco fel (Nivel 1)*/        call BOUNTY('n00D',35,6,3)
        /*Grunt orco fel (Nivel 2)*/        call BOUNTY('n00F',35,6,3)
        /*Grunt orco fel (Nivel 3)*/        call BOUNTY('n00S',35,6,3)
        /*Brujo orco fel (Nivel 2)*/        call BOUNTY('n017',35,6,3)
        /*Brujo orco fel (Nivel 3)*/        call BOUNTY('n00R',35,6,3)
        /*Defense Tower (Demons)*/          call BOUNTY('o00I',100,5,5)
        /*Defense Tower (Dummy)*/           call BOUNTY('u00K',100,5,5)
        /*Death Tower*/                     call BOUNTY('n00I',30,8,3)
        /*Death Tower (Level 2)*/           call BOUNTY('n00L',20,8,3)
        /*Death Tower (Level 3)*/           call BOUNTY('n00M',20,8,3)
        /*Renegade Draenei*/                call BOUNTY('ndrp',25,1,3)
        /*Wild Dragon*/                     call BOUNTY('n00O',25,1,3)

        set i=0
        loop
            exitwhen i>PLAYER_NEUTRAL_AGGRESSIVE
            call SetPlayerFlagBJ(PLAYER_STATE_GIVES_BOUNTY,false,Player(i))
            set i=i+1
        endloop
    endfunction

    //To clear the data
    private function Clear takes nothing returns nothing
        if not udg_BountyNotClear then
            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_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_BountyPlayer=null
            set udg_BountyUnitPos=null
            set udg_BountyLocPos=null
            set udg_Bounty=0
            call ForceClear(udg_BountyWhoSee)
        endif
        set udg_BountyKillingUnit==null
        set udg_BountyDyingUnit=null
        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 null
        else
            return "+"
        endif
    endfunction

    //The function that runs the bounty and the texttag
    function BountyText takes nothing returns nothing
        local texttag tt=null
        local playerstate state=null

        if udg_BountyPlayerState=="gold" then
            set state=PLAYER_STATE_RESOURCE_GOLD
        elseif udg_BountyPlayerState=="lumber" then
            set state=PLAYER_STATE_RESOURCE_LUMBER
        else
            call Clear()
            return //If the state is not valid, the process stop
        endif

        call AdjustPlayerStateSimpleBJ(udg_BountyPlayer,state,udg_Bounty)
        set state=null

        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 PosX=GetLocationX(udg_BountyLocPos)
            set PosY=GetLocationY(udg_BountyLocPos)
        elseif udg_BountyUnitPos!=null then
            set PosX=GetUnitX(udg_BountyUnitPos)
            set PosY=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

        if udg_BountyShow then
            set tt=CreateTextTag()
            call SetTextTagPermanent(tt,false)
            call SetTextTagText(tt,"|cff"+udg_BountyColor+Sign(udg_Bounty)+I2S(udg_Bounty)+"|r",TextTagSize2Height(udg_BountySize))
            call SetTextTagVisibility(tt,IsPlayerInForce(LocalPlayer,udg_BountyWhoSee))
            call SetTextTagPos(tt,PosX,PosY,udg_BountyHeight)
            call SetTextTagFadepoint(tt,udg_BountyFadePoint)
            call SetTextTagLifespan(tt,udg_BountyLifeSpan)
            call SetTextTagVelocityBJ(tt,udg_BountySpeed,90)
            set tt=null
        endif

        if udg_BountyShowEffect then
            call DestroyEffect(AddSpecialEffect(udg_BountyEffect,PosX,PosY))
        endif

        set udg_BountyEvent=0.00
        set udg_BountyEvent=1.00
        set udg_BountyEvent=0.00

        call Clear()
    endfunction

    private function UnitBounty takes nothing returns boolean
        set udg_BountyKillingUnit=GetKillingUnit()
        if udg_BountyKillingUnit==null then //If there is not killing unit then the process stop
            return false
        endif

        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
            if udg_Bounty!=0 or udg_BountyShowNothing then
                call BountyText()
            endif
        endif

        return false
    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 Clear()
        call DestroyTimer(GetExpiredTimer())
    endfunction

    private function Init takes nothing returns nothing
        //The trigger that runs when a unit dies
        set udg_BountyDie=CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(udg_BountyDie,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddCondition(udg_BountyDie,Condition(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)
        //Last details
        set LocalPlayer=GetLocalPlayer()
        call SetData()
        call TimerStart(CreateTimer(),0.00,false,function InitClear)
    endfunction

endlibrary
 
Last edited:
Top