/* Starshatter: The Open Source Project Copyright (c) 2021-2024, Starshatter: The Open Source Project Contributors Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors Copyright (c) 1997-2006, Destroyer Studios LLC. AUTHOR: John DiCamillo OVERVIEW ======== Low-Level Artificial Intelligence class for Ground Units */ #include "GroundAI.h" #include "SteerAI.h" #include "System.h" #include "Ship.h" #include "ShipDesign.h" #include "Shield.h" #include "Sim.h" #include "Player.h" #include "CarrierAI.h" #include "Contact.h" #include "Weapon.h" #include "WeaponGroup.h" #include "Clock.h" #include "Physical.h" // +----------------------------------------------------------------------+ GroundAI::GroundAI(SimObject* s) : ship((Ship*) s), target(0), subtarget(0), exec_time(0), carrier_ai(0) { Sim* sim = Sim::GetSim(); Ship* pship = sim->GetPlayerShip(); int player_team = 1; int ai_level = 1; if (pship) player_team = pship->GetIFF(); Player* player = Player::GetCurrentPlayer(); if (player) { if (ship && ship->GetIFF() && ship->GetIFF() != player_team) { ai_level = player->AILevel(); } else if (player->AILevel() == 0) { ai_level = 1; } } // evil alien ships are *always* smart: if (ship && ship->GetIFF() > 1 && ship->Design()->auto_roll > 1) { ai_level = 2; } if (ship && ship->GetHangar() && ship->GetCommandAILevel() > 0) carrier_ai = new CarrierAI(ship, ai_level); } // +--------------------------------------------------------------------+ GroundAI::~GroundAI() { delete carrier_ai; } // +--------------------------------------------------------------------+ void GroundAI::SetTarget(SimObject* targ, System* sub) { if (target != targ) { target = targ; if (target) Observe(target); } subtarget = sub; } // +--------------------------------------------------------------------+ bool GroundAI::Update(SimObject* obj) { if (obj == target) { target = 0; subtarget = 0; } return SimObserver::Update(obj); } const char* GroundAI::GetObserverName() const { static char name[64]; sprintf_s(name, "GroundAI(%s)", ship->Name()); return name; } // +--------------------------------------------------------------------+ void GroundAI::SelectTarget() { SimObject* potential_target = 0; // pick the closest combatant ship with a different IFF code: double target_dist = 1.0e15; Ship* current_ship_target = 0; ListIter c_iter = ship->ContactList(); while (++c_iter) { Contact* contact = c_iter.value(); int c_iff = contact->GetIFF(ship); Ship* c_ship = contact->GetShip(); Shot* c_shot = contact->GetShot(); bool rogue = false; if (c_ship) rogue = c_ship->IsRogue(); if (rogue || c_iff > 0 && c_iff != ship->GetIFF() && c_iff < 1000) { if (c_ship && !c_ship->InTransition()) { // found an enemy, check distance: double dist = (ship->Location() - c_ship->Location()).length(); if (!current_ship_target || (c_ship->Class() <= current_ship_target->Class() && dist < target_dist)) { current_ship_target = c_ship; target_dist = dist; } } } potential_target = current_ship_target; } SetTarget(potential_target); } // +--------------------------------------------------------------------+ int GroundAI::Type() const { return SteerAI::GROUND; } // +--------------------------------------------------------------------+ void GroundAI::ExecFrame(double secs) { const int exec_period = 1000; if ((int) Clock::GetInstance()->GameTime() - exec_time > exec_period) { exec_time = (int) Clock::GetInstance()->GameTime(); SelectTarget(); } if (ship) { Shield* shield = ship->GetShield(); if (shield) shield->SetPowerLevel(100); ListIter iter = ship->Weapons(); while (++iter) { WeaponGroup* group = (WeaponGroup*) iter.value(); if (group->NumWeapons() > 1 && group->CanTarget(Ship::DROPSHIPS)) group->SetFiringOrders(Weapon::POINT_DEFENSE); else group->SetFiringOrders(Weapon::AUTO); group->SetTarget((Ship*) target, 0); } if (carrier_ai) carrier_ai->ExecFrame(secs); } }