Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Preparation before merging.

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