Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/HUD_HS16/src/modules/pickup/PickupManager.cc @ 11241

Last change on this file since 11241 was 11241, checked in by patricwi, 8 years ago

KeyBindings-logic added, eventhough still all leading to ESC

  • Property svn:eol-style set to native
File size: 23.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 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      ...
26 *
27*/
28
29/**
30    @file PickupManager.cc
31    @brief Implementation of the PickupManager class.
32*/
33
34#include "PickupManager.h"
35
36#include "core/CoreIncludes.h"
37#include "core/LuaState.h"
38#include "core/GUIManager.h"
39#include "core/class/Identifier.h"
40#include "core/singleton/ScopedSingletonIncludes.h"
41#include "network/Host.h"
42#include "network/NetworkFunctionIncludes.h"
43#include "core/input/KeyBinderManager.h"    //for keybinding
44#include "core/input/KeyBinder.h"           //for keybinding
45
46#include "infos/PlayerInfo.h"
47#include "interfaces/PickupCarrier.h"
48#include "worldentities/pawns/Pawn.h"
49
50#include "CollectiblePickup.h"
51#include "PickupRepresentation.h"
52
53namespace orxonox
54{
55    ManageScopedSingleton(PickupManager, ScopeID::ROOT, false);
56
57    // Initialization of the name of the PickupInventory GUI.
58    /*static*/ const std::string PickupManager::guiName_s = "PickupInventory";
59
60    // Register static network functions that are used to communicate changes to pickups over the network, such that the PickupInventory can display the information about the pickups properly.
61    registerStaticNetworkFunction(PickupManager::pickupChangedUsedNetwork);
62    registerStaticNetworkFunction(PickupManager::pickupChangedPickedUpNetwork);
63    registerStaticNetworkFunction(PickupManager::dropPickupNetworked);
64    registerStaticNetworkFunction(PickupManager::usePickupNetworked);
65
66    RegisterAbstractClass(PickupManager).inheritsFrom<PickupListener>();
67
68    /**
69    @brief
70        Constructor. Registers the PickupManager and creates the default PickupRepresentation.
71    */
72    PickupManager::PickupManager() : guiLoaded_(false), pickupHighestIndex_(0), defaultRepresentation_(nullptr)
73    {
74        RegisterObject(PickupManager);
75
76        this->defaultRepresentation_ = new PickupRepresentation();
77
78        orxout(internal_info, context::pickups) << "PickupManager created." << endl;
79    }
80
81    /**
82    @brief
83        Destructor.
84        Destroys the default PickupRepresentation and does some cleanup.
85    */
86    PickupManager::~PickupManager()
87    {
88        // Destroying the default representation.
89        if(this->defaultRepresentation_ != nullptr)
90            this->defaultRepresentation_->destroy();
91
92        this->representations_.clear();
93
94        // Destroying all the PickupInventoryContainers that are still there.
95        for(const auto& mapEntry : this->pickupInventoryContainers_)
96            delete mapEntry.second;
97        this->pickupInventoryContainers_.clear();
98
99        // Destroying all the WeakPointers that are still there.
100        this->pickups_.clear();
101
102        this->indexes_.clear();
103
104        orxout(internal_info, context::pickups) << "PickupManager destroyed." << endl;
105    }
106
107    /**
108    @brief
109        Registers a PickupRepresentation.
110    @param name
111        The representation's name.
112    @param representation
113        A pointer to the PickupRepresentation.
114    @return
115        Returns true if successful and false if not.
116    */
117    bool PickupManager::registerRepresentation(const std::string& name, PickupRepresentation* representation)
118    {
119        assert(representation);
120
121        // If the list is not empty and Pickupable already has a Representation registered.
122        if(!this->representations_.empty() && this->representations_.find(name) != this->representations_.end())
123            return false;
124
125        this->representations_[name] = representation;
126
127        orxout(verbose, context::pickups) << "PickupRepresentation &" << representation << " registered with the PickupManager." << endl;
128        return true;
129    }
130
131    /**
132    @brief
133        Unegisters a PickupRepresentation.
134    @param name
135        The representation's name.
136    @return
137        Returns true if successful and false if not.
138    */
139    bool PickupManager::unregisterRepresentation(const std::string& name)
140    {
141        std::map<std::string, PickupRepresentation*>::iterator it = this->representations_.find(name);
142        if(it == this->representations_.end()) // If the Pickupable is not registered in the first place.
143            return false;
144
145        this->representations_.erase(it);
146
147        orxout(verbose, context::pickups) << "PickupRepresentation &" << name << " unregistered with the PickupManager." << endl;
148        return true;
149    }
150
151    /**
152    @brief
153        Get the PickupRepresentation with the given name.
154    @param name
155        The name of the PickupRepresentation.
156    @return
157        Returns a pointer to the PickupRepresentation.
158    */
159    PickupRepresentation* PickupManager::getRepresentation(const std::string& name)
160    {
161        std::map<std::string, PickupRepresentation*>::iterator it = this->representations_.find(name);
162        if(it == this->representations_.end()) // If there is no PickupRepresentation associated with the input name.
163        {
164            orxout(verbose, context::pickups) << "PickupManager::getRepresentation() returned default representation." << endl;
165            return this->defaultRepresentation_;
166        }
167
168        return it->second;
169    }
170
171    /**
172    @brief
173        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input used state.
174    @param pickup
175        The Pickupable whose used status changed.
176    @param used
177        The used status the Pickupable changed to.
178    */
179    void PickupManager::pickupChangedUsed(Pickupable* pickup, bool used)
180    {
181        assert(pickup);
182
183        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
184            return;
185
186        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
187        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
188        if(collectible != nullptr && collectible->isInCollection())
189            return;
190
191        // Getting clientId of the host this change of the pickup's used status concerns.
192        PickupCarrier* carrier = pickup->getCarrier();
193        while(carrier->getCarrierParent() != nullptr)
194            carrier = carrier->getCarrierParent();
195        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
196        if(pawn == nullptr)
197            return;
198        PlayerInfo* info = pawn->getPlayer();
199        if(info == nullptr)
200            return;
201        unsigned int clientId = info->getClientID();
202
203        // Get the number identifying the pickup.
204        std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
205        assert(it != this->indexes_.end());
206        uint32_t index = it->second;
207
208        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
209        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
210        {
211            PickupManager::pickupChangedUsedNetwork(index, used, pickup->isUsable(), pickup->isUnusable());
212        }
213        // If the concerned host is somewhere in the network, we call pickupChangedUsedNetwork() on its PickupManager.
214        else
215        {
216            callStaticNetworkFunction(&PickupManager::pickupChangedUsedNetwork, clientId, index, used, pickup->isUsable(), pickup->isUnusable());
217        }
218    }
219
220    /**
221    @brief
222        Helper method to react to the change in the used status of a Pickupable.
223        Static method that is used by the server to inform the client it concerns about the status change.
224        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
225    @param pickup
226        A number identifying the Pickupable that changed its used status.
227    @param inUse
228        The used status the Pickupable changed to. (i.e. whether the Pickupable is in use or not).
229    @param usable
230        Whether the Pickupable's used status can be changed used in the PickupInventory.
231    @param unusable
232        Whether the Pickupable's used status can be changed to unused in the PickupInventory.
233    */
234    /*static*/ void PickupManager::pickupChangedUsedNetwork(uint32_t pickup, bool inUse, bool usable, bool unusable)
235    {
236        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
237        // If the input Pickupable (i.e its identifier) is not present in the list the PickupManager has.
238        if(manager.pickupInventoryContainers_.find(pickup) == manager.pickupInventoryContainers_.end())
239        {
240            orxout(internal_error, context::pickups) << "Pickupable &(" << pickup << ") was not registered with PickupManager for the PickupInventory, when it changed used." << endl;
241            return;
242        }
243
244        // Update the Pickupable's container with the information transferred.
245        manager.pickupInventoryContainers_[pickup]->inUse = inUse;
246        manager.pickupInventoryContainers_[pickup]->usable = usable;
247        manager.pickupInventoryContainers_[pickup]->unusable = unusable;
248
249        manager.updateGUI(); // Tell the PickupInventory that something has changed.
250    }
251
252    /**
253    @brief
254        Is called by the PickupListener to notify the PickupManager, that the input Pickupable has transited to the input pickedUp state.
255    @param pickup
256        The Pickupable whose pickedUp status changed.
257    @param pickedUp
258        The pickedUp status the Pickupable changed to.
259    */
260    void PickupManager::pickupChangedPickedUp(Pickupable* pickup, bool pickedUp)
261    {
262        assert(pickup);
263
264        if(!GameMode::isMaster()) // If this is neither standalone nor the server.
265            return;
266
267        CollectiblePickup* collectible = orxonox_cast<CollectiblePickup*>(pickup);
268        // If the Pickupable is part of a PickupCollection it isn't displayed in the PickupInventory, just the PickupCollection is.
269        if(collectible != nullptr && collectible->isInCollection())
270            return;
271
272        // Getting clientId of the host this change of the pickup's pickedUp status concerns.
273        PickupCarrier* carrier = pickup->getCarrier();
274        while(carrier->getCarrierParent() != nullptr)
275            carrier = carrier->getCarrierParent();
276        Pawn* pawn = orxonox_cast<Pawn*>(carrier);
277        if(pawn == nullptr)
278            return;
279        PlayerInfo* info = pawn->getFormerPlayer();
280        if(info == nullptr)
281            return;
282        unsigned int clientId = info->getClientID();
283
284        uint32_t index = 0;
285        if(pickedUp) // If the Pickupable has changed to picked up, it is added to the required lists.
286        {
287            index = this->getPickupIndex(); // Get a new identifier (index) for the Pickupable.
288            // Add the Pickupable to the indexes_ and pickups_ lists.
289            this->indexes_[pickup] = index;
290            this->pickups_[index] = pickup;
291
292             //Add pickup keybinding
293            if( KeyBinderManager::exists() )
294                addKeyBindingForNewPickup(pickup, index);
295            else
296                orxout() << "Could not create new keybinding because KeyBinderManager doesn't exist." << endl;
297        }
298        else // If it was dropped, it is removed from the required lists.
299        {
300            // Get the indentifier (index) that identifies the input Pickupable.
301            std::map<Pickupable*, uint32_t>::iterator it = this->indexes_.find(pickup);
302            index = it->second;
303
304            //Remove pickup keybinding
305            if( KeyBinderManager::exists() )
306                  removeKeyBindingForOldPickup(pickup, index);
307            else
308                orxout() << "Could not delete old keybinding because KeyBinderManager doesn't exist." << endl;
309
310            // Remove the Pickupable from the indexes_ and pickups_ list.
311            this->indexes_.erase(pickup);
312            this->pickups_.find(index)->second=nullptr; //set to null, so that can be indentified as free slot by getPickupIndex()
313        }
314
315        // If we're either in standalone mode or this is the host whom the change of the pickup's status concerns.
316        if(GameMode::isStandalone() || Host::getPlayerID() == clientId)
317        {
318            // If there is no PickupRepresentation registered the default representation is used.
319            if(this->representations_.find(pickup->getRepresentationName()) == this->representations_.end())
320                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickup->getRepresentationName(), pickedUp);
321            else
322                PickupManager::pickupChangedPickedUpNetwork(index, pickup->isUsable(), this->representations_[pickup->getRepresentationName()]->getObjectID(), pickup->getRepresentationName(), pickedUp);
323        }
324        // If the concerned host is somewhere in the network, we call pickupChangedPickedUpNetwork() on its PickupManager.
325        else
326        {
327            // If there is no PickupRepresentation registered the default representation is used.
328            if(this->representations_.find(pickup->getRepresentationName()) == this->representations_.end())
329            {
330                callStaticNetworkFunction(&PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->defaultRepresentation_->getObjectID(), pickedUp);
331            }
332            else
333            {
334                callStaticNetworkFunction(&PickupManager::pickupChangedPickedUpNetwork, clientId, index, pickup->isUsable(), this->representations_[pickup->getRepresentationName()]->getObjectID(), pickedUp);
335            }
336        }
337
338    }
339
340    //PRECONDITION: KeyBinderManager exists, pickup is not NULL, 0 < index < 9
341    //FUNCTION: Adds a keybinding for the new pickup using its index
342    void PickupManager::addKeyBindingForNewPickup(Pickupable* pickup, uint32_t index)
343    {
344        std::string name="Keys.KeyNumpad";
345        std::string binding="";
346
347        name.append(std::to_string(index));
348
349        KeyBinderManager::getInstance().getCurrent()->setBinding("KeyESC", name, true); // TODO do not set all bindings to ESC
350
351        orxout() << "Keybinding for item " << index << " has been added on keybinding " << name << endl;
352
353
354    }
355
356    //PRECONDITION: KeyBinderManager exists, pickup is not NULL, 0 < index < 9
357    //FUNCTION: Removes the keybinding of the pickup using its index
358    void PickupManager::removeKeyBindingForOldPickup(Pickupable* pickup, uint32_t index)
359    {
360        std::string name="Keys.KeyNumpad";
361        std::string binding="";
362
363        name.append(std::to_string(index));
364
365        KeyBinderManager::getInstance().getCurrent()->setBinding("", name, true); 
366
367        orxout() << "Keybinding for item " << index << " has been removed on keybinding " << name << endl;
368
369    }
370
371    /**
372    @brief
373        Helper method to react to the change in the pickedUp status of a Pickupable.
374        Static method that is used by the server to inform the client it concerns about the status change.
375        The parameters that are given are used to update the information (i.e. the PickupInventoryContainer) the concerning PickupManager has about the Pickupable that changed.
376    @param pickup
377        A number identifying the Pickupable that changed its pickedUp status.
378    @param usable
379        Whether the Pickupable's used status can be changed to used in the PickupInventory.
380    @param representationObjectId
381        The objectId identifying (over the network) the PickupRepresentation that represents this Pickupable.
382    @param representationName
383        The name of the associated PickupRepresentation
384    @param pickedUp
385        The pickedUp status the Pickupable changed to.
386    */
387    /*static*/ void PickupManager::pickupChangedPickedUpNetwork(uint32_t pickup, bool usable, uint32_t representationObjectId, const std::string& representationName, bool pickedUp)
388    {
389        PickupManager& manager = PickupManager::getInstance(); // Get the PickupManager singleton on this host.
390        // If the Pickupable has been picked up, we create a new PickupInventoryContainer for it.
391        if(pickedUp)
392        {
393            // Create a new PickupInventoryContainer for the Pickupable and set all the necessary information.
394            PickupInventoryContainer* container = new PickupInventoryContainer;
395            container->pickup = pickup;
396            container->inUse = false;
397            container->pickedUp = pickedUp;
398            container->usable = usable;
399            container->unusable = false;
400            container->representationObjectId = representationObjectId;
401            container->representationName = representationName;
402            // Insert the container into the pickupInventoryContainers_ list.
403            manager.pickupInventoryContainers_.insert(std::pair<uint32_t, PickupInventoryContainer*>(pickup, container));
404
405            manager.updateGUI(); // Tell the PickupInventory that something has changed.
406        }
407        // If the Pickupable has been dropped, we remove it from the pickupInventoryContainers_ list.
408        else
409        {
410            std::map<uint32_t, PickupInventoryContainer*>::iterator it = manager.pickupInventoryContainers_.find(pickup);
411            if(it != manager.pickupInventoryContainers_.end())
412                delete it->second;
413            manager.pickupInventoryContainers_.erase(pickup);
414
415            manager.updateGUI(); // Tell the PickupInventory that something has changed.
416        }
417    }
418
419    /**
420    @brief
421        Get the number of pickups currently picked up by the player.
422        This method is used in lua to populate the PickupInventory. The intended usage is to call this method to reset the iterator of the list of PickupInventoryContainers and then use popPickup() to get the individual PickupInventoryContainers.
423    @return
424        Returns the number of the players picked up Pickupables.
425    */
426    int PickupManager::getNumPickups(void)
427    {
428        this->pickupsIterator_ = this->pickupInventoryContainers_.begin(); // Reset iterator.
429
430        return this->pickupInventoryContainers_.size();
431    }
432
433    /**
434    @brief
435        Drop the input Pickupable.
436        This method checks whether the input Pickupable still exists and drops it, if so.
437    @param pickup
438        The identifier of the Pickupable to be dropped.
439    */
440    void PickupManager::dropPickup(uint32_t pickup)
441    {
442        // If we're either server or standalone and the list of pickups is not empty, we find and drop the input pickup.
443        if(GameMode::isMaster())
444        {
445            if(this->pickups_.empty())
446                return;
447            Pickupable* pickupable = this->pickups_.find(pickup)->second;
448            if(pickupable != nullptr)
449            {
450                pickupable->drop();
451
452            }
453        }
454        // If we're neither server nor standalone we drop the pickup by calling dropPickupNetworked() of the PickupManager on the server.
455        else
456        {
457            callStaticNetworkFunction(&PickupManager::dropPickupNetworked, 0, pickup);
458        }
459    }
460
461    /**
462    @brief
463        Helper method to drop the input pickup on the server.
464        Static method that is used by clients to instruct the server to drop the input pickup.
465    @param pickup
466        The identifier of the Pickupable to be dropped.
467    */
468    /*static*/ void PickupManager::dropPickupNetworked(uint32_t pickup)
469    {
470        if(GameMode::isServer()) // Obviously we only want to do this on the server.
471        {
472            PickupManager& manager = PickupManager::getInstance();
473            manager.dropPickup(pickup);
474        }
475    }
476
477    /**
478    @brief
479        Use (or unuse) the input Pickupable.
480        This method checks whether the input Pickupable still exists and uses (or unuses) it, if so,
481    @param pickup
482        The identifier of the Pickupable to be used (or unused).
483    @param use
484        If true the input Pickupable is used, if false it is unused.
485    */
486    void PickupManager::usePickup(uint32_t pickup, bool use)
487    {
488        // If we're either server or standalone and the list of pickups is not empty, we find and change the used status of the input pickup.
489        if(GameMode::isMaster())
490        {
491            if(this->pickups_.empty())
492                return;
493            Pickupable* pickupable = this->pickups_.find(pickup)->second;
494            if(pickupable != nullptr)
495                pickupable->setUsed(use);
496        }
497        // If we're neither server nor standalone we change the used status of the pickup by calling usePickupNetworked() of the PickupManager on the server.
498        else
499        {
500            callStaticNetworkFunction(&PickupManager::usePickupNetworked, 0, pickup, use);
501        }
502    }
503
504    /**
505    @brief
506        Helper method to use (or unuse) the input Pickupable on the server.
507        Static method that is used by clients to instruct the server to use (or unuse) the input pickup.
508    @param pickup
509        The identifier of the Pickupable to be used (or unused).
510    @param use
511        If true the input Pickupable is used, if false it is unused.
512    */
513    /*static*/ void PickupManager::usePickupNetworked(uint32_t pickup, bool use)
514    {
515        if(GameMode::isServer())
516        {
517            PickupManager& manager = PickupManager::getInstance();
518            manager.usePickup(pickup, use);
519        }
520    }
521
522    /**
523    @brief
524        Updates the PickupInventory GUI.
525        Also loads the PickupInventory GUI if is hasn't been done already.
526    */
527    inline void PickupManager::updateGUI(void)
528    {
529        // We only need to update (and load) the GUI if this host shows graphics.
530        if(GameMode::showsGraphics())
531        {
532            if(!this->guiLoaded_) // If the GUI hasn't been loaded, yet, we load it.
533            {
534                GUIManager::getInstance().loadGUI(PickupManager::guiName_s);
535                this->guiLoaded_ = true;
536            }
537
538            // Update the GUI.
539            GUIManager::getInstance().getLuaState()->doString(PickupManager::guiName_s + ".update()");
540        }
541    }
542
543    /**
544    @brief
545        Get a new index between 0 and 9 for a Pickupable.
546        If all slots are occupied, the Pickupable in the first slot will be dropped.
547    @return
548        Returns the new index.
549    */
550    uint32_t PickupManager::getPickupIndex(void)
551    {
552        //check if there are free slots available
553
554        for(uint32_t i=0; i<10; i++)
555        {
556            if(pickups_.find(i)->second==nullptr) return i;
557        }
558        //all slots are full and we have to drop sth
559        orxout() << "everything was full and we have now dropped the first element" << endl;
560        this->dropPickup(0);
561        return 0;
562    }
563
564}
Note: See TracBrowser for help on using the repository browser.