/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Gani Aliguzhinov * Co-authors: * ... * */ #include "WingmanController.h" namespace orxonox { RegisterClass(WingmanController); //ActionpointController contains all common functionality of AI Controllers WingmanController::WingmanController(Context* context) : ActionpointController(context) { RegisterObject(WingmanController); //this->actionTimer_.setTimer(ACTION_INTERVAL, true, createExecutor(createFunctor(&WingmanController::action, this))); this->myLeader_ = 0; this->bFirstAction_ = true; } WingmanController::~WingmanController() { for (size_t i = 0; i < this->actionpoints_.size(); ++i) { if(this->actionpoints_[i]) this->actionpoints_[i]->destroy(); } this->parsedActionpoints_.clear(); this->actionpoints_.clear(); } void WingmanController::XMLPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(WingmanController, XMLPort, xmlelement, mode); } //----in tick, move (or look) and shoot---- void WingmanController::tick(float dt) { if (!this->isActive()) return; SUPER(WingmanController, tick, dt); if (!this->myLeader_) { /*if (this->actionTime_ == 2.0f) { if (this->timeOffset_ >= 0.0f && this->timeOffset_ <= 0.8f && !this->bActionCalled_) { this->action(); this->bActionCalled_ = true; } if (this->timeOffset_ > 1.6f) { this->bActionCalled_ = false; } } else { if (this->timeOffset_ > 0.8f && this->timeOffset_ <= 1.6f && !this->bActionCalled_) { this->action(); this->bActionCalled_ = true; } if (this->timeOffset_ > 2.0f) { this->bActionCalled_ = false; } }*/ } else { /* if (this->timeOffset_ >= this->actionTime_ && this->timeOffset_ <= this->actionTime_ + 0.4f && !this->bActionCalled_) { this->action(); this->bActionCalled_ = true; } if (this->timeOffset_ <= 0.5f) { this->bActionCalled_ = false; }*/ } } //----action for hard calculations---- void WingmanController::action() { if (!this || !this->getControllableEntity()) return; //----If no leader, find one---- if (!this->myLeader_) { ActionpointController* newLeader = (findNewLeader()); this->myLeader_ = newLeader; if (this->myLeader_) { } } //----If have leader, he will deal with logic---- else { } if (!this->myLeader_) { ActionpointController::action(); if (!this || !this->getControllableEntity()) return; } else if (this->myLeader_) { if (this->myLeader_->bKeepFormation_ || !(this->myLeader_->getAction() == Action::FIGHT || this->myLeader_->getAction() == Action::FIGHTALL || this->myLeader_->getAction() == Action::ATTACK)) { this->keepFormation(); } else if (!this->myLeader_->bKeepFormation_) { if (!this->hasTarget()) { this->setTarget(this->myLeader_->getTarget()); } if (this->hasTarget()) { // this->maneuver(); // this->bShooting_ = this->canFire(); // Vector3 healthPosition = bestHealthPickup((this->target_->getWorldPosition() - this->getControllableEntity()->getWorldPosition()).length()); // if ((this->getControllableEntity()->getWorldPosition() - healthPosition).length() < this->tolerance_) // { // //----choose where to go---- // this->maneuver(); // } // else // { // this->dodgeTowards(healthPosition); // } // //----fire if you can---- // this->bShooting_ = this->canFire(); } } } } Vector3 WingmanController::getFormationPosition () { this->setFormationMode( this->myLeader_->getFormationMode() ); Vector3* targetRelativePosition; this->spread_ = this->myLeader_->getSpread(); if (this->myLeader_->getIdentifier()->getName() == "DivisionController") { switch (this->formationMode_){ case FormationMode::WALL: { targetRelativePosition = new Vector3 (2*this->spread_, 0, 0 - this->tolerance_); break; } case FormationMode::FINGER4: { targetRelativePosition = new Vector3 (2*this->spread_, 0, this->spread_ - this->tolerance_); break; } case FormationMode::DIAMOND: { targetRelativePosition = new Vector3 (2*this->spread_, 0, this->spread_ - this->tolerance_); break; } } } else { switch (this->formationMode_){ case FormationMode::WALL: { targetRelativePosition = new Vector3 (-2*this->spread_, 0, 0 - this->tolerance_); break; } case FormationMode::FINGER4: { targetRelativePosition = new Vector3 (-2*this->spread_, 0, this->spread_ - this->tolerance_); break; } case FormationMode::DIAMOND: { targetRelativePosition = new Vector3 (2*this->spread_, -this->spread_, 0 - this->tolerance_); break; } } } Vector3 result = *targetRelativePosition; delete targetRelativePosition; return result; } void WingmanController::keepFormation() { this->bKeepFormation_ = true; ControllableEntity* leaderEntity = this->myLeader_->getControllableEntity(); Vector3 targetRelativePosition = this->getFormationPosition(); if (!leaderEntity) return; FlyingController::keepFormation (leaderEntity, targetRelativePosition); } //----POST: closest leader that is ready to take a new wingman is returned---- ActionpointController* WingmanController::findNewLeader() { if (!this->getControllableEntity()) return 0; //----vars for finding the closest leader---- ActionpointController* closestLeader = 0; float minDistance = std::numeric_limits::infinity(); Gametype* gt = this->getGametype(); for (ObjectList::iterator it = ObjectList::begin(); it; ++it) { //----0ptr or not a leader or dead?---- if (!it || (it->getIdentifier()->getName() != "SectionController" && it->getIdentifier()->getName() != "DivisionController") || !(it->getControllableEntity())) continue; //----same team?---- if ( !CommonController::sameTeam (this->getControllableEntity(), (it)->getControllableEntity(), gt) ) continue; //----check distance---- float distance = CommonController::distance (it->getControllableEntity(), this->getControllableEntity()); if (distance < minDistance && !(it->hasWingman())) { closestLeader = *it; minDistance = distance; } } if (closestLeader) { //----Racing conditions---- if (closestLeader->setWingman(orxonox_cast(this))) { if (closestLeader->getIdentifier()->getName() == "SectionController") { this->actionTime_ = 1.6f; } else { this->actionTime_ = 2.0f; } return closestLeader; } } return 0; } }