Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/util/multiplayer_team_deathmatch.cc @ 8980

Last change on this file since 8980 was 8802, checked in by patrick, 18 years ago

merged the network branche back to trunk

File size: 19.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Patrick Boenzli
13*/
14
15#define DEBUG_MODULE_GAME_RULES
16
17#include <map>
18
19#include "multiplayer_team_deathmatch.h"
20
21#include "util/loading/load_param.h"
22#include "util/loading/factory.h"
23
24#include "render2D/image_plane.h"
25#include "state.h"
26#include "class_list.h"
27
28#include "player.h"
29#include "playable.h"
30#include "space_ships/space_ship.h"
31
32
33#include "shared_network_data.h"
34#include "terrain.h"
35#include "class_list.h"
36#include "space_ships/space_ship.h"
37
38#include "network_game_manager.h"
39
40#include "event_handler.h"
41
42#include "glgui.h"
43
44#include "story_entity.h"
45
46#include "shell_command.h"
47
48#include "spawning_point.h"
49
50
51using namespace std;
52
53
54CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
55
56
57/**
58 * constructor
59 */
60MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
61  : NetworkGameRules(root)
62{
63  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
64
65  this->bLocalPlayerDead = false;
66  this->deathTimeout = 10.0f;     // 5 seconds
67  this->timeout = 0.0f;
68  this->numTeams = 2;
69  this->currentGameState = GAMESTATE_PRE_GAME;
70  this->gameStateTimer = 10.0f;
71  this->bShowTeamChange = false;
72
73  this->box = NULL;
74  this->table = NULL;
75  this->statsBox = NULL;
76
77  this->localPlayer = State::getPlayer();
78
79  if( root != NULL)
80    this->loadParams(root);
81
82  subscribeEvent( ES_GAME, SDLK_o );
83  subscribeEvent( ES_GAME, SDLK_TAB );
84  subscribeEvent( ES_GAME, SDLK_F1 );
85  subscribeEvent( ES_MENU, SDLK_F1 );
86  subscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
87 
88  this->notifier = new OrxGui::GLGuiNotifier();
89  this->notifier->show();
90  this->notifier->setAbsCoor2D(5, 30);
91  this->notifier->setFadeAge( 6.0 );
92  this->notifier->setHideAge( 8.0 );
93  this->input = new OrxGui::GLGuiInputLine();
94  this->input->setAbsCoor2D(180, 5);
95  this->input->connect(SIGNAL(input, enterPushed), this, SLOT(MultiplayerTeamDeathmatch, onInputEnter));
96}
97
98/**
99 * decontsructor
100 */
101MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
102{
103  unsubscribeEvent( ES_GAME, SDLK_o );
104  unsubscribeEvent( ES_GAME, SDLK_TAB );
105  unsubscribeEvent( ES_GAME, SDLK_F1 );
106  unsubscribeEvent( ES_MENU, SDLK_F1 );
107  unsubscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
108 
109  if ( this->notifier )
110  {
111    delete this->notifier;
112    this->notifier = NULL;
113  }
114
115  if ( this->input )
116  {
117    delete this->input;
118    this->input = NULL;
119  }
120}
121
122
123
124void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
125{
126  GameRules::loadParams(root) ;
127
128  LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout)
129      .describe("sets the time in seconds a player has to wait for respawn");
130
131  LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills)
132      .describe("sets the maximal kills for winning condition");
133
134  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
135      .describe("sets number of teams");
136
137}
138
139
140/**
141 * time tick
142 * @param dt time
143 */
144void MultiplayerTeamDeathmatch::tick(float dt)
145{
146  tickStatsTable();
147  //on client side hostId is -1 until hanshake finished
148  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
149    return;
150
151  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
152  {
153    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
154         && box == NULL
155         &&  (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM
156         || bShowTeamChange )
157
158       )
159    {
160      EventHandler::getInstance()->pushState( ES_MENU );
161
162      OrxGui::GLGuiHandler::getInstance()->activateCursor();
163
164      box = new OrxGui::GLGuiBox();
165      box->setAbsCoor2D( 300, 100 );
166
167      OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
168      box->pack( buttonSpectator );
169      buttonSpectator->connect(SIGNAL(buttonSpectator, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonSpectator));
170
171      OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
172      box->pack( buttonRandom );
173      buttonRandom->connect(SIGNAL(buttonRandom, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonRandom));
174
175      OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
176      box->pack( buttonTeam0 );
177      buttonTeam0->connect(SIGNAL(buttonTeam0, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam0));
178
179      OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
180      box->pack( buttonTeam1 );
181      buttonTeam1->connect(SIGNAL(buttonTeam1, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam1));
182
183      if ( bShowTeamChange )
184      {
185        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
186        box->pack( buttonCancel );
187        buttonCancel->connect(SIGNAL(buttonCancel, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonCancel));
188      }
189
190      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
191      box->pack( buttonExit );
192      buttonExit->connect(SIGNAL(buttonExit, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonExit));
193
194      box->showAll();
195    }
196  }
197
198  if ( box != NULL
199       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
200       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() != TEAM_NOTEAM
201       && !bShowTeamChange
202     )
203  {
204    delete box;
205    box = NULL;
206
207    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
208
209    EventHandler::getInstance()->popState();
210  }
211
212  if ( box != NULL )
213  {
214    OrxGui::GLGuiHandler::getInstance()->tick( dt );
215  }
216
217  assignPlayable();
218
219  if ( !SharedNetworkData::getInstance()->isGameServer() )
220    return;
221   
222  //handle kills
223  for ( std::vector<Kill>::iterator it = this->killList.begin(); it != this->killList.end();  )
224  {
225    std::vector<Kill>::iterator delit = it;
226   
227    onKill( it->getKiller()->getOwner(), it->getVictim()->getOwner() );
228   
229    it++;
230    killList.erase( delit );
231  }
232 
233  gameStateTimer -= dt;
234  //PRINTF(0)("TICK %f\n", gameStateTimer);
235
236  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
237    nextGameState();
238
239  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
240
241  if ( currentGameState == GAMESTATE_GAME )
242  {
243    handleTeamChanges();
244  }
245
246  this->calculateTeamScore();
247
248  this->checkGameRules();
249
250  // is the local player dead and inactive
251  if( unlikely(this->bLocalPlayerDead))
252  {
253    this->timeout += dt;
254    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
255    // long enough dead?
256    if( this->timeout >= this->deathTimeout)
257    {
258      this->timeout = 0.0f;
259      // respawn
260      PRINTF(0)("RESPAWN\n");
261      (State::getPlayer())->getPlayable()->respawn();
262    }
263  }
264}
265
266
267/**
268 * draws the stuff
269 */
270void MultiplayerTeamDeathmatch::draw()
271{
272  if( unlikely( this->bLocalPlayerDead))
273  {
274
275  }
276}
277
278
279/**
280 * check the game rules for consistency
281 */
282void MultiplayerTeamDeathmatch::checkGameRules()
283{
284  if ( !SharedNetworkData::getInstance()->isGameServer() )
285    return;
286
287  // check for max killing count
288  for ( int i = 0; i<numTeams; i++ )
289  {
290    if ( teamScore[i] >= maxKills )
291    {
292      nextGameState();
293    }
294  }
295}
296
297/**
298 * find group for new player
299 * @return group id
300 */
301int MultiplayerTeamDeathmatch::getTeamForNewUser()
302{
303  return TEAM_NOTEAM;
304}
305
306ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
307{
308  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
309    return CL_SPECTATOR;
310
311  if ( team == 0 || team == 1 )
312    return CL_SPACE_SHIP;
313
314  assert( false );
315}
316
317std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
318{
319  if ( team == 0 )
320    return "models/ships/reap_#.obj";
321  else if ( team == 1 )
322    return "models/ships/fighter.obj";
323  else
324    return "";
325}
326
327/**
328 * calculate team score
329 */
330void MultiplayerTeamDeathmatch::calculateTeamScore( )
331{
332  teamScore.clear();
333
334  for ( int i = 0; i<numTeams; i++ )
335    teamScore[i] = 0;
336
337
338  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
339
340  if ( !list )
341    return;
342
343  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
344  {
345    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
346
347    if ( stats.getTeamId() >= 0 )
348    {
349      teamScore[stats.getTeamId()] += stats.getScore();
350    }
351  }
352}
353
354/**
355 * get team for player who choose to join random team
356 * @return smallest team
357 */
358int MultiplayerTeamDeathmatch::getRandomTeam( )
359{
360  std::map<int,int> playersInTeam;
361
362  for ( int i = 0; i<numTeams; i++ )
363    playersInTeam[i] = 0;
364
365  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
366
367  if ( !list )
368    return 0;
369
370  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
371  {
372    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
373
374    if ( stats.getTeamId() >= 0 )
375    {
376      playersInTeam[stats.getTeamId()]++;
377    }
378  }
379
380
381  int minPlayers = 0xFFFF;
382  int minTeam = -1;
383
384  for ( int i = 0; i<numTeams; i++ )
385  {
386    if ( playersInTeam[i] < minPlayers )
387    {
388      minTeam = i;
389      minPlayers = playersInTeam[i];
390    }
391  }
392
393  assert( minTeam != -1 );
394
395  return minTeam;
396}
397
398void MultiplayerTeamDeathmatch::nextGameState( )
399{
400  if ( currentGameState == GAMESTATE_PRE_GAME )
401  {
402    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
403
404    return;
405  }
406
407  if ( currentGameState == GAMESTATE_GAME )
408  {
409    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
410
411    return;
412  }
413
414  if ( currentGameState == GAMESTATE_POST_GAME )
415  {
416    State::getCurrentStoryEntity()->stop();
417    this->bShowTeamChange = false;
418
419    return;
420  }
421}
422
423void MultiplayerTeamDeathmatch::handleTeamChanges( )
424{
425  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
426
427  if ( !list )
428    return;
429
430  //first server players with choices
431  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
432  {
433    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
434
435    if ( stats.getTeamId() != stats.getPreferedTeamId() )
436    {
437      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
438      {
439        teamChange( stats.getUserId() );
440      }
441    }
442  }
443
444  //now serve player who want join a random team
445  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
446  {
447    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
448
449    if ( stats.getTeamId() != stats.getPreferedTeamId() )
450    {
451      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
452      {
453        stats.setPreferedTeamId( getRandomTeam() );
454        teamChange( stats.getUserId() );
455      }
456    }
457  }
458}
459
460void MultiplayerTeamDeathmatch::teamChange( int userId )
461{
462  assert( PlayerStats::getStats( userId ) );
463  PlayerStats & stats = *(PlayerStats::getStats( userId ));
464
465  stats.setTeamId( stats.getPreferedTeamId() );
466
467  Playable * oldPlayable = stats.getPlayable();
468
469
470  ClassID playableClassId = getPlayableClassId( userId, stats.getPreferedTeamId() );
471  std::string playableModel = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
472
473  BaseObject * bo = Factory::fabricate( playableClassId );
474
475  assert( bo != NULL );
476  assert( bo->isA( CL_PLAYABLE ) );
477
478  Playable & playable = *(dynamic_cast<Playable*>(bo));
479
480  playable.loadModel( playableModel );
481  playable.setOwner( userId );
482  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
483  playable.setSynchronized( true );
484
485  stats.setTeamId( stats.getPreferedTeamId() );
486  stats.setPlayableClassId( playableClassId );
487  stats.setPlayableUniqueId( playable.getUniqueID() );
488  stats.setModelFileName( playableModel );
489
490  if ( oldPlayable )
491  {
492    //if ( userId == SharedNetworkData::getInstance()->getHostID() )
493    //  State::getPlayer()->setPlayable( NULL );
494    delete oldPlayable;
495  }
496}
497
498void MultiplayerTeamDeathmatch::onButtonExit( )
499{
500  State::getCurrentStoryEntity()->stop();
501  this->bShowTeamChange = false;
502}
503
504void MultiplayerTeamDeathmatch::onButtonRandom( )
505{
506  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
507  this->bShowTeamChange = false;
508}
509
510void MultiplayerTeamDeathmatch::onButtonTeam0( )
511{
512  NetworkGameManager::getInstance()->prefereTeam( 0 );
513  this->bShowTeamChange = false;
514}
515
516void MultiplayerTeamDeathmatch::onButtonTeam1( )
517{
518  NetworkGameManager::getInstance()->prefereTeam( 1 );
519  this->bShowTeamChange = false;
520}
521
522void MultiplayerTeamDeathmatch::onButtonSpectator( )
523{
524  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
525  this->bShowTeamChange = false;
526}
527
528void MultiplayerTeamDeathmatch::assignPlayable( )
529{
530  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
531    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
532}
533
534  /**
535   * function that processes events from the handler
536   * @param event: the event
537   * @todo replace SDLK_o with something from KeyMapper
538   */
539void MultiplayerTeamDeathmatch::process( const Event & event )
540{
541  if ( event.type == SDLK_o )
542  {
543    if ( event.bPressed )
544      this->bShowTeamChange = true;
545  } else if ( event.type == SDLK_F1 )
546  {
547    if ( !this->statsBox && event.bPressed )
548    {
549      PRINTF(0)("show stats\n");
550      this->showStats();
551    }
552    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed && this->table->rowCount() != 0 && this->table->columnCount() != 0 )
553    {
554      PRINTF(0)("hide stats\n");
555      this->hideStats();
556    }
557  }
558  else if ( event.type == SDLK_TAB )
559  {
560    if ( !event.bPressed )
561    {
562      EventHandler::getInstance()->pushState( ES_MENU );
563      OrxGui::GLGuiHandler::getInstance()->activateCursor();
564      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
565      input->show();
566      input->giveMouseFocus();
567      input->setText("say ");
568    }
569  }
570  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
571  {
572    this->hideStats();
573  }
574}
575
576void MultiplayerTeamDeathmatch::onButtonCancel( )
577{
578  this->bShowTeamChange = false;
579}
580
581
582
583/**
584 * this method is called by NetworkGameManger when he recieved a chat message
585 * @param userId senders user id
586 * @param message message string
587 * @param messageType some int
588 */
589void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
590{
591  std::string name = "unknown";
592
593  if ( PlayerStats::getStats( userId ) )
594  {
595    name = PlayerStats::getStats( userId )->getNickName();
596  }
597
598  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
599  notifier->pushNotifyMessage(name + ": " + message);
600}
601
602void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
603{
604  EventHandler::getInstance()->popState();
605  input->breakMouseFocus();
606  input->hide();
607  input->setText("");
608
609  std::string command = text;
610
611  //HACK insert " in say commands so user doesn't have to type them
612  if ( command.length() >= 4 && command[0] == 's' && command[1] == 'a' && command[2] == 'y' && command[3] == ' ' )
613  {
614    command.insert( 4, "\"" );
615    command = command + "\"";
616  }
617
618  OrxShell::ShellCommand::execute( command );
619}
620
621/**
622 * show table with frags
623 */
624void MultiplayerTeamDeathmatch::showStats( )
625{
626  EventHandler::getInstance()->pushState( ES_MENU );
627  statsBox = new OrxGui::GLGuiBox();
628  statsBox->setAbsCoor2D( 300, 100 );
629 
630  this->table = new OrxGui::GLGuiTable(0,0);
631
632  statsBox->pack( this->table );
633
634  statsBox->showAll();
635}
636
637/**
638 * hide table with frags
639 */
640void MultiplayerTeamDeathmatch::hideStats( )
641{
642    if ( statsBox )
643    {
644      delete statsBox;
645      statsBox = NULL;
646    }
647     
648    EventHandler::getInstance()->popState();
649}
650
651/**
652 * fill stats table with values
653 */
654void MultiplayerTeamDeathmatch::tickStatsTable( )
655{
656  if ( !this->statsBox )
657    return;
658
659  std::vector<std::string> headers;
660  headers.push_back("Red Team");
661  headers.push_back("");
662  headers.push_back("");
663  headers.push_back("Blue Team");
664  headers.push_back("");
665  this->table->setHeader(headers);
666 
667  std::map<int,std::string> fragsTeam0;
668  std::map<int,std::string> fragsTeam1;
669 
670  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
671 
672  if ( !list )
673    return;
674 
675  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
676  {
677    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
678   
679    if ( stats.getTeamId() == 0 || stats.getTeamId() == 1 )
680    {
681      if ( stats.getTeamId() == 0 )
682        fragsTeam0[stats.getScore()] = stats.getNickName();
683      else
684        fragsTeam1[stats.getScore()] = stats.getNickName();
685    }
686  }
687 
688  char st[10];
689  int i = 0;
690 
691 
692  i = 2;
693  for ( std::map<int,std::string>::const_iterator it = fragsTeam0.begin(); it != fragsTeam0.end(); it++ )
694  {
695    this->table->setEntry( 0, i, it->second );
696    snprintf( st, 10, "%d", it->first );
697    this->table->setEntry( 1, i, st );
698    this->table->setEntry( 2, i, "" );
699    i++;
700  }
701 
702  i = 2;
703  for ( std::map<int,std::string>::const_iterator it = fragsTeam1.begin(); it != fragsTeam1.end(); it++ )
704  {
705    this->table->setEntry( 3, i, it->second );
706    snprintf( st, 10, "%d", it->first );
707    this->table->setEntry( 4, i, st );
708    i++;
709  }
710}
711
712/**
713 * this function is called when a player kills another one or himself
714 * @param killedUserId
715 * @param userId
716 */
717void MultiplayerTeamDeathmatch::onKill( int killedUserId, int userId )
718{
719  assert( PlayerStats::getStats( killedUserId ) );
720  assert( PlayerStats::getStats( userId ) );
721 
722  PlayerStats & killedStats = *PlayerStats::getStats( killedUserId );
723  PlayerStats & stats = *PlayerStats::getStats( userId );
724 
725  if ( killedUserId != userId )
726    stats.setScore( stats.getScore() + 1 );
727  else
728    stats.setScore( stats.getScore() - 1 );
729 
730  if ( killedUserId == SharedNetworkData::getInstance()->getHostID() )
731  {
732    this->bLocalPlayerDead = true;
733    this->showStats();
734  }
735 
736  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
737 
738  assert( list );
739 
740  std::vector<SpawningPoint*> spList;
741 
742  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
743  {
744    SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
745   
746    if ( sp->getTeamId() < 0 || sp->getTeamId() == killedStats.getTeamId() )
747      spList.push_back( sp );
748  }
749 
750  int n = spList.size()*rand();
751 
752  spList[n]->pushEntity( killedStats.getPlayable(), 3 );
753}
754
755/**
756 * this function is called on player respawn
757 * @param userId
758 */
759void MultiplayerTeamDeathmatch::onRespawn( int userId )
760{
761  if ( userId == SharedNetworkData::getInstance()->getHostID() )
762  {
763    this->bLocalPlayerDead = false;
764    this->hideStats();
765  }
766}
767
768/**
769 * this function is called on player respawn
770 * @param we
771 */
772void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
773{
774  onRespawn( we->getOwner() );
775}
776
Note: See TracBrowser for help on using the repository browser.