1 #include "PlayerSelectController.h"
2 #include "PlayerSelectView.h"
3 #include "PlayerSelect.h"
4 #include "Chooser.h"
5 #include "MortalNetwork.h"
6 #include "State.h"
7 #include "Backend.h"
8 #include "Event.h"
9 #include "Audio.h"
10
11 #include "TextArea.h"
12 #include "sge_tt_text.h"
13 #include "common.h"
14
15
16
17 int GetBackgroundNumber();
18
19
20
CPlayerSelectController(bool a_bNetworkGame)21 CPlayerSelectController::CPlayerSelectController( bool a_bNetworkGame )
22 {
23 m_bNetworkGame = a_bNetworkGame;
24 m_bTeamMode = SState::Team_CUSTOM == g_oState.m_enTeamMode;
25 m_poView = new CPlayerSelectView( a_bNetworkGame, m_bTeamMode );
26 }
27
28
~CPlayerSelectController()29 CPlayerSelectController::~CPlayerSelectController()
30 {
31 delete m_poView;
32 m_poView = NULL;
33 }
34
35
36
GetThisTick()37 void CPlayerSelectController::GetThisTick()
38 {
39 m_iLastTick = m_iThisTick;
40
41 while (1)
42 {
43 m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
44 if ( m_iThisTick==m_iLastTick )
45 {
46 SDL_Delay(1);
47 }
48 else
49 {
50 break;
51 }
52 }
53 }
54
55
56
HandleChatKey(SDL_Event & a_roEvent)57 bool CPlayerSelectController::HandleChatKey( SDL_Event& a_roEvent )
58 {
59 if ( !m_bNetworkGame )
60 {
61 return false;
62 }
63
64 SDLKey enKey = a_roEvent.key.keysym.sym;
65
66 if ( enKey == SDLK_PAGEUP || enKey == SDLK_KP9 )
67 {
68 m_poView->GetTextArea()->ScrollUp();
69 return true;
70 }
71 if ( enKey == SDLK_PAGEDOWN || enKey == SDLK_KP3 )
72 {
73 m_poView->GetTextArea()->ScrollDown();
74 return true;
75 }
76
77 if ( !m_bChatActive && ( SDLK_TAB == enKey
78 || SDLK_RETURN == enKey || SDLK_KP_ENTER == enKey ) )
79 {
80 // Activate chat.
81 m_acChatMsg[0] = 0;
82 m_poView->GetReadline()->Clear();
83 m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
84 m_bChatActive = true;
85 return true;
86 }
87
88 if ( !m_bChatActive )
89 {
90 return false;
91 }
92
93 if ( SDLK_ESCAPE == enKey || SDLK_TAB == enKey )
94 {
95 // Deactivate chat.
96 m_poView->GetReadline()->Clear();
97 m_bChatActive = false;
98 return true;
99 }
100
101 // other keys..
102
103 m_poView->GetReadline()->HandleKeyEvent( a_roEvent );
104 int iResult = m_poView->GetReadline()->GetResult();
105
106 if ( iResult < 0 )
107 {
108 // Escape was pressed?
109 m_poView->GetReadline()->Clear();
110 m_bChatActive = false;
111 }
112 if ( iResult > 0 )
113 {
114 if ( strlen( m_acChatMsg ) )
115 {
116 g_poNetwork->SendMsg( m_acChatMsg );
117 std::string sMsg = std::string("<") + g_oState.m_acNick + "> " + m_acChatMsg;
118 m_poView->GetTextArea()->AddString( sMsg.c_str(), C_LIGHTCYAN );
119 m_poView->GetTextArea()->Redraw();
120
121 m_acChatMsg[0] = 0;
122 m_poView->GetReadline()->Clear();
123 m_poView->GetReadline()->Restart( m_acChatMsg, strlen(m_acChatMsg), 256, C_LIGHTCYAN, C_BLACK, 255 );
124 }
125 else
126 {
127 m_poView->GetReadline()->Clear();
128 m_bChatActive = false;
129 }
130 }
131
132 return true;
133 }
134
135
136
HandleEvents()137 void CPlayerSelectController::HandleEvents()
138 {
139 SDL_Event oSdlEvent;
140 while (SDL_PollEvent(&oSdlEvent))
141 {
142 if ( m_bNetworkGame
143 && SDL_KEYDOWN == oSdlEvent.type )
144 {
145 if (HandleChatKey( oSdlEvent ))
146 {
147 continue;
148 }
149 }
150
151 if ( m_bNetworkGame
152 && SDL_KEYDOWN == oSdlEvent.type
153 && (oSdlEvent.key.keysym.sym == SDLK_RETURN || oSdlEvent.key.keysym.sym==SDLK_KP_ENTER) )
154 {
155 m_bChatActive = true;
156 continue;
157 }
158
159 SMortalEvent oEvent;
160 TranslateEvent( &oSdlEvent, &oEvent );
161
162 switch ( oEvent.m_enType )
163 {
164 case Me_QUIT:
165 g_oState.m_bQuitFlag = true;
166 break;
167
168 case Me_MENU:
169 DoMenu();
170 if ( m_bNetworkGame && g_poNetwork->IsMaster() )
171 {
172 g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iGameTime, g_oState.m_iHitPoints, GetBackgroundNumber() );
173 }
174 break;
175
176 case Me_PLAYERKEYDOWN:
177 HandleKey( oEvent.m_iPlayer, oEvent.m_iKey );
178 break;
179
180 case Me_NOTHING:
181 case Me_SKIP:
182 case Me_PLAYERKEYUP:
183 break;
184 } // end of switch statement
185 }
186 }
187
188
189
HandleKey(int a_iPlayer,int a_iKey)190 void CPlayerSelectController::HandleKey( int a_iPlayer, int a_iKey )
191 {
192 if ( m_bNetworkGame )
193 {
194 a_iPlayer = g_poNetwork->IsMaster() ? 0 : 1;
195 }
196
197 if ( !m_abPlayerActive[a_iPlayer] )
198 {
199 return;
200 }
201
202 int iSetPlayer = a_iPlayer;
203 if ( m_bTeamMode && !g_oState.m_bTeamMultiselect )
204 {
205 iSetPlayer = 0;
206 }
207
208 // MOVE THE CURSOR
209
210 if ( a_iKey < 4 )
211 {
212 g_oChooser.MoveRectangle( a_iPlayer, a_iKey );
213 FighterEnum enNewFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
214 if ( enNewFighter != g_oPlayerSelect.GetPlayerInfo( iSetPlayer ).m_enFighter )
215 {
216 Audio->PlaySample("PLAYER_SELECTION_CHANGES");
217 if ( IsFighterSelectable(enNewFighter) )
218 {
219 if ( m_bNetworkGame )
220 {
221 g_poNetwork->SendFighter( enNewFighter );
222 }
223
224 g_oPlayerSelect.SetPlayer( iSetPlayer, enNewFighter );
225 }
226 }
227 return;
228 }
229
230 // SELECT THE CURRENT FIGHTER
231
232 FighterEnum enFighter = g_oChooser.GetCurrentFighter( a_iPlayer );
233 if ( !IsFighterSelectable( enFighter ) )
234 {
235 // Current fighter cannot be selected.
236 return;
237 }
238
239 Audio->PlaySample("PLAYER_SELECTED");
240 g_oBackend.PerlEvalF( "PlayerSelected(%d);", iSetPlayer );
241 if ( m_bNetworkGame )
242 {
243 g_poNetwork->SendFighter( enFighter );
244 g_poNetwork->SendReady();
245 }
246
247 bool bKeepPlayerActive = false;
248
249 PlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo(a_iPlayer);
250 const PlayerInfo& roOtherInfo = g_oPlayerSelect.GetPlayerInfo(1-a_iPlayer);
251 int iTeamSize = roInfo.m_aenTeam.size() + 1;
252 int iOtherTeamSize = roOtherInfo.m_aenTeam.size();
253
254 if ( m_bTeamMode )
255 {
256 m_poView->AddFighterToTeam( a_iPlayer, enFighter );
257 roInfo.m_aenTeam.push_back( enFighter );
258
259 if ( g_oState.m_bTeamMultiselect )
260 {
261 SetPlayerActive( a_iPlayer, iTeamSize < g_oState.m_iTeamSize );
262 }
263 else
264 {
265 --m_iNumberOfSelectableFighters;
266 g_oChooser.MarkFighter( enFighter, a_iPlayer ? C_LIGHTMAGENTA : C_LIGHTGREEN );
267 ActivateNextPlayer( a_iPlayer );
268 }
269 }
270 else
271 {
272 roInfo.m_aenTeam.clear();
273 roInfo.m_aenTeam.push_back( enFighter );
274 SetPlayerActive( a_iPlayer, false );
275 }
276
277 }
278
279
HandleNetwork()280 void CPlayerSelectController::HandleNetwork()
281 {
282 g_poNetwork->Update();
283
284 // 1. READ CHAT MESSAGES
285
286 bool bUpdateText = false;
287 while ( g_poNetwork->IsMsgAvailable() )
288 {
289 const char* pcMsg = g_poNetwork->GetMsg();
290 int iColor = C_YELLOW;
291 if ( pcMsg[0] == '*' && pcMsg[1] == '*' && pcMsg[2] == '*' ) iColor = C_WHITE;
292 m_poView->GetTextArea()->AddString( pcMsg, iColor );
293 bUpdateText = true;
294 }
295 if ( bUpdateText )
296 {
297 Audio->PlaySample("NETWORK_MESSAGE");
298 m_poView->GetTextArea()->Redraw();
299 }
300
301 // 2. READ PLAYER SELECTION ACTIONS
302
303 bool bMaster = g_poNetwork->IsMaster();
304 int iPlayer = bMaster ? 1 : 0;
305
306 if ( !m_abPlayerActive[iPlayer] )
307 {
308 return;
309 }
310
311 FighterEnum enOldFighter = g_oPlayerSelect.GetPlayerInfo(iPlayer).m_enFighter;
312 FighterEnum enRemoteFighter = g_poNetwork->GetRemoteFighter();
313
314 if ( enOldFighter != enRemoteFighter
315 && enRemoteFighter != UNKNOWN )
316 {
317 Audio->PlaySample("PLAYER_SELECTION_CHANGES");
318 g_oPlayerSelect.SetPlayer( iPlayer, enRemoteFighter );
319 g_oChooser.SetRectangle( iPlayer, enRemoteFighter );
320 }
321
322 bool bDone = g_poNetwork->IsRemoteSideReady();
323 if ( bDone )
324 {
325 m_abPlayerActive[iPlayer] = false;
326 Audio->PlaySample("PLAYER_SELECTED");
327 g_oBackend.PerlEvalF( "PlayerSelected(%d);", iPlayer );
328
329 PlayerInfo& roInfo = g_oPlayerSelect.EditPlayerInfo( iPlayer );
330
331 roInfo.m_aenTeam.clear();
332 roInfo.m_aenTeam.push_back( enRemoteFighter );
333 SetPlayerActive( iPlayer, false );
334 }
335 }
336
337
338
MarkFighters()339 void CPlayerSelectController::MarkFighters()
340 {
341 int iNumberOfFighters = g_oBackend.GetNumberOfFighters();
342 int i;
343
344 for ( i=0; i<iNumberOfFighters; ++i )
345 {
346 FighterEnum enFighter = g_oBackend.GetFighterID( i );
347 if ( !g_oPlayerSelect.IsLocalFighterAvailable( enFighter ) )
348 {
349 g_oChooser.MarkFighter( enFighter, C_LIGHTRED );
350 }
351 else if ( !g_oPlayerSelect.IsFighterAvailable( enFighter ) )
352 {
353 g_oChooser.MarkFighter( enFighter, C_LIGHTBLUE );
354 }
355 }
356 }
357
358
359
SetPlayerActive(int a_iPlayer,bool a_bActive)360 void CPlayerSelectController::SetPlayerActive( int a_iPlayer, bool a_bActive )
361 {
362 m_abPlayerActive[a_iPlayer] = a_bActive;
363 g_oChooser.SetRectangleVisible( a_iPlayer, a_bActive );
364 }
365
366
367 /** This method finds the next player and lets him choose a fighter.
368 This only should be called in team mode without multiselect.
369 */
370
ActivateNextPlayer(int a_iCurrentPlayer)371 void CPlayerSelectController::ActivateNextPlayer( int a_iCurrentPlayer )
372 {
373 // Go in the following order:
374 // 1 2 3 4 4 3 2 1 1 2 3 4 ...
375
376 int iNextPlayer = a_iCurrentPlayer;
377
378 if ( m_iNumberOfSelectableFighters <= 0 )
379 {
380 SetPlayerActive( a_iCurrentPlayer, false );
381 return;
382 }
383
384 if ( a_iCurrentPlayer == 0 )
385 {
386 iNextPlayer = 1;
387 }
388 else if ( g_oState.m_iNumPlayers-1 == a_iCurrentPlayer )
389 {
390 iNextPlayer = a_iCurrentPlayer - 1;
391 }
392 else
393 {
394 iNextPlayer = GetTeamSize(a_iCurrentPlayer-1) > GetTeamSize(a_iCurrentPlayer+1) ?
395 a_iCurrentPlayer+1 : a_iCurrentPlayer-1;
396 }
397
398 if ( GetTeamSize(a_iCurrentPlayer) <= GetTeamSize(iNextPlayer) )
399 {
400 iNextPlayer = a_iCurrentPlayer;
401 }
402
403 if ( iNextPlayer != a_iCurrentPlayer )
404 {
405 SetPlayerActive( a_iCurrentPlayer, false );
406 }
407 SetPlayerActive( iNextPlayer, GetTeamSize(iNextPlayer) < g_oState.m_iTeamSize );
408 }
409
410
GetTeamSize(int a_iPlayer)411 int CPlayerSelectController::GetTeamSize( int a_iPlayer )
412 {
413 return g_oPlayerSelect.GetPlayerInfo( a_iPlayer ).m_aenTeam.size();
414 }
415
416
417
IsFighterSelectable(FighterEnum a_enFighter)418 bool CPlayerSelectController::IsFighterSelectable( FighterEnum a_enFighter )
419 {
420 if ( !g_oPlayerSelect.IsFighterAvailable( a_enFighter ) )
421 {
422 return false;
423 }
424
425 if ( m_bTeamMode && !g_oState.m_bTeamMultiselect && g_oPlayerSelect.IsFighterInTeam(a_enFighter) )
426 {
427 return false;
428 }
429
430 return true;
431 }
432
433
434
DoPlayerSelect()435 void CPlayerSelectController::DoPlayerSelect()
436 {
437
438 // 1. INITIALIZE
439
440 if ( SState::IN_NETWORK == g_oState.m_enGameMode )
441 {
442 g_oState.m_enTeamMode = SState::Team_ONE_VS_ONE;
443 g_oState.m_iNumPlayers = 2;
444 }
445
446 int i;
447 for ( i=0; i<g_oState.m_iNumPlayers; ++i )
448 {
449 g_oPlayerSelect.SetPlayer( i, g_oChooser.GetCurrentFighter(i) );
450 SetPlayerActive( i, !m_bTeamMode || g_oState.m_bTeamMultiselect || 0 == i );
451 }
452 m_iNumberOfSelectableFighters = g_oBackend.GetNumberOfAvailableFighters();
453 MarkFighters();
454
455 if ( m_bTeamMode )
456 {
457 for ( int i=0; i<g_oState.m_iNumPlayers; ++i )
458 {
459 g_oPlayerSelect.EditPlayerInfo(i).m_aenTeam.clear();
460 }
461 }
462
463 if ( m_bNetworkGame && g_poNetwork->IsMaster() )
464 {
465 g_poNetwork->SendGameParams( g_oState.m_iGameSpeed, g_oState.m_iGameTime, g_oState.m_iHitPoints, GetBackgroundNumber() );
466 }
467
468 g_oBackend.PerlEvalF( "SelectStart(%d);", g_oState.m_iNumPlayers );
469
470 m_bChatActive = false;
471
472 m_iGameSpeed = 12 ;
473 m_iThisTick = SDL_GetTicks() / m_iGameSpeed;
474 m_iLastTick = m_iThisTick - 1;
475
476 // 2. RUN THE PLAYER SELECTION LOOP
477
478 while (1)
479 {
480 // 2.1. Wait for the next tick (on extremely fast machines..)
481 GetThisTick();
482 int iAdvance = m_iThisTick - m_iLastTick;
483 if ( iAdvance > 5 )
484 iAdvance = 5;
485
486 // 2.2. Handle events
487 HandleEvents();
488 if ( m_bNetworkGame )
489 {
490 HandleNetwork();
491 }
492
493 // 2.3. Update the view
494 m_poView->Advance( iAdvance );
495 m_poView->Draw();
496
497 if ( g_oState.m_bQuitFlag || SState::IN_DEMO == g_oState.m_enGameMode)
498 break;
499
500 //@ FIX THIS
501
502 if ( !m_abPlayerActive[0] && !m_abPlayerActive[1] && m_poView->IsOver() )
503 break;
504 }
505 }
506