Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 11277 was 11277, checked in by patricwi, 7 years ago

visualization of pickup system initiated. next steps: add pickup icons when picked up

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