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, 5 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
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(SmartPtr<Gametype>(this, false));
64
65        this->gtinfo_ = new GametypeInfo(context);
66        this->gtinfo_->setGametype(this);
67
68        this->defaultControllableEntity_ = Class(Spectator);
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        // load the corresponding score board
84        if (GameMode::showsGraphics() && !this->scoreboardTemplate_.empty())
85        {
86            this->scoreboard_ = new OverlayGroup(context);
87            this->scoreboard_->addTemplate(this->scoreboardTemplate_);
88            this->scoreboard_->setGametype(this);
89        }
90        else
91            this->scoreboard_ = 0;
92
93        ModifyConsoleCommand(__CC_addBots_name).setObject(this);
94        ModifyConsoleCommand(__CC_killBots_name).setObject(this);
95    }
96
97    Gametype::~Gametype()
98    {
99        if (this->isInitialized())
100        {
101            if (this->gtinfo_)
102                this->gtinfo_->destroy();
103
104            ModifyConsoleCommand(__CC_addBots_name).setObject(NULL);
105            ModifyConsoleCommand(__CC_killBots_name).setObject(NULL);
106        }
107    }
108
109    void Gametype::setConfigValues()
110    {
111        SetConfigValue(initialStartCountdown_, 3.0f);
112        SetConfigValue(bAutoStart_, false);
113        SetConfigValue(bForceSpawn_, false);
114        SetConfigValue(bAutoEnd_, true);
115        SetConfigValue(numberOfBots_, 0);
116        SetConfigValue(scoreboardTemplate_, "defaultScoreboard");
117    }
118
119    void Gametype::tick(float dt)
120    {
121        SUPER(Gametype, tick, dt);
122
123        //count timer
124        if (timerIsActive_)
125        {
126            if (this->timeLimit_ == 0)
127                this->time_ += dt;
128            else
129                this->time_ -= dt;
130        }
131
132        if (this->gtinfo_->isStartCountdownRunning() && !this->gtinfo_->hasStarted())
133            this->gtinfo_->countdownStartCountdown(dt);
134
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            }
143
144            this->checkStart();
145        }
146        else if (!this->gtinfo_->hasEnded())
147            this->spawnDeadPlayersIfRequested();
148
149        this->assignDefaultPawnsIfNeeded();
150    }
151
152    void Gametype::start()
153    {
154        this->addBots(this->numberOfBots_);
155        this->gtinfo_->start();
156        this->spawnPlayersIfRequested();
157    }
158
159    void Gametype::end()
160    {
161        this->gtinfo_->end();
162        if (this->bAutoEnd_)
163        {
164            this->showMenuTimer_.setTimer(3.0f, true, createExecutor(createFunctor(&Gametype::showMenu, this)));
165        }
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();
172
173                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(oldentity->getContext());
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        }
189    }
190
191    void Gametype::playerEntered(PlayerInfo* player)
192    {
193        this->players_[player].state_ = PlayerState::Joined;
194        this->gtinfo_->playerEntered(player);
195    }
196
197    bool Gametype::playerLeft(PlayerInfo* player)
198    {
199        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
200        if (it != this->players_.end())
201        {
202            this->players_.erase(it);
203            return true;
204        }
205        return false;
206    }
207
208    void Gametype::playerSwitched(PlayerInfo* player, Gametype* newgametype)
209    {
210    }
211
212    void Gametype::playerSwitchedBack(PlayerInfo* player, Gametype* oldgametype)
213    {
214    }
215
216    bool Gametype::playerChangedName(PlayerInfo* player)
217    {
218        if (this->players_.find(player) != this->players_.end())
219        {
220            if (player->getName() != player->getOldName())
221            {
222                return true;
223            }
224        }
225        return false;
226    }
227
228    void Gametype::pawnPreSpawn(Pawn* pawn)
229    {
230    }
231
232    void Gametype::pawnPostSpawn(Pawn* pawn)
233    {
234    }
235
236    void Gametype::playerPreSpawn(PlayerInfo* player)
237    {
238    }
239
240    void Gametype::playerPostSpawn(PlayerInfo* player)
241    {
242    }
243
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    {
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
278                if (killer && killer->getPlayer())
279                {
280                    std::map<PlayerInfo*, Player>::iterator it = this->players_.find(killer->getPlayer());
281                    if (it != this->players_.end())
282                    {
283                        it->second.frags_++;
284
285                        if (killer->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
286                            this->gtinfo_->sendKillMessage("You killed " + victim->getPlayer()->getName(), killer->getPlayer()->getClientID());
287                        if (victim->getPlayer()->getClientID() != NETWORK_PEER_ID_UNKNOWN)
288                            this->gtinfo_->sendDeathMessage("You were killed by " + killer->getPlayer()->getName(), victim->getPlayer()->getClientID());
289                    }
290                }
291
292                if(victim->getPlayer()->isHumanPlayer())
293                    this->gtinfo_->pawnKilled(victim->getPlayer());
294
295                ControllableEntity* entity = this->defaultControllableEntity_.fabricate(victim->getContext());
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
309                orxout(internal_warning) << "Killed Pawn was not in the playerlist" << endl;
310        }
311    }
312
313    void Gametype::playerScored(PlayerInfo* player, int score)
314    {
315        std::map<PlayerInfo*, Player>::iterator it = this->players_.find(player);
316        if (it != this->players_.end())
317            it->second.frags_ += score;
318    }
319
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
329    SpawnPoint* Gametype::getBestSpawnPoint(PlayerInfo* player) const
330    {
331        // If there is at least one SpawnPoint.
332        if (this->spawnpoints_.size() > 0)
333        {
334            // Fallback spawn point if there is no active one, choose a random one.
335            SpawnPoint* fallbackSpawnPoint = NULL;
336            unsigned int randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(this->spawnpoints_.size())));
337            unsigned int index = 0;
338            std::vector<SpawnPoint*> activeSpawnPoints;
339            for (std::set<SpawnPoint*>::const_iterator it = this->spawnpoints_.begin(); it != this->spawnpoints_.end(); ++it)
340            {
341                if (index == randomspawn)
342                    fallbackSpawnPoint = (*it);
343
344                if (*it != NULL && (*it)->isActive())
345                    activeSpawnPoints.push_back(*it);
346
347                ++index;
348            }
349
350            if(activeSpawnPoints.size() > 0)
351            {
352                randomspawn = static_cast<unsigned int>(rnd(static_cast<float>(activeSpawnPoints.size())));
353                return activeSpawnPoints[randomspawn];
354            }
355
356            orxout(internal_warning) << "Fallback SpawnPoint was used because there were no active SpawnPoints." << endl;
357            return fallbackSpawnPoint;
358        }
359        return 0;
360    }
361
362    void Gametype::assignDefaultPawnsIfNeeded()
363    {
364        for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
365        {
366            if (!it->first->getControllableEntity())
367            {
368                it->second.state_ = PlayerState::Dead;
369
370                if (!it->first->isReadyToSpawn() || !this->gtinfo_->hasStarted())
371                {
372                    this->spawnPlayerAsDefaultPawn(it->first);
373                    it->second.state_ = PlayerState::Dead;
374                }
375            }
376        }
377    }
378
379    void Gametype::checkStart()
380    {
381        if (!this->gtinfo_->hasStarted())
382        {
383            if (this->gtinfo_->isStartCountdownRunning())
384            {
385                if (this->gtinfo_->getStartCountdown() <= 0.0f)
386                {
387                    this->gtinfo_->stopStartCountdown();
388                    this->gtinfo_->setStartCountdown(0.0f);
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;
401                    bool hashumanplayers = false;
402                    for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
403                    {
404                        if (!it->first->isReadyToSpawn())
405                            allplayersready = false;
406                        if (it->first->isHumanPlayer())
407                            hashumanplayers = true;
408                    }
409
410                    if (allplayersready && hashumanplayers)
411                    {
412                        // If in developer's mode, there is no start countdown.
413                        if(Core::getInstance().getConfig()->inDevMode())
414                            this->start();
415                        else
416                        {
417                            this->gtinfo_->setStartCountdown(this->initialStartCountdown_);
418                            this->gtinfo_->startStartCountdown();
419                        }
420                    }
421                }
422            }
423        }
424    }
425
426    void Gametype::spawnPlayersIfRequested()
427    {
428        for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
429        {
430            if (it->first->isReadyToSpawn() || this->bForceSpawn_)
431                this->spawnPlayer(it->first);
432        }
433    }
434
435    void Gametype::spawnDeadPlayersIfRequested()
436    {
437        for (std::map<PlayerInfo*, Player>::iterator it = this->players_.begin(); it != this->players_.end(); ++it)
438            if (it->second.state_ == PlayerState::Dead)
439                if (it->first->isReadyToSpawn() || this->bForceSpawn_)
440                    this->spawnPlayer(it->first);
441    }
442
443    void Gametype::spawnPlayer(PlayerInfo* player)
444    {
445        SpawnPoint* spawnpoint = this->getBestSpawnPoint(player);
446        if (spawnpoint)
447        {
448            this->playerPreSpawn(player);
449            player->startControl(spawnpoint->spawn());
450            this->players_[player].state_ = PlayerState::Alive;
451
452            if(player->isHumanPlayer())
453                this->gtinfo_->playerSpawned(player);
454
455            this->playerPostSpawn(player);
456        }
457        else
458        {
459            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
460            abort();
461        }
462    }
463
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
470            ControllableEntity* entity = this->defaultControllableEntity_.fabricate(spawn->getContext());
471            spawn->spawn(entity);
472            player->startControl(entity);
473        }
474        else
475        {
476            orxout(user_error) << "No SpawnPoints in current Gametype" << endl;
477            abort();
478        }
479    }
480
481    void Gametype::addBots(unsigned int amount)
482    {
483        for (unsigned int i = 0; i < amount; ++i)
484            this->botclass_.fabricate(this->getContext());
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            {
494                (it++)->destroy();
495                ++i;
496            }
497            else
498                ++it;
499        }
500    }
501
502    void Gametype::addTime(float t)
503    {
504        if (this->timeLimit_ == 0)
505          this->time_ -= t;
506        else
507          this->time_ += t;
508    }
509
510    void Gametype::removeTime(float t)
511    {
512        if (this->timeLimit_ == 0)
513          this->time_ += t;
514        else
515          this->time_ -= t;
516    }
517
518    void Gametype::resetTimer()
519    {
520        this->resetTimer(timeLimit_);
521    }
522
523    void Gametype::resetTimer(float t)
524    {
525        this->timeLimit_ = t;
526        this->time_ = t;
527    }
528
529    void Gametype::showMenu()
530    {
531        GSLevel::startMainMenu();
532    }
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    }
597}
Note: See TracBrowser for help on using the repository browser.