Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11407 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
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 *      Gani Aliguzhinov
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "ActionpointController.h"
30
31#include "core/XMLPort.h"
32#include <algorithm>
33#include "worldentities/Actionpoint.h"
34namespace orxonox
35{
36
37    RegisterClass(ActionpointController);
38
39    ActionpointController::ActionpointController(Context* context) : FightingController(context)
40    {
41        this->ticks_ = 0;
42        this->bPatrolling_ = false;
43        this->bInLoop_ = false;
44        this->bLoop_ = false;
45        this->bEndLoop_ = false;
46        loopActionpoints_.clear();
47        parsedActionpoints_.clear();
48        actionpoints_.clear();
49        this->bTakenOver_ = false;
50        this->action_ = Action::NONE;
51        this->squaredaccuracy_ = 2500;
52        this->bStartedDodging_ = false;
53        this->bDefaultPatrol_ = true;
54        this->bDefaultFightAll_ = true;
55        RegisterObject(ActionpointController);
56
57    }
58    void ActionpointController::XMLPort( Element& xmlelement, XMLPort::Mode mode )
59    {
60        SUPER( ActionpointController, XMLPort, xmlelement, mode );
61
62        XMLPortObject(ActionpointController, WorldEntity, "actionpoints", addActionpoint, getActionpoint,  xmlelement, mode);
63        XMLPortParam(ActionpointController, "defaultFightAll", setDefaultFightAll, getDefaultFightAll, xmlelement, mode).defaultValues(true);
64        XMLPortParam(ActionpointController, "defaultPatrol", setDefaultPatrol, getDefaultPatrol, xmlelement, mode).defaultValues(true);
65    }
66
67    ActionpointController::~ActionpointController()
68    {
69        loopActionpoints_.clear();
70        parsedActionpoints_.clear();
71        actionpoints_.clear();
72
73    }
74    void ActionpointController::tick(float dt)
75    {
76        if (!this->getControllableEntity() || !this->isActive())
77            return;
78
79        //count ticks, ticks_ is unsigned, so overflow is not a problem
80        ++this->ticks_;
81        if (this->ticks_ == 1)
82        {
83            //those vectors are in reversed order after being set by XML.
84            std::reverse(parsedActionpoints_.begin(), parsedActionpoints_.end());
85            std::reverse(actionpoints_.begin(), actionpoints_.end());
86        }
87
88        //fly
89        if (this->bHasTargetPosition_)
90        {
91            this->moveToTargetPosition(dt);
92        }//or just rotate
93        else if (this->bLookAtTarget_)
94        {
95            this->lookAtTarget(dt);
96        }
97       
98        //don't fire rocket each tick
99        if (timeout_ <= 0)
100        {   
101            this->bFiredRocket_ = false;
102        }
103        else if (this->bFiredRocket_)
104        {
105            --this->timeout_;
106        }
107
108        //sometimes dodge, sometimes attack
109        if (this->ticks_ % 80 <= 10)
110        {
111            this->bDodge_ = false;
112        }
113        else
114        {
115            this->bDodge_ = true;
116        }
117
118        //fire if you can
119        if (this->bShooting_)
120        {
121            this->doFire();
122        }
123        SUPER(ActionpointController, tick, dt);
124    }
125     
126    /**
127    @brief
128        action() manages the state machine.
129    */
130
131    void ActionpointController::action()
132    {
133        if (!this->getControllableEntity() || !this->isActive())
134            return;
135
136        //deltaHp is used to know if this got attacked
137        this->deltaHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth() - this->previousHp;
138        this->previousHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth();
139
140        //look out for enemies
141        if (this->bDefaultPatrol_ || (this->action_ != Action::FLY && this->action_ != Action::NONE))
142        {
143            this->startAttackingEnemiesThatAreClose();
144        }
145
146        //No action -> pop one from stack
147        if (this->action_ == Action::NONE || this->bTakenOver_)
148        {
149            //if default behaviour is fighting all, push it onto the stack
150            if (this->parsedActionpoints_.empty() && this->loopActionpoints_.empty() && this->bDefaultFightAll_)
151            {
152                Point p = { Action::FIGHTALL, "", Vector3::ZERO, false };
153                this->parsedActionpoints_.push_back (p);
154            }
155            this->executeActionpoint();
156            this->bTakenOver_ = false;
157        }
158
159        //Action fightall -> fight till nobody alive
160        if (this->action_ == Action::FIGHTALL)
161        {
162
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();
173                    this->executeActionpoint();
174   
175                }
176            }
177        }
178        //Action fight -> fight as long as enemies in range
179        else if (this->action_ == Action::FIGHT)
180        {
181            if (!this->hasTarget() )
182            {
183                //----find a target----
184                ControllableEntity* newTarget = this->closestTarget();
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();
193                    this->executeActionpoint();
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();
212                        this->executeActionpoint();
213                    }
214                }
215            }
216        }
217        else if (this->action_ == Action::FLY)
218        {
219            if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
220            {
221                this->nextActionpoint();   
222                this->executeActionpoint();
223            }
224        }
225        else if (this->action_ == Action::PROTECT)
226        {
227            if (!this->getProtect())
228            {
229                this->nextActionpoint();
230                this->executeActionpoint(); 
231            }
232            this->stayNearProtect();
233        }
234        else if (this->action_ == Action::ATTACK)
235        {   
236            if (!this->hasTarget())
237            {
238                this->nextActionpoint();
239                this->executeActionpoint();
240            }
241        }
242    }
243    /**
244    @brief
245        if action is protect, this follows protect_ and fights enemies that are close
246    */
247    void ActionpointController::setProtect (ControllableEntity* protect)
248    {
249        this->protect_ = protect;
250    }
251    ControllableEntity* ActionpointController::getProtect ()
252    {
253        return this->protect_;
254    }
255    //XML method
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;
263        if (actionpoint->getIdentifier()->getName() == "Actionpoint")
264        {
265            Actionpoint* ap = orxonox_cast<Actionpoint*> (actionpoint);
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
284            Action value;
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        {
304            inLoop = true;
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    }
310    //XML method
311    WorldEntity* ActionpointController::getActionpoint(unsigned int index) const
312    {
313        if (index < this->actionpoints_.size())
314            return this->actionpoints_[index];
315        else
316            return nullptr;
317    }
318    //XML method
319    Action ActionpointController::getAction ()
320    {
321        return this->action_;
322    }
323    //XML method
324    std::string ActionpointController::getActionName()
325    {
326        switch ( this->action_ )
327        {
328            case Action::FIGHT:
329            { return "FIGHT"; }
330            case Action::FLY:
331            { return "FLY"; }
332            case Action::PROTECT:
333            { return "PROTECT"; }
334            case Action::NONE:
335            { return "NONE"; }
336            case Action::FIGHTALL:
337            { return "FIGHTALL"; }
338            case Action::ATTACK:
339            { return "ATTACK"; }
340            default:
341                return "NONE";
342                break;
343        }
344    }
345    //XML method
346    void ActionpointController::setAction (Action action)
347    {
348        this->action_ = action;
349    }
350    //set action and target/protect
351    void ActionpointController::setAction (Action action, ControllableEntity* target)
352    {
353        if (!this->getControllableEntity())
354            return;
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    }
367    //set action and target position
368    void ActionpointController::setAction (Action action, const Vector3& target)
369    {
370        if (!this->getControllableEntity())
371            return;
372        this->action_ = action;
373        if (action == Action::FLY)
374        {
375            this->setTargetPosition (target);
376        }
377    }
378    //set action and target position and orientation
379    void ActionpointController::setAction (Action action, const Vector3& target,  const Quaternion& orient )
380    {
381        if (!this->getControllableEntity())
382            return;
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    {
399        if (!this->getControllableEntity())
400            return;
401
402        Point p;
403        if (this->bLoop_ && !loopActionpoints_.empty())
404        {
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        {
418            this->setTarget(nullptr);
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        }
431        this->setAction (p.action);
432
433        switch (this->action_)
434        {
435            case Action::FIGHT:
436            {
437                std::string targetName = p.name;
438                if (targetName == "")
439                    break;
440                for (Pawn* pawn : ObjectList<Pawn>())
441                {
442                    if (CommonController::getName(pawn) == targetName)
443                    {
444                        this->setTarget (static_cast<ControllableEntity*>(pawn));
445                    }
446                }
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            {
461
462                std::string protectName = p.name;
463                if (protectName == "reservedKeyword:human")
464                {
465                    for (Pawn* pawn : ObjectList<Pawn>())
466                    {
467                        if (orxonox_cast<ControllableEntity*>(pawn) && (pawn->getController()) && (pawn->getController()->getIdentifier()->getName() == "NewHumanController"))
468                        {
469                            this->setProtect (static_cast<ControllableEntity*>(pawn));
470                        }
471                    }
472                }
473                else
474                {
475                    for (Pawn* pawn : ObjectList<Pawn>())
476                    {
477                        if (CommonController::getName(pawn) == protectName)
478                        {
479                            this->setProtect (static_cast<ControllableEntity*>(pawn));
480                        }
481                    }                           
482                }
483                if (!this->getProtect())
484                {
485                    this->nextActionpoint();
486                    this->executeActionpoint();
487                }
488                break;
489            }
490            case Action::NONE:
491            {
492                break;
493            }
494            case Action::FIGHTALL:
495            {
496                break;
497            }
498            case Action::ATTACK:
499            {
500                std::string targetName = p.name;
501
502                for (Pawn* pawn : ObjectList<Pawn>())
503                {
504                    if (CommonController::getName(pawn) == targetName)
505                    {
506                        this->setTarget (static_cast<ControllableEntity*>(pawn));
507                    }
508                }
509                if (!this->hasTarget())
510                {
511                    this->nextActionpoint();
512                    this->executeActionpoint();
513                }
514                break;
515            }
516            default:
517                break;
518        }   
519    }
520
521    //calculate where in world coordinates this ship has to be, so that it keeps distance to protect_, and fly there
522    void ActionpointController::stayNearProtect()
523    {
524        if (!this->getControllableEntity())
525            return;
526
527        Vector3 targetRelativePosition(0, 300, 300);
528        if (!this->getProtect())
529        {
530            this->nextActionpoint();
531            return;
532        } 
533        Vector3 targetAbsolutePosition = ((this->getProtect()->getWorldPosition()) + 
534            (this->getProtect()->getWorldOrientation()* (targetRelativePosition)));
535        this->setTargetPosition(targetAbsolutePosition);
536        if (!this->getProtect())
537        {
538            this->nextActionpoint();
539            return;
540        } 
541        this->setTargetOrientation(this->getProtect()->getWorldOrientation());
542    }
543    //remove current point from the stack
544    void ActionpointController::nextActionpoint()
545    {
546        if (this->bLoop_)
547        {
548            if (this->bPatrolling_)
549            {
550                this->loopActionpoints_.pop_back();
551                this->bPatrolling_ = false;
552            }
553            else if (!this->loopActionpoints_.empty())
554            {
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);
566        this->bHasTargetPosition_ = false;
567    }
568    //if looping, instead of erasing point, move it to the top (back is what gets executed, so it's kinda reversed stack)
569    void ActionpointController::moveBackToTop()
570    {
571        if (!this->getControllableEntity())
572            return;
573
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    }
580    //POST: moves all consecutive points that are in loop to the loop stack
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    }
599    //copy other ship's stacks so that if it dies, this can finish that ship's actions
600    void ActionpointController::takeActionpoints (const std::vector<Point>& vector, const std::vector<Point>& loop, bool b)
601    {
602        if (!this->getControllableEntity())
603            return;
604        this->parsedActionpoints_ = vector;
605        this->loopActionpoints_ = loop;
606        this->bLoop_ = b;
607        this->bTakenOver_ = true;
608    }
609    //attack closest target
610    void ActionpointController::setClosestTarget()
611    {
612        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
613    }
614    //find closest target
615    Pawn* ActionpointController::closestTarget()
616    {
617        if (!this->getControllableEntity())
618            return nullptr;
619
620        Pawn* closestTarget = nullptr;
621        float minDistance =  std::numeric_limits<float>::infinity();
622        Gametype* gt = this->getGametype();
623        for (Pawn* pawn : ObjectList<Pawn>())
624        {
625            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(pawn), gt) )
626                continue;
627
628            float distance = CommonController::distance (pawn, this->getControllableEntity());
629            if (distance < minDistance)
630            {
631                closestTarget = pawn;
632                minDistance = distance;
633            }
634        }
635        if (closestTarget)
636        {
637           return closestTarget;
638        } 
639        return nullptr;
640    }
641    //push action FIGHT to the stack and set target to the closest enemy
642    void ActionpointController::startAttackingEnemiesThatAreClose()
643    {
644        if (!this->getControllableEntity())
645            return;
646       
647        if (!this->target_ || (this->target_ && CommonController::distance (this->getControllableEntity(), this->target_) > this->attackRange_))
648        {
649            Pawn* newTarget = this->closestTarget();
650            if ( newTarget && 
651                CommonController::distance (this->getControllableEntity(), static_cast<ControllableEntity*>(newTarget))
652                    <= this->attackRange_ )
653            {
654                this->setTarget(newTarget);
655                if (this->bLoop_ && !this->bPatrolling_)
656                {
657                    Point p = { Action::FIGHT, "", Vector3::ZERO, true };
658                    this->loopActionpoints_.push_back(p);
659                }
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();
667            }
668        }
669    }
670}   
Note: See TracBrowser for help on using the repository browser.