Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/proxy/src/util/multiplayer_team_deathmatch.cc @ 9567

Last change on this file since 9567 was 9565, checked in by patrick, 19 years ago

server team joining and gui showing fix

File size: 20.9 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
51
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 = 3.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, KeyMapper::PEV_FIRE1 );
86
87  this->input = new OrxGui::GLGuiInputLine();
88  this->input->setAbsCoor2D(180, 5);
89  this->input->enterPushed.connect(this, &MultiplayerTeamDeathmatch::onInputEnter);
90}
91
92/**
93 * decontsructor
94 */
95MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
96{
97  unsubscribeEvent( ES_GAME, SDLK_o );
98  unsubscribeEvent( ES_GAME, SDLK_TAB );
99  unsubscribeEvent( ES_GAME, SDLK_F1 );
100  unsubscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
101
102  if ( this->input )
103  {
104    delete this->input;
105    this->input = NULL;
106  }
107}
108
109
110
111void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
112{
113  GameRules::loadParams(root) ;
114
115  LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout)
116      .describe("sets the time in seconds a player has to wait for respawn");
117
118  LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills)
119      .describe("sets the maximal kills for winning condition");
120
121  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
122      .describe("sets number of teams");
123
124}
125
126
127/**
128 * time tick
129 * @param dt time
130 */
131void MultiplayerTeamDeathmatch::tick(float dt)
132{
133  tickStatsTable();
134  //on client side hostId is -1 until hanshake finished
135  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
136    return;
137
138  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
139  {
140    if( !PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ))
141      PRINTF(0)("got no stats\n");
142
143    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) &&
144         box == NULL &&
145         (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM || bShowTeamChange )
146
147       )
148    {
149      EventHandler::getInstance()->pushState( ES_MENU );
150
151      OrxGui::GLGuiHandler::getInstance()->activateCursor();
152
153      box = new OrxGui::GLGuiBox();
154      box->setAbsCoor2D( 300, 100 );
155
156      if( SharedNetworkData::getInstance()->isClient() ||  SharedNetworkData::getInstance()->isProxyServerActive())
157      {
158        OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
159        box->pack( buttonSpectator );
160        buttonSpectator->released.connect(this, &MultiplayerTeamDeathmatch::onButtonSpectator);
161
162        OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
163        box->pack( buttonRandom );
164        buttonRandom->released.connect(this, &MultiplayerTeamDeathmatch::onButtonRandom);
165
166        OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
167        box->pack( buttonTeam0 );
168        buttonTeam0->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam0);
169
170        OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
171        box->pack( buttonTeam1 );
172        buttonTeam1->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam1);
173      }
174      else
175      {
176        OrxGui::GLGuiText* text = new OrxGui::GLGuiText();
177        text->setText("Server Mode: not able to play at this node");
178        box->pack( text);
179      }
180
181
182      if ( bShowTeamChange )
183      {
184        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
185        box->pack( buttonCancel );
186        buttonCancel->released.connect(this, &MultiplayerTeamDeathmatch::onButtonCancel);
187      }
188
189      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
190      box->pack( buttonExit );
191      buttonExit->released.connect(this, &MultiplayerTeamDeathmatch::onButtonExit);
192
193      box->showAll();
194    }
195  }
196
197  if ( box != NULL
198       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
199       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() != TEAM_NOTEAM
200       && !bShowTeamChange
201     )
202  {
203    delete box;
204    box = NULL;
205
206    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
207
208    EventHandler::getInstance()->popState();
209  }
210
211  if ( box != NULL )
212  {
213    OrxGui::GLGuiHandler::getInstance()->tick( dt );
214  }
215
216  assignPlayable();
217
218  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
219    return;
220
221  //handle kills
222  while ( this->killList.begin() != this->killList.end() )
223  {
224    PRINTF(0)("KKKKKKKKIIIIIIIIILLLLLLLLLLLLL\n");
225    onKill( this->killList.begin()->getVictim(), this->killList.begin()->getKiller() );
226    this->killList.erase( this->killList.begin() );
227  }
228
229
230
231  gameStateTimer -= dt;
232  //PRINTF(0)("TICK %f\n", gameStateTimer);
233
234  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
235    nextGameState();
236
237  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
238
239  if ( currentGameState == GAMESTATE_GAME )
240  {
241    handleTeamChanges();
242  }
243
244  this->calculateTeamScore();
245
246  this->checkGameRules();
247
248  // is the local player dead and inactive
249  if( unlikely(this->bLocalPlayerDead))
250  {
251    this->timeout += dt;
252    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
253    // long enough dead?
254    if( this->timeout >= this->deathTimeout)
255    {
256      this->timeout = 0.0f;
257      // respawn
258      PRINTF(0)("RESPAWN\n");
259      (State::getPlayer())->getPlayable()->respawn();
260    }
261  }
262}
263
264
265/**
266 * draws the stuff
267 */
268void MultiplayerTeamDeathmatch::draw()
269{
270  if( unlikely( this->bLocalPlayerDead))
271  {
272
273  }
274}
275
276
277/**
278 * check the game rules for consistency
279 */
280void MultiplayerTeamDeathmatch::checkGameRules()
281{
282  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
283    return;
284
285  // check for max killing count
286  for ( int i = 0; i<numTeams; i++ )
287  {
288    if ( teamScore[i] >= maxKills )
289    {
290      nextGameState();
291    }
292  }
293}
294
295/**
296 * find group for new player
297 * @return group id
298 */
299int MultiplayerTeamDeathmatch::getTeamForNewUser()
300{
301  return TEAM_NOTEAM;
302}
303
304ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
305{
306  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
307    return CL_SPECTATOR;
308
309  if ( team == 0 || team == 1 )
310    return CL_TURBINE_HOVER;
311
312  assert( false );
313}
314
315std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
316{
317  if (classId == CL_TURBINE_HOVER)
318   return "models/ships/hoverglider_mainbody.obj";
319  if ( team == 0 )
320    return "models/creatures/doom_guy.md2";
321  else if ( team == 1 )
322    return "models/creatures/male.md2";
323  else
324    return "";
325}
326
327std::string MultiplayerTeamDeathmatch::getPlayableModelTextureFileName( int userId, int team, ClassID classId )
328{
329  if ( classId == CL_FPS_PLAYER )
330  {
331    if ( team == 0 )
332      return "maps/doom_guy.png";
333    else
334      return "maps/male_fiend.pcx";
335  }
336
337  return "";
338}
339
340float MultiplayerTeamDeathmatch::getPlayableScale( int userId, int team, ClassID classId )
341{
342  if ( classId == CL_FPS_PLAYER )
343  {
344    return 10.0f;
345  }
346
347  return 1.0f;
348}
349
350/**
351 * calculate team score
352 */
353void MultiplayerTeamDeathmatch::calculateTeamScore( )
354{
355  teamScore.clear();
356
357  for ( int i = 0; i<numTeams; i++ )
358    teamScore[i] = 0;
359
360
361  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
362
363  if ( !list )
364    return;
365
366  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
367  {
368    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
369
370    if ( stats.getTeamId() >= 0 )
371    {
372      teamScore[stats.getTeamId()] += stats.getScore();
373    }
374  }
375}
376
377/**
378 * get team for player who choose to join random team
379 * @return smallest team
380 */
381int MultiplayerTeamDeathmatch::getRandomTeam( )
382{
383  std::map<int,int> playersInTeam;
384
385  for ( int i = 0; i<numTeams; i++ )
386    playersInTeam[i] = 0;
387
388  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
389
390  if ( !list )
391    return 0;
392
393  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
394  {
395    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
396
397    if ( stats.getTeamId() >= 0 )
398    {
399      playersInTeam[stats.getTeamId()]++;
400    }
401  }
402
403
404  int minPlayers = 0xFFFF;
405  int minTeam = -1;
406
407  for ( int i = 0; i<numTeams; i++ )
408  {
409    if ( playersInTeam[i] < minPlayers )
410    {
411      minTeam = i;
412      minPlayers = playersInTeam[i];
413    }
414  }
415
416  assert( minTeam != -1 );
417
418  return minTeam;
419}
420
421void MultiplayerTeamDeathmatch::nextGameState( )
422{
423  if ( currentGameState == GAMESTATE_PRE_GAME )
424  {
425    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
426
427    return;
428  }
429
430  if ( currentGameState == GAMESTATE_GAME )
431  {
432    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
433
434    return;
435  }
436
437  if ( currentGameState == GAMESTATE_POST_GAME )
438  {
439    //State::getCurrentStoryEntity()->stop();
440    this->bShowTeamChange = false;
441
442    return;
443  }
444}
445
446void MultiplayerTeamDeathmatch::handleTeamChanges( )
447{
448  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
449
450  if ( !list )
451    return;
452
453  //first server players with choices
454  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
455  {
456    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
457
458    if ( stats.getTeamId() != stats.getPreferedTeamId() )
459    {
460      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
461      {
462        teamChange( stats.getUserId() );
463      }
464    }
465  }
466
467  //now serve player who want join a random team
468  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
469  {
470    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
471
472    if ( stats.getTeamId() != stats.getPreferedTeamId() )
473    {
474      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
475      {
476        stats.setPreferedTeamId( getRandomTeam() );
477        teamChange( stats.getUserId() );
478      }
479    }
480  }
481}
482
483void MultiplayerTeamDeathmatch::teamChange( int userId )
484{
485  assert( PlayerStats::getStats( userId ) );
486  PlayerStats & stats = *(PlayerStats::getStats( userId ));
487
488  stats.setTeamId( stats.getPreferedTeamId() );
489
490  Playable * oldPlayable = stats.getPlayable();
491
492
493  ClassID     playableClassId = getPlayableClassId( userId, stats.getPreferedTeamId() );
494  std::string playableModel = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
495  std::string playableTexture = getPlayableModelTextureFileName( userId, stats.getPreferedTeamId(), playableClassId );
496  float       playableScale = getPlayableScale( userId, stats.getPreferedTeamId(), playableClassId );
497
498  BaseObject * bo = Factory::fabricate( playableClassId );
499
500  assert( bo != NULL );
501  assert( bo->isA( CL_PLAYABLE ) );
502
503  Playable & playable = *(dynamic_cast<Playable*>(bo));
504
505  playable.loadMD2Texture( playableTexture );
506  playable.loadModel( playableModel, playableScale );
507  playable.setOwner( userId );
508  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
509  playable.setSynchronized( true );
510
511  stats.setPlayableClassId( playableClassId );
512  stats.setPlayableUniqueId( playable.getUniqueID() );
513  stats.setModelFileName( playableModel );
514  stats.setTeamId( stats.getPreferedTeamId() );
515
516  playable.setTeam(stats.getPreferedTeamId());
517
518
519  this->respawnPlayable( &playable, stats.getPreferedTeamId(), 0.0f );
520
521  if ( oldPlayable )
522  {
523    //if ( userId == SharedNetworkData::getInstance()->getHostID() )
524    //  State::getPlayer()->setPlayable( NULL );
525    delete oldPlayable;
526  }
527}
528
529void MultiplayerTeamDeathmatch::onButtonExit( )
530{
531  State::getCurrentStoryEntity()->stop();
532  this->bShowTeamChange = false;
533}
534
535void MultiplayerTeamDeathmatch::onButtonRandom( )
536{
537  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
538  this->bShowTeamChange = false;
539}
540
541void MultiplayerTeamDeathmatch::onButtonTeam0( )
542{
543  NetworkGameManager::getInstance()->prefereTeam( 0 );
544  this->bShowTeamChange = false;
545}
546
547void MultiplayerTeamDeathmatch::onButtonTeam1( )
548{
549  NetworkGameManager::getInstance()->prefereTeam( 1 );
550  this->bShowTeamChange = false;
551}
552
553void MultiplayerTeamDeathmatch::onButtonSpectator( )
554{
555  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
556  this->bShowTeamChange = false;
557}
558
559void MultiplayerTeamDeathmatch::assignPlayable( )
560{
561  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
562    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
563}
564
565  /**
566   * function that processes events from the handler
567   * @param event: the event
568   * @todo replace SDLK_o with something from KeyMapper
569   */
570void MultiplayerTeamDeathmatch::process( const Event & event )
571{
572  if ( event.type == SDLK_o )
573  {
574    if ( event.bPressed )
575      this->bShowTeamChange = true;
576  } else if ( event.type == SDLK_F1 )
577  {
578    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed )
579    {
580      PRINTF(0)("hide stats\n");
581      this->hideStats();
582    }
583    else if ( !this->statsBox && event.bPressed )
584    {
585      PRINTF(0)("show stats\n");
586      this->showStats();
587    }
588  }
589  else if ( event.type == SDLK_TAB )
590  {
591    if ( currentGameState == GAMESTATE_GAME && event.bPressed && !EventHandler::getInstance()->isPressed( SDLK_RALT ) && !EventHandler::getInstance()->isPressed( SDLK_LALT ) )
592    {
593      EventHandler::getInstance()->pushState( ES_MENU );
594      OrxGui::GLGuiHandler::getInstance()->activateCursor();
595      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
596      input->show();
597      input->giveMouseFocus();
598      input->setText("say ");
599    }
600  }
601  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
602  {
603    this->hideStats();
604  }
605}
606
607void MultiplayerTeamDeathmatch::onButtonCancel( )
608{
609  this->bShowTeamChange = false;
610}
611
612
613
614/**
615 * this method is called by NetworkGameManger when he recieved a chat message
616 * @param userId senders user id
617 * @param message message string
618 * @param messageType some int
619 */
620void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
621{
622  std::string name = "unknown";
623
624  if ( PlayerStats::getStats( userId ) )
625  {
626    name = PlayerStats::getStats( userId )->getNickName();
627  }
628
629  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
630  State::getPlayer()->hud().notifyUser(name + ": " + message);
631}
632
633void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
634{
635  EventHandler::getInstance()->popState();
636  input->breakMouseFocus();
637  input->hide();
638  input->setText("");
639
640  std::string command = text;
641
642  //HACK insert " in say commands so user doesn't have to type them
643  if ( command.length() >= 4 && command[0] == 's' && command[1] == 'a' && command[2] == 'y' && command[3] == ' ' )
644  {
645    command.insert( 4, "\"" );
646    command = command + "\"";
647  }
648
649  OrxShell::ShellCommand::execute( command );
650}
651
652/**
653 * show table with frags
654 */
655void MultiplayerTeamDeathmatch::showStats( )
656{
657  statsBox = new OrxGui::GLGuiBox();
658  statsBox->setAbsCoor2D( 100, 100 );
659
660  this->table = new OrxGui::GLGuiTable(10,5);
661
662  statsBox->pack( this->table );
663
664  statsBox->showAll();
665}
666
667/**
668 * hide table with frags
669 */
670void MultiplayerTeamDeathmatch::hideStats( )
671{
672    if ( statsBox )
673    {
674      delete statsBox;
675      statsBox = NULL;
676    }
677}
678
679/**
680 * fill stats table with values
681 */
682void MultiplayerTeamDeathmatch::tickStatsTable( )
683{
684  if ( !this->statsBox )
685    return;
686
687  std::vector<std::string> headers;
688  headers.push_back("Blue Team");
689  headers.push_back("");
690  headers.push_back("");
691  headers.push_back("Red Team");
692  headers.push_back("");
693  this->table->setHeader(headers);
694
695  ScoreList scoreList = PlayerStats::getScoreList();
696
697  char st[10];
698  int i = 0;
699
700  i = 2;
701  for ( TeamScoreList::const_iterator it = scoreList[0].begin(); it != scoreList[0].end(); it++ )
702  {
703    this->table->setEntry( i, 0, it->name );
704    snprintf( st, 10, "%d", it->score );
705    this->table->setEntry( i, 1, st );
706    this->table->setEntry( i, 2, "" );
707    i++;
708  }
709
710  i = 2;
711  for ( TeamScoreList::const_iterator it = scoreList[1].begin(); it != scoreList[1].end(); it++ )
712  {
713    this->table->setEntry( i, 3, it->name );
714    snprintf( st, 10, "%d", it->score );
715    this->table->setEntry( i, 4, st );
716    i++;
717  }
718
719}
720
721/**
722 * this function is called when a player kills another one or himself
723 * @param killedUserId
724 * @param userId
725 */
726void MultiplayerTeamDeathmatch::onKill( WorldEntity * victim, WorldEntity * killer )
727{
728  if ( !victim )
729  {
730    PRINTF(0)("victim == NULL\n");
731    return;
732  }
733  if ( !killer )
734  {
735    PRINTF(0)("killer == NULL\n");
736    return;
737  }
738
739  int killerUserId = killer->getOwner();
740  int victimUserId = victim->getOwner();
741
742  PRINTF(0)("%d %d %x %x %s %s\n", killerUserId, victimUserId, killer, victim, killer->getClassCName(), victim->getClassCName());
743
744  PlayerStats & victimStats = *PlayerStats::getStats( victimUserId );
745  PlayerStats & killerStats = *PlayerStats::getStats( killerUserId );
746
747  if ( killerStats.getPlayable() != killer || victimStats.getPlayable() != victim )
748  {
749    PRINTF(0)("killerStats.getPlayable() != killer || victimStats.getPlayable() != victim\n");
750    PRINTF(0)("%x %x %x %x\n", killerStats.getPlayable(), killer, victimStats.getPlayable(), victim );
751    PRINTF(0)("%d %d %d %d\n", killerStats.getPlayable()->getUniqueID(), killer->getUniqueID(), victimStats.getPlayable()->getUniqueID(), victim->getUniqueID() );
752    return;
753  }
754
755  //check for suicide
756  if ( killerUserId != victimUserId )
757  {
758    //check for teamkill
759    if ( victimStats.getTeamId() != killerStats.getTeamId() )
760    {
761      killerStats.setScore( killerStats.getScore() + 1 );
762    }
763    else
764    {
765      killerStats.setScore( killerStats.getScore() - 1 );
766    }
767  }
768  else
769    killerStats.setScore( killerStats.getScore() - 1 );
770
771  if ( victimUserId == SharedNetworkData::getInstance()->getHostID() )
772  {
773    this->bLocalPlayerDead = true;
774    this->showStats();
775  }
776
777  this->respawnPlayable( victimStats.getPlayable(), victimStats.getTeamId(), 3.0f );
778}
779
780/**
781 * this function is called on player respawn
782 * @param userId
783 */
784void MultiplayerTeamDeathmatch::onRespawn( int userId )
785{
786  if ( userId == SharedNetworkData::getInstance()->getHostID() )
787  {
788    this->bLocalPlayerDead = false;
789    this->hideStats();
790  }
791}
792
793/**
794 * this function is called on player respawn
795 * @param we
796 */
797void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
798{
799  onRespawn( we->getOwner() );
800}
801
802
803/**
804 * respawns a playable in the world via spawning points
805 * @param playable the playable to respawn
806 * @param teamId the teamId to use
807 * @param delay time delay for delayed spawning
808 */
809void MultiplayerTeamDeathmatch::respawnPlayable( Playable * playable, int teamId, float delay )
810{
811  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
812
813  assert( list );
814
815  std::vector<SpawningPoint*> spList;
816
817  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
818  {
819    SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
820
821    if ( sp->getTeamId() == teamId )
822      spList.push_back( sp );
823  }
824
825  if ( spList.size() == 0 )
826  {
827    for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
828    {
829      SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
830
831      if ( sp->getTeamId() < 0 )
832        spList.push_back( sp );
833    }
834  }
835
836  assert( spList.size() != 0 );
837
838  int n = (int)((float)spList.size() * (float)rand()/(float)RAND_MAX);
839
840  spList[n]->pushEntity( playable, delay );
841}
842
843
Note: See TracBrowser for help on using the repository browser.