Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/gamecontent/src/orxonox/controllers/ArtificialController.cc @ 8909

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

On the way to add quests. Combined distance trigger does not act as expected.

  • Property svn:eol-style set to native
File size: 45.0 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.2f;
95        this->mode_ = DEFAULT;////Vector-implementation: mode_.push_back(DEFAULT);
96        this->timeout_ = 0;
97        this->currentWaypoint_ = 0;
98        this->setAccuracy(5);
99        this->defaultWaypoint_ = NULL;
100    }
101
102    ArtificialController::~ArtificialController()
103    {
104        if (this->isInitialized())
105        {//Vector-implementation: mode_.erase(mode_.begin(),mode_.end());
106            this->waypoints_.clear();
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                        orxout(internal_error) << this << " is still master in " << (*it) << 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                            orxout(internal_error) << this << " is still slave in " << (*it) << 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::absoluteMoveToPosition(const Vector3& target)
408    {
409        float minDistance = 40.0f;
410        if (!this->getControllableEntity())
411            return;
412
413        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
414        float distance = (target - this->getControllableEntity()->getPosition()).length();
415
416            if (this->target_ || distance > minDistance)
417            {
418                // Multiply with ROTATEFACTOR_FREE to make them a bit slower
419                this->getControllableEntity()->rotateYaw(-1.0f * ROTATEFACTOR_FREE * sgn(coord.x) * coord.x*coord.x);
420                this->getControllableEntity()->rotatePitch(ROTATEFACTOR_FREE * sgn(coord.y) * coord.y*coord.y);
421                this->getControllableEntity()->moveFrontBack(SPEED_FREE);
422            }
423
424
425        if (distance < minDistance)
426        {
427            this->positionReached();
428        }
429    }
430
431
432    void ArtificialController::moveToTargetPosition()
433    {
434        this->moveToPosition(this->targetPosition_);
435    }
436
437    /**
438        @brief Unregisters a slave from its master. Initiated by a slave.
439    */
440    void ArtificialController::unregisterSlave()
441    {
442        if (this->myMaster_)
443        {
444            std::vector<ArtificialController*>::iterator it = std::find(this->myMaster_->slaves_.begin(), this->myMaster_->slaves_.end(), this);
445            if (it != this->myMaster_->slaves_.end())
446                this->myMaster_->slaves_.erase(it);
447        }
448
449        this->myMaster_ = 0;
450        this->state_ = FREE;
451    }
452
453    void ArtificialController::searchNewMaster()
454    {
455
456        if (!this->getControllableEntity())
457            return;
458
459        this->targetPosition_ = this->getControllableEntity()->getPosition();
460        this->forgetTarget();
461        int teamSize = 0;
462        //go through all pawns
463        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
464        {
465            //same team?
466            if (!ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
467                continue;
468
469            //has it an ArtificialController?
470            Controller* controller = 0;
471
472            if (it->getController())
473                controller = it->getController();
474            else if (it->getXMLController())
475                controller = it->getXMLController();
476
477            if (!controller)
478                continue;
479
480            //is pawn oneself?
481            if (orxonox_cast<ControllableEntity*>(*it) == this->getControllableEntity())
482                continue;
483
484            teamSize++;
485
486            ArtificialController *newMaster = orxonox_cast<ArtificialController*>(controller);
487
488            //is it a master?
489            if (!newMaster || newMaster->state_ != MASTER)
490                continue;
491
492            float distance = (it->getPosition() - this->getControllableEntity()->getPosition()).length();
493
494            // is pawn in range?
495            if (distance < RADIUS_TO_SEARCH_FOR_MASTERS)
496            {
497                if(newMaster->slaves_.size() > this->maxFormationSize_) continue;
498
499                for(std::vector<ArtificialController*>::iterator itSlave = this->slaves_.begin(); itSlave != this->slaves_.end(); itSlave++)
500                {
501                    (*itSlave)->myMaster_ = newMaster;
502                    newMaster->slaves_.push_back(*itSlave);
503                }
504                this->slaves_.clear();
505                this->state_ = SLAVE;
506
507                this->myMaster_ = newMaster;
508                newMaster->slaves_.push_back(this);
509
510                break;
511            }
512        }
513
514        if (this->state_ != SLAVE  && teamSize != 0)
515        {
516            this->state_ = MASTER;
517            this->myMaster_ = 0;
518        }
519    }
520
521    /**
522        @brief Commands the slaves of a master into a formation. Sufficiently fast not to be called within tick. Initiated by a master.
523    */
524    void ArtificialController::commandSlaves()
525    {
526        if(this->state_ != MASTER) return;
527
528        Quaternion orient = this->getControllableEntity()->getOrientation();
529        Vector3 dest = this->getControllableEntity()->getPosition();
530
531        // 1 slave: follow
532        if (this->slaves_.size() == 1)
533        {
534            dest += 4*orient*WorldEntity::BACK;
535            this->slaves_.front()->setTargetPosition(dest);
536        }
537        else
538        {
539            dest += 1.0f*orient*WorldEntity::BACK;
540            Vector3 pos = Vector3::ZERO;
541            int i = 1;
542
543            for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
544            {
545                pos = Vector3::ZERO;
546                if (i <= 1) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::LEFT);
547                if (i == 2) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::RIGHT);
548                if (i == 3) pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::UP);
549                if (i >= 4)
550                {
551                    pos += dest  + (float)FORMATION_WIDTH*(orient*WorldEntity::DOWN);
552                    i = 1;
553                    dest += (float)FORMATION_LENGTH*(orient*WorldEntity::BACK);
554                    (*it)->setTargetPosition(pos);
555                    continue;
556                }
557                i++;
558                (*it)->setTargetPosition(pos);
559            }
560        }
561    }
562
563    /**
564        @brief Sets a new master within the formation. Called by a master.
565    */
566    void ArtificialController::setNewMasterWithinFormation()
567    {
568        if(this->state_ != MASTER) return;
569
570        if (!this->slaves_.empty())
571        {
572            ArtificialController *newMaster = this->slaves_.back();
573            this->slaves_.pop_back();
574
575            newMaster->state_ = MASTER;
576            newMaster->slaves_ = this->slaves_;
577            newMaster->myMaster_ = 0;
578
579            for(std::vector<ArtificialController*>::iterator it = newMaster->slaves_.begin(); it != newMaster->slaves_.end(); it++)
580            {
581                (*it)->myMaster_ = newMaster;
582            }
583        }
584
585        this->slaves_.clear();
586        this->specificMasterAction_ = NONE;
587        this->state_ = FREE;
588    }
589
590    /**
591        @brief Frees all slaves form a master. Initiated by a master.
592    */
593    void ArtificialController::freeSlaves()
594    {
595        if(this->state_ != MASTER) return;
596
597        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
598        {
599            (*it)->state_ = FREE;
600            (*it)->myMaster_ = 0;
601        }
602        this->slaves_.clear();
603    }
604
605    /**
606        @brief Master sets its slaves free for @ref FREEDOM_COUNT seconds.
607    */
608    void ArtificialController::forceFreeSlaves()
609    {
610        if(this->state_ != MASTER) return;
611
612        for(std::vector<ArtificialController*>::iterator it = slaves_.begin(); it != slaves_.end(); it++)
613        {
614            (*it)->state_ = FREE;
615            (*it)->forceFreedom();
616            (*it)->targetPosition_ = this->targetPosition_;
617            (*it)->bShooting_ = true;
618//             (*it)->getControllableEntity()->fire(0);// fire once for fun
619        }
620    }
621
622    void ArtificialController::loseMasterState()
623    {
624        this->freeSlaves();
625        this->state_ = FREE;
626    }
627
628
629    void ArtificialController::forceFreedom()
630    {
631        this->freedomCount_ = FREEDOM_COUNT;
632    }
633
634    /**
635        @brief Checks wether caller has been forced free, decrements time to stay forced free.
636        @return true if forced free.
637    */
638    bool ArtificialController::forcedFree()
639    {
640        if(this->freedomCount_ > 0)
641        {
642            this->freedomCount_--;
643            return true;
644        } else return false;
645    }
646
647    /**
648        @brief Used to continue a "specific master action" for a certain time and resuming normal behaviour after.
649    */
650    void ArtificialController::specificMasterActionHold()
651    {
652        if(this->state_ != MASTER) return;
653
654        if (specificMasterActionHoldCount_ == 0)
655         {
656            this->specificMasterAction_ = NONE;
657            this->searchNewTarget();
658         }
659        else specificMasterActionHoldCount_--;
660    }
661
662    /**
663        @brief Master initializes a 180 degree turn. Leads to a "specific master action".
664    */
665    void ArtificialController::turn180Init()
666    {
667        if(this->state_ != MASTER) return;
668
669        Quaternion orient = this->getControllableEntity()->getOrientation();
670
671        this->setTargetPosition(this->getControllableEntity()->getPosition() + 1000.0f*orient*WorldEntity::BACK);
672
673        this->specificMasterActionHoldCount_ = 4;
674
675        this->specificMasterAction_ = TURN180;
676    }
677
678    /**
679        @brief Execute the 180 degree turn. Called within tick.
680    */
681    void ArtificialController::turn180()
682    {
683            Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->targetPosition_);
684
685            this->getControllableEntity()->rotateYaw(-2.0f * sgn(coord.x) * coord.x*coord.x);
686            this->getControllableEntity()->rotatePitch(2.0f * sgn(coord.y) * coord.y*coord.y);
687
688            this->getControllableEntity()->moveFrontBack(SPEED_MASTER);
689    }
690
691    /**
692        @brief Master initializes a spin around its looking direction axis. Leads to a "specific master action".
693    */
694    void ArtificialController::spinInit()
695    {
696        if(this->state_ != MASTER) return;
697        this->specificMasterAction_ = SPIN;
698        this->specificMasterActionHoldCount_ = 10;
699    }
700
701    /**
702        @brief Execute the spin. Called within tick.
703    */
704    void ArtificialController::spin()
705    {
706            this->moveToTargetPosition();
707            this->getControllableEntity()->rotateRoll(0.8f);
708    }
709
710    /**
711        @brief Master begins to follow a pawn. Is a "specific master action".
712        @param pawn pawn to follow.
713        @param always follows pawn forever if true (false if omitted).
714        @param secondsToFollow seconds to follow the pawn if always is false. Will follow pawn 100 seconds if omitted (set in header).
715    */
716    void ArtificialController::followInit(Pawn* pawn, const bool always, const int secondsToFollow)
717    {
718        if (pawn == NULL || this->state_ != MASTER)
719            return;
720        this->specificMasterAction_  =  FOLLOW;
721
722        this->setTarget(pawn);
723        if (!always)
724            this->specificMasterActionHoldCount_ = secondsToFollow;
725        else
726            this->specificMasterActionHoldCount_ = INT_MAX; //for now...
727
728    }
729
730
731    /**
732        @brief Master begins to follow a randomly chosen human player of the same team. Is a "specific master action".
733    */
734    void ArtificialController::followRandomHumanInit()
735    {
736
737        Pawn *humanPawn = NULL;
738        NewHumanController *currentHumanController = NULL;
739
740        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
741        {
742            if (!it->getController())
743                continue;
744
745            currentHumanController = orxonox_cast<NewHumanController*>(it->getController());
746            if(currentHumanController)
747            {
748                if (!ArtificialController::sameTeam(this->getControllableEntity(), *it, this->getGametype())) continue;
749                humanPawn = *it;
750                break;
751            }
752        }
753
754        if((humanPawn != NULL))
755                this->followInit(humanPawn);
756    }
757
758    /**
759        @brief Master follows target with adjusted speed. Called within tick.
760    */
761    void ArtificialController::follow()
762    {
763        if (this->target_)
764            this->moveToPosition(this->target_->getPosition());
765        else
766            this->specificMasterActionHoldCount_ = 0;
767/*
768        if (!this->getControllableEntity())
769            return;
770
771        float distance = (this->target_->getPosition() - this->getControllableEntity()->getPosition()).length();
772
773        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, this->target_->getPosition());
774
775
776        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
777        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
778
779        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->target_->getVelocity().squaredLength();
780
781orxout() << "~follow distance: " << distance << "SpeedCounter: " << this->speedCounter_ << "~speedDiv: " << speedDiv << endl;
782        if (distance < 800)
783        {
784            if (distance < 200)
785            {
786                this->speedCounter_ -= 0.5f;
787                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
788                this->getControllableEntity()->moveFrontBack(speedCounter_);
789            } else {
790                if(speedDiv < 0)
791                    this->speedCounter_ +=  0.01f;
792                else
793                    this->speedCounter_ -= 0.05f;
794                this->getControllableEntity()->moveFrontBack(speedCounter_);
795            }
796
797        } else {
798            this->speedCounter_ += 0.05f;
799            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
800        }
801//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
802
803*/
804    }
805
806
807    /**
808        @brief Slave moving behaviour when master is following a pawn, gets redirected from moveToPosition(const Vector3& target)). Called within tick.
809    */
810    void ArtificialController::followForSlaves(const Vector3& target)
811    {
812
813/*
814        if (!this->getControllableEntity() && !this->myMaster_ && this->myMaster_->state_ != FOLLOW && !this->myMaster_->target_)
815            return;
816
817        float distance = (target - this->getControllableEntity()->getPosition()).length();
818
819        Vector2 coord = get2DViewdirection(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->getControllableEntity()->getOrientation() * WorldEntity::UP, target);
820
821
822        this->getControllableEntity()->rotateYaw(-0.8f * sgn(coord.x) * coord.x*coord.x);
823        this->getControllableEntity()->rotatePitch(0.8f * sgn(coord.y) * coord.y*coord.y);
824
825
826        float speedDiv = this->getControllableEntity()->getVelocity().squaredLength() - this->myMaster_->target_->getVelocity().squaredLength();
827
828
829         if (distance < 800)
830        {
831            if (distance < 200)
832            {
833                this->speedCounter_ -= 5.0f;
834                if(this->speedCounter_ < 0) this->speedCounter_ = 0.0f;
835                this->getControllableEntity()->moveFrontBack(speedCounter_);
836            } else {
837                if(speedDiv < 0)
838                    this->speedCounter_ +=  0.01f;
839                else
840                    this->speedCounter_ -= 0.05f;
841                this->getControllableEntity()->moveFrontBack(speedCounter_);
842            }
843
844        } else {
845            this->speedCounter_ += 0.05f;
846            this->getControllableEntity()->moveFrontBack(speedCounter_ + distance/300.0f);
847        }
848//         if (this->getControllableEntity()->getVelocity().squaredLength() > 50.0f) this->speedCounter_ = 0;
849*/
850    }
851
852
853    void ArtificialController::setTargetPosition(const Vector3& target)
854    {
855        this->targetPosition_ = target;
856        this->bHasTargetPosition_ = true;
857    }
858
859    void ArtificialController::searchRandomTargetPosition()
860    {
861        this->targetPosition_ = Vector3(rnd(-2000,2000), rnd(-2000,2000), rnd(-2000,2000));
862        this->bHasTargetPosition_ = true;
863    }
864
865    void ArtificialController::setTarget(Pawn* target)
866    {
867        this->target_ = target;
868
869        if (target)
870            this->targetPosition_ = target->getPosition();
871    }
872
873    void ArtificialController::searchNewTarget()
874    {
875        if (!this->getControllableEntity())
876            return;
877
878        this->targetPosition_ = this->getControllableEntity()->getPosition();
879        this->forgetTarget();
880
881        for (ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it; ++it)
882        {
883            if (ArtificialController::sameTeam(this->getControllableEntity(), static_cast<ControllableEntity*>(*it), this->getGametype()))
884                continue;
885
886            /* So AI won't choose invisible Spaceships as target */
887            if (!it->getRadarVisibility())
888                continue;
889
890            if (static_cast<ControllableEntity*>(*it) != this->getControllableEntity())
891            {
892                float speed = this->getControllableEntity()->getVelocity().length();
893                Vector3 distanceCurrent = this->targetPosition_ - this->getControllableEntity()->getPosition();
894                Vector3 distanceNew = it->getPosition() - this->getControllableEntity()->getPosition();
895                if (!this->target_ || it->getPosition().squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceNew) / speed / distanceNew.length()) / math::twoPi)
896                        < this->targetPosition_.squaredDistance(this->getControllableEntity()->getPosition()) * (1.5f + acos((this->getControllableEntity()->getOrientation() * WorldEntity::FRONT).dotProduct(distanceCurrent) / speed / distanceCurrent.length()) / math::twoPi) + rnd(-250, 250))
897                {
898                    this->target_ = (*it);
899                    this->targetPosition_ = it->getPosition();
900                }
901            }
902        }
903    }
904
905    void ArtificialController::forgetTarget()
906    {
907        this->target_ = 0;
908        this->bShooting_ = false;
909    }
910
911    void ArtificialController::aimAtTarget()
912    {
913        if (!this->target_ || !this->getControllableEntity())
914            return;
915
916        static const float hardcoded_projectile_speed = 1250;
917
918        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity());
919        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
920
921        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
922        if (pawn)
923            pawn->setAimPosition(this->targetPosition_);
924    }
925
926    bool ArtificialController::isCloseAtTarget(float distance) const
927    {
928        if (!this->getControllableEntity())
929            return false;
930
931        if (!this->target_)
932            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
933        else
934            return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
935    }
936
937    bool ArtificialController::isLookingAtTarget(float angle) const
938    {
939        if (!this->getControllableEntity())
940            return false;
941
942        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
943    }
944
945    void ArtificialController::abandonTarget(Pawn* target)
946    {
947        if (target == this->target_)
948            this->targetDied();
949    }
950
951    void ArtificialController::targetDied()
952    {
953        this->forgetTarget();
954        this->searchRandomTargetPosition();
955    }
956
957    bool ArtificialController::sameTeam(ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype)
958    {
959        if(!entity1 || !entity2)
960            return true;
961        if (entity1 == entity2)
962            return true;
963
964        int team1 = -1;
965        int team2 = -1;
966
967        Controller* controller = 0;
968        if (entity1->getController())
969            controller = entity1->getController();
970        else
971            controller = entity1->getXMLController();
972        if (controller)
973        {
974            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
975            if (ac)
976                team1 = ac->getTeam();
977        }
978
979        if (entity2->getController())
980            controller = entity2->getController();
981        else
982            controller = entity2->getXMLController();
983        if (controller)
984        {
985            ArtificialController* ac = orxonox_cast<ArtificialController*>(controller);
986            if (ac)
987                team2 = ac->getTeam();
988        }
989
990        TeamDeathmatch* tdm = orxonox_cast<TeamDeathmatch*>(gametype);
991        if (tdm)
992        {
993            if (entity1->getPlayer())
994                team1 = tdm->getTeam(entity1->getPlayer());
995
996            if (entity2->getPlayer())
997                team2 = tdm->getTeam(entity2->getPlayer());
998        }
999
1000        TeamBaseMatchBase* base = 0;
1001        base = orxonox_cast<TeamBaseMatchBase*>(entity1);
1002        if (base)
1003        {
1004            switch (base->getState())
1005            {
1006                case BaseState::ControlTeam1:
1007                    team1 = 0;
1008                    break;
1009                case BaseState::ControlTeam2:
1010                    team1 = 1;
1011                    break;
1012                case BaseState::Uncontrolled:
1013                default:
1014                    team1 = -1;
1015            }
1016        }
1017        base = orxonox_cast<TeamBaseMatchBase*>(entity2);
1018        if (base)
1019        {
1020            switch (base->getState())
1021            {
1022                case BaseState::ControlTeam1:
1023                    team2 = 0;
1024                    break;
1025                case BaseState::ControlTeam2:
1026                    team2 = 1;
1027                    break;
1028                case BaseState::Uncontrolled:
1029                default:
1030                    team2 = -1;
1031            }
1032        }
1033
1034        DroneController* droneController = 0;
1035        droneController = orxonox_cast<DroneController*>(entity1->getController());
1036        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity2)
1037            return true;
1038        droneController = orxonox_cast<DroneController*>(entity2->getController());
1039        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity1)
1040            return true;
1041        DroneController* droneController1 = orxonox_cast<DroneController*>(entity1->getController());
1042        DroneController* droneController2 = orxonox_cast<DroneController*>(entity2->getController());
1043        if (droneController1 && droneController2 && droneController1->getOwner() == droneController2->getOwner())
1044            return true;
1045
1046        Dynamicmatch* dynamic = orxonox_cast<Dynamicmatch*>(gametype);
1047        if (dynamic)
1048        {
1049            if (dynamic->notEnoughPigs||dynamic->notEnoughKillers||dynamic->notEnoughChasers) {return false;}
1050
1051            if (entity1->getPlayer())
1052                team1 = dynamic->getParty(entity1->getPlayer());
1053
1054            if (entity2->getPlayer())
1055                team2 = dynamic->getParty(entity2->getPlayer());
1056
1057            if (team1 ==-1 ||team2 ==-1 ) {return false;}
1058            else if (team1 == dynamic->chaser && team2 != dynamic->chaser) {return false;}
1059            else if (team1 == dynamic->piggy && team2 == dynamic->chaser) {return false;}
1060            else if (team1 == dynamic->killer && team2 == dynamic->chaser) {return false;}
1061            else return true;
1062        }
1063
1064        return (team1 == team2 && team1 != -1);
1065    }
1066
1067    /**
1068        @brief DoFire is called when a bot should shoot and decides which weapon is used and whether the bot shoots at all.
1069    */
1070    void ArtificialController::doFire()
1071    {
1072        if(!this->bSetupWorked)//setup: find out which weapons are active ! hard coded: laser is "0", lens flare is "1", ...
1073        {
1074            this->setupWeapons();
1075        }
1076        else if(this->getControllableEntity() && weaponModes_.size()&&this->bShooting_ && this->isCloseAtTarget((1 + 2*botlevel_)*1000) && this->isLookingAtTarget(math::pi / 20.0f))
1077        {
1078            int firemode;
1079            float random = rnd(1);//
1080            if (this->isCloseAtTarget(130) && (firemode = getFiremode("LightningGun")) > -1 )
1081            {//LENSFLARE: short range weapon
1082                this->getControllableEntity()->fire(firemode); //ai uses lens flare if they're close enough to the target
1083            }
1084            else if( this->isCloseAtTarget(400) && (random < this->botlevel_) && (firemode = getFiremode("RocketFire")) > -1 )
1085            {//ROCKET: mid range weapon
1086                this->mode_ = ROCKET; //Vector-implementation: mode_.push_back(ROCKET);
1087                this->getControllableEntity()->fire(firemode); //launch rocket
1088                if(this->getControllableEntity() && this->target_) //after fire(3) is called, getControllableEntity() refers to the rocket!
1089                {
1090                    float speed = this->getControllableEntity()->getVelocity().length() - target_->getVelocity().length();
1091                    if(!speed) speed = 0.1f;
1092                    float distance = target_->getPosition().length() - this->getControllableEntity()->getPosition().length();
1093                    this->timeout_= distance/speed*sgn(speed*distance) + 1.8f; //predicted time of target hit (+ tolerance)
1094                }
1095                else
1096                    this->timeout_ = 4.0f; //TODO: find better default value
1097            }
1098            else if ((firemode = getFiremode("HsW01")) > -1 ) //LASER: default weapon
1099                this->getControllableEntity()->fire(firemode);
1100        }
1101    }
1102
1103    /**
1104        @brief Information gathering: Which weapons are ready to use?
1105    */
1106    void ArtificialController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions)
1107    {
1108        this->bSetupWorked = false;
1109        if(this->getControllableEntity())
1110        {
1111            Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
1112            if(pawn && pawn->isA(Class(SpaceShip))) //fix for First Person Mode: check for SpaceShip
1113            {
1114                this->weaponModes_.clear(); // reset previous weapon information
1115                WeaponSlot* wSlot = 0;
1116                for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++)
1117                {
1118                    WeaponMode* wMode = 0;
1119                    for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++)
1120                    {
1121                        std::string wName = wMode->getIdentifier()->getName();
1122                        if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new"
1123                            weaponModes_[wName] = wMode->getMode();
1124                    }
1125                }
1126                if(weaponModes_.size())//at least one weapon detected
1127                    this->bSetupWorked = true;
1128            }//pawn->weaponSystem_->getMunition(SubclassIdentifier< Munition > *identifier)->getNumMunition (WeaponMode *user);
1129        }
1130    }
1131
1132
1133    void ArtificialController::setBotLevel(float level)
1134    {
1135        if (level < 0.0f)
1136            this->botlevel_ = 0.0f;
1137        else if (level > 1.0f)
1138            this->botlevel_ = 1.0f;
1139        else
1140            this->botlevel_ = level;
1141    }
1142
1143    void ArtificialController::setAllBotLevel(float level)
1144    {
1145        for (ObjectList<ArtificialController>::iterator it = ObjectList<ArtificialController>::begin(); it != ObjectList<ArtificialController>::end(); ++it)
1146            it->setBotLevel(level);
1147    }
1148
1149    void ArtificialController::setPreviousMode()
1150    {
1151        this->mode_ = DEFAULT; //Vector-implementation: mode_.pop_back();
1152    }
1153
1154    /**
1155        @brief Manages boost. Switches between boost usage and boost safe mode.
1156    */
1157    void ArtificialController::boostControl()
1158    {
1159        SpaceShip* ship = orxonox_cast<SpaceShip*>(this->getControllableEntity());
1160        if(ship == NULL) return;
1161        if(ship->getBoostPower()*1.5f > ship->getInitialBoostPower() ) //upper limit ->boost
1162            this->getControllableEntity()->boost(true);
1163        else if(ship->getBoostPower()*4.0f < ship->getInitialBoostPower()) //lower limit ->do not boost
1164            this->getControllableEntity()->boost(false);
1165    }
1166
1167    int ArtificialController::getFiremode(std::string name)
1168    {
1169        for (std::map< std::string, int >::iterator it = this->weaponModes_.begin(); it != this->weaponModes_.end(); ++it)
1170        {
1171            if (it->first == name)
1172                return it->second;
1173        }
1174        return -1;
1175    }
1176
1177    void ArtificialController::addWaypoint(WorldEntity* waypoint)
1178    {
1179        this->waypoints_.push_back(waypoint);
1180    }
1181
1182    WorldEntity* ArtificialController::getWaypoint(unsigned int index) const
1183    {
1184        if (index < this->waypoints_.size())
1185            return this->waypoints_[index];
1186        else
1187            return 0;
1188    }
1189
1190    /**
1191        @brief Adds first waypoint of type name to the waypoint stack, which is within the searchDistance
1192        @param name object-name of a point of interest (e.g. "PickupSpawner", "ForceField")
1193    */
1194    void ArtificialController::updatePointsOfInterest(std::string name, float searchDistance)
1195    {
1196        WorldEntity* waypoint = NULL;
1197        for (ObjectList<WorldEntity>::iterator it = ObjectList<WorldEntity>::begin(); it != ObjectList<WorldEntity>::end(); ++it)
1198        {
1199            if((*it)->getIdentifier() == ClassByString(name))
1200            {
1201                ControllableEntity* controllable = this->getControllableEntity();
1202                if(!controllable) continue;
1203                float actualDistance = ( (*it)->getPosition() - controllable->getPosition() ).length();
1204                if(actualDistance > searchDistance || actualDistance < 5.0f) continue;
1205                    // TODO: PickupSpawner: adjust waypoint accuracy to PickupSpawner's triggerdistance
1206                    // TODO: ForceField: analyze is angle between forcefield boost and own flying direction is acceptable
1207                else
1208                {
1209                    waypoint = *it;
1210                    break;
1211                }
1212            }
1213        }
1214        if(waypoint)
1215            this->waypoints_.push_back(waypoint);
1216    }
1217
1218    /**
1219        @brief Adds point of interest depending on context. Further Possibilites: "ForceField", "PortalEndPoint", "MovableEntity", "Dock"
1220    */
1221    void ArtificialController::manageWaypoints()
1222    {
1223        if(!defaultWaypoint_)
1224            this->updatePointsOfInterest("PickupSpawner", 200.0f); // long search radius if there is no default goal
1225        else
1226            this->updatePointsOfInterest("PickupSpawner", 20.0f); // take pickup en passant if there is a default waypoint
1227    }
1228
1229}
Note: See TracBrowser for help on using the repository browser.