Kurosu wrote:
I hope to spark some interest this time around. ;)
Constant svn breakage made the attached patch the last straw into trying to add replay support. It adds nothing compared to the previous patch, except for bugfixes from the report by lodesi. So it is as buggy and non-functional as the previous one. But that's it for me.
Index: src/include/action.h =================================================================== --- src/include/action.h (revision 934) +++ src/include/action.h (working copy) @@ -34,6 +34,7 @@ { private: std::list<Uint32> var; + inline void CheckSize(uint i) const; protected: Action_t m_type; public: Index: src/include/enum.h =================================================================== --- src/include/enum.h (revision 934) +++ src/include/enum.h (working copy) @@ -59,68 +59,67 @@ typedef enum { // Actions de jeu. - ACTION_MOVE_LEFT, - ACTION_MOVE_RIGHT, - ACTION_UP, - ACTION_DOWN, - ACTION_JUMP, - ACTION_HIGH_JUMP, - ACTION_SHOOT, - ACTION_CHANGE_WEAPON, - ACTION_WIND, - ACTION_CHANGE_CHARACTER, - ACTION_CHANGE_TEAM, - ACTION_SET_CLOTHE, - ACTION_SET_MOVEMENT, - ACTION_SET_FRAME, - ACTION_SYNC_BEGIN, - ACTION_SYNC_END, - ACTION_EXPLOSION, - ACTION_SUPERTUX_STATE, - ACTION_WEAPON_1, - ACTION_WEAPON_2, - ACTION_WEAPON_3, - ACTION_WEAPON_4, - ACTION_WEAPON_5, - ACTION_WEAPON_6, - ACTION_WEAPON_7, - ACTION_WEAPON_8, - ACTION_WEAPON_9, - ACTION_WEAPON_MORE, - ACTION_WEAPON_LESS, - ACTION_SET_TARGET, + /* 1 */ ACTION_MOVE_LEFT, + /* 2 */ ACTION_MOVE_RIGHT, + /* 3 */ ACTION_UP, + /* 4 */ ACTION_DOWN, + /* 5 */ ACTION_JUMP, + /* 6 */ ACTION_HIGH_JUMP, + /* 7 */ ACTION_SHOOT, + /* 8 */ ACTION_CHANGE_WEAPON, + /* 9 */ ACTION_WIND, + /* 10 */ ACTION_CHANGE_CHARACTER, + /* 11 */ ACTION_CHANGE_TEAM, + /* 12 */ ACTION_SET_CLOTHE, + /* 13 */ ACTION_SET_MOVEMENT, + /* 14 */ ACTION_SET_FRAME, + /* 15 */ ACTION_SYNC_BEGIN, + /* 16 */ ACTION_SYNC_END, + /* 17 */ ACTION_EXPLOSION, + ACTION_SUPERTUX_STATE, + /* 18 */ ACTION_WEAPON_1, + /* 19 */ ACTION_WEAPON_2, + /* 20 */ ACTION_WEAPON_3, + /* 21 */ ACTION_WEAPON_4, + /* 22 */ ACTION_WEAPON_5, + /* 23 */ ACTION_WEAPON_6, + /* 24 */ ACTION_WEAPON_7, + /* 25 */ ACTION_WEAPON_8, + /* 26 */ ACTION_WEAPON_9, + /* 27 */ ACTION_WEAPON_MORE, + /* 28 */ ACTION_WEAPON_LESS, + ACTION_SET_TARGET, - // Game initialisation - ACTION_SET_GAME_MODE, - ACTION_SET_MAP, - ACTION_CLEAR_TEAMS, - ACTION_NEW_TEAM, - ACTION_DEL_TEAM, - ACTION_SET_CHARACTER_PHYSICS, - ACTION_SET_CHARACTER_DIRECTION, - ACTION_CHANGE_STATE, - ACTION_ASK_VERSION, - ACTION_ASK_TEAM, - ACTION_SEND_VERSION, - ACTION_SEND_TEAM, - ACTION_SEND_RANDOM, + /* 28 */ ACTION_SET_GAME_MODE, + /* 29 */ ACTION_SET_MAP, + /* 30 */ ACTION_CLEAR_TEAMS, + /* 31 */ ACTION_NEW_TEAM, + /* 32 */ ACTION_DEL_TEAM, + /* 34 */ ACTION_SET_CHARACTER_PHYSICS, + /* 35 */ ACTION_SET_CHARACTER_DIRECTION, + /* 36 */ ACTION_CHANGE_STATE, + /* 37 */ ACTION_ASK_VERSION, + /* 38 */ ACTION_ASK_TEAM, + /* 39 */ ACTION_SEND_VERSION, + /* 40 */ ACTION_SEND_TEAM, + /* 41 */ ACTION_SEND_RANDOM, // Actions "hors-jeu", en local seulement. - ACTION_QUIT, - ACTION_WEAPONS1, - ACTION_WEAPONS2, - ACTION_WEAPONS3, - ACTION_WEAPONS4, - ACTION_WEAPONS5, - ACTION_WEAPONS6, - ACTION_WEAPONS7, - ACTION_WEAPONS8, - ACTION_PAUSE, - ACTION_FULLSCREEN, - ACTION_TOGGLE_INTERFACE, - ACTION_CENTER, - ACTION_TOGGLE_WEAPONS_MENUS, - ACTION_MAX, + /* 42 */ ACTION_QUIT, + /* 43 */ ACTION_WEAPONS1, + /* 44 */ ACTION_WEAPONS2, + /* 45 */ ACTION_WEAPONS3, + /* 46 */ ACTION_WEAPONS4, + /* 47 */ ACTION_WEAPONS5, + /* 48 */ ACTION_WEAPONS6, + /* 49 */ ACTION_WEAPONS7, + /* 51 */ ACTION_WEAPONS8, + /* 52 */ ACTION_PAUSE, + /* 53 */ ACTION_FULLSCREEN, + /* 54 */ ACTION_TOGGLE_INTERFACE, + /* 55 */ ACTION_CENTER, + /* 56 */ ACTION_TOGGLE_WEAPONS_MENUS, + /* 57 */ ACTION_MAX, } Action_t; //----------------------------------------------------------------------------- Index: src/include/action_handler.cpp =================================================================== --- src/include/action_handler.cpp (revision 934) +++ src/include/action_handler.cpp (working copy) @@ -40,8 +40,9 @@ #include "../weapon/weapon.h" #include "../weapon/weapons_list.h" #include "../weapon/explosion.h" +#include "../replay/replay.h" -// Delta appliqu l'angle du viseur +// Delta applied to crosshair angle #define DELTA_CROSSHAIR 2 ActionHandler * ActionHandler::singleton = NULL; @@ -147,7 +148,7 @@ { //Set the frame of the walking skin, to get the position of the hand synced ActionInt* ai = dynamic_cast<ActionInt*>(a); - if (!ActiveTeam().is_local || network.state != Network::NETWORK_PLAYING) + if (replay.IsPlaying() || !ActiveTeam().is_local || network.state != Network::NETWORK_PLAYING) { ActiveTeam().ActiveCharacter().body->SetFrame((uint)ai->GetValue()); } @@ -156,7 +157,7 @@ void Action_SetClothe (Action *a) { ActionString* action = dynamic_cast<ActionString*>(a); - if (!ActiveTeam().is_local || network.state != Network::NETWORK_PLAYING) + if (replay.IsPlaying() || !ActiveTeam().is_local || network.state != Network::NETWORK_PLAYING) { ActiveTeam().ActiveCharacter().SetClothe(action->GetValue()); } @@ -181,14 +182,14 @@ { ActionString* action = dynamic_cast<ActionString*>(a); MSG_DEBUG("action.handler", "SetMap : %s", action->GetValue()); - if (!network.IsClient()) return; + if (!network.IsClient() && !replay.IsPlaying()) return; lst_terrain.ChangeTerrainNom (action->GetValue()); } void Action_ClearTeams (Action *a) { MSG_DEBUG("action.handler", "ClearTeams"); - if (!network.IsClient()) return; + if (!network.IsClient() && !replay.IsPlaying()) return; teams_list.Clear(); } @@ -287,8 +288,9 @@ void Action_SendRandom (Action *a) { - if (!network.IsClient()) return; + if (!network.IsClient() && !replay.IsPlaying()) return; ActionDouble* action = dynamic_cast<ActionDouble*>(a); + printf("Adding random value to randomsync\n"); randomSync.AddToTable(action->GetValue()); } @@ -360,6 +362,7 @@ { SDL_LockMutex(mutex); Action *action = queue.front(); + queue.pop_front(); SDL_UnlockMutex(mutex); Exec (action); @@ -376,11 +379,12 @@ queue.push_back(a); // std::cout << " queue_size " << queue.size() << std::endl; SDL_UnlockMutex(mutex); + if (replay.IsRecording()) replay.StoreAction(a); if (repeat_to_network) network.SendAction(a); } void ActionHandler::Register (Action_t action, - const std::string &name,callback_t fct) + const std::string &name,callback_t fct) { handler[action] = fct; action_name[action] = name; @@ -391,7 +395,6 @@ // #ifdef DBG_ACT // std::cout << "Exec action " << *a << std::endl; // #endif - handler_it it=handler.find(a->GetType()); assert(it != handler.end()); (*it->second) (a); Index: src/include/action.cpp =================================================================== --- src/include/action.cpp (revision 934) +++ src/include/action.cpp (working copy) @@ -25,6 +25,8 @@ #include "action_handler.h" //----------------------------------------------------------------------------- +//#define ACTION_DEBUG + Action::Action (Action_t type) { m_type = type; @@ -33,10 +35,10 @@ Action::Action (Action_t type, Uint32 *is) { m_type = type; - int m_lenght = SDLNet_Read32(is); + int m_length = SDLNet_Read32(is); is++; - for(int i=0; i < m_lenght; i++) + for(int i=0; i < m_length; i++) { Uint32 val = SDLNet_Read32(is); var.push_back(val); @@ -48,6 +50,13 @@ { } +void Action::CheckSize(uint i) const +{ + if (var.size() < i) + fprintf(stderr, "Bad size %i for action of type %i\n", + var.size(), m_type); +} + Action_t Action::GetType() const { return m_type; @@ -75,7 +84,9 @@ Uint32 tmp; memcpy(&tmp, &val, 4); var.push_back(tmp); +#ifdef ACTION_DEBUG std::cout << "Pushing int value: " << val << std::endl; +#endif } void Action::Push(double val) @@ -84,7 +95,9 @@ memcpy(&tmp, &val, 8); var.push_back(tmp[0]); var.push_back(tmp[1]); +#ifdef ACTION_DEBUG std::cout << "Pushing double value: " << val << " (" << tmp << ")" << std::endl; +#endif } void Action::Push(std::string val) @@ -95,32 +108,42 @@ char* ch = (char*)val.c_str(); int count = val.size(); - while(count > 0) + while(count > 3) { Uint32 tmp; - // Fix-me : We are reading out of the c_str() buffer there : memcpy(&tmp, ch, 4); var.push_back(tmp); ch += 4; count -= 4; } + if (count > 0) + { + Uint32 tmp = 0; + memcpy(&tmp, ch, count); + var.push_back(tmp); + } +#ifdef ACTION_DEBUG std::cout << "Pushing string value: " << val << std::endl; +#endif } int Action::PopInt() { - assert(var.size() > 0); + CheckSize(1); int val; Uint32 tmp = var.front(); memcpy(&val, &tmp, 4); var.pop_front(); +#ifdef ACTION_DEBUG std::cout << "Poping int value: " << val << std::endl; +#endif return val; } double Action::PopDouble() { - assert(var.size() > 0); + /* Huh? Shouldn't that be <2, as double is 64bits ? */ + CheckSize(1); double val; Uint32 tmp[2]; tmp[0] = var.front(); @@ -128,28 +151,32 @@ tmp[1] = var.front(); var.pop_front(); memcpy(&val, &tmp, 8); +#ifdef ACTION_DEBUG std::cout << "Poping double value: " << val << " (" << tmp << ")" << std::endl; +#endif return val; } std::string Action::PopString() { - assert(var.size() > 1); - int lenght = (int) var.front(); + CheckSize(2); + int length = (int) var.front(); var.pop_front(); std::string str=""; - assert((int)var.size() >= lenght/4); - while(lenght > 0) + assert((int)var.size() >= length/4); + while(length > 0) { Uint32 tmp = var.front(); var.pop_front(); char tmp_str[5] = {0, 0, 0, 0, 0}; memcpy(tmp_str, &tmp, 4); str += tmp_str; - lenght -= 4; + length -= 4; } +#ifdef ACTION_DEBUG std::cout << "Poping string value: " << str << std::endl; +#endif return str; } Index: src/team/teams_list.cpp =================================================================== --- src/team/teams_list.cpp (revision 934) +++ src/team/teams_list.cpp (working copy) @@ -23,9 +23,6 @@ //----------------------------------------------------------------------------- #include "body_list.h" #include "../include/action_handler.h" -#ifdef CL -#include "../network/network.h" -#endif #include "../game/config.h" #include "../tool/file_tools.h" #include "../tool/i18n.h" @@ -56,10 +53,6 @@ { // Fin du tour pour l' uipe active if (debut_jeu) return; -#ifdef CL - if (network.is_client()) return; - ActiveTeam().FinTurn(); -#endif // Passe l' uipe suivante std::vector<Team*>::iterator it=m_equipe_active; Index: src/team/move.cpp =================================================================== --- src/team/move.cpp (revision 934) +++ src/team/move.cpp (working copy) @@ -28,6 +28,7 @@ #include "../map/map.h" #include "../map/camera.h" #include "../network/network.h" +#include "../replay/replay.h" #include "../sound/jukebox.h" #include "../tool/debug.h" @@ -126,18 +127,32 @@ character.InitMouvementDG (PAUSE_CHG_SENS); } - //Refresh skin position across network - if( !network.IsLocal() && ActiveTeam().is_local) + if (ActiveTeam().is_local) { Action* a = BuildActionSendCharacterPhysics(ActiveCharacter().GetTeamIndex(), ActiveCharacter().GetCharacterIndex()); ActionString a_set_clothe(ACTION_SET_CLOTHE,character.body->GetClothe()); ActionString a_set_movement(ACTION_SET_MOVEMENT,character.body->GetMovement()); ActionInt a_set_frame(ACTION_SET_FRAME,character.body->GetFrame()); - network.SendAction(a); + + //Store skin refresh + if (replay.IsRecording()) + { + replay.StoreAction(a); + replay.StoreAction(&a_set_clothe); + replay.StoreAction(&a_set_movement); + replay.StoreAction(&a_set_frame); + } + + //Refresh skin position across network + if(!network.IsLocal()) + { + network.SendAction(a); + network.SendAction(&a_set_clothe); + network.SendAction(&a_set_movement); + network.SendAction(&a_set_frame); + } + delete a; - network.SendAction(&a_set_clothe); - network.SendAction(&a_set_movement); - network.SendAction(&a_set_frame); } } @@ -159,17 +174,29 @@ //Refresh skin position across network - if( !network.IsLocal() && ActiveTeam().is_local) + if (ActiveTeam().is_local) { Action* a = BuildActionSendCharacterPhysics(ActiveCharacter().GetTeamIndex(), ActiveCharacter().GetCharacterIndex()); ActionString a_set_clothe(ACTION_SET_CLOTHE,character.body->GetClothe()); ActionString a_set_movement(ACTION_SET_MOVEMENT,character.body->GetMovement()); ActionInt a_set_frame(ACTION_SET_FRAME,character.body->GetFrame()); - network.SendAction(a); + + if (replay.IsRecording()) + { + replay.StoreAction(a); + replay.StoreAction(&a_set_clothe); + replay.StoreAction(&a_set_movement); + replay.StoreAction(&a_set_frame); + } + + if (!network.IsLocal()) + { + network.SendAction(a); + network.SendAction(&a_set_clothe); + network.SendAction(&a_set_movement); + network.SendAction(&a_set_frame); + } delete a; - network.SendAction(&a_set_clothe); - network.SendAction(&a_set_movement); - network.SendAction(&a_set_frame); } } Index: src/team/team.cpp =================================================================== --- src/team/team.cpp (revision 934) +++ src/team/team.cpp (working copy) @@ -133,7 +133,7 @@ LitDocXml::LitAttrString(elem, "name", character_name); LitDocXml::LitAttrString(elem, "body", body_name); - if (!(body = body_list.GetBody(body_name)) ) + if ((body = body_list.GetBody(body_name)) == NULL) { std::cerr << Format(_("Error: can't find the body \"%s\" for the team \"%s\"."), Index: src/team/character.cpp =================================================================== --- src/team/character.cpp (revision 934) +++ src/team/character.cpp (working copy) @@ -73,7 +73,7 @@ //#define DEBUG_STATS #endif -// Barre d' ergie +// Energy bar const uint LARG_ENERGIE = 40; const uint HAUT_ENERGIE = 6; @@ -182,7 +182,7 @@ GameLoop::GetInstance()->SignalCharacterDeath (this); } -// Si un ver devient un fantome, il meurt ! Signale sa mort +// If a player becomes a ghost, he dies! Signal his death void Character::SignalGhostState (bool was_dead) { // Report to damage performer this character lost all of its energy Index: src/network/network.h =================================================================== --- src/network/network.h (revision 934) +++ src/network/network.h (working copy) @@ -29,6 +29,7 @@ #include <string> #include "../include/action.h" //----------------------------------------------------------------------------- +Action* make_action(Uint32* packet); class Network { @@ -57,8 +58,6 @@ IPaddress ip; // for server : store listening port // for client : store server address/port - Action* make_action(Uint32* packet); - public: uint max_player_number; uint connected_player; Index: src/network/randomsync.h =================================================================== --- src/network/randomsync.h (revision 934) +++ src/network/randomsync.h (working copy) @@ -34,6 +34,7 @@ public: RandomSync(); void Init(); + void Flush() { rnd_table.clear(); } bool GetBool(); double GetDouble(); Index: src/network/network.cpp =================================================================== --- src/network/network.cpp (revision 934) +++ src/network/network.cpp (working copy) @@ -343,7 +343,7 @@ //----------------------------------------------------------------------------- -Action* Network::make_action(Uint32* packet) +Action* make_action(Uint32* packet) { Action_t type = (Action_t)SDLNet_Read32(packet); Index: src/network/randomsync.cpp =================================================================== --- src/network/randomsync.cpp (revision 934) +++ src/network/randomsync.cpp (working copy) @@ -25,6 +25,7 @@ #include <assert.h> #include "randomsync.h" #include "network.h" +#include "../replay/replay.h" #include "../include/action_handler.h" const uint table_size = 40; //Number of pregerated numbers @@ -35,8 +36,9 @@ } void RandomSync::Init(){ - //If we are a client on the network, we don't generate any random number - if(network.IsClient()) return; + //If we are a client on the network or are getting our random events from + //the replay actions, we don't generate any random number + if (network.IsClient() || replay.IsPlaying()) return; srand( time(NULL) ); @@ -51,8 +53,13 @@ { //Add a random number to the table, send it over network if needed double nbr = rand(); + Action *a = new ActionDouble(ACTION_SEND_RANDOM,nbr); AddToTable(nbr); - if(network.IsServer()) ActionHandler::GetInstance()->NewAction(new ActionDouble(ACTION_SEND_RANDOM,nbr)); + + // NewAction has replay recording + if (network.IsServer()) ActionHandler::GetInstance()->NewAction(a); + // Normal mode, force record + else if (replay.IsRecording()) replay.StoreAction(a); } void RandomSync::AddToTable(double nbr) @@ -62,7 +69,9 @@ double RandomSync::GetRand() { - if(network.IsServer() || network.IsLocal()) GenerateTable(); + // Generate table only in these cases + if(network.IsServer() || network.IsLocal() || replay.IsRecording()) + GenerateTable(); assert(rnd_table.size() != 0); double nbr = rnd_table.front(); Index: src/weapon/explosion.cpp =================================================================== --- src/weapon/explosion.cpp (revision 934) +++ src/weapon/explosion.cpp (working copy) @@ -26,6 +26,7 @@ #include "../map/camera.h" #include "../map/map.h" #include "../network/network.h" +#include "../replay/replay.h" #include "../object/objects_list.h" #include "../object/particle.h" #include "../object/physical_obj.h" @@ -52,11 +53,9 @@ { if(network.IsLocal()) ApplyExplosion_common(pos, config, son, fire_particle, smoke); - else - if(network.IsServer()) + else if(network.IsServer()) ApplyExplosion_server(pos, config, son, fire_particle, smoke); - else - if(network.IsClient()) + else if(network.IsClient() || replay.IsPlaying()) return; // client receives explosion via the action handler } @@ -187,7 +186,8 @@ { ActionHandler* action_handler = ActionHandler::GetInstance(); - Action a_begin_sync(ACTION_SYNC_BEGIN); + Action a_begin_sync(ACTION_SYNC_BEGIN), *a; + // Kurosu: add here wait for sink ? network.SendAction(&a_begin_sync); // world.Dig(pos, config.explosion_range); @@ -217,12 +217,13 @@ { // cliens : Place characters Action* a = BuildActionSendCharacterPhysics(team_no, char_no); + //if (replay.IsRecording()) replay.StoreAction(a); action_handler->NewAction(a); } } } - Action* a = new Action(ACTION_EXPLOSION); + a = new Action(ACTION_EXPLOSION); a->Push(pos.x); a->Push(pos.y); a->Push((int)config.explosion_range); Index: src/interface/interface.cpp =================================================================== --- src/interface/interface.cpp (revision 934) +++ src/interface/interface.cpp (working copy) @@ -74,7 +74,7 @@ game_menu = resource_manager.LoadImage( res, "interface/menu_jeu"); bg_time = resource_manager.LoadImage( res, "interface/fond_compteur"); weapon_box_button = resource_manager.LoadImage( res, "interface/weapon_box_button"); - + barre_energie.InitVal (0, 0, GameMode::GetInstance()->character.init_energy); barre_energie.InitPos (ENERGY_BAR_POS.x, ENERGY_BAR_POS.y, BARENERGIE_LARG, BARENERGIE_HAUT); @@ -82,7 +82,7 @@ barre_energie.value_color = lightgray_color; barre_energie.background_color = gray_color; - // strength bar initialisation + // strength bar initialisation weapon_strength_bar.InitPos (0, 0, 400, 10); weapon_strength_bar.InitVal (0, 0, 100); Index: src/interface/keyboard.cpp =================================================================== --- src/interface/keyboard.cpp (revision 934) +++ src/interface/keyboard.cpp (working copy) @@ -34,6 +34,7 @@ #include "../include/action_handler.h" #include "../include/constant.h" #include "../map/camera.h" +#include "../replay/replay.h" #include "../team/macro.h" #include "../team/move.h" #include "../tool/i18n.h" @@ -73,6 +74,9 @@ void Clavier::HandleKeyEvent( const SDL_Event *event) { + // Don't check mouse events when in replay (for now) + if (replay.IsPlaying()) return; + std::map<int, Action_t>::iterator it = layout.find(event->key.keysym.sym); if ( it == layout.end() ) Index: src/interface/mouse.cpp =================================================================== --- src/interface/mouse.cpp (revision 934) +++ src/interface/mouse.cpp (working copy) @@ -31,6 +31,7 @@ #include "../include/action_handler.h" #include "../map/camera.h" #include "../map/map.h" +#include "../replay/replay.h" #include "../team/macro.h" #include "../tool/point.h" #include "../weapon/weapon.h" @@ -246,6 +247,9 @@ } void Mouse::TraiteClic (const SDL_Event *event){ + // Don't check mouse events when in replay (for now) + if (replay.IsPlaying()) return; + if( event->type == SDL_MOUSEBUTTONDOWN ){ if( event->button.button == SDL_BUTTON_RIGHT ){ Index: src/menu/results_menu.cpp =================================================================== --- src/menu/results_menu.cpp (revision 934) +++ src/menu/results_menu.cpp (working copy) @@ -21,8 +21,11 @@ #include "results_menu.h" +#include "../game/config.h" #include "../team/results.h" #include "../team/character.h" +#include "../gui/text_box.h" +#include "../replay/replay.h" #include "../include/app.h" #include "../tool/i18n.h" #include "../tool/string_tools.h" @@ -69,18 +72,18 @@ margin = DEF_MARGIN; border.SetValues(DEF_BORDER, DEF_BORDER); - type_box = new HBox( Rectanglei(pos, type_size), true); + type_box = new HBox( Rectanglei(pos, type_size)); type_box->AddWidget(new Label(type_name, Rectanglei(pos, type_size), font)); AddWidget(type_box); pos.SetValues(pos.GetX()+type_size.GetX(), pos.GetY()); - name_box = new HBox( Rectanglei(pos, name_size), true); + name_box = new HBox( Rectanglei(pos, name_size)); name_lbl = new Label("", Rectanglei(pos, name_size), font); name_box->AddWidget(name_lbl); AddWidget(name_box); pos.SetValues(pos.GetX()+name_size.GetX(), pos.GetY()); - score_box = new HBox( Rectanglei(pos, score_size), true); + score_box = new HBox( Rectanglei(pos, score_size)); score_lbl = new Label("", Rectanglei(pos, score_size), font); score_box->AddWidget(score_lbl); AddWidget(score_box); @@ -105,18 +108,20 @@ , results(v) , index(0) , max_height(DEF_SIZE+3*DEF_BORDER) - , team_size(200, 40) - , type_size(160, 40) - , name_size(250, 40) - , score_size(60, 40) + , team_size(200, 40), type_size(160, 40), name_size(250, 40), score_size(60, 40) + , bt_prev_team(NULL), bt_next_team(NULL) + , most_violent(NULL), most_usefull(NULL), most_useless(NULL), biggest_traitor(NULL) + , filename(NULL), comment(NULL) { Profile *res = resource_manager.LoadXMLProfile( "graphism.xml",false); Point2i pos (0, 0); + const Rectanglei rectZero(0, 0, 0, 0); Font* big_font = Font::GetInstance(Font::FONT_BIG); + Font* font = Font::GetInstance(Font::FONT_NORMAL); // Center the boxes! - uint x = 60; - uint y = 60; + uint x = 30; + uint y = 30; #if 0 // Determining sizes really doesn't work so hardcoding them at init score_size = big_font->GetSize("999"); @@ -177,14 +182,14 @@ #endif //Team selection - team_box = new HBox(Rectanglei(x, y, total_width, max_height), true); + HBox *team_box = new HBox(Rectanglei(x, y, total_width, max_height)); team_box->SetMargin(DEF_MARGIN); team_box->SetBorder(Point2i(DEF_BORDER, DEF_BORDER)); bt_prev_team = new Button(Rectanglei(pos, Point2i(DEF_SIZE, DEF_SIZE)), res, "menu/arrow-left"); team_box->AddWidget(bt_prev_team); pos.SetValues(pos.GetX()+DEF_SIZE, pos.GetY()); - HBox* tmp_box = new HBox( Rectanglei(pos, team_size), true); + HBox* tmp_box = new HBox( Rectanglei(pos, team_size)); team_name = new Label("", Rectanglei(pos, team_size), *big_font); tmp_box->AddWidget(team_name); team_box->AddWidget(tmp_box); @@ -192,31 +197,51 @@ bt_next_team = new Button(Rectanglei(pos, Point2i(DEF_SIZE, DEF_SIZE)), res, "menu/arrow-right"); team_box->AddWidget(bt_next_team); - + widgets.AddWidget(team_box); + //Results most_violent = new ResultBox(Rectanglei(x, y+int(1.5*max_height), total_width, max_height), true, _("Most violent"), *big_font, type_size, name_size, score_size); + widgets.AddWidget(most_violent); most_usefull = new ResultBox(Rectanglei(x, y+3*max_height, total_width, max_height), true, _("Most usefull"), *big_font, type_size, name_size, score_size); + widgets.AddWidget(most_usefull); most_useless = new ResultBox(Rectanglei(x, y+int(4.5*max_height), total_width, max_height), true, _("Most useless"), *big_font, type_size, name_size, score_size); + widgets.AddWidget(most_useless); biggest_traitor = new ResultBox(Rectanglei(x, y+6*max_height, total_width, max_height), true, _("Most sold-out"), *big_font, type_size, name_size, score_size); + widgets.AddWidget(biggest_traitor); + // Save replay + widgets.AddWidget(new Label(_("Save replay?"), Rectanglei(30, 470, 160, 1), *big_font)); + + VBox* vbox = new VBox(Rectanglei(200, 460, 200, 1)); + vbox->AddWidget(new Label(_("Filename:"), rectZero, *font)); + filename = new TextBox("record.dat", rectZero, *font); + vbox->AddWidget(filename); + widgets.AddWidget(vbox); + + vbox = new VBox(Rectanglei(420, 460, 200, 1)); + vbox->AddWidget(new Label(_("Comment:"), rectZero, *font)); + comment = new TextBox(_("No comment."), rectZero, *font); + vbox->AddWidget(comment); + widgets.AddWidget(vbox); + SetResult(0); } -ResultsMenu::~ResultsMenu() +void ResultsMenu::__sig_ok() { - delete team_box; - delete most_violent; - delete most_usefull; - delete most_useless; - delete biggest_traitor; + printf("Should be saving to '%s' with comment '%s'\n", + filename->GetText().c_str(), comment->GetText().c_str()); + + replay.SaveReplay(Config::GetInstance()->GetPersonalDir() + filename->GetText(), + comment->GetText().c_str()); } void ResultsMenu::SetResult(int i) @@ -273,15 +298,6 @@ SetResult(index-1); else if ( bt_next_team->Contains(mousePosition)) SetResult(index+1); + else + widgets.Clic(mousePosition, button); } - -void ResultsMenu::Draw(const Point2i &mousePosition) -{ - team_box->Draw(mousePosition); - - most_violent->Draw(mousePosition); - most_usefull->Draw(mousePosition); - most_useless->Draw(mousePosition); - biggest_traitor->Draw(mousePosition); -} - Index: src/menu/main_menu.cpp =================================================================== --- src/menu/main_menu.cpp (revision 934) +++ src/menu/main_menu.cpp (working copy) @@ -118,12 +118,12 @@ Profile *res = resource_manager.LoadXMLProfile( "graphism.xml", false); - int y = 300; + int y = 260; const int y2 = 580; #ifdef NETWORK_BUTTON + int dy = (y2-y)/5; +#else int dy = (y2-y)/4; -#else - int dy = (y2-y)/3; #endif play = new ButtonText( Point2i(x_button, (int)(y * y_scale)), @@ -142,6 +142,12 @@ network = NULL; #endif + replays = new ButtonText( Point2i(x_button, (int)(y * y_scale) ), + res, "main_menu/button", + _("Replays"), + large_font); + y += dy; + options = new ButtonText( Point2i(x_button, (int)(y * y_scale) ), res, "main_menu/button", _("Options"), @@ -161,6 +167,7 @@ widgets.AddWidget(play); widgets.AddWidget(network); + widgets.AddWidget(replays); widgets.AddWidget(options); widgets.AddWidget(infos); widgets.AddWidget(quit); @@ -185,6 +192,7 @@ #ifdef NETWORK_BUTTON else if(b == network) choice = menuNETWORK; #endif + else if(b == replays) choice = menuREPLAYS; else if(b == options) choice = menuOPTIONS; else if(b == infos) choice = menuCREDITS; else if(b == quit) choice = menuQUIT; @@ -216,6 +224,11 @@ onClick( Point2i(event.button.x, event.button.y), event.button.button); else if( event.type == SDL_KEYDOWN ) { + if( event.key.keysym.sym == SDLK_TAB ) + { + choice = menuREPLAYS; + break; + } if( event.key.keysym.sym == SDLK_ESCAPE ) { choice = menuQUIT; @@ -301,6 +314,7 @@ #ifdef NETWORK_BUTTON background->Blit(app->video.window, network->GetRectangle(), network->GetPosition()); #endif + background->Blit(app->video.window, replays->GetRectangle(), replays->GetPosition()); background->Blit(app->video.window, options->GetRectangle(), options->GetPosition()); background->Blit(app->video.window, infos->GetRectangle(), infos->GetPosition()); background->Blit(app->video.window, quit->GetRectangle(), quit->GetPosition()); @@ -459,12 +473,12 @@ //////////////////////////// Buttons position / scale ////////////////// - int y = 300; + int y = 260; const int y2 = 580; #ifdef NETWORK_BUTTON + int dy = (y2-y)/5; +#else int dy = (y2-y)/4; -#else - int dy = (y2-y)/3; #endif int y_play = (int)(y * y_scale);//Position y += dy; @@ -472,6 +486,8 @@ int y_network = (int)(y * y_scale);//Position y += dy; #endif + int y_replays = (int)(y * y_scale); //Position + y += dy; int y_options = (int)(y * y_scale); //Position y += dy; int y_infos = (int)(y * y_scale); //Position @@ -489,11 +505,14 @@ network->SetSizePosition( Rectanglei(x_button, y_network, button_width, button_height) ); #endif + replays->GetSprite()->cache.EnableLastFrameCache(); + replays->SetSizePosition( Rectanglei(x_button, y_replays, button_width, button_height) ); + options->GetSprite()->cache.EnableLastFrameCache(); options->SetSizePosition( Rectanglei(x_button, y_options, button_width, button_height) ); infos->GetSprite()->cache.EnableLastFrameCache(); - infos->SetSizePosition( Rectanglei(x_button, y_infos, button_width, button_height) ); + infos->SetSizePosition( Rectanglei(x_button, y_infos, button_width, button_height) ); quit->GetSprite()->cache.EnableLastFrameCache(); quit->SetSizePosition( Rectanglei(x_button, y_quit, button_width, button_height) ); @@ -512,6 +531,9 @@ network->SetSize(button_width, button_height + button_dh); network->SetXY(x_button, y_network + button_dy); #endif + replays->GetSprite()->cache.DisableLastFrameCache(); + replays->SetSize(button_width, button_height + button_dh); + replays->SetXY(x_button, y_replays + button_dy); options->GetSprite()->cache.DisableLastFrameCache(); options->SetSize(button_width, button_height + button_dh); options->SetXY(x_button, y_options + button_dy); @@ -532,6 +554,8 @@ network->GetSprite()->cache.EnableLastFrameCache(); network->SetXY(x_button, (dt*dt*app->video.window.GetHeight()/fall_duration/fall_duration) - app->video.window.GetHeight() + y_network); #endif + replays->GetSprite()->cache.EnableLastFrameCache(); + replays->SetXY(x_button, (dt*dt*app->video.window.GetHeight()/fall_duration/fall_duration) - app->video.window.GetHeight() + y_replays); options->GetSprite()->cache.EnableLastFrameCache(); options->SetXY(x_button, (dt*dt*app->video.window.GetHeight()/fall_duration/fall_duration) - app->video.window.GetHeight() + y_options); infos ->GetSprite()->cache.EnableLastFrameCache(); @@ -544,6 +568,7 @@ #ifdef NETWORK_BUTTON network->Draw(mousePosition); #endif + replays->Draw(mousePosition); options->Draw(mousePosition); infos->Draw(mousePosition); quit->Draw(mousePosition); Index: src/menu/results_menu.h =================================================================== --- src/menu/results_menu.h (revision 934) +++ src/menu/results_menu.h (working copy) @@ -28,6 +28,7 @@ class TeamResults; class ResultBox; +class TextBox; class ResultsMenu : public Menu { @@ -36,34 +37,36 @@ int index; // Box sizes - int total_width; - int max_height; - Point2i team_size; - Point2i type_size; - Point2i name_size; - Point2i score_size; + int total_width; + int max_height; + Point2i team_size; + Point2i type_size; + Point2i name_size; + Point2i score_size; - /* Team controllers */ - Button *bt_prev_team; - Button *bt_next_team; - Label *team_name; - HBox *team_box; + // Team controllers + Button *bt_prev_team; + Button *bt_next_team; + Label *team_name; - ResultBox* most_violent; - ResultBox* most_usefull; - ResultBox* most_useless; - ResultBox* biggest_traitor; + ResultBox *most_violent; + ResultBox *most_usefull; + ResultBox *most_useless; + ResultBox *biggest_traitor; + + // Save replay + TextBox *filename; + TextBox *comment; - void __sig_ok() { }; + void __sig_ok(); void __sig_cancel() { }; void SetResult(int i); void OnClic(const Point2i &mousePosition, int button); - void Draw(const Point2i &mousePosition); + void Draw(const Point2i &mousePosition) { }; public: ResultsMenu(const std::vector<TeamResults*>* v, const char *winner_name); - ~ResultsMenu(); }; #endif //RESULTS_MENU_H Index: src/menu/main_menu.h =================================================================== --- src/menu/main_menu.h (revision 934) +++ src/menu/main_menu.h (working copy) @@ -36,6 +36,7 @@ menuNULL=0, menuPLAY, menuNETWORK, + menuREPLAYS, menuOPTIONS, menuCREDITS, menuQUIT @@ -45,7 +46,7 @@ { Sprite *background, *skin_left, *skin_right, *title; WidgetList widgets; - ButtonText *play, *network, *options, *infos, *quit; + ButtonText *play, *network, *replays, *options, *infos, *quit; Text * version_text, * website_text; uint start_time; uint last_refresh; Index: src/main.cpp =================================================================== --- src/main.cpp (revision 934) +++ src/main.cpp (working copy) @@ -36,6 +36,7 @@ #include "menu/game_menu.h" #include "menu/main_menu.h" #include "menu/network_menu.h" +#include "menu/replay_menu.h" #include "menu/options_menu.h" #include "include/action_handler.h" #include "include/constant.h" @@ -97,7 +98,14 @@ break; } case menuQUIT: - quit = true; + quit = true; + break; + case menuREPLAYS: + { + ReplayMenu replay_menu; + replay_menu.Run(); + break; + } default: break; } @@ -232,5 +240,6 @@ { AppWormux::GetInstance()->main(argc,argv); delete AppWormux::GetInstance(); + exit (EXIT_SUCCESS); } Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 934) +++ src/Makefile.am (working copy) @@ -63,6 +63,7 @@ menu/options_menu.cpp menu/options_menu.h \ menu/game_menu.cpp menu/game_menu.h \ menu/results_menu.cpp menu/results_menu.h \ + menu/replay_menu.cpp menu/replay_menu.h \ game/time.cpp game/time.h \ gui/progress_bar.cpp gui/progress_bar.h \ gui/question.cpp gui/question.h \ @@ -88,6 +89,8 @@ map/wind.cpp map/wind.h \ network/network.cpp network/network.h \ network/randomsync.cpp network/randomsync.h \ + replay/replay.cpp replay/replay.h \ + replay/replay_info.cpp replay/replay_info.h \ team/macro.h \ team/body.cpp team/body.h \ team/body_list.cpp team/body_list.h \ Index: src/game/game.h =================================================================== --- src/game/game.h (revision 934) +++ src/game/game.h (working copy) @@ -41,6 +41,7 @@ public: static Game * GetInstance(); + void Replay(const std::string& name); void Start(); bool IsGameFinished(); Index: src/game/game_loop.cpp =================================================================== --- src/game/game_loop.cpp (revision 934) +++ src/game/game_loop.cpp (working copy) @@ -45,6 +45,7 @@ #include "../map/wind.h" #include "../network/network.h" #include "../network/randomsync.h" +#include "../replay/replay.h" #include "../object/bonus_box.h" #include "../object/objects_list.h" #include "../object/particle.h" @@ -96,7 +97,7 @@ // Create objects lst_objects.Init(); - // Remise z ro + // Reset std::cout << "o " << _("Initialise data") << std::endl; CharacterCursor::GetInstance()->Reset(); Mouse::GetInstance()->Reset(); @@ -104,8 +105,8 @@ Interface::GetInstance()->Reset(); GameMessages::GetInstance()->Reset(); - //Signale les clients que le jeu peut d marrer - //Attend que le client ait d marr + //Inform clients that game can start + //Wait for the client to have started network.SendAction ( &a_change_state ); while (network.state != Network::NETWORK_READY_TO_PLAY) { @@ -149,6 +150,24 @@ std::cout << network.state << " : Run game !" << std::endl; } + +void GameLoop::InitGameData_RePlay() +{ + AppWormux * app = AppWormux::GetInstance(); + app->video.SetWindowCaption( std::string("Wormux ") + Constants::VERSION + " - Replay mode"); + ActionHandler * action_handler = ActionHandler::GetInstance(); + + replay.SetWaitState(Replay::WAIT_FOR_SINK); + action_handler->ExecActions(); + + std::cout << "o " << _("Initialise teams") << std::endl; + world.Reset(); + teams_list.LoadGamingData(GameMode::GetInstance()->max_characters); + + // Create objects + lst_objects.Init(); +} + void GameLoop::InitData_Local() { // Placement des vers @@ -170,7 +189,9 @@ InitGameData_NetServer(); else if (network.IsClient()) InitGameData_NetClient(); - else + else if (replay.IsPlaying()) + InitGameData_RePlay(); + else InitData_Local(); CharacterCursor::GetInstance()->Reset(); @@ -240,32 +261,32 @@ // Poll and treat events SDL_Event event; - while( SDL_PollEvent( &event) ) - { - if ( event.type == SDL_QUIT) - { - std::cout << "SDL_QUIT received ===> exit TODO" << std::endl; - Game::GetInstance()->SetEndOfGameStatus( true ); - std::cout << "FIN PARTIE" << std::endl; - return; - } - if ( event.type == SDL_MOUSEBUTTONDOWN ) - { - Mouse::GetInstance()->TraiteClic( &event); - } - if ( event.type == SDL_KEYDOWN - || event.type == SDL_KEYUP) - { - if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE) - { - Game::GetInstance()->SetEndOfGameStatus( true ); - std::cout << "FIN PARTIE" << std::endl; - return; - } - - Clavier::GetInstance()->HandleKeyEvent( &event); - } - } + while( SDL_PollEvent( &event) ) + { + if ( event.type == SDL_QUIT) + { + std::cout << "SDL_QUIT received ===> exit TODO" << std::endl; + Game::GetInstance()->SetEndOfGameStatus( true ); + std::cout << "FIN PARTIE" << std::endl; + return; + } + + if ( event.type == SDL_MOUSEBUTTONDOWN ) + { + Mouse::GetInstance()->TraiteClic(&event); + } + if ( event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) + { + if (event.type == SDL_KEYUP && event.key.keysym.sym == SDLK_ESCAPE) + { + Game::GetInstance()->SetEndOfGameStatus( true ); + std::cout << "FIN PARTIE" << std::endl; + return; + } + + Clavier::GetInstance()->HandleKeyEvent( &event); + } + } // How many frame by seconds ? fps.Refresh(); @@ -284,6 +305,7 @@ Clavier::GetInstance()->Refresh(); } + ActionHandler::GetInstance()->ExecActions(); do { ActionHandler::GetInstance()->ExecActions(); @@ -532,10 +554,10 @@ Interface::GetInstance()->EnableDisplayTimer(true); pause_seconde = global_time->Read(); - if (network.IsServer() || network.IsLocal()) - wind.ChooseRandomVal(); + if (replay.IsRecording() || network.IsServer() || network.IsLocal()) + wind.ChooseRandomVal(); - character_already_chosen = false; + character_already_chosen = false; // Pr pare un tour pour un ver FOR_ALL_LIVING_CHARACTERS(equipe,ver) ver -> PrepareTurn(); @@ -543,7 +565,7 @@ // Changement d' quipe assert (!Game::GetInstance()->IsGameFinished()); - if(network.IsLocal() || network.IsServer()) + if(!replay.IsPlaying() && (network.IsLocal() || network.IsServer())) { do { Index: src/game/game_loop.h =================================================================== --- src/game/game_loop.h (revision 934) +++ src/game/game_loop.h (working copy) @@ -72,6 +72,7 @@ private: GameLoop(); + void InitGameData_RePlay(); void InitGameData_NetServer(); void InitGameData_NetClient(); void InitData_Local(); Index: src/game/game.cpp =================================================================== --- src/game/game.cpp (revision 934) +++ src/game/game.cpp (working copy) @@ -36,6 +36,7 @@ #include "../interface/mouse.h" #include "../map/camera.h" #include "../map/map.h" +#include "../replay/replay.h" #include "../menu/results_menu.h" #include "../sound/jukebox.h" #include "../team/macro.h" @@ -127,6 +128,55 @@ return answer; } +void Game::Replay(const std::string& name) +{ + std::string err_msg; + bool err=true; + + try + { + replay.Init(false); + if (replay.LoadReplay(name.c_str())) + { + if (replay.StartPlaying()) + { + GameLoop::GetInstance()->Init (); + + isGameLaunched = true; + GameLoop::GetInstance()->fps.Reset(); + + SetEndOfGameStatus( false ); + replay.SetWaitState(Replay::WAIT_NOT); + + printf("Running game loop instance\n"); + GameLoop::GetInstance()->Run(); + + err = false; + replay.StopPlaying(); + } + } + replay.DeInit(); + } + catch (const std::exception &e) + { + err_msg = e.what(); + } + + world.FreeMem(); + teams_list.UnloadGamingData(); + jukebox.StopAll(); + Mouse::GetInstance()->SetPointer(POINTER_STANDARD); + + + if (err) + { + std::string txt = Format(_("Error:\n%s"), err_msg.c_str()); + std::cout << std::endl << txt << std::endl; + question.Set (txt, true, 0); + AskQuestion (false); + } +} + void Game::Start() { bool err=true; @@ -135,6 +185,11 @@ try { + // We always record, only stuff that matters is whether we discard recording + replay.Init(true); + if (!replay.StartRecording()) + MSG_DEBUG( "game", "Couldn't start recording game" ); + GameLoop::GetInstance()->Init (); do @@ -177,6 +232,8 @@ } } while (!end); err = false; + + replay.StopRecording(); } catch (const std::exception &e) { @@ -186,6 +243,7 @@ if (!err) if (IsGameFinished()) MessageEndOfGame(); + replay.DeInit(); world.FreeMem(); teams_list.UnloadGamingData(); Index: src/map/maps_list.cpp =================================================================== --- src/map/maps_list.cpp (revision 934) +++ src/map/maps_list.cpp (working copy) @@ -45,8 +45,6 @@ bool InfoTerrain::Init (const std::string &map_name, const std::string &directory) { - std::string nomfich; - m_directory = directory; res_profile = NULL; @@ -54,7 +52,7 @@ try { - nomfich = m_directory+"config.xml"; + std::string nomfich = m_directory+"config.xml"; // Load resources if (!IsFileExist(nomfich)) Index: src/tool/rectangle.h =================================================================== --- src/tool/rectangle.h (revision 934) +++ src/tool/rectangle.h (working copy) @@ -33,7 +33,7 @@ * * @param T Type for position and size of the Rectangle */ -template<class T> class Rectangle +template<class T> class WmxRectangle { protected: /** Position of the rectangle. */ @@ -45,7 +45,7 @@ /** * Default constructor */ - inline Rectangle(){ + inline WmxRectangle(){ } /** @@ -56,7 +56,7 @@ * @param width Width of the new rectangle. * @param height Height of the new rectangle. */ - inline Rectangle(T x, T y, T width, T height){ + inline WmxRectangle(T x, T y, T width, T height){ position.SetValues( x, y ); size.SetValues( width, height ); } @@ -67,7 +67,7 @@ * @param thePosition Position of the new rectangle. * @param theSize Size of the new rectangle. */ - inline Rectangle(Vector2<T> thePosition, Vector2<T> theSize){ + inline WmxRectangle(Vector2<T> thePosition, Vector2<T> theSize){ position = thePosition; size = theSize; } @@ -141,7 +141,7 @@ size = newSize; } - inline Rectangle<T> GetRectangle() const{ + inline WmxRectangle<T> GetRectangle() const{ return *this; } @@ -180,7 +180,7 @@ * * @param cr The rectangle used for clipping */ - void Clip( const Rectangle &cr){ + void Clip( const WmxRectangle &cr){ if( !Intersect(cr) ){ size.x = 0; size.y = 0; @@ -236,7 +236,7 @@ * * @param r2 The rectangle for witch the check if performed. */ - inline bool Contains( const Rectangle<T> &r2 ) const{ + inline bool Contains( const WmxRectangle<T> &r2 ) const{ if( r2.IsSizeZero() ) return false; @@ -250,7 +250,7 @@ * * @param r2 The second rectangle. */ - inline bool Intersect( const Rectangle<T> &r2 ) const{ + inline bool Intersect( const WmxRectangle<T> &r2 ) const{ if( IsSizeZero() || r2.IsSizeZero() ) return false; @@ -325,7 +325,7 @@ } }; -typedef Rectangle<int> Rectanglei; -typedef Rectangle<float> Rectanglef; -typedef Rectangle<double> Rectangled; +typedef WmxRectangle<int> Rectanglei; +typedef WmxRectangle<float> Rectanglef; +typedef WmxRectangle<double> Rectangled; #endif // _RECTANGLE_H
_______________________________________________ Wormux-dev mailing list Wormux-dev@gna.org https://mail.gna.org/listinfo/wormux-dev