Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10262 was 10216, checked in by landauf, 9 years ago

merged branch presentationFS14 back to trunk

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