Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/campaignHS15/src/orxonox/controllers/ActionpointController.cc @ 10958

Last change on this file since 10958 was 10958, checked in by gania, 8 years ago

separated MasterController from my hierarchy

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