Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/formation/src/orxonox/controllers/ArtificialController.cc @ 9215

Last change on this file since 9215 was 8991, checked in by jo, 13 years ago

Works. (Seperate/independent states are used to manage the behaviour).

  • Property svn:eol-style set to native
File size: 10.8 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
29#include "ArtificialController.h"
30#include "core/CoreIncludes.h"
31#include "worldentities/pawns/Pawn.h"
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"
38#include "weaponsystem/WeaponSlot.h"
39
40
41namespace orxonox
42{
43
44    ArtificialController::ArtificialController(BaseObject* creator) : FormationController(creator)
45    {
46        this->bSetupWorked = false;
47        this->botlevel_ = 0.5f;
48        this->timeout_ = 0;
49        this->currentWaypoint_ = 0;
50        this->setAccuracy(5);
51        this->defaultWaypoint_ = NULL;
52        this->mode_ = DEFAULT;//Vector-implementation: mode_.push_back(DEFAULT);
53    }
54
55    ArtificialController::~ArtificialController()
56    {
57        if (this->isInitialized())
58        {//Vector-implementation: mode_.erase(mode_.begin(),mode_.end());
59            this->waypoints_.clear();
60            this->weaponModes_.clear();
61        }
62    }
63
64
65    /**
66        @brief Gets called when ControllableEntity is being changed. Resets the bot when it dies.
67    */
68    void ArtificialController::changedControllableEntity()
69    {
70        if (!this->getControllableEntity())
71            this->removeFromFormation();
72    }
73
74
75    void ArtificialController::aimAtTarget()
76    {
77        if (!this->target_ || !this->getControllableEntity())
78            return;
79
80        static const float hardcoded_projectile_speed = 1250;
81
82        this->targetPosition_ = getPredictedPosition(this->getControllableEntity()->getPosition(), hardcoded_projectile_speed, this->target_->getPosition(), this->target_->getVelocity());
83        this->bHasTargetPosition_ = (this->targetPosition_ != Vector3::ZERO);
84
85        Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
86        if (pawn)
87            pawn->setAimPosition(this->targetPosition_);
88    }
89
90    bool ArtificialController::isCloseAtTarget(float distance) const
91    {
92        if (!this->getControllableEntity())
93            return false;
94
95        if (!this->target_)
96            return (this->getControllableEntity()->getPosition().squaredDistance(this->targetPosition_) < distance*distance);
97        else
98            return (this->getControllableEntity()->getPosition().squaredDistance(this->target_->getPosition()) < distance*distance);
99    }
100
101    bool ArtificialController::isLookingAtTarget(float angle) const
102    {
103        if (!this->getControllableEntity())
104            return false;
105
106        return (getAngle(this->getControllableEntity()->getPosition(), this->getControllableEntity()->getOrientation() * WorldEntity::FRONT, this->targetPosition_) < angle);
107    }
108
109    void ArtificialController::abandonTarget(Pawn* target)
110    {
111        if (target == this->target_)
112            this->targetDied();
113    }
114
115//****************************************************************************************** NEW
116    /**
117        @brief DoFire is called when a bot should shoot and decides which weapon is used and whether the bot shoots at all.
118    */
119    void ArtificialController::doFire()
120    {
121        if(!this->bSetupWorked)//setup: find out which weapons are active ! hard coded: laser is "0", lens flare is "1", ...
122        {
123            this->setupWeapons();
124        }
125        else if(this->getControllableEntity() && weaponModes_.size()&&this->bShooting_ && this->isCloseAtTarget((1 + 2*botlevel_)*1000) && this->isLookingAtTarget(math::pi / 20.0f))
126        {
127            int firemode;
128            float random = rnd(1);//
129            if (this->isCloseAtTarget(130) && (firemode = getFiremode("LightningGun")) > -1 )
130            {//LENSFLARE: short range weapon
131                this->getControllableEntity()->fire(firemode); //ai uses lens flare if they're close enough to the target
132            }
133            else if( this->isCloseAtTarget(400) && (random < this->botlevel_) && (firemode = getFiremode("RocketFire")) > -1 )
134            {//ROCKET: mid range weapon
135                this->mode_ = ROCKET; //Vector-implementation: mode_.push_back(ROCKET);
136                this->getControllableEntity()->fire(firemode); //launch rocket
137                if(this->getControllableEntity() && this->target_) //after fire(3) is called, getControllableEntity() refers to the rocket!
138                {
139                    float speed = this->getControllableEntity()->getVelocity().length() - target_->getVelocity().length();
140                    if(!speed) speed = 0.1f;
141                    float distance = target_->getPosition().length() - this->getControllableEntity()->getPosition().length();
142                    this->timeout_= distance/speed*sgn(speed*distance) + 1.8f; //predicted time of target hit (+ tolerance)
143                }
144                else
145                    this->timeout_ = 4.0f; //TODO: find better default value
146            }
147            else if ((firemode = getFiremode("HsW01")) > -1 ) //LASER: default weapon
148                this->getControllableEntity()->fire(firemode);
149        }
150    }
151
152    /**
153        @brief Information gathering: Which weapons are ready to use?
154    */
155    void ArtificialController::setupWeapons() //TODO: Make this function generic!! (at the moment is is based on conventions)
156    {
157        this->bSetupWorked = false;
158        if(this->getControllableEntity())
159        {
160            Pawn* pawn = orxonox_cast<Pawn*>(this->getControllableEntity());
161            if(pawn && pawn->isA(Class(SpaceShip))) //fix for First Person Mode: check for SpaceShip
162            {
163                this->weaponModes_.clear(); // reset previous weapon information
164                WeaponSlot* wSlot = 0;
165                for(int l=0; (wSlot = pawn->getWeaponSlot(l)) ; l++)
166                {
167                    WeaponMode* wMode = 0;
168                    for(int i=0; (wMode = wSlot->getWeapon()->getWeaponmode(i)) ; i++)
169                    {
170                        std::string wName = wMode->getIdentifier()->getName();
171                        if(this->getFiremode(wName) == -1) //only add a weapon, if it is "new"
172                            weaponModes_[wName] = wMode->getMode();
173                    }
174                }
175                if(weaponModes_.size())//at least one weapon detected
176                    this->bSetupWorked = true;
177            }//pawn->weaponSystem_->getMunition(SubclassIdentifier< Munition > *identifier)->getNumMunition (WeaponMode *user);
178        }
179    }
180
181
182    void ArtificialController::setBotLevel(float level)
183    {
184        if (level < 0.0f)
185            this->botlevel_ = 0.0f;
186        else if (level > 1.0f)
187            this->botlevel_ = 1.0f;
188        else
189            this->botlevel_ = level;
190    }
191
192    void ArtificialController::setAllBotLevel(float level)
193    {
194        for (ObjectList<ArtificialController>::iterator it = ObjectList<ArtificialController>::begin(); it != ObjectList<ArtificialController>::end(); ++it)
195            it->setBotLevel(level);
196    }
197
198    void ArtificialController::setPreviousMode()
199    {
200        this->mode_ = DEFAULT; //Vector-implementation: mode_.pop_back();
201    }
202
203    /**
204        @brief Manages boost. Switches between boost usage and boost safe mode.
205    */
206    void ArtificialController::boostControl()
207    {
208        SpaceShip* ship = orxonox_cast<SpaceShip*>(this->getControllableEntity());
209        if(ship == NULL) return;
210        if(ship->getBoostPower()*1.5f > ship->getInitialBoostPower() ) //upper limit ->boost
211            this->getControllableEntity()->boost(true);
212        else if(ship->getBoostPower()*4.0f < ship->getInitialBoostPower()) //lower limit ->do not boost
213            this->getControllableEntity()->boost(false);
214    }
215
216    int ArtificialController::getFiremode(std::string name)
217    {
218        for (std::map< std::string, int >::iterator it = this->weaponModes_.begin(); it != this->weaponModes_.end(); ++it)
219        {
220            if (it->first == name)
221                return it->second;
222        }
223        return -1;
224    }
225
226    void ArtificialController::addWaypoint(WorldEntity* waypoint)
227    {
228        this->waypoints_.push_back(waypoint);
229    }
230
231    WorldEntity* ArtificialController::getWaypoint(unsigned int index) const
232    {
233        if (index < this->waypoints_.size())
234            return this->waypoints_[index];
235        else
236            return 0;
237    }
238
239    /**
240        @brief Adds first waypoint of type name to the waypoint stack, which is within the searchDistance
241        @param name object-name of a point of interest (e.g. "PickupSpawner", "ForceField")
242    */
243    void ArtificialController::updatePointsOfInterest(std::string name, float searchDistance)
244    {
245        WorldEntity* waypoint = NULL;
246        for (ObjectList<WorldEntity>::iterator it = ObjectList<WorldEntity>::begin(); it != ObjectList<WorldEntity>::end(); ++it)
247        {
248            if((*it)->getIdentifier() == ClassByString(name))
249            {
250                ControllableEntity* controllable = this->getControllableEntity();
251                if(!controllable) continue;
252                float actualDistance = ( (*it)->getPosition() - controllable->getPosition() ).length();
253                if(actualDistance > searchDistance || actualDistance < 5.0f) continue;
254                    // TODO: PickupSpawner: adjust waypoint accuracy to PickupSpawner's triggerdistance
255                    // TODO: ForceField: analyze is angle between forcefield boost and own flying direction is acceptable
256                else
257                {
258                    waypoint = *it;
259                    break;
260                }
261            }
262        }
263        if(waypoint)
264            this->waypoints_.push_back(waypoint);
265    }
266
267    /**
268        @brief Adds point of interest depending on context.  TODO: Further Possibilites: "ForceField", "PortalEndPoint", "MovableEntity", "Dock"
269    */
270    void ArtificialController::manageWaypoints()
271    {
272        if(!defaultWaypoint_)
273            this->updatePointsOfInterest("PickupSpawner", 200.0f); // long search radius if there is no default goal
274        else
275            this->updatePointsOfInterest("PickupSpawner", 20.0f); // take pickup en passant if there is a default waypoint
276    }
277 
278}
Note: See TracBrowser for help on using the repository browser.