Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/controllers/ArtificialController.cc @ 9229

Last change on this file since 9229 was 9016, checked in by jo, 13 years ago

Merging presentation2011 branch to trunk. Please check for possible bugs.

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