Skip to content

Feature/rework bot behaviour#2026

Open
Sapphire2408 wants to merge 2 commits intowindy10v10ai:developfrom
Sapphire2408:feature/rework_bot_behaviour
Open

Feature/rework bot behaviour#2026
Sapphire2408 wants to merge 2 commits intowindy10v10ai:developfrom
Sapphire2408:feature/rework_bot_behaviour

Conversation

@Sapphire2408
Copy link
Copy Markdown

Issue

  • fix #9999

Checklist

  • I have tested the changes works well.

Release Note

[b]游戏性更新 v5.00a[/b]

- 修正一些bug和平衡性改动。
[b]Gameplay update v5.00a[/b]

- Fixed some bugs and balance.

Copilot AI review requested due to automatic review settings April 16, 2026 14:21
*/
private lastKnownByTeam: Map<number, Map<number, { power: number; posX: number; posY: number }>> =
new Map();
private ghostsByTeam: Map<number, Map<number, GhostEntry>> = new Map();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expected blank line between class members.

Suggested change
private ghostsByTeam: Map<number, Map<number, GhostEntry>> = new Map();
private ghostsByTeam: Map<number, Map<number, GhostEntry>> = new Map();

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reworks core bot decision-making by introducing shared team-level state (missing enemies, fog “ghost” threat, and target reservations), new math/utility helpers, and significant updates to PUSH/ATTACK/RETREAT desirability plus a new damage-evasion layer.

Changes:

  • Add TeamCommander blackboard with enemy missing counts, fog-ghost threat decay, and target-claim tracking.
  • Rebalance mode desires (ATTACK/RETREAT/PUSH) using power estimation + logistic/linear curves, and add FSA hysteresis + micro-jitter to reduce flip-flopping.
  • Add pure-logic behavior utilities and a new dodge system (HP spike/sustained damage/channeling/clumping) to improve survivability and positioning.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/vscripts/ai/team/team-commander.ts New singleton blackboard for missing-enemy counts, fog ghosts, and target claims
src/vscripts/ai/team/team-commander.test.ts Unit tests for per-team missing counts and ghost lifecycle/decay
src/vscripts/ai/mode/utility-math.ts New helper curves (linear/quadratic/logistic) for desire shaping
src/vscripts/ai/mode/utility-math.test.ts Unit tests for curve behavior including inverted ranges
src/vscripts/ai/mode/power-util.ts New combat power estimator (HP×level adjusted by mana and ult cooldown)
src/vscripts/ai/mode/mode-retreat.ts New retreat desire composition (health panic, missing enemies, power ratio, tower rules)
src/vscripts/ai/mode/mode-retreat.test.ts Tests for retreat desire components and caps
src/vscripts/ai/mode/mode-push.ts Push desire now suppressed by HP and outnumbered power ratio
src/vscripts/ai/mode/mode-push.test.ts Tests for push desire scaling and suppression
src/vscripts/ai/mode/mode-laning.test.ts Adds unit tests for laning desire baseline/threshold behavior
src/vscripts/ai/mode/mode-base.ts Adds hysteresisBonus field for mode stickiness
src/vscripts/ai/mode/mode-attack.ts Attack desire rebuilt around local superiority, tower-dive suppression, missing-enemy bait checks
src/vscripts/ai/mode/mode-attack.test.ts Tests for superiority→desire mapping, tower modifiers, mana scaling, and caps
src/vscripts/ai/mode/bot-behavior-util.ts New pure-logic helpers (tower confidence, flee vectors, orb-walk heuristic, thresholds)
src/vscripts/ai/mode/bot-behavior-util.test.ts Unit tests for pure-logic helpers
src/vscripts/ai/mode/FSA.ts Mode selection now uses score (raw + jitter + hysteresis) but gates switching by raw desire threshold
src/vscripts/ai/mode/FSA.test.ts Tests for switching, hysteresis behavior, and raw-threshold gating
src/vscripts/ai/hero/bot-base.ts Adds personality biases, dodge system, last-hit/kill targeting helpers, target-claim integration, retreat logic changes
src/vscripts/ai/action/action-move.ts Adds centroid-based FleeTowardSafety helper

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

UnitTargetType.HERO,
UnitTargetFlags.NONE,
);
return allies.length > 0 ? allies[0] : undefined;
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindNearestAllyHero() uses ActionFind.Find(... FRIENDLY, HERO ...) and returns allies[0]. Because the query includes this.hero itself, the closest result will typically be self (distance 0), so this helper won’t actually return an ally. Filter out this.hero from the results (and consider returning undefined when no other allies are found).

Suggested change
return allies.length > 0 ? allies[0] : undefined;
for (const ally of allies) {
if (ally !== this.hero) {
return ally;
}
}
return undefined;

Copilot uses AI. Check for mistakes.
Comment on lines +556 to +560
const lastHitCreep = this.FindCreepToLastHit();
if (lastHitCreep) {
if (this.CastCreep()) {
return true;
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lastHitCreep is selected, but the next step calls CastCreep() which (via UseItem.UseItemCreep(...)) targets aroundEnemyCreeps[0] rather than the chosen lastHitCreep. This can fire creep-targeted items/abilities on the wrong creep and miss the last-hit. Consider passing lastHitCreep explicitly (or filtering/reordering the creep list) before attempting creep casts.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +25
/**
* Target reservation: tracks how many bots have claimed each target this
* second. Cleared every updateInterval to prevent stale penalisation.
* Key: entity index (number). Value: claim count.
*/
private targetClaims: Map<number, number> = new Map();

Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetClaims is stored once on the singleton, so claim counts will be shared across both teams. That can cause DIRE/RADIANT bots to penalize each other’s targets if both teams are running bots in the same match. Consider storing claims per team (e.g., Map<DOTATeam_t, Map<entityIndex, count>>).

Copilot uses AI. Check for mistakes.
Comment on lines +115 to +117
this.lastUpdateTimeByTeam[botTeam] = gameTime;
// Reset target claims each second so stale reservations don't persist.
this.targetClaims.clear();
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.targetClaims.clear() clears claims globally, even though UpdateGameState is executed per-team (cooldown tracked in lastUpdateTimeByTeam). With the current design, one team’s update can wipe the other team’s in-progress claims. If claims are moved to per-team storage, clear only the calling team’s claim map here.

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +145
lastKnown.set(playerId, {
power: (hero.GetHealthPercent() / 100) * hero.GetLevel(),
posX: heroPos.x,
posY: heroPos.y,
});
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ghost power is currently computed as (hp%/100) * level, but the rest of the PR introduces PowerUtil.CalculatePowerUnit() (mana ratio + ult cooldown) and uses it for live ally/enemy power. This makes ghost power systematically inconsistent with visible-unit power, which can skew outnumbered/attack decisions right after an enemy disappears. Consider using PowerUtil.CalculatePowerUnit(hero) when recording lastKnown so the same power metric is used everywhere.

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +52
// Sum HP and DPS of all nearby allies + self
const allyHeroes = ActionFind.Find(
hero,
1200,
UnitTargetTeam.FRIENDLY,
UnitTargetType.HERO,
UnitTargetFlags.NONE,
);
let teamHp = hero.GetHealth();
let teamDps = hero.GetLevel() * 10;
for (const ally of allyHeroes) {
teamHp += ally.GetHealth();
teamDps += ally.GetLevel() * 10;
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ActionFind.Find(... FRIENDLY, HERO ...) ultimately wraps FindUnitsInRadius, which includes the querying hero itself (distance 0). Since teamHp/teamDps already start with hero and then iterate allyHeroes, the hero will be double-counted, inflating TowerKillConfidence and reducing tower-dive suppression. Filter allyHeroes to exclude hero (or start sums at 0 and rely on the list) to avoid overconfidence under towers.

Copilot uses AI. Check for mistakes.
);
let teamHp = this.hero.GetHealth();
let teamDps = this.hero.GetLevel() * 10;
for (const ally of allyHeroes) {
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same self-inclusion issue as in ModeAttack: ActionFind.Find(... FRIENDLY, HERO ...) will include this.hero, so teamHp/teamDps (which already include this.hero) get the bot double-counted. That can incorrectly return REWARD_FULL/PARTIAL and suppress dodging when it shouldn’t. Exclude this.hero from allyHeroes (or don’t pre-seed the sums) before computing confidence.

Suggested change
for (const ally of allyHeroes) {
for (const ally of allyHeroes) {
if (ally === this.hero) {
continue;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants