-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathControlSiegeTanks.cpp
152 lines (125 loc) · 4.07 KB
/
ControlSiegeTanks.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "BasicSc2Bot.h"
using namespace sc2;
// ------------------ Helper Functions ------------------
// Determine whether siege tank should transform to Siege Mode, or Unsiege
bool BasicSc2Bot::SiegeTankInCombat(const Unit* unit) {
if (!unit) {
return false;
}
// Detect radius of the Siege Tank
const float enemy_detection_radius = 13.5f;
bool enemy_nearby = false;
// Check for nearby enemies within the detection radius
for (const auto& enemy_unit :
Observation()->GetUnits(Unit::Alliance::Enemy)) {
// Skip trivial and worker units
if (IsTrivialUnit(enemy_unit) || IsWorkerUnit(enemy_unit)) {
continue;
}
// Calculate distance to enemy
float distance_to_enemy = Distance2D(unit->pos, enemy_unit->pos);
if (distance_to_enemy <= enemy_detection_radius) {
enemy_nearby = true;
break;
}
}
return enemy_nearby;
}
// ------------------ Main Functions ------------------
// Main function to control Siege Tanks
void BasicSc2Bot::ControlSiegeTanks() {
SiegeMode();
TargetSiegeTank();
}
// Transform Siege Tanks to Siege Mode or Unsiege
void BasicSc2Bot::SiegeMode() {
// Get all Siege Tanks
const Units siege_tanks = Observation()->GetUnits(
Unit::Alliance::Self, IsUnit(UNIT_TYPEID::TERRAN_SIEGETANK));
const Units siege_tanks_sieged = Observation()->GetUnits(
Unit::Alliance::Self, IsUnit(UNIT_TYPEID::TERRAN_SIEGETANKSIEGED));
if (siege_tanks.empty() && siege_tanks_sieged.empty()) { // No Siege Tanks
return;
}
// Siege Tanks in combat should be in Siege Mode
for (const auto& tank : siege_tanks) {
if (SiegeTankInCombat(tank)) {
Actions()->UnitCommand(tank, ABILITY_ID::MORPH_SIEGEMODE);
}
}
// Siege Tanks not in combat should be Unsieged
for (const auto& tank : siege_tanks_sieged) {
if (!SiegeTankInCombat(tank)) {
Actions()->UnitCommand(tank, ABILITY_ID::MORPH_UNSIEGE);
}
}
}
// Target mechanics for Siege Tanks
void BasicSc2Bot::TargetSiegeTank() {
if (current_gameloop % 10 != 0)
{
return;
}
// Get all Siege Tanks
const Units siege_tanks_sieged = Observation()->GetUnits(
Unit::Alliance::Self, IsUnit(UNIT_TYPEID::TERRAN_SIEGETANKSIEGED));
if (siege_tanks_sieged.empty()) {
return;
}
for (const auto& siege_tank : siege_tanks_sieged) {
// Initialize variables to find the best target
const Unit* best_target = nullptr;
float best_score = -1.0f;
// Get all enemy units
for (const auto& enemy_unit :
Observation()->GetUnits(Unit::Alliance::Enemy)) {
// Skip invalid or dead units
if (!enemy_unit || !enemy_unit->is_alive) {
continue;
}
// Calculate priority score for this enemy
float score = 0.0f;
// 1. Priority: Heavy Armor (e.g., Stalkers, Marauiders...etc)
if (std::find(heavy_armor_units.begin(), heavy_armor_units.end(),
enemy_unit->unit_type) != heavy_armor_units.end()) {
score += 200.0f;
}
// 2. Priority: Packed Enemies (AOE Potential)
int packed_count = 0;
for (const auto& nearby_enemy :
Observation()->GetUnits(Unit::Alliance::Enemy)) {
if (nearby_enemy != enemy_unit &&
Distance2D(enemy_unit->pos, nearby_enemy->pos) < 1.25f) {
packed_count++;
}
}
// Add 10 points for each nearby enemy
score += packed_count * 10.0f;
// 3. Priority: Enemies close to one-shot
// Tank damage is 40(Light) or 70(Armored) in Siege Mode
float health_difference = 0.0f;
if (std::find(heavy_armor_units.begin(), heavy_armor_units.end(),
enemy_unit->unit_type) != heavy_armor_units.end()) {
health_difference =
std::abs((enemy_unit->health + enemy_unit->shield) - 70.0f);
}
else {
health_difference =
std::abs((enemy_unit->health + enemy_unit->shield) - 40.0f);
}
score += 200.0f / (health_difference + 1.0f);
// 4. The Rest (Prioritize closer targets)
score +=
1.0f / (Distance2D(siege_tank->pos, enemy_unit->pos) + 1.0f);
// Update best target based on score
if (score > best_score) {
best_score = score;
best_target = enemy_unit;
}
}
// Issue attack command if a valid target is found
if (best_target) {
Actions()->UnitCommand(siege_tank, ABILITY_ID::ATTACK, best_target);
}
}
}