Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

better debug output now

File size: 21.1 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         box == NULL &&
142         (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM || bShowTeamChange )
143
144       )
145    {
146      EventHandler::getInstance()->pushState( ES_MENU );
147
148      OrxGui::GLGuiHandler::getInstance()->activateCursor();
149
150      box = new OrxGui::GLGuiBox();
151      box->setAbsCoor2D( 300, 100 );
152
153      if( SharedNetworkData::getInstance()->isClient() ||  SharedNetworkData::getInstance()->isProxyServerActive())
154      {
155        OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
156        box->pack( buttonSpectator );
157        buttonSpectator->released.connect(this, &MultiplayerTeamDeathmatch::onButtonSpectator);
158
159        OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
160        box->pack( buttonRandom );
161        buttonRandom->released.connect(this, &MultiplayerTeamDeathmatch::onButtonRandom);
162
163        OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
164        box->pack( buttonTeam0 );
165        buttonTeam0->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam0);
166
167        OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
168        box->pack( buttonTeam1 );
169        buttonTeam1->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam1);
170      }
171      else
172      {
173        OrxGui::GLGuiText* text = new OrxGui::GLGuiText();
174        text->setText("Server Mode: not able to play at this node");
175        box->pack( text);
176      }
177
178
179      if ( bShowTeamChange )
180      {
181        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
182        box->pack( buttonCancel );
183        buttonCancel->released.connect(this, &MultiplayerTeamDeathmatch::onButtonCancel);
184      }
185
186      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
187      box->pack( buttonExit );
188      buttonExit->released.connect(this, &MultiplayerTeamDeathmatch::onButtonExit);
189
190      box->showAll();
191    }
192  }
193
194
195  // check if the menu should be removed and the game state should be entered
196  if ( box != NULL &&
197       PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) &&
198       PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() != TEAM_NOTEAM &&
199       !bShowTeamChange
200     )
201  {
202    delete box;
203    box = NULL;
204
205    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
206
207    EventHandler::getInstance()->popState();
208  }
209
210  if ( box != NULL )
211  {
212    OrxGui::GLGuiHandler::getInstance()->tick( dt );
213  }
214
215  assignPlayable();
216
217  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
218    return;
219
220  //handle kills
221  while ( this->killList.begin() != this->killList.end() )
222  {
223    PRINTF(0)("KKKKKKKKIIIIIIIIILLLLLLLLLLLLL\n");
224    onKill( this->killList.begin()->getVictim(), this->killList.begin()->getKiller() );
225    this->killList.erase( this->killList.begin() );
226  }
227
228
229
230  gameStateTimer -= dt;
231  //PRINTF(0)("TICK %f\n", gameStateTimer);
232
233  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
234    nextGameState();
235
236  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
237
238  if ( currentGameState == GAMESTATE_GAME )
239  {
240    handleTeamChanges();
241  }
242
243  this->calculateTeamScore();
244
245  this->checkGameRules();
246
247  // is the local player dead and inactive
248  if( unlikely(this->bLocalPlayerDead))
249  {
250    this->timeout += dt;
251    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
252    // long enough dead?
253    if( this->timeout >= this->deathTimeout)
254    {
255      this->timeout = 0.0f;
256      // respawn
257      PRINTF(0)("RESPAWN\n");
258      (State::getPlayer())->getPlayable()->respawn();
259    }
260  }
261}
262
263
264/**
265 * draws the stuff
266 */
267void MultiplayerTeamDeathmatch::draw()
268{
269  if( unlikely( this->bLocalPlayerDead))
270  {
271
272  }
273}
274
275
276/**
277 * check the game rules for consistency
278 */
279void MultiplayerTeamDeathmatch::checkGameRules()
280{
281  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
282    return;
283
284  // check for max killing count
285  for ( int i = 0; i<numTeams; i++ )
286  {
287    if ( teamScore[i] >= maxKills )
288    {
289      nextGameState();
290    }
291  }
292}
293
294/**
295 * find group for new player
296 * @return group id
297 */
298int MultiplayerTeamDeathmatch::getTeamForNewUser()
299{
300  return TEAM_NOTEAM;
301}
302
303ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
304{
305  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
306    return CL_SPECTATOR;
307
308  if ( team == 0 || team == 1 )
309    return CL_TURBINE_HOVER;
310
311  assert( false );
312}
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
446/**
447 *  this handles team changes but only on the master server
448 */
449void MultiplayerTeamDeathmatch::handleTeamChanges( )
450{
451  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
452
453  if ( !list )
454    return;
455
456  //first server players with choices
457  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
458  {
459    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
460
461    if ( stats.getTeamId() != stats.getPreferedTeamId() )
462    {
463      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
464      {
465        teamChange( stats.getAssignedUserId() );
466      }
467    }
468  }
469
470  //now serve player who want join a random team
471  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
472  {
473    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
474
475    if ( stats.getTeamId() != stats.getPreferedTeamId() )
476    {
477      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
478      {
479        stats.setPreferedTeamId( getRandomTeam() );
480        teamChange( stats.getAssignedUserId() );
481      }
482    }
483  }
484}
485
486
487
488/**
489 * changes the team
490 * @param userId the user changing team (userId)
491 */
492void MultiplayerTeamDeathmatch::teamChange( int userId )
493{
494  assert( PlayerStats::getStats( userId ) );
495  PlayerStats & stats = *(PlayerStats::getStats( userId ));
496
497  stats.setTeamId( stats.getPreferedTeamId() );
498
499  Playable * oldPlayable = stats.getPlayable();
500
501
502  ClassID       playableClassId  = getPlayableClassId( userId, stats.getPreferedTeamId() );
503  std::string   playableModel    = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
504  std::string   playableTexture  = getPlayableModelTextureFileName( userId, stats.getPreferedTeamId(), playableClassId );
505  float         playableScale    = getPlayableScale( userId, stats.getPreferedTeamId(), playableClassId );
506
507  BaseObject * bo = Factory::fabricate( playableClassId );
508
509  assert( bo != NULL );
510  assert( bo->isA( CL_PLAYABLE ) );
511
512  Playable & playable = *(dynamic_cast<Playable*>(bo));
513
514  playable.loadMD2Texture( playableTexture );
515  playable.loadModel( playableModel, playableScale );
516  playable.setOwner( userId );
517  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
518  playable.setSynchronized( true );
519
520  stats.setPlayableClassId( playableClassId );
521  stats.setPlayableUniqueId( playable.getUniqueID() );
522  stats.setModelFileName( playableModel );
523  stats.setTeamId( stats.getPreferedTeamId() );
524
525//   playable.setTeam(stats.getPreferedTeamId());
526
527
528  this->respawnPlayable( &playable, stats.getPreferedTeamId(), 0.0f );
529
530  if ( oldPlayable )
531  {
532    //if ( userId == SharedNetworkData::getInstance()->getHostID() )
533    //  State::getPlayer()->setPlayable( NULL );
534    delete oldPlayable;
535  }
536}
537
538
539void MultiplayerTeamDeathmatch::onButtonExit( )
540{
541  State::getCurrentStoryEntity()->stop();
542  this->bShowTeamChange = false;
543}
544
545void MultiplayerTeamDeathmatch::onButtonRandom( )
546{
547  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
548  this->bShowTeamChange = false;
549}
550
551void MultiplayerTeamDeathmatch::onButtonTeam0( )
552{
553  NetworkGameManager::getInstance()->prefereTeam( 0 );
554  this->bShowTeamChange = false;
555}
556
557void MultiplayerTeamDeathmatch::onButtonTeam1( )
558{
559  NetworkGameManager::getInstance()->prefereTeam( 1 );
560  this->bShowTeamChange = false;
561}
562
563void MultiplayerTeamDeathmatch::onButtonSpectator( )
564{
565  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
566  this->bShowTeamChange = false;
567}
568
569void MultiplayerTeamDeathmatch::assignPlayable( )
570{
571  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
572    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
573}
574
575
576/**
577 * function that processes events from the handler
578 * @param event: the event
579 * @todo replace SDLK_o with something from KeyMapper
580 */
581void MultiplayerTeamDeathmatch::process( const Event & event )
582{
583  if ( event.type == SDLK_o )
584  {
585    if ( event.bPressed )
586      this->bShowTeamChange = true;
587  } else if ( event.type == SDLK_F1 )
588  {
589    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed )
590    {
591      PRINTF(5)("hide stats\n");
592      this->hideStats();
593    }
594    else if ( !this->statsBox && event.bPressed )
595    {
596      PRINTF(5)("show stats\n");
597      this->showStats();
598    }
599  }
600  else if ( event.type == SDLK_TAB )
601  {
602    if ( currentGameState == GAMESTATE_GAME && event.bPressed && !EventHandler::getInstance()->isPressed( SDLK_RALT ) && !EventHandler::getInstance()->isPressed( SDLK_LALT ) )
603    {
604      EventHandler::getInstance()->pushState( ES_MENU );
605      OrxGui::GLGuiHandler::getInstance()->activateCursor();
606      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
607      input->show();
608      input->giveMouseFocus();
609      input->setText("say ");
610    }
611  }
612  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
613  {
614    this->hideStats();
615  }
616}
617
618void MultiplayerTeamDeathmatch::onButtonCancel( )
619{
620  this->bShowTeamChange = false;
621}
622
623
624
625/**
626 * this method is called by NetworkGameManger when he recieved a chat message
627 * @param userId senders user id
628 * @param message message string
629 * @param messageType some int
630 */
631void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
632{
633  std::string name = "unknown";
634
635  if ( PlayerStats::getStats( userId ) )
636  {
637    name = PlayerStats::getStats( userId )->getNickName();
638  }
639
640  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
641  State::getPlayer()->hud().notifyUser(name + ": " + message);
642}
643
644void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
645{
646  EventHandler::getInstance()->popState();
647  input->breakMouseFocus();
648  input->hide();
649  input->setText("");
650
651  std::string command = text;
652
653  //HACK insert " in say commands so user doesn't have to type them
654  if ( command.length() >= 4 && command[0] == 's' && command[1] == 'a' && command[2] == 'y' && command[3] == ' ' )
655  {
656    command.insert( 4, "\"" );
657    command = command + "\"";
658  }
659
660  OrxShell::ShellCommand::execute( command );
661}
662
663/**
664 * show table with frags
665 */
666void MultiplayerTeamDeathmatch::showStats( )
667{
668  statsBox = new OrxGui::GLGuiBox();
669  statsBox->setAbsCoor2D( 100, 100 );
670
671  this->table = new OrxGui::GLGuiTable(10,5);
672
673  statsBox->pack( this->table );
674
675  statsBox->showAll();
676}
677
678/**
679 * hide table with frags
680 */
681void MultiplayerTeamDeathmatch::hideStats( )
682{
683    if ( statsBox )
684    {
685      delete statsBox;
686      statsBox = NULL;
687    }
688}
689
690/**
691 * fill stats table with values
692 */
693void MultiplayerTeamDeathmatch::tickStatsTable( )
694{
695  if ( !this->statsBox )
696    return;
697
698  std::vector<std::string> headers;
699  headers.push_back("Blue Team");
700  headers.push_back("");
701  headers.push_back("");
702  headers.push_back("Red Team");
703  headers.push_back("");
704  this->table->setHeader(headers);
705
706  ScoreList scoreList = PlayerStats::getScoreList();
707
708  char st[10];
709  int i = 0;
710
711  i = 2;
712  for ( TeamScoreList::const_iterator it = scoreList[0].begin(); it != scoreList[0].end(); it++ )
713  {
714    this->table->setEntry( i, 0, it->name );
715    snprintf( st, 10, "%d", it->score );
716    this->table->setEntry( i, 1, st );
717    this->table->setEntry( i, 2, "" );
718    i++;
719  }
720
721  i = 2;
722  for ( TeamScoreList::const_iterator it = scoreList[1].begin(); it != scoreList[1].end(); it++ )
723  {
724    this->table->setEntry( i, 3, it->name );
725    snprintf( st, 10, "%d", it->score );
726    this->table->setEntry( i, 4, st );
727    i++;
728  }
729
730}
731
732/**
733 * this function is called when a player kills another one or himself
734 * @param killedUserId
735 * @param userId
736 */
737void MultiplayerTeamDeathmatch::onKill( WorldEntity * victim, WorldEntity * killer )
738{
739  if ( !victim )
740  {
741    PRINTF(0)("victim == NULL\n");
742    return;
743  }
744  if ( !killer )
745  {
746    PRINTF(0)("killer == NULL\n");
747    return;
748  }
749
750  int killerUserId = killer->getOwner();
751  int victimUserId = victim->getOwner();
752
753  PRINTF(0)("%d %d %x %x %s %s\n", killerUserId, victimUserId, killer, victim, killer->getClassCName(), victim->getClassCName());
754
755  PlayerStats & victimStats = *PlayerStats::getStats( victimUserId );
756  PlayerStats & killerStats = *PlayerStats::getStats( killerUserId );
757
758  if ( killerStats.getPlayable() != killer || victimStats.getPlayable() != victim )
759  {
760    PRINTF(0)("killerStats.getPlayable() != killer || victimStats.getPlayable() != victim\n");
761    PRINTF(0)("%x %x %x %x\n", killerStats.getPlayable(), killer, victimStats.getPlayable(), victim );
762    PRINTF(0)("%d %d %d %d\n", killerStats.getPlayable()->getUniqueID(), killer->getUniqueID(), victimStats.getPlayable()->getUniqueID(), victim->getUniqueID() );
763    return;
764  }
765
766  //check for suicide
767  if ( killerUserId != victimUserId )
768  {
769    //check for teamkill
770    if ( victimStats.getTeamId() != killerStats.getTeamId() )
771    {
772      killerStats.setScore( killerStats.getScore() + 1 );
773    }
774    else
775    {
776      killerStats.setScore( killerStats.getScore() - 1 );
777    }
778  }
779  else
780    killerStats.setScore( killerStats.getScore() - 1 );
781
782  if ( victimUserId == SharedNetworkData::getInstance()->getHostID() )
783  {
784    this->bLocalPlayerDead = true;
785    this->showStats();
786  }
787
788  this->respawnPlayable( victimStats.getPlayable(), victimStats.getTeamId(), 3.0f );
789}
790
791/**
792 * this function is called on player respawn
793 * @param userId
794 */
795void MultiplayerTeamDeathmatch::onRespawn( int userId )
796{
797  if ( userId == SharedNetworkData::getInstance()->getHostID() )
798  {
799    this->bLocalPlayerDead = false;
800    this->hideStats();
801  }
802}
803
804/**
805 * this function is called on player respawn
806 * @param we
807 */
808void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
809{
810  onRespawn( we->getOwner() );
811}
812
813
814/**
815 * respawns a playable in the world via spawning points
816 * @param playable the playable to respawn
817 * @param teamId the teamId to use
818 * @param delay time delay for delayed spawning
819 */
820void MultiplayerTeamDeathmatch::respawnPlayable( Playable * playable, int teamId, float delay )
821{
822  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
823
824  assert( list );
825
826  std::vector<SpawningPoint*> spList;
827
828  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
829  {
830    SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
831
832    if ( sp->getTeamId() == teamId )
833      spList.push_back( sp );
834  }
835
836  if ( spList.size() == 0 )
837  {
838    for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
839    {
840      SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
841
842      if ( sp->getTeamId() < 0 )
843        spList.push_back( sp );
844    }
845  }
846
847  assert( spList.size() != 0 );
848
849  int n = (int)((float)spList.size() * (float)rand()/(float)RAND_MAX);
850
851  spList[n]->pushEntity( playable, delay );
852}
853
854
Note: See TracBrowser for help on using the repository browser.