Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 18.7 KB
RevLine 
[2072]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
[3196]31#include "util/Math.h"
[8079]32#include "core/Core.h"
[2072]33#include "core/CoreIncludes.h"
[9667]34#include "core/config/ConfigValueIncludes.h"
[2896]35#include "core/GameMode.h"
[10624]36#include "core/command/ConsoleCommandIncludes.h"
[9977]37#include "gamestates/GSLevel.h"
[3196]38
[5735]39#include "infos/PlayerInfo.h"
40#include "infos/Bot.h"
[5737]41#include "graphics/Camera.h"
[5735]42#include "worldentities/ControllableEntity.h"
43#include "worldentities/SpawnPoint.h"
44#include "worldentities/pawns/Spectator.h"
45#include "worldentities/pawns/Pawn.h"
[3196]46#include "overlays/OverlayGroup.h"
[10281]47#include "Scene.h"
[2072]48
49namespace orxonox
50{
[10624]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
[9667]57    RegisterUnloadableClass(Gametype);
[2072]58
[9667]59    Gametype::Gametype(Context* context) : BaseObject(context)
[2072]60    {
61        RegisterObject(Gametype);
[6417]62
[10624]63        this->setGametype(WeakPtr<Gametype>(this)); // store a weak-pointer to itself (a strong-pointer would create a recursive dependency)
64
[9667]65        this->gtinfo_ = new GametypeInfo(context);
[2072]66
67        this->defaultControllableEntity_ = Class(Spectator);
[11071]68        this->scoreboard_ = nullptr;
[2072]69
70        this->bAutoStart_ = false;
71        this->bForceSpawn_ = false;
[9977]72        this->bAutoEnd_ = true;
[2662]73        this->numberOfBots_ = 0;
[2072]74
[3033]75        this->timeLimit_ = 0;
76        this->time_ = 0;
77        this->timerIsActive_ = false;
78
[2072]79        this->initialStartCountdown_ = 3;
[2662]80
81        this->setConfigValues();
82
[10624]83        ModifyConsoleCommand(__CC_addBots_name).setObject(this);
84        ModifyConsoleCommand(__CC_killBots_name).setObject(this);
[2072]85    }
[6417]86
[5929]87    Gametype::~Gametype()
88    {
89        if (this->isInitialized())
90        {
[10624]91            if (this->gtinfo_)
92                this->gtinfo_->destroy();
93
[11071]94            ModifyConsoleCommand(__CC_addBots_name).setObject(nullptr);
95            ModifyConsoleCommand(__CC_killBots_name).setObject(nullptr);
[5929]96        }
97    }
[2072]98
[10624]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
[2662]113    void Gametype::setConfigValues()
114    {
115        SetConfigValue(initialStartCountdown_, 3.0f);
116        SetConfigValue(bAutoStart_, false);
117        SetConfigValue(bForceSpawn_, false);
[9977]118        SetConfigValue(bAutoEnd_, true);
[2662]119        SetConfigValue(numberOfBots_, 0);
120        SetConfigValue(scoreboardTemplate_, "defaultScoreboard");
121    }
122
[2072]123    void Gametype::tick(float dt)
124    {
[2662]125        SUPER(Gametype, tick, dt);
[2072]126
[3033]127        //count timer
128        if (timerIsActive_)
129        {
130            if (this->timeLimit_ == 0)
131                this->time_ += dt;
132            else
133                this->time_ -= dt;
134        }
135
[8706]136        if (this->gtinfo_->isStartCountdownRunning() && !this->gtinfo_->hasStarted())
137            this->gtinfo_->countdownStartCountdown(dt);
[9260]138
[8706]139        if (!this->gtinfo_->hasStarted())
140        {
[11071]141            for (const auto& mapEntry : this->players_)
[8706]142            {
143                // Inform the GametypeInfo that the player is ready to spawn.
[11071]144                if(mapEntry.first->isHumanPlayer() && mapEntry.first->isReadyToSpawn())
145                    this->gtinfo_->playerReadyToSpawn(mapEntry.first);
[8706]146            }
[9260]147
[2072]148            this->checkStart();
[8706]149        }
150        else if (!this->gtinfo_->hasEnded())
[2171]151            this->spawnDeadPlayersIfRequested();
[2072]152
153        this->assignDefaultPawnsIfNeeded();
154    }
155
156    void Gametype::start()
157    {
[2826]158        this->addBots(this->numberOfBots_);
[8706]159        this->gtinfo_->start();
[2072]160        this->spawnPlayersIfRequested();
161    }
162
163    void Gametype::end()
164    {
[8706]165        this->gtinfo_->end();
[9977]166        if (this->bAutoEnd_)
[9980]167        {
168            this->showMenuTimer_.setTimer(3.0f, true, createExecutor(createFunctor(&Gametype::showMenu, this)));
[9977]169        }
[3033]170
[11071]171        for (const auto& mapEntry : this->players_)
[3033]172        {
[11071]173            if (mapEntry.first->getControllableEntity())
[3033]174            {
[11071]175                ControllableEntity* oldentity = mapEntry.first->getControllableEntity();
[3038]176
[9667]177                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(oldentity->getContext());
[3033]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                }
[11071]188                mapEntry.first->startControl(entity);
[3033]189            }
190            else
[11071]191                this->spawnPlayerAsDefaultPawn(mapEntry.first);
[3033]192        }
[2072]193    }
194
195    void Gametype::playerEntered(PlayerInfo* player)
196    {
[2662]197        this->players_[player].state_ = PlayerState::Joined;
[8706]198        this->gtinfo_->playerEntered(player);
[2072]199    }
200
[2826]201    bool Gametype::playerLeft(PlayerInfo* player)
[2072]202    {
[2662]203        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
[2072]204        if (it != this->players_.end())
205        {
206            this->players_.erase(it);
[2826]207            return true;
[2072]208        }
[2826]209        return false;
[2072]210    }
211
212    void Gametype::playerSwitched(PlayerInfo* player, Gametype* newgametype)
213    {
214    }
215
216    void Gametype::playerSwitchedBack(PlayerInfo* player, Gametype* oldgametype)
217    {
218    }
219
[2826]220    bool Gametype::playerChangedName(PlayerInfo* player)
[2072]221    {
222        if (this->players_.find(player) != this->players_.end())
223        {
224            if (player->getName() != player->getOldName())
225            {
[2826]226                return true;
[2072]227            }
228        }
[2826]229        return false;
[2072]230    }
231
232    void Gametype::pawnPreSpawn(Pawn* pawn)
233    {
234    }
235
236    void Gametype::pawnPostSpawn(Pawn* pawn)
237    {
238    }
239
[2826]240    void Gametype::playerPreSpawn(PlayerInfo* player)
[2072]241    {
[2826]242    }
[2662]243
[2826]244    void Gametype::playerPostSpawn(PlayerInfo* player)
245    {
246    }
[2662]247
[2826]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    {
[2662]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
[3099]282                if (killer && killer->getPlayer())
[2839]283                {
284                    std::map<PlayerInfo*, Player>::iterator it = this->players_.find(killer->getPlayer());
285                    if (it != this->players_.end())
[3099]286                    {
[2839]287                        it->second.frags_++;
[3099]288
[8327]289                        if (killer->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
[5929]290                            this->gtinfo_->sendKillMessage("You killed " + victim->getPlayer()->getName(), killer->getPlayer()->getClientID());
[8327]291                        if (victim->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
[5929]292                            this->gtinfo_->sendDeathMessage("You were killed by " + killer->getPlayer()->getName(), victim->getPlayer()->getClientID());
[3099]293                    }
[2839]294                }
[2662]295
[8706]296                if(victim->getPlayer()->isHumanPlayer())
297                    this->gtinfo_->pawnKilled(victim->getPlayer());
298
[9667]299                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(victim->getContext());
[2662]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
[8858]313                orxout(internal_warning) << "Killed Pawn was not in the playerlist" << endl;
[2662]314        }
[2072]315    }
316
[9348]317    void Gametype::playerScored(PlayerInfo* player, int score)
[2072]318    {
[2826]319        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
320        if (it != this->players_.end())
[9348]321            it->second.frags_ += score;
[2072]322    }
323
[2890]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
[2072]333    SpawnPoint* Gametype::getBestSpawnPoint(PlayerInfo* player) const
334    {
[8706]335        // If there is at least one SpawnPoint.
[2072]336        if (this->spawnpoints_.size() > 0)
337        {
[8706]338            // Fallback spawn point if there is no active one, choose a random one.
[11071]339            SpawnPoint* fallbackSpawnPoint = nullptr;
[3196]340            unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(this->spawnpoints_.size())));
[2072]341            unsigned int index = 0;
[8706]342            std::vector<SpawnPoint*> activeSpawnPoints;
[11071]343            for (SpawnPoint* spawnpoint : this->spawnpoints_)
[2072]344            {
345                if (index == randomspawn)
[11071]346                    fallbackSpawnPoint = spawnpoint;
[7163]347
[11071]348                if (spawnpoint != nullptr && spawnpoint->isActive())
349                    activeSpawnPoints.push_back(spawnpoint);
[7163]350
351                ++index;
352            }
353
[8706]354            if(activeSpawnPoints.size() > 0)
[7163]355            {
[8706]356                randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(activeSpawnPoints.size())));
357                return activeSpawnPoints[randomspawn];
[2072]358            }
[7163]359
[8858]360            orxout(internal_warning) << "Fallback SpawnPoint was used because there were no active SpawnPoints." << endl;
[7163]361            return fallbackSpawnPoint;
[2072]362        }
[11071]363        return nullptr;
[2072]364    }
365
[2171]366    void Gametype::assignDefaultPawnsIfNeeded()
[2072]367    {
[11071]368        for (auto& mapEntry : this->players_)
[2072]369        {
[11071]370            if (!mapEntry.first->getControllableEntity())
[2072]371            {
[11071]372                mapEntry.second.state_ = PlayerState::Dead;
[2662]373
[11071]374                if (!mapEntry.first->isReadyToSpawn() || !this->gtinfo_->hasStarted())
[2072]375                {
[11071]376                    this->spawnPlayerAsDefaultPawn(mapEntry.first);
377                    mapEntry.second.state_ = PlayerState::Dead;
[2072]378                }
379            }
380        }
381    }
382
383    void Gametype::checkStart()
384    {
[8706]385        if (!this->gtinfo_->hasStarted())
[2072]386        {
[8706]387            if (this->gtinfo_->isStartCountdownRunning())
[2072]388            {
[8706]389                if (this->gtinfo_->getStartCountdown() <= 0.0f)
[2072]390                {
[8706]391                    this->gtinfo_->stopStartCountdown();
[9016]392                    this->gtinfo_->setStartCountdown(0.0f);
[2072]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;
[2662]405                    bool hashumanplayers = false;
[11071]406                    for (const auto& mapEntry : this->players_)
[2072]407                    {
[11071]408                        if (!mapEntry.first->isReadyToSpawn())
[2072]409                            allplayersready = false;
[11071]410                        if (mapEntry.first->isHumanPlayer())
[2662]411                            hashumanplayers = true;
[2072]412                    }
[9260]413
[2662]414                    if (allplayersready && hashumanplayers)
[2072]415                    {
[8079]416                        // If in developer's mode, there is no start countdown.
[10624]417                        if(Core::getInstance().getConfig()->inDevMode())
[8706]418                            this->start();
[8079]419                        else
[9261]420                        {
[8706]421                            this->gtinfo_->setStartCountdown(this->initialStartCountdown_);
[9261]422                            this->gtinfo_->startStartCountdown();
423                        }
[2072]424                    }
425                }
426            }
427        }
428    }
429
430    void Gametype::spawnPlayersIfRequested()
431    {
[11071]432        for (const auto& mapEntry : this->players_)
[8706]433        {
[11071]434            if (mapEntry.first->isReadyToSpawn() || this->bForceSpawn_)
435                this->spawnPlayer(mapEntry.first);
[8706]436        }
[2072]437    }
438
439    void Gametype::spawnDeadPlayersIfRequested()
440    {
[11071]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);
[2072]445    }
446
447    void Gametype::spawnPlayer(PlayerInfo* player)
448    {
449        SpawnPoint* spawnpoint = this->getBestSpawnPoint(player);
450        if (spawnpoint)
451        {
[2826]452            this->playerPreSpawn(player);
[2072]453            player->startControl(spawnpoint->spawn());
[2662]454            this->players_[player].state_ = PlayerState::Alive;
[8706]455
456            if(player->isHumanPlayer())
457                this->gtinfo_->playerSpawned(player);
[9016]458
[2826]459            this->playerPostSpawn(player);
[2072]460        }
461        else
462        {
[8858]463            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
[2072]464            abort();
465        }
466    }
[2662]467
[3033]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
[9667]474            ControllableEntity* entity = this->defaultControllableEntity_.fabricate(spawn->getContext());
[3033]475            spawn->spawn(entity);
476            player->startControl(entity);
477        }
478        else
479        {
[8858]480            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
[3033]481            abort();
482        }
483    }
484
[2662]485    void Gametype::addBots(unsigned int amount)
486    {
487        for (unsigned int i = 0; i < amount; ++i)
[9667]488            this->botclass_.fabricate(this->getContext());
[2662]489    }
490
491    void Gametype::killBots(unsigned int amount)
492    {
493        unsigned int i = 0;
[11071]494        ObjectList<Bot> list;
495        for (ObjectList<Bot>::iterator it = list.begin(); (it != list.end()) && ((amount == 0) || (i < amount)); )
[2662]496        {
497            if (it->getGametype() == this)
498            {
[5929]499                (it++)->destroy();
[2662]500                ++i;
501            }
[5929]502            else
503                ++it;
[2662]504        }
505    }
[3033]506
507    void Gametype::addTime(float t)
[3038]508    {
[3033]509        if (this->timeLimit_ == 0)
510          this->time_ -= t;
511        else
512          this->time_ += t;
513    }
514
515    void Gametype::removeTime(float t)
[3038]516    {
[3033]517        if (this->timeLimit_ == 0)
518          this->time_ += t;
519        else
520          this->time_ -= t;
521    }
522
523    void Gametype::resetTimer()
[3038]524    {
[3033]525        this->resetTimer(timeLimit_);
526    }
527
528    void Gametype::resetTimer(float t)
[3038]529    {
[3033]530        this->timeLimit_ = t;
531        this->time_ = t;
532    }
[9969]533
[9977]534    void Gametype::showMenu()
535    {
[9984]536        GSLevel::startMainMenu();
[9977]537    }
[10281]538
539    GSLevelMementoState* Gametype::exportMementoState()
540    {
[11071]541        for (const auto& mapEntry : this->players_)
[10281]542        {
[11071]543            if (mapEntry.first->isHumanPlayer() && mapEntry.first->getControllableEntity() && mapEntry.first->getControllableEntity()->getCamera())
[10281]544            {
[11071]545                Camera* camera = mapEntry.first->getControllableEntity()->getCamera();
[10281]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
[11071]555        return nullptr;
[10281]556    }
557
558    void Gametype::importMementoState(const std::vector<GSLevelMementoState*>& states)
559    {
560        // find correct memento state
[11071]561        GametypeMementoState* state = nullptr;
562        for (GSLevelMementoState* temp : states)
[10281]563        {
[11071]564            state = dynamic_cast<GametypeMementoState*>(temp);
[10281]565            if (state)
566                break;
567        }
568
569        if (!state)
570            return;
571
572        // find correct scene
[11071]573        Scene* scene = nullptr;
574        for (Scene* someScene : ObjectList<Scene>())
[10281]575        {
[11071]576            if (someScene->getName() == state->sceneName_)
[10281]577            {
[11071]578                scene = someScene;
[10281]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
[11071]590        for (const auto& mapEntry : this->players_)
[10281]591        {
[11071]592            if (mapEntry.first->isHumanPlayer())
[10281]593            {
594                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(scene->getContext());
595                entity->setPosition(state->cameraPosition_);
596                entity->setOrientation(state->cameraOrientation_);
[11071]597                mapEntry.first->startControl(entity);
[10281]598                break;
599            }
600        }
601    }
[2072]602}
Note: See TracBrowser for help on using the repository browser.