Team and Hero Decision Evaluation - Nostrademous/Dota2-FullOverwrite GitHub Wiki

-------------------------------------------------------------------------------
--- AUTHOR: Nostrademous
--- GITHUB REPO: https://github.com/Nostrademous/Dota2-FullOverwrite
-------------------------------------------------------------------------------

require( GetScriptDirectory().."/constants" )

local freqTeamThink = 0.1
local lastTeamThink = -1000.0

local teamForcedPlayerAssignments = {}

function MainThink()
    
    -- Exercise TeamThink() at coded frequency
    if GameTime() > lastTeamThink then
        TeamThink()
        lastTeamThink = GameTime() + freqTeamThink
    end
    
    -- Exercise individual Hero think at every frame (if possible).
    -- HeroThink() will check assignments from TeamThink()
    -- for that individual Hero that it should perform, if any.
    local bot = GetBot()
    return HeroThink(bot)
end

function TeamThink()

    -- This is at top as all item purchases are Immediate actions,
    -- and therefore won't affect any other decision making.
    -- Intent is to smartly determine which heroes should purchases
    -- Team items like Tome of Knowledge, Wards, Dust/Sentry, and
    -- even stuff like picking up Gem, Aegis, Cheese, etc.
    ConsiderTeamWideItemAcquisition()

    -- This is at top as all courier actions are Immediate actions,
    -- and therefore won't affect any other decision making.
    -- Intent is to make courier use more efficient by aligning
    -- the purchases of multiple localized heroes together.
    ConsiderTeamWideCourierUse()

    -- This is a fight orchestration evaluator. It will determined
    -- based on the global picture and location of all enemy and
    -- friendly units whether we should pick a fight whether in
    -- the middle of nowhere, as part of a push/defense of a lane,
    -- or even as part of an ally defense. All Heroes involved will
    -- have their actionQueues filled out by this function and
    -- their only responsibility will be to do those actions. Note,
    -- heroes with Global skills (Invoker Sun Strike, Zeus Ult, etc.)
    -- can be part of this without actually being present in the area.
    ConsiderTeamFightAssignment()
    
    -- Determine which lanes should be pushed and which Heroes should
    -- be part of the push.
    ConsiderTeamLanePush()
    
    -- Determine which lanes should be defended and which Heroes should
    -- be part of the defense.
    ConsiderTeamLaneDefense()
    
    -- Determine which hero (based on their role) should farm where. By
    -- default it is best to probably leave their default lane assignment,
    -- but if they are getting killed repeatedly we could rotate them. This
    -- also considers jungling assignments and lane rotations.
    ConsiderTeamFarmDesignation()
    
    -- Determine if we should Roshan and which Heroes should be part of it.
    ConsiderTeamRoshan()
    
    -- Determine if we should seek out a specific enemy for a kill attempt
    -- and which Heroes should be part of the kill.
    ConsiderTeamRoam()
    
    -- If we see a rune, determine if any specific Heroes should get it 
    -- (to fill a bottle for example). If not the hero that saw it will get it.
    ConsiderTeamRune()
    
    -- If any of our Heroes needs to heal up, Shrines are an option.
    -- However, we should be smart about the use and see if any other 
    -- friends could benefit as well rather than just being selfish.
    ConsiderTeamShrine()
end

function HeroThink(bot)
    local highestDesireValue = 0.0
    local highestDesireMode = constants.MODE_NONE
    
    local evaluatedDesireValue = BOT_MODE_DESIRE_NONE 
    
    -- Consider incoming projectiles or nearby AOE and if we can evade.
    -- This is of highest importance b/c if we are stunned/disabled we 
    -- cannot do any of the other actions we might be asked to perform.
    evaluatedDesireValue = ConsiderEvading(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_EVADE
    end
    
    -- If we really want to evade ( >= 0.9 ); short-circuit 
    -- consideration of other modes for better performance.
    if evaluatedDesireValue >= BOT_MODE_DESIRE_VERYHIGH then
        return highestDesireMode
    end
    
    -- Fight orchestration is done at a global Team level.
    -- This just checks if we are given a fight target and a specific
    -- action queue to execute as part of the fight.
    evaluatedDesireValue = ConsiderAttacking(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_FIGHT
    end
    
    -- Which Heroes should be present for Shrine heal is made at Team level.
    -- This just tells us if we should be part of this event.
    evaluatedDesireValue = ConsiderShrine(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_SHRINE
    end
    
    -- Determine if we should retreat. Team Fight Assignements can 
    -- over-rule our desire though. It might be more important for us to die
    -- in a fight but win the over-all battle. If no Team Fight Assignment, 
    -- then it is up to the Hero to manage their safety from global and
    -- tower/creep damage.
    evaluatedDesireValue = ConsiderRetreating(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_RETREAT
    end
    
    -- If we really want to Attack, Use Shrine or Retreat ( >= 0.75 ); 
    -- short-circuit consideration of other modes for better performance.
    if evaluatedDesireValue >= BOT_MODE_DESIRE_HIGH then
        return highestDesireMode
    end
    
    -- Courier usage is done at Team wide level. We can do our own 
    -- shopping at secret/side shop if we are informed that the courier
    -- will be unavailable to use for a certain period of time.
    evaluatedDesireValue = ConsiderSecretAndSideShop(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_SPECIALSHOP
    end
    
    -- The decision is made at Team level. 
    -- This just checks if the Hero is part of the push, and if so, 
    -- what lane.
    evaluatedDesireValue = ConsiderPushingLane(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_PUSHLANE
    end
    
    -- The decision is made at Team level.
    -- This just checks if the Hero is part of the defense, and 
    -- where to go to defend if so.
    evaluatedDesireValue = ConsiderDefendingLane(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_DEFENDLANE
    end
    
    -- This is a localized lane decision. An ally defense can turn into an 
    -- orchestrated Team level fight, but that will be determined at the 
    -- Team level. If not a fight, then this is just a "buy my retreating
    -- friend some time to go heal up / retreat".
    evaluatedDesireValue = ConsiderDefendingAlly(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_DEFENDALLY
    end
    
    -- Roaming decision are made at the Team level to keep all relevant
    -- heroes informed of the upcoming kill opportunity. 
    -- This just checks if this Hero is part of the Gank.
    evaluatedDesireValue = ConsiderRoam(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_ROAM
    end
    
    -- The decision if and who should get Rune is made Team wide.
    -- This just checks if this Hero should get it.
    evaluatedDesireValue = ConsiderRune(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_RUNEPICKUP
    end
    
    -- The decision to Roshan is done in TeamThink().
    -- This just checks if this Hero should be part of the effort.
    evaluatedDesireValue = ConsiderRoshan(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_ROSHAN
    end
    
    -- Farming assignments are made Team Wide.
    -- This just tells the Hero where he should go to Farm.
    evaluatedDesireValue = ConsiderFarm(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_FARM
    end
    
    -- Laning assignments are made Team Wide for Pushing & Defending.
    -- Laning assignments are initially determined at start of game/hero-selection.
    -- This just tells the Hero which Lane he is supposed to be in.
    evaluatedDesireValue = ConsiderLaning(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_LANING
    end
    
    -- Warding is done on a per-lane basis. This evaluates if this Hero
    -- should ward, and where. (might be a team wide thing later)
    evaluatedDesireValue = ConsiderWarding(bot)
    if evaluatedDesireValue > highestDesireValue then
        highestDesireValue = evaluatedDesireValue
        highestDesireMode = constants.MODE_WARD
    end
    
    return highestDesireMode
end