Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11052 was 11052, checked in by landauf, 8 years ago

merged branch presentationHS15 back to trunk

  • Property svn:eol-style set to native
File size: 26.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 *      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 || !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        if (!this || !this->getControllableEntity())
89            return;
90        //fly
91        if (this->bHasTargetPosition_)
92        {
93            this->moveToTargetPosition(dt);
94        }//or just rotate
95        else if (this->bLookAtTarget_)
96        {
97            this->lookAtTarget(dt);
98        }
99       
100
101        if (!this || !this->getControllableEntity())
102            return;
103        //don't fire rocket each tick
104        if (timeout_ <= 0)
105        {   
106            this->bFiredRocket_ = false;
107        }
108        else if (this->bFiredRocket_)
109        {
110            --this->timeout_;
111        }
112
113        if (!this || !this->getControllableEntity())
114            return;
115        //sometimes dodge, sometimes attack
116        if (this->ticks_ % 80 <= 10)
117        {
118            this->bDodge_ = false;
119        }
120        else
121        {
122            this->bDodge_ = true;
123        }
124
125        if (!this || !this->getControllableEntity())
126            return;
127        //fire if you can
128        if (this->bShooting_)
129        {
130            this->doFire();
131        }
132        SUPER(ActionpointController, tick, dt);
133    }
134     
135    /**
136    @brief
137        action() manages the state machine.
138    */
139
140    void ActionpointController::action()
141    {
142        if (!this || !this->getControllableEntity() || !this->isActive())
143            return;
144
145        //deltaHp is used to know if this got attacked
146        this->deltaHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth() - this->previousHp;
147        this->previousHp = orxonox_cast<Pawn*> (this->getControllableEntity())->getHealth();
148
149        //look out for enemies
150        if (this->bDefaultPatrol_ || (this->action_ != Action::FLY && this->action_ != Action::NONE))
151        {
152            this->startAttackingEnemiesThatAreClose();
153        }
154        if (!this || !this->getControllableEntity())
155            return;
156
157        //No action -> pop one from stack
158        if (this->action_ == Action::NONE || this->bTakenOver_)
159        {
160            //if default behaviour is fighting all, push it onto the stack
161            if (this->parsedActionpoints_.empty() && this->loopActionpoints_.empty() && this->bDefaultFightAll_)
162            {
163                if (!this || !this->getControllableEntity())
164                    return;
165                Point p = { Action::FIGHTALL, "", Vector3::ZERO, false };
166                this->parsedActionpoints_.push_back (p);
167            }
168            if (!this || !this->getControllableEntity())
169                return;
170            this->executeActionpoint();
171            if (!this || !this->getControllableEntity())
172                return;
173            this->bTakenOver_ = false;
174        }
175        if (!this || !this->getControllableEntity())
176            return;
177
178        //Action fightall -> fight till nobody alive
179        if (this->action_ == Action::FIGHTALL)
180        {
181
182            if (!this->hasTarget())
183            {
184                ControllableEntity* newTarget = this->closestTarget();   
185                if (newTarget)
186                {
187                    if (!this || !this->getControllableEntity())
188                        return;
189                    this->setAction (Action::FIGHTALL, newTarget);
190                }
191                else
192                {
193                    if (!this || !this->getControllableEntity())
194                        return;
195                    this->nextActionpoint();
196                    if (!this || !this->getControllableEntity())
197                        return;
198                    this->executeActionpoint();
199   
200                }
201            }
202        }
203        //Action fight -> fight as long as enemies in range
204        else if (this->action_ == Action::FIGHT)
205        {
206            if (!this->hasTarget() )
207            {
208                //----find a target----
209                ControllableEntity* newTarget = this->closestTarget(); 
210                if (!this || !this->getControllableEntity())
211                    return; 
212                if (newTarget && 
213                        CommonController::distance (this->getControllableEntity(), newTarget) < this->attackRange_)
214                {
215                    if (!this || !this->getControllableEntity())
216                        return;
217                    this->setAction (Action::FIGHT, newTarget);
218                }
219                else
220                {
221                    if (!this || !this->getControllableEntity())
222                        return;
223                    this->nextActionpoint();
224                    if (!this || !this->getControllableEntity())
225                        return;
226                    this->executeActionpoint();
227                }
228            }
229            else if (this->hasTarget())
230            {
231                //----fly in formation if far enough----
232                Vector3 diffVector = this->positionOfTarget_ - this->getControllableEntity()->getWorldPosition();         
233                   
234                if (diffVector.length() > this->attackRange_)
235                {
236                    ControllableEntity* newTarget = this->closestTarget();
237                    if (!this || !this->getControllableEntity())
238                        return;
239                    if (newTarget && 
240                        CommonController::distance (this->getControllableEntity(), newTarget) < this->attackRange_)
241                    {
242                        if (!this || !this->getControllableEntity())
243                            return;
244                        this->setAction (Action::FIGHT, newTarget);
245                    }
246                    else
247                    {
248                        if (!this || !this->getControllableEntity())
249                            return;
250                        this->nextActionpoint();
251                        if (!this || !this->getControllableEntity())
252                            return;
253                        this->executeActionpoint();
254                    }
255                }
256            }
257        }
258        else if (this->action_ == Action::FLY)
259        {
260            if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
261            {
262                if (!this || !this->getControllableEntity())
263                    return;
264                this->nextActionpoint();   
265                if (!this || !this->getControllableEntity())
266                    return;
267                this->executeActionpoint();
268            }
269        }
270        else if (this->action_ == Action::PROTECT)
271        {
272            if (!this->getProtect())
273            {
274                if (!this || !this->getControllableEntity())
275                    return;
276                this->nextActionpoint();
277                if (!this || !this->getControllableEntity())
278                    return;
279                this->executeActionpoint(); 
280            }
281            if (!this || !this->getControllableEntity())
282                return;
283            this->stayNearProtect();
284        }
285        else if (this->action_ == Action::ATTACK)
286        {   
287            if (!this || !this->getControllableEntity())
288                return;
289            if (!this->hasTarget())
290            {
291                if (!this || !this->getControllableEntity())
292                    return;
293                this->nextActionpoint();
294                if (!this || !this->getControllableEntity())
295                    return;
296                this->executeActionpoint();
297            }
298        }
299    }
300    /**
301    @brief
302        if action is protect, this follows protect_ and fights enemies that are close
303    */
304    void ActionpointController::setProtect (ControllableEntity* protect)
305    {
306        this->protect_ = protect;
307    }
308    ControllableEntity* ActionpointController::getProtect ()
309    {
310        return this->protect_;
311    }
312    //XML method
313    void ActionpointController::addActionpoint(WorldEntity* actionpoint)
314    {
315        std::string actionName;
316        Vector3 position;
317        std::string targetName;
318        bool inLoop = false;
319        Point p;
320        if (actionpoint->getIdentifier()->getName() == "Actionpoint")
321        {
322            Actionpoint* ap = orxonox_cast<Actionpoint*> (actionpoint);
323            actionName = ap->getActionXML();
324            targetName = ap->getName();
325            position = ap->getWorldPosition();
326
327            if (this->bEndLoop_)
328            {
329                this->bInLoop_ = false;
330            }
331            if (!this->bInLoop_ && ap->getLoopStart())
332            {
333                this->bInLoop_ = true;
334            }
335            if (this->bInLoop_ && ap->getLoopEnd())
336            {
337                this->bEndLoop_ = true;
338            }
339            inLoop = this->bInLoop_;
340
341            Action::Value value;
342           
343            if ( actionName == "FIGHT" )
344            { value = Action::FIGHT; }
345            else if ( actionName == "FLY" )
346            { value = Action::FLY; }
347            else if ( actionName == "PROTECT" )
348            { value = Action::PROTECT; }
349            else if ( actionName == "NONE" )
350            { value = Action::NONE; }
351            else if ( actionName == "FIGHTALL" )
352            { value = Action::FIGHTALL; }
353            else if ( actionName == "ATTACK" )
354            { value = Action::ATTACK; }
355            else
356                ThrowException( ParseError, std::string( "Attempting to set an unknown Action: '" )+ actionName + "'." );
357            p.action = value; p.name = targetName; p.position = position; p.inLoop = inLoop;
358        }
359        else
360        {
361            inLoop = true;
362            p.action = Action::FLY; p.name = ""; p.position = actionpoint->getWorldPosition(); p.inLoop = inLoop;
363        }
364            parsedActionpoints_.push_back(p);
365            this->actionpoints_.push_back(actionpoint);
366    }
367    //XML method
368    WorldEntity* ActionpointController::getActionpoint(unsigned int index) const
369    {
370        if (index < this->actionpoints_.size())
371            return this->actionpoints_[index];
372        else
373            return 0;
374    }
375    //XML method
376    Action::Value ActionpointController::getAction ()
377    {
378        return this->action_;
379    }
380    //XML method
381    std::string ActionpointController::getActionName()
382    {
383        switch ( this->action_ )
384        {
385            case Action::FIGHT:
386            { return "FIGHT"; }
387            case Action::FLY:
388            { return "FLY"; }
389            case Action::PROTECT:
390            { return "PROTECT"; }
391            case Action::NONE:
392            { return "NONE"; }
393            case Action::FIGHTALL:
394            { return "FIGHTALL"; }
395            case Action::ATTACK:
396            { return "ATTACK"; }
397            default:
398                return "NONE";
399                break;
400        }
401    }
402    //XML method
403    void ActionpointController::setAction (Action::Value action)
404    {
405        this->action_ = action;
406    }
407    //set action and target/protect
408    void ActionpointController::setAction (Action::Value action, ControllableEntity* target)
409    {
410        if (!this || !this->getControllableEntity())
411            return;
412        this->action_ = action;
413        if (action == Action::FIGHT || action == Action::FIGHTALL || action == Action::ATTACK)
414        {   
415            if (target)
416                this->setTarget (target);
417        }
418        else if (action == Action::PROTECT)
419        {
420            if (target)
421                this->setProtect (target);
422        }
423    }
424    //set action and target position
425    void ActionpointController::setAction (Action::Value action, const Vector3& target)
426    {
427        if (!this || !this->getControllableEntity())
428            return;
429        this->action_ = action;
430        if (action == Action::FLY)
431        {
432            this->setTargetPosition (target);
433        }
434    }
435    //set action and target position and orientation
436    void ActionpointController::setAction (Action::Value action, const Vector3& target,  const Quaternion& orient )
437    {
438        if (!this || !this->getControllableEntity())
439            return;
440        this->action_ = action;
441        if (action == Action::FLY)
442        {
443            this->setTargetPosition (target);
444            this->setTargetOrientation (orient);
445        } 
446    }
447   
448    //------------------------------------------------------------------------------
449    //------------------------------Actionpoint methods-----------------------------
450    //------------------------------------------------------------------------------
451
452    //POST: this starts doing what was asked by the last element of parsedActionpoints_,
453    //if last element was failed to be parsed, next element will be executed.
454    void ActionpointController::executeActionpoint()
455    {
456        if (!this || !this->getControllableEntity())
457            return;
458
459        Point p;
460        if (this->bLoop_ && !loopActionpoints_.empty())
461        {
462            p = loopActionpoints_.back();
463        }
464        else if (this->bLoop_)
465        {
466            this->bLoop_ = false;
467            return;
468        }
469        else if (!this->bLoop_ && !parsedActionpoints_.empty())
470        {
471            p = parsedActionpoints_.back();
472        }
473        else
474        {
475            if (!this || !this->getControllableEntity())
476                return;
477
478            this->setTarget(0);
479            this->setTargetPosition(this->getControllableEntity()->getWorldPosition());
480            this->action_ = Action::NONE;
481            return;
482        }
483        if (!this || !this->getControllableEntity())
484            return;
485        if (!this->bLoop_ && this->parsedActionpoints_.back().inLoop)
486        {
487            //MOVES all points that are in loop to a loop vector
488            this->fillLoop();
489            if (!this || !this->getControllableEntity())
490                return;
491            this->bLoop_ = true;
492            executeActionpoint();
493            return;
494        }
495        if (!this || !this->getControllableEntity())
496            return;
497        this->setAction (p.action);
498        if (!this || !this->getControllableEntity())
499            return;
500
501        switch (this->action_)
502        {
503            case Action::FIGHT:
504            {
505                std::string targetName = p.name;
506                if (targetName == "")
507                    break;
508                for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
509                {
510                    if (!this || !this->getControllableEntity())
511                        return;
512                    if (CommonController::getName(*itP) == targetName)
513                    {
514                        this->setTarget (static_cast<ControllableEntity*>(*itP));
515                    }
516                }
517                break;
518            }
519            case Action::FLY:
520            {
521                this->setTargetPosition( p.position );
522                if (!this || !this->getControllableEntity())
523                    return;
524                if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
525                {
526                    if (!this || !this->getControllableEntity())
527                        return;
528                    this->nextActionpoint();
529                    if (!this || !this->getControllableEntity())
530                        return;
531                    this->executeActionpoint();
532                }
533                break;
534            }
535            case Action::PROTECT:
536            {
537                if (!this || !this->getControllableEntity())
538                    return;
539
540                std::string protectName = p.name;
541                if (protectName == "reservedKeyword:human")
542                {
543                    for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
544                    {
545                        if (orxonox_cast<ControllableEntity*>(*itP) && ((*itP)->getController()) && ((*itP)->getController()->getIdentifier()->getName() == "NewHumanController"))
546                        {
547                            this->setProtect (static_cast<ControllableEntity*>(*itP));
548                        }
549                    }
550                }
551                else
552                {
553                    for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
554                    {
555                        if (CommonController::getName(*itP) == protectName)
556                        {
557                            this->setProtect (static_cast<ControllableEntity*>(*itP));
558                        }
559                    }                           
560                }
561                if (!this->getProtect())
562                {
563                    this->nextActionpoint();
564                    this->executeActionpoint();
565                }
566                break;
567            }
568            case Action::NONE:
569            {
570                break;
571            }
572            case Action::FIGHTALL:
573            {
574                break;
575            }
576            case Action::ATTACK:
577            {
578                std::string targetName = p.name;
579
580                for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
581                {
582                    if (CommonController::getName(*itP) == targetName)
583                    {
584                        if (!this || !this->getControllableEntity())
585                            return;
586                        this->setTarget (static_cast<ControllableEntity*>(*itP));
587                    }
588                }
589                if (!this->hasTarget())
590                {
591                    this->nextActionpoint();
592                    if (!this || !this->getControllableEntity())
593                        return;
594                    this->executeActionpoint();
595                }
596                break;
597            }
598            default:
599                break;
600        }   
601    }
602
603    //calculate where in world coordinates this ship has to be, so that it keeps distance to protect_, and fly there
604    void ActionpointController::stayNearProtect()
605    {
606        if (!this || !this->getControllableEntity())
607            return;
608
609        Vector3 targetRelativePosition(0, 300, 300);
610        if (!this->getProtect())
611        {
612            this->nextActionpoint();
613            return;
614        } 
615        Vector3 targetAbsolutePosition = ((this->getProtect()->getWorldPosition()) + 
616            (this->getProtect()->getWorldOrientation()* (targetRelativePosition)));
617        this->setTargetPosition(targetAbsolutePosition);
618        if (!this->getProtect())
619        {
620            this->nextActionpoint();
621            return;
622        } 
623        this->setTargetOrientation(this->getProtect()->getWorldOrientation());
624    }
625    //remove current point from the stack
626    void ActionpointController::nextActionpoint()
627    {
628        if (!this || !this->getControllableEntity())
629            return;
630        if (this->bLoop_)
631        {
632            if (this->bPatrolling_)
633            {
634                this->loopActionpoints_.pop_back();
635                this->bPatrolling_ = false;
636            }
637            else if (!this->loopActionpoints_.empty())
638            {
639                this->moveBackToTop();
640            }
641        }
642        else
643        {
644            if (!this->parsedActionpoints_.empty())
645            {
646                this->parsedActionpoints_.pop_back();
647            }           
648        }
649        this->setAction(Action::NONE);
650        this->bHasTargetPosition_ = false;
651    }
652    //if looping, instead of erasing point, move it to the top (back is what gets executed, so it's kinda reversed stack)
653    void ActionpointController::moveBackToTop()
654    {
655        if (!this || !this->getControllableEntity())
656            return;
657
658        Point temp = loopActionpoints_.back();
659        loopActionpoints_.pop_back();
660        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
661        loopActionpoints_.push_back(temp);
662        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
663    }
664    //POST: moves all consecutive points that are in loop to the loop stack
665    void ActionpointController::fillLoop()
666    {
667        loopActionpoints_.clear();
668        fillLoopReversed();
669        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
670    }
671    void ActionpointController::fillLoopReversed()
672    {
673        if (parsedActionpoints_.back().inLoop)
674        {
675            loopActionpoints_.push_back(parsedActionpoints_.back());
676            parsedActionpoints_.pop_back();
677        }
678        if (parsedActionpoints_.back().inLoop)
679        {
680            fillLoopReversed();
681        }
682    }
683    //copy other ship's stacks so that if it dies, this can finish that ship's actions
684    void ActionpointController::takeActionpoints (const std::vector<Point>& vector, const std::vector<Point>& loop, bool b)
685    {
686        if (!this || !this->getControllableEntity())
687            return;
688        this->parsedActionpoints_ = vector;
689        if (!this || !this->getControllableEntity())
690            return;
691        this->loopActionpoints_ = loop;
692        this->bLoop_ = b;
693        this->bTakenOver_ = true;
694    }
695    //attack closest target
696    void ActionpointController::setClosestTarget()
697    {
698        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
699    }
700    //find closest target
701    Pawn* ActionpointController::closestTarget()
702    {
703        if (!this || !this->getControllableEntity())
704            return 0;
705
706        Pawn* closestTarget = 0;
707        float minDistance =  std::numeric_limits<float>::infinity();
708        Gametype* gt = this->getGametype();
709        for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
710        {
711            if (!this || !this->getControllableEntity())
712                return 0;
713            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(*itP), gt) )
714                continue;
715
716            float distance = CommonController::distance (*itP, this->getControllableEntity());
717            if (distance < minDistance)
718            {
719                closestTarget = *itP;
720                minDistance = distance;
721            }
722        }
723        if (closestTarget)
724        {
725           return closestTarget;
726        } 
727        return 0; 
728    }
729    //push action FIGHT to the stack and set target to the closest enemy
730    void ActionpointController::startAttackingEnemiesThatAreClose()
731    {
732        if (!this || !this->getControllableEntity())
733            return;
734       
735        if (!this->target_ || (this->target_ && CommonController::distance (this->getControllableEntity(), this->target_) > this->attackRange_))
736        {
737            if (!this || !this->getControllableEntity())
738                return;
739            Pawn* newTarget = this->closestTarget();
740            if ( newTarget && 
741                CommonController::distance (this->getControllableEntity(), static_cast<ControllableEntity*>(newTarget))
742                    <= this->attackRange_ )
743            {
744                if (!this || !this->getControllableEntity())
745                    return;
746                this->setTarget(newTarget);
747                if (this->bLoop_ && !this->bPatrolling_)
748                {
749                    Point p = { Action::FIGHT, "", Vector3::ZERO, true };
750                    this->loopActionpoints_.push_back(p);
751                }
752                else if (!this->bPatrolling_)
753                {
754                    Point p = { Action::FIGHT, "", Vector3::ZERO, false };
755                    this->parsedActionpoints_.push_back(p);
756                }
757                this->bPatrolling_ = true;
758                this->executeActionpoint();
759            }
760        }
761    }
762}   
Note: See TracBrowser for help on using the repository browser.