Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/controllers/FightingController.cc @ 11071

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

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 12.5 KB
RevLine 
[10871]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:
[10885]23 *      Gani Aliguzhinov
[10871]24 *   Co-authors:
[10885]25 *      Fabian 'x3n' Landau, Dominik Solenicki
[10871]26 *
27 */
28#include "controllers/FightingController.h"
[10875]29#include "util/Math.h"
[10871]30
31
[10885]32#include "worldentities/pawns/SpaceShip.h"
33
34#include "weaponsystem/WeaponMode.h"
35#include "weaponsystem/WeaponPack.h"
36#include "weaponsystem/Weapon.h"
37#include "weaponsystem/WeaponSlot.h"
[10903]38#include "weaponsystem/WeaponSystem.h"
39#include "weaponsystem/Munition.h"
40
[10871]41namespace orxonox
42{
43
44    RegisterClass (FightingController);
45   
46    FightingController::FightingController( Context* context ): FlyingController( context )
47    {
[11025]48        this->attackRange_ = 2500;
[10871]49        this->stopLookingAtTarget();
[10885]50        this->bSetupWorked = false;
51        this->timeout_ = 0;
[10871]52        RegisterObject( FightingController );
53    }
54    FightingController::~FightingController() 
55    {
56       
57    }
58    void FightingController::lookAtTarget(float dt)
59    {
[10923]60        if (!this || !this->getControllableEntity())
61            return;
[10871]62        ControllableEntity* entity = this->getControllableEntity();
63        if ( !entity )
64            return;
65        Vector2 coord = get2DViewCoordinates
66            ( entity->getPosition() , 
67            entity->getOrientation()  * WorldEntity::FRONT, 
68            entity->getOrientation()  * WorldEntity::UP, 
69            positionOfTarget_ );
70
71        //rotates should be in range [-1,+1], clamp cuts off all that is not
72        float rotateX = -clamp( coord.x * 10, -1.0f, 1.0f );
73        float rotateY = clamp( coord.y * 10, -1.0f, 1.0f ); 
74   
75        //Yaw and Pitch are enough to start facing the target
76        this->getControllableEntity() ->rotateYaw( ROTATEFACTOR * rotateX * dt );
77        this->getControllableEntity() ->rotatePitch( ROTATEFACTOR * rotateY * dt );
78    }
79    void FightingController::stopLookingAtTarget()
80    {
81        this->bLookAtTarget_ = false;
82    }
83    void FightingController::startLookingAtTarget()
84    {
85        this->bLookAtTarget_ = true;
86    }
[10885]87    bool FightingController::hasTarget() const
[10871]88    {
89        if ( this->target_ )
90            return true;
91        return false;
92    }
93
94    void FightingController::setTarget( ControllableEntity* target )
95    {
96        this->target_ = target;       
97        if ( this->target_ )
98        {
99            this->setPositionOfTarget( target_->getWorldPosition() );
100        }
101    }
102    void FightingController::setPositionOfTarget( const Vector3& target )
103    {
104        this->positionOfTarget_ = target;
105        this->bHasPositionOfTarget_ = true;
106    }
107    void FightingController::setOrientationOfTarget( const Quaternion& orient )
108    {
109        this->orientationOfTarget_=orient;
110        this->bHasOrientationOfTarget_=true;
111    }
112   
113    void FightingController::maneuver() 
114    {
[10885]115        if ( !this->target_ || !this->getControllableEntity())
116            return;
[10871]117
[10906]118
[10871]119        Vector3 thisPosition = this->getControllableEntity()->getWorldPosition();
[10885]120        this->setPositionOfTarget(this->target_->getWorldPosition());
121        //this->setOrientationOfTarget(this->target_->getOrientation());
[10871]122        Vector3 diffVector = this->positionOfTarget_ - thisPosition;
123        float diffLength = diffVector.length();
124        Vector3 diffUnit = diffVector/diffLength;
[10886]125
[10923]126        if (!this || !this->getControllableEntity())
127            return;
128
[10871]129        //too far? well, come closer then
[10883]130        if (diffLength > this->attackRange_)
[10871]131        {
[10886]132            this->spread_ = 400;
133            this->formationMode_ = FormationMode::DIAMOND;
[10883]134            this->bKeepFormation_ = true;
135           
[10886]136            this->setTargetPosition(this->positionOfTarget_ - diffUnit * 100.0f);
[10871]137        }
[10906]138        else
[10923]139        {   
[10953]140            bool bTargetIsLookingAtThis = CommonController::isLooking (this->target_, this->getControllableEntity(), math::pi/20.0f)
[10923]141                || this->deltaHp < 0;
[10906]142            this->bKeepFormation_ = false;
[10923]143
144            if (!this || !this->getControllableEntity())
145                return;
[10927]146            if (!this->bDodge_)
[10906]147            {
[10927]148                this->bStartedDodging_ = false;
149
[10906]150                this->setTargetPosition(this->positionOfTarget_ - diffUnit * 50.0f);   
151                return;
152            }
153            else if (bTargetIsLookingAtThis || diffLength < 700.0f)
154            {
155                if (!this->bStartedDodging_)
156                {
157                    this->bStartedDodging_ = true;
158                    dodge(thisPosition, diffLength, diffUnit);       
159                }
160            }
161            else
162            {
163                if (diffLength < 1000)
164                {
165                    this->stopMoving();
166                    this->startLookingAtTarget();
167
168                }
169                else
170                {
171                    this->setTargetPosition(this->positionOfTarget_ - diffUnit * 300.0f);
172                }
173            }
174        }
[10871]175    }
[10923]176   
[10906]177    void FightingController::dodge(const Vector3& thisPosition, float diffLength, Vector3& diffUnit)
[10871]178    {
[10885]179        //d.x*x + d.y*y + d.z*z == 0
180        //z = 1/d.z * (-d.y*y - d.x * x)
[10906]181        float x = CommonController::randomInRange (300, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
182        float y = CommonController::randomInRange (300, 800) * (CommonController::randomInRange(0,1) <= 0.5 ? 1 : -1);
[10888]183        float z = diffUnit.z == 0 ? 0 : (1/diffUnit.z) * (-x * diffUnit.x - y * diffUnit.y);
[10906]184        if (diffLength < 150.0f)
185        {
186            this->setTargetPosition(this->positionOfTarget_ + Vector3(z,x,y));
187        }
188        else
189        {
190        this->setTargetPosition(thisPosition + Vector3(x,y,z) + (this->deltaHp < 0 ? -diffUnit * 450.0f : 
191            (diffLength < 700.0f ? -diffUnit*700.0f : diffUnit * 50.0f)));
192
193        }
[10885]194        this->boostControl();
[10871]195
196    }
197    bool FightingController::canFire() 
198    {
199        //no target? why fire?
[10923]200        if (!this->target_ || !this->getControllableEntity())
[10871]201            return false;
[10885]202        Vector3 newPositionOfTarget = getPredictedPosition(this->getControllableEntity()->getWorldPosition(), 
[11028]203                                                           HARDCODED_PROJECTILE_SPEED, this->target_->getWorldPosition(),
[10885]204                                                           this->target_->getVelocity());
[10925]205        if (!this->target_ || !this->getControllableEntity())
206            return false;
[10891]207        //Vector3.isNaN() is what I used on my machine and it worked...
208        if (!(std::isnan(newPositionOfTarget.x) || std::isnan(newPositionOfTarget.y) || std::isnan(newPositionOfTarget.z)))
[10871]209        {
[10885]210            this->setPositionOfTarget(newPositionOfTarget);
[10871]211        }
[10886]212
[10953]213        return squaredDistanceToTarget() < this->attackRange_*this->attackRange_ && this->isLookingAtTarget(math::pi / 20.0f);
[10871]214    }
215
[10885]216
[10871]217    float FightingController::squaredDistanceToTarget()  const
218    {
[10923]219        if (!this || !this->getControllableEntity())
[10871]220            return 0;
[10885]221        if (!this->target_ || !this->getControllableEntity())
222            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_));
[10871]223        else
[10885]224            return (this->getControllableEntity()->getPosition().squaredDistance(this->positionOfTarget_));
[10871]225    }
[10885]226    bool FightingController::isLookingAtTarget( float angle ) const
[10871]227    {
228        if ( !this->getControllableEntity()  || !this->target_ )
229            return false;
[10877]230        return CommonController::isLooking(this->getControllableEntity(), this->getTarget(), angle);
[10871]231    }
[10885]232    void FightingController::setClosestTarget()
[10871]233    {
234        this->setTarget (static_cast<ControllableEntity*>( closestTarget() ) ); 
235    }
236   
[10885]237    Pawn* FightingController::closestTarget() const
[10871]238    {
[10923]239        if (!this || !this->getControllableEntity())
[11071]240            return nullptr;
[10871]241
[11071]242        Pawn* closestTarget = nullptr;
[10871]243        float minDistance =  std::numeric_limits<float>::infinity();
244        Gametype* gt = this->getGametype();
[11071]245        for (Pawn* pawn : ObjectList<Pawn>())
[10871]246        {
[11071]247            if ( CommonController::sameTeam (this->getControllableEntity(), static_cast<ControllableEntity*>(pawn), gt) )
[10871]248                continue;
249
[11071]250            float distance = CommonController::distance (pawn, this->getControllableEntity());
[10871]251            if (distance < minDistance)
252            {
[11071]253                closestTarget = pawn;
[10871]254                minDistance = distance;
255            }
256        }
257        if (closestTarget)
258        {
259           return closestTarget;
260        } 
[11071]261        return nullptr;
[10871]262    }
[10885]263    //I checked it out, rockets DO NOT cause any problems! this->getControllableEntity() is always a SpaceShip
264    void FightingController::doFire()
265    {
266        if (!this->bSetupWorked)
267        {
268            this->setupWeapons();
269        }
270        if (!this->target_ || !this->getControllableEntity())
271        {
272            return;
273        }
[10886]274
[10885]275        Pawn* pawn = orxonox_cast<Pawn*> (this->getControllableEntity());
276        if (pawn)
277            pawn->setAimPosition (this->positionOfTarget_);
[10935]278
[10885]279        int firemode;
280        float distance = CommonController::distance (this->getControllableEntity(), this->target_);
281
[10935]282
283       
[10886]284        if (distance < 1500)
[10885]285        {
[10886]286            if (this->rocketsLeft_ > 0 && !this->bFiredRocket_)
[10885]287            {
[10886]288                firemode = getFiremode ("RocketFire");
[10885]289            }
290            else
291            {
[10886]292                if (distance > 800)
293                    firemode = getFiremode ("HsW01");
294                else
[10885]295                    firemode = getFiremode ("LightningGun");
296            }
297
298        } 
[10935]299   
300
[10886]301        else if (distance < 2000)
[10885]302        {
[10886]303            firemode = getFiremode ("HsW01");
[10885]304        }
[10886]305        else
[10885]306        {
307            firemode = getFiremode ("LightningGun");
308        }
309        if (firemode < 0)
310        {
[10886]311            //assuming there is always some weapon with index 0
312            firemode = 0;
[10885]313        }
314        if (firemode == getFiremode("RocketFire"))
315        {
[10934]316            this->timeout_ = 5;
[10885]317            this->rocketsLeft_--;
318            this->bFiredRocket_ = true;
319        }
320        if (firemode == getFiremode("SimpleRocketFire"))
321        {
322            this->rocketsLeft_--;
323        }
324             
325        this->getControllableEntity()->fire(firemode);
326       
327    }
328    void FightingController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions)
329    {
330        this->bSetupWorked = false;
331        if(this->getControllableEntity())
332        {
333            Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
334            if(pawn && pawn->isA(Class(SpaceShip))) //fix for First Person Mode: check for SpaceShip
335            {
336                this->weaponModes_.clear(); // reset previous weapon information
[11071]337                WeaponSlot* wSlot = nullptr;
[10885]338                for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++)
339                {
[11071]340                    WeaponMode* wMode = nullptr;
[10885]341                    for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++)
342                    {
343                        std::string wName = wMode->getIdentifier()->getName();
[10903]344                        // SubclassIdentifier<Munition> munition =  ClassByString(wName);
[10885]345                        if (wName == "RocketFire")
346                            this->rocketsLeft_ = 10;
347                        if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new"
348                            weaponModes_[wName] = wMode->getMode();
349                    }
350                }
351                if(weaponModes_.size())//at least one weapon detected
352                    this->bSetupWorked = true;
[10974]353            }
[10885]354        }
[10903]355
[10885]356    }
357
[11071]358    int FightingController::getFiremode(const std::string& name)
[10885]359    {
[11071]360        for (const auto& mapEntry : this->weaponModes_)
[10885]361        {
[11071]362            if (mapEntry.first == name)
363                return mapEntry.second;
[10885]364        }
365        return -1;
366    }
[10871]367}
Note: See TracBrowser for help on using the repository browser.