Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/pickup/PickupSpawner.cc @ 9343

Last change on this file since 9343 was 8891, checked in by jo, 13 years ago

Ai and tutorial improvements merged back to the trunk. AI features: all weapons are used, the ai-firestrength is configurable, bots are able to collect pickups . I've set the tutorial level as default level.

  • Property svn:eol-style set to native
File size: 11.3 KB
RevLine 
[2917]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 *      Daniel 'Huty' Haggenmueller
24 *   Co-authors:
[6405]25 *      Damian 'Mozork' Frick
[2917]26 *
27 */
28
29/**
[6540]30    @file PickupSpawner.cc
31    @brief Implementation of the PickupSpawner class.
[2917]32*/
33
34#include "PickupSpawner.h"
[3196]35
[2917]36#include "core/CoreIncludes.h"
[7493]37#include "core/GameMode.h"
[3196]38#include "core/Template.h"
[2917]39#include "core/XMLPort.h"
[7547]40
[5735]41#include "worldentities/pawns/Pawn.h"
[7547]42
[6466]43#include "PickupManager.h"
44#include "PickupRepresentation.h"
[2917]45
46namespace orxonox
47{
[5953]48
[2917]49    CreateFactory(PickupSpawner);
50
51    /**
[5947]52    @brief
[6421]53        Constructor. Creates a blank PickupSpawner.
[5947]54    @param creator
55        Pointer to the object which created this item.
[2917]56    */
[6540]57    PickupSpawner::PickupSpawner(BaseObject* creator) : StaticEntity(creator), pickup_(NULL)
[2917]58    {
[6540]59        RegisterObject(PickupSpawner);
[7163]60
[6514]61        this->initialize();
[5953]62    }
63
[6421]64    /**
65    @brief
66        Constructor, Creates a fully functional PickupSpawner.
67    @param creator
68        The creator of this PickupSpawner.
69    @param pickup
70        The Pickupable to be spawned by this PickupSpawner.
71    @param triggerDistance
72        The distance at which the PickupSpawner will trigger.
73    @param respawnTime
74        The minimum time between two spawns.
[7401]75    @param maxSpawnedItems
[6421]76        The maximum number of items spawned by this PickupSpawner.
77    */
[6540]78    PickupSpawner::PickupSpawner(BaseObject* creator, Pickupable* pickup, float triggerDistance, float respawnTime, int maxSpawnedItems) : StaticEntity(creator), pickup_(NULL)
[5953]79    {
[6466]80        RegisterObject(PickupSpawner);
[7163]81
[5953]82        this->initialize();
[7163]83
[6405]84        this->pickup_ = pickup;
[5953]85
86        this->triggerDistance_ = triggerDistance;
87        this->respawnTime_ = respawnTime;
88        this->setMaxSpawnedItems(maxSpawnedItems);
[7163]89
[6475]90        if(this->pickup_ == NULL)
91        {
[8858]92            orxout(internal_warning, context::pickups) << "A PickupSpawner was created without a valid Pickupable. This won't work." << endl;
[6475]93            this->setActive(false);
94        }
95        else
96        {
97            PickupRepresentation* representation = PickupManager::getInstance().getRepresentation(this->pickup_->getPickupIdentifier());
98            this->attach(representation->getSpawnerRepresentation(this));
[7548]99            this->setActive(true);
[6475]100        }
[5953]101    }
102
[6421]103    /**
104    @brief
105        Registers the object and sets some default values.
106    */
[5953]107    void PickupSpawner::initialize(void)
108    {
[6563]109        this->triggerDistance_ = 10;
[7549]110        this->respawnTime_ = 5.0f;
[5953]111        this->maxSpawnedItems_ = INF;
112        this->spawnsRemaining_ = INF;
[7163]113        this->selfDestruct_ = false;
[2917]114    }
[5947]115
116    /**
117    @brief
118        Destructor.
119    */
[2917]120    PickupSpawner::~PickupSpawner()
121    {
[7801]122        if(this->isInitialized() && this->selfDestruct_ && this->pickup_ != NULL)
[6478]123            this->pickup_->destroy();
[2917]124    }
[5947]125
[2917]126    /**
[5947]127    @brief
128        Method for creating a PickupSpawner through XML.
129    @param xmlelement
130        XML element which contains the PickupSpawner.
131    @param mode
132        XMLPort mode.
[2917]133    */
134    void PickupSpawner::XMLPort(Element& xmlelement, XMLPort::Mode mode)
135    {
136        SUPER(PickupSpawner, XMLPort, xmlelement, mode);
137
[6421]138        XMLPortObject(PickupSpawner, Pickupable, "pickup", setPickupable, getPickupable, xmlelement, mode);
[7163]139
[2917]140        XMLPortParam(PickupSpawner, "triggerDistance", setTriggerDistance, getTriggerDistance, xmlelement, mode);
141        XMLPortParam(PickupSpawner, "respawnTime", setRespawnTime, getRespawnTime, xmlelement, mode);
[5953]142        XMLPortParam(PickupSpawner, "maxSpawnedItems", setMaxSpawnedItems, getMaxSpawnedItems, xmlelement, mode);
[7163]143
[6475]144        if(this->pickup_ == NULL)
[6405]145        {
[8858]146            orxout(internal_warning, context::pickups) << "A PickupSpawner was created without a valid Pickupable. This won't work." << endl;
[6475]147            this->setActive(false);
[6405]148        }
[6475]149        else
[6405]150        {
[6475]151            PickupRepresentation* representation = PickupManager::getInstance().getRepresentation(this->pickup_->getPickupIdentifier());
152            this->attach(representation->getSpawnerRepresentation(this));
[7549]153            this->setActive(true);
[6405]154        }
[2917]155    }
[7163]156
[6421]157    /**
158    @brief
[6475]159        Invoked when the activity has changed. Sets visibility of attached objects.
[6421]160    */
[6475]161    void PickupSpawner::changedActivity()
[6405]162    {
[6475]163        SUPER(PickupSpawner, changedActivity);
[5947]164
[7493]165        if(GameMode::isMaster())
166            this->setVisible(this->isActive());
[5953]167    }
[7163]168
[2917]169    /**
[5947]170    @brief
171        Tick, checks if any Pawn is close enough to trigger.
172    @param dt
173        Time since last tick.
[2917]174    */
[7493]175    //TODO: Replace with collisions?
[2917]176    void PickupSpawner::tick(float dt)
177    {
[6540]178        SUPER(PickupSpawner, tick, dt);
[7163]179
[7493]180        // If the PickupSpawner is active.
181        if(GameMode::isMaster() && this->isActive())
[2917]182        {
[8891]183            WeakPtr<PickupSpawner> spawner = this; // Create a smart pointer to keep the PickupSpawner alive until we iterated through all Pawns (in case a Pawn takes the last pickup)
[7163]184
[7549]185            // Remove PickupCarriers from the blocked list if they have exceeded their time.
186            for(std::map<PickupCarrier*, std::time_t>::iterator it = this->blocked_.begin(); it != this->blocked_.end(); )
187            {
188                std::map<PickupCarrier*, std::time_t>::iterator temp = it;
189                it++;
190                if(temp->second < std::time(0))
191                    this->blocked_.erase(temp);
192            }
193
[7493]194            // Iterate trough all Pawns.
[7549]195            for(ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it != ObjectList<Pawn>::end(); ++it)
[2917]196            {
[8891]197                if(spawner == NULL) // Stop if the PickupSpawner has been deleted (e.g. because it has run out of pickups to distribute).
198                    break;
199
[2917]200                Vector3 distance = it->getWorldPosition() - this->getWorldPosition();
[6711]201                PickupCarrier* carrier = dynamic_cast<PickupCarrier*>(*it);
[8891]202                // If a PickupCarrier, that fits the target-range of the Pickupable spawned by this PickupSpawner, is in trigger-distance and the carrier is not blocked.
[7549]203                if(distance.length() < this->triggerDistance_ && carrier != NULL && this->blocked_.find(carrier) == this->blocked_.end())
[6405]204                {
[7547]205                    if(carrier->isTarget(this->pickup_))
206                        this->trigger(*it);
[6405]207                }
[2917]208            }
209        }
210    }
[7163]211
[2917]212    /**
[5947]213    @brief
[6475]214        Sets the maximum number of spawned items.
215    @param items
216        The maximum number of spawned items to be set.
[2917]217    */
[6475]218    void PickupSpawner::setMaxSpawnedItems(int items)
[2917]219    {
[6475]220        this->maxSpawnedItems_ = items;
221        this->spawnsRemaining_ = items;
[6405]222    }
[7163]223
[6421]224    /**
225    @brief
226        Decrements the number of remaining spawns.
227        Sets the PickupSpawner to inactive for the duration of the respawnTime.
228        Destroys the PickupSpawner if the number of remaining spawns has reached zero.
229    */
[6405]230    void PickupSpawner::decrementSpawnsRemaining(void)
231    {
232        if(this->spawnsRemaining_ != INF)
233            this->spawnsRemaining_--;
[7493]234
[6405]235        if(this->spawnsRemaining_ != 0 && this->respawnTime_ > 0)
236        {
[6512]237            this->startRespawnTimer();
[5953]238
[6405]239            this->setActive(false);
240            this->fireEvent();
241        }
242        else
[5953]243        {
[8858]244            orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") empty, selfdestruct initialized." << endl;
[5953]245            this->setActive(false);
[6475]246            this->destroy();
[5953]247        }
[2917]248    }
[7163]249
[6475]250    /**
251    @brief
[6512]252        Starts the respawn timer.
253    */
254    void PickupSpawner::startRespawnTimer(void)
255    {
256        this->respawnTimer_.setTimer(this->respawnTime_, false, createExecutor(createFunctor(&PickupSpawner::respawnTimerCallback, this)));
257    }
[7163]258
[6512]259    /**
260    @brief
[6475]261        Sets a Pickupable for the PickupSpawner to spawn.
262    @param pickup
263        The Pickupable to be set.
264    */
265    void PickupSpawner::setPickupable(Pickupable* pickup)
266    {
267        if(this->pickup_ != NULL)
268        {
[8858]269            orxout(internal_error, context::pickups) << "In PickupSpawner (&" << this << "): setPickupable called, with this->pickup_ already set." << endl;
[6475]270            return;
271        }
272        if(pickup == NULL)
273        {
[8858]274            orxout(internal_error, context::pickups) << "In PickupSpawner (&" << this << "): Argument of setPickupable is NULL." << endl;
[6475]275            return;
276        }
[7163]277
[6475]278        this->pickup_ = pickup;
279    }
[7163]280
[6475]281    /**
282    @brief
283        Get the Pickupable that is spawned by this PickupSpawner.
284    @return
285        Returns the Pickupable that is spawned by this PickupSpawner.
286    */
[7547]287    const Pickupable* PickupSpawner::getPickupable(void) const
[6475]288    {
289        return this->pickup_;
290    }
[5947]291
[2917]292    /**
[5947]293    @brief
[6475]294        Trigger the PickupSpawner.
295        Adds the pickup to the Pawn that triggered, sets the timer to re-activate and deactives the PickupSpawner.
296    @param pawn
297        Pawn which triggered the PickupSpawner.
298    */
299    void PickupSpawner::trigger(Pawn* pawn)
300    {
[7493]301        if(this->isActive()) // Checks whether PickupSpawner is active.
[6475]302        {
[8858]303            orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") triggered and active." << endl;
[7163]304
[6475]305            PickupCarrier* carrier = dynamic_cast<PickupCarrier*>(pawn);
[7549]306            assert(carrier);
[7163]307
[7549]308            // If the Pawn isn't a target of the Pickupable.
[6475]309            if(!carrier->isTarget(this->pickup_))
310            {
[8858]311                orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") triggered but Pawn wasn't a target of the Pickupable." << endl;
[6475]312                return;
313            }
[7163]314
[6475]315            PickupCarrier* target = carrier->getTarget(this->pickup_);
316            Pickupable* pickup = this->getPickup();
[7163]317
[7549]318            this->block(carrier);
319
[7493]320            assert(pickup);
321            assert(target);
[7801]322            bool pickedUp = pickup->pickup(target);
323            assert(pickedUp);
324            pickedUp = false; // To avoid compiler warning.
[7163]325
[7493]326            this->decrementSpawnsRemaining();
[6475]327        }
328    }
329
330    /**
331    @brief
[6405]332        Creates a new Pickupable.
[5953]333    @return
[6405]334        The Pickupable created.
[7163]335    */
[6405]336    Pickupable* PickupSpawner::getPickup(void)
[5953]337    {
[6405]338        if(this->spawnsRemaining_ == 0)
339        {
[8858]340            orxout(internal_error, context::pickups) << "Massive Error: PickupSpawner still alive until having spawned last item." << endl;
[6405]341            return NULL;
342        }
[7163]343
[6405]344        Pickupable* pickup = this->pickup_->clone();
345        return pickup;
[5953]346    }
347
348    /**
349    @brief
[5947]350        Invoked by the timer, re-activates the PickupSpawner.
[2917]351    */
352    void PickupSpawner::respawnTimerCallback()
353    {
[8858]354        orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") reactivated." << endl;
[2917]355
356        this->setActive(true);
357    }
358}
Note: See TracBrowser for help on using the repository browser.