-
Notifications
You must be signed in to change notification settings - Fork 3
/
ControlMarines.cpp
212 lines (178 loc) · 5.34 KB
/
ControlMarines.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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include "BasicSc2Bot.h"
using namespace sc2;
// ------------------ Helper Functions ------------------
// Check if the ramp structure is intact
bool BasicSc2Bot::IsRampIntact() {
bool ramp_intact = true;
for (const auto& building : ramp_depots) {
if (!building || building->unit_type == UNIT_TYPEID::TERRAN_SUPPLYDEPOTLOWERED) {
ramp_intact = false;
break;
}
}
for (const auto& building : ramp_middle) {
if (!building || building->is_flying) {
ramp_intact = false;
break;
}
}
return ramp_intact;
}
// Check if the unit is near the ramp
bool BasicSc2Bot::IsNearRamp(const Unit* unit) {
if (!unit) { // Null check
return false;
}
bool near_ramp = false;
const float ramp_check_distance = 5.0f; // Distance to check for ramp proximity
// Check if the unit is near the ramp
for (const auto& building : ramp_depots) {
if (building &&
Distance2D(unit->pos, building->pos) < ramp_check_distance) {
near_ramp = true;
break;
}
}
for (const auto& building : ramp_middle) {
if (building &&
Distance2D(unit->pos, building->pos) < ramp_check_distance) {
near_ramp = true;
break;
}
}
return near_ramp;
}
// Get closest target to the unit
const Unit* BasicSc2Bot::GetClosestTarget(const Unit* unit) {
if (!unit) { // Null check
return nullptr;
}
const Unit* target = nullptr;
float min_distance = std::numeric_limits<float>::max();
// Find the closest enemy
for (const auto& enemy_unit :
Observation()->GetUnits(Unit::Alliance::Enemy)) {
// Skip invalid or dead units
if (!enemy_unit || !enemy_unit->is_alive) {
continue;
}
// Calculate distance to the enemy unit
float distance_to_enemy = Distance2D(unit->pos, enemy_unit->pos);
// Find the closest unit
if (distance_to_enemy < min_distance && distance_to_enemy < 13.0f) {
min_distance = distance_to_enemy;
target = enemy_unit;
}
}
return target;
}
// Move Marine to a new position to perform kite
void BasicSc2Bot::KiteMarine(const Unit* marine, const Unit* target,
bool advance, float distance) {
Point2D direction =
advance ? (target->pos - marine->pos) : (marine->pos - target->pos);
float length =
std::sqrt(direction.x * direction.x + direction.y * direction.y);
// Normalize the vector
if (length > 0) {
direction /= length;
}
// Move the Marine to the new position
Point2D new_position = marine->pos + direction * distance;
Actions()->UnitCommand(marine, ABILITY_ID::MOVE_MOVE, new_position);
}
// ------------------ Main Functions ------------------
// Main function to control Marines
void BasicSc2Bot::ControlMarines() {
KillScouts();
TargetMarines();
}
// Target agressive scouts(Reapers) with Marines
void BasicSc2Bot::KillScouts() {
// Get all Marines
Units marines = Observation()->GetUnits(Unit::Alliance::Self,
IsUnit(UNIT_TYPEID::TERRAN_MARINE));
// Get all enemy units
Units enemies = Observation()->GetUnits(Unit::Alliance::Enemy);
// Check if there are no Marines or enemies
if (marines.empty() || enemies.empty()) {
return;
}
// Attack the scouts
for (const auto& enemy_unit : enemies) {
if (enemy_unit->unit_type == UNIT_TYPEID::TERRAN_REAPER &&
Distance2D(enemy_unit->pos, start_location) <= 15.0f) {
for (const auto& marine : marines) {
if (marine->orders.empty()) {
Actions()->UnitCommand(marine, ABILITY_ID::ATTACK_ATTACK,
enemy_unit);
}
}
}
}
}
// Target mechanics for Marines
void BasicSc2Bot::TargetMarines() {
// Get all Marines
Units marines = Observation()->GetUnits(Unit::Alliance::Self,
IsUnit(UNIT_TYPEID::TERRAN_MARINE));
if (marines.empty()) { // Check if there are no Marines
return;
}
// Marine parameters
float marine_vision = 0.0f; // Marine's vision(default)
const float fallback_distance =
1.0f; // Distance to kite away for melee units
const float advance_distance = 0.5f; // Distance to close for ranged units
// For each Marine
for (const auto& marine : marines) {
const Unit* target = GetClosestTarget(marine);
if (target) {
// Check if the target is a melee unit
bool is_melee =
melee_units.find(target->unit_type) != melee_units.end();
if (IsNearRamp(marine)) {
marine_vision = 8.0f;
}
else {
marine_vision = 13.0f;
}
// Check if the target is within the Marine's vision
if (Distance2D(marine->pos, target->pos) > marine_vision) {
continue;
}
// Attack whenever possible
if (marine->weapon_cooldown == 0.0f) {
Actions()->UnitCommand(marine, ABILITY_ID::ATTACK_ATTACK,
target);
}
// Do not Kite if the ramp is intact and the Marine is near the ramp
else if (IsRampIntact() && IsNearRamp(marine)) {
continue;
}
else {
if (is_melee && Distance2D(marine->pos, target->pos) <= 4.5f) {
// Fall back if the target is melee
KiteMarine(marine, target, false, fallback_distance);
}
else {
// Check if the target is ranged but not a structure
const UnitTypeData& target_type_data =
Observation()->GetUnitTypeData().at(target->unit_type);
bool is_structure = false;
for (const auto& attribute : target_type_data.attributes) {
if (attribute == Attribute::Structure) {
is_structure = true;
break;
}
}
// Advance if the target is ranged and not a structure
if (!is_structure &&
Distance2D(marine->pos, target->pos) > 4.5f) {
KiteMarine(marine, target, true, advance_distance);
}
}
}
}
}
}