Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 12351 was 11783, checked in by landauf, 7 years ago

merged Presentation_HS17_merge 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    */
55    PickupSpawner::PickupSpawner(Context* context) : StaticEntity(context), pickup_(nullptr), representation_(nullptr), pickupTemplate_(nullptr)
56    {
57        RegisterObject(PickupSpawner);
58
59        this->initialize();
60    }
61
62    /**
63    @brief
64        Registers the object and sets some default values.
65    */
66    void PickupSpawner::initialize(void)
67    {
68        this->triggerDistance_ = 10;
69        this->respawnTime_ = 5.0f;
70        this->maxSpawnedItems_ = INF;
71        this->spawnsRemaining_ = INF;
72        this->selfDestruct_ = false;
73
74        this->setPickupable(nullptr);
75    }
76
77    /**
78    @brief
79        Destructor.
80    */
81    PickupSpawner::~PickupSpawner()
82    {
83        if(this->isInitialized() && this->selfDestruct_ && this->pickup_ != nullptr)
84            this->pickup_->destroy();
85    }
86
87    /**
88    @brief
89        Factory method, Creates a fully functional PickupSpawner.
90    @param context
91        The context of this PickupSpawner.
92    @param pickup
93        The Pickupable to be spawned by this PickupSpawner.
94    @param carrier
95        The PickupCarrier that carried the input pickup before it was dropped.
96    @param triggerDistance
97        The distance at which the PickupSpawner will trigger.
98    */
99    /*static*/ PickupSpawner* PickupSpawner::createDroppedPickup(Context* context, Pickupable* pickup, PickupCarrier* carrier, float triggerDistance)
100    {
101        PickupSpawner* spawner = new PickupSpawner(context);
102
103        spawner->setPickupable(pickup);
104        spawner->setTriggerDistance(triggerDistance);
105        spawner->setMaxSpawnedItems(1);
106
107        spawner->setPosition(carrier->getCarrierPosition());
108        spawner->block(carrier);
109
110        return spawner;
111    }
112
113    /**
114    @brief
115        Method for creating a PickupSpawner through XML.
116    @param xmlelement
117        XML element which contains the PickupSpawner.
118    @param mode
119        XMLPort mode.
120    */
121    void PickupSpawner::XMLPort(Element& xmlelement, XMLPort::Mode mode)
122    {
123        SUPER(PickupSpawner, XMLPort, xmlelement, mode);
124
125        XMLPortParam(PickupSpawner, "pickup", setPickupTemplateName, getPickupTemplateName, xmlelement, mode);
126        XMLPortParam(PickupSpawner, "triggerDistance", setTriggerDistance, getTriggerDistance, xmlelement, mode);
127        XMLPortParam(PickupSpawner, "respawnTime", setRespawnTime, getRespawnTime, xmlelement, mode);
128        XMLPortParam(PickupSpawner, "maxSpawnedItems", setMaxSpawnedItems, getMaxSpawnedItems, xmlelement, mode);
129    }
130
131    /**
132    @brief
133        Tick, checks if any Pawn is close enough to trigger.
134    @param dt
135        Time since last tick.
136    */
137    //TODO: Replace with collisions?
138    void PickupSpawner::tick(float dt)
139    {
140        SUPER(PickupSpawner, tick, dt);
141
142        // If the PickupSpawner is active.
143        if(GameMode::isMaster() && this->isActive())
144        {
145            // TODO: why is this a WeakPtr when the comment says StrongPtr?
146            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)
147
148            // Remove PickupCarriers from the blocked list if they have exceeded their time.
149            for(std::map<PickupCarrier*, std::time_t>::iterator it = this->blocked_.begin(); it != this->blocked_.end(); )
150            {
151                std::map<PickupCarrier*, std::time_t>::iterator temp = it;
152                it++;
153                if(temp->second < std::time(0))
154                    this->blocked_.erase(temp);
155            }
156
157            // Iterate trough all Pawns.
158            for(Pawn* pawn : ObjectList<Pawn>())
159            {
160                if(!(pawn->doesAcceptPickups())){continue;} // skip those pawns, e.g. AsteroidMinables.
161
162                Vector3 distance = pawn->getWorldPosition() - this->getWorldPosition();
163                PickupCarrier* carrier = static_cast<PickupCarrier*>(pawn);
164                // 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.
165                if(distance.length() < this->triggerDistance_ && carrier != nullptr && this->blocked_.find(carrier) == this->blocked_.end())
166                {
167                    if(carrier->isTarget(this->pickup_))
168                    {
169                        this->trigger(pawn); // Attention: after this line, pickup_ is probably nullptr (because it was taken) and even spawner can be nullptr (if it run out of pickups)!
170                        break;
171                    }
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        (void)pickedUp; // 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.