Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/cpp11_v2/src/orxonox/controllers/ArtificialController.cc @ 10916

Last change on this file since 10916 was 10916, checked in by landauf, 10 years ago

use actual types instead of 'auto'. only exception is for complicated template types, e.g. when iterating over a map

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