Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation3/src/modules/pickup/PickupSpawner.cc @ 7110

Last change on this file since 7110 was 7086, checked in by landauf, 14 years ago

Fixed a bug in PickupSpawner.

When one Pawn picked up the last item, spawnsRemaining_ became 0 and the PickupSpawner was destroyed immediately. But PickupSpawner::tick() continued iterating through the other pawns, which lead to a crash.

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