Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/campaignHS15/src/orxonox/controllers/FightingController.cc @ 10891

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

hotfix for isnan

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