Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8990 was 8990, checked in by jo, 12 years ago

Rough adding of both concepts. Further work on the states is needed. (single player bots are inactive at the moment)

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