Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

fixed bugs that are not supposed to even exist by initializing a variable in the constructor

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