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