Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

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

File size: 21.2 KB
RevLine 
[7034]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
[8068]17#include <map>
18
[7034]19#include "multiplayer_team_deathmatch.h"
20
[7193]21#include "util/loading/load_param.h"
22#include "util/loading/factory.h"
[7034]23
[7810]24#include "render2D/image_plane.h"
[7039]25#include "state.h"
[7101]26#include "class_list.h"
[7034]27
[7044]28#include "player.h"
29#include "playable.h"
[7101]30#include "space_ships/space_ship.h"
[7039]31
[7116]32
[7101]33#include "shared_network_data.h"
[7116]34#include "terrain.h"
35#include "class_list.h"
36#include "space_ships/space_ship.h"
[7044]37
[8068]38#include "network_game_manager.h"
[7101]39
[8147]40#include "event_handler.h"
[8068]41
[8147]42#include "glgui.h"
43
44#include "story_entity.h"
45
[8708]46#include "shell_command.h"
[8147]47
[8802]48#include "spawning_point.h"
[8708]49
[8802]50
[7034]51
52
[9406]53
[7035]54CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
55
56
[7034]57/**
58 * constructor
59 */
[7035]60MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
[8068]61  : NetworkGameRules(root)
[7035]62{
63  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
[7034]64
[7037]65  this->bLocalPlayerDead = false;
66  this->deathTimeout = 10.0f;     // 5 seconds
[7082]67  this->timeout = 0.0f;
[8068]68  this->numTeams = 2;
69  this->currentGameState = GAMESTATE_PRE_GAME;
[9008]70  this->gameStateTimer = 3.0f;
[8623]71  this->bShowTeamChange = false;
[8717]72
[8147]73  this->box = NULL;
[8802]74  this->table = NULL;
75  this->statsBox = NULL;
[7040]76
[7044]77  this->localPlayer = State::getPlayer();
78
[7035]79  if( root != NULL)
80    this->loadParams(root);
[8717]81
[8623]82  subscribeEvent( ES_GAME, SDLK_o );
[8708]83  subscribeEvent( ES_GAME, SDLK_TAB );
[8802]84  subscribeEvent( ES_GAME, SDLK_F1 );
85  subscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
[9008]86
[8708]87  this->input = new OrxGui::GLGuiInputLine();
88  this->input->setAbsCoor2D(180, 5);
[9406]89  this->input->enterPushed.connect(this, &MultiplayerTeamDeathmatch::onInputEnter);
[7035]90}
91
[7034]92/**
93 * decontsructor
94 */
95MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
[7044]96{
[8623]97  unsubscribeEvent( ES_GAME, SDLK_o );
[8708]98  unsubscribeEvent( ES_GAME, SDLK_TAB );
[8802]99  unsubscribeEvent( ES_GAME, SDLK_F1 );
100  unsubscribeEvent( ES_MENU, KeyMapper::PEV_FIRE1 );
[9008]101
[8708]102  if ( this->input )
103  {
104    delete this->input;
105    this->input = NULL;
106  }
[7044]107}
[7034]108
109
110
111void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
[7035]112{
[7040]113  GameRules::loadParams(root) ;
[7037]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");
[7039]120
[8068]121  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
122      .describe("sets number of teams");
[7039]123
[7035]124}
125
126
127/**
128 * time tick
129 * @param dt time
130 */
131void MultiplayerTeamDeathmatch::tick(float dt)
[7037]132{
[8802]133  tickStatsTable();
[8147]134  //on client side hostId is -1 until hanshake finished
135  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
136    return;
[8717]137
[8623]138  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
[8147]139  {
[9565]140    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) &&
[9564]141         box == NULL &&
142         (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM || bShowTeamChange )
[8717]143
[8147]144       )
145    {
146      EventHandler::getInstance()->pushState( ES_MENU );
[8717]147
[8147]148      OrxGui::GLGuiHandler::getInstance()->activateCursor();
[8717]149
[8147]150      box = new OrxGui::GLGuiBox();
151      box->setAbsCoor2D( 300, 100 );
[8717]152
[9494]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);
[8717]158
[9494]159        OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
160        box->pack( buttonRandom );
161        buttonRandom->released.connect(this, &MultiplayerTeamDeathmatch::onButtonRandom);
[8717]162
[9494]163        OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
164        box->pack( buttonTeam0 );
165        buttonTeam0->released.connect(this, &MultiplayerTeamDeathmatch::onButtonTeam0);
[8717]166
[9494]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      }
[8717]177
[9494]178
[8623]179      if ( bShowTeamChange )
180      {
181        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
182        box->pack( buttonCancel );
[9406]183        buttonCancel->released.connect(this, &MultiplayerTeamDeathmatch::onButtonCancel);
[8623]184      }
[8717]185
[8147]186      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
187      box->pack( buttonExit );
[9406]188      buttonExit->released.connect(this, &MultiplayerTeamDeathmatch::onButtonExit);
[8717]189
[8147]190      box->showAll();
191    }
192  }
193
[9580]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//   }
[9574]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
[8147]204     )
205  {
206    delete box;
207    box = NULL;
[8717]208
[8147]209    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
[8717]210
[8147]211    EventHandler::getInstance()->popState();
212  }
[8717]213
[8147]214  if ( box != NULL )
215  {
216    OrxGui::GLGuiHandler::getInstance()->tick( dt );
217  }
[8717]218
[8147]219  assignPlayable();
[8717]220
[9494]221  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
[8068]222    return;
[9008]223
[8802]224  //handle kills
[9008]225  while ( this->killList.begin() != this->killList.end() )
[8802]226  {
[9235]227    PRINTF(0)("KKKKKKKKIIIIIIIIILLLLLLLLLLLLL\n");
[9008]228    onKill( this->killList.begin()->getVictim(), this->killList.begin()->getKiller() );
229    this->killList.erase( this->killList.begin() );
[8802]230  }
[9008]231
232
[9406]233
[8068]234  gameStateTimer -= dt;
[8147]235  //PRINTF(0)("TICK %f\n", gameStateTimer);
[8717]236
[8068]237  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
238    nextGameState();
[8717]239
[8068]240  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
[8717]241
[8068]242  if ( currentGameState == GAMESTATE_GAME )
243  {
244    handleTeamChanges();
245  }
[8717]246
[8068]247  this->calculateTeamScore();
[8717]248
[7039]249  this->checkGameRules();
[7035]250
[7039]251  // is the local player dead and inactive
252  if( unlikely(this->bLocalPlayerDead))
253  {
254    this->timeout += dt;
[7088]255    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
[7039]256    // long enough dead?
[7044]257    if( this->timeout >= this->deathTimeout)
[7039]258    {
259      this->timeout = 0.0f;
260      // respawn
[7079]261      PRINTF(0)("RESPAWN\n");
[7044]262      (State::getPlayer())->getPlayable()->respawn();
[7039]263    }
264  }
[7037]265}
[7035]266
[7037]267
[7035]268/**
269 * draws the stuff
270 */
271void MultiplayerTeamDeathmatch::draw()
[7039]272{
273  if( unlikely( this->bLocalPlayerDead))
274  {
[7035]275
[7039]276  }
277}
[7035]278
[7039]279
[7035]280/**
281 * check the game rules for consistency
282 */
283void MultiplayerTeamDeathmatch::checkGameRules()
[7039]284{
[9494]285  if ( SharedNetworkData::getInstance()->isClient() || SharedNetworkData::getInstance()->isProxyServerActive())
[8068]286    return;
[8717]287
[8068]288  // check for max killing count
289  for ( int i = 0; i<numTeams; i++ )
290  {
291    if ( teamScore[i] >= maxKills )
292    {
[8802]293      nextGameState();
[8068]294    }
295  }
296}
[7101]297
[8068]298/**
299 * find group for new player
300 * @return group id
301 */
[8147]302int MultiplayerTeamDeathmatch::getTeamForNewUser()
[8068]303{
304  return TEAM_NOTEAM;
305}
[7101]306
[8147]307ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
[8068]308{
[8147]309  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
310    return CL_SPECTATOR;
[8717]311
[8147]312  if ( team == 0 || team == 1 )
[9494]313    return CL_TURBINE_HOVER;
[8717]314
[8147]315  assert( false );
[8068]316}
[7101]317
[9574]318
[8147]319std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
[8068]320{
[9494]321  if (classId == CL_TURBINE_HOVER)
322   return "models/ships/hoverglider_mainbody.obj";
[8147]323  if ( team == 0 )
[9059]324    return "models/creatures/doom_guy.md2";
[8147]325  else if ( team == 1 )
[9235]326    return "models/creatures/male.md2";
[8147]327  else
328    return "";
[8068]329}
330
[9235]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  }
[9406]340
[9235]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  }
[9406]350
[9235]351  return 1.0f;
352}
353
[8068]354/**
355 * calculate team score
356 */
357void MultiplayerTeamDeathmatch::calculateTeamScore( )
358{
359  teamScore.clear();
[8717]360
[8068]361  for ( int i = 0; i<numTeams; i++ )
362    teamScore[i] = 0;
[8717]363
364
[8068]365  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
[8717]366
[8068]367  if ( !list )
368    return;
[8717]369
[8068]370  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7039]371  {
[8068]372    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
373
374    if ( stats.getTeamId() >= 0 )
375    {
376      teamScore[stats.getTeamId()] += stats.getScore();
377    }
[7039]378  }
[8068]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;
[8717]388
[8068]389  for ( int i = 0; i<numTeams; i++ )
390    playersInTeam[i] = 0;
[8717]391
[8068]392  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
[8717]393
[8068]394  if ( !list )
395    return 0;
[8717]396
[8068]397  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7039]398  {
[8068]399    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
400
401    if ( stats.getTeamId() >= 0 )
402    {
403      playersInTeam[stats.getTeamId()]++;
404    }
[7039]405  }
[8717]406
407
[8068]408  int minPlayers = 0xFFFF;
409  int minTeam = -1;
[8717]410
[8068]411  for ( int i = 0; i<numTeams; i++ )
412  {
413    if ( playersInTeam[i] < minPlayers )
414    {
415      minTeam = i;
416      minPlayers = playersInTeam[i];
417    }
418  }
[8717]419
[8068]420  assert( minTeam != -1 );
[8717]421
[8068]422  return minTeam;
423}
[7101]424
[8068]425void MultiplayerTeamDeathmatch::nextGameState( )
426{
427  if ( currentGameState == GAMESTATE_PRE_GAME )
428  {
429    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
[8717]430
[8068]431    return;
432  }
[8717]433
[8068]434  if ( currentGameState == GAMESTATE_GAME )
435  {
436    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
[8717]437
[8068]438    return;
439  }
[8717]440
[8068]441  if ( currentGameState == GAMESTATE_POST_GAME )
442  {
[9235]443    //State::getCurrentStoryEntity()->stop();
[8802]444    this->bShowTeamChange = false;
[8717]445
[8068]446    return;
447  }
448}
[7118]449
[9574]450/**
451 *  this handles team changes but only on the master server
452 */
[8068]453void MultiplayerTeamDeathmatch::handleTeamChanges( )
454{
455  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
[8717]456
[8068]457  if ( !list )
458    return;
[8717]459
[8068]460  //first server players with choices
461  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7116]462  {
[8068]463    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
[7118]464
[8068]465    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7116]466    {
[8147]467      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
[7116]468      {
[9574]469        teamChange( stats.getAssignedUserId() );
[7116]470      }
471    }
472  }
[8717]473
[8068]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);
[7101]478
[8068]479    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7101]480    {
[8068]481      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
[7101]482      {
[8147]483        stats.setPreferedTeamId( getRandomTeam() );
[9574]484        teamChange( stats.getAssignedUserId() );
[7101]485      }
486    }
487  }
[8068]488}
[7101]489
[9574]490
491
492/**
493 * changes the team
494 * @param userId the user changing team (userId)
495 */
[8068]496void MultiplayerTeamDeathmatch::teamChange( int userId )
497{
498  assert( PlayerStats::getStats( userId ) );
499  PlayerStats & stats = *(PlayerStats::getStats( userId ));
[8717]500
[8147]501  stats.setTeamId( stats.getPreferedTeamId() );
[8717]502
[8147]503  Playable * oldPlayable = stats.getPlayable();
[8717]504
505
[9574]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 );
[8717]510
[8147]511  BaseObject * bo = Factory::fabricate( playableClassId );
[8717]512
[8147]513  assert( bo != NULL );
514  assert( bo->isA( CL_PLAYABLE ) );
[8717]515
[8147]516  Playable & playable = *(dynamic_cast<Playable*>(bo));
[8717]517
[9235]518  playable.loadMD2Texture( playableTexture );
519  playable.loadModel( playableModel, playableScale );
[8147]520  playable.setOwner( userId );
521  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
522  playable.setSynchronized( true );
[8717]523
[8147]524  stats.setPlayableClassId( playableClassId );
525  stats.setPlayableUniqueId( playable.getUniqueID() );
526  stats.setModelFileName( playableModel );
[9504]527  stats.setTeamId( stats.getPreferedTeamId() );
[8717]528
[9594]529  playable.setTeam(stats.getPreferedTeamId());
[9504]530
531
[9008]532  this->respawnPlayable( &playable, stats.getPreferedTeamId(), 0.0f );
533
[8147]534  if ( oldPlayable )
535  {
536    delete oldPlayable;
537  }
[7039]538}
[7035]539
[9574]540
[8147]541void MultiplayerTeamDeathmatch::onButtonExit( )
542{
543  State::getCurrentStoryEntity()->stop();
[8623]544  this->bShowTeamChange = false;
[8147]545}
[7035]546
[8147]547void MultiplayerTeamDeathmatch::onButtonRandom( )
548{
549  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
[8623]550  this->bShowTeamChange = false;
[8147]551}
[7035]552
[8147]553void MultiplayerTeamDeathmatch::onButtonTeam0( )
554{
555  NetworkGameManager::getInstance()->prefereTeam( 0 );
[8623]556  this->bShowTeamChange = false;
[8147]557}
[7035]558
[8147]559void MultiplayerTeamDeathmatch::onButtonTeam1( )
560{
561  NetworkGameManager::getInstance()->prefereTeam( 1 );
[8623]562  this->bShowTeamChange = false;
[8147]563}
[7035]564
[8147]565void MultiplayerTeamDeathmatch::onButtonSpectator( )
566{
567  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
[8623]568  this->bShowTeamChange = false;
[8147]569}
[7035]570
[8147]571void MultiplayerTeamDeathmatch::assignPlayable( )
572{
573  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
574    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
575}
576
[9574]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 */
[8623]583void MultiplayerTeamDeathmatch::process( const Event & event )
584{
585  if ( event.type == SDLK_o )
586  {
587    if ( event.bPressed )
588      this->bShowTeamChange = true;
[8802]589  } else if ( event.type == SDLK_F1 )
590  {
[9059]591    if ( this->statsBox && !this->bLocalPlayerDead && event.bPressed )
592    {
[9575]593      PRINTF(5)("hide stats\n");
[9059]594      this->hideStats();
595    }
[9110]596    else if ( !this->statsBox && event.bPressed )
[8802]597    {
[9575]598      PRINTF(5)("show stats\n");
[8802]599      this->showStats();
600    }
[8623]601  }
[8708]602  else if ( event.type == SDLK_TAB )
603  {
[9008]604    if ( currentGameState == GAMESTATE_GAME && event.bPressed && !EventHandler::getInstance()->isPressed( SDLK_RALT ) && !EventHandler::getInstance()->isPressed( SDLK_LALT ) )
[8708]605    {
606      EventHandler::getInstance()->pushState( ES_MENU );
607      OrxGui::GLGuiHandler::getInstance()->activateCursor();
608      OrxGui::GLGuiHandler::getInstance()->deactivateCursor();
609      input->show();
[8717]610      input->giveMouseFocus();
[8708]611      input->setText("say ");
612    }
613  }
[8802]614  else if ( this->bLocalPlayerDead && statsBox && event.type == KeyMapper::PEV_FIRE1 )
615  {
616    this->hideStats();
617  }
[8623]618}
[8147]619
[8623]620void MultiplayerTeamDeathmatch::onButtonCancel( )
621{
622  this->bShowTeamChange = false;
623}
[8147]624
625
626
[8623]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";
[8717]636
[8623]637  if ( PlayerStats::getStats( userId ) )
638  {
639    name = PlayerStats::getStats( userId )->getNickName();
640  }
[8717]641
[8708]642  PRINTF(0)("CHATMESSAGE %s (%d): %s\n", name.c_str(), userId, message.c_str() );
[9059]643  State::getPlayer()->hud().notifyUser(name + ": " + message);
[8623]644}
[8147]645
[8708]646void MultiplayerTeamDeathmatch::onInputEnter( const std::string & text )
647{
648  EventHandler::getInstance()->popState();
[8717]649  input->breakMouseFocus();
[8708]650  input->hide();
651  input->setText("");
[8623]652
[8708]653  std::string command = text;
[8717]654
[8708]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  }
[8623]661
[8708]662  OrxShell::ShellCommand::execute( command );
663}
[8623]664
[8802]665/**
666 * show table with frags
667 */
668void MultiplayerTeamDeathmatch::showStats( )
669{
670  statsBox = new OrxGui::GLGuiBox();
[9110]671  statsBox->setAbsCoor2D( 100, 100 );
[9008]672
[9110]673  this->table = new OrxGui::GLGuiTable(10,5);
[8708]674
[8802]675  statsBox->pack( this->table );
[8708]676
[8802]677  statsBox->showAll();
678}
[8708]679
[8802]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;
[9110]701  headers.push_back("Blue Team");
[8802]702  headers.push_back("");
703  headers.push_back("");
[9110]704  headers.push_back("Red Team");
[8802]705  headers.push_back("");
706  this->table->setHeader(headers);
[9008]707
[9110]708  ScoreList scoreList = PlayerStats::getScoreList();
[9008]709
[8802]710  char st[10];
711  int i = 0;
[9406]712
[8802]713  i = 2;
[9110]714  for ( TeamScoreList::const_iterator it = scoreList[0].begin(); it != scoreList[0].end(); it++ )
[8802]715  {
[9110]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, "" );
[8802]720    i++;
721  }
[9008]722
[8802]723  i = 2;
[9110]724  for ( TeamScoreList::const_iterator it = scoreList[1].begin(); it != scoreList[1].end(); it++ )
[8802]725  {
[9110]726    this->table->setEntry( i, 3, it->name );
727    snprintf( st, 10, "%d", it->score );
728    this->table->setEntry( i, 4, st );
[8802]729    i++;
730  }
[9110]731
[8802]732}
733
734/**
735 * this function is called when a player kills another one or himself
[9008]736 * @param killedUserId
737 * @param userId
[8802]738 */
[9008]739void MultiplayerTeamDeathmatch::onKill( WorldEntity * victim, WorldEntity * killer )
[8802]740{
[9008]741  if ( !victim )
[9235]742  {
743    PRINTF(0)("victim == NULL\n");
[9008]744    return;
[9235]745  }
[9008]746  if ( !killer )
[9235]747  {
748    PRINTF(0)("killer == NULL\n");
[9008]749    return;
[9235]750  }
[9406]751
[9008]752  int killerUserId = killer->getOwner();
753  int victimUserId = victim->getOwner();
754
[9406]755  PRINTF(0)("%d %d %x %x %s %s\n", killerUserId, victimUserId, killer, victim, killer->getClassCName(), victim->getClassCName());
756
[9008]757  PlayerStats & victimStats = *PlayerStats::getStats( victimUserId );
758  PlayerStats & killerStats = *PlayerStats::getStats( killerUserId );
[9406]759
[9008]760  if ( killerStats.getPlayable() != killer || victimStats.getPlayable() != victim )
[9235]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() );
[9008]765    return;
[9235]766  }
[9008]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  }
[8802]781  else
[9008]782    killerStats.setScore( killerStats.getScore() - 1 );
783
784  if ( victimUserId == SharedNetworkData::getInstance()->getHostID() )
[8802]785  {
786    this->bLocalPlayerDead = true;
787    this->showStats();
788  }
[9008]789
790  this->respawnPlayable( victimStats.getPlayable(), victimStats.getTeamId(), 3.0f );
[8802]791}
792
793/**
794 * this function is called on player respawn
[9008]795 * @param userId
[8802]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
[9008]808 * @param we
[8802]809 */
810void MultiplayerTeamDeathmatch::registerSpawn( WorldEntity * we )
811{
812  onRespawn( we->getOwner() );
813}
814
[9008]815
[9565]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 */
[9008]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
[9110]856
Note: See TracBrowser for help on using the repository browser.