System Hero Tavern System (HTS)

wraithseeker

Tired.
Reaction score
122
As usual, I don't like typing things so I will let the documention take my place.

Requirements: AutoIndex & SimError

JASS:
Hero Tavern System
v1.00

By wraithseeker

        Changelog v1.00
    - Initial Release
    
Main Purpose
    - Saving space 
    - Extending Taverns
    - Hero Selection System

HTS is a system that extends the selection of Taverns. As most people know, when you select a hero from a
tavern, you cannot see his abilities his stats. This system does that when you buy a unit from the tavern,
it creates a final verison of the hero for you to look at it and see if you like it. It has 2 abilities
that are able to be used which is SelectHero and Random. Random is just randoming a hero out of a unitpool
and you get one correctly, nicely and efficiently. You can specify the weight for it, the higher the value,
the easier it is to get the unit. There are many boolean that can help you setup the system your way.

Somewhat interesting facts.

This tavern system helps you save space if you want to, there is a next page ability that selects the next
tavern without the player knowing it so you can have endless amount of tavern but in reality, it looks
just like one tavern only!.

Available function

function AddPlayerToTeam takes player whichPlayer, integer team returns nothing
function AddForceStartLocation takes rect whichRect, integer team returns nothing
function AddHeroToPool takes integer HeroId, real weight returns nothing
function SetTavern takes unit u returns nothing
function CreateMoreTavern takes integer tavernId returns nothing

AddPlayerToTeam simply adds the player to team 1 or team 2, only 2 teams are allowed.

AddForceToStart location sets the location where the heroes spawn in a random point in that rect.

AddHeroToPool adds the hero into the random unitpool so you can random all your heroes.
If you do not add it, randoming a hero is impossible.

SetTavern must be used first before CreateMoreTavern is used.

CreateMoreTavern simply stacks the tavern together.


JASS:
library HSS initializer Init uses AutoIndex, SimError

globals
    private constant integer RANDOMID = 'RAND'
    private constant integer CHOOSEID = 'CHOS'
    private constant integer NEXTPAGEID = 'NEXT'
    private constant integer MAXLEVEL = 100 // max level of heroes in your game
    private constant integer AMOUNTOfRepicks = 1 // How many times can a hero repick
    private constant integer MAXSTOCK = 99 // totally random
    private constant integer MAXHEROESTOVIEW = 1 // How many heroes you can view at once
    private constant real PANTIME = 0.5 // when bought, pan the camera
    private constant real SELECTIONTIME = 30
    private constant string TAVERNSFX = "Abilities\\Spells\\NightElf\\Starfall\\StarfallCaster.mdl" // "" == nothing  != "" == effect
    private constant string SFXPOINT = "origin" // attach point of effect
    private constant string CHOOSESFX = "Abilities\\Spells\\Human\\HolyBolt\\HolyBoltSpecialArt.mdl"  // effect when you choose and pick or random a hero
    private constant string ViewError = "You can only view a maximum of 1 heroes!" // set the value of 1 to the value of MAXHEROESTOVIEW
    private constant boolean EYECANDY = false // eye candy of leveling when player choose a unit
    private constant boolean GIVERANDOMHEROES = true // after selection time, give random heroes
    private constant boolean REPICKTYPE = true // false = random true = user specificed
    private constant boolean SHOWBOARD = true // show the amount of time left
    private constant boolean DEFEATAFKPLAYERS = true // Anybody who hasn't finished choosing a hero will get defeated
endglobals

globals 
    private constant integer GHOSTID = 'Aeth'
    private constant integer MOVEID = 'Amov'
    private constant integer ATKID = 'Aatk' // stuffs here you will probaby never touch
    private integer Count = 1 // why 1? Simple, because the default tavern is array 0
    private rect FORCE1
    private rect FORCE2
    private real sx1
    private real sy1
    private real mx1
    private real my1
    private real sx2
    private real sy2
    private real mx2
    private real my2
    private force TEAM1 = CreateForce()
    private force TEAM2 = CreateForce()
    private force Playing = CreateForce()
    private force Unused = CreateForce()
    private group Testers = CreateGroup()
    private group Enum = CreateGroup()
    private group Chosen = CreateGroup()
    private unitpool Heroes = CreateUnitPool()
    private boolexpr ChosenB
    private timer Board = CreateTimer()
    private timerdialog T = CreateTimerDialog(Board)
    private trigger Sold = CreateTrigger()
    private trigger Orders = CreateTrigger()
    private trigger ChatRepick = CreateTrigger()
    private trigger OnDeath = CreateTrigger()
    private trigger Next = CreateTrigger()
    private trigger NoClick = CreateTrigger()
    private unit array Tavern
    private integer array Counter
    private integer array Times
    private string array Colours
    private effect TavernEffect
    private constant integer CHOOSEIDCLICK = 852273
    private constant integer RANDOMIDCLICK = 852277
endglobals

function AddPlayerToTeam takes player whichPlayer, integer team returns nothing
    if team == 1 then
        call ForceAddPlayer(TEAM1,whichPlayer)
    elseif team == 2 then
        call ForceAddPlayer(TEAM2,whichPlayer)
    endif
endfunction

private function GetPlayerColour takes player p returns string // A string system
    local integer it = GetPlayerId(p)
    local string s = Colours[it] + GetPlayerName(p)+ "|r"
    return s
endfunction

private function RepickCond takes nothing returns boolean
    return IsUnitType(GetFilterUnit(),UNIT_TYPE_HERO) and not IsUnitInGroup(GetFilterUnit(),Testers) and IsUnitInGroup(GetFilterUnit(),Chosen)
endfunction

function AddForceStartLocation takes rect whichRect, integer team returns nothing
    if team == 1 then
        set FORCE1 = whichRect
        set sx1 = GetRectMaxX(FORCE1)
        set sy1 = GetRectMaxY(FORCE1)
        set mx1 = GetRectMinX(FORCE1)
        set my1 = GetRectMinY(FORCE1)
    elseif team == 2 then
        set FORCE2 = whichRect
        set sx2 = GetRectMaxX(FORCE2)
        set sy2 = GetRectMaxY(FORCE2)
        set mx2 = GetRectMinX(FORCE2)
        set my2 = GetRectMaxY(FORCE2)
    endif
endfunction

function AddHeroToPool takes integer HeroId, real weight returns nothing
    call UnitPoolAddUnitType(Heroes,HeroId,weight)
endfunction

function CreateMoreTavern takes integer tavernId returns nothing
    set Tavern[Count] = CreateUnit(Player(0),tavernId,GetUnitX(Tavern[0]),GetUnitY(Tavern[0]),GetUnitFacing(Tavern[0]))
    set Count = Count + 1 // we need to increase it everytime new taverns appear
endfunction

private function DisplayText takes string s returns nothing
    if IsPlayerInForce(GetLocalPlayer(),Playing) then // oh just to tell you, i took the GetLocalPlayer() usage from the BJ
        call DisplayTextToPlayer(GetLocalPlayer(), 0, 0,s)
    endif
endfunction

function SetTavern takes unit u returns nothing
    set Tavern[0] = u
    if TAVERNSFX != "" then
        set TavernEffect = AddSpecialEffectTarget(TAVERNSFX,u,SFXPOINT)
    endif
endfunction

private function Choose takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local unit t = GetSoldUnit()
    local integer i = 0
    local string s
    local player p = GetOwningPlayer(t)
    local integer it = GetPlayerId(p)
    if Times[it] >= MAXHEROESTOVIEW then
        call SimError(p,ViewError)
        call RemoveUnitEx(t)
        call AddUnitToStock(u,GetUnitTypeId(t),0,1)
        set u = null
        set t = null
        return false
    endif
    loop
        exitwhen i >= bj_MAX_PLAYERS
        call SetPlayerTechMaxAllowed(Player(i),GetUnitTypeId(t),0)
        set i = i + 1
    endloop
    set Times[it] = Times[it] + 1
    if GetLocalPlayer() == p then
        call ClearSelection()
        call PanCameraToTimed(GetUnitX(t),GetUnitY(t),PANTIME)
    endif
    call SelectUnit(t,true)
    if IsPlayerInForce(p,TEAM1) then
        call SetUnitX(t,GetRandomReal(mx1,sx1))
        call SetUnitY(t,GetRandomReal(my1,sy1))
        if GetLocalPlayer() == GetOwningPlayer(t) then
            call PanCameraToTimed(GetUnitX(t),GetUnitY(t),PANTIME)
        endif
        if not EYECANDY then
            call SetHeroLevel(t,MAXLEVEL,false)
        else
             call SetHeroLevel(t,MAXLEVEL,true)
        endif
        call GroupAddUnit(Testers,t)
        call UnitAddAbility(t,GHOSTID)
        call UnitRemoveAbility(t, 'Amov' ) //* Removes movement
        call UnitRemoveAbility(t, 'Aatk' ) //* Removes Attack
        call UnitAddAbility(t,RANDOMID)
        call UnitAddAbility(t,CHOOSEID)
        call ForceRemovePlayer(Unused,p)
    elseif IsPlayerInForce(p,TEAM2) then
        call SetUnitX(t,GetRandomReal(mx2,sx2))
        call SetUnitY(t,GetRandomReal(my2,sy2))
        if GetLocalPlayer() == p then
            call PanCameraToTimed(GetUnitX(t),GetUnitY(t),PANTIME)
        endif
        if not EYECANDY then
            call SetHeroLevel(t,MAXLEVEL,false)
        else
            call SetHeroLevel(t,MAXLEVEL,true)
        endif
        call GroupAddUnit(Testers,t)
        call UnitAddAbility(t,GHOSTID)
        call UnitRemoveAbility(t,MOVEID)
        call UnitRemoveAbility(t,ATKID)
        call UnitAddAbility(t,RANDOMID)
        call UnitAddAbility(t,CHOOSEID)
        call ForceRemovePlayer(Unused,p)
    endif
    if CHOOSESFX != "" then
        call DestroyEffect(AddSpecialEffect(CHOOSESFX,GetUnitX(t),GetUnitY(t)))
    endif
    set s = GetPlayerColour(p)
    call DisplayText(s + " is currently viewing " + GetUnitName(t))
    set u = null
    set t = null
    return false
endfunction

private function ReplaceUnit takes unit u, integer newUnitId returns unit
    local integer index = 0 // modified specially for the system
    local item    indexItem
    local real    oldRatio
    local unit p
    call ShowUnit(u, false)
    set p = CreateUnit(GetOwningPlayer(u), newUnitId, GetUnitX(u),GetUnitY(u),GetUnitFacing(u))
    call SetUnitState(p, UNIT_STATE_LIFE, GetUnitState(u, UNIT_STATE_LIFE))
    if GetUnitState(p, UNIT_STATE_MAX_MANA) > 0 then
        call SetUnitState(p, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA))
    endif
    call SetResourceAmount(p,GetResourceAmount(u))
    loop
        set indexItem = UnitItemInSlot(u, index)
        if indexItem != null then
            call UnitRemoveItem(u, indexItem)
            call UnitAddItem(p, indexItem)
        endif
        set index = index + 1
        exitwhen index > 5
    endloop
    call RemoveUnitEx(u)
    call GroupRemoveUnit(Testers,u)
    return p
endfunction
        
private function BLOCK takes nothing returns boolean
    local unit u = GetTriggerUnit()
    local real x 
    local real y
    local real angle
    local unit f
    local string s
    local integer i = 0
    local trigger t = GetTriggeringTrigger() // do triggers need to be nulled? I'll just null it for the sake of safety
    if IsUnitInGroup(u,Testers) then
        call DisableTrigger(t)
        if GetIssuedOrderId() == RANDOMIDCLICK then
            set f = PlaceRandomUnit(Heroes,GetOwningPlayer(u),GetUnitX(u),GetUnitY(u),GetUnitFacing(u))
            if GetLocalPlayer() == GetOwningPlayer(f) then
                call ClearSelection()
            endif
            loop
                exitwhen i >= bj_MAX_PLAYERS
                call SetPlayerTechMaxAllowed(Player(i),GetUnitTypeId(u),MAXSTOCK)
                call SetPlayerTechMaxAllowed(Player(i),GetUnitTypeId(f),0)
                set i = i + 1
            endloop
            if f == null then
                call BJDebugMsg("Unitpool does not have anymore heroes left!")
            endif
            set s = GetPlayerColour(GetOwningPlayer(u))
            call DisplayText(s + " has just randomed " + GetUnitName(f))
            call SelectUnit(f,true)
            call UnitPoolRemoveUnitType(Heroes,GetUnitTypeId(f))
            call RemoveUnitEx(u)
            call GroupRemoveUnit(Testers,u)
            call GroupAddUnit(Chosen,f)
            if CHOOSESFX != "" then
                call DestroyEffect(AddSpecialEffect(CHOOSESFX,GetUnitX(f),GetUnitY(f)))
            endif
            set f = null
            set u = null
            call EnableTrigger(t)
            set t = null
            return false
        elseif GetIssuedOrderId() == CHOOSEIDCLICK then
            set f = ReplaceUnit(u,GetUnitTypeId(u))
            set s = GetPlayerColour(GetOwningPlayer(u))
            call DisplayText(s + " has just chosen " + GetUnitName(f))
            if GetLocalPlayer() == GetOwningPlayer(u) then
                call ClearSelection()
            endif
            call SelectUnit(f,true)
            call GroupAddUnit(Chosen,f)
             if CHOOSESFX != "" then
                call DestroyEffect(AddSpecialEffect(CHOOSESFX,GetUnitX(f),GetUnitY(f)))
            endif
            call UnitPoolRemoveUnitType(Heroes,GetUnitTypeId(f))
            set f = null
            set u = null
            call EnableTrigger(t)
            set t = null
            return false
        endif
        if GetTriggerEventId() == EVENT_PLAYER_UNIT_ISSUED_ORDER and GetHeroSkillPoints(u) >= 1 then
            call EnableTrigger(t)
            set t = null
            set u = null
            return false
        endif
        call PauseUnit(u,true)
        call IssueImmediateOrder(u,"stop")
        call PauseUnit(u,false)
        call EnableTrigger(t)
        set u = null
        set t = null
        set f = null
        return false
    endif
    set u = null
    set t = null
    return false
endfunction

private struct data
    unit target
    integer times

    implement AutoData

static method create takes unit u returns data
    local data d = data.allocate()
    set d.target = u
    set d.times = 0
    set data<u> = d
    return d
endmethod

endstruct

private function Repick takes nothing returns nothing
    local unit u
    local unit f
    local string s
    local integer i = 0
    local data d
    local player p = GetTriggerPlayer()
    call GroupEnumUnitsSelected(Enum,p,ChosenB)
    set u = FirstOfGroup(Enum)
    set d = data<u>
    if d == 0 then
        set d = data.create(u)
    endif
    if u != null and d.times &lt; AMOUNTOfRepicks then
        call RemoveUnitEx(u)
        if GetLocalPlayer() == p then
            call ClearSelection()
        endif
        if not REPICKTYPE then         
            set f = PlaceRandomUnit(Heroes,p,GetUnitX(u),GetUnitY(u),GetUnitFacing(u))
            call SelectUnit(f,true)
            set s = GetPlayerColour(p)
            call DisplayText(s + &quot; has repicked into &quot; + GetUnitName(f))
            call GroupAddUnit(Chosen,f)
            call GroupRemoveUnit(Chosen,u)
            call UnitPoolAddUnitType(Heroes,GetUnitTypeId(u),1)
            call UnitPoolRemoveUnitType(Heroes,GetUnitTypeId(f))
        elseif REPICKTYPE then
            set s = GetPlayerColour(p)
            call DisplayText(s + &quot; has repicked&quot;)
            loop
                exitwhen i &gt;= bj_MAX_PLAYERS
                call SetPlayerTechMaxAllowed(Player(i),GetUnitTypeId(u),MAXSTOCK) // let them buy the hero again
                set i = i + 1
            endloop
            if GetLocalPlayer() == p then
                call PanCameraToTimed(GetUnitX(Tavern[0]),GetUnitY(Tavern[0]),PANTIME)
            endif
        endif // if you ask me why I don&#039;t destroy them, when I destroy, they bug and they are heroes anyway ^_^
        set d.times = d.times + 1
        set data[f] = d
        call GroupRemoveUnit(Enum,u)
    endif
    set f = null
    set u = null
endfunction

private function End takes nothing returns nothing
    local unit f
    local integer i = 0
    local string s
    debug call BJDebugMsg(&quot;Selection Has Ended&quot;)
    if GIVERANDOMHEROES then
        loop
            exitwhen i &gt; 12
            if IsPlayerInForce(Player(i),Unused) then
                if IsPlayerInForce(Player(i),TEAM1) then
                    set f = PlaceRandomUnit(Heroes,Player(i),GetRandomReal(mx1,sx1),GetRandomReal(my1,sy1),0)
                    call UnitPoolRemoveUnitType(Heroes,GetUnitTypeId(f))
                elseif IsPlayerInForce(Player(i),TEAM2) then
                   set f = PlaceRandomUnit(Heroes,Player(i),GetRandomReal(mx2,sx2),GetRandomReal(my2,sy2),0)
                    call UnitPoolRemoveUnitType(Heroes,GetUnitTypeId(f))
                endif
            endif
            set i = i + 1
        endloop
    endif
    loop
        set f = FirstOfGroup(Testers)
        exitwhen f == null
        call KillUnit(f)
        if DEFEATAFKPLAYERS then
            set s = GetPlayerColour(GetOwningPlayer(f))
            call CustomDefeatBJ(GetOwningPlayer(f),&quot;Defeat!&quot;)
            call DisplayText(s + &quot; has been kicked for not choosing a hero&quot;)
        endif
        call GroupRemoveUnit(Testers,f)
    endloop
    set i = 0
    loop
        exitwhen i &gt; 12
        if IsPlayerInForce(Player(i),Unused) and DEFEATAFKPLAYERS then
            set s = GetPlayerColour(Player(i))
            call CustomDefeatBJ(Player(i), &quot;Defeat!&quot;)
            call DisplayText(s + &quot; has been kicked for not choosing a hero&quot;)
        endif
        set i = i + 1
    endloop
    call DisableTrigger(Sold)
    call DisableTrigger(ChatRepick)
    call DisableTrigger(Orders)
    call DisableTrigger(OnDeath)
    call DisableTrigger(Next)
    call PauseTimer(Board)
    call DestroyTimer(Board)
    call DestroyForce(TEAM1)
    call DestroyForce(TEAM2)
    call DestroyForce(Playing)
    call DestroyForce(Unused)
    call DestroyGroup(Testers)
    call DestroyGroup(Enum)
    call DestroyGroup(Chosen)
    call DestroyUnitPool(Heroes)
    call DestroyBoolExpr(ChosenB)
    if SHOWBOARD then
        call TimerDialogDisplay(T,false)
        call DestroyTimerDialog(T)
    endif
endfunction

private function AfterInit takes nothing returns nothing
    local timer t = GetExpiredTimer() // Had to do this.
    if SHOWBOARD then
        call TimerDialogDisplay(T,true)
        call TimerDialogSetTitle(T,&quot;Selection Time&quot;)
    endif
    call PauseTimer(t)
    call DestroyTimer(t)
endfunction

private function IsTavern takes nothing returns boolean
    local unit u = GetTriggerUnit() // Destroy the effect if the main tavern dies, simple?
    if u == Tavern[0] then
        call DestroyEffect(TavernEffect)
    endif
    set u = null
    return false
endfunction

private function NextPage takes nothing returns boolean
    local unit u = GetTriggerUnit() // Flips to the next page for the user.
    local player p = GetOwningPlayer(u)
    local integer Counting = GetPlayerId(p)
    if GetSpellAbilityId() == NEXTPAGEID then
        if GetLocalPlayer() == p then
            call ClearSelection()
        endif
        call SelectUnit(Tavern[Counter[Counting]],true)
        set Counter[Counting] = Counter[Counting] + 1
        if Counter[Counting] &gt;= Count then
            set Counter[Counting] = 0
        endif
        return false
    endif
    return false
endfunction
    
//===========================================================================
private function Init takes nothing returns nothing
    local integer i = 0
    call TriggerRegisterAnyUnitEventBJ(Sold,EVENT_PLAYER_UNIT_SELL)
    call TriggerAddCondition(Sold,Condition(function Choose))
    call TriggerRegisterAnyUnitEventBJ(Orders,EVENT_PLAYER_UNIT_ISSUED_ORDER)
    call TriggerRegisterAnyUnitEventBJ(Orders,EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
    call TriggerRegisterAnyUnitEventBJ(Orders,EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
    call TriggerAddCondition(Orders, Condition(function BLOCK))
    call TriggerRegisterAnyUnitEventBJ(OnDeath,EVENT_PLAYER_UNIT_DEATH)
    call TriggerAddCondition(OnDeath,Condition(function IsTavern))
    call TriggerRegisterAnyUnitEventBJ(Next,EVENT_PLAYER_UNIT_SPELL_EFFECT)
    call TriggerAddCondition(Next,Condition(function NextPage))
    loop
        exitwhen i &gt; 12
        call TriggerRegisterPlayerChatEvent(ChatRepick,Player(i),&quot;-repick&quot;,true)
        call TriggerAddAction(ChatRepick,function Repick)
        set Counter<i> = 1
        if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then
            call ForceAddPlayer(Playing,Player(i))
            call ForceAddPlayer(Unused,Player(i))
        endif
        set i = i + 1
    endloop
    set ChosenB = Filter(function RepickCond)
    if SELECTIONTIME &gt; 0 then
        call TimerStart(Board,SELECTIONTIME,false,function End)
        call TimerStart(CreateTimer(),0.,false,function AfterInit)
    endif
    set Colours[0] =&quot;|cffff0000&quot;
    set Colours[1] = &quot;|cff0000ff&quot;
    set Colours[2] = &quot;|cff93ffc9&quot;
    set Colours[3] = &quot;|cff400080&quot;
    set Colours[4] = &quot;|cffffff00&quot;
    set Colours[5] = &quot;|cffff8000&quot;
    set Colours[6] = &quot;|cff00c400&quot;
    set Colours[7] = &quot;|cffff80c0&quot;
    set Colours[8] = &quot;|cff808080&quot;
    set Colours[9] = &quot;|cffc1c1ff&quot;
    set Colours[10] = &quot;|cff5e5e2f&quot;
    set Colours[11] = &quot;|cff004000&quot;
    set Colours[12] = &quot;|cff000000&quot;
endfunction

endlibrary</i></u></u>
 

Attachments

  • HTS v1.00.w3x
    66.2 KB · Views: 282
  • HTS PIC.jpg
    HTS PIC.jpg
    362 KB · Views: 414

BlackRose

Forum User
Reaction score
239
Tasty, I like. I think its useful for many AoS / Arena map where you have a Tavern. Why is it HRS? Hero ??? System? Hero Tavern System?
 

wraithseeker

Tired.
Reaction score
122
The syntax error is noted obviously and this is a hero selection system too. Why the hell would you implement 2 hero selection when this one does it's job well?
 

Nexor

...
Reaction score
74
could you make it so that if the selection time is 0 then players will have infinite time to choose?
 

Gwypaas

hook DoNothing MakeGUIUsersCrash
Reaction score
50
It doesn't matter since it's a small optimization unless you can point out big or errors that are worth fixing.

Do you want to get it approved? It doesn't matter if it's a "small" optimize. The systms which gets approved must be perfect so they cannot cause any bugs in anyway nor be anywhere near a bottleneck when you can fix it.

Stop trying to avoid the problem, just go fix it.


Edit - You should really recode this system to use Structs instead of this gay syntax. So you just create a new tavern with like
JASS:
local tavern t = tavern.create(x, y)
and then you just add the extra functionality you want.
 

Larcenist

REP: Respect, Envy, Prosperity?
Reaction score
211
While the term "perfect" is to be used with caution any code submitted should ta least aim for optimization, readability and most of all, no utterly useless lines such as the one pointed out by Komaqtion.
 
Reaction score
91
Style of coding is something you cannot force someone to change depending on your own tastes. So either quit it with the immature flaming, Gwypass, or say something less offending and mocking because it is really annoying from a side view.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top