Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/new_class_id/src/util/multiplayer_team_deathmatch.cc @ 9704

Last change on this file since 9704 was 9704, checked in by bensch, 18 years ago

adapted some game-rules

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
27#include "player.h"
28#include "playable.h"
29#include "space_ships/space_ship.h"
30
31
32#include "shared_network_data.h"
33#include "terrain.h"
34#include "space_ships/space_ship.h"
35
36#include "network_game_manager.h"
37
38#include "event_handler.h"
39
40#include "glgui.h"
41
42#include "story_entity.h"
43
44#include "shell_command.h"
45
46#include "spawning_point.h"
47
48
49
50#include "class_id.h"
51
52CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
53NewObjectListDefinitionID(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
54/**
55 * constructor
56 */
57MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
58  : NetworkGameRules(root)
59{
60  this->registerObject(this, MultiplayerTeamDeathmatch::_objectList);
61
62  this->bLocalPlayerDead = false;
63  this->deathTimeout = 10.0f;     // 5 seconds
64  this->timeout = 0.0f;
65  this->numTeams = 2;
66  this->currentGameState = GAMESTATE_PRE_GAME;
67  this->gameStateTimer = 3.0f;
68  this->bShowTeamChange = false;
69
70  this->box = NULL;
71  this->table = NULL;
72  this->statsBox = NULL;
73
74  this->localPlayer = State::getPlayer();
75
76  if( root != NULL)
77    this->loadParams(root);
78
79  subscribeEvent( ES_GAME, SDLK_o );
80  subscribeEvent( ES_GAME, SDLK_TAB );
81  subscribeEvent( ES_GAME, SDLK_F1 );
82  subscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
83
84  this->input = new OrxGui::GLGuiInputLine();
85  this->input->setAbsCoor2D(180, 5);
86  this->input->enterPushed.connect(this, &MultiplayerTeamDeathmatch::onInputEnter);
87}
88
89/**
90 * decontsructor
91 */
92MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
93{
94  unsubscribeEvent( ES_GAME, SDLK_o );
95  unsubscribeEvent( ES_GAME, SDLK_TAB );
96  unsubscribeEvent( ES_GAME, SDLK_F1 );
97  unsubscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
98
99  if ( this->input )
100  {
101    delete this->input;
102    this->input = NULL;
103  }
104}
105
106
107
108void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
109{
110  GameRules::loadParams(root) ;
111
112  LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout)
113      .describe("sets the time in seconds a player has to wait for respawn");
114
115  LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills)
116      .describe("sets the maximal kills for winning condition");
117
118  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
119      .describe("sets number of teams");
120
121}
122
123
124/**
125 * time tick
126 * @param dt time
127 */
128void MultiplayerTeamDeathmatch::tick(float dt)
129{
130  tickStatsTable();
131  //on client side hostId is -1 until hanshake finished
132  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
133    return;
134
135  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
136  {
137    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) &&
138         box == NULL &&
139         (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM || bShowTeamChange )
140
141       )
142    {
143      EventHandler::getInstance()->pushState( ES_MENU );
144
145      OrxGui::GLGuiHandler::getInstance()->activateCursor();
146
147      box = new OrxGui::GLGuiBox();
148      box->setAbsCoor2D( 300, 100 );
149
150      if( SharedNetworkData::getInstance()->isClient() ||  SharedNetworkData::getInstance()->isProxyServerActive())
151      {
152        OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
153        box->pack( buttonSpectator );
154        buttonSpectator->released.connect(this, &MultiplayerTeamDeathmatch::onButtonSpectator);
155
156        OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
157        box->pack( buttonRandom );
158        buttonRandom->released.connect(this, &MultiplayerTeamDeathmatch::onButtonRandom);
159
160        OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
161        box->pack( buttonTeam0 );
162        buttonTeam0->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam0);
163
164        OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
165        box->pack( buttonTeam1 );
166        buttonTeam1->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam1);
167      }
168      else
169      {
170        OrxGui::GLGuiText* text = new OrxGui::GLGuiText();
171        text->setText("Server Mode: not able to play at this node");
172        box->pack( text);
173      }
174
175
176      if ( bShowTeamChange )
177      {
178        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
179        box->pack( buttonCancel );
180        buttonCancel->released.connect(this, &MultiplayerTeamDeathmatch::onButtonCancel);
181      }
182
183      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
184      box->pack( buttonExit );
185      buttonExit->released.connect(this, &MultiplayerTeamDeathmatch::onButtonExit);
186
187      box->showAll();
188    }
189  }
190
191//   if( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
192//   {
193//     PRINTF(0)("prefered team id: %i, noteam: %i\n", PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId(), TEAM_NOTEAM);
194//   }
195
196  // check if the menu should be removed and the game state should be entered
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
304NewClassID 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
315
316std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
317{
318  if (classId == CL_TURBINE_HOVER)
319   return "models/ships/hoverglider_mainbody.obj";
320  if ( team == 0 )
321    return "models/creatures/doom_guy.md2";
322  else if ( team == 1 )
323    return "models/creatures/male.md2";
324  else
325    return "";
326}
327
328std::string MultiplayerTeamDeathmatch::getPlayableModelTextureFileName( int userId, int team, ClassID classId )
329{
330  if ( classId == CL_FPS_PLAYER )
331  {
332    if ( team == 0 )
333      return "maps/doom_guy.png";
334    else
335      return "maps/male_fiend.pcx";
336  }
337
338  return "";
339}
340
341float MultiplayerTeamDeathmatch::getPlayableScale( int userId, int team, ClassID classId )
342{
343  if ( classId == CL_FPS_PLAYER )
344  {
345    return 10.0f;
346  }
347
348  return 1.0f;
349}
350
351/**
352 * calculate team score
353 */
354void MultiplayerTeamDeathmatch::calculateTeamScore( )
355{
356  teamScore.clear();
357
358  for ( int i = 0; i<numTeams; i++ )
359    teamScore[i] = 0;
360
361
362  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
363
364  if ( !list )
365    return;
366
367  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
368  {
369    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
370
371    if ( stats.getTeamId() >= 0 )
372    {
373      teamScore[stats.getTeamId()] += stats.getScore();
374    }
375  }
376}
377
378/**
379 * get team for player who choose to join random team
380 * @return smallest team
381 */
382int MultiplayerTeamDeathmatch::getRandomTeam( )
383{
384  std::map<int,int> playersInTeam;
385
386  for ( int i = 0; i<numTeams; i++ )
387    playersInTeam[i] = 0;
388
389  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
390
391  if ( !list )
392    return 0;
393
394  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
395  {
396    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
397
398    if ( stats.getTeamId() >= 0 )
399    {
400      playersInTeam[stats.getTeamId()]++;
401    }
402  }
403
404
405  int minPlayers = 0xFFFF;
406  int minTeam = -1;
407
408  for ( int i = 0; i<numTeams; i++ )
409  {
410    if ( playersInTeam[i] < minPlayers )
411    {
412      minTeam = i;
413      minPlayers = playersInTeam[i];
414    }
415  }
416
417  assert( minTeam != -1 );
418
419  return minTeam;
420}
421
422void MultiplayerTeamDeathmatch::nextGameState( )
423{
424  if ( currentGameState == GAMESTATE_PRE_GAME )
425  {
426    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
427
428    return;
429  }
430
431  if ( currentGameState == GAMESTATE_GAME )
432  {
433    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
434
435    return;
436  }
437
438  if ( currentGameState == GAMESTATE_POST_GAME )
439  {
440    //State::getCurrentStoryEntity()->stop();
441    this->bShowTeamChange = false;
442
443    return;
444  }
445}
446
447/**
448 *  this handles team changes but only on the master server
449 */
450void MultiplayerTeamDeathmatch::handleTeamChanges( )
451{
452  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
453
454  if ( !list )
455    return;
456
457  //first server players with choices
458  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
459  {
460    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
461
462    if ( stats.getTeamId() != stats.getPreferedTeamId() )
463    {
464      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
465      {
466        teamChange( stats.getAssignedUserId() );
467      }
468    }
469  }
470
471  //now serve player who want join a random team
472  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
473  {
474    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
475
476    if ( stats.getTeamId() != stats.getPreferedTeamId() )
477    {
478      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
479      {
480        stats.setPreferedTeamId( getRandomTeam() );
481        teamChange( stats.getAssignedUserId() );
482      }
483    }
484  }
485}
486
487
488
489/**
490 * changes the team
491 * @param userId the user changing team (userId)
492 */
493void MultiplayerTeamDeathmatch::teamChange( int userId )
494{
495  assert( PlayerStats::getStats( userId ) );
496  PlayerStats & stats = *(PlayerStats::getStats( userId ));
497
498  stats.setTeamId( stats.getPreferedTeamId() );
499
500  Playable * oldPlayable = stats.getPlayable();
501
502
503  ClassID       playableClassId  = getPlayableClassId( userId, stats.getPreferedTeamId() );
504  std::string   playableModel    = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
505  std::string   playableTexture  = getPlayableModelTextureFileName( userId, stats.getPreferedTeamId(), playableClassId );
506  float         playableScale    = getPlayableScale( userId, stats.getPreferedTeamId(), playableClassId );
507
508  BaseObject * bo = Factory::fabricate( playableClassId );
509
510  assert( bo != NULL );
511  assert( bo->isA( CL_PLAYABLE ) );
512
513  Playable & playable = *(dynamic_cast<Playable*>(bo));
514
515  playable.loadMD2Texture( playableTexture );
516  playable.loadModel( playableModel, playableScale );
517  playable.setOwner( userId );
518  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
519  playable.setSynchronized( true );
520
521  stats.setPlayableClassId( playableClassId );
522  stats.setPlayableUniqueId( playable.getUniqueID() );
523  stats.setModelFileName( playableModel );
524  stats.setTeamId( stats.getPreferedTeamId() );
525
526  playable.setTeam(stats.getPreferedTeamId());
527
528
529  this->respawnPlayable( &playable, stats.getPreferedTeamId(), 0.0f );
530
531  if ( oldPlayable )
532  {
533    delete oldPlayable;
534  }
535}
536
537
538void MultiplayerTeamDeathmatch::onButtonExit( )
539{
540  State::getCurrentStoryEntity()->stop();
541  this->bShowTeamChange = false;
542}
543
544void MultiplayerTeamDeathmatch::onButtonRandom( )
545{
546  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
547  this->bShowTeamChange = false;
548}
549
550void MultiplayerTeamDeathmatch::onButtonTeam0( )
551{
552  NetworkGameManager::getInstance()->prefereTeam( 0 );
553  this->bShowTeamChange = false;
554}
555
556void MultiplayerTeamDeathmatch::onButtonTeam1( )
557{
558  NetworkGameManager::getInstance()->prefereTeam( 1 );
559  this->bShowTeamChange = false;
560}
561
562void MultiplayerTeamDeathmatch::onButtonSpectator( )
563{
564  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
565  this->bShowTeamChange = false;
566}
567
568void MultiplayerTeamDeathmatch::assignPlayable( )
569{
570  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
571    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
572}
573
574
575/**
576 * function that processes events from the handler
577 * @param event: the event
578 * @todo replace SDLK_o with something from KeyMapper
579 */
580void MultiplayerTeamDeathmatch::process( const Event & event )
581{
582  if ( event.type == SDLK_o )
583  {
584    if ( event.bPressed )
585      this->bShowTeamChange = true;
586  } else if ( event.type == SDLK_F1 )
587  {
588    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed )
589    {
590      PRINTF(5)("hide stats\n");
591      this->hideStats();
592    }
593    else if ( !this->statsBox && event.bPressed )
594    {
595      PRINTF(5)("show stats\n");
596      this->showStats();
597    }
598  }
599  else if ( event.type == SDLK_TAB )
600  {
601    if ( currentGameState == GAMESTATE_GAME && event.bPressed && !EventHandler::getInstance()->isPressed( SDLK_RALT ) && !EventHandler::getInstance()->isPressed( SDLK_LALT ) )
602    {
603      EventHandler::getInstance()->pushState( ES_MENU );
604      OrxGui::GLGuiHandler::getInstance()->activateCursor();
605      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
606      input->show();
607      input->giveMouseFocus();
608      input->setText("say ");
609    }
610  }
611  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
612  {
613    this->hideStats();
614  }
615}
616
617void MultiplayerTeamDeathmatch::onButtonCancel( )
618{
619  this->bShowTeamChange = false;
620}
621
622
623
624/**
625 * this method is called by NetworkGameManger when he recieved a chat message
626 * @param userId senders user id
627 * @param message message string
628 * @param messageType some int
629 */
630void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
631{
632  std::string name = "unknown";
633
634  if ( PlayerStats::getStats( userId ) )
635  {
636    name = PlayerStats::getStats( userId )->getNickName();
637  }
638
639  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
640  State::getPlayer()->hud().notifyUser(name + ": " + message);
641}
642
643void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
644{
645  EventHandler::getInstance()->popState();
646  input->breakMouseFocus();
647  input->hide();
648  input->setText("");
649
650  std::string command = text;
651
652  //HACK insert " in say commands so user doesn't have to type them
653  if ( command.length() >= 4 && command[0] == 's' && command[1] == 'a' && command[2] == 'y' && command[3] == ' ' )
654  {
655    command.insert( 4, "\"" );
656    command = command + "\"";
657  }
658
659  OrxShell::ShellCommand::execute( command );
660}
661
662/**
663 * show table with frags
664 */
665void MultiplayerTeamDeathmatch::showStats( )
666{
667  statsBox = new OrxGui::GLGuiBox();
668  statsBox->setAbsCoor2D( 100, 100 );
669
670  this->table = new OrxGui::GLGuiTable(10,5);
671
672  statsBox->pack( this->table );
673
674  statsBox->showAll();
675}
676
677/**
678 * hide table with frags
679 */
680void MultiplayerTeamDeathmatch::hideStats( )
681{
682    if ( statsBox )
683    {
684      delete statsBox;
685      statsBox = NULL;
686    }
687}
688
689/**
690 * fill stats table with values
691 */
692void MultiplayerTeamDeathmatch::tickStatsTable( )
693{
694  if ( !this->statsBox )
695    return;
696
697  std::vector<std::string> headers;
698  headers.push_back("Blue Team");
699  headers.push_back("");
700  headers.push_back("");
701  headers.push_back("Red Team");
702  headers.push_back("");
703  this->table->setHeader(headers);
704
705  ScoreList scoreList = PlayerStats::getScoreList();
706
707  char st[10];
708  int i = 0;
709
710  i = 2;
711  for ( TeamScoreList::const_iterator it = scoreList[0].begin(); it != scoreList[0].end(); it++ )
712  {
713    this->table->setEntry( i, 0, it->name );
714    snprintf( st, 10, "%d", it->score );
715    this->table->setEntry( i, 1, st );
716    this->table->setEntry( i, 2, "" );
717    i++;
718  }
719
720  i = 2;
721  for ( TeamScoreList::const_iterator it = scoreList[1].begin(); it != scoreList[1].end(); it++ )
722  {
723    this->table->setEntry( i, 3, it->name );
724    snprintf( st, 10, "%d", it->score );
725    this->table->setEntry( i, 4, st );
726    i++;
727  }
728
729}
730
731/**
732 * this function is called when a player kills another one or himself
733 * @param killedUserId
734 * @param userId
735 */
736void MultiplayerTeamDeathmatch::onKill( WorldEntity * victim, WorldEntity * killer )
737{
738  if ( !victim )
739  {
740    PRINTF(0)("victim == NULL\n");
741    return;
742  }
743  if ( !killer )
744  {
745    PRINTF(0)("killer == NULL\n");
746    return;
747  }
748
749  int killerUserId = killer->getOwner();
750  int victimUserId = victim->getOwner();
751
752  PRINTF(0)("%d %d %x %x %s %s\n", killerUserId, victimUserId, killer, victim, killer->getClassCName(), victim->getClassCName());
753
754  PlayerStats & victimStats = *PlayerStats::getStats( victimUserId );
755  PlayerStats & killerStats = *PlayerStats::getStats( killerUserId );
756
757  if ( killerStats.getPlayable() == NULL || victimStats.getPlayable() == NULL)
758  {
759    PRINTF(0)("killerStats.getPlayable() != NULL || victimStats.getPlayable() != NULL\n");
760    PRINTF(0)("%x %x %x %x\n", killerStats.getPlayable(), killer, victimStats.getPlayable(), victim );
761    PRINTF(0)("%d %d %d %d\n", killerStats.getPlayable()->getUniqueID(), killer->getUniqueID(), victimStats.getPlayable()->getUniqueID(), victim->getUniqueID() );
762    return;
763  }
764
765  //check for suicide
766  if ( killerUserId != victimUserId )
767  {
768    //check for teamkill
769    if ( victimStats.getTeamId() != killerStats.getTeamId() )
770    {
771      killerStats.setScore( killerStats.getScore() + 1 );
772    }
773    else
774    {
775      killerStats.setScore( killerStats.getScore() - 1 );
776    }
777  }
778  else
779    killerStats.setScore( killerStats.getScore() - 1 );
780
781  if ( victimUserId == SharedNetworkData::getInstance()->getHostID() )
782  {
783    this->bLocalPlayerDead = true;
784    this->showStats();
785  }
786
787  this->respawnPlayable( victimStats.getPlayable(), victimStats.getTeamId(), 3.0f );
788}
789
790/**
791 * this function is called on player respawn
792 * @param userId
793 */
794void MultiplayerTeamDeathmatch::onRespawn( int userId )
795{
796  if ( userId == SharedNetworkData::getInstance()->getHostID() )
797  {
798    this->bLocalPlayerDead = false;
799    this->hideStats();
800  }
801}
802
803/**
804 * this function is called on player respawn
805 * @param we
806 */
807void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
808{
809  onRespawn( we->getOwner() );
810}
811
812
813/**
814 * respawns a playable in the world via spawning points
815 * @param playable the playable to respawn
816 * @param teamId the teamId to use
817 * @param delay time delay for delayed spawning
818 */
819void MultiplayerTeamDeathmatch::respawnPlayable( Playable * playable, int teamId, float delay )
820{
821  const std::list<BaseObject*> * list = ClassList::getList( CL_SPAWNING_POINT );
822
823  assert( list );
824
825  std::vector<SpawningPoint*> spList;
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() == teamId )
832      spList.push_back( sp );
833  }
834
835  if ( spList.size() == 0 )
836  {
837    for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
838    {
839      SpawningPoint * sp = dynamic_cast<SpawningPoint*>(*it);
840
841      if ( sp->getTeamId() < 0 )
842        spList.push_back( sp );
843    }
844  }
845
846  assert( spList.size() != 0 );
847
848  int n = (int)((float)spList.size() * (float)rand()/(float)RAND_MAX);
849
850  spList[n]->pushEntity( playable, delay );
851}
852
853
Note: See TracBrowser for help on using the repository browser.