Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core6/src/modules/pickup/PickupSpawner.cc @ 10121

Last change on this file since 10121 was 9638, checked in by landauf, 11 years ago

renamed CreateFactory() as RegisterClass() to be more consistent with the corresponding RegisterObject() macro

  • Property svn:eol-style set to native
File size: 10.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 *      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/GameMode.h"
38#include "core/Template.h"
39#include "core/XMLPort.h"
40
41#include "worldentities/pawns/Pawn.h"
42
43#include "PickupManager.h"
44#include "PickupRepresentation.h"
45
46namespace orxonox
47{
48
49    RegisterClass(PickupSpawner);
50
51    /**
52    @brief
53        Constructor. Creates a blank PickupSpawner.
54    @param creator
55        Pointer to the object which created this item.
56    */
57    PickupSpawner::PickupSpawner(Context* context) : StaticEntity(context), pickup_(NULL), representation_(NULL), pickupTemplate_(NULL)
58    {
59        RegisterObject(PickupSpawner);
60
61        this->initialize();
62    }
63
64    /**
65    @brief
66        Registers the object and sets some default values.
67    */
68    void PickupSpawner::initialize(void)
69    {
70        this->triggerDistance_ = 10;
71        this->respawnTime_ = 5.0f;
72        this->maxSpawnedItems_ = INF;
73        this->spawnsRemaining_ = INF;
74        this->selfDestruct_ = false;
75
76        this->setPickupable(NULL);
77    }
78
79    /**
80    @brief
81        Destructor.
82    */
83    PickupSpawner::~PickupSpawner()
84    {
85        if(this->isInitialized() && this->selfDestruct_ && this->pickup_ != NULL)
86            this->pickup_->destroy();
87    }
88
89    /**
90    @brief
91        Factory method, Creates a fully functional PickupSpawner.
92    @param creator
93        The creator of this PickupSpawner.
94    @param pickup
95        The Pickupable to be spawned by this PickupSpawner.
96    @param carrier
97        The PickupCarrier that carried the input pickup before it was dropped.
98    @param triggerDistance
99        The distance at which the PickupSpawner will trigger.
100    */
101    /*static*/ PickupSpawner* PickupSpawner::createDroppedPickup(Context* context, Pickupable* pickup, PickupCarrier* carrier, float triggerDistance)
102    {
103        PickupSpawner* spawner = new PickupSpawner(context);
104
105        spawner->setPickupable(pickup);
106        spawner->setTriggerDistance(triggerDistance);
107        spawner->setMaxSpawnedItems(1);
108
109        spawner->setPosition(carrier->getCarrierPosition());
110        spawner->block(carrier);
111
112        return spawner;
113    }
114
115    /**
116    @brief
117        Method for creating a PickupSpawner through XML.
118    @param xmlelement
119        XML element which contains the PickupSpawner.
120    @param mode
121        XMLPort mode.
122    */
123    void PickupSpawner::XMLPort(Element& xmlelement, XMLPort::Mode mode)
124    {
125        SUPER(PickupSpawner, XMLPort, xmlelement, mode);
126
127        XMLPortParam(PickupSpawner, "pickup", setPickupTemplateName, getPickupTemplateName, xmlelement, mode);
128        XMLPortParam(PickupSpawner, "triggerDistance", setTriggerDistance, getTriggerDistance, xmlelement, mode);
129        XMLPortParam(PickupSpawner, "respawnTime", setRespawnTime, getRespawnTime, xmlelement, mode);
130        XMLPortParam(PickupSpawner, "maxSpawnedItems", setMaxSpawnedItems, getMaxSpawnedItems, xmlelement, mode);
131    }
132
133    /**
134    @brief
135        Tick, checks if any Pawn is close enough to trigger.
136    @param dt
137        Time since last tick.
138    */
139    //TODO: Replace with collisions?
140    void PickupSpawner::tick(float dt)
141    {
142        SUPER(PickupSpawner, tick, dt);
143
144        // If the PickupSpawner is active.
145        if(GameMode::isMaster() && this->isActive())
146        {
147            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)
148
149            // Remove PickupCarriers from the blocked list if they have exceeded their time.
150            for(std::map<PickupCarrier*, std::time_t>::iterator it = this->blocked_.begin(); it != this->blocked_.end(); )
151            {
152                std::map<PickupCarrier*, std::time_t>::iterator temp = it;
153                it++;
154                if(temp->second < std::time(0))
155                    this->blocked_.erase(temp);
156            }
157
158            // Iterate trough all Pawns.
159            for(ObjectList<Pawn>::iterator it = ObjectList<Pawn>::begin(); it != ObjectList<Pawn>::end(); ++it)
160            {
161                if(spawner == NULL) // Stop if the PickupSpawner has been deleted (e.g. because it has run out of pickups to distribute).
162                    break;
163
164                Vector3 distance = it->getWorldPosition() - this->getWorldPosition();
165                PickupCarrier* carrier = static_cast<PickupCarrier*>(*it);
166                // 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.
167                if(distance.length() < this->triggerDistance_ && carrier != NULL && this->blocked_.find(carrier) == this->blocked_.end())
168                {
169                    if(carrier->isTarget(this->pickup_))
170                        this->trigger(*it);
171                }
172            }
173        }
174    }
175
176    /**
177    @brief
178        Trigger the PickupSpawner.
179        Adds the pickup to the Pawn that triggered, sets the timer to re-activate and deactives the PickupSpawner.
180    @param carrier
181        Carrier which triggered the PickupSpawner.
182    */
183    void PickupSpawner::trigger(PickupCarrier* carrier)
184    {
185        orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") triggered and active." << endl;
186
187        PickupCarrier* target = carrier->getTarget(this->pickup_);
188
189        this->block(carrier);
190
191        assert(target);
192        bool pickedUp = this->pickup_->pickup(target);
193        assert(pickedUp);
194        pickedUp = false; // To avoid compiler warning.
195
196        this->setPickupable(NULL);
197        this->decrementSpawnsRemaining();
198    }
199
200    void PickupSpawner::setPickupTemplateName(const std::string& name)
201    {
202        Template* temp = Template::getTemplate(name);
203        if (temp)
204            this->setPickupTemplate(temp);
205    }
206
207    void PickupSpawner::setPickupTemplate(Template* temp)
208    {
209        this->pickupTemplate_ = temp;
210        this->pickupTemplateName_ = temp->getName();
211
212        this->setPickupable(this->createPickup());
213    }
214
215    /**
216    @brief
217        Sets the maximum number of spawned items.
218    @param items
219        The maximum number of spawned items to be set.
220    */
221    void PickupSpawner::setMaxSpawnedItems(int items)
222    {
223        this->maxSpawnedItems_ = items;
224        this->spawnsRemaining_ = items;
225    }
226
227    /**
228    @brief
229        Decrements the number of remaining spawns.
230        Sets the PickupSpawner to inactive for the duration of the respawnTime.
231        Destroys the PickupSpawner if the number of remaining spawns has reached zero.
232    */
233    void PickupSpawner::decrementSpawnsRemaining(void)
234    {
235        if(this->spawnsRemaining_ != INF)
236            this->spawnsRemaining_--;
237
238        this->setActive(false);
239
240        if(this->spawnsRemaining_ != 0 && this->respawnTime_ > 0)
241        {
242            this->startRespawnTimer();
243            this->fireEvent();
244        }
245        else
246        {
247            orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") empty, selfdestruct initialized." << endl;
248            this->destroy();
249        }
250    }
251
252    /**
253    @brief
254        Starts the respawn timer.
255    */
256    void PickupSpawner::startRespawnTimer(void)
257    {
258        this->respawnTimer_.setTimer(this->respawnTime_, false, createExecutor(createFunctor(&PickupSpawner::respawnTimerCallback, this)));
259    }
260
261    /**
262    @brief
263        Invoked by the timer, re-activates the PickupSpawner.
264    */
265    void PickupSpawner::respawnTimerCallback()
266    {
267        orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") reactivated." << endl;
268
269        this->setPickupable(this->createPickup());
270    }
271
272    /**
273    @brief
274        Creates a new Pickupable.
275    @return
276        The Pickupable created.
277    */
278    Pickupable* PickupSpawner::createPickup(void)
279    {
280        if(this->spawnsRemaining_ == 0)
281        {
282            orxout(internal_error, context::pickups) << "Massive Error: PickupSpawner still alive until having spawned last item." << endl;
283            return NULL;
284        }
285
286        if (this->pickupTemplate_ != NULL)
287        {
288            Identifier* identifier = this->pickupTemplate_->getBaseclassIdentifier();
289            if (identifier != NULL)
290            {
291                Pickupable* pickup = orxonox_cast<Pickupable*>(identifier->fabricate(this->getContext()));
292                orxonox_cast<BaseObject*>(pickup)->addTemplate(this->pickupTemplate_);
293                return pickup;
294            }
295            else
296                orxout(internal_error, context::pickups) << "No base class defined in pickup-template " << this->pickupTemplateName_ << endl;
297        }
298
299        return NULL;
300    }
301
302    /**
303    @brief
304        Sets a Pickupable for the PickupSpawner to spawn.
305    @param pickup
306        The Pickupable to be set.
307    */
308    void PickupSpawner::setPickupable(Pickupable* pickup)
309    {
310        if (this->representation_ != NULL)
311        {
312            this->representation_->destroy();
313            this->representation_ = NULL;
314        }
315
316        if (pickup != NULL)
317        {
318            if (this->pickup_ != NULL)
319                this->pickup_->destroy();
320
321            PickupRepresentation* representation = PickupManager::getInstance().getRepresentation(pickup->getRepresentationName());
322            this->representation_ = representation->createSpawnerRepresentation(this);
323            this->attach(this->representation_);
324            this->setActive(true);
325        }
326        else
327        {
328            this->setActive(false);
329        }
330
331        this->pickup_ = pickup;
332    }
333}
Note: See TracBrowser for help on using the repository browser.