Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/orxonox/gametypes/Gametype.cc @ 10554

Last change on this file since 10554 was 10554, checked in by landauf, 9 years ago

Gametype should store a WeakPtr to GametypeInfo to avoid circular reference if GametypeInfo references back to its Gametype

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