Zh/Dota Bot Scripting

== 概述 ==
Dota中的机器人脚本通过lua语言实现。该过程是服务器级别的，因此并不需要实现检查屏幕像素或是模拟鼠标点击这样的操作；脚本会检查游戏状态并直接发送指令到各部件。脚本可以完全访问所有的实体位置，冷却时间，法力值，等等队伍中的玩家所期望的内容。API所限制的操作脚本也不能执行——战争迷雾中的单位不能被查寻，对非脚本控制的对象不能下达指令，等等。
现在已经有了一个为机器人脚本开发开设的论坛。 dev subforum 
除了lua脚本之外，底层的C++机器人代码仍然存在，而且脚本能够决定对机器人的安排使用多少底层代码。
机器人被组织为三个评估和决策等级：
==== 团队级别 ====
这一级别代码决定全体团队成员去推线，防守，打钱发育，或是去打肉山。这些要求独立存在于任何机器人的状态之外。它们不是强制性的；事实上它们不会决定任何机器人的任何行为。这些要求仅仅为所有机器人提供可用的决策依据。
==== 模式级别 ====
模式是一种高级的要求，机器人会频繁地在模式间切换，选择最高分数的模式作为它们当前行为的模式。例如对线，尝试杀死某个单位，打钱，撤退和推塔等模式。
==== 行为级别 ====
行为是机器人可以基于即时去做的，单独的一件事。这些事粗略地说，是关于鼠标点击和按下按钮的行为——像是移动到某个位置，攻击某个目标，或是购买某样物品。
整体流程上大概是团队级别提供对全体队员当前战略的顶层指导。每个机器人会评估它们各个模式的需求分数，综合考虑团队级别的需求和机器人个体级别的需求。分数最高的模式将变为当前激活模式，该模式将负责控制机器人所表现出的行为。
== 目录结构 ==
所有正在开发中的机器人脚本会放在DOTA2安装文件夹中game/dota/scripts/vscripts/bots目录下。当你上传你的脚本到工坊时，就会上传该目录下的内容。而下载的脚本则放在你Steam安装目录下自己的文件夹中。
机器人脚本被结构化为可以独立实现的多个元素。哪个逻辑被重写取决于你在你的文件中实现了哪个函数。
下面的每个脚本元素都有自己的脚本作用域：
==== 完全接手 ====
如果你想完全地接手控制英雄，你可以在文件名为bot_generic.lua的文件中实现Think()函数，该函数将代替标准机器人智能代码的每一帧。这将会完全地接手控制所有机器人——团队级别和模式级别的智能都不再起作用。你要负责对所有的机器人发出所有的行为指令。如果你仅仅打算控制某个特定的英雄，比如火女(Lina)，你可以在文件名为bot_lina.lua的文件中实现Think()函数。
被完全接手的英雄仍然会受到游戏难度的修正（参考附件B），并仍会计算它们的估计伤害值。
==== 模式重写 ====
如果你想在已有模式体系下修改某个模式逻辑的需求和行为，例如修改对线模式(laning mode)，你可以在文件名为mode_laning_generic.lua的文件中实现如下函数:
* GetDesire() - 每帧都被调用，需要返回一个0到1之间的浮点值，该值标志了该模式有多大可能成为当前激活模式 
* OnStart() - 当该模式成为当前激活模式时调用
* OnEnd() - 当该模式让出控制权给其他被激活模式时调用
* Think() - 当该模式为当前激活模式时，每帧都被调用。负责发出机器人的行为指令。
你也可以仅重写某个特定英雄的模式逻辑，比如火女(Lina),写在文件名为mode_laning_lina.lua的文件中。如果你想在特定英雄的模式重写时调用泛用的英雄模式代码，请参考附件A的实现细节。
可重写的机器人模式清单如下：
* laning
* attack
* roam
* retreat
* secret_shop
* side_shop
* rune
* push_tower_top
* push_tower_mid
* push_tower_bot
* defend_tower_top
* defend_tower_mid
* defend_tower_bottom
* assemble
* team_roam
* farm
* defend_ally
* evasive_maneuvers
* roshan
* item
* ward
==== 技能和物品使用 ====
如果你只想重写在技能和物品使用时的决策，你可以在文件名为ability_item_usage_generic.lua的文件中实现如下函数:
* ItemUsageThink() - 每帧被调用。负责发出物品使用行为。 
* AbilityUsageThink() - 每帧被调用。负责发出技能使用行为。 
* CourierUsageThink() - 每帧被调用。负责发出信使的相关命令。 
* BuybackUsageThink() - 每帧被调用。负责发出购回指令。 
这些函数中未被重写的，会自动采用默认的C++实现。
你也可以仅重写某个特定英雄对技能/物品使用的逻辑，比如火女(Lina),写在文件名为ability_item_usage_lina.lua的文件中。如果你想在特定英雄对技能/物品使用的逻辑重写时调用泛用的逻辑代码，请参考附件A的实现细节。
==== 物品购买 ====
如果你只想重写在购买物品时的决策，你可以在文件名为item_purchase_generic.lua的文件中实现如下函数：
* ItemPurchaseThink() - 每帧被调用。负责物品购买。
你也可以仅重写某个特定英雄的物品购买逻辑，比如火女(Lina),写在文件名为item_purchase_lina.lua的文件中。
==== 团队级别需求 ====
如果你想提供团队级别需求，你可以在文件名为team_desires.lua的文件中实现如下函数：
* TeamThink() - 每帧被调用。为你的整个队伍提供一次思考调用。
* UpdatePushLaneDesires() - 每帧被调用。返回多个0到1之间的浮点值，分别表示推进上，中，下路的需求值。
* UpdateDefendLaneDesires() - 每帧被调用。返回多个0到1之间的浮点值，分别表示防守上，中，下路的需求值。
* UpdateFarmLaneDesires() - 每帧被调用。返回多个0到1之间的浮点值，分别表示在上，中，下路打钱的需求值。
* UpdateRoamDesire() - 每帧被调用。返回一个0到1之间的浮点值和一个目标句柄，表示某人游走gank特定目标的需求值。
* UpdateRoshanDesire() - 每帧被调用。返回一个0到1之间的浮点值，表示团队去杀肉山的需求值。
这些函数中未被重写的，会自动采用默认的C++实现。
==== 英雄选择 ====
如果你想控制英雄选择和分路，你可以在文件名为hero_selection.lua的文件中实现如下函数：
* Think() - 每帧被调用。负责机器人选择英雄。
* UpdateLaneAssignments() - 在游戏开始前的每一帧被调用。返回玩家ID-分路的值对。
* GetBotNames() - 调用一次，返回玩家名字表。
== API参考 ==
有两种基本级别的API可用：全局的和对特定单位的。以下是这两个级别的函数列表：
==== 全局 ====
(细节待完善)
* GetBot
* GetTeam
* GetTeamMember
* DotaTime
* GameTime
* RealTime
* GetUnitToUnitDistance
* GetUnitToLocationDistance
* GetWorldBounds
* IsLocationPassable
* GetHeightLevel
* GetLocationAlongLane
* GetNeutralSpawners
* GetItemCost
* IsItemPurchasedFromSecretShop
* IsItemPurchasedFromSideShop
* GetItemStockCount
* GetPushLaneDesire
* GetDefendLaneDesire
* GetFarmLaneDesire
* GetRoamDesire
* GetRoamTarget
* GetRoshanDesire
* int GetGameState()
* -Returns the current game state [LINK HERE]
* float GetGameStateTimeRemaining()
* -Returns how much time is remaining in the curren game state, if applicable
* int GetGameMode()
* -Returns the current game mode [LINK HERE]
* int GetHeroPickState()
* -Returns the current hero pick state [LINK HERE]
* IsPlayerInHeroSelectionControl
* SelectHero
* GetSelectedHeroName
* IsInCMBanPhase
* IsInCMPickPhase
* GetCMPhaseTimeRemaining
* GetCMCaptain
* SetCMCaptain
* IsCMBannedHero
* IsCMPickedHero
* CMBanHero
* CMPickHero
* RandomInt
* RandomFloat
* RandomYawVector
* RollPercentage
* Min
* Max
* Clamp
* RemapVal
* RemapValClamped
* DebugDrawLine
* DebugDrawCircle
* DebugDrawText
==== 单位作用域 ====
* Action_ClearActions
* Action_MoveToLocation
* Action_MoveToUnit
* Action_AttackUnit
* Action_AttackMove
* Action_UseAbility
* Action_UseAbilityOnEntity
* Action_UseAbilityOnLocation
* Action_UseAbilityOnTree
* Action_PickUpRune
* Action_PickUpItem
* Action_DropItem
* Action_PurchaseItem
* Action_SellItem
* Action_Buyback
* Action_LevelAbility
* GetDifficulty
* GetUnitName
* GetPlayer
* IsHero
* IsCreep
* IsTower
* IsBuilding
* IsFort
* IsIllusion
* CanBeSeen
* GetActiveMode
* GetActiveModeDesire
* GetHealth
* GetMaxHealth 
* GetMana
* GetMaxMana
* IsAlive
* GetRespawnTime
* HasBuyback
* GetGold
* GetStashValue
* GetCourierValue
* GetLocation
* GetFacing
* GetGroundHeight
* GetAbilityByName
* GetItemInSlot
* IsChanneling
* IsUsingAbility
* GetVelocity
* GetAttackTarget
* GetLastSeenLocation
* GetTimeSinceLastSeen
* IsRooted
* IsDisarmed
* IsAttackImmune
* IsSilenced
* IsMuted
* IsStunned
* IsHexed
* IsInvulnerable
* IsMagicImmune
* IsNightmared
* IsBlockDisabled
* IsEvadeDisabled
* IsUnableToMiss
* IsSpeciallyDeniable
* IsDominated
* IsBlind
* HasScepter
* WasRecentlyDamagedByAnyHero
* WasRecentlyDamagedByHero
* TimeSinceDamagedByAnyHero
* TimeSinceDamagedByHero
* DistanceFromFountain
* DistanceFromSideShop
* DistanceFromSecretShop
* SetTarget
* GetTarget
* SetNextItemPurchaseValue
* GetNextItemPurchaseValue
* GetAssignedLane
* GetEstimatedDamageToTarget
* GetStunDuration
* GetSlowDuration
* HasBlink
* HasMinistunOnAttack
* HasSilence
* HasInvisibility
* UsingItemBreaksInvisibility
* GetNearbyHeroes
* GetNearbyTowers
* GetNearbyCreeps
* FindAoELocation
* GetExtrapolatedLocation
* GetMovementDirectionStability
* GetActualDamage
== 机器人难度 ==
有五种机器人难度等级：
==== 消极(Passive) ====
* 不能使用技能、物品和信使
* 一直停留在对线模式
* 当试图正补小兵和野怪时，估计的最佳攻击时间随机相差0.4秒
* 当试图反补小兵时，估计的最佳攻击时间随机相差0.2秒
==== 简单(Easy) ====
* 对技能和物品使用有随机0.5到1秒的延迟
* 每隔8秒，技能和物品使用被限制6秒不能使用
* 当某技能或物品被使用时，限制技能和物品使用6秒
* 当试图正补小兵和野怪时，估计的最佳攻击时间随机相差0.4秒
* 当试图反补小兵时，估计的最佳攻击时间随机相差0.2秒
==== 中等(Medium) ====
* 对技能和物品使用有随机0.3到0.6秒的延迟
* 每隔10秒，技能和物品使用被限制3秒不能使用
* 当某技能或物品被使用时，限制技能和物品使用3秒
* 当试图正补小兵和野怪时，估计的最佳攻击时间随机相差0.2秒
* 当试图反补小兵时，估计的最佳攻击时间随机相差0.1秒
==== 困难(Hard) ====
* 对技能和物品使用有随机0.1到0.2秒的延迟
==== 疯狂(Unfair) ====
* 对技能和物品使用有随机0.075到0.15秒的延迟
* 经验和金钱的获取将有25%的加成
== 调试 == 
有很多命令可以帮助你调试脚本机器人的运行。
dota_bot_debug_team
dota_bot_debug_team 显示一个针对特定队伍的面板(2 is Radiant, 3 is Dire)，显示：
* 团队级别的需求值，关于推进(pushing),防守(defending),打钱(farming lanes),肉山(Roshan)
* 机器人名字和等级
* 机器人当前和最大“战斗力”等级(关于战斗力的计算请参考附录D)，可以被命令 dota_bot_debug_team_power 0 设置为关闭
* 当前激活模式，和其他模式的需求值
* 某一机器人的全部模式(可折叠显示)和所有模式的需求值
* 机器人当前行为以及行为目标(如果存在的话)
* 全队所有机器人的执行时间计算，以及单独每个机器人的执行时间
也支持dota_bot_select_debug对特定队伍的线-球绘制。
dota_bot_debug_grid
dota_bot_debug_grid_cycle
dota_bot_debug_minimap
dota_bot_debug_minimap_cycle
在地图或小地图上绘制网格。*_cycle式的指令在不同值间循环，其他指令则直接设置显示模式。
* 0 - 关
* 1 - 不显示天辉
* 2 - 不显示夜魇
* 3 - 天辉的潜在敌人位置
* 4 - 夜魇的潜在敌人位置
* 5 - 天辉的可见敌人
* 6 - 夜魇的可见敌人
* 7 - 地形高度值
* 8 - 可通过体积
dota_bot_select_debug
激活光标选中机器人的如下信息显示：
* 当前机器人的模式和行为
* 当前路径的白色线条
* 上一个攻击目标的蓝色点-线图
* 当前攻击目标的红色点-线图
dota_bot_select_debug_attack
显示光标选中机器人对周围敌人的攻击欲望值
dota_bot_debug_clear
清除dota_bot_select_debug指令和dota_bot_select_debug_attack指令显示的光标选中单位的状态。
dota_bot_debug_lanes
显示对线路径，并以圆圈的形式显示“前线”区域。
dota_bot_debug_ward_locations
以黄色圆圈显示机器人可能考虑插眼的位置。
== 潜在位置 ==
一个对机器人脚本很有用的函数GetUnitPotentialValue()，能够返回一个0到255之间的值，表示在某一特定位置的特定半径内是否有英雄在内。这个值是基于机器人游戏中潜在的坐标网格。
它的运作机制如下： 
* 当队伍丢失一个英雄的视野时，会有一条路径通过地图上的可通过区域，和该英雄的移动速度相同。
* 这个“潜在位置”将开始高亮，然后随着潜在位置圈变得越大越淡而降低。
* 该过程对所有敌方英雄独立进行
它也有一些限制：
* 它不考虑英雄通过传送或其他加速方式进行的位移(如狼人的变身，敌法师的闪烁，等等)
* 它不包括任何关于英雄消失原因和移动目标的估计逻辑——它假定在战争迷雾中的英雄走各条路径有平均可能性。
它仍是在决策时非常有用的功能，尤其是当潜在位置值较高时。你显然不想在英雄离开视野时就不再顾虑它，那么通过潜在坐标网格就可以帮助你估计一个位置是否足够安全。
== 英雄战斗力 ==
你经常需要知道一个队伍中的机器人有多强，或是一个敌人多有威胁。英雄战斗力这个概念就是一个粗略的估计值，对每个英雄在每帧都会刷新该数值。
它的计算方法如下(对每个英雄)：
* 对每个英雄，计算在一个时间段内对敌方英雄造成的总伤害值。
* 这个时间段被定义为5秒，如果英雄能击晕对方将延长一倍，如果能减速对方就延长一半。
* 这个伤害包括攻击伤害加上技能伤害。
* 攻击伤害包括累积和负面效果。
* 技能伤害基于可用的法力值，施法时间，冷却时间，被沉默状态等等。
* 该伤害为对所有敌方英雄取平均值。
此外，我们也计算了每个英雄的原始战斗力，即不考虑冷却时间和英雄状态(法力值，buff效果，等等)的战斗力。它更多地表示在给定时间内该英雄理论上的强度。
需要注意战斗力仅仅意味着输出能力，与坦克和续航能力无关。
GetRawOffensivePower() 函数(得到原始战斗力)能对你看到的队友和敌人使用。
GetOffensivePower() 函数(得到英雄战斗力)只能对友方使用。
== 附录A - 链接到一个泛用的Lua脚本实现 ==
如果你实现了一个泛用的模式或是技能/物品使用脚本，你应该在你的泛用文件头部加入如下代码(需根据实现模块的名字作调整)：
_G._savedEnv = getfenv()
module( "mode_generic_defend_ally", package.seeall )
然后你要在尾部加入如下代码：
for k,v in pairs( mode_generic_defend_ally ) do _G._savedEnv[k] = v end
那么在你的某个特定英雄的脚本中，你可以在文件头部加入:
require( GetScriptDirectory().."/mode_defend_ally_generic" )
这将允许你在特定英雄脚本中调用如下函数:
mode_generic_defend_ally.OnStart();
== 附录B - 可用常量列表 == 
=== 机器人模式 === 
* BOT_MODE_NONE
* BOT_MODE_LANING
* BOT_MODE_ATTACK
* BOT_MODE_ROAM
* BOT_MODE_RETREAT
* BOT_MODE_SECRET_SHOP
* BOT_MODE_SIDE_SHOP
* BOT_MODE_PUSH_TOWER_TOP
* BOT_MODE_PUSH_TOWER_MID
* BOT_MODE_PUSH_TOWER_BOT
* BOT_MODE_DEFEND_TOWER_TOP
* BOT_MODE_DEFEND_TOWER_MID
* BOT_MODE_DEFEND_TOWER_BOT
* BOT_MODE_ASSEMBLE
* BOT_MODE_TEAM_ROAM
* BOT_MODE_FARM
* BOT_MODE_DEFEND_ALLY
* BOT_MODE_EVASIVE_MANEUVERS
* BOT_MODE_ROSHAN
* BOT_MODE_ITEM
* BOT_MODE_WARD
=== 行为需求值 ===
这对于保证所有行为的需求值使用统一语言描述很有帮助。
* BOT_ACTION_DESIRE_NONE - 0.0
* BOT_ACTION_DESIRE_VERYLOW - 0.1
* BOT_ACTION_DESIRE_LOW - 0.25
* BOT_ACTION_DESIRE_MODERATE - 0.5
* BOT_ACTION_DESIRE_HIGH - 0.75
* BOT_ACTION_DESIRE_VERYHIGH - 0.9
* BOT_ACTION_DESIRE_ABSOLUTE - 1.0
=== 模式需求值 ===
这对于保证所有模式的需求值使用统一语言描述很有帮助。
* BOT_MODE_DESIRE_NONE" - 0
* BOT_MODE_DESIRE_VERYLOW - 0.1
* BOT_MODE_DESIRE_LOW - 0.25
* BOT_MODE_DESIRE_MODERATE - 0.5
* BOT_MODE_DESIRE_HIGH - 0.75
* BOT_MODE_DESIRE_VERYHIGH - 0.9
* BOT_MODE_DESIRE_ABSOLUTE - 1.0
=== 伤害类型 === 
* DAMAGE_TYPE_PHYSICAL
* DAMAGE_TYPE_MAGICAL
* DAMAGE_TYPE_PURE
* DAMAGE_TYPE_ALL
=== 难度等级 ===
* DIFFICULTY_INVALID
* DIFFICULTY_PASSIVE
* DIFFICULTY_EASY
* DIFFICULTY_MEDIUM
* DIFFICULTY_HARD
* DIFFICULTY_UNFAIR
=== 物品购买结果 === 
* PURCHASE_ITEM_SUCCESS
* PURCHASE_ITEM_OUT_OF_STOCK
* PURCHASE_ITEM_DISALLOWED_ITEM
* PURCHASE_ITEM_INSUFFICIENT_GOLD
* PURCHASE_ITEM_NOT_AT_HOME_SHOP
* PURCHASE_ITEM_NOT_AT_SIDE_SHOP
* PURCHASE_ITEM_NOT_AT_SECRET_SHOP
* PURCHASE_ITEM_INVALID_ITEM_NAME
=== 游戏模式 === 
* GAMEMODE_NONE
* GAMEMODE_AP
* GAMEMODE_CM
* GAMEMODE_RD
* GAMEMODE_SD
* GAMEMODE_AR
* GAMEMODE_REVERSE_CM
* GAMEMODE_MO
* GAMEMODE_CD
* GAMEMODE_ABILITY_DRAFT
* GAMEMODE_ARDM
* GAMEMODE_1V1MID
* GAMEMODE_ALL_DRAFT (aka Ranked All Pick)
=== 队伍 ===
* TEAM_RADIANT
* TEAM_DIRE
* TEAM_NEUTRAL
* TEAM_NONE
=== 路 === 
* LANE_NONE
* LANE_TOP
* LANE_MID
* LANE_BOT
=== 游戏状态 === 
* GAME_STATE_INIT
* GAME_STATE_WAIT_FOR_PLAYERS_TO_LOAD
* GAME_STATE_HERO_SELECTION
* GAME_STATE_STRATEGY_TIME
* GAME_STATE_PRE_GAME
* GAME_STATE_GAME_IN_PROGRESS
* GAME_STATE_POST_GAME
* GAME_STATE_DISCONNECT
* GAME_STATE_TEAM_SHOWCASE
* GAME_STATE_CUSTOM_GAME_SETUP
* GAME_STATE_WAIT_FOR_MAP_TO_LOAD
* GAME_STATE_LAST
=== 英雄选择状态 === 
* HEROPICK_STATE_NONE
* HEROPICK_STATE_AP_SELECT
* HEROPICK_STATE_SD_SELECT
* HEROPICK_STATE_CM_INTRO
* HEROPICK_STATE_CM_CAPTAINPICK
* HEROPICK_STATE_CM_BAN1
* HEROPICK_STATE_CM_BAN2
* HEROPICK_STATE_CM_BAN3
* HEROPICK_STATE_CM_BAN4
* HEROPICK_STATE_CM_BAN5
* HEROPICK_STATE_CM_BAN6
* HEROPICK_STATE_CM_BAN7
* HEROPICK_STATE_CM_BAN8
* HEROPICK_STATE_CM_BAN9
* HEROPICK_STATE_CM_BAN10
* HEROPICK_STATE_CM_SELECT1
* HEROPICK_STATE_CM_SELECT2
* HEROPICK_STATE_CM_SELECT3
* HEROPICK_STATE_CM_SELECT4
* HEROPICK_STATE_CM_SELECT5
* HEROPICK_STATE_CM_SELECT6
* HEROPICK_STATE_CM_SELECT7
* HEROPICK_STATE_CM_SELECT8
* HEROPICK_STATE_CM_SELECT9
* HEROPICK_STATE_CM_SELECT10
* HEROPICK_STATE_CM_PICK
* HEROPICK_STATE_AR_SELECT
* HEROPICK_STATE_MO_SELECT
* HEROPICK_STATE_FH_SELECT
* HEROPICK_STATE_CD_INTRO
* HEROPICK_STATE_CD_CAPTAINPICK
* HEROPICK_STATE_CD_BAN1
* HEROPICK_STATE_CD_BAN2
* HEROPICK_STATE_CD_BAN3
* HEROPICK_STATE_CD_BAN4
* HEROPICK_STATE_CD_BAN5
* HEROPICK_STATE_CD_BAN6
* HEROPICK_STATE_CD_SELECT1
* HEROPICK_STATE_CD_SELECT2
* HEROPICK_STATE_CD_SELECT3
* HEROPICK_STATE_CD_SELECT4
* HEROPICK_STATE_CD_SELECT5
* HEROPICK_STATE_CD_SELECT6
* HEROPICK_STATE_CD_SELECT7
* HEROPICK_STATE_CD_SELECT8
* HEROPICK_STATE_CD_SELECT9
* HEROPICK_STATE_CD_SELECT10
* HEROPICK_STATE_CD_PICK
* HEROPICK_STATE_BD_SELECT
* HERO_PICK_STATE_ABILITY_DRAFT_SELECT
* HERO_PICK_STATE_ARDM_SELECT
* HEROPICK_STATE_ALL_DRAFT_SELECT
* HERO_PICK_STATE_CUSTOMGAME_SELECT
* HEROPICK_STATE_SELECT_PENALTY
=== 神符 ===
* RUNE_DOUBLEDAMAGE
* RUNE_HASTE
* RUNE_ILLUSION
* RUNE_INVISIBILITY
* RUNE_REGENERATION
* RUNE_BOUNTY
* RUNE_ARCANE
=== 神符状态 ===
* RUNE_STATUS_UNKNOWN
* RUNE_STATUS_AVAILABLE
* RUNE_STATUS_MISSING
Category:Chinese