Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/campaignHS15/src/orxonox/controllers/CommonController.cc @ 10869

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

fixed a bug and got rid of unnecessary Rank enumeration, used getIdentifire instead

File size: 20.5 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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      Dominik Solenicki
26 *
27 */
28#include "controllers/CommonController.h"
29#include "core/XMLPort.h"
30
31//stuff for sameTeam function
32#include "worldentities/pawns/TeamBaseMatchBase.h"
33#include "gametypes/TeamDeathmatch.h"
34#include "gametypes/Dynamicmatch.h"
35#include "gametypes/Mission.h"
36#include "gametypes/Gametype.h"
37#include "controllers/WaypointPatrolController.h"
38#include "controllers/NewHumanController.h"
39#include "controllers/DroneController.h"
40
41//Today, on 25th of November, 2015, I hereby officially declare my code a huge pack of bullshit that I do not understand.
42//#Almost2KLines
43//#SpaghettiCode
44//#ISworeiWouldNever
45//#ItAllStartedSoWell
46
47namespace orxonox
48{
49
50    RegisterClass( CommonController );
51    const float SPEED = 0.9f/0.02f;
52    const float ROTATEFACTOR = 1.0f/0.02f;
53
54    //Table of content:
55    //Constructor, Destructor & tick
56    //XML methods
57    //World interaction
58    //Helper methods
59    //Flying methods
60    //Fighting methods
61    //Actionpoint methods
62
63
64    //------------------------------------------------------------------------------
65    //------------------------Constructor, Destructor & tick------------------------
66    //------------------------------------------------------------------------------
67   
68    CommonController::CommonController( Context* context ): Controller( context )
69    {
70        this->bFirstTick_ = true;
71        this->tolerance_ = 50;
72        this->stopLookingAtTarget();
73        this->attackRange_ = 2500;
74        RegisterObject( CommonController );
75
76    }
77    CommonController::~CommonController() 
78    {
79       
80    }
81    void CommonController::tick(float dt)
82    {
83       
84        SUPER(CommonController, tick, dt);
85    }
86
87    //------------------------------------------------------------------------------
88    //----------------------------------XML methods---------------------------------
89    //------------------------------------------------------------------------------
90   
91    void CommonController::XMLPort( Element& xmlelement, XMLPort::Mode mode )
92    {
93        SUPER( CommonController, XMLPort, xmlelement, mode );
94        XMLPortParam( CommonController, "formationMode", setFormationModeXML, getFormationModeXML,  xmlelement, mode );
95    }
96    void CommonController::setFormationModeXML( std::string val )
97    {
98        const std::string valUpper = getUppercase( val );
99        FormationMode::Value value;
100       
101        if ( valUpper == "WALL" )
102            value = FormationMode::WALL;
103        else if ( valUpper == "FINGER4" )
104            value = FormationMode::FINGER4;
105        else if ( valUpper == "DIAMOND" )
106            value = FormationMode::DIAMOND;
107        else
108            ThrowException( ParseError, std::string( "Attempting to set an unknown FormationMode: '" )+ val + "'." );
109        this->setFormationMode( value );
110    }
111    std::string CommonController::getFormationModeXML() 
112    {
113        switch ( this->formationMode_ )
114        {
115            case FormationMode::WALL:
116            { return "WALL"; break; }
117            case FormationMode::FINGER4:
118            { return "FINGER4"; break; }
119            case FormationMode::DIAMOND:
120            { return "DIAMOND"; break; }
121            default:
122                return "DIAMOND"; break;
123        }
124    }
125    void CommonController::setFormationMode(FormationMode::Value val)
126    { 
127        this->formationMode_ = val; 
128    }
129    FormationMode::Value CommonController::getFormationMode() const
130    { 
131        return this->formationMode_; 
132    }
133   
134    //------------------------------------------------------------------------------
135    //-------------------------------World interaction------------------------------
136    //------------------------------------------------------------------------------
137
138    //"Virtual" methods
139    bool CommonController::setWingman ( CommonController* wingman )
140    { return false; }
141    bool CommonController::hasWingman() 
142    { return true; }
143    bool CommonController::hasTarget() 
144    {
145        if ( this->target_ )
146            return true;
147        return false;
148    }
149    ControllableEntity* CommonController::getTarget()
150    {
151        return this->target_;
152    }
153 
154
155    //------------------------------------------------------------------------------
156    //--------------------------------Helper methods--------------------------------
157    //------------------------------------------------------------------------------
158
159    float CommonController::randomInRange( float a, float b )
160    {
161        float random = rnd( 1.0f );
162        float diff = b - a;
163        float r = random * diff;
164        return a + r;
165    }
166    float CommonController::distance (ControllableEntity* entity1, ControllableEntity* entity2)
167    {
168        if (!entity1 || !entity2)
169            return std::numeric_limits<float>::infinity();
170        return ( entity1->getPosition() - entity2->getPosition() ).length();
171    }
172    bool CommonController::sameTeam (ControllableEntity* entity1, ControllableEntity* entity2, Gametype* gametype)
173    {
174        /*if (!entity1 || !entity2)
175            return false;
176        return entity1->getTeam() == entity2->getTeam();*/
177        if (entity1 == entity2)
178            return true;
179
180        int team1 = entity1->getTeam();
181        int team2 = entity2->getTeam();
182
183        Controller* controller = 0;
184        if (entity1->getController())
185            controller = entity1->getController();
186        else
187            controller = entity1->getXMLController();
188        if (controller)
189        {
190            CommonController* ac = orxonox_cast<CommonController*>(controller);
191            if (ac)
192                team1 = ac->getTeam();
193        }
194
195        if (entity2->getController())
196            controller = entity2->getController();
197        else
198            controller = entity2->getXMLController();
199        if (controller)
200        {
201            CommonController* ac = orxonox_cast<CommonController*>(controller);
202            if (ac)
203                team2 = ac->getTeam();
204        }
205
206        TeamGametype* tdm = orxonox_cast<TeamGametype*>(gametype);
207        if (tdm)
208        {
209            if (entity1->getPlayer())
210                team1 = tdm->getTeam(entity1->getPlayer());
211
212            if (entity2->getPlayer())
213                team2 = tdm->getTeam(entity2->getPlayer());
214        }
215
216        TeamBaseMatchBase* base = 0;
217        base = orxonox_cast<TeamBaseMatchBase*>(entity1);
218        if (base)
219        {
220            switch (base->getState())
221            {
222                case BaseState::ControlTeam1:
223                    team1 = 0;
224                    break;
225                case BaseState::ControlTeam2:
226                    team1 = 1;
227                    break;
228                case BaseState::Uncontrolled:
229                default:
230                    team1 = -1;
231            }
232        }
233        base = orxonox_cast<TeamBaseMatchBase*>(entity2);
234        if (base)
235        {
236            switch (base->getState())
237            {
238                case BaseState::ControlTeam1:
239                    team2 = 0;
240                    break;
241                case BaseState::ControlTeam2:
242                    team2 = 1;
243                    break;
244                case BaseState::Uncontrolled:
245                default:
246                    team2 = -1;
247            }
248        }
249
250        DroneController* droneController = 0;
251        droneController = orxonox_cast<DroneController*>(entity1->getController());
252        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity2)
253            return true;
254        droneController = orxonox_cast<DroneController*>(entity2->getController());
255        if (droneController && static_cast<ControllableEntity*>(droneController->getOwner()) == entity1)
256            return true;
257        DroneController* droneController1 = orxonox_cast<DroneController*>(entity1->getController());
258        DroneController* droneController2 = orxonox_cast<DroneController*>(entity2->getController());
259        if (droneController1 && droneController2 && droneController1->getOwner() == droneController2->getOwner())
260            return true;
261
262        Dynamicmatch* dynamic = orxonox_cast<Dynamicmatch*>(gametype);
263        if (dynamic)
264        {
265            if (dynamic->notEnoughPigs||dynamic->notEnoughKillers||dynamic->notEnoughChasers) {return false;}
266
267            if (entity1->getPlayer())
268                team1 = dynamic->getParty(entity1->getPlayer());
269
270            if (entity2->getPlayer())
271                team2 = dynamic->getParty(entity2->getPlayer());
272
273            if (team1 ==-1 ||team2 ==-1 ) {return false;}
274            else if (team1 == dynamic->chaser && team2 != dynamic->chaser) {return false;}
275            else if (team1 == dynamic->piggy && team2 == dynamic->chaser) {return false;}
276            else if (team1 == dynamic->killer && team2 == dynamic->chaser) {return false;}
277            else return true;
278        }
279
280        return (team1 == team2 && team1 != -1);
281    }
282    bool CommonController::isLooking( ControllableEntity* entityThatLooks, ControllableEntity* entityBeingLookedAt, float angle )
283    {
284        if ( !entityThatLooks || !entityBeingLookedAt )
285            return false;
286        return ( getAngle( entityThatLooks ->getPosition() , 
287            entityThatLooks->getOrientation()  * WorldEntity::FRONT, 
288            entityBeingLookedAt->getWorldPosition() ) < angle );
289    }
290    std::string CommonController::getName(Pawn* entity)
291    {
292        std::string name = entity->getName();
293        if (name == "")
294        {
295            const void * address = static_cast<const void*>(entity);
296            std::stringstream ss;
297            ss << address; 
298            name = ss.str();           
299        }
300        return name;
301    }
302    float CommonController::squaredDistanceToTarget()  const
303    {
304        if ( !this->getControllableEntity()  )
305            return 0;
306        if ( !this->target_ || !this->getControllableEntity() )
307            return ( this->getControllableEntity() ->getPosition() .squaredDistance( this->targetPosition_ ) );
308        else
309            return ( this->getControllableEntity() ->getPosition() .squaredDistance( this->positionOfTarget_ ) );
310    }
311    bool CommonController::isLookingAtTarget( float angle )
312    {
313        if ( !this->getControllableEntity()  || !this->target_ )
314            return false;
315        return this->isLooking(this->getControllableEntity(), this->getTarget(), angle);
316    }
317
318
319    //------------------------------------------------------------------------------
320    //--------------------------------Flying methods--------------------------------
321    //------------------------------------------------------------------------------
322
323    void CommonController::stopMoving()
324    {
325        this->bHasTargetPosition_ = false;
326    }
327    void CommonController::stopLookingAtTarget()
328    {
329        this->bLookAtTarget_ = false;
330    }
331    void CommonController::startLookingAtTarget()
332    {
333        this->bLookAtTarget_ = true;
334    }
335    void CommonController::moveToPosition( const Vector3& target, float dt )
336    {
337        ControllableEntity* entity = this->getControllableEntity();
338        Vector2 coord = get2DViewCoordinates
339            ( entity->getPosition() , 
340            entity->getOrientation()  * WorldEntity::FRONT, 
341            entity->getOrientation()  * WorldEntity::UP, 
342            target );
343
344        float distance = ( target - this->getControllableEntity() ->getPosition() ).length();
345        float rotateX = -clamp( coord.x * 10, -1.0f, 1.0f );
346        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f );
347
348        if ( distance > this->tolerance_ )
349        {
350            this->getControllableEntity() ->rotateYaw( ROTATEFACTOR * rotateX * dt );
351            this->getControllableEntity() ->rotatePitch( ROTATEFACTOR * rotateY * dt );
352
353            if ( distance < 300 )
354            {
355                if ( bHasTargetOrientation_ )
356                {
357                    copyTargetOrientation( dt );
358                }
359            }
360            if (distance > this->tolerance_*1.5f || (rotateX > -0.01 && rotateX < 0.01 && rotateY > -0.01 && rotateY < 0.01))
361                this->getControllableEntity() ->moveFrontBack( SPEED * dt );
362        }
363        else
364        {     
365            bHasTargetPosition_ = false;
366            bHasTargetOrientation_ = false;
367        }
368    }
369    void CommonController::moveToTargetPosition(float dt)
370    {
371        this->moveToPosition (this->targetPosition_, dt);
372    }
373    void CommonController::copyOrientation( const Quaternion& orient, float dt )
374    {
375        //roll angle difference in radian
376        float diff=orient.getRoll(false).valueRadians() -
377                        ( this->getControllableEntity() ->getOrientation() .getRoll( false ).valueRadians() );
378        while( diff>math::twoPi )diff-=math::twoPi;
379        while( diff<-math::twoPi )diff+=math::twoPi;
380        this->getControllableEntity() ->rotateRoll( diff*0.2f*ROTATEFACTOR * dt );
381    }
382    void CommonController::copyTargetOrientation( float dt )
383    {
384        if ( bHasTargetOrientation_ )
385        {   
386            copyOrientation( targetOrientation_, dt );
387        }
388    }
389    void CommonController::lookAtTarget(float dt)
390    {
391        ControllableEntity* entity = this->getControllableEntity();
392        if ( !entity )
393            return;
394        Vector2 coord = get2DViewCoordinates
395            ( entity->getPosition() , 
396            entity->getOrientation()  * WorldEntity::FRONT, 
397            entity->getOrientation()  * WorldEntity::UP, 
398            positionOfTarget_ );
399
400        //rotates should be in range [-1,+1], clamp cuts off all that is not
401        float rotateX = -clamp( coord.x * 10, -1.0f, 1.0f );
402        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f ); 
403   
404        //Yaw and Pitch are enough to start facing the target
405        this->getControllableEntity() ->rotateYaw( ROTATEFACTOR * rotateX * dt );
406        this->getControllableEntity() ->rotatePitch( ROTATEFACTOR * rotateY * dt );
407    }
408    void CommonController::setTargetPosition( const Vector3& target )
409    {
410        this->targetPosition_ = target;
411        this->bHasTargetPosition_ = true;
412    }
413
414    void CommonController::setTargetOrientation( const Quaternion& orient )
415    {
416        this->targetOrientation_=orient;
417        this->bHasTargetOrientation_=true;
418    }
419
420    void CommonController::setTargetOrientation( ControllableEntity* target )
421    {
422        if ( target )
423            setTargetOrientation( target->getOrientation() );
424    }
425
426    //------------------------------------------------------------------------------
427    //-------------------------------Fighting methods-------------------------------
428    //------------------------------------------------------------------------------
429
430    void CommonController::setTarget( ControllableEntity* target )
431    {
432        this->target_ = target;       
433        if ( this->target_ )
434        {
435            this->setPositionOfTarget( target_->getWorldPosition() );
436        }
437    }
438    void CommonController::setPositionOfTarget( const Vector3& target )
439    {
440        this->positionOfTarget_ = target;
441        this->bHasPositionOfTarget_ = true;
442    }
443    void CommonController::setOrientationOfTarget( const Quaternion& orient )
444    {
445        this->orientationOfTarget_=orient;
446        this->bHasOrientationOfTarget_=true;
447    }
448   
449    void CommonController::maneuver() 
450    {
451        maneuverCounter_++;
452        if (maneuverCounter_ > 5)
453            maneuverCounter_ = 0;
454
455        if ( !this->target_ || !this->getControllableEntity())
456            return;
457       
458        Vector3 thisPosition = this->getControllableEntity()->getWorldPosition();
459        this->setPositionOfTarget( getPredictedPosition( 
460            thisPosition, 
461            hardcoded_projectile_speed, 
462            this->target_->getWorldPosition() , 
463            this->target_->getVelocity() 
464            )  );
465        this->setOrientationOfTarget( this->target_->getOrientation() );
466
467        Vector3 diffVector = this->positionOfTarget_ - thisPosition;
468        float diffLength = diffVector.length();
469        Vector3 diffUnit = diffVector/diffLength;
470
471        bool bTargetIsLookingAtThis = this->isLooking ( this->target_, getControllableEntity(), math::pi/10.0f );
472       
473        //too far? well, come closer then
474        if ( diffLength > this->attackRange_ )
475        {
476            this->setTargetPosition( this->positionOfTarget_ );
477        }
478        //too close? How do u expect to dodge anything? Just attack!
479        else if ( diffLength < 500 )
480        {   
481            //at this point, just look and shoot
482            if ( diffLength < 250 )
483            {
484                this->stopMoving();
485                this->startLookingAtTarget();
486            }
487            else
488            {
489                this->setTargetPosition( this->positionOfTarget_ );
490            }
491        }
492        //Good distance? Check if target looks at us. It doesn't? Go hunt!
493        else if ( !bTargetIsLookingAtThis )
494        {
495            this->setTargetPosition( this->positionOfTarget_ );
496        }
497        //That's unfortunate, he is looking and probably shooting... try to dodge what we can... 
498        else 
499        {   
500            if (maneuverCounter_ == 0)
501            {
502                this->setTargetPosition( this->positionOfTarget_ );   
503                return;
504            }
505            dodge( thisPosition, diffUnit );
506        }
507    }
508   
509    void CommonController::dodge(Vector3& thisPosition, Vector3& diffUnit)
510    {
511        float factorX = 0, factorY = 0, factorZ = 0;
512        float rand = randomInRange (0, 1);
513   
514        if (rand <= 0.5)
515        { factorX = 1; }
516        else
517        { factorX = -1; }
518        rand = randomInRange (0, 1);
519        if (rand <= 0.5)
520        { factorY = 1; }
521        else
522        { factorY = -1; }
523        rand = randomInRange (0, 1);
524        if (rand <= 0.5)
525        { factorZ = 1; }
526        else
527        { factorZ = -1; }
528
529        Vector3 target = ( diffUnit )* 8000.0f;
530        Vector3* randVector = new Vector3( 
531            factorX * randomInRange( 10000, 40000 ), 
532            factorY * randomInRange( 10000, 40000 ), 
533            factorZ * randomInRange( 10000, 40000 ) 
534        );
535        Vector3 projection = randVector->dotProduct( diffUnit )* diffUnit;
536        *randVector -= projection;
537        target += *randVector;
538        this->setTargetPosition( thisPosition + target );
539    }
540    bool CommonController::canFire() 
541    {
542        //no target? why fire?
543        if ( !this->target_ )
544            return false;
545
546        Vector3 newPositionOfTarget = getPredictedPosition( this->getControllableEntity() ->getWorldPosition() , 
547            hardcoded_projectile_speed, this->target_->getWorldPosition() , this->target_->getVelocity() );
548        if ( newPositionOfTarget != Vector3::ZERO )
549        {
550            this->setPositionOfTarget( newPositionOfTarget );
551        }
552
553        float squaredDistance = squaredDistanceToTarget();
554
555        if ( squaredDistance < this->attackRange_*this->attackRange_ && this->isLookingAtTarget( math::pi / 20.0f)) 
556        {
557            return true;
558        }
559        else
560        {
561            return false;
562        }
563    }
564    void CommonController::doFire() 
565    {
566        if ( !this->target_ || !this->getControllableEntity() )
567        {
568            return;
569        }
570     
571        Pawn* pawn = orxonox_cast<Pawn*>( this->getControllableEntity() );
572
573        if ( pawn )
574            pawn->setAimPosition( this->positionOfTarget_ );
575        this->getControllableEntity() ->fire( 0 );
576    }
577
578
579   
580    void CommonController::boostControl()
581    {
582        SpaceShip* ship = orxonox_cast<SpaceShip*>(this->getControllableEntity());
583        if(ship == NULL) return;
584        if(ship->getBoostPower()*1.5f > ship->getInitialBoostPower() ) //upper limit ->boost
585        {
586
587            this->getControllableEntity()->boost(true);
588        }
589        else if(ship->getBoostPower()*4.0f < ship->getInitialBoostPower()) //lower limit ->do not boost
590        {
591           this->getControllableEntity()->boost(false);
592        }
593    }
594}
Note: See TracBrowser for help on using the repository browser.