Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

even less debug

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