Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11074 was 11071, checked in by landauf, 9 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 10.5 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_(nullptr), representation_(nullptr), pickupTemplate_(nullptr)
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(nullptr);
77    }
78
79    /**
80    @brief
81        Destructor.
82    */
83    PickupSpawner::~PickupSpawner()
84    {
85        if(this->isInitialized() && this->selfDestruct_ && this->pickup_ != nullptr)
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            // TODO: why is this a WeakPtr when the comment says StrongPtr?
148            WeakPtr<PickupSpawner> spawner = this; // Create a strong pointer to keep the PickupSpawner alive until we iterated through all Pawns (in case a Pawn takes the last pickup)
149
150            // Remove PickupCarriers from the blocked list if they have exceeded their time.
151            for(std::map<PickupCarrier*, std::time_t>::iterator it = this->blocked_.begin(); it != this->blocked_.end(); )
152            {
153                std::map<PickupCarrier*, std::time_t>::iterator temp = it;
154                it++;
155                if(temp->second < std::time(0))
156                    this->blocked_.erase(temp);
157            }
158
159            // Iterate trough all Pawns.
160            for(Pawn* pawn : ObjectList<Pawn>())
161            {
162                if(spawner == nullptr) // Stop if the PickupSpawner has been deleted (e.g. because it has run out of pickups to distribute).
163                    break;
164
165                Vector3 distance = pawn->getWorldPosition() - this->getWorldPosition();
166                PickupCarrier* carrier = static_cast<PickupCarrier*>(pawn);
167                // 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.
168                if(distance.length() < this->triggerDistance_ && carrier != nullptr && this->blocked_.find(carrier) == this->blocked_.end())
169                {
170                    if(carrier->isTarget(this->pickup_))
171                        this->trigger(pawn);
172                }
173            }
174        }
175    }
176
177    /**
178    @brief
179        Trigger the PickupSpawner.
180        Adds the pickup to the Pawn that triggered, sets the timer to re-activate and deactives the PickupSpawner.
181    @param carrier
182        Carrier which triggered the PickupSpawner.
183    */
184    void PickupSpawner::trigger(PickupCarrier* carrier)
185    {
186        orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") triggered and active." << endl;
187
188        PickupCarrier* target = carrier->getTarget(this->pickup_);
189
190        this->block(carrier);
191
192        assert(target);
193        bool pickedUp = this->pickup_->pickup(target);
194        assert(pickedUp);
195        pickedUp = false; // To avoid compiler warning.
196
197        this->setPickupable(nullptr);
198        this->decrementSpawnsRemaining();
199    }
200
201    void PickupSpawner::setPickupTemplateName(const std::string& name)
202    {
203        Template* temp = Template::getTemplate(name);
204        if (temp)
205            this->setPickupTemplate(temp);
206    }
207
208    void PickupSpawner::setPickupTemplate(Template* temp)
209    {
210        this->pickupTemplate_ = temp;
211        this->pickupTemplateName_ = temp->getName();
212
213        this->setPickupable(this->createPickup());
214    }
215
216    /**
217    @brief
218        Sets the maximum number of spawned items.
219    @param items
220        The maximum number of spawned items to be set.
221    */
222    void PickupSpawner::setMaxSpawnedItems(int items)
223    {
224        this->maxSpawnedItems_ = items;
225        this->spawnsRemaining_ = items;
226    }
227
228    /**
229    @brief
230        Decrements the number of remaining spawns.
231        Sets the PickupSpawner to inactive for the duration of the respawnTime.
232        Destroys the PickupSpawner if the number of remaining spawns has reached zero.
233    */
234    void PickupSpawner::decrementSpawnsRemaining(void)
235    {
236        if(this->spawnsRemaining_ != INF)
237            this->spawnsRemaining_--;
238
239        this->setActive(false);
240
241        if(this->spawnsRemaining_ != 0 && this->respawnTime_ > 0)
242        {
243            this->startRespawnTimer();
244            this->fireEvent();
245        }
246        else
247        {
248            orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") empty, selfdestruct initialized." << endl;
249            this->destroy();
250        }
251    }
252
253    /**
254    @brief
255        Starts the respawn timer.
256    */
257    void PickupSpawner::startRespawnTimer(void)
258    {
259        this->respawnTimer_.setTimer(this->respawnTime_, false, createExecutor(createFunctor(&PickupSpawner::respawnTimerCallback, this)));
260    }
261
262    /**
263    @brief
264        Invoked by the timer, re-activates the PickupSpawner.
265    */
266    void PickupSpawner::respawnTimerCallback()
267    {
268        orxout(verbose, context::pickups) << "PickupSpawner (&" << this << ") reactivated." << endl;
269
270        this->setPickupable(this->createPickup());
271    }
272
273    /**
274    @brief
275        Creates a new Pickupable.
276    @return
277        The Pickupable created.
278    */
279    Pickupable* PickupSpawner::createPickup(void)
280    {
281        if(this->spawnsRemaining_ == 0)
282        {
283            orxout(internal_error, context::pickups) << "Massive Error: PickupSpawner still alive until having spawned last item." << endl;
284            return nullptr;
285        }
286
287        if (this->pickupTemplate_ != nullptr)
288        {
289            Identifier* identifier = this->pickupTemplate_->getBaseclassIdentifier();
290            if (identifier != nullptr)
291            {
292                Pickupable* pickup = orxonox_cast<Pickupable*>(identifier->fabricate(this->getContext()));
293                orxonox_cast<BaseObject*>(pickup)->addTemplate(this->pickupTemplate_);
294                return pickup;
295            }
296            else
297                orxout(internal_error, context::pickups) << "No base class defined in pickup-template " << this->pickupTemplateName_ << endl;
298        }
299
300        return nullptr;
301    }
302
303    /**
304    @brief
305        Sets a Pickupable for the PickupSpawner to spawn.
306    @param pickup
307        The Pickupable to be set.
308    */
309    void PickupSpawner::setPickupable(Pickupable* pickup)
310    {
311        if (this->representation_ != nullptr)
312        {
313            this->representation_->destroy();
314            this->representation_ = nullptr;
315        }
316
317        if (pickup != nullptr)
318        {
319            if (this->pickup_ != nullptr)
320                this->pickup_->destroy();
321
322            PickupRepresentation* representation = PickupManager::getInstance().getRepresentation(pickup->getRepresentationName());
323            this->representation_ = representation->createSpawnerRepresentation(this);
324            this->attach(this->representation_);
325            this->setActive(true);
326        }
327        else
328        {
329            this->setActive(false);
330        }
331
332        this->pickup_ = pickup;
333    }
334}
Note: See TracBrowser for help on using the repository browser.