Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/gametypes/Gametype.cc @ 11358

Last change on this file since 11358 was 11358, checked in by patricwi, 3 years ago

space race merged

  • Property svn:eol-style set to native
File size: 18.7 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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Gametype.h"
30
31#include "util/Math.h"
32#include "core/Core.h"
33#include "core/CoreIncludes.h"
34#include "core/config/ConfigValueIncludes.h"
35#include "core/GameMode.h"
36#include "core/command/ConsoleCommandIncludes.h"
37#include "gamestates/GSLevel.h"
38
39#include "infos/PlayerInfo.h"
40#include "infos/Bot.h"
41#include "graphics/Camera.h"
42#include "worldentities/ControllableEntity.h"
43#include "worldentities/SpawnPoint.h"
44#include "worldentities/pawns/Spectator.h"
45#include "worldentities/pawns/Pawn.h"
46#include "overlays/OverlayGroup.h"
47#include "Scene.h"
48
49namespace orxonox
50{
51    static const std::string __CC_addBots_name  = "addBots";
52    static const std::string __CC_killBots_name = "killBots";
53
54    SetConsoleCommand("Gametype", __CC_addBots_name,  &Gametype::addBots ).addShortcut().defaultValues(1);
55    SetConsoleCommand("Gametype", __CC_killBots_name, &Gametype::killBots).addShortcut().defaultValues(0);
56
57    RegisterUnloadableClass(Gametype);
58
59    Gametype::Gametype(Context* context) : BaseObject(context)
60    {
61        RegisterObject(Gametype);
62
63        this->setGametype(WeakPtr<Gametype>(this)); // store a weak-pointer to itself (a strong-pointer would create a recursive dependency)
64
65        this->gtinfo_ = new GametypeInfo(context);
66
67        this->defaultControllableEntity_ = Class(Spectator);
68        this->scoreboard_ = nullptr;
69
70        this->bAutoStart_ = false;
71        this->bForceSpawn_ = false;
72        this->bAutoEnd_ = true;
73        this->numberOfBots_ = 0;
74
75        this->timeLimit_ = 0;
76        this->time_ = 0;
77        this->timerIsActive_ = false;
78
79        this->initialStartCountdown_ = 3;
80
81        this->setConfigValues();
82
83        ModifyConsoleCommand(__CC_addBots_name).setObject(this);
84        ModifyConsoleCommand(__CC_killBots_name).setObject(this);
85    }
86
87    Gametype::~Gametype()
88    {
89        if (this->isInitialized())
90        {
91            if (this->gtinfo_)
92                this->gtinfo_->destroy();
93
94            ModifyConsoleCommand(__CC_addBots_name).setObject(nullptr);
95            ModifyConsoleCommand(__CC_killBots_name).setObject(nullptr);
96        }
97    }
98   
99    /**
100     * @brief Initializes sub-objects of the Gametype. This must be called after the constructor.
101     * At this point, the context is expected to have the current gametype. This allows to pass the current gametype to the sub-objects via constructor.
102     */
103    void Gametype::init()
104    {
105        // load the corresponding score board
106        if (GameMode::showsGraphics() && !this->scoreboardTemplate_.empty())
107        {
108            this->scoreboard_ = new OverlayGroup(this->getContext());
109            this->scoreboard_->addTemplate(this->scoreboardTemplate_);
110        }
111    }
112
113    void Gametype::setConfigValues()
114    {
115        SetConfigValue(initialStartCountdown_, 3.0f);
116        SetConfigValue(bAutoStart_, false);
117        SetConfigValue(bForceSpawn_, false);
118        SetConfigValue(bAutoEnd_, true);
119        SetConfigValue(numberOfBots_, 0);
120        SetConfigValue(scoreboardTemplate_, "defaultScoreboard");
121    }
122
123    void Gametype::tick(float dt)
124    {
125        SUPER(Gametype, tick, dt);
126
127        //count timer
128        if (timerIsActive_)
129        {
130            if (this->timeLimit_ == 0)
131                this->time_ += dt;
132            else
133                this->time_ -= dt;
134        }
135
136        if (this->gtinfo_->isStartCountdownRunning() && !this->gtinfo_->hasStarted())
137            this->gtinfo_->countdownStartCountdown(dt);
138
139        if (!this->gtinfo_->hasStarted())
140        {
141            for (const auto& mapEntry : this->players_)
142            {
143                // Inform the GametypeInfo that the player is ready to spawn.
144                if(mapEntry.first->isHumanPlayer() && mapEntry.first->isReadyToSpawn())
145                    this->gtinfo_->playerReadyToSpawn(mapEntry.first);
146            }
147
148            this->checkStart();
149        }
150        else if (!this->gtinfo_->hasEnded())
151            this->spawnDeadPlayersIfRequested();
152
153        this->assignDefaultPawnsIfNeeded();
154    }
155
156    void Gametype::start()
157    {
158        this->addBots(this->numberOfBots_);
159        this->gtinfo_->start();
160        this->spawnPlayersIfRequested();
161    }
162
163    void Gametype::end()
164    {
165        this->gtinfo_->end();
166        if (this->bAutoEnd_)
167        {
168            this->showMenuTimer_.setTimer(3.0f, true, createExecutor(createFunctor(&Gametype::showMenu, this)));
169        }
170
171        for (const auto& mapEntry : this->players_)
172        {
173            if (mapEntry.first->getControllableEntity())
174            {
175                ControllableEntity* oldentity = mapEntry.first->getControllableEntity();
176
177                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(oldentity->getContext());
178                if (oldentity->getCamera())
179                {
180                    entity->setPosition(oldentity->getCamera()->getWorldPosition());
181                    entity->setOrientation(oldentity->getCamera()->getWorldOrientation());
182                }
183                else
184                {
185                    entity->setPosition(oldentity->getWorldPosition());
186                    entity->setOrientation(oldentity->getWorldOrientation());
187                }
188                mapEntry.first->startControl(entity);
189            }
190            else
191                this->spawnPlayerAsDefaultPawn(mapEntry.first);
192        }
193    }
194
195    void Gametype::playerEntered(PlayerInfo* player)
196    {
197        this->players_[player].state_ = PlayerState::Joined;
198        this->gtinfo_->playerEntered(player);
199    }
200
201    bool Gametype::playerLeft(PlayerInfo* player)
202    {
203        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
204        if (it != this->players_.end())
205        {
206            this->players_.erase(it);
207            return true;
208        }
209        return false;
210    }
211
212    void Gametype::playerSwitched(PlayerInfo* player, Gametype* newgametype)
213    {
214    }
215
216    void Gametype::playerSwitchedBack(PlayerInfo* player, Gametype* oldgametype)
217    {
218    }
219
220    bool Gametype::playerChangedName(PlayerInfo* player)
221    {
222        if (this->players_.find(player) != this->players_.end())
223        {
224            if (player->getName() != player->getOldName())
225            {
226                return true;
227            }
228        }
229        return false;
230    }
231
232    void Gametype::pawnPreSpawn(Pawn* pawn)
233    {
234    }
235
236    void Gametype::pawnPostSpawn(Pawn* pawn)
237    {
238    }
239
240    void Gametype::playerPreSpawn(PlayerInfo* player)
241    {
242    }
243
244    void Gametype::playerPostSpawn(PlayerInfo* player)
245    {
246    }
247
248    void Gametype::playerStartsControllingPawn(PlayerInfo* player, Pawn* pawn)
249    {
250    }
251
252    void Gametype::playerStopsControllingPawn(PlayerInfo* player, Pawn* pawn)
253    {
254    }
255
256    bool Gametype::allowPawnHit(Pawn* victim, Pawn* originator)
257    {
258        return true;
259    }
260
261    bool Gametype::allowPawnDamage(Pawn* victim, Pawn* originator)
262    {
263        return true;
264    }
265
266    bool Gametype::allowPawnDeath(Pawn* victim, Pawn* originator)
267    {
268        return true;
269    }
270
271    void Gametype::pawnKilled(Pawn* victim, Pawn* killer)
272    {
273        if (victim && victim->getPlayer())
274        {
275            std::map<PlayerInfo*, Player>::iterator it = this->players_.find(victim->getPlayer());
276            if (it != this->players_.end())
277            {
278                it->second.state_ = PlayerState::Dead;
279                it->second.killed_++;
280
281                // Reward killer
282                if (killer && killer->getPlayer())
283                {
284                    std::map<PlayerInfo*, Player>::iterator it = this->players_.find(killer->getPlayer());
285                    if (it != this->players_.end())
286                    {
287                        it->second.frags_++;
288
289                        if (killer->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
290                            this->gtinfo_->sendKillMessage("You killed " + victim->getPlayer()->getName(), killer->getPlayer()->getClientID());
291                        if (victim->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
292                            this->gtinfo_->sendDeathMessage("You were killed by " + killer->getPlayer()->getName(), victim->getPlayer()->getClientID());
293                    }
294                }
295
296                if(victim->getPlayer()->isHumanPlayer())
297                    this->gtinfo_->pawnKilled(victim->getPlayer());
298
299                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(victim->getContext());
300                if (victim->getCamera())
301                {
302                    entity->setPosition(victim->getCamera()->getWorldPosition());
303                    entity->setOrientation(victim->getCamera()->getWorldOrientation());
304                }
305                else
306                {
307                    entity->setPosition(victim->getWorldPosition());
308                    entity->setOrientation(victim->getWorldOrientation());
309                }
310                it->first->startControl(entity);
311            }
312            else
313                orxout(internal_warning) << "Killed Pawn was not in the playerlist" << endl;
314        }
315    }
316
317    void Gametype::playerScored(PlayerInfo* player, int score)
318    {
319        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
320        if (it != this->players_.end())
321            it->second.frags_ += score;
322    }
323
324    int Gametype::getScore(PlayerInfo* player) const
325    {
326        std::map<PlayerInfo*, Player>::const_iterator it = this->players_.find(player);
327        if (it != this->players_.end())
328            return it->second.frags_;
329        else
330            return 0;
331    }
332
333    SpawnPoint* Gametype::getBestSpawnPoint(PlayerInfo* player) const
334    {
335        // If there is at least one SpawnPoint.
336        if (this->spawnpoints_.size() > 0)
337        {
338            // Fallback spawn point if there is no active one, choose a random one.
339            SpawnPoint* fallbackSpawnPoint = nullptr;
340            unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(this->spawnpoints_.size())));
341            unsigned int index = 0;
342            std::vector<SpawnPoint*> activeSpawnPoints;
343            for (SpawnPoint* spawnpoint : this->spawnpoints_)
344            {
345                if (index == randomspawn)
346                    fallbackSpawnPoint = spawnpoint;
347
348                if (spawnpoint != nullptr && spawnpoint->isActive())
349                    activeSpawnPoints.push_back(spawnpoint);
350
351                ++index;
352            }
353
354            if(activeSpawnPoints.size() > 0)
355            {
356                randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(activeSpawnPoints.size())));
357                return activeSpawnPoints[randomspawn];
358            }
359
360            orxout(internal_warning) << "Fallback SpawnPoint was used because there were no active SpawnPoints." << endl;
361            return fallbackSpawnPoint;
362        }
363        return nullptr;
364    }
365
366    void Gametype::assignDefaultPawnsIfNeeded()
367    {
368        for (auto& mapEntry : this->players_)
369        {
370            if (!mapEntry.first->getControllableEntity())
371            {
372                mapEntry.second.state_ = PlayerState::Dead;
373
374                if (!mapEntry.first->isReadyToSpawn() || !this->gtinfo_->hasStarted())
375                {
376                    this->spawnPlayerAsDefaultPawn(mapEntry.first);
377                    mapEntry.second.state_ = PlayerState::Dead;
378                }
379            }
380        }
381    }
382
383    void Gametype::checkStart()
384    {
385        if (!this->gtinfo_->hasStarted())
386        {
387            if (this->gtinfo_->isStartCountdownRunning())
388            {
389                if (this->gtinfo_->getStartCountdown() <= 0.0f)
390                {
391                    this->gtinfo_->stopStartCountdown();
392                    this->gtinfo_->setStartCountdown(0.0f);
393                    this->start();
394                }
395            }
396            else if (this->players_.size() > 0)
397            {
398                if (this->bAutoStart_)
399                {
400                    this->start();
401                }
402                else
403                {
404                    bool allplayersready = true;
405                    bool hashumanplayers = false;
406                    for (const auto& mapEntry : this->players_)
407                    {
408                        if (!mapEntry.first->isReadyToSpawn())
409                            allplayersready = false;
410                        if (mapEntry.first->isHumanPlayer())
411                            hashumanplayers = true;
412                    }
413
414                    if (allplayersready && hashumanplayers)
415                    {
416                        // If in developer's mode, there is no start countdown.
417                        if(Core::getInstance().getConfig()->inDevMode())
418                            this->start();
419                        else
420                        {
421                            this->gtinfo_->setStartCountdown(this->initialStartCountdown_);
422                            this->gtinfo_->startStartCountdown();
423                        }
424                    }
425                }
426            }
427        }
428    }
429
430    void Gametype::spawnPlayersIfRequested()
431    {
432        for (const auto& mapEntry : this->players_)
433        {
434            if (mapEntry.first->isReadyToSpawn() || this->bForceSpawn_)
435                this->spawnPlayer(mapEntry.first);
436        }
437    }
438
439    void Gametype::spawnDeadPlayersIfRequested()
440    {
441        for (const auto& mapEntry : this->players_)
442            if (mapEntry.second.state_ == PlayerState::Dead)
443                if (mapEntry.first->isReadyToSpawn() || this->bForceSpawn_)
444                    this->spawnPlayer(mapEntry.first);
445    }
446
447    void Gametype::spawnPlayer(PlayerInfo* player)
448    {
449        SpawnPoint* spawnpoint = this->getBestSpawnPoint(player);
450        if (spawnpoint)
451        {
452            this->playerPreSpawn(player);
453            player->startControl(spawnpoint->spawn());
454            this->players_[player].state_ = PlayerState::Alive;
455
456            if(player->isHumanPlayer())
457                this->gtinfo_->playerSpawned(player);
458
459            this->playerPostSpawn(player);
460        }
461        else
462        {
463            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
464            abort();
465        }
466    }
467
468    void Gametype::spawnPlayerAsDefaultPawn(PlayerInfo* player)
469    {
470        SpawnPoint* spawn = this->getBestSpawnPoint(player);
471        if (spawn)
472        {
473            // force spawn at spawnpoint with default pawn
474            ControllableEntity* entity = this->defaultControllableEntity_.fabricate(spawn->getContext());
475            spawn->spawn(entity);
476            player->startControl(entity);
477        }
478        else
479        {
480            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
481            abort();
482        }
483    }
484
485    void Gametype::addBots(unsigned int amount)
486    {
487        for (unsigned int i = 0; i < amount; ++i)
488            this->botclass_.fabricate(this->getContext());
489    }
490
491    void Gametype::killBots(unsigned int amount)
492    {
493        unsigned int i = 0;
494        ObjectList<Bot> list;
495        for (ObjectList<Bot>::iterator it = list.begin(); (it != list.end()) && ((amount == 0) || (i < amount)); )
496        {
497            if (it->getGametype() == this)
498            {
499                (it++)->destroy();
500                ++i;
501            }
502            else
503                ++it;
504        }
505    }
506
507    void Gametype::addTime(float t)
508    {
509        if (this->timeLimit_ == 0)
510          this->time_ -= t;
511        else
512          this->time_ += t;
513    }
514
515    void Gametype::removeTime(float t)
516    {
517        if (this->timeLimit_ == 0)
518          this->time_ += t;
519        else
520          this->time_ -= t;
521    }
522
523    void Gametype::resetTimer()
524    {
525        this->resetTimer(timeLimit_);
526    }
527
528    void Gametype::resetTimer(float t)
529    {
530        this->timeLimit_ = t;
531        this->time_ = t;
532    }
533
534    void Gametype::showMenu()
535    {
536        GSLevel::startMainMenu();
537    }
538
539    GSLevelMementoState* Gametype::exportMementoState()
540    {
541        for (const auto& mapEntry : this->players_)
542        {
543            if (mapEntry.first->isHumanPlayer() && mapEntry.first->getControllableEntity() && mapEntry.first->getControllableEntity()->getCamera())
544            {
545                Camera* camera = mapEntry.first->getControllableEntity()->getCamera();
546
547                GametypeMementoState* state = new GametypeMementoState();
548                state->cameraPosition_ = camera->getWorldPosition();
549                state->cameraOrientation_ = camera->getWorldOrientation();
550                state->sceneName_ = camera->getScene()->getName();
551                return state;
552            }
553        }
554
555        return nullptr;
556    }
557
558    void Gametype::importMementoState(const std::vector<GSLevelMementoState*>& states)
559    {
560        // find correct memento state
561        GametypeMementoState* state = nullptr;
562        for (GSLevelMementoState* temp : states)
563        {
564            state = dynamic_cast<GametypeMementoState*>(temp);
565            if (state)
566                break;
567        }
568
569        if (!state)
570            return;
571
572        // find correct scene
573        Scene* scene = nullptr;
574        for (Scene* someScene : ObjectList<Scene>())
575        {
576            if (someScene->getName() == state->sceneName_)
577            {
578                scene = someScene;
579                break;
580            }
581        }
582
583        if (!scene)
584        {
585            orxout(internal_warning) << "Could not find scene with name " << state->sceneName_ << endl;
586            return;
587        }
588
589        // find correct player and assign default entity with original position & orientation
590        for (const auto& mapEntry : this->players_)
591        {
592            if (mapEntry.first->isHumanPlayer())
593            {
594                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(scene->getContext());
595                entity->setPosition(state->cameraPosition_);
596                entity->setOrientation(state->cameraOrientation_);
597                mapEntry.first->startControl(entity);
598                break;
599            }
600        }
601    }
602}
Note: See TracBrowser for help on using the repository browser.