00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "ai_shoot_module.h"
00023 #include "../include/action_handler.h"
00024 #include "../interface/game_msg.h"
00025 #include "../map/map.h"
00026 #include "../network/randomsync.h"
00027 #include "../team/macro.h"
00028 #include "../tool/error.h"
00029 #include "../tool/math_tools.h"
00030 #include "../tool/string_tools.h"
00031
00032 #include <iostream>
00033
00034
00035
00036
00037 bool AIShootModule::FindShootableEnemy()
00038 {
00039 FOR_ALL_LIVING_ENEMIES(team, character) {
00040 if ( IsDirectlyShootable(*character) ) {
00041 m_enemy = &(*character);
00042 return true;
00043 }
00044 }
00045
00046 return false;
00047 }
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 bool AIShootModule::IsDirectlyShootable(Character& character)
00059 {
00060 Point2i pos = ActiveCharacter().GetCenter();
00061 Point2i arrival = character.GetCenter();
00062 Point2i departure = pos;
00063 Point2i delta_pos;
00064
00065 double original_angle = pos.ComputeAngle(arrival);
00066
00067
00068
00069 while (pos != arrival) {
00070
00071
00072 if ( !world.EstDansVide(pos.x, pos.y)) {
00073 return false;
00074 }
00075
00076
00077 if ( world.EstHorsMondeX(pos.x) || world.EstHorsMondeY(pos.y) ) {
00078 break;
00079 }
00080
00081
00082 FOR_ALL_CHARACTERS(team, other_character) {
00083 if ( &(*other_character) != &ActiveCharacter()
00084 && &(*other_character) != &character ) {
00085
00086 if ( other_character->GetTestRect().Contains(pos) )
00087 return false;
00088
00089 }
00090 }
00091
00092
00093 int diff_x = pos.x - arrival.x;
00094 int diff_y = pos.y - arrival.y;
00095
00096 delta_pos.x = 0;
00097 delta_pos.y = 0;
00098
00099 if (abs(diff_x) > abs(diff_y)) {
00100 if (pos.x < arrival.x)
00101 delta_pos.x = 1;
00102 else
00103 delta_pos.x = -1;
00104 } else {
00105 if (pos.y < arrival.y)
00106 delta_pos.y = 1;
00107 else
00108 delta_pos.y = -1;
00109 }
00110
00111 pos += delta_pos;
00112 }
00113
00114 m_angle = original_angle;
00115
00116
00117 if (departure.x > arrival.x) {
00118 ActiveCharacter().SetDirection(Body::DIRECTION_LEFT);
00119 m_angle = InverseAngleRad(m_angle);
00120 } else {
00121 ActiveCharacter().SetDirection(Body::DIRECTION_RIGHT);
00122 }
00123
00124
00125 std::string s = "Try to shoot "+character.GetName();
00126 char buff[3];
00127 sprintf(buff, "%f", m_angle);
00128 s += " with angle ";
00129 s += buff;
00130 GameMessages::GetInstance()->Add(s);
00131
00132 return true;
00133 }
00134
00135
00136
00137
00138
00139 bool AIShootModule::FindProximityEnemy()
00140 {
00141 FOR_ALL_LIVING_ENEMIES(team, character) {
00142 if ( IsNear(*character) ) {
00143 m_enemy = &(*character);
00144 return true;
00145 }
00146 }
00147
00148 return false;
00149
00150
00151
00152
00153
00154
00155
00156 }
00157
00158
00159
00160
00161
00162
00163 bool AIShootModule::IsNear(Character& character)
00164 {
00165 uint delta_x = abs(character.GetX() - ActiveCharacter().GetX());
00166 uint delta_y = abs(character.GetY() - ActiveCharacter().GetY());
00167
00168 if (delta_x > 300)
00169 return false;
00170
00171 if (delta_y > 100)
00172 return false;
00173
00174 return true;
00175 }
00176
00177
00178
00179
00180 void AIShootModule::Shoot()
00181 {
00182 if (m_current_time > m_last_shoot_time + 1 ||
00183 m_last_shoot_time == 0) {
00184 ActiveTeam().GetWeapon().NewActionShoot();
00185 m_last_shoot_time = m_current_time;
00186 }
00187
00188 if (!(ActiveTeam().GetWeapon().EnoughAmmoUnit())) {
00189 m_has_finished = true;
00190 ActiveCharacter().body->StartWalk();
00191 }
00192 }
00193
00194 Character* AIShootModule::FindEnemy()
00195 {
00196 if (m_has_finished) {
00197 return NULL;
00198 }
00199
00200 if (m_enemy != NULL && !(m_enemy->IsDead())) {
00201 return m_enemy;
00202 }
00203
00204 m_current_strategy = NO_STRATEGY;
00205
00206 if (FindProximityEnemy()) {
00207 GameMessages::GetInstance()->Add(ActiveCharacter().GetName()+" has decided to injured "
00208 + m_enemy->GetName());
00209
00210 m_current_strategy = NEAR_FROM_ENEMY;
00211
00212
00213 uint selected = uint(randomSync.GetDouble(0.0, 3.5));
00214
00215 switch (selected) {
00216 case 0:
00217 case 1:
00218 ActiveTeam().SetWeapon(Weapon::WEAPON_DYNAMITE);
00219 if (ActiveTeam().GetWeapon().EnoughAmmo()) break;
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 case 3:
00230 default:
00231 ActiveTeam().SetWeapon(Weapon::WEAPON_MINE);
00232 }
00233 m_angle = 0;
00234 ActiveCharacter().SetFiringAngle(m_angle);
00235 }
00236 else if (FindShootableEnemy()) {
00237
00238 m_current_strategy = SHOOT_FROM_POINT;
00239 GameMessages::GetInstance()->Add(ActiveCharacter().GetName()+" will shoot "
00240 + m_enemy->GetName());
00241
00242
00243 uint selected = uint(randomSync.GetDouble(0.0, 3.5));
00244 switch (selected) {
00245 case 0:
00246 ActiveTeam().SetWeapon(Weapon::WEAPON_SHOTGUN);
00247 if (ActiveTeam().GetWeapon().EnoughAmmo()) break;
00248 case 1:
00249 ActiveTeam().SetWeapon(Weapon::WEAPON_SNIPE_RIFLE);
00250 if (ActiveTeam().GetWeapon().EnoughAmmo()) break;
00251 case 2:
00252
00253
00254 case 3:
00255 default:
00256 ActiveTeam().SetWeapon(Weapon::WEAPON_GUN);
00257 }
00258
00259 double angle = BorneDouble(m_angle, - (ActiveTeam().GetWeapon().GetMaxAngle()),
00260 - (ActiveTeam().GetWeapon().GetMinAngle()) );
00261
00262 if (AbsReel(angle-m_angle) < 0.08726) {
00263 ActiveCharacter().SetFiringAngle(m_angle);
00264 } else {
00265 GameMessages::GetInstance()->Add("Angle is too wide!");
00266
00267 m_current_strategy = NO_STRATEGY;
00268 m_angle = 0;
00269 m_enemy = NULL;
00270
00271 return m_enemy;
00272 }
00273 }
00274
00275
00276 if ( ! ActiveTeam().GetWeapon().EnoughAmmo() ) {
00277 ActiveTeam().SetWeapon(Weapon::WEAPON_SKIP_TURN);
00278 }
00279
00280 ChooseDirection();
00281
00282 return m_enemy;
00283 }
00284
00285 void AIShootModule::ChooseDirection()
00286 {
00287 if ( m_enemy ) {
00288
00289 if ( ActiveCharacter().GetCenterX() < m_enemy->GetCenterX())
00290 ActiveCharacter().SetDirection(Body::DIRECTION_RIGHT);
00291 else
00292 ActiveCharacter().SetDirection(Body::DIRECTION_LEFT);
00293
00294 }
00295 }
00296
00297 bool AIShootModule::Refresh(uint current_time)
00298 {
00299 if (m_has_finished) {
00300 return true;
00301 }
00302
00303 m_current_time = current_time;
00304
00305 FindEnemy();
00306
00307 switch (m_current_strategy) {
00308
00309 case NO_STRATEGY:
00310
00311
00312 break;
00313
00314 case NEAR_FROM_ENEMY:
00315
00316 FOR_ALL_LIVING_ENEMIES(team, character) {
00317 if ( abs((*character).GetX() - ActiveCharacter().GetX()) <= 10 &&
00318 abs ((*character).GetY() - ActiveCharacter().GetY()) < 60 ) {
00319
00320 if (&(*character) != m_enemy) {
00321 GameMessages::GetInstance()->Add(ActiveCharacter().GetName()+" changes target : "
00322 + (*character).GetName());
00323 }
00324 m_enemy = &(*character);
00325 Shoot();
00326 }
00327 }
00328 break;
00329
00330 case SHOOT_FROM_POINT:
00331 Shoot();
00332 return false;
00333 break;
00334 }
00335
00336 return true;
00337 }
00338
00339
00340
00341
00342
00343 void AIShootModule::BeginTurn()
00344 {
00345 m_enemy = NULL;
00346 m_last_shoot_time = 0;
00347 m_angle = 0;
00348 m_current_strategy = NO_STRATEGY;
00349 m_has_finished = false;
00350
00351
00352 ActiveCharacter().SetDirection( randomSync.GetBool()?Body::DIRECTION_LEFT:Body::DIRECTION_RIGHT );
00353 }
00354
00355 AIShootModule::AIShootModule()
00356 {
00357 std::cout << "o Artificial Intelligence Shoot module initialization" << std::endl;
00358 }