Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/util/multiplayer_team_deathmatch.cc @ 9656

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

orxonox/trunk: merged the proxy bache back with no conflicts

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  {
[9656]140    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) &&
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
[9656]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
[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
[9656]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
[9656]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      {
[9656]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() );
[9656]484        teamChange( stats.getAssignedUserId() );
[7101]485      }
486    }
487  }
[8068]488}
[7101]489
[9656]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
[9656]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 );
[9656]527  stats.setTeamId( stats.getPreferedTeamId() );
[8717]528
[9656]529  playable.setTeam(stats.getPreferedTeamId());
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
[9656]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
[9656]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    {
[9656]593      PRINTF(5)("hide stats\n");
[9059]594      this->hideStats();
595    }
[9110]596    else if ( !this->statsBox && event.bPressed )
[8802]597    {
[9656]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
[9656]760  if ( killerStats.getPlayable() == NULL || victimStats.getPlayable() == NULL)
[9235]761  {
[9656]762    PRINTF(0)("killerStats.getPlayable() != NULL || victimStats.getPlayable() != NULL\n");
[9235]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
[9656]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.