[2362] | 1 | /* |
---|
| 2 | * ORXONOX - the hottest 3D action shooter ever to exist |
---|
| 3 | * > www.orxonox.net < |
---|
| 4 | * |
---|
| 5 | * |
---|
| 6 | * License notice: |
---|
| 7 | * |
---|
| 8 | * This program is free software; you can redistribute it and/or |
---|
| 9 | * modify it under the terms of the GNU General Public License |
---|
| 10 | * as published by the Free Software Foundation; either version 2 |
---|
| 11 | * of the License, or (at your option) any later version. |
---|
| 12 | * |
---|
| 13 | * This program is distributed in the hope that it will be useful, |
---|
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 16 | * GNU General Public License for more details. |
---|
| 17 | * |
---|
| 18 | * You should have received a copy of the GNU General Public License |
---|
| 19 | * along with this program; if not, write to the Free Software |
---|
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
---|
| 21 | * |
---|
| 22 | * Author: |
---|
| 23 | * Fabian 'x3n' Landau |
---|
| 24 | * Co-authors: |
---|
[6978] | 25 | * Dominik Solenicki |
---|
[2362] | 26 | * |
---|
| 27 | */ |
---|
| 28 | |
---|
| 29 | #include "ArtificialController.h" |
---|
| 30 | |
---|
[6978] | 31 | #include <vector> |
---|
[2362] | 32 | #include "core/CoreIncludes.h" |
---|
[6601] | 33 | #include "core/XMLPort.h" |
---|
[5735] | 34 | #include "worldentities/ControllableEntity.h" |
---|
| 35 | #include "worldentities/pawns/Pawn.h" |
---|
| 36 | #include "worldentities/pawns/TeamBaseMatchBase.h" |
---|
| 37 | #include "gametypes/TeamDeathmatch.h" |
---|
| 38 | #include "controllers/WaypointPatrolController.h" |
---|
[6978] | 39 | #include "controllers/NewHumanController.h" |
---|
[6918] | 40 | #include "controllers/DroneController.h" |
---|
[6888] | 41 | #include "util/Math.h" |
---|
[6958] | 42 | #include "core/ConsoleCommand.h" |
---|
[3049] | 43 | |
---|
[2362] | 44 | namespace orxonox |
---|
| 45 | { |
---|
[6978] | 46 | SetConsoleCommand(ArtificialController, formationflight, true); |
---|
[6958] | 47 | SetConsoleCommand(ArtificialController, masteraction, true); |
---|
[6978] | 48 | SetConsoleCommand(ArtificialController, followme, true); |
---|
[6986] | 49 | SetConsoleCommand(ArtificialController, passivebehaviour, true); |
---|
| 50 | SetConsoleCommand(ArtificialController, formationsize, true); |
---|
[6888] | 51 | |
---|
[6986] | 52 | static const unsigned int STANDARD_MAX_FORMATION_SIZE = 7; |
---|
[6997] | 53 | static const int FORMATION_LENGTH = 130; |
---|
[6919] | 54 | static const int FORMATION_WIDTH = 110; |
---|
[6888] | 55 | static const int FREEDOM_COUNT = 4; //seconds the slaves in a formation will be set free when master attacks an enemy |
---|
| 56 | static const float SPEED_MASTER = 0.6f; |
---|
| 57 | static const float ROTATEFACTOR_MASTER = 0.2f; |
---|
| 58 | static const float SPEED_FREE = 0.8f; |
---|
| 59 | static const float ROTATEFACTOR_FREE = 0.8f; |
---|
[6986] | 60 | static const int SECONDS_TO_FOLLOW_HUMAN = 100; |
---|
[6888] | 61 | |
---|
[2362] | 62 | ArtificialController::ArtificialController(BaseObject* creator) : Controller(creator) |
---|
| 63 | { |
---|
| 64 | RegisterObject(ArtificialController); |
---|
| 65 | |
---|
| 66 | this->target_ = 0; |
---|
[6958] | 67 | this->formationFlight_ = true; |
---|
[6978] | 68 | this->passive_ = false; |
---|
[6986] | 69 | this->maxFormationSize_ = STANDARD_MAX_FORMATION_SIZE; |
---|
[6695] | 70 | this->myMaster_ = 0; |
---|
[6850] | 71 | this->freedomCount_ = 0; |
---|
| 72 | this->team_ = -1; |
---|
| 73 | this->state_ = FREE; |
---|
[6919] | 74 | this->specificMasterAction_ = NONE; |
---|
| 75 | this->specificMasterActionHoldCount_ = 0; |
---|
[2362] | 76 | this->bShooting_ = false; |
---|
| 77 | this->bHasTargetPosition_ = false; |
---|
| 78 | this->targetPosition_ = Vector3::ZERO; |
---|
[6978] | 79 | this->humanToFollow_ = NULL; |
---|
[6417] | 80 | |
---|
[5929] | 81 | this->target_.setCallback(createFunctor(&ArtificialController::targetDied, this)); |
---|
[2362] | 82 | } |
---|
| 83 | |
---|
| 84 | ArtificialController::~ArtificialController() |
---|
| 85 | { |
---|
| 86 | } |
---|
| 87 | |
---|
[6601] | 88 | void ArtificialController::XMLPort(Element& xmlelement, XMLPort::Mode mode) |
---|
| 89 | { |
---|
| 90 | SUPER(ArtificialController, XMLPort, xmlelement, mode); |
---|
| 91 | |
---|
[6919] | 92 | XMLPortParam(ArtificialController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(-1); |
---|
[6958] | 93 | XMLPortParam(ArtificialController, "formation", setFormationFlight, getFormationFlight, xmlelement, mode).defaultValues(true); |
---|
[6601] | 94 | } |
---|
| 95 | |
---|
[6978] | 96 | // Documentation only here to get a faster overview for creating a useful documentation, what you're reading here not intended for an actual documentation... |
---|
| 97 | |
---|
| 98 | /** |
---|
| 99 | @brief Activates / deactivates formationflight behaviour |
---|
| 100 | @param form activate formflight if form is true |
---|
| 101 | */ |
---|
[6958] | 102 | void ArtificialController::formationflight(bool form) |
---|
| 103 | { |
---|
| 104 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 105 | { |
---|
| 106 | if (!it->getController()) |
---|
| 107 | continue; |
---|
| 108 | |
---|
[6986] | 109 | ArtificialController *aiController = orxonox_cast<ArtificialController*>(it->getController()); |
---|
[6958] | 110 | |
---|
| 111 | if(aiController) |
---|
| 112 | { |
---|
| 113 | aiController->formationFlight_ = form; |
---|
[6997] | 114 | if(!form) |
---|
| 115 | { |
---|
| 116 | if(aiController->state_ == MASTER) aiController->freeSlaves(); |
---|
| 117 | aiController->state_ = FREE; |
---|
| 118 | } |
---|
[6958] | 119 | } |
---|
| 120 | } |
---|
| 121 | } |
---|
[6978] | 122 | |
---|
| 123 | /** |
---|
[6986] | 124 | @brief Get all masters to do a "specific master action" |
---|
[6978] | 125 | @param action which action to perform (integer, so it can be called with a console command (tmp solution)) |
---|
| 126 | */ |
---|
[6997] | 127 | void ArtificialController::masteraction(int action) |
---|
[6958] | 128 | { |
---|
| 129 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 130 | { |
---|
| 131 | if (!it->getController()) |
---|
| 132 | continue; |
---|
| 133 | |
---|
[6986] | 134 | ArtificialController *aiController = orxonox_cast<ArtificialController*>(it->getController()); |
---|
[6958] | 135 | |
---|
[6997] | 136 | if(aiController && aiController->state_ == MASTER) |
---|
[6958] | 137 | { |
---|
[6986] | 138 | if (action == 1) |
---|
[6997] | 139 | aiController->spinInit(); |
---|
[6986] | 140 | if (action == 2) |
---|
[6997] | 141 | aiController->turn180Init(); |
---|
[6958] | 142 | } |
---|
| 143 | } |
---|
| 144 | } |
---|
| 145 | |
---|
[6978] | 146 | /** |
---|
[6986] | 147 | @brief A human player gets followed by its nearest master. Initiated by console command, intended for demonstration puproses. Does not work at the moment. |
---|
[6978] | 148 | */ |
---|
| 149 | void ArtificialController::followme() |
---|
| 150 | { |
---|
| 151 | |
---|
| 152 | Pawn *humanPawn = NULL; |
---|
| 153 | NewHumanController *currentHumanController = NULL; |
---|
| 154 | std::vector<ArtificialController*> allMasters; |
---|
| 155 | |
---|
| 156 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 157 | { |
---|
| 158 | if (!it->getController()) |
---|
| 159 | continue; |
---|
| 160 | |
---|
[6986] | 161 | currentHumanController = orxonox_cast<NewHumanController*>(it->getController()); |
---|
[6978] | 162 | |
---|
| 163 | if(currentHumanController) humanPawn = *it; |
---|
| 164 | |
---|
[6986] | 165 | ArtificialController *aiController = orxonox_cast<ArtificialController*>(it->getController()); |
---|
[6978] | 166 | |
---|
| 167 | if(aiController || aiController->state_ == MASTER) |
---|
| 168 | allMasters.push_back(aiController); |
---|
| 169 | |
---|
| 170 | } |
---|
[6986] | 171 | |
---|
| 172 | if((humanPawn != NULL) && (allMasters.size() != 0)) |
---|
[6978] | 173 | { |
---|
| 174 | float posHuman = humanPawn->getPosition().length(); |
---|
| 175 | float distance = 0.0f; |
---|
[6986] | 176 | float minDistance = FLT_MAX; |
---|
[6978] | 177 | int index = 0; |
---|
| 178 | int i = 0; |
---|
| 179 | |
---|
| 180 | for(std::vector<ArtificialController*>::iterator it = allMasters.begin(); it != allMasters.end(); it++) |
---|
| 181 | { |
---|
| 182 | distance = posHuman - (*it)->getControllableEntity()->getPosition().length(); |
---|
| 183 | if(distance < minDistance) index = i; |
---|
| 184 | } |
---|
[6986] | 185 | allMasters[index]->humanToFollow_ = humanPawn; |
---|
| 186 | allMasters[index]->followHuman(humanPawn, false); |
---|
| 187 | } |
---|
[6978] | 188 | |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | /** |
---|
[6986] | 192 | @brief Sets shooting behaviour of pawns. |
---|
| 193 | @param passive if true, bots won't shoot. |
---|
[6978] | 194 | */ |
---|
| 195 | void ArtificialController::passivebehaviour(bool passive) |
---|
| 196 | { |
---|
[6986] | 197 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 198 | { |
---|
| 199 | if (!it->getController()) |
---|
| 200 | continue; |
---|
| 201 | |
---|
| 202 | ArtificialController *aiController = orxonox_cast<ArtificialController*>(it->getController()); |
---|
| 203 | |
---|
| 204 | if(aiController) |
---|
| 205 | { |
---|
| 206 | aiController->passive_ = passive; |
---|
| 207 | } |
---|
| 208 | } |
---|
[6978] | 209 | } |
---|
| 210 | |
---|
[6986] | 211 | |
---|
[6978] | 212 | /** |
---|
[6986] | 213 | @brief Sets maximal formation size |
---|
| 214 | @param size maximal formation size. |
---|
| 215 | */ |
---|
| 216 | void ArtificialController::formationsize(int size) |
---|
| 217 | { |
---|
| 218 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 219 | { |
---|
| 220 | if (!it->getController()) |
---|
| 221 | continue; |
---|
| 222 | |
---|
| 223 | ArtificialController *aiController = orxonox_cast<ArtificialController*>(it->getController()); |
---|
| 224 | |
---|
| 225 | if(aiController) |
---|
| 226 | { |
---|
| 227 | aiController->maxFormationSize_ = size; |
---|
| 228 | } |
---|
| 229 | } |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | /** |
---|
[6978] | 233 | @brief Gets called if ControllableEntity is changed. Resets the bot when it dies. |
---|
| 234 | */ |
---|
[6850] | 235 | void ArtificialController::changedControllableEntity() |
---|
| 236 | { |
---|
| 237 | if(!getControllableEntity()) |
---|
| 238 | { |
---|
| 239 | if (this->state_ == SLAVE) unregisterSlave(); |
---|
| 240 | if (this->state_ == MASTER) setNewMasterWithinFormation(); |
---|
| 241 | this->slaves_.clear(); |
---|
| 242 | this->state_ = FREE; |
---|
[6888] | 243 | |
---|
[6850] | 244 | } |
---|
| 245 | } |
---|
| 246 | |
---|
[6978] | 247 | |
---|
[3049] | 248 | void ArtificialController::moveToPosition(const Vector3& target) |
---|
[2362] | 249 | { |
---|
| 250 | if (!this->getControllableEntity()) |
---|
| 251 | return; |
---|
| 252 | |
---|
[3049] | 253 | Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target); |
---|
| 254 | float distance = (target - this->getControllableEntity()->getPosition()).length(); |
---|
[2362] | 255 | |
---|
[6888] | 256 | |
---|
| 257 | if(this->state_ == FREE) |
---|
[2362] | 258 | { |
---|
[6888] | 259 | if (this->target_ || distance > 10) |
---|
| 260 | { |
---|
| 261 | // Multiply with 0.8 to make them a bit slower |
---|
| 262 | this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_FREE * sgn(coord.x) * coord.x*coord.x); |
---|
| 263 | this->getControllableEntity()->rotatePitch(ROTATEFACTOR_FREE * sgn(coord.y) * coord.y*coord.y); |
---|
| 264 | } |
---|
[6850] | 265 | |
---|
[6888] | 266 | if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength()) |
---|
| 267 | { |
---|
| 268 | this->getControllableEntity()->moveFrontBack(-0.05f); // They don't brake with full power to give the player a chance |
---|
| 269 | } else this->getControllableEntity()->moveFrontBack(SPEED_FREE); |
---|
| 270 | } |
---|
[6850] | 271 | |
---|
| 272 | |
---|
| 273 | |
---|
[6888] | 274 | if(this->state_ == MASTER) |
---|
| 275 | { |
---|
| 276 | if (this->target_ || distance > 10) |
---|
| 277 | { |
---|
| 278 | this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x); |
---|
| 279 | this->getControllableEntity()->rotatePitch(ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y); |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength()) |
---|
| 283 | { |
---|
| 284 | this->getControllableEntity()->moveFrontBack(-0.05f); |
---|
| 285 | } else this->getControllableEntity()->moveFrontBack(SPEED_MASTER); |
---|
[2362] | 286 | } |
---|
| 287 | |
---|
[6888] | 288 | |
---|
| 289 | |
---|
| 290 | if(this->state_ == SLAVE) |
---|
[6850] | 291 | { |
---|
[6888] | 292 | |
---|
[6919] | 293 | this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x); |
---|
| 294 | this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y); |
---|
[6888] | 295 | |
---|
[6919] | 296 | if (distance < 300) |
---|
[6888] | 297 | { |
---|
[6919] | 298 | if (distance < 40) |
---|
[6888] | 299 | { |
---|
[6919] | 300 | this->getControllableEntity()->moveFrontBack(0.8f*SPEED_MASTER); |
---|
| 301 | } else this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER); |
---|
[6888] | 302 | |
---|
| 303 | } else { |
---|
[6919] | 304 | this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER + distance/300.0f); |
---|
[6888] | 305 | } |
---|
[6850] | 306 | } |
---|
[2362] | 307 | } |
---|
| 308 | |
---|
[3049] | 309 | void ArtificialController::moveToTargetPosition() |
---|
| 310 | { |
---|
| 311 | this->moveToPosition(this->targetPosition_); |
---|
| 312 | } |
---|
| 313 | |
---|
[6640] | 314 | int ArtificialController::getState() |
---|
| 315 | { |
---|
| 316 | return this->state_; |
---|
| 317 | } |
---|
| 318 | |
---|
[6978] | 319 | /** |
---|
| 320 | @brief Unregisters a slave from its master. Called by a slave. |
---|
| 321 | */ |
---|
[6695] | 322 | void ArtificialController::unregisterSlave() { |
---|
| 323 | if(myMaster_) |
---|
| 324 | { |
---|
[6888] | 325 | std::vector<ArtificialController*>::iterator it = std::find(myMaster_->slaves_.begin(), myMaster_->slaves_.end(), this); |
---|
| 326 | if( it != myMaster_->slaves_.end() ) |
---|
| 327 | myMaster_->slaves_.erase(it); |
---|
[6695] | 328 | } |
---|
| 329 | } |
---|
| 330 | |
---|
[6640] | 331 | void ArtificialController::searchNewMaster() |
---|
| 332 | { |
---|
[6695] | 333 | |
---|
[6640] | 334 | if (!this->getControllableEntity()) |
---|
| 335 | return; |
---|
| 336 | |
---|
| 337 | this->targetPosition_ = this->getControllableEntity()->getPosition(); |
---|
| 338 | this->forgetTarget(); |
---|
[6919] | 339 | int teamSize = 0; |
---|
[6640] | 340 | //go through all pawns |
---|
| 341 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 342 | { |
---|
[6695] | 343 | |
---|
| 344 | //same team? |
---|
[6640] | 345 | if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype())) |
---|
| 346 | continue; |
---|
| 347 | |
---|
[6919] | 348 | //has it an ArtificialController? |
---|
[6695] | 349 | if (!it->getController()) |
---|
| 350 | continue; |
---|
[6640] | 351 | |
---|
[6919] | 352 | //is pawn oneself? |
---|
[6986] | 353 | if (orxonox_cast<ControllableEntity*>(*it) == this->getControllableEntity()) |
---|
[6919] | 354 | continue; |
---|
| 355 | |
---|
| 356 | teamSize++; |
---|
| 357 | |
---|
[6986] | 358 | ArtificialController *newMaster = orxonox_cast<ArtificialController*>(it->getController()); |
---|
[6850] | 359 | |
---|
[6919] | 360 | //is it a master? |
---|
[6850] | 361 | if (!newMaster || newMaster->getState() != MASTER) |
---|
[6640] | 362 | continue; |
---|
| 363 | |
---|
[6888] | 364 | float distance = (it->getPosition() - this->getControllableEntity()->getPosition()).length(); |
---|
| 365 | |
---|
[6919] | 366 | // is pawn in range? |
---|
| 367 | if (distance < 5000) |
---|
[6640] | 368 | { |
---|
[6986] | 369 | if(newMaster->slaves_.size() > this->maxFormationSize_) continue; |
---|
[6696] | 370 | |
---|
[6888] | 371 | for(std::vector<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++) |
---|
[6850] | 372 | { |
---|
| 373 | (*itSlave)->myMaster_ = newMaster; |
---|
| 374 | newMaster->slaves_.push_back(*itSlave); |
---|
| 375 | } |
---|
[6795] | 376 | this->slaves_.clear(); |
---|
[6683] | 377 | this->state_ = SLAVE; |
---|
[6696] | 378 | |
---|
[6850] | 379 | this->myMaster_ = newMaster; |
---|
| 380 | newMaster->slaves_.push_back(this); |
---|
[6696] | 381 | |
---|
[6695] | 382 | break; |
---|
[6640] | 383 | } |
---|
[6978] | 384 | } |
---|
[6640] | 385 | |
---|
[6978] | 386 | if (state_ != SLAVE && teamSize != 0) state_ = MASTER; |
---|
| 387 | |
---|
[6640] | 388 | } |
---|
| 389 | |
---|
[6978] | 390 | /** |
---|
| 391 | @brief Commands the slaves of a master into a formation. Called by a master. |
---|
| 392 | */ |
---|
| 393 | void ArtificialController::commandSlaves() |
---|
| 394 | { |
---|
| 395 | if(this->state_ != MASTER) return; |
---|
[6683] | 396 | |
---|
[6888] | 397 | Quaternion orient = this->getControllableEntity()->getOrientation(); |
---|
| 398 | Vector3 dest = this->getControllableEntity()->getPosition(); |
---|
| 399 | |
---|
| 400 | // 1 slave: follow |
---|
| 401 | if (this->slaves_.size() == 1) |
---|
[6695] | 402 | { |
---|
[6888] | 403 | dest += 4*orient*WorldEntity::BACK; |
---|
| 404 | this->slaves_.front()->setTargetPosition(dest); |
---|
[6695] | 405 | } |
---|
[6919] | 406 | else |
---|
[6888] | 407 | { |
---|
[6919] | 408 | dest += 1.0f*orient*WorldEntity::BACK; |
---|
| 409 | Vector3 pos = Vector3::ZERO; |
---|
| 410 | int i = 1; |
---|
[6888] | 411 | |
---|
| 412 | for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++) |
---|
| 413 | { |
---|
[6919] | 414 | pos = Vector3::ZERO; |
---|
[6997] | 415 | if (i <= 1) pos += dest + FORMATION_WIDTH*(orient*WorldEntity::LEFT); |
---|
| 416 | if (i == 2) pos += dest + FORMATION_WIDTH*(orient*WorldEntity::RIGHT); |
---|
| 417 | if (i == 3) pos += dest + FORMATION_WIDTH*(orient*WorldEntity::UP); |
---|
[6919] | 418 | if (i >= 4) |
---|
| 419 | { |
---|
[6997] | 420 | pos += dest + FORMATION_WIDTH*(orient*WorldEntity::DOWN); |
---|
[6919] | 421 | i = 1; |
---|
[6997] | 422 | dest += FORMATION_LENGTH*(orient*WorldEntity::BACK); |
---|
[6919] | 423 | (*it)->setTargetPosition(pos); |
---|
| 424 | continue; |
---|
| 425 | } |
---|
| 426 | i++; |
---|
| 427 | (*it)->setTargetPosition(pos); |
---|
[6888] | 428 | } |
---|
| 429 | } |
---|
[6683] | 430 | } |
---|
| 431 | |
---|
[6978] | 432 | /** |
---|
| 433 | @brief Sets a new master within the formation. Called by a master. |
---|
| 434 | */ |
---|
[6795] | 435 | void ArtificialController::setNewMasterWithinFormation() |
---|
| 436 | { |
---|
[6978] | 437 | if(this->state_ != MASTER) return; |
---|
[6888] | 438 | |
---|
[6795] | 439 | if (this->slaves_.empty()) |
---|
| 440 | return; |
---|
| 441 | |
---|
| 442 | ArtificialController *newMaster = this->slaves_.back(); |
---|
| 443 | this->slaves_.pop_back(); |
---|
[6888] | 444 | |
---|
[6795] | 445 | if(!newMaster) return; |
---|
| 446 | newMaster->state_ = MASTER; |
---|
| 447 | newMaster->slaves_ = this->slaves_; |
---|
[6888] | 448 | |
---|
[6850] | 449 | this->slaves_.clear(); |
---|
[6795] | 450 | this->state_ = SLAVE; |
---|
| 451 | this->myMaster_ = newMaster; |
---|
| 452 | |
---|
[6888] | 453 | for(std::vector<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++) |
---|
[6795] | 454 | { |
---|
| 455 | (*it)->myMaster_ = newMaster; |
---|
| 456 | } |
---|
| 457 | |
---|
| 458 | } |
---|
| 459 | |
---|
[6978] | 460 | /** |
---|
| 461 | @brief Frees all slaves form a master. Called by a master. |
---|
| 462 | */ |
---|
[6850] | 463 | void ArtificialController::freeSlaves() |
---|
[6683] | 464 | { |
---|
[6978] | 465 | if(this->state_ != MASTER) return; |
---|
| 466 | |
---|
[6888] | 467 | for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++) |
---|
[6696] | 468 | { |
---|
| 469 | (*it)->state_ = FREE; |
---|
| 470 | } |
---|
[6850] | 471 | this->slaves_.clear(); |
---|
| 472 | } |
---|
| 473 | |
---|
[6978] | 474 | /** |
---|
| 475 | @brief Master sets its slaves free for \var FREEDOM_COUNT seconds. |
---|
| 476 | */ |
---|
[6850] | 477 | void ArtificialController::forceFreeSlaves() |
---|
| 478 | { |
---|
[6978] | 479 | if(this->state_ != MASTER) return; |
---|
| 480 | |
---|
[6888] | 481 | for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++) |
---|
[6683] | 482 | { |
---|
[6850] | 483 | (*it)->state_ = FREE; |
---|
| 484 | (*it)->forceFreedom(); |
---|
| 485 | (*it)->targetPosition_ = this->targetPosition_; |
---|
| 486 | (*it)->bShooting_ = true; |
---|
[6986] | 487 | // (*it)->getControllableEntity()->fire(0);// fire once for fun |
---|
[6683] | 488 | } |
---|
[6696] | 489 | } |
---|
[6683] | 490 | |
---|
[6696] | 491 | void ArtificialController::loseMasterState() |
---|
| 492 | { |
---|
[6850] | 493 | this->freeSlaves(); |
---|
[6696] | 494 | this->state_ = FREE; |
---|
[6683] | 495 | } |
---|
| 496 | |
---|
[6978] | 497 | |
---|
[6850] | 498 | void ArtificialController::forceFreedom() |
---|
| 499 | { |
---|
[6888] | 500 | this->freedomCount_ = FREEDOM_COUNT; |
---|
[6850] | 501 | } |
---|
| 502 | |
---|
[6978] | 503 | /** |
---|
| 504 | @brief Checks wether caller has been forced free, decrements time to stay forced free. |
---|
| 505 | @return true if forced free. |
---|
| 506 | */ |
---|
[6850] | 507 | bool ArtificialController::forcedFree() |
---|
| 508 | { |
---|
| 509 | if(this->freedomCount_ > 0) |
---|
| 510 | { |
---|
| 511 | this->freedomCount_--; |
---|
| 512 | return true; |
---|
| 513 | } else return false; |
---|
| 514 | } |
---|
| 515 | |
---|
[6978] | 516 | /** |
---|
[6997] | 517 | @brief Used to continue a "specific master action" for a certain time and resuming normal behaviour after. |
---|
[6978] | 518 | */ |
---|
[6919] | 519 | void ArtificialController::specificMasterActionHold() |
---|
| 520 | { |
---|
[6978] | 521 | if(this->state_ != MASTER) return; |
---|
| 522 | |
---|
[6958] | 523 | if (specificMasterActionHoldCount_ == 0) |
---|
| 524 | { |
---|
| 525 | this->specificMasterAction_ = NONE; |
---|
| 526 | this->searchNewTarget(); |
---|
| 527 | } |
---|
[6919] | 528 | else specificMasterActionHoldCount_--; |
---|
| 529 | } |
---|
| 530 | |
---|
[6978] | 531 | /** |
---|
[6997] | 532 | @brief Master initializes a 180 degree turn. Leads to a "specific master action". |
---|
[6978] | 533 | */ |
---|
[6997] | 534 | void ArtificialController::turn180Init() |
---|
[6919] | 535 | { |
---|
[6997] | 536 | COUT(0) << "~turnInit" << std::endl; |
---|
[6978] | 537 | if(this->state_ != MASTER) return; |
---|
| 538 | |
---|
[6958] | 539 | Quaternion orient = this->getControllableEntity()->getOrientation(); |
---|
| 540 | |
---|
[6997] | 541 | this->setTargetPosition(this->getControllableEntity()->getPosition() + 1000.0f*orient*WorldEntity::BACK); |
---|
| 542 | |
---|
| 543 | this->specificMasterActionHoldCount_ = 4; |
---|
| 544 | |
---|
| 545 | this->specificMasterAction_ = TURN180; |
---|
[6919] | 546 | } |
---|
| 547 | |
---|
[6978] | 548 | /** |
---|
[6997] | 549 | @brief Execute the 180 degree turn. Called within tick. |
---|
[6978] | 550 | */ |
---|
[6997] | 551 | void ArtificialController::turn180() |
---|
[6919] | 552 | { |
---|
[6997] | 553 | Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_); |
---|
| 554 | |
---|
| 555 | this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x); |
---|
| 556 | this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y); |
---|
| 557 | |
---|
| 558 | this->getControllableEntity()->moveFrontBack(SPEED_MASTER); |
---|
| 559 | } |
---|
| 560 | |
---|
| 561 | /** |
---|
| 562 | @brief Master initializes a spin around its looking direction axis. Leads to a "specific master action". Not yet implemented. |
---|
| 563 | */ |
---|
| 564 | void ArtificialController::spinInit() |
---|
| 565 | { |
---|
| 566 | COUT(0) << "~spinInit" << std::endl; |
---|
[6978] | 567 | if(this->state_ != MASTER) return; |
---|
[6997] | 568 | this->specificMasterAction_ = SPIN; |
---|
| 569 | this->specificMasterActionHoldCount_ = 10; |
---|
| 570 | } |
---|
[6978] | 571 | |
---|
[6997] | 572 | /** |
---|
| 573 | @brief Execute the spin. Called within tick. |
---|
| 574 | */ |
---|
| 575 | void ArtificialController::spin() |
---|
| 576 | { |
---|
| 577 | this->moveToTargetPosition(); |
---|
| 578 | this->getControllableEntity()->rotateRoll(0.8f); |
---|
[6919] | 579 | } |
---|
| 580 | |
---|
[6978] | 581 | /** |
---|
| 582 | @brief Master begins to follow a human player. Is a "specific master action". |
---|
| 583 | @param humanController human to follow. |
---|
[6986] | 584 | @param alaways follows human forever if true - only inplemented for false yet. |
---|
[6978] | 585 | */ |
---|
| 586 | void ArtificialController::followHuman(Pawn* human, bool always) |
---|
| 587 | { |
---|
| 588 | if (human == NULL) |
---|
| 589 | { |
---|
| 590 | this->specificMasterAction_ = NONE; |
---|
| 591 | return; |
---|
| 592 | } |
---|
| 593 | if (!always) |
---|
| 594 | { |
---|
| 595 | this->setTarget(human); |
---|
| 596 | this->specificMasterActionHoldCount_ = SECONDS_TO_FOLLOW_HUMAN; |
---|
| 597 | this->specificMasterAction_ = HOLD; |
---|
| 598 | } |
---|
[6919] | 599 | |
---|
[6978] | 600 | } |
---|
| 601 | |
---|
| 602 | |
---|
[3049] | 603 | void ArtificialController::setTargetPosition(const Vector3& target) |
---|
| 604 | { |
---|
| 605 | this->targetPosition_ = target; |
---|
| 606 | this->bHasTargetPosition_ = true; |
---|
| 607 | } |
---|
| 608 | |
---|
[2362] | 609 | void ArtificialController::searchRandomTargetPosition() |
---|
| 610 | { |
---|
[2493] | 611 | this->targetPosition_ = Vector3(rnd(-2000,2000), rnd(-2000,2000), rnd(-2000,2000)); |
---|
[2362] | 612 | this->bHasTargetPosition_ = true; |
---|
| 613 | } |
---|
| 614 | |
---|
[3049] | 615 | void ArtificialController::setTarget(Pawn* target) |
---|
| 616 | { |
---|
| 617 | this->target_ = target; |
---|
| 618 | |
---|
| 619 | if (target) |
---|
| 620 | this->targetPosition_ = target->getPosition(); |
---|
| 621 | } |
---|
| 622 | |
---|
[2362] | 623 | void ArtificialController::searchNewTarget() |
---|
| 624 | { |
---|
| 625 | if (!this->getControllableEntity()) |
---|
| 626 | return; |
---|
| 627 | |
---|
| 628 | this->targetPosition_ = this->getControllableEntity()->getPosition(); |
---|
| 629 | this->forgetTarget(); |
---|
| 630 | |
---|
| 631 | for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it) |
---|
| 632 | { |
---|
[3049] | 633 | if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype())) |
---|
| 634 | continue; |
---|
| 635 | |
---|
[2506] | 636 | if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity()) |
---|
[2362] | 637 | { |
---|
| 638 | float speed = this->getControllableEntity()->getVelocity().length(); |
---|
| 639 | Vector3 distanceCurrent = this->targetPosition_ - this->getControllableEntity()->getPosition(); |
---|
| 640 | Vector3 distanceNew = it->getPosition() - this->getControllableEntity()->getPosition(); |
---|
| 641 | if (!this->target_ || it->getPosition().squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceNew) / speed / distanceNew.length()) / (2 * Ogre::Math::PI)) |
---|
| 642 | < this->targetPosition_.squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceCurrent) / speed / distanceCurrent.length()) / (2 * Ogre::Math::PI)) + rnd(-250, 250)) |
---|
| 643 | { |
---|
| 644 | this->target_ = (*it); |
---|
| 645 | this->targetPosition_ = it->getPosition(); |
---|
| 646 | } |
---|
| 647 | } |
---|
| 648 | } |
---|
| 649 | } |
---|
| 650 | |
---|
| 651 | void ArtificialController::forgetTarget() |
---|
| 652 | { |
---|
| 653 | this->target_ = 0; |
---|
| 654 | this->bShooting_ = false; |
---|
| 655 | } |
---|
| 656 | |
---|
| 657 | void ArtificialController::aimAtTarget() |
---|
| 658 | { |
---|
| 659 | if (!this->target_ || !this->getControllableEntity()) |
---|
| 660 | return; |
---|
| 661 | |
---|
[2493] | 662 | static const float hardcoded_projectile_speed = 1250; |
---|
[2362] | 663 | |
---|
[2493] | 664 | this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity()); |
---|
[2362] | 665 | this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO); |
---|
[6417] | 666 | |
---|
[6986] | 667 | Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity()); |
---|
[6417] | 668 | if (pawn) |
---|
| 669 | pawn->setAimPosition(this->targetPosition_); |
---|
[2362] | 670 | } |
---|
| 671 | |
---|
| 672 | bool ArtificialController::isCloseAtTarget(float distance) const |
---|
| 673 | { |
---|
| 674 | if (!this->getControllableEntity()) |
---|
| 675 | return false; |
---|
| 676 | |
---|
| 677 | if (!this->target_) |
---|
| 678 | return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance); |
---|
| 679 | else |
---|
| 680 | return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance); |
---|
| 681 | } |
---|
| 682 | |
---|
| 683 | bool ArtificialController::isLookingAtTarget(float angle) const |
---|
| 684 | { |
---|
| 685 | if (!this->getControllableEntity()) |
---|
| 686 | return false; |
---|
| 687 | |
---|
| 688 | return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle); |
---|
| 689 | } |
---|
| 690 | |
---|
[5929] | 691 | void ArtificialController::abandonTarget(Pawn* target) |
---|
[2362] | 692 | { |
---|
[5929] | 693 | if (target == this->target_) |
---|
| 694 | this->targetDied(); |
---|
[2362] | 695 | } |
---|
[3049] | 696 | |
---|
[5929] | 697 | void ArtificialController::targetDied() |
---|
| 698 | { |
---|
| 699 | this->forgetTarget(); |
---|
| 700 | this->searchRandomTargetPosition(); |
---|
| 701 | } |
---|
| 702 | |
---|
[3049] | 703 | bool ArtificialController::sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype) |
---|
| 704 | { |
---|
| 705 | if (entity1 == entity2) |
---|
| 706 | return true; |
---|
| 707 | |
---|
| 708 | int team1 = -1; |
---|
| 709 | int team2 = -1; |
---|
| 710 | |
---|
[6601] | 711 | Controller* controller = 0; |
---|
| 712 | if (entity1->getController()) |
---|
| 713 | controller = entity1->getController(); |
---|
| 714 | else |
---|
| 715 | controller = entity1->getXMLController(); |
---|
| 716 | if (controller) |
---|
[3049] | 717 | { |
---|
[6601] | 718 | ArtificialController* ac = orxonox_cast<ArtificialController*>(controller); |
---|
| 719 | if (ac) |
---|
| 720 | team1 = ac->getTeam(); |
---|
[3049] | 721 | } |
---|
[6601] | 722 | |
---|
| 723 | if (entity1->getController()) |
---|
| 724 | controller = entity1->getController(); |
---|
| 725 | else |
---|
| 726 | controller = entity1->getXMLController(); |
---|
| 727 | if (controller) |
---|
[3049] | 728 | { |
---|
[6601] | 729 | ArtificialController* ac = orxonox_cast<ArtificialController*>(controller); |
---|
| 730 | if (ac) |
---|
| 731 | team2 = ac->getTeam(); |
---|
[3049] | 732 | } |
---|
| 733 | |
---|
[3325] | 734 | TeamDeathmatch* tdm = orxonox_cast<TeamDeathmatch*>(gametype); |
---|
[3049] | 735 | if (tdm) |
---|
| 736 | { |
---|
| 737 | if (entity1->getPlayer()) |
---|
| 738 | team1 = tdm->getTeam(entity1->getPlayer()); |
---|
| 739 | |
---|
| 740 | if (entity2->getPlayer()) |
---|
| 741 | team2 = tdm->getTeam(entity2->getPlayer()); |
---|
| 742 | } |
---|
| 743 | |
---|
[3086] | 744 | TeamBaseMatchBase* base = 0; |
---|
[3325] | 745 | base = orxonox_cast<TeamBaseMatchBase*>(entity1); |
---|
[3086] | 746 | if (base) |
---|
| 747 | { |
---|
| 748 | switch (base->getState()) |
---|
| 749 | { |
---|
[3280] | 750 | case BaseState::ControlTeam1: |
---|
[3086] | 751 | team1 = 0; |
---|
| 752 | break; |
---|
[3280] | 753 | case BaseState::ControlTeam2: |
---|
[3086] | 754 | team1 = 1; |
---|
| 755 | break; |
---|
[3280] | 756 | case BaseState::Uncontrolled: |
---|
[3086] | 757 | default: |
---|
| 758 | team1 = -1; |
---|
| 759 | } |
---|
| 760 | } |
---|
[3325] | 761 | base = orxonox_cast<TeamBaseMatchBase*>(entity2); |
---|
[3086] | 762 | if (base) |
---|
| 763 | { |
---|
| 764 | switch (base->getState()) |
---|
| 765 | { |
---|
[3280] | 766 | case BaseState::ControlTeam1: |
---|
[3086] | 767 | team2 = 0; |
---|
| 768 | break; |
---|
[3280] | 769 | case BaseState::ControlTeam2: |
---|
[3086] | 770 | team2 = 1; |
---|
| 771 | break; |
---|
[3280] | 772 | case BaseState::Uncontrolled: |
---|
[3086] | 773 | default: |
---|
| 774 | team2 = -1; |
---|
| 775 | } |
---|
| 776 | } |
---|
| 777 | |
---|
[6891] | 778 | DroneController* droneController = 0; |
---|
| 779 | droneController = orxonox_cast<DroneController*>(entity1->getController()); |
---|
| 780 | if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity2) |
---|
| 781 | return true; |
---|
| 782 | droneController = orxonox_cast<DroneController*>(entity2->getController()); |
---|
| 783 | if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity1) |
---|
| 784 | return true; |
---|
[6991] | 785 | DroneController* droneController1 = orxonox_cast<DroneController*>(entity1->getController()); |
---|
| 786 | DroneController* droneController2 = orxonox_cast<DroneController*>(entity2->getController()); |
---|
| 787 | if (droneController1 && droneController2 && droneController1->getOwner() == droneController2->getOwner()) |
---|
| 788 | return true; |
---|
[6958] | 789 | |
---|
[3049] | 790 | return (team1 == team2 && team1 != -1); |
---|
| 791 | } |
---|
[2362] | 792 | } |
---|