Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ai2/src/orxonox/controllers/ArtificialController.cc @ 8769

Last change on this file since 8769 was 8769, checked in by jo, 13 years ago

Moved intern waypoint functionallity from the waypointController to its base class ArtificialController. Further usage of this is planned.

  • Property svn:eol-style set to native
File size: 43.3 KB
Line 
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:
25 *      Dominik Solenicki
26 *
27 */
28
29#include "ArtificialController.h"
30
31#include <vector>
32#include <climits>
33
34#include "util/Math.h"
35#include "core/CoreIncludes.h"
36#include "core/XMLPort.h"
37#include "core/command/ConsoleCommand.h"
38#include "worldentities/ControllableEntity.h"
39#include "worldentities/pawns/Pawn.h"
40#include "worldentities/pawns/TeamBaseMatchBase.h"
41#include "worldentities/pawns/SpaceShip.h"
42#include "gametypes/TeamDeathmatch.h"
43#include "gametypes/Dynamicmatch.h"
44#include "controllers/WaypointPatrolController.h"
45#include "controllers/NewHumanController.h"
46#include "controllers/DroneController.h"
47#include "weaponsystem/WeaponMode.h"
48#include "weaponsystem/WeaponPack.h"
49#include "weaponsystem/Weapon.h"
50#include "weaponsystem/WeaponSlot.h"
51#include "weaponsystem/WeaponSlot.h"
52
53namespace orxonox
54{
55    SetConsoleCommand("ArtificialController", "formationflight",  &ArtificialController::formationflight);
56    SetConsoleCommand("ArtificialController", "masteraction",     &ArtificialController::masteraction);
57    SetConsoleCommand("ArtificialController", "followme",         &ArtificialController::followme);
58    SetConsoleCommand("ArtificialController", "passivebehaviour", &ArtificialController::passivebehaviour);
59    SetConsoleCommand("ArtificialController", "formationsize",    &ArtificialController::formationsize);
60    SetConsoleCommand("ArtificialController", "setbotlevel",      &ArtificialController::setAllBotLevel);
61
62    static const unsigned int STANDARD_MAX_FORMATION_SIZE = 7;
63    static const int RADIUS_TO_SEARCH_FOR_MASTERS = 5000;
64    static const int FORMATION_LENGTH =  130;
65    static const int FORMATION_WIDTH =  110;
66    static const int FREEDOM_COUNT = 4; //seconds the slaves in a formation will be set free when master attacks an enemy
67    static const float SPEED_MASTER = 0.6f;
68    static const float ROTATEFACTOR_MASTER = 0.2f;
69    static const float SPEED_FREE = 0.8f;
70    static const float ROTATEFACTOR_FREE = 0.8f;
71
72
73    ArtificialController::ArtificialController(BaseObject* creator) : Controller(creator)
74    {
75        RegisterObject(ArtificialController);
76
77        this->target_ = 0;
78        this->formationFlight_ = false;
79        this->passive_ = false;
80        this->maxFormationSize_ = STANDARD_MAX_FORMATION_SIZE;
81        this->myMaster_ = 0;
82        this->freedomCount_ = 0;
83        this->team_ = -1;
84        this->state_ = FREE;
85        this->specificMasterAction_ = NONE;
86        this->specificMasterActionHoldCount_  = 0;
87        this->bShooting_ = false;
88        this->bHasTargetPosition_ = false;
89        this->speedCounter_ = 0.2f;
90        this->targetPosition_ = Vector3::ZERO;
91
92        this->target_.setCallback(createFunctor(&ArtificialController::targetDied, this));
93        this->bSetupWorked = false;
94        this->botlevel_ = 0.5f;
95        this->mode_ = DEFAULT;////Vector-implementation: mode_.push_back(DEFAULT);
96        this->timeout_ = 0;
97        this->currentWaypoint_ = 0;
98        this->setAccuracy(100);
99    }
100
101    ArtificialController::~ArtificialController()
102    {
103        if (this->isInitialized())
104        {//Vector-implementation: mode_.erase(mode_.begin(),mode_.end());
105            for (size_t i = 0; i < this->waypoints_.size(); ++i)
106                this->waypoints_[i]->destroy();
107            this->removeFromFormation();
108            this->weaponModes_.clear();
109            for (ObjectList<ArtificialController>::iterator it = ObjectList<ArtificialController>::begin(); it; ++it)
110            {
111                if (*it != this)
112                {
113                    if (it->myMaster_ == this)
114                    {
115                        COUT(1) << "error: " << this << " is still master in " << (*it) << std::endl;
116                        it->myMaster_ = 0;
117                    }
118
119                    while (true)
120                    {
121                        std::vector<ArtificialController*>::iterator it2 = std::find(it->slaves_.begin(), it->slaves_.end(), this);
122                        if (it2 != it->slaves_.end())
123                        {
124                            COUT(1) << "error: " << this << " is still slave in " << (*it) << std::endl;
125                            it->slaves_.erase(it2);
126                        }
127                        else
128                            break;
129                    }
130                }
131            }
132        }
133    }
134
135    void ArtificialController::XMLPort(Element& xmlelement, XMLPort::Mode mode)
136    {
137        SUPER(ArtificialController, XMLPort, xmlelement, mode);
138
139        XMLPortParam(ArtificialController, "team", setTeam, getTeam, xmlelement, mode).defaultValues(-1);
140        XMLPortParam(ArtificialController, "formationFlight", setFormationFlight, getFormationFlight, xmlelement, mode).defaultValues(false);
141        XMLPortParam(ArtificialController, "formationSize", setFormationSize, getFormationSize, xmlelement, mode).defaultValues(STANDARD_MAX_FORMATION_SIZE);
142        XMLPortParam(ArtificialController, "passive", setPassive, getPassive, xmlelement, mode).defaultValues(false);
143    }
144
145// Documentation only here to get a faster overview for creating a useful documentation...
146
147    /**
148        @brief Activates / deactivates formationflight behaviour
149        @param form activate formflight if form is true
150    */
151    void ArtificialController::formationflight(const bool form)
152    {
153        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
154        {
155            Controller* controller = 0;
156
157            if (it->getController())
158                controller = it->getController();
159            else if (it->getXMLController())
160                controller = it->getXMLController();
161
162            if (!controller)
163                continue;
164
165            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
166
167            if (aiController)
168            {
169                aiController->formationFlight_ = form;
170                if (!form)
171                {
172                    aiController->removeFromFormation();
173                }
174            }
175        }
176    }
177
178    /**
179        @brief Get all masters to do a "specific master action"
180        @param action which action to perform (integer, so it can be called with a console command (tmp solution))
181    */
182    void ArtificialController::masteraction(const int action)
183    {
184        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
185        {
186            Controller* controller = 0;
187
188            if (it->getController())
189                controller = it->getController();
190            else if (it->getXMLController())
191                controller = it->getXMLController();
192
193            if (!controller)
194                continue;
195
196            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
197
198            if(aiController && aiController->state_ == MASTER)
199            {
200                if (action == 1)
201                    aiController->spinInit();
202                if (action == 2)
203                    aiController->turn180Init();
204            }
205        }
206    }
207
208    /**
209        @brief A human player gets followed by its nearest master. Initiated by console command, so far intended for demonstration puproses (possible future pickup).
210    */
211    void ArtificialController::followme()
212    {
213
214        Pawn *humanPawn = NULL;
215        NewHumanController *currentHumanController = NULL;
216        std::vector<ArtificialController*> allMasters;
217
218        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
219        {
220            Controller* controller = 0;
221
222            if (it->getController())
223                controller = it->getController();
224            else if (it->getXMLController())
225                controller = it->getXMLController();
226
227            if (!controller)
228                continue;
229
230            currentHumanController = orxonox_cast<NewHumanController*>(controller);
231
232            if(currentHumanController) humanPawn = *it;
233
234            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
235
236            if(aiController && aiController->state_ == MASTER)
237                allMasters.push_back(aiController);
238
239        }
240
241        if((humanPawn != NULL) && (allMasters.size() != 0))
242        {
243                float posHuman = humanPawn->getPosition().length();
244                float distance = 0.0f;
245                float minDistance = FLT_MAX;
246                int index = 0;
247                int i = 0;
248
249                for(std::vector<ArtificialController*>::iterator it = allMasters.begin(); it != allMasters.end(); it++, i++)
250                    {
251                        if (!ArtificialController::sameTeam((*it)->getControllableEntity(), humanPawn, (*it)->getGametype())) continue;
252                        distance = posHuman - (*it)->getControllableEntity()->getPosition().length();
253                        if(distance < minDistance) index = i;
254                    }
255                allMasters[index]->followInit(humanPawn);
256            }
257
258    }
259
260    /**
261        @brief Sets shooting behaviour of pawns.
262        @param passive if true, bots won't shoot.
263    */
264    void ArtificialController::passivebehaviour(const bool passive)
265    {
266        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
267        {
268            Controller* controller = 0;
269
270            if (it->getController())
271                controller = it->getController();
272            else if (it->getXMLController())
273                controller = it->getXMLController();
274
275            if (!controller)
276                continue;
277
278            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
279
280            if(aiController)
281            {
282                aiController->passive_ = passive;
283            }
284        }
285    }
286
287
288    /**
289        @brief Sets maximal formation size
290        @param size maximal formation size.
291    */
292    void ArtificialController::formationsize(const int size)
293    {
294        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
295        {
296            Controller* controller = 0;
297
298            if (it->getController())
299                controller = it->getController();
300            else if (it->getXMLController())
301                controller = it->getXMLController();
302
303            if (!controller)
304                continue;
305
306            ArtificialController *aiController = orxonox_cast<ArtificialController*>(controller);
307
308            if(aiController)
309            {
310                aiController->maxFormationSize_ = size;
311            }
312        }
313    }
314
315    /**
316        @brief Gets called when ControllableEntity is being changed. Resets the bot when it dies.
317    */
318    void ArtificialController::changedControllableEntity()
319    {
320        if (!this->getControllableEntity())
321            this->removeFromFormation();
322        this->bSetupWorked = false;        // reset weapon information
323        this->setupWeapons();
324    }
325
326    void ArtificialController::removeFromFormation()
327    {
328        if (this->state_ == SLAVE || this->myMaster_) // slaves can also be temporary free, so check if myMaster_ is set
329            this->unregisterSlave();
330        else if (this->state_ == MASTER)
331            this->setNewMasterWithinFormation();
332    }
333
334    void ArtificialController::moveToPosition(const Vector3& target)
335    {
336        if (!this->getControllableEntity())
337            return;
338
339        // Slave uses special movement if its master is in FOLLOW mode
340        if(this->state_ == SLAVE && this->myMaster_ && this->myMaster_->specificMasterAction_ == FOLLOW)
341        {
342//             this->followForSlaves(target);
343//             return;
344        }
345
346        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
347        float distance = (target - this->getControllableEntity()->getPosition()).length();
348
349
350        if(this->state_ == FREE)
351        {
352            if (this->target_ || distance > 10)
353            {
354                // Multiply with ROTATEFACTOR_FREE to make them a bit slower
355                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_FREE * sgn(coord.x) * coord.x*coord.x);
356                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_FREE * sgn(coord.y) * coord.y*coord.y);
357            }
358
359            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
360            {
361              this->getControllableEntity()->moveFrontBack(-0.05f); // They don't brake with full power to give the player a chance
362            } else this->getControllableEntity()->moveFrontBack(SPEED_FREE);
363        }
364
365
366
367        if(this->state_ == MASTER)
368        {
369            if (this->target_ || distance > 10)
370            {
371                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x);
372                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y);
373            }
374
375            if (this->target_ && distance < 200 && this->getControllableEntity()->getVelocity().squaredLength() > this->target_->getVelocity().squaredLength())
376            {
377                this->getControllableEntity()->moveFrontBack(-0.05f);
378            } else this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
379        }
380
381
382
383        if(this->state_ == SLAVE)
384        {
385
386           this->getControllableEntity()->rotateYaw(-2.0f * ROTATEFACTOR_MASTER * sgn(coord.x) * coord.x*coord.x);
387           this->getControllableEntity()->rotatePitch(2.0f * ROTATEFACTOR_MASTER * sgn(coord.y) * coord.y*coord.y);
388
389            if (distance < 300)
390            {
391                if (distance < 40)
392                {
393                    this->getControllableEntity()->moveFrontBack(0.8f*SPEED_MASTER);
394                } else this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER);
395
396            } else {
397                this->getControllableEntity()->moveFrontBack(1.2f*SPEED_MASTER + distance/300.0f);
398            }
399        }
400
401        if (distance < 10)
402        {
403            this->positionReached();
404        }
405    }
406
407    void ArtificialController::moveToTargetPosition()
408    {
409        this->moveToPosition(this->targetPosition_);
410    }
411
412    /**
413        @brief Unregisters a slave from its master. Initiated by a slave.
414    */
415    void ArtificialController::unregisterSlave()
416    {
417        if (this->myMaster_)
418        {
419            std::vector<ArtificialController*>::iterator it = std::find(this->myMaster_->slaves_.begin(), this->myMaster_->slaves_.end(), this);
420            if (it != this->myMaster_->slaves_.end())
421                this->myMaster_->slaves_.erase(it);
422        }
423
424        this->myMaster_ = 0;
425        this->state_ = FREE;
426    }
427
428    void ArtificialController::searchNewMaster()
429    {
430
431        if (!this->getControllableEntity())
432            return;
433
434        this->targetPosition_ = this->getControllableEntity()->getPosition();
435        this->forgetTarget();
436        int teamSize = 0;
437        //go through all pawns
438        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
439        {
440            //same team?
441            if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
442                continue;
443
444            //has it an ArtificialController?
445            Controller* controller = 0;
446
447            if (it->getController())
448                controller = it->getController();
449            else if (it->getXMLController())
450                controller = it->getXMLController();
451
452            if (!controller)
453                continue;
454
455            //is pawn oneself?
456            if (orxonox_cast<ControllableEntity*>(*it) == this->getControllableEntity())
457                continue;
458
459            teamSize++;
460
461            ArtificialController *newMaster = orxonox_cast<ArtificialController*>(controller);
462
463            //is it a master?
464            if (!newMaster || newMaster->state_ != MASTER)
465                continue;
466
467            float distance = (it->getPosition() - this->getControllableEntity()->getPosition()).length();
468
469            // is pawn in range?
470            if (distance < RADIUS_TO_SEARCH_FOR_MASTERS)
471            {
472                if(newMaster->slaves_.size() > this->maxFormationSize_) continue;
473
474                for(std::vector<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++)
475                {
476                    (*itSlave)->myMaster_ = newMaster;
477                    newMaster->slaves_.push_back(*itSlave);
478                }
479                this->slaves_.clear();
480                this->state_ = SLAVE;
481
482                this->myMaster_ = newMaster;
483                newMaster->slaves_.push_back(this);
484
485                break;
486            }
487        }
488
489        if (this->state_ != SLAVE  && teamSize != 0)
490        {
491            this->state_ = MASTER;
492            this->myMaster_ = 0;
493        }
494    }
495
496    /**
497        @brief Commands the slaves of a master into a formation. Sufficiently fast not to be called within tick. Initiated by a master.
498    */
499    void ArtificialController::commandSlaves()
500    {
501        if(this->state_ != MASTER) return;
502
503        Quaternion orient = this->getControllableEntity()->getOrientation();
504        Vector3 dest = this->getControllableEntity()->getPosition();
505
506        // 1 slave: follow
507        if (this->slaves_.size() == 1)
508        {
509            dest += 4*orient*WorldEntity::BACK;
510            this->slaves_.front()->setTargetPosition(dest);
511        }
512        else
513        {
514            dest += 1.0f*orient*WorldEntity::BACK;
515            Vector3 pos = Vector3::ZERO;
516            int i = 1;
517
518            for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
519            {
520                pos = Vector3::ZERO;
521                if (i <= 1) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::LEFT);
522                if (i == 2) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::RIGHT);
523                if (i == 3) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::UP);
524                if (i >= 4)
525                {
526                    pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::DOWN);
527                    i = 1;
528                    dest += (float)FORMATION_LENGTH*(orient*WorldEntity::BACK);
529                    (*it)->setTargetPosition(pos);
530                    continue;
531                }
532                i++;
533                (*it)->setTargetPosition(pos);
534            }
535        }
536    }
537
538    /**
539        @brief Sets a new master within the formation. Called by a master.
540    */
541    void ArtificialController::setNewMasterWithinFormation()
542    {
543        if(this->state_ != MASTER) return;
544
545        if (!this->slaves_.empty())
546        {
547            ArtificialController *newMaster = this->slaves_.back();
548            this->slaves_.pop_back();
549
550            newMaster->state_ = MASTER;
551            newMaster->slaves_ = this->slaves_;
552            newMaster->myMaster_ = 0;
553
554            for(std::vector<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++)
555            {
556                (*it)->myMaster_ = newMaster;
557            }
558        }
559
560        this->slaves_.clear();
561        this->specificMasterAction_ = NONE;
562        this->state_ = FREE;
563    }
564
565    /**
566        @brief Frees all slaves form a master. Initiated by a master.
567    */
568    void ArtificialController::freeSlaves()
569    {
570        if(this->state_ != MASTER) return;
571
572        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
573        {
574            (*it)->state_ = FREE;
575            (*it)->myMaster_ = 0;
576        }
577        this->slaves_.clear();
578    }
579
580    /**
581        @brief Master sets its slaves free for @ref FREEDOM_COUNT seconds.
582    */
583    void ArtificialController::forceFreeSlaves()
584    {
585        if(this->state_ != MASTER) return;
586
587        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
588        {
589            (*it)->state_ = FREE;
590            (*it)->forceFreedom();
591            (*it)->targetPosition_ = this->targetPosition_;
592            (*it)->bShooting_ = true;
593//             (*it)->getControllableEntity()->fire(0);// fire once for fun
594        }
595    }
596
597    void ArtificialController::loseMasterState()
598    {
599        this->freeSlaves();
600        this->state_ = FREE;
601    }
602
603
604    void ArtificialController::forceFreedom()
605    {
606        this->freedomCount_ = FREEDOM_COUNT;
607    }
608
609    /**
610        @brief Checks wether caller has been forced free, decrements time to stay forced free.
611        @return true if forced free.
612    */
613    bool ArtificialController::forcedFree()
614    {
615        if(this->freedomCount_ > 0)
616        {
617            this->freedomCount_--;
618            return true;
619        } else return false;
620    }
621
622    /**
623        @brief Used to continue a "specific master action" for a certain time and resuming normal behaviour after.
624    */
625    void ArtificialController::specificMasterActionHold()
626    {
627        if(this->state_ != MASTER) return;
628
629        if (specificMasterActionHoldCount_ == 0)
630         {
631            this->specificMasterAction_ = NONE;
632            this->searchNewTarget();
633         }
634        else specificMasterActionHoldCount_--;
635    }
636
637    /**
638        @brief Master initializes a 180 degree turn. Leads to a "specific master action".
639    */
640    void ArtificialController::turn180Init()
641    {
642        if(this->state_ != MASTER) return;
643
644        Quaternion orient = this->getControllableEntity()->getOrientation();
645
646        this->setTargetPosition(this->getControllableEntity()->getPosition() + 1000.0f*orient*WorldEntity::BACK);
647
648        this->specificMasterActionHoldCount_ = 4;
649
650        this->specificMasterAction_ = TURN180;
651    }
652
653    /**
654        @brief Execute the 180 degree turn. Called within tick.
655    */
656    void ArtificialController::turn180()
657    {
658            Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_);
659
660            this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x);
661            this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y);
662
663            this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
664    }
665
666    /**
667        @brief Master initializes a spin around its looking direction axis. Leads to a "specific master action".
668    */
669    void ArtificialController::spinInit()
670    {
671        if(this->state_ != MASTER) return;
672        this->specificMasterAction_ = SPIN;
673        this->specificMasterActionHoldCount_ = 10;
674    }
675
676    /**
677        @brief Execute the spin. Called within tick.
678    */
679    void ArtificialController::spin()
680    {
681            this->moveToTargetPosition();
682            this->getControllableEntity()->rotateRoll(0.8f);
683    }
684
685    /**
686        @brief Master begins to follow a pawn. Is a "specific master action".
687        @param pawn pawn to follow.
688        @param always follows pawn forever if true (false if omitted).
689        @param secondsToFollow seconds to follow the pawn if always is false. Will follow pawn 100 seconds if omitted (set in header).
690    */
691    void ArtificialController::followInit(Pawn* pawn, const bool always, const int secondsToFollow)
692    {
693        if (pawn == NULL || this->state_ != MASTER)
694            return;
695        this->specificMasterAction_  =  FOLLOW;
696
697        this->setTarget(pawn);
698        if (!always)
699            this->specificMasterActionHoldCount_ = secondsToFollow;
700        else
701            this->specificMasterActionHoldCount_ = INT_MAX; //for now...
702
703    }
704
705
706    /**
707        @brief Master begins to follow a randomly chosen human player of the same team. Is a "specific master action".
708    */
709    void ArtificialController::followRandomHumanInit()
710    {
711
712        Pawn *humanPawn = NULL;
713        NewHumanController *currentHumanController = NULL;
714
715        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
716        {
717            if (!it->getController())
718                continue;
719
720            currentHumanController = orxonox_cast<NewHumanController*>(it->getController());
721            if(currentHumanController)
722            {
723                if (!ArtificialController::sameTeam(this->getControllableEntity(), *it, this->getGametype())) continue;
724                humanPawn = *it;
725                break;
726            }
727        }
728
729        if((humanPawn != NULL))
730                this->followInit(humanPawn);
731    }
732
733    /**
734        @brief Master follows target with adjusted speed. Called within tick.
735    */
736    void ArtificialController::follow()
737    {
738        if (this->target_)
739            this->moveToPosition(this->target_->getPosition());
740        else
741            this->specificMasterActionHoldCount_ = 0;
742/*
743        if (!this->getControllableEntity())
744            return;
745
746        float distance = (this->target_->getPosition() - this->getControllableEntity()->getPosition()).length();
747
748        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->target_->getPosition());
749
750
751        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
752        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
753
754        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->target_->getVelocity().squaredLength();
755
756COUT(0) << "~follow distance: " << distance << "SpeedCounter: " << this->speedCounter_ << "~speedDiv: " << speedDiv << std::endl;
757        if (distance < 800)
758        {
759            if (distance < 200)
760            {
761                this->speedCounter_ -= 0.5f;
762                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
763                this->getControllableEntity()->moveFrontBack(speedCounter_);
764            } else {
765                if(speedDiv < 0)
766                    this->speedCounter_ +=  0.01f;
767                else
768                    this->speedCounter_ -= 0.05f;
769                this->getControllableEntity()->moveFrontBack(speedCounter_);
770            }
771
772        } else {
773            this->speedCounter_ += 0.05f;
774            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
775        }
776//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
777
778*/
779    }
780
781
782    /**
783        @brief Slave moving behaviour when master is following a pawn, gets redirected from moveToPosition(const Vector3& target)). Called within tick.
784    */
785    void ArtificialController::followForSlaves(const Vector3& target)
786    {
787
788/*
789        if (!this->getControllableEntity() && !this->myMaster_ && this->myMaster_->state_ != FOLLOW && !this->myMaster_->target_)
790            return;
791
792        float distance = (target - this->getControllableEntity()->getPosition()).length();
793
794        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
795
796
797        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
798        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
799
800
801        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->myMaster_->target_->getVelocity().squaredLength();
802
803
804         if (distance < 800)
805        {
806            if (distance < 200)
807            {
808                this->speedCounter_ -= 5.0f;
809                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
810                this->getControllableEntity()->moveFrontBack(speedCounter_);
811            } else {
812                if(speedDiv < 0)
813                    this->speedCounter_ +=  0.01f;
814                else
815                    this->speedCounter_ -= 0.05f;
816                this->getControllableEntity()->moveFrontBack(speedCounter_);
817            }
818
819        } else {
820            this->speedCounter_ += 0.05f;
821            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
822        }
823//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
824*/
825    }
826
827
828    void ArtificialController::setTargetPosition(const Vector3& target)
829    {
830        this->targetPosition_ = target;
831        this->bHasTargetPosition_ = true;
832    }
833
834    void ArtificialController::searchRandomTargetPosition()
835    {
836        this->targetPosition_ = Vector3(rnd(-2000,2000), rnd(-2000,2000), rnd(-2000,2000));
837        this->bHasTargetPosition_ = true;
838    }
839
840    void ArtificialController::setTarget(Pawn* target)
841    {
842        this->target_ = target;
843
844        if (target)
845            this->targetPosition_ = target->getPosition();
846    }
847
848    void ArtificialController::searchNewTarget()
849    {
850        if (!this->getControllableEntity())
851            return;
852
853        this->targetPosition_ = this->getControllableEntity()->getPosition();
854        this->forgetTarget();
855
856        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
857        {
858            if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
859                continue;
860
861            /* So AI won't choose invisible Spaceships as target */
862            if (!it->getRadarVisibility())
863                continue;
864
865            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity())
866            {
867                float speed = this->getControllableEntity()->getVelocity().length();
868                Vector3 distanceCurrent = this->targetPosition_ - this->getControllableEntity()->getPosition();
869                Vector3 distanceNew = it->getPosition() - this->getControllableEntity()->getPosition();
870                if (!this->target_ || it->getPosition().squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceNew) / speed / distanceNew.length()) / math::twoPi)
871                        < this->targetPosition_.squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceCurrent) / speed / distanceCurrent.length()) / math::twoPi) + rnd(-250, 250))
872                {
873                    this->target_ = (*it);
874                    this->targetPosition_ = it->getPosition();
875                }
876            }
877        }
878    }
879
880    void ArtificialController::forgetTarget()
881    {
882        this->target_ = 0;
883        this->bShooting_ = false;
884    }
885
886    void ArtificialController::aimAtTarget()
887    {
888        if (!this->target_ || !this->getControllableEntity())
889            return;
890
891        static const float hardcoded_projectile_speed = 1250;
892
893        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity());
894        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
895
896        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
897        if (pawn)
898            pawn->setAimPosition(this->targetPosition_);
899    }
900
901    bool ArtificialController::isCloseAtTarget(float distance) const
902    {
903        if (!this->getControllableEntity())
904            return false;
905
906        if (!this->target_)
907            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
908        else
909            return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
910    }
911
912    bool ArtificialController::isLookingAtTarget(float angle) const
913    {
914        if (!this->getControllableEntity())
915            return false;
916
917        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
918    }
919
920    void ArtificialController::abandonTarget(Pawn* target)
921    {
922        if (target == this->target_)
923            this->targetDied();
924    }
925
926    void ArtificialController::targetDied()
927    {
928        this->forgetTarget();
929        this->searchRandomTargetPosition();
930    }
931
932    bool ArtificialController::sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype)
933    {
934        if (entity1 == entity2)
935            return true;
936
937        int team1 = -1;
938        int team2 = -1;
939
940        Controller* controller = 0;
941        if (entity1->getController())
942            controller = entity1->getController();
943        else
944            controller = entity1->getXMLController();
945        if (controller)
946        {
947            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
948            if (ac)
949                team1 = ac->getTeam();
950        }
951
952        if (entity2->getController())
953            controller = entity2->getController();
954        else
955            controller = entity2->getXMLController();
956        if (controller)
957        {
958            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
959            if (ac)
960                team2 = ac->getTeam();
961        }
962
963        TeamDeathmatch* tdm = orxonox_cast<TeamDeathmatch*>(gametype);
964        if (tdm)
965        {
966            if (entity1->getPlayer())
967                team1 = tdm->getTeam(entity1->getPlayer());
968
969            if (entity2->getPlayer())
970                team2 = tdm->getTeam(entity2->getPlayer());
971        }
972
973        TeamBaseMatchBase* base = 0;
974        base = orxonox_cast<TeamBaseMatchBase*>(entity1);
975        if (base)
976        {
977            switch (base->getState())
978            {
979                case BaseState::ControlTeam1:
980                    team1 = 0;
981                    break;
982                case BaseState::ControlTeam2:
983                    team1 = 1;
984                    break;
985                case BaseState::Uncontrolled:
986                default:
987                    team1 = -1;
988            }
989        }
990        base = orxonox_cast<TeamBaseMatchBase*>(entity2);
991        if (base)
992        {
993            switch (base->getState())
994            {
995                case BaseState::ControlTeam1:
996                    team2 = 0;
997                    break;
998                case BaseState::ControlTeam2:
999                    team2 = 1;
1000                    break;
1001                case BaseState::Uncontrolled:
1002                default:
1003                    team2 = -1;
1004            }
1005        }
1006
1007        DroneController* droneController = 0;
1008        droneController = orxonox_cast<DroneController*>(entity1->getController());
1009        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity2)
1010            return true;
1011        droneController = orxonox_cast<DroneController*>(entity2->getController());
1012        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity1)
1013            return true;
1014        DroneController* droneController1 = orxonox_cast<DroneController*>(entity1->getController());
1015        DroneController* droneController2 = orxonox_cast<DroneController*>(entity2->getController());
1016        if (droneController1 && droneController2 && droneController1->getOwner() == droneController2->getOwner())
1017            return true;
1018
1019        Dynamicmatch* dynamic = orxonox_cast<Dynamicmatch*>(gametype);
1020        if (dynamic)
1021        {
1022            if (dynamic->notEnoughPigs||dynamic->notEnoughKillers||dynamic->notEnoughChasers) {return false;}
1023
1024            if (entity1->getPlayer())
1025                team1 = dynamic->getParty(entity1->getPlayer());
1026
1027            if (entity2->getPlayer())
1028                team2 = dynamic->getParty(entity2->getPlayer());
1029
1030            if (team1 ==-1 ||team2 ==-1 ) {return false;}
1031            else if (team1 == dynamic->chaser && team2 != dynamic->chaser) {return false;}
1032            else if (team1 == dynamic->piggy && team2 == dynamic->chaser) {return false;}
1033            else if (team1 == dynamic->killer && team2 == dynamic->chaser) {return false;}
1034            else return true;
1035        }
1036
1037        return (team1 == team2 && team1 != -1);
1038    }
1039
1040    /**
1041        @brief DoFire is called when a bot should shoot and decides which weapon is used and whether the bot shoots at all.
1042    */
1043    void ArtificialController::doFire()
1044    {
1045        if(!this->bSetupWorked)//setup: find out which weapons are active ! hard coded: laser is "0", lens flare is "1", ...
1046        {
1047            this->setupWeapons();
1048        }
1049        else if(this->getControllableEntity() && weaponModes_.size()&&this->bShooting_ && this->isCloseAtTarget((1 + 2*botlevel_)*1000) && this->isLookingAtTarget(math::pi / 20.0f))
1050        {
1051            int firemode;
1052            float random = rnd(1);//
1053            if (this->isCloseAtTarget(130) && (firemode = getFiremode("LightningGun")) > -1 )
1054            {//LENSFLARE: short range weapon
1055                this->getControllableEntity()->fire(firemode); //ai uses lens flare if they're close enough to the target
1056            }
1057            else if( this->isCloseAtTarget(400) && (random < this->botlevel_) && (firemode = getFiremode("RocketFire")) > -1 )
1058            {//ROCKET: mid range weapon
1059                this->mode_ = ROCKET; //Vector-implementation: mode_.push_back(ROCKET);
1060                this->getControllableEntity()->fire(firemode); //launch rocket
1061                if(this->getControllableEntity() && this->target_) //after fire(3) is called, getControllableEntity() refers to the rocket!
1062                {
1063                    float speed = this->getControllableEntity()->getVelocity().length() - target_->getVelocity().length();
1064                    if(!speed) speed = 0.1f;
1065                    float distance = target_->getPosition().length() - this->getControllableEntity()->getPosition().length();
1066                    this->timeout_= distance/speed*sgn(speed*distance) + 1.8f; //predicted time of target hit (+ tolerance)
1067                }
1068                else
1069                    this->timeout_ = 4.0f; //TODO: find better default value
1070            }
1071            else if ((firemode = getFiremode("HsW01")) > -1 ) //LASER: default weapon
1072                this->getControllableEntity()->fire(firemode);
1073        }
1074    }
1075
1076    /**
1077        @brief Information gathering: Which weapons are ready to use?
1078    */
1079    void ArtificialController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions)
1080    {
1081        this->bSetupWorked = false;
1082        if(this->getControllableEntity())
1083        {
1084            Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
1085            if(pawn)
1086            {
1087                this->weaponModes_.clear(); // reset previous weapon information
1088                WeaponSlot* wSlot = 0;
1089                for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++)
1090                {
1091                    WeaponMode* wMode = 0;
1092                    for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++)
1093                    {
1094                        std::string wName = wMode->getIdentifier()->getName();
1095                        if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new"
1096                            weaponModes_[wName] = wMode->getMode();
1097                    }
1098                }
1099                if(weaponModes_.size())//at least one weapon detected
1100                    this->bSetupWorked = true;
1101            }//pawn->weaponSystem_->getMunition(SubclassIdentifier< Munition > *identifier)->getNumMunition (WeaponMode *user);
1102        }
1103    }
1104
1105
1106    void ArtificialController::setBotLevel(float level)
1107    {
1108        if (level < 0.0f)
1109            this->botlevel_ = 0.0f;
1110        else if (level > 1.0f)
1111            this->botlevel_ = 1.0f;
1112        else
1113            this->botlevel_ = level;
1114    }
1115
1116    void ArtificialController::setAllBotLevel(float level)
1117    {
1118        for (ObjectList<ArtificialController>::iterator it = ObjectList<ArtificialController>::begin(); it != ObjectList<ArtificialController>::end(); ++it)
1119            it->setBotLevel(level);
1120    }
1121
1122    void ArtificialController::setPreviousMode()
1123    {
1124        this->mode_ = DEFAULT; //Vector-implementation: mode_.pop_back();
1125    }
1126
1127    void ArtificialController::boostControl()
1128    {
1129        SpaceShip* ship = orxonox_cast<SpaceShip*>(this->getControllableEntity());
1130        if(ship == NULL) return;
1131        if(ship->getBoostPower()*1.5f > ship->getInitialBoostPower() ) //upper limit ->boost
1132            this->getControllableEntity()->boost(true);
1133        else if(ship->getBoostPower()*4.0f < ship->getInitialBoostPower()) //lower limit ->do not boost
1134            this->getControllableEntity()->boost(false);
1135    }
1136
1137    int ArtificialController::getFiremode(std::string name)
1138    {
1139        for (std::map< std::string, int >::iterator it = this->weaponModes_.begin(); it != this->weaponModes_.end(); ++it)
1140        {
1141            if (it->first == name)
1142                return it->second;
1143        }
1144        return -1;
1145    }
1146
1147    void ArtificialController::addWaypoint(WorldEntity* waypoint)
1148    {
1149        this->waypoints_.push_back(waypoint);
1150    }
1151
1152    WorldEntity* ArtificialController::getWaypoint(unsigned int index) const
1153    {
1154        if (index < this->waypoints_.size())
1155            return this->waypoints_[index];
1156        else
1157            return 0;
1158    }
1159
1160    void ArtificialController::updatePointsOfInterest(std::string name, float distance)
1161    {
1162        WorldEntity* waypoint = NULL;
1163        if(name == "Pickup")
1164        {
1165            for (ObjectList<WorldEntity>::iterator it = ObjectList<WorldEntity>::begin(); it != ObjectList<WorldEntity>::end(); ++it)
1166            {
1167                //get POI by string: Possible POIs are PICKUPSPAWNER, FORCEFIELDS (!analyse!), ...
1168                //if(it->isA(Pickupable)) //distance to POI decides wether it is added (neither too close nor too far away)
1169                //To Think: how should POI's be managed? (e.g. if there are no real moving target or if the can be taken "en passant".)
1170                   waypoint = *it;
1171                /*const Vector3 realDistance = it->getPosition() - this->getControllableEntity()->getPosition();
1172                if( realDistance.length() < distance)
1173                {
1174                    float minDistance = it->getTriggerDistance().length()*it->getTriggerDistance().length();
1175                    if(this->squaredaccuracy_ > minDistance)
1176                        this->squaredaccuracy_ = minDistance;
1177                    //waypoint = static_cast<WorldEntity*>(it);
1178                    break;
1179               // }*/
1180            }
1181        }
1182        if(waypoint)
1183            this->waypoints_.push_back(waypoint);
1184    }
1185
1186}
Note: See TracBrowser for help on using the repository browser.