Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8691 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
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: Patrick Boenzli
13*/
14
15#define DEBUG_MODULE_GAME_RULES
16
17#include <map>
18
19#include "multiplayer_team_deathmatch.h"
20
21#include "util/loading/load_param.h"
22#include "util/loading/factory.h"
23
24#include "render2D/image_plane.h"
25#include "state.h"
26#include "class_list.h"
27
28#include "player.h"
29#include "playable.h"
30#include "space_ships/space_ship.h"
31
32
33#include "shared_network_data.h"
34#include "terrain.h"
35#include "class_list.h"
36#include "space_ships/space_ship.h"
37
38#include "network_game_manager.h"
39
40#include "event_handler.h"
41
42#include "glgui.h"
43
44#include "story_entity.h"
45
46
47using namespace std;
48
49
50CREATE_FACTORY(MultiplayerTeamDeathmatch, CL_MULTIPLAYER_TEAM_DEATHMATCH);
51
52
53/**
54 * constructor
55 */
56MultiplayerTeamDeathmatch::MultiplayerTeamDeathmatch(const TiXmlElement* root)
57  : NetworkGameRules(root)
58{
59  this->setClassID(CL_MULTIPLAYER_TEAM_DEATHMATCH, "MultiplayerTeamDeathmatch");
60
61  this->bLocalPlayerDead = false;
62  this->deathTimeout = 10.0f;     // 5 seconds
63  this->timeout = 0.0f;
64  this->numTeams = 2;
65  this->currentGameState = GAMESTATE_PRE_GAME;
66  this->gameStateTimer = 10.0f;
67  this->bShowTeamChange = false;
68 
69  this->box = NULL;
70
71  this->deathScreen = new ImagePlane();
72  this->deathScreen->setSize(State::getResX()/4.0, State::getResY()/4.0);
73  this->deathScreen->setAbsCoor2D(State::getResX()/2.0f, State::getResY()/2.0f);
74  this->deathScreen->setVisibility(false);
75
76  this->localPlayer = State::getPlayer();
77
78  if( root != NULL)
79    this->loadParams(root);
80 
81  subscribeEvent( ES_GAME, SDLK_o );
82}
83
84/**
85 * decontsructor
86 */
87MultiplayerTeamDeathmatch::~MultiplayerTeamDeathmatch()
88{
89  if( this->deathScreen)
90    delete this->deathScreen;
91 
92  unsubscribeEvent( ES_GAME, SDLK_o );
93}
94
95
96
97void MultiplayerTeamDeathmatch::loadParams(const TiXmlElement* root)
98{
99  GameRules::loadParams(root) ;
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");
106
107  LoadParam(root, "death-screen-image", this, MultiplayerTeamDeathmatch, setDeathScreen)
108      .describe("sets the death screen image");
109 
110  LoadParam(root, "num-teams", this, MultiplayerTeamDeathmatch, setNumTeams)
111      .describe("sets number of teams");
112
113}
114
115
116
117void MultiplayerTeamDeathmatch::setDeathScreen(const std::string& imageName)
118{
119  if( this->deathScreen)
120    this->deathScreen->setTexture(imageName);
121}
122
123
124
125/**
126 * called when the player enters the game
127 * @param player the spawned player
128 */
129void MultiplayerTeamDeathmatch::onPlayerSpawn()
130{
131  this->bLocalPlayerDead = false;
132  this->deathScreen->setVisibility(false);
133}
134
135
136/**
137 * when the player is killed
138 * @param player the killed player
139 */
140void MultiplayerTeamDeathmatch::onPlayerDeath()
141{
142  this->bLocalPlayerDead = true;
143  this->deathScreen->setVisibility(true);
144}
145
146
147/**
148 * time tick
149 * @param dt time
150 */
151void MultiplayerTeamDeathmatch::tick(float dt)
152{
153  //on client side hostId is -1 until hanshake finished
154  if ( SharedNetworkData::getInstance()->getHostID() < 0 )
155    return;
156 
157  if ( currentGameState == GAMESTATE_PRE_GAME || currentGameState == GAMESTATE_GAME )
158  {
159    if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )
160         && box == NULL
161         &&  (PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPreferedTeamId() == TEAM_NOTEAM
162         || bShowTeamChange )
163         
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     
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     
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
207       && !bShowTeamChange
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 
225  if ( !SharedNetworkData::getInstance()->isGameServer() )
226    return;
227 
228  gameStateTimer -= dt;
229  //PRINTF(0)("TICK %f\n", gameStateTimer);
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 
243  this->checkGameRules();
244
245  // is the local player dead and inactive
246  if( unlikely(this->bLocalPlayerDead))
247  {
248    this->timeout += dt;
249    PRINTF(0)("TICK DEATH: %f of %f\n", this->timeout, this->deathTimeout);
250    // long enough dead?
251    if( this->timeout >= this->deathTimeout)
252    {
253      this->timeout = 0.0f;
254      // respawn
255      PRINTF(0)("RESPAWN\n");
256      (State::getPlayer())->getPlayable()->respawn();
257    }
258  }
259}
260
261
262/**
263 * draws the stuff
264 */
265void MultiplayerTeamDeathmatch::draw()
266{
267  if( unlikely( this->bLocalPlayerDead))
268  {
269
270  }
271}
272
273
274/**
275 * check the game rules for consistency
276 */
277void MultiplayerTeamDeathmatch::checkGameRules()
278{
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}
292
293/**
294 * find group for new player
295 * @return group id
296 */
297int MultiplayerTeamDeathmatch::getTeamForNewUser()
298{
299  return TEAM_NOTEAM;
300}
301
302ClassID MultiplayerTeamDeathmatch::getPlayableClassId( int userId, int team )
303{
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 );
311}
312
313std::string MultiplayerTeamDeathmatch::getPlayableModelFileName( int userId, int team, ClassID classId )
314{
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 "";
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++ )
340  {
341    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
342
343    if ( stats.getTeamId() >= 0 )
344    {
345      teamScore[stats.getTeamId()] += stats.getScore();
346    }
347  }
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++ )
367  {
368    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
369
370    if ( stats.getTeamId() >= 0 )
371    {
372      playersInTeam[stats.getTeamId()]++;
373    }
374  }
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}
393
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}
417
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++ )
427  {
428    PlayerStats & stats = *dynamic_cast<PlayerStats*>(*it);
429
430    if ( stats.getTeamId() != stats.getPreferedTeamId() )
431    {
432      if ( stats.getPreferedTeamId() == TEAM_SPECTATOR || ( stats.getPreferedTeamId() >= 0 && stats.getPreferedTeamId() < numTeams ) )
433      {
434        teamChange( stats.getUserId() );
435      }
436    }
437  }
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);
443
444    if ( stats.getTeamId() != stats.getPreferedTeamId() )
445    {
446      if ( stats.getPreferedTeamId() == TEAM_RANDOM )
447      {
448        stats.setPreferedTeamId( getRandomTeam() );
449        teamChange( stats.getUserId() );
450      }
451    }
452  }
453}
454
455void MultiplayerTeamDeathmatch::teamChange( int userId )
456{
457  assert( PlayerStats::getStats( userId ) );
458  PlayerStats & stats = *(PlayerStats::getStats( userId ));
459 
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  }
491}
492
493void MultiplayerTeamDeathmatch::onButtonExit( )
494{
495  State::getCurrentStoryEntity()->stop();
496  this->bShowTeamChange = false;
497}
498
499void MultiplayerTeamDeathmatch::onButtonRandom( )
500{
501  NetworkGameManager::getInstance()->prefereTeam( TEAM_RANDOM );
502  this->bShowTeamChange = false;
503}
504
505void MultiplayerTeamDeathmatch::onButtonTeam0( )
506{
507  NetworkGameManager::getInstance()->prefereTeam( 0 );
508  this->bShowTeamChange = false;
509}
510
511void MultiplayerTeamDeathmatch::onButtonTeam1( )
512{
513  NetworkGameManager::getInstance()->prefereTeam( 1 );
514  this->bShowTeamChange = false;
515}
516
517void MultiplayerTeamDeathmatch::onButtonSpectator( )
518{
519  NetworkGameManager::getInstance()->prefereTeam( TEAM_SPECTATOR );
520  this->bShowTeamChange = false;
521}
522
523void MultiplayerTeamDeathmatch::assignPlayable( )
524{
525  if ( PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() ) )
526    PlayerStats::getStats( SharedNetworkData::getInstance()->getHostID() )->getPlayable();
527}
528
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}
542
543void MultiplayerTeamDeathmatch::onButtonCancel( )
544{
545  this->bShowTeamChange = false;
546}
547
548
549
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}
567
568
569
570
Note: See TracBrowser for help on using the repository browser.