Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/controllers/ActionpointController.cc @ 12250

Last change on this file since 12250 was 11083, checked in by muemart, 9 years ago

Fix some clang-tidy warnings.
Also, Serialise.h was doing some C-style casts that ended up being const casts. I moved those const casts as close to the source as possible and changed the loadAndIncrease functions to not do that.

  • Property svn:eol-style set to native
File size: 21.8 KB
RevLine 
[10864]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:
[10885]23 *      Gani Aliguzhinov
[10864]24 *   Co-authors:
[10885]25 *      ...
[10864]26 *
27 */
28
29#include "ActionpointController.h"
30
31#include "core/XMLPort.h"
[10875]32#include <algorithm>
[10877]33#include "worldentities/Actionpoint.h"
[10864]34namespace orxonox
35{
36
37    RegisterClass(ActionpointController);
38
[10871]39    ActionpointController::ActionpointController(Context* context) : FightingController(context)
[10864]40    {
[10923]41        this->ticks_ = 0;
[10915]42        this->bPatrolling_ = false;
[10877]43        this->bInLoop_ = false;
[10864]44        this->bLoop_ = false;
45        this->bEndLoop_ = false;
[10888]46        loopActionpoints_.clear();
47        parsedActionpoints_.clear();
48        actionpoints_.clear();
[10864]49        this->bTakenOver_ = false;
50        this->action_ = Action::NONE;
51        this->squaredaccuracy_ = 2500;
[10906]52        this->bStartedDodging_ = false;
[10912]53        this->bDefaultPatrol_ = true;
54        this->bDefaultFightAll_ = true;
[10864]55        RegisterObject(ActionpointController);
56
57    }
58    void ActionpointController::XMLPort( Element& xmlelement, XMLPort::Mode mode )
59    {
60        SUPER( ActionpointController, XMLPort, xmlelement, mode );
[10912]61
[10864]62        XMLPortObject(ActionpointController, WorldEntity, "actionpoints", addActionpoint, getActionpoint,  xmlelement, mode);
[10912]63        XMLPortParam(ActionpointController, "defaultFightAll", setDefaultFightAll, getDefaultFightAll, xmlelement, mode).defaultValues(true);
64        XMLPortParam(ActionpointController, "defaultPatrol", setDefaultPatrol, getDefaultPatrol, xmlelement, mode).defaultValues(true);
[10864]65    }
[10912]66
[10886]67    ActionpointController::~ActionpointController()
68    {
69        loopActionpoints_.clear();
70        parsedActionpoints_.clear();
71        actionpoints_.clear();
[10935]72
[10886]73    }
74    void ActionpointController::tick(float dt)
75    {
[11083]76        if (!this->getControllableEntity() || !this->isActive())
[10915]77            return;
[10953]78
[10955]79        //count ticks, ticks_ is unsigned, so overflow is not a problem
[10923]80        ++this->ticks_;
[10953]81        if (this->ticks_ == 1)
[10885]82        {
[10955]83            //those vectors are in reversed order after being set by XML.
[10923]84            std::reverse(parsedActionpoints_.begin(), parsedActionpoints_.end());
85            std::reverse(actionpoints_.begin(), actionpoints_.end());
[10906]86        }
[10935]87
[10955]88        //fly
[10886]89        if (this->bHasTargetPosition_)
[10864]90        {
91            this->moveToTargetPosition(dt);
[10955]92        }//or just rotate
[10864]93        else if (this->bLookAtTarget_)
94        {
95            this->lookAtTarget(dt);
96        }
[10925]97       
[10955]98        //don't fire rocket each tick
[10923]99        if (timeout_ <= 0)
[10953]100        {   
[10923]101            this->bFiredRocket_ = false;
[10953]102        }
103        else if (this->bFiredRocket_)
[10925]104        {
[10934]105            --this->timeout_;
[10925]106        }
107
[10955]108        //sometimes dodge, sometimes attack
[10953]109        if (this->ticks_ % 80 <= 10)
[10927]110        {
111            this->bDodge_ = false;
112        }
113        else
114        {
115            this->bDodge_ = true;
116        }
[10925]117
[10955]118        //fire if you can
[10953]119        if (this->bShooting_)
[10924]120        {
[10953]121            this->doFire();
[10906]122        }
[10886]123        SUPER(ActionpointController, tick, dt);
124    }
[10912]125     
[10955]126    /**
127    @brief
128        action() manages the state machine.
129    */
[10910]130
[10886]131    void ActionpointController::action()
132    {
[11083]133        if (!this->getControllableEntity() || !this->isActive())
[10886]134            return;
[10935]135
[10955]136        //deltaHp is used to know if this got attacked
[10953]137        this->deltaHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth() - this->previousHp;
138        this->previousHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth();
[10955]139
140        //look out for enemies
[10912]141        if (this->bDefaultPatrol_ || (this->action_ != Action::FLY && this->action_ != Action::NONE))
142        {
143            this->startAttackingEnemiesThatAreClose();
144        }
[10923]145
[10886]146        //No action -> pop one from stack
147        if (this->action_ == Action::NONE || this->bTakenOver_)
148        {
[10955]149            //if default behaviour is fighting all, push it onto the stack
[10912]150            if (this->parsedActionpoints_.empty() && this->loopActionpoints_.empty() && this->bDefaultFightAll_)
[10886]151            {
152                Point p = { Action::FIGHTALL, "", Vector3::ZERO, false };
153                this->parsedActionpoints_.push_back (p);
154            }
155            this->executeActionpoint();
156            this->bTakenOver_ = false;
[10879]157        }
[10923]158
[10886]159        //Action fightall -> fight till nobody alive
160        if (this->action_ == Action::FIGHTALL)
161        {
[10903]162
[10886]163            if (!this->hasTarget())
164            {
165                ControllableEntity* newTarget = this->closestTarget();   
166                if (newTarget)
167                {
168                    this->setAction (Action::FIGHTALL, newTarget);
169                }
170                else
171                {
172                    this->nextActionpoint();
[10915]173                    this->executeActionpoint();
174   
[10886]175                }
176            }
177        }
178        //Action fight -> fight as long as enemies in range
179        else if (this->action_ == Action::FIGHT)
180        {
[10903]181            if (!this->hasTarget() )
[10886]182            {
183                //----find a target----
[11083]184                ControllableEntity* newTarget = this->closestTarget();
[10886]185                if (newTarget && 
186                        CommonController::distance (this->getControllableEntity(), newTarget) < this->attackRange_)
187                {
188                    this->setAction (Action::FIGHT, newTarget);
189                }
190                else
191                {
192                    this->nextActionpoint();
[10915]193                    this->executeActionpoint();
[10886]194                }
195            }
196            else if (this->hasTarget())
197            {
198                //----fly in formation if far enough----
199                Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();         
200                   
201                if (diffVector.length() > this->attackRange_)
202                {
203                    ControllableEntity* newTarget = this->closestTarget();
204                    if (newTarget && 
205                        CommonController::distance (this->getControllableEntity(), newTarget) < this->attackRange_)
206                    {
207                        this->setAction (Action::FIGHT, newTarget);
208                    }
209                    else
210                    {
211                        this->nextActionpoint();
[10915]212                        this->executeActionpoint();
[10886]213                    }
214                }
215            }
216        }
217        else if (this->action_ == Action::FLY)
218        {
219            if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
220            {
221                this->nextActionpoint();   
[10915]222                this->executeActionpoint();
[10886]223            }
224        }
225        else if (this->action_ == Action::PROTECT)
226        {
227            if (!this->getProtect())
228            {
229                this->nextActionpoint();
[10915]230                this->executeActionpoint(); 
[10886]231            }
232            this->stayNearProtect();
233        }
234        else if (this->action_ == Action::ATTACK)
235        {   
236            if (!this->hasTarget())
237            {
238                this->nextActionpoint();
[10915]239                this->executeActionpoint();
[10886]240            }
241        }
[10864]242    }
[10955]243    /**
244    @brief
245        if action is protect, this follows protect_ and fights enemies that are close
246    */
[10864]247    void ActionpointController::setProtect (ControllableEntity* protect)
248    {
249        this->protect_ = protect;
250    }
251    ControllableEntity* ActionpointController::getProtect ()
252    {
253        return this->protect_;
254    }
[10955]255    //XML method
[10864]256    void ActionpointController::addActionpoint(WorldEntity* actionpoint)
257    {
258        std::string actionName;
259        Vector3 position;
260        std::string targetName;
261        bool inLoop = false;
262        Point p;
[10888]263        if (actionpoint->getIdentifier()->getName() == "Actionpoint")
[10864]264        {
[10888]265            Actionpoint* ap = orxonox_cast<Actionpoint*> (actionpoint);
[10864]266            actionName = ap->getActionXML();
267            targetName = ap->getName();
268            position = ap->getWorldPosition();
269
270            if (this->bEndLoop_)
271            {
272                this->bInLoop_ = false;
273            }
274            if (!this->bInLoop_ && ap->getLoopStart())
275            {
276                this->bInLoop_ = true;
277            }
278            if (this->bInLoop_ && ap->getLoopEnd())
279            {
280                this->bEndLoop_ = true;
281            }
282            inLoop = this->bInLoop_;
283
[11071]284            Action value;
[10864]285           
286            if ( actionName == "FIGHT" )
287            { value = Action::FIGHT; }
288            else if ( actionName == "FLY" )
289            { value = Action::FLY; }
290            else if ( actionName == "PROTECT" )
291            { value = Action::PROTECT; }
292            else if ( actionName == "NONE" )
293            { value = Action::NONE; }
294            else if ( actionName == "FIGHTALL" )
295            { value = Action::FIGHTALL; }
296            else if ( actionName == "ATTACK" )
297            { value = Action::ATTACK; }
298            else
299                ThrowException( ParseError, std::string( "Attempting to set an unknown Action: '" )+ actionName + "'." );
300            p.action = value; p.name = targetName; p.position = position; p.inLoop = inLoop;
301        }
302        else
303        {
[10888]304            inLoop = true;
[10864]305            p.action = Action::FLY; p.name = ""; p.position = actionpoint->getWorldPosition(); p.inLoop = inLoop;
306        }
307            parsedActionpoints_.push_back(p);
308            this->actionpoints_.push_back(actionpoint);
309    }
[10955]310    //XML method
[10864]311    WorldEntity* ActionpointController::getActionpoint(unsigned int index) const
312    {
313        if (index < this->actionpoints_.size())
314            return this->actionpoints_[index];
315        else
[11071]316            return nullptr;
[10864]317    }
[10955]318    //XML method
[11071]319    Action ActionpointController::getAction ()
[10864]320    {
321        return this->action_;
322    }
[10955]323    //XML method
[10864]324    std::string ActionpointController::getActionName()
325    {
326        switch ( this->action_ )
327        {
328            case Action::FIGHT:
[10923]329            { return "FIGHT"; }
[10864]330            case Action::FLY:
[10923]331            { return "FLY"; }
[10864]332            case Action::PROTECT:
[10923]333            { return "PROTECT"; }
[10864]334            case Action::NONE:
[10923]335            { return "NONE"; }
[10864]336            case Action::FIGHTALL:
[10923]337            { return "FIGHTALL"; }
[10864]338            case Action::ATTACK:
[10923]339            { return "ATTACK"; }
[10864]340            default:
341                return "NONE";
342                break;
343        }
344    }
[10955]345    //XML method
[11071]346    void ActionpointController::setAction (Action action)
[10864]347    {
348        this->action_ = action;
349    }
[10955]350    //set action and target/protect
[11071]351    void ActionpointController::setAction (Action action, ControllableEntity* target)
[10864]352    {
[11083]353        if (!this->getControllableEntity())
[10946]354            return;
[10864]355        this->action_ = action;
356        if (action == Action::FIGHT || action == Action::FIGHTALL || action == Action::ATTACK)
357        {   
358            if (target)
359                this->setTarget (target);
360        }
361        else if (action == Action::PROTECT)
362        {
363            if (target)
364                this->setProtect (target);
365        }
366    }
[10955]367    //set action and target position
[11071]368    void ActionpointController::setAction (Action action, const Vector3& target)
[10864]369    {
[11083]370        if (!this->getControllableEntity())
[10946]371            return;
[10864]372        this->action_ = action;
373        if (action == Action::FLY)
374        {
375            this->setTargetPosition (target);
376        }
377    }
[10955]378    //set action and target position and orientation
[11071]379    void ActionpointController::setAction (Action action, const Vector3& target,  const Quaternion& orient )
[10864]380    {
[11083]381        if (!this->getControllableEntity())
[10946]382            return;
[10864]383        this->action_ = action;
384        if (action == Action::FLY)
385        {
386            this->setTargetPosition (target);
387            this->setTargetOrientation (orient);
388        } 
389    }
390   
391    //------------------------------------------------------------------------------
392    //------------------------------Actionpoint methods-----------------------------
393    //------------------------------------------------------------------------------
394
395    //POST: this starts doing what was asked by the last element of parsedActionpoints_,
396    //if last element was failed to be parsed, next element will be executed.
397    void ActionpointController::executeActionpoint()
398    {
[11083]399        if (!this->getControllableEntity())
[10923]400            return;
401
[10872]402        Point p;
403        if (this->bLoop_ && !loopActionpoints_.empty())
[10864]404        {
[10872]405            p = loopActionpoints_.back();
406        }
407        else if (this->bLoop_)
408        {
409            this->bLoop_ = false;
410            return;
411        }
412        else if (!this->bLoop_ && !parsedActionpoints_.empty())
413        {
414            p = parsedActionpoints_.back();
415        }
416        else
417        {
[11071]418            this->setTarget(nullptr);
[10872]419            this->setTargetPosition(this->getControllableEntity()->getWorldPosition());
420            this->action_ = Action::NONE;
421            return;
422        }
423        if (!this->bLoop_ && this->parsedActionpoints_.back().inLoop)
424        {
425            //MOVES all points that are in loop to a loop vector
426            this->fillLoop();
427            this->bLoop_ = true;
428            executeActionpoint();
429            return;
430        }
[10886]431        this->setAction (p.action);
[10925]432
[10886]433        switch (this->action_)
[10872]434        {
435            case Action::FIGHT:
[10864]436            {
[10872]437                std::string targetName = p.name;
438                if (targetName == "")
439                    break;
[11071]440                for (Pawn* pawn : ObjectList<Pawn>())
[10872]441                {
[11071]442                    if (CommonController::getName(pawn) == targetName)
[10864]443                    {
[11071]444                        this->setTarget (static_cast<ControllableEntity*>(pawn));
[10864]445                    }
[10886]446                }
[10872]447                break;
448            }
449            case Action::FLY:
450            {
451                this->setTargetPosition( p.position );
452                if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
453                {
454                    this->nextActionpoint();
455                    this->executeActionpoint();
456                }
457                break;
458            }
459            case Action::PROTECT:
460            {
[10923]461
[10872]462                std::string protectName = p.name;
463                if (protectName == "reservedKeyword:human")
464                {
[11071]465                    for (Pawn* pawn : ObjectList<Pawn>())
[10864]466                    {
[11071]467                        if (orxonox_cast<ControllableEntity*>(pawn) && (pawn->getController()) && (pawn->getController()->getIdentifier()->getName() == "NewHumanController"))
[10864]468                        {
[11071]469                            this->setProtect (static_cast<ControllableEntity*>(pawn));
[10864]470                        }
471                    }
[10872]472                }
473                else
474                {
[11071]475                    for (Pawn* pawn : ObjectList<Pawn>())
[10864]476                    {
[11071]477                        if (CommonController::getName(pawn) == protectName)
[10864]478                        {
[11071]479                            this->setProtect (static_cast<ControllableEntity*>(pawn));
[10864]480                        }
[10872]481                    }                           
[10864]482                }
[10872]483                if (!this->getProtect())
484                {
485                    this->nextActionpoint();
486                    this->executeActionpoint();
487                }
488                break;
[10864]489            }
[10872]490            case Action::NONE:
[10864]491            {
[10872]492                break;
[10864]493            }
[10872]494            case Action::FIGHTALL:
[10864]495            {
[10872]496                break;
497            }
498            case Action::ATTACK:
499            {
500                std::string targetName = p.name;
501
[11071]502                for (Pawn* pawn : ObjectList<Pawn>())
[10864]503                {
[11071]504                    if (CommonController::getName(pawn) == targetName)
[10864]505                    {
[11071]506                        this->setTarget (static_cast<ControllableEntity*>(pawn));
[10864]507                    }
508                }
[10872]509                if (!this->hasTarget())
510                {
511                    this->nextActionpoint();
512                    this->executeActionpoint();
513                }
514                break;
[10864]515            }
[10872]516            default:
517                break;
[10886]518        }   
[10872]519    }
[10864]520
[10955]521    //calculate where in world coordinates this ship has to be, so that it keeps distance to protect_, and fly there
[10864]522    void ActionpointController::stayNearProtect()
523    {
[11083]524        if (!this->getControllableEntity())
[10923]525            return;
526
[10886]527        Vector3 targetRelativePosition(0, 300, 300);
528        if (!this->getProtect())
529        {
530            this->nextActionpoint();
531            return;
532        } 
[10864]533        Vector3 targetAbsolutePosition = ((this->getProtect()->getWorldPosition()) + 
[10880]534            (this->getProtect()->getWorldOrientation()* (targetRelativePosition)));
[10864]535        this->setTargetPosition(targetAbsolutePosition);
[10886]536        if (!this->getProtect())
537        {
538            this->nextActionpoint();
539            return;
540        } 
[10909]541        this->setTargetOrientation(this->getProtect()->getWorldOrientation());
[10864]542    }
[10955]543    //remove current point from the stack
[10864]544    void ActionpointController::nextActionpoint()
545    {
546        if (this->bLoop_)
547        {
[10915]548            if (this->bPatrolling_)
[10864]549            {
[10915]550                this->loopActionpoints_.pop_back();
551                this->bPatrolling_ = false;
552            }
553            else if (!this->loopActionpoints_.empty())
554            {
[10864]555                this->moveBackToTop();
556            }
557        }
558        else
559        {
560            if (!this->parsedActionpoints_.empty())
561            {
562                this->parsedActionpoints_.pop_back();
563            }           
564        }
565        this->setAction(Action::NONE);
[10882]566        this->bHasTargetPosition_ = false;
[10864]567    }
[10955]568    //if looping, instead of erasing point, move it to the top (back is what gets executed, so it's kinda reversed stack)
[10864]569    void ActionpointController::moveBackToTop()
570    {
[11083]571        if (!this->getControllableEntity())
[10925]572            return;
573
[10864]574        Point temp = loopActionpoints_.back();
575        loopActionpoints_.pop_back();
576        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
577        loopActionpoints_.push_back(temp);
578        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
579    }
[10955]580    //POST: moves all consecutive points that are in loop to the loop stack
[10864]581    void ActionpointController::fillLoop()
582    {
583        loopActionpoints_.clear();
584        fillLoopReversed();
585        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
586    }
587    void ActionpointController::fillLoopReversed()
588    {
589        if (parsedActionpoints_.back().inLoop)
590        {
591            loopActionpoints_.push_back(parsedActionpoints_.back());
592            parsedActionpoints_.pop_back();
593        }
594        if (parsedActionpoints_.back().inLoop)
595        {
596            fillLoopReversed();
597        }
598    }
[10955]599    //copy other ship's stacks so that if it dies, this can finish that ship's actions
[10885]600    void ActionpointController::takeActionpoints (const std::vector<Point>& vector, const std::vector<Point>& loop, bool b)
[10864]601    {
[11083]602        if (!this->getControllableEntity())
[10946]603            return;
604        this->parsedActionpoints_ = vector;
605        this->loopActionpoints_ = loop;
606        this->bLoop_ = b;
607        this->bTakenOver_ = true;
[10864]608    }
[10955]609    //attack closest target
[10864]610    void ActionpointController::setClosestTarget()
611    {
612        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
613    }
[10955]614    //find closest target
[10864]615    Pawn* ActionpointController::closestTarget()
616    {
[11083]617        if (!this->getControllableEntity())
[11071]618            return nullptr;
[10864]619
[11071]620        Pawn* closestTarget = nullptr;
[10864]621        float minDistance =  std::numeric_limits<float>::infinity();
622        Gametype* gt = this->getGametype();
[11071]623        for (Pawn* pawn : ObjectList<Pawn>())
[10864]624        {
[11071]625            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(pawn), gt) )
[10864]626                continue;
627
[11071]628            float distance = CommonController::distance (pawn, this->getControllableEntity());
[10864]629            if (distance < minDistance)
630            {
[11071]631                closestTarget = pawn;
[10864]632                minDistance = distance;
633            }
634        }
635        if (closestTarget)
636        {
637           return closestTarget;
638        } 
[11071]639        return nullptr;
[10864]640    }
[10955]641    //push action FIGHT to the stack and set target to the closest enemy
[10864]642    void ActionpointController::startAttackingEnemiesThatAreClose()
643    {
[11083]644        if (!this->getControllableEntity())
[10923]645            return;
[10974]646       
647        if (!this->target_ || (this->target_ && CommonController::distance (this->getControllableEntity(), this->target_) > this->attackRange_))
[10864]648        {
[10974]649            Pawn* newTarget = this->closestTarget();
650            if ( newTarget && 
651                CommonController::distance (this->getControllableEntity(), static_cast<ControllableEntity*>(newTarget))
652                    <= this->attackRange_ )
[10864]653            {
[10974]654                this->setTarget(newTarget);
655                if (this->bLoop_ && !this->bPatrolling_)
[10864]656                {
[10974]657                    Point p = { Action::FIGHT, "", Vector3::ZERO, true };
658                    this->loopActionpoints_.push_back(p);
[10864]659                }
[10974]660                else if (!this->bPatrolling_)
661                {
662                    Point p = { Action::FIGHT, "", Vector3::ZERO, false };
663                    this->parsedActionpoints_.push_back(p);
664                }
665                this->bPatrolling_ = true;
666                this->executeActionpoint();
[10864]667            }
668        }
669    }
[10923]670}   
Note: See TracBrowser for help on using the repository browser.