Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10955 was 10955, checked in by gania, 9 years ago

cleaned up a bit

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    }
303    /**
304    @brief
305        if action is protect, this follows protect_ and fights enemies that are close
306    */
307    void ActionpointController::setProtect (ControllableEntity* protect)
308    {
309
310        this->protect_ = protect;
311    }
312    ControllableEntity* ActionpointController::getProtect ()
313    {
314
315        return this->protect_;
316    }
317    //XML method
318    void ActionpointController::addActionpoint(WorldEntity* actionpoint)
319    {
320        std::string actionName;
321        Vector3 position;
322        std::string targetName;
323        bool inLoop = false;
324        Point p;
325        if (actionpoint->getIdentifier()->getName() == "Actionpoint")
326        {
327            Actionpoint* ap = orxonox_cast<Actionpoint*> (actionpoint);
328            actionName = ap->getActionXML();
329            targetName = ap->getName();
330            position = ap->getWorldPosition();
331
332            if (this->bEndLoop_)
333            {
334                this->bInLoop_ = false;
335            }
336            if (!this->bInLoop_ && ap->getLoopStart())
337            {
338                this->bInLoop_ = true;
339            }
340            if (this->bInLoop_ && ap->getLoopEnd())
341            {
342                this->bEndLoop_ = true;
343            }
344            inLoop = this->bInLoop_;
345
346            Action::Value value;
347           
348            if ( actionName == "FIGHT" )
349            { value = Action::FIGHT; }
350            else if ( actionName == "FLY" )
351            { value = Action::FLY; }
352            else if ( actionName == "PROTECT" )
353            { value = Action::PROTECT; }
354            else if ( actionName == "NONE" )
355            { value = Action::NONE; }
356            else if ( actionName == "FIGHTALL" )
357            { value = Action::FIGHTALL; }
358            else if ( actionName == "ATTACK" )
359            { value = Action::ATTACK; }
360            else
361                ThrowException( ParseError, std::string( "Attempting to set an unknown Action: '" )+ actionName + "'." );
362            p.action = value; p.name = targetName; p.position = position; p.inLoop = inLoop;
363        }
364        else
365        {
366            inLoop = true;
367            p.action = Action::FLY; p.name = ""; p.position = actionpoint->getWorldPosition(); p.inLoop = inLoop;
368        }
369            parsedActionpoints_.push_back(p);
370            this->actionpoints_.push_back(actionpoint);
371    }
372    //XML method
373    WorldEntity* ActionpointController::getActionpoint(unsigned int index) const
374    {
375        if (index < this->actionpoints_.size())
376            return this->actionpoints_[index];
377        else
378            return 0;
379    }
380    //XML method
381    Action::Value ActionpointController::getAction ()
382    {
383        return this->action_;
384    }
385    //XML method
386    std::string ActionpointController::getActionName()
387    {
388        switch ( this->action_ )
389        {
390            case Action::FIGHT:
391            { return "FIGHT"; }
392            case Action::FLY:
393            { return "FLY"; }
394            case Action::PROTECT:
395            { return "PROTECT"; }
396            case Action::NONE:
397            { return "NONE"; }
398            case Action::FIGHTALL:
399            { return "FIGHTALL"; }
400            case Action::ATTACK:
401            { return "ATTACK"; }
402            default:
403                return "NONE";
404                break;
405        }
406    }
407    //XML method
408    void ActionpointController::setAction (Action::Value action)
409    {
410        this->action_ = action;
411    }
412    //set action and target/protect
413    void ActionpointController::setAction (Action::Value action, ControllableEntity* target)
414    {
415        if (!this || !this->getControllableEntity())
416            return;
417        this->action_ = action;
418        if (action == Action::FIGHT || action == Action::FIGHTALL || action == Action::ATTACK)
419        {   
420            if (target)
421                this->setTarget (target);
422        }
423        else if (action == Action::PROTECT)
424        {
425            if (target)
426                this->setProtect (target);
427        }
428    }
429    //set action and target position
430    void ActionpointController::setAction (Action::Value action, const Vector3& target)
431    {
432        if (!this || !this->getControllableEntity())
433            return;
434        this->action_ = action;
435        if (action == Action::FLY)
436        {
437            this->setTargetPosition (target);
438        }
439    }
440    //set action and target position and orientation
441    void ActionpointController::setAction (Action::Value action, const Vector3& target,  const Quaternion& orient )
442    {
443        if (!this || !this->getControllableEntity())
444            return;
445        this->action_ = action;
446        if (action == Action::FLY)
447        {
448            this->setTargetPosition (target);
449            this->setTargetOrientation (orient);
450        } 
451    }
452   
453    //------------------------------------------------------------------------------
454    //------------------------------Actionpoint methods-----------------------------
455    //------------------------------------------------------------------------------
456
457    //POST: this starts doing what was asked by the last element of parsedActionpoints_,
458    //if last element was failed to be parsed, next element will be executed.
459    void ActionpointController::executeActionpoint()
460    {
461        if (!this || !this->getControllableEntity())
462            return;
463
464        Point p;
465        if (this->bLoop_ && !loopActionpoints_.empty())
466        {
467            p = loopActionpoints_.back();
468        }
469        else if (this->bLoop_)
470        {
471            this->bLoop_ = false;
472            return;
473        }
474        else if (!this->bLoop_ && !parsedActionpoints_.empty())
475        {
476            p = parsedActionpoints_.back();
477        }
478        else
479        {
480            if (!this || !this->getControllableEntity())
481                return;
482
483            this->setTarget(0);
484            this->setTargetPosition(this->getControllableEntity()->getWorldPosition());
485            this->action_ = Action::NONE;
486            return;
487        }
488        if (!this || !this->getControllableEntity())
489            return;
490        if (!this->bLoop_ && this->parsedActionpoints_.back().inLoop)
491        {
492            //MOVES all points that are in loop to a loop vector
493            this->fillLoop();
494            if (!this || !this->getControllableEntity())
495                return;
496            this->bLoop_ = true;
497            executeActionpoint();
498            return;
499        }
500        if (!this || !this->getControllableEntity())
501            return;
502        this->setAction (p.action);
503        if (!this || !this->getControllableEntity())
504            return;
505
506        switch (this->action_)
507        {
508            case Action::FIGHT:
509            {
510                std::string targetName = p.name;
511                if (targetName == "")
512                    break;
513                for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
514                {
515                    if (!this || !this->getControllableEntity())
516                        return;
517                    if (CommonController::getName(*itP) == targetName)
518                    {
519                        this->setTarget (static_cast<ControllableEntity*>(*itP));
520                    }
521                }
522                break;
523            }
524            case Action::FLY:
525            {
526                this->setTargetPosition( p.position );
527                if (!this || !this->getControllableEntity())
528                    return;
529                if (this->squaredDistanceToTarget() <= this->squaredaccuracy_)
530                {
531                    if (!this || !this->getControllableEntity())
532                        return;
533                    this->nextActionpoint();
534                    if (!this || !this->getControllableEntity())
535                        return;
536                    this->executeActionpoint();
537                }
538                break;
539            }
540            case Action::PROTECT:
541            {
542                if (!this || !this->getControllableEntity())
543                    return;
544
545                std::string protectName = p.name;
546                if (protectName == "reservedKeyword:human")
547                {
548                    for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
549                    {
550                        if (orxonox_cast<ControllableEntity*>(*itP) && ((*itP)->getController()) && ((*itP)->getController()->getIdentifier()->getName() == "NewHumanController"))
551                        {
552                            this->setProtect (static_cast<ControllableEntity*>(*itP));
553                        }
554                    }
555                }
556                else
557                {
558                    for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
559                    {
560                        if (CommonController::getName(*itP) == protectName)
561                        {
562                            this->setProtect (static_cast<ControllableEntity*>(*itP));
563                        }
564                    }                           
565                }
566                if (!this->getProtect())
567                {
568                    this->nextActionpoint();
569                    this->executeActionpoint();
570                }
571                break;
572            }
573            case Action::NONE:
574            {
575                break;
576            }
577            case Action::FIGHTALL:
578            {
579                break;
580            }
581            case Action::ATTACK:
582            {
583                std::string targetName = p.name;
584
585                for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
586                {
587                    if (CommonController::getName(*itP) == targetName)
588                    {
589                        if (!this || !this->getControllableEntity())
590                            return;
591                        this->setTarget (static_cast<ControllableEntity*>(*itP));
592                    }
593                }
594                if (!this->hasTarget())
595                {
596                    this->nextActionpoint();
597                    if (!this || !this->getControllableEntity())
598                        return;
599                    this->executeActionpoint();
600                }
601                break;
602            }
603            default:
604                break;
605        }   
606    }
607
608    //calculate where in world coordinates this ship has to be, so that it keeps distance to protect_, and fly there
609    void ActionpointController::stayNearProtect()
610    {
611        if (!this || !this->getControllableEntity())
612            return;
613
614        Vector3 targetRelativePosition(0, 300, 300);
615        if (!this->getProtect())
616        {
617            this->nextActionpoint();
618            return;
619        } 
620        Vector3 targetAbsolutePosition = ((this->getProtect()->getWorldPosition()) + 
621            (this->getProtect()->getWorldOrientation()* (targetRelativePosition)));
622        this->setTargetPosition(targetAbsolutePosition);
623        if (!this->getProtect())
624        {
625            this->nextActionpoint();
626            return;
627        } 
628        this->setTargetOrientation(this->getProtect()->getWorldOrientation());
629    }
630    //remove current point from the stack
631    void ActionpointController::nextActionpoint()
632    {
633        if (!this || !this->getControllableEntity())
634            return;
635        if (this->bLoop_)
636        {
637            if (this->bPatrolling_)
638            {
639                this->loopActionpoints_.pop_back();
640                this->bPatrolling_ = false;
641            }
642            else if (!this->loopActionpoints_.empty())
643            {
644                this->moveBackToTop();
645            }
646        }
647        else
648        {
649            if (!this->parsedActionpoints_.empty())
650            {
651                this->parsedActionpoints_.pop_back();
652            }           
653        }
654        this->setAction(Action::NONE);
655        this->bHasTargetPosition_ = false;
656    }
657    //if looping, instead of erasing point, move it to the top (back is what gets executed, so it's kinda reversed stack)
658    void ActionpointController::moveBackToTop()
659    {
660        if (!this || !this->getControllableEntity())
661            return;
662
663        Point temp = loopActionpoints_.back();
664        loopActionpoints_.pop_back();
665        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
666        loopActionpoints_.push_back(temp);
667        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
668    }
669    //POST: moves all consecutive points that are in loop to the loop stack
670    void ActionpointController::fillLoop()
671    {
672        loopActionpoints_.clear();
673        fillLoopReversed();
674        std::reverse (loopActionpoints_.begin(), loopActionpoints_.end());
675    }
676    void ActionpointController::fillLoopReversed()
677    {
678        if (parsedActionpoints_.back().inLoop)
679        {
680            loopActionpoints_.push_back(parsedActionpoints_.back());
681            parsedActionpoints_.pop_back();
682        }
683        if (parsedActionpoints_.back().inLoop)
684        {
685            fillLoopReversed();
686        }
687    }
688    //copy other ship's stacks so that if it dies, this can finish that ship's actions
689    void ActionpointController::takeActionpoints (const std::vector<Point>& vector, const std::vector<Point>& loop, bool b)
690    {
691        if (!this || !this->getControllableEntity())
692            return;
693        this->parsedActionpoints_ = vector;
694        if (!this || !this->getControllableEntity())
695            return;
696        this->loopActionpoints_ = loop;
697        this->bLoop_ = b;
698        this->bTakenOver_ = true;
699    }
700    //attack closest target
701    void ActionpointController::setClosestTarget()
702    {
703        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
704    }
705    //find closest target
706    Pawn* ActionpointController::closestTarget()
707    {
708        if (!this || !this->getControllableEntity())
709            return 0;
710
711        Pawn* closestTarget = 0;
712        float minDistance =  std::numeric_limits<float>::infinity();
713        Gametype* gt = this->getGametype();
714        for (ObjectList<Pawn>::iterator itP = ObjectList<Pawn>::begin(); itP; ++itP)
715        {
716            if (!this || !this->getControllableEntity())
717                return 0;
718            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(*itP), gt) )
719                continue;
720
721            float distance = CommonController::distance (*itP, this->getControllableEntity());
722            if (distance < minDistance)
723            {
724                closestTarget = *itP;
725                minDistance = distance;
726            }
727        }
728        if (closestTarget)
729        {
730           return closestTarget;
731        } 
732        return 0; 
733    }
734    //push action FIGHT to the stack and set target to the closest enemy
735    void ActionpointController::startAttackingEnemiesThatAreClose()
736    {
737        if (!this || !this->getControllableEntity())
738            return;
739
740        //if (this->action_ != Action::FIGHT && this->action_ != Action::FIGHTALL)
741        {
742            if (!this->target_ || (this->target_ && CommonController::distance (this->getControllableEntity(), this->target_) > this->attackRange_))
743            {
744                if (!this || !this->getControllableEntity())
745                    return;
746                Pawn* newTarget = this->closestTarget();
747                if ( newTarget && 
748                    CommonController::distance (this->getControllableEntity(), static_cast<ControllableEntity*>(newTarget))
749                        <= this->attackRange_ )
750                {
751                    if (!this || !this->getControllableEntity())
752                        return;
753                    this->setTarget(newTarget);
754                    if (this->bLoop_ && !this->bPatrolling_)
755                    {
756                        Point p = { Action::FIGHT, "", Vector3::ZERO, true };
757                        this->loopActionpoints_.push_back(p);
758                    }
759                    else if (!this->bPatrolling_)
760                    {
761                        //orxout (internal_error) << "found new target " << CommonController::getName(newTarget) <<endl;
762                        Point p = { Action::FIGHT, "", Vector3::ZERO, false };
763                        this->parsedActionpoints_.push_back(p);
764                    }
765                    this->bPatrolling_ = true;
766                    this->executeActionpoint();
767                }
768            }
769        }
770    }
771}   
Note: See TracBrowser for help on using the repository browser.