Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

userId address spaces adjusted since the proxys are handled differently than clients

File size: 21.2 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    delete oldPlayable;
537  }
538}
539
540
541void MultiplayerTeamDeathmatch::onButtonExit( )
542{
543  State::getCurrentStoryEntity()->stop();
544  this->bShowTeamChange = false;
545}
546
547void MultiplayerTeamDeathmatch::onButtonRandom( )
548{
549  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
550  this->bShowTeamChange = false;
551}
552
553void MultiplayerTeamDeathmatch::onButtonTeam0( )
554{
555  NetworkGameManager::getInstance()->prefereTeam( 0 );
556  this->bShowTeamChange = false;
557}
558
559void MultiplayerTeamDeathmatch::onButtonTeam1( )
560{
561  NetworkGameManager::getInstance()->prefereTeam( 1 );
562  this->bShowTeamChange = false;
563}
564
565void MultiplayerTeamDeathmatch::onButtonSpectator( )
566{
567  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
568  this->bShowTeamChange = false;
569}
570
571void MultiplayerTeamDeathmatch::assignPlayable( )
572{
573  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
574    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
575}
576
577
578/**
579 * function that processes events from the handler
580 * @param event: the event
581 * @todo replace SDLK_o with something from KeyMapper
582 */
583void MultiplayerTeamDeathmatch::process( const Event & event )
584{
585  if ( event.type == SDLK_o )
586  {
587    if ( event.bPressed )
588      this->bShowTeamChange = true;
589  } else if ( event.type == SDLK_F1 )
590  {
591    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed )
592    {
593      PRINTF(5)("hide stats\n");
594      this->hideStats();
595    }
596    else if ( !this->statsBox && event.bPressed )
597    {
598      PRINTF(5)("show stats\n");
599      this->showStats();
600    }
601  }
602  else if ( event.type == SDLK_TAB )
603  {
604    if ( currentGameState == GAMESTATE_GAME && event.bPressed && !EventHandler::getInstance()->isPressed( SDLK_RALT ) && !EventHandler::getInstance()->isPressed( SDLK_LALT ) )
605    {
606      EventHandler::getInstance()->pushState( ES_MENU );
607      OrxGui::GLGuiHandler::getInstance()->activateCursor();
608      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
609      input->show();
610      input->giveMouseFocus();
611      input->setText("say ");
612    }
613  }
614  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
615  {
616    this->hideStats();
617  }
618}
619
620void MultiplayerTeamDeathmatch::onButtonCancel( )
621{
622  this->bShowTeamChange = false;
623}
624
625
626
627/**
628 * this method is called by NetworkGameManger when he recieved a chat message
629 * @param userId senders user id
630 * @param message message string
631 * @param messageType some int
632 */
633void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
634{
635  std::string name = "unknown";
636
637  if ( PlayerStats::getStats( userId ) )
638  {
639    name = PlayerStats::getStats( userId )->getNickName();
640  }
641
642  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
643  State::getPlayer()->hud().notifyUser(name + ": " + message);
644}
645
646void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
647{
648  EventHandler::getInstance()->popState();
649  input->breakMouseFocus();
650  input->hide();
651  input->setText("");
652
653  std::string command = text;
654
655  //HACK insert " in say commands so user doesn't have to type them
656  if ( command.length() >= 4 && command[0] == 's' && command[1] == 'a' && command[2] == 'y' && command[3] == ' ' )
657  {
658    command.insert( 4, "\"" );
659    command = command + "\"";
660  }
661
662  OrxShell::ShellCommand::execute( command );
663}
664
665/**
666 * show table with frags
667 */
668void MultiplayerTeamDeathmatch::showStats( )
669{
670  statsBox = new OrxGui::GLGuiBox();
671  statsBox->setAbsCoor2D( 100, 100 );
672
673  this->table = new OrxGui::GLGuiTable(10,5);
674
675  statsBox->pack( this->table );
676
677  statsBox->showAll();
678}
679
680/**
681 * hide table with frags
682 */
683void MultiplayerTeamDeathmatch::hideStats( )
684{
685    if ( statsBox )
686    {
687      delete statsBox;
688      statsBox = NULL;
689    }
690}
691
692/**
693 * fill stats table with values
694 */
695void MultiplayerTeamDeathmatch::tickStatsTable( )
696{
697  if ( !this->statsBox )
698    return;
699
700  std::vector<std::string> headers;
701  headers.push_back("Blue Team");
702  headers.push_back("");
703  headers.push_back("");
704  headers.push_back("Red Team");
705  headers.push_back("");
706  this->table->setHeader(headers);
707
708  ScoreList scoreList = PlayerStats::getScoreList();
709
710  char st[10];
711  int i = 0;
712
713  i = 2;
714  for ( TeamScoreList::const_iterator it = scoreList[0].begin(); it != scoreList[0].end(); it++ )
715  {
716    this->table->setEntry( i, 0, it->name );
717    snprintf( st, 10, "%d", it->score );
718    this->table->setEntry( i, 1, st );
719    this->table->setEntry( i, 2, "" );
720    i++;
721  }
722
723  i = 2;
724  for ( TeamScoreList::const_iterator it = scoreList[1].begin(); it != scoreList[1].end(); it++ )
725  {
726    this->table->setEntry( i, 3, it->name );
727    snprintf( st, 10, "%d", it->score );
728    this->table->setEntry( i, 4, st );
729    i++;
730  }
731
732}
733
734/**
735 * this function is called when a player kills another one or himself
736 * @param killedUserId
737 * @param userId
738 */
739void MultiplayerTeamDeathmatch::onKill( WorldEntity * victim, WorldEntity * killer )
740{
741  if ( !victim )
742  {
743    PRINTF(0)("victim == NULL\n");
744    return;
745  }
746  if ( !killer )
747  {
748    PRINTF(0)("killer == NULL\n");
749    return;
750  }
751
752  int killerUserId = killer->getOwner();
753  int victimUserId = victim->getOwner();
754
755  PRINTF(0)("%d %d %x %x %s %s\n", killerUserId, victimUserId, killer, victim, killer->getClassCName(), victim->getClassCName());
756
757  PlayerStats & victimStats = *PlayerStats::getStats( victimUserId );
758  PlayerStats & killerStats = *PlayerStats::getStats( killerUserId );
759
760  if ( killerStats.getPlayable() != killer || victimStats.getPlayable() != victim )
761  {
762    PRINTF(0)("killerStats.getPlayable() != killer || victimStats.getPlayable() != victim\n");
763    PRINTF(0)("%x %x %x %x\n", killerStats.getPlayable(), killer, victimStats.getPlayable(), victim );
764    PRINTF(0)("%d %d %d %d\n", killerStats.getPlayable()->getUniqueID(), killer->getUniqueID(), victimStats.getPlayable()->getUniqueID(), victim->getUniqueID() );
765    return;
766  }
767
768  //check for suicide
769  if ( killerUserId != victimUserId )
770  {
771    //check for teamkill
772    if ( victimStats.getTeamId() != killerStats.getTeamId() )
773    {
774      killerStats.setScore( killerStats.getScore() + 1 );
775    }
776    else
777    {
778      killerStats.setScore( killerStats.getScore() - 1 );
779    }
780  }
781  else
782    killerStats.setScore( killerStats.getScore() - 1 );
783
784  if ( victimUserId == SharedNetworkData::getInstance()->getHostID() )
785  {
786    this->bLocalPlayerDead = true;
787    this->showStats();
788  }
789
790  this->respawnPlayable( victimStats.getPlayable(), victimStats.getTeamId(), 3.0f );
791}
792
793/**
794 * this function is called on player respawn
795 * @param userId
796 */
797void MultiplayerTeamDeathmatch::onRespawn( int userId )
798{
799  if ( userId == SharedNetworkData::getInstance()->getHostID() )
800  {
801    this->bLocalPlayerDead = false;
802    this->hideStats();
803  }
804}
805
806/**
807 * this function is called on player respawn
808 * @param we
809 */
810void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
811{
812  onRespawn( we->getOwner() );
813}
814
815
816/**
817 * respawns a playable in the world via spawning points
818 * @param playable the playable to respawn
819 * @param teamId the teamId to use
820 * @param delay time delay for delayed spawning
821 */
822void MultiplayerTeamDeathmatch::respawnPlayable( Playable * playable, int teamId, float delay )
823{
824  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
825
826  assert( list );
827
828  std::vector<SpawningPoint*> spList;
829
830  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
831  {
832    SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
833
834    if ( sp->getTeamId() == teamId )
835      spList.push_back( sp );
836  }
837
838  if ( spList.size() == 0 )
839  {
840    for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
841    {
842      SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
843
844      if ( sp->getTeamId() < 0 )
845        spList.push_back( sp );
846    }
847  }
848
849  assert( spList.size() != 0 );
850
851  int n = (int)((float)spList.size() * (float)rand()/(float)RAND_MAX);
852
853  spList[n]->pushEntity( playable, delay );
854}
855
856
Note: See TracBrowser for help on using the repository browser.