00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "game_loop.h"
00023 #include <SDL.h>
00024 #include <SDL_image.h>
00025 #include <sstream>
00026 #include <iostream>
00027 #include "config.h"
00028 #include "game.h"
00029 #include "game_mode.h"
00030 #include "time.h"
00031 #include "../ai/ai_engine.h"
00032 #include "../graphic/fps.h"
00033 #include "../graphic/video.h"
00034 #include "../include/action_handler.h"
00035 #include "../include/app.h"
00036 #include "../include/constant.h"
00037 #include "../interface/cursor.h"
00038 #include "../interface/game_msg.h"
00039 #include "../interface/interface.h"
00040 #include "../interface/keyboard.h"
00041 #include "../interface/loading_screen.h"
00042 #include "../interface/mouse.h"
00043 #include "../map/camera.h"
00044 #include "../map/map.h"
00045 #include "../map/maps_list.h"
00046 #include "../map/wind.h"
00047 #include "../network/network.h"
00048 #include "../network/randomsync.h"
00049 #include "../object/bonus_box.h"
00050 #include "../object/objects_list.h"
00051 #include "../particles/particle.h"
00052 #include "../sound/jukebox.h"
00053 #include "../team/macro.h"
00054 #include "../tool/debug.h"
00055 #include "../tool/i18n.h"
00056 #include "../tool/stats.h"
00057 #include "../weapon/weapons_list.h"
00058
00059
00060 #define ENABLE_LIMIT_FPS
00061
00062 bool game_fin_partie;
00063
00064 GameLoop * GameLoop::singleton = NULL;
00065
00066 GameLoop * GameLoop::GetInstance()
00067 {
00068 if (singleton == NULL) {
00069 singleton = new GameLoop();
00070 }
00071 return singleton;
00072 }
00073
00074 GameLoop::GameLoop()
00075 {
00076 state = PLAYING;
00077 interaction_enabled = true;
00078 }
00079
00080 void GameLoop::InitGameData_NetServer()
00081 {
00082 network.client_inited = 1;
00083 AppWormux * app = AppWormux::GetInstance();
00084 app->video.SetWindowCaption( std::string("Wormux ") + Constants::VERSION + " - Server mode");
00085
00086 ActionHandler * action_handler = ActionHandler::GetInstance();
00087
00088 network.RejectIncoming();
00089
00090 Action a_change_state(Action::ACTION_CHANGE_STATE);
00091 network.SendAction ( &a_change_state );
00092 network.state = Network::NETWORK_INIT_GAME;
00093
00094 SendGameMode();
00095
00096 world.Reset();
00097
00098 randomSync.Init();
00099
00100 lst_objects.PlaceBarrels();
00101
00102 std::cout << "o " << _("Initialise teams") << std::endl;
00103 teams_list.LoadGamingData(GameMode::GetInstance()->max_characters);
00104
00105 lst_objects.PlaceMines();
00106 std::cout << "o " << _("Initialise data") << std::endl;
00107 CharacterCursor::GetInstance()->Reset();
00108 Mouse::GetInstance()->Reset();
00109 fps.Reset();
00110 Interface::GetInstance()->Reset();
00111 GameMessages::GetInstance()->Reset();
00112
00113
00114 network.SendAction ( &a_change_state );
00115
00116
00117 while (network.state != Network::NETWORK_READY_TO_PLAY)
00118 {
00119 action_handler->ExecActions();
00120 SDL_Delay(200);
00121 }
00122 network.SendAction ( &a_change_state );
00123 network.state = Network::NETWORK_PLAYING;
00124 }
00125
00126 void GameLoop::InitGameData_NetClient()
00127 {
00128 AppWormux * app = AppWormux::GetInstance();
00129 app->video.SetWindowCaption( std::string("Wormux ") + Constants::VERSION + " - Client mode");
00130 ActionHandler * action_handler = ActionHandler::GetInstance();
00131 std::cout << "o " << _("Initialise teams") << std::endl;
00132
00133 world.Reset();
00134
00135 lst_objects.PlaceBarrels();
00136 teams_list.LoadGamingData(GameMode::GetInstance()->max_characters);
00137 lst_objects.PlaceMines();
00138
00139 Action a_change_state(Action::ACTION_CHANGE_STATE);
00140
00141 network.SendAction (&a_change_state);
00142 while (network.state != Network::NETWORK_READY_TO_PLAY)
00143 {
00144
00145
00146 action_handler->ExecActions();
00147 SDL_Delay(100);
00148 }
00149
00150 std::cout << network.state << " : Waiting for people over the network" << std::endl;
00151 while (network.state != Network::NETWORK_PLAYING)
00152 {
00153
00154 action_handler->ExecActions();
00155 SDL_Delay(100);
00156 }
00157 std::cout << network.state << " : Run game !" << std::endl;
00158 }
00159
00160 void GameLoop::InitData_Local()
00161 {
00162 std::cout << "o " << _("Find a random position for characters") << std::endl;
00163 world.Reset();
00164 MapsList::GetInstance()->ActiveMap().FreeData();
00165 lst_objects.PlaceBarrels();
00166 teams_list.LoadGamingData(0);
00167
00168 std::cout << "o " << _("Initialise objects") << std::endl;
00169 lst_objects.PlaceMines();
00170 }
00171
00172 void GameLoop::InitData()
00173 {
00174 Time::GetInstance()->Reset();
00175
00176 if (network.IsServer())
00177 InitGameData_NetServer();
00178 else if (network.IsClient())
00179 InitGameData_NetClient();
00180 else
00181 InitData_Local();
00182
00183 CharacterCursor::GetInstance()->Reset();
00184 Mouse::GetInstance()->Reset();
00185 Config::GetInstance()->GetKeyboard()->Reset();
00186
00187 fps.Reset();
00188 if(network.IsConnected())
00189 chatsession.Reset();
00190 Interface::GetInstance()->Reset();
00191 GameMessages::GetInstance()->Reset();
00192 ParticleEngine::Init();
00193 }
00194
00195 void GameLoop::Init ()
00196 {
00197
00198 LoadingScreen::GetInstance()->DrawBackground();
00199
00200 Game::GetInstance()->MessageLoading();
00201
00202
00203 std::cout << "o " << _("Initialisation") << std::endl;
00204
00205
00206 LoadingScreen::GetInstance()->StartLoading(1, "map_icon", _("Maps"));
00207 InitData();
00208
00209
00210 LoadingScreen::GetInstance()->StartLoading(2, "team_icon", _("Teams"));
00211
00212
00213 if (teams_list.playing_list.size() < 2)
00214 Error(_("You need at least two teams to play: "
00215 "change this in 'Options menu' !"));
00216 assert (teams_list.playing_list.size() <= GameMode::GetInstance()->max_teams);
00217
00218
00219 LoadingScreen::GetInstance()->StartLoading(3, "weapon_icon", _("Weapons"));
00220
00221 teams_list.InitEnergy();
00222
00223
00224 LoadingScreen::GetInstance()->StartLoading(4, "sound_icon", _("Sounds"));
00225
00226 jukebox.LoadXML("default");
00227 FOR_EACH_TEAM(team)
00228 if ( (**team).GetSoundProfile() != "default" )
00229 jukebox.LoadXML((**team).GetSoundProfile()) ;
00230
00231
00232
00233 if (jukebox.UseMusic()) jukebox.Play ("share", "music/grenouilles", -1);
00234
00235 Game::GetInstance()->SetEndOfGameStatus( false );
00236
00237 Mouse::GetInstance()->SetPointer(Mouse::POINTER_SELECT);
00238
00239
00240 ActiveTeam().AccessWeapon().Select();
00241
00242 SetState(PLAYING, true);
00243 }
00244
00245 void GameLoop::RefreshInput()
00246 {
00247
00248 SDL_Event event;
00249
00250 while(SDL_PollEvent(&event)) {
00251 if ( event.type == SDL_QUIT) {
00252 std::cout << "SDL_QUIT received ===> exit TODO" << std::endl;
00253 Game::GetInstance()->SetEndOfGameStatus( true );
00254 std::cout << "FIN PARTIE" << std::endl;
00255 return;
00256 }
00257 if ( event.type == SDL_MOUSEBUTTONDOWN ) {
00258 Mouse::GetInstance()->TraiteClic( &event);
00259 }
00260 if ( event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) {
00261 if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE) {
00262 Game::GetInstance()->SetEndOfGameStatus( true );
00263 std::cout << "FIN PARTIE" << std::endl;
00264 return;
00265 }
00266 Config::GetInstance()->GetKeyboard()->HandleKeyEvent( &event);
00267 }
00268 }
00269
00270 if (!Time::GetInstance()->IsGamePaused()) {
00271
00272 if ((interaction_enabled && state != END_TURN) ||
00273 (ActiveTeam().GetWeapon().IsActive() &&
00274 ActiveTeam().GetWeapon().override_keys)) {
00275 Mouse::GetInstance()->Refresh();
00276 Config::GetInstance()->GetKeyboard()->Refresh();
00277 AIengine::GetInstance()->Refresh();
00278 }
00279
00280 do {
00281 ActionHandler::GetInstance()->ExecActions();
00282 if(network.sync_lock) SDL_Delay(SDL_TIMESLICE);
00283 } while(network.sync_lock);
00284 }
00285 GameMessages::GetInstance()->Refresh();
00286 camera.Refresh();
00287 }
00288
00289 void GameLoop::RefreshObject()
00290 {
00291 if (!Time::GetInstance()->IsGamePaused()) {
00292 FOR_ALL_CHARACTERS(team,character)
00293 character->Refresh();
00294
00295 FOR_EACH_TEAM(team)
00296 (**team).Refresh();
00297 teams_list.RefreshEnergy();
00298
00299 ActiveTeam().AccessWeapon().Manage();
00300 lst_objects.Refresh();
00301 ParticleEngine::Refresh();
00302 CharacterCursor::GetInstance()->Refresh();
00303 }
00304 }
00305
00306 void GameLoop::Draw ()
00307 {
00308
00309 StatStart("GameDraw:sky");
00310 world.DrawSky();
00311 StatStop("GameDraw:sky");
00312
00313
00314 StatStart("GameDraw:world");
00315 world.Draw();
00316 StatStop("GameDraw:world");
00317
00318
00319 StatStart("GameDraw:characters");
00320 FOR_ALL_CHARACTERS(team,character)
00321 if (!character->IsActiveCharacter())
00322 character->Draw();
00323
00324 StatStart("GameDraw:particles_behind_active_character");
00325 ParticleEngine::Draw(false);
00326 StatStop("GameDraw:particles_behind_active_character");
00327
00328 StatStart("GameDraw:active_character");
00329 ActiveCharacter().Draw();
00330 if (!ActiveCharacter().IsDead() && state != END_TURN) {
00331 ActiveTeam().crosshair.Draw();
00332 ActiveTeam().AccessWeapon().Draw();
00333 }
00334 StatStop("GameDraw:active_character");
00335 StatStop("GameDraw:characters");
00336
00337
00338 StatStart("GameDraw:objects");
00339 lst_objects.Draw();
00340 ParticleEngine::Draw(true);
00341 StatStart("GameDraw:objects");
00342
00343
00344 StatStart("GameDraw:arrow_character");
00345 CharacterCursor::GetInstance()->Draw();
00346 StatStop("GameDraw:arrow_character");
00347
00348
00349 StatStart("GameDraw:water");
00350 world.DrawWater();
00351 StatStop("GameDraw:water");
00352
00353
00354 StatStart("GameDraw::game_messages");
00355 GameMessages::GetInstance()->Draw();
00356 StatStop("GameDraw::game_messages");
00357
00358
00359 StatStart("GameDraw:fps_and_map_author_name");
00360 world.DrawAuthorName();
00361 fps.Draw();
00362 StatStop("GameDraw:fps_and_map_author_name");
00363
00364 StatStop("GameDraw:other");
00365
00366
00367 StatStart("GameDraw:interface");
00368 Interface::GetInstance()->Draw ();
00369 StatStop("GameDraw:interface");
00370
00371
00372 if(network.IsConnected()){
00373 StatStart("GameDraw:chatsession");
00374 chatsession.Show();
00375 StatStop("GameDraw:chatsession");
00376 }
00377
00378
00379 fps.AddOneFrame();
00380
00381
00382 StatStart("GameDraw:mouse_pointer");
00383 Mouse::GetInstance()->Draw();
00384 StatStart("GameDraw:mouse_pointer");
00385 }
00386
00387 void GameLoop::CallDraw()
00388 {
00389 Draw();
00390 StatStart("GameDraw:flip()");
00391 AppWormux::GetInstance()->video.Flip();
00392 StatStop("GameDraw:flip()");
00393 }
00394
00395 void GameLoop::PingClient()
00396 {
00397 Action * a = new Action(Action::ACTION_PING);
00398 ActionHandler::GetInstance()->NewAction(a);
00399 }
00400
00401 void GameLoop::Run()
00402 {
00403 int delay = 0;
00404 uint time_of_next_frame = SDL_GetTicks();
00405 uint previous_time_frame = 0;
00406
00407
00408 do
00409 {
00410 Game::GetInstance()->SetEndOfGameStatus( false );
00411
00412
00413 RefreshClock();
00414 if(Time::GetInstance()->Read() % 1000 == 20 && network.IsServer())
00415 PingClient();
00416 StatStart("GameLoop:RefreshInput()");
00417 RefreshInput();
00418 StatStop("GameLoop:RefreshInput()");
00419 if(previous_time_frame < Time::GetInstance()->Read()) {
00420 StatStart("GameLoop:RefreshObject()");
00421 RefreshObject();
00422 StatStop("GameLoop:RefreshObject()");
00423 } else {
00424 previous_time_frame = Time::GetInstance()->Read();
00425 }
00426
00427 world.Refresh();
00428
00429 time_of_next_frame += Time::GetInstance()->GetDelta();
00430 if (time_of_next_frame > SDL_GetTicks()) {
00431 StatStart("GameLoop:Draw()");
00432 CallDraw();
00433
00434 fps.Refresh();
00435 StatStop("GameLoop:Draw()");
00436 }
00437 delay = time_of_next_frame - SDL_GetTicks();
00438 if (delay >= 0)
00439 SDL_Delay(delay);
00440 } while( !Game::GetInstance()->GetEndOfGameStatus() );
00441 }
00442
00443 void GameLoop::RefreshClock()
00444 {
00445 Time * global_time = Time::GetInstance();
00446 if (global_time->IsGamePaused()) return;
00447 global_time->Refresh();
00448
00449 if (1000 < global_time->Read() - pause_seconde)
00450 {
00451 pause_seconde = global_time->Read();
00452
00453 switch (state) {
00454
00455 case PLAYING:
00456 if (duration <= 1) {
00457 jukebox.Play("share", "end_turn");
00458 SetState(END_TURN);
00459 } else {
00460 duration--;
00461 Interface::GetInstance()->UpdateTimer(duration);
00462 }
00463 break;
00464
00465 case HAS_PLAYED:
00466 if (duration <= 1) {
00467 SetState (END_TURN);
00468 } else {
00469 duration--;
00470 Interface::GetInstance()->UpdateTimer(duration);
00471 }
00472 break;
00473
00474 case END_TURN:
00475 if (duration <= 1) {
00476
00477 if (IsAnythingMoving()) {
00478 duration = 1;
00479
00480
00481 break;
00482 }
00483
00484 if (Game::GetInstance()->IsGameFinished())
00485 Game::GetInstance()->SetEndOfGameStatus( true );
00486 else if (BonusBox::NewBonusBox())
00487 break;
00488 else {
00489 ActiveTeam().AccessWeapon().Deselect();
00490 SetState(PLAYING);
00491 break;
00492 }
00493 } else {
00494 duration--;
00495 }
00496 break;
00497 }
00498 }
00499 }
00500
00501 void GameLoop::SetState(int new_state, bool begin_game)
00502 {
00503 ActionHandler * action_handler = ActionHandler::GetInstance();
00504
00505
00506 if ((state == new_state) && !begin_game) return;
00507
00508 state = new_state;
00509
00510 if(begin_game)
00511 action_handler->ExecActions();
00512
00513 Interface::GetInstance()->weapons_menu.Hide();
00514
00515 Time * global_time = Time::GetInstance();
00516 GameMode * game_mode = GameMode::GetInstance();
00517
00518 switch (state)
00519 {
00520
00521 case PLAYING:
00522 MSG_DEBUG("game.statechange", "Playing" );
00523
00524 Mouse::GetInstance()->CenterPointer();
00525
00526
00527 duration = game_mode->duration_turn;
00528 Interface::GetInstance()->UpdateTimer(duration);
00529 Interface::GetInstance()->EnableDisplayTimer(true);
00530 pause_seconde = global_time->Read();
00531
00532 if (network.IsServer() || network.IsLocal())
00533 wind.ChooseRandomVal();
00534
00535 character_already_chosen = false;
00536
00537
00538 FOR_ALL_LIVING_CHARACTERS(team,character)
00539 character->PrepareTurn();
00540
00541
00542 assert (!Game::GetInstance()->IsGameFinished());
00543
00544 if(network.IsLocal() || network.IsServer())
00545 {
00546 do
00547 {
00548 teams_list.NextTeam (begin_game);
00549 action_handler->ExecActions();
00550 } while (ActiveTeam().NbAliveCharacter() == 0);
00551
00552
00553 if( game_mode->allow_character_selection==GameMode::CHANGE_ON_END_TURN
00554 || game_mode->allow_character_selection==GameMode::BEFORE_FIRST_ACTION_AND_END_TURN)
00555 {
00556 ActiveTeam().NextCharacter();
00557 }
00558
00559 if( network.IsServer() )
00560 {
00561
00562 Action playing_char(Action::ACTION_CHANGE_CHARACTER);
00563 playing_char.StoreActiveCharacter();
00564 network.SendAction(&playing_char);
00565
00566 printf("Action_ChangeCharacter:\n");
00567 printf("char_index = %i\n",ActiveCharacter().GetCharacterIndex());
00568 printf("Playing character : %i %s\n", ActiveCharacter().GetCharacterIndex(), ActiveCharacter().GetName().c_str());
00569 printf("Playing team : %i %s\n", ActiveCharacter().GetTeamIndex(), ActiveTeam().GetName().c_str());
00570 printf("Alive characters: %i / %i\n\n",ActiveTeam().NbAliveCharacter(),ActiveTeam().GetNbCharacters());
00571
00572 }
00573 }
00574
00575 action_handler->ExecActions();
00576
00577
00578 camera.FollowObject (&ActiveCharacter(), true, true);
00579 interaction_enabled = true;
00580
00581
00582 ApplyDiseaseDamage();
00583 ApplyDeathMode();
00584
00585 break;
00586
00587
00588 case HAS_PLAYED:
00589 MSG_DEBUG("game.statechange", "Has played, now can move");
00590 duration = game_mode->duration_move_player;
00591 pause_seconde = global_time->Read();
00592 Interface::GetInstance()->UpdateTimer(duration);
00593 CharacterCursor::GetInstance()->Hide();
00594 break;
00595
00596
00597 case END_TURN:
00598 MSG_DEBUG("game.statechange", "End of turn");
00599 ActiveTeam().AccessWeapon().SignalTurnEnd();
00600 CharacterCursor::GetInstance()->Hide();
00601 duration = game_mode->duration_exchange_player;
00602 Interface::GetInstance()->UpdateTimer(duration);
00603 Interface::GetInstance()->EnableDisplayTimer(false);
00604 pause_seconde = global_time->Read();
00605
00606 interaction_enabled = false;
00607 if(network.IsServer())
00608 SyncCharacters();
00609 break;
00610 }
00611 }
00612
00613 PhysicalObj* GameLoop::GetMovingObject()
00614 {
00615 if (!ActiveCharacter().IsImmobile()) return &ActiveCharacter();
00616
00617 FOR_ALL_CHARACTERS(team,character)
00618 {
00619 if (!character->IsImmobile() && !character->IsGhost())
00620 {
00621 MSG_DEBUG("game.endofturn", "%s is not ready", character->GetName().c_str())
00622 return &(*character);
00623 }
00624 }
00625
00626 FOR_EACH_OBJECT(object)
00627 {
00628 if (!(*object)->IsImmobile())
00629 {
00630 MSG_DEBUG("game.endofturn", "%s is moving", (*object)->GetName().c_str())
00631 return (*object);
00632 }
00633 }
00634
00635 return ParticleEngine::IsSomethingMoving();
00636 }
00637
00638 bool GameLoop::IsAnythingMoving()
00639 {
00640
00641 bool object_still_moving = false;
00642
00643 if (ActiveTeam().GetWeapon().IsActive()) object_still_moving = true;
00644
00645 if (!object_still_moving)
00646 {
00647 PhysicalObj *obj = GetMovingObject();
00648 if (obj != NULL)
00649 {
00650 camera.FollowObject (obj, true, true);
00651 object_still_moving = true;
00652 }
00653 }
00654
00655 return object_still_moving;
00656 }
00657
00658
00659 void GameLoop::SignalCharacterDeath (Character *character)
00660 {
00661 std::string txt;
00662
00663 if (!Game::GetInstance()->IsGameLaunched())
00664 return;
00665
00666 if (character -> IsDrowned()) {
00667 txt = Format(_("%s has fallen in water."), character -> GetName().c_str());
00668
00669 } else if (&ActiveCharacter() == character) {
00670 CharacterCursor::GetInstance()->Hide();
00671
00672
00673 if (ActiveTeam().GetWeaponType() == Weapon::WEAPON_SUICIDE) {
00674 txt = Format(_("%s commits suicide !"), character -> GetName().c_str());
00675
00676
00677 } else if (state == PLAYING) {
00678 txt = Format(_("%s has fallen off the map!"),
00679 character -> GetName().c_str());
00680 jukebox.Play(ActiveTeam().GetSoundProfile(), "out");
00681
00682
00683 } else {
00684 txt = Format(_("%s is dead because he is clumsy!"),
00685 character -> GetName().c_str());
00686 }
00687 } else if (!ActiveCharacter().IsDead()
00688 && character->GetTeam().IsSameAs(ActiveTeam()) ) {
00689 txt = Format(_("%s is a psychopath, he has killed a member of %s team!"),
00690 ActiveCharacter().GetName().c_str(), character -> GetName().c_str());
00691 } else if (ActiveTeam().GetWeaponType() == Weapon::WEAPON_GUN) {
00692 txt = Format(_("What a shame for %s - he was killed by a simple gun!"),
00693 character -> GetName().c_str());
00694 } else {
00695 txt = Format(_("%s (%s) has died."),
00696 character -> GetName().c_str(),
00697 character -> GetTeam().GetName().c_str());
00698 }
00699
00700 GameMessages::GetInstance()->Add (txt);
00701
00702
00703 if (character->IsActiveCharacter())
00704 SetState(END_TURN);
00705 }
00706
00707
00708 void GameLoop::SignalCharacterDamage(Character *character)
00709 {
00710 if (character->IsActiveCharacter())
00711 SetState(END_TURN);
00712 }
00713
00714
00715 void GameLoop::ApplyDiseaseDamage()
00716 {
00717 FOR_ALL_LIVING_CHARACTERS(team, character) {
00718 if (character->IsDiseased()) {
00719 character->SetEnergyDelta(-character->GetDiseaseDamage());
00720 character->DecDiseaseDuration();
00721 }
00722 }
00723 }
00724
00725
00726 void GameLoop::ApplyDeathMode ()
00727 {
00728 if(Time::GetInstance()->Read() > GameMode::GetInstance()->duration_before_death_mode * 1000)
00729 {
00730 GameMessages::GetInstance()->Add (_("Hurry up, you are too slow !!"));
00731 FOR_ALL_LIVING_CHARACTERS(team, character)
00732 {
00733
00734
00735 if (static_cast<uint>(character->GetEnergy()) >
00736 GameMode::GetInstance()->damage_per_turn_during_death_mode)
00737 character->SetEnergyDelta(-GameMode::GetInstance()->damage_per_turn_during_death_mode);
00738 else
00739 character->SetEnergy(1);
00740 }
00741 }
00742 }