Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

orxonox/trunk: merged the network branche back here
merged with command:
svn merge -r8230:HEAD https://svn.orxonox.net/orxonox/branches/network .
conflicts resolved in favour of the network branche (conflicts were in network)

File size: 13.8 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
46
[7034]47using namespace std;
48
49
[7035]50CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
51
52
[7034]53/**
54 * constructor
55 */
[7035]56MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
[8068]57  : NetworkGameRules(root)
[7035]58{
59  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
[7034]60
[7037]61  this->bLocalPlayerDead = false;
62  this->deathTimeout = 10.0f;     // 5 seconds
[7082]63  this->timeout = 0.0f;
[8068]64  this->numTeams = 2;
65  this->currentGameState = GAMESTATE_PRE_GAME;
66  this->gameStateTimer = 10.0f;
[8623]67  this->bShowTeamChange = false;
[8147]68 
69  this->box = NULL;
[7040]70
[7810]71  this->deathScreen = new ImagePlane();
[7044]72  this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0);
[7040]73  this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f);
[7044]74  this->deathScreen->setVisibility(false);
[7037]75
[7044]76  this->localPlayer = State::getPlayer();
77
[7035]78  if( root != NULL)
79    this->loadParams(root);
[8623]80 
81  subscribeEvent( ES_GAME, SDLK_o );
[7035]82}
83
[7034]84/**
85 * decontsructor
86 */
87MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
[7044]88{
89  if( this->deathScreen)
90    delete this->deathScreen;
[8623]91 
92  unsubscribeEvent( ES_GAME, SDLK_o );
[7044]93}
[7034]94
95
96
97void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
[7035]98{
[7040]99  GameRules::loadParams(root) ;
[7037]100
101  LoadParam(root, "death-penalty-timeout", this, MultiplayerTeamDeathmatch, setDeathPenaltyTimeout)
102      .describe("sets the time in seconds a player has to wait for respawn");
103
104  LoadParam(root, "max-kills", this, MultiplayerTeamDeathmatch, setMaxKills)
105      .describe("sets the maximal kills for winning condition");
[7039]106
107  LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen)
108      .describe("sets the death screen image");
[8068]109 
110  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
111      .describe("sets number of teams");
[7039]112
[7035]113}
114
115
[7039]116
[7221]117void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName)
[7039]118{
119  if( this->deathScreen)
120    this->deathScreen->setTexture(imageName);
121}
122
123
124
[7035]125/**
126 * called when the player enters the game
127 * @param player the spawned player
128 */
[7044]129void MultiplayerTeamDeathmatch::onPlayerSpawn()
[7039]130{
[7044]131  this->bLocalPlayerDead = false;
132  this->deathScreen->setVisibility(false);
[7039]133}
[7034]134
[7035]135
136/**
137 * when the player is killed
138 * @param player the killed player
139 */
[7044]140void MultiplayerTeamDeathmatch::onPlayerDeath()
[7039]141{
142  this->bLocalPlayerDead = true;
[7044]143  this->deathScreen->setVisibility(true);
[7039]144}
[7035]145
146
147/**
148 * time tick
149 * @param dt time
150 */
151void MultiplayerTeamDeathmatch::tick(float dt)
[7037]152{
[8147]153  //on client side hostId is -1 until hanshake finished
154  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
155    return;
156 
[8623]157  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
[8147]158  {
159    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
160         && box == NULL
[8623]161         &&  (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM
162         || bShowTeamChange )
163         
[8147]164       )
165    {
166      EventHandler::getInstance()->pushState( ES_MENU );
167     
168      OrxGui::GLGuiHandler::getInstance()->activateCursor();
169     
170      box = new OrxGui::GLGuiBox();
171      box->setAbsCoor2D( 300, 100 );
172     
173      OrxGui::GLGuiPushButton * buttonSpectator = new OrxGui::GLGuiPushButton("Spectator");
174      box->pack( buttonSpectator );
175      buttonSpectator->connect(SIGNAL(buttonSpectator, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonSpectator));
176     
177      OrxGui::GLGuiPushButton * buttonRandom = new OrxGui::GLGuiPushButton("Random");
178      box->pack( buttonRandom );
179      buttonRandom->connect(SIGNAL(buttonRandom, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonRandom));
180     
181      OrxGui::GLGuiPushButton * buttonTeam0 = new OrxGui::GLGuiPushButton("Blue Team");
182      box->pack( buttonTeam0 );
183      buttonTeam0->connect(SIGNAL(buttonTeam0, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam0));
184     
185      OrxGui::GLGuiPushButton * buttonTeam1 = new OrxGui::GLGuiPushButton("Red Team");
186      box->pack( buttonTeam1 );
187      buttonTeam1->connect(SIGNAL(buttonTeam1, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonTeam1));
188     
[8623]189      if ( bShowTeamChange )
190      {
191        OrxGui::GLGuiPushButton * buttonCancel = new OrxGui::GLGuiPushButton("Cancel");
192        box->pack( buttonCancel );
193        buttonCancel->connect(SIGNAL(buttonCancel, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonCancel));
194      }
195     
[8147]196      OrxGui::GLGuiPushButton * buttonExit = new OrxGui::GLGuiPushButton("Exit");
197      box->pack( buttonExit );
198      buttonExit->connect(SIGNAL(buttonExit, released), this, SLOT(MultiplayerTeamDeathmatch, onButtonExit));
199     
200      box->showAll();
201    }
202  }
203
204  if ( box != NULL
205       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
206       && PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() != TEAM_NOTEAM
[8623]207       && !bShowTeamChange
[8147]208     )
209  {
210    delete box;
211    box = NULL;
212     
213    OrxGui::GLGuiHandler::getInstance()->deactivateCursor( true );
214     
215    EventHandler::getInstance()->popState();
216  }
217 
218  if ( box != NULL )
219  {
220    OrxGui::GLGuiHandler::getInstance()->tick( dt );
221  }
222 
223  assignPlayable();
224 
[8068]225  if ( !SharedNetworkData::getInstance()->isGameServer() )
226    return;
227 
228  gameStateTimer -= dt;
[8147]229  //PRINTF(0)("TICK %f\n", gameStateTimer);
[8068]230 
231  if ( currentGameState != GAMESTATE_GAME && gameStateTimer < 0 )
232    nextGameState();
233 
234  this->currentGameState = NetworkGameManager::getInstance()->getGameState();
235 
236  if ( currentGameState == GAMESTATE_GAME )
237  {
238    handleTeamChanges();
239  }
240 
241  this->calculateTeamScore();
242 
[7039]243  this->checkGameRules();
[7035]244
[7039]245  // is the local player dead and inactive
246  if( unlikely(this->bLocalPlayerDead))
247  {
248    this->timeout += dt;
[7088]249    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
[7039]250    // long enough dead?
[7044]251    if( this->timeout >= this->deathTimeout)
[7039]252    {
253      this->timeout = 0.0f;
254      // respawn
[7079]255      PRINTF(0)("RESPAWN\n");
[7044]256      (State::getPlayer())->getPlayable()->respawn();
[7039]257    }
258  }
[7037]259}
[7035]260
[7037]261
[7035]262/**
263 * draws the stuff
264 */
265void MultiplayerTeamDeathmatch::draw()
[7039]266{
267  if( unlikely( this->bLocalPlayerDead))
268  {
[7035]269
[7039]270  }
271}
[7035]272
[7039]273
[7035]274/**
275 * check the game rules for consistency
276 */
277void MultiplayerTeamDeathmatch::checkGameRules()
[7039]278{
[8068]279  if ( !SharedNetworkData::getInstance()->isGameServer() )
280    return;
281 
282  // check for max killing count
283  for ( int i = 0; i<numTeams; i++ )
284  {
285    if ( teamScore[i] >= maxKills )
286    {
287      //team i wins
288      //TODO
289    }
290  }
291}
[7101]292
[8068]293/**
294 * find group for new player
295 * @return group id
296 */
[8147]297int MultiplayerTeamDeathmatch::getTeamForNewUser()
[8068]298{
299  return TEAM_NOTEAM;
300}
[7101]301
[8147]302ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
[8068]303{
[8147]304  if ( team == TEAM_NOTEAM || team == TEAM_SPECTATOR )
305    return CL_SPECTATOR;
306 
307  if ( team == 0 || team == 1 )
308    return CL_SPACE_SHIP;
309 
310  assert( false );
[8068]311}
[7101]312
[8147]313std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
[8068]314{
[8147]315  if ( team == 0 )
316    return "models/ships/reap_#.obj";
317  else if ( team == 1 )
318    return "models/ships/fighter.obj";
319  else
320    return "";
[8068]321}
322
323/**
324 * calculate team score
325 */
326void MultiplayerTeamDeathmatch::calculateTeamScore( )
327{
328  teamScore.clear();
329 
330  for ( int i = 0; i<numTeams; i++ )
331    teamScore[i] = 0;
332 
333   
334  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
335 
336  if ( !list )
337    return;
338 
339  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7039]340  {
[8068]341    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
342
343    if ( stats.getTeamId() >= 0 )
344    {
345      teamScore[stats.getTeamId()] += stats.getScore();
346    }
[7039]347  }
[8068]348}
349
350/**
351 * get team for player who choose to join random team
352 * @return smallest team
353 */
354int MultiplayerTeamDeathmatch::getRandomTeam( )
355{
356  std::map<int,int> playersInTeam;
357 
358  for ( int i = 0; i<numTeams; i++ )
359    playersInTeam[i] = 0;
360 
361  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
362 
363  if ( !list )
364    return 0;
365 
366  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7039]367  {
[8068]368    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
369
370    if ( stats.getTeamId() >= 0 )
371    {
372      playersInTeam[stats.getTeamId()]++;
373    }
[7039]374  }
[8068]375 
376 
377  int minPlayers = 0xFFFF;
378  int minTeam = -1;
379 
380  for ( int i = 0; i<numTeams; i++ )
381  {
382    if ( playersInTeam[i] < minPlayers )
383    {
384      minTeam = i;
385      minPlayers = playersInTeam[i];
386    }
387  }
388 
389  assert( minTeam != -1 );
390 
391  return minTeam;
392}
[7101]393
[8068]394void MultiplayerTeamDeathmatch::nextGameState( )
395{
396  if ( currentGameState == GAMESTATE_PRE_GAME )
397  {
398    NetworkGameManager::getInstance()->setGameState( GAMESTATE_GAME );
399   
400    return;
401  }
402 
403  if ( currentGameState == GAMESTATE_GAME )
404  {
405    NetworkGameManager::getInstance()->setGameState( GAMESTATE_POST_GAME );
406   
407    return;
408  }
409 
410  if ( currentGameState == GAMESTATE_POST_GAME )
411  {
412    //TODO end game
413   
414    return;
415  }
416}
[7118]417
[8068]418void MultiplayerTeamDeathmatch::handleTeamChanges( )
419{
420  const std::list<BaseObject*> * list = ClassList::getList( CL_PLAYER_STATS );
421 
422  if ( !list )
423    return;
424 
425  //first server players with choices
426  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
[7116]427  {
[8068]428    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
[7118]429
[8068]430    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7116]431    {
[8147]432      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
[7116]433      {
[8068]434        teamChange( stats.getUserId() );
[7116]435      }
436    }
437  }
[8068]438 
439  //now serve player who want join a random team
440  for ( std::list<BaseObject*>::const_iterator it = list->begin(); it != list->end(); it++ )
441  {
442    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
[7101]443
[8068]444    if ( stats.getTeamId() != stats.getPreferedTeamId() )
[7101]445    {
[8068]446      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
[7101]447      {
[8147]448        stats.setPreferedTeamId( getRandomTeam() );
[8068]449        teamChange( stats.getUserId() );
[7101]450      }
451    }
452  }
[8068]453}
[7101]454
[8068]455void MultiplayerTeamDeathmatch::teamChange( int userId )
456{
457  assert( PlayerStats::getStats( userId ) );
458  PlayerStats & stats = *(PlayerStats::getStats( userId ));
459 
[8147]460  stats.setTeamId( stats.getPreferedTeamId() );
461 
462  Playable * oldPlayable = stats.getPlayable();
463 
464 
465  ClassID playableClassId = getPlayableClassId( userId, stats.getPreferedTeamId() );
466  std::string playableModel = getPlayableModelFileName( userId, stats.getPreferedTeamId(), playableClassId );
467 
468  BaseObject * bo = Factory::fabricate( playableClassId );
469 
470  assert( bo != NULL );
471  assert( bo->isA( CL_PLAYABLE ) );
472 
473  Playable & playable = *(dynamic_cast<Playable*>(bo));
474 
475  playable.loadModel( playableModel );
476  playable.setOwner( userId );
477  playable.setUniqueID( SharedNetworkData::getInstance()->getNewUniqueID() );
478  playable.setSynchronized( true );
479 
480  stats.setTeamId( stats.getPreferedTeamId() );
481  stats.setPlayableClassId( playableClassId );
482  stats.setPlayableUniqueId( playable.getUniqueID() );
483  stats.setModelFileName( playableModel );
484 
485  if ( oldPlayable )
486  {
487    //if ( userId == SharedNetworkData::getInstance()->getHostID() )
488    //  State::getPlayer()->setPlayable( NULL );
489    delete oldPlayable;
490  }
[7039]491}
[7035]492
[8147]493void MultiplayerTeamDeathmatch::onButtonExit( )
494{
495  State::getCurrentStoryEntity()->stop();
[8623]496  this->bShowTeamChange = false;
[8147]497}
[7035]498
[8147]499void MultiplayerTeamDeathmatch::onButtonRandom( )
500{
501  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
[8623]502  this->bShowTeamChange = false;
[8147]503}
[7035]504
[8147]505void MultiplayerTeamDeathmatch::onButtonTeam0( )
506{
507  NetworkGameManager::getInstance()->prefereTeam( 0 );
[8623]508  this->bShowTeamChange = false;
[8147]509}
[7035]510
[8147]511void MultiplayerTeamDeathmatch::onButtonTeam1( )
512{
513  NetworkGameManager::getInstance()->prefereTeam( 1 );
[8623]514  this->bShowTeamChange = false;
[8147]515}
[7035]516
[8147]517void MultiplayerTeamDeathmatch::onButtonSpectator( )
518{
519  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
[8623]520  this->bShowTeamChange = false;
[8147]521}
[7035]522
[8147]523void MultiplayerTeamDeathmatch::assignPlayable( )
524{
525  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
526    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
527}
528
[8623]529  /**
530   * function that processes events from the handler
531   * @param event: the event
532   * @todo replace SDLK_o with something from KeyMapper
533   */
534void MultiplayerTeamDeathmatch::process( const Event & event )
535{
536  if ( event.type == SDLK_o )
537  {
538    if ( event.bPressed )
539      this->bShowTeamChange = true;
540  }
541}
[8147]542
[8623]543void MultiplayerTeamDeathmatch::onButtonCancel( )
544{
545  this->bShowTeamChange = false;
546}
[8147]547
548
549
[8623]550/**
551 * this method is called by NetworkGameManger when he recieved a chat message
552 * @param userId senders user id
553 * @param message message string
554 * @param messageType some int
555 */
556void MultiplayerTeamDeathmatch::handleChatMessage( int userId, const std::string & message, int messageType )
557{
558  std::string name = "unknown";
559 
560  if ( PlayerStats::getStats( userId ) )
561  {
562    name = PlayerStats::getStats( userId )->getNickName();
563  }
564 
565  PRINTF(0)("CHATMESSAGE %s: %s\n", name.c_str(), message.c_str() );
566}
[8147]567
[8623]568
569
570
Note: See TracBrowser for help on using the repository browser.