355 lines
9.8 KiB
C++
355 lines
9.8 KiB
C++
#include "events.hpp"
|
|
#include "font.hpp"
|
|
#include "image.hpp"
|
|
#include "key.hpp"
|
|
#include "language.hpp"
|
|
#include "multiplayer_lobby.hpp"
|
|
#include "network.hpp"
|
|
#include "preferences.hpp"
|
|
#include "show_dialog.hpp"
|
|
#include "widgets/textbox.hpp"
|
|
#include "widgets/button.hpp"
|
|
#include "widgets/menu.hpp"
|
|
|
|
#include "SDL.h"
|
|
|
|
#include <sstream>
|
|
|
|
namespace {
|
|
int xscale(display& disp, int x)
|
|
{
|
|
return (x*disp.x())/1024;
|
|
}
|
|
|
|
int yscale(display& disp, int y)
|
|
{
|
|
return (y*disp.y())/768;
|
|
}
|
|
}
|
|
|
|
namespace lobby {
|
|
|
|
RESULT enter(display& disp, config& game_data, const config& terrain_data, dialog* dlg,
|
|
std::vector<std::string>& messages)
|
|
{
|
|
const events::resize_lock prevent_resizing;
|
|
|
|
CKey key;
|
|
|
|
scoped_sdl_surface background(image::get_image("misc/lobby.png",image::UNSCALED));
|
|
background.assign(scale_surface(background,disp.x(),disp.y()));
|
|
|
|
if(background == NULL) {
|
|
return QUIT;
|
|
}
|
|
|
|
SDL_BlitSurface(background, NULL, disp.video().getSurface(), NULL);
|
|
update_whole_screen();
|
|
|
|
gui::textbox message_entry(disp,500);
|
|
|
|
bool last_escape = true;
|
|
|
|
int game_selection = 0, user_selection = 0;
|
|
|
|
for(bool first_time = true; ; first_time = false) {
|
|
message_entry.set_focus(true);
|
|
|
|
const SDL_Rect dlg_rect = {xscale(disp,19),yscale(disp,23),xscale(disp,832),yscale(disp,520)};
|
|
|
|
//if the dialog is present, back it up before we repaint the entire screen
|
|
surface_restorer dlg_restorer;
|
|
if(dlg != NULL && first_time == false) {
|
|
dlg_restorer = surface_restorer(&disp.video(),dlg_rect);
|
|
}
|
|
|
|
SDL_BlitSurface(background, NULL, disp.video().getSurface(), NULL);
|
|
|
|
dlg_restorer.restore();
|
|
dlg_restorer = surface_restorer();
|
|
|
|
// Display Chats
|
|
std::stringstream text;
|
|
for(size_t n = messages.size() > 60 ? messages.size()-60 : 0;
|
|
n != messages.size(); ++n) {
|
|
text << messages[n] << "\n";
|
|
}
|
|
|
|
const SDL_Rect chat_area = { xscale(disp,19), yscale(disp,574), xscale(disp,832), yscale(disp,130) };
|
|
|
|
gui::textbox chat_textbox(disp,chat_area.w,text.str(),false);
|
|
chat_textbox.set_location(chat_area);
|
|
chat_textbox.set_wrap(true);
|
|
chat_textbox.scroll_to_bottom();
|
|
|
|
std::vector<std::string> options;
|
|
std::vector<bool> game_vacant_slots, game_observers;
|
|
|
|
const config* const gamelist = game_data.child("gamelist");
|
|
|
|
if(dlg == NULL) {
|
|
// Game List GUI
|
|
if(gamelist == NULL) {
|
|
std::cerr << "ERROR: could not find gamelist\n";
|
|
return QUIT;
|
|
}
|
|
|
|
config::const_child_itors i;
|
|
for(i = gamelist->child_range("game"); i.first != i.second; ++i.first) {
|
|
|
|
std::cerr << "game data here:" << (**i.first).write() << "end game data here\n";
|
|
|
|
std::stringstream str;
|
|
|
|
//if this is the item that should be selected, make it selected by default
|
|
if(game_selection-- == 0) {
|
|
str << "*";
|
|
}
|
|
|
|
std::string map_data = (**i.first)["map_data"];
|
|
if(map_data == "") {
|
|
map_data = read_file("data/maps/" + (**i.first)["map"]);
|
|
}
|
|
|
|
if(map_data != "") {
|
|
try {
|
|
gamemap map(terrain_data,map_data);
|
|
SDL_Surface* const mini = image::getMinimap(100,100,map,0);
|
|
|
|
//generate a unique id to show the map as
|
|
char buf[50];
|
|
sprintf(buf,"addr %d",(int)mini);
|
|
|
|
image::register_image(buf,mini);
|
|
|
|
str << "&" << buf << ",";
|
|
} catch(gamemap::incorrect_format_exception& e) {
|
|
std::cerr << "illegal map: " << e.msg_ << "\n";
|
|
}
|
|
} else {
|
|
str << "(" << translate_string("shroud") << "),";
|
|
}
|
|
|
|
std::string name = (**i.first)["name"];
|
|
if(name.size() > 30)
|
|
name.resize(30);
|
|
|
|
str << name;
|
|
|
|
const std::string& turn = (**i.first)["turn"];
|
|
const std::string& slots = (**i.first)["slots"];
|
|
if(turn != "") {
|
|
str << "," << translate_string("turn") << " " << turn;
|
|
} else if(slots != "") {
|
|
str << "," << slots << " " << string_table[slots == "1" ? "vacant_slot" : "vacant_slots"];
|
|
}
|
|
|
|
options.push_back(str.str());
|
|
game_vacant_slots.push_back(slots != "" && slots != "0");
|
|
game_observers.push_back((**i.first)["observer"] != "no");
|
|
}
|
|
}
|
|
|
|
const bool games_available = dlg == NULL && options.empty() == false;
|
|
if(!games_available) {
|
|
options.push_back("<no games open>");
|
|
}
|
|
|
|
gui::menu games_menu(disp,options);
|
|
gui::button observe_game(disp,string_table["observe_game"]);
|
|
gui::button join_game(disp,string_table["join_game"]);
|
|
gui::button new_game(disp,string_table["create_new_game"]);
|
|
gui::button quit_game(disp,string_table["quit_button"]);
|
|
|
|
if(dlg != NULL) {
|
|
observe_game.hide();
|
|
join_game.hide();
|
|
new_game.hide();
|
|
quit_game.hide();
|
|
}
|
|
|
|
if(games_menu.selection() >= 0 && games_menu.selection() < int(game_vacant_slots.size())) {
|
|
assert(game_vacant_slots.size() == game_observers.size());
|
|
|
|
join_game.hide(!game_vacant_slots[games_menu.selection()]);
|
|
observe_game.hide(!game_observers[games_menu.selection()]);
|
|
} else {
|
|
observe_game.hide();
|
|
join_game.hide();
|
|
}
|
|
|
|
std::vector<std::string> users;
|
|
for(config::const_child_itors i = game_data.child_range("user"); i.first != i.second; ++i.first) {
|
|
std::string name = (**i.first)["name"];
|
|
if(name.size() > 30)
|
|
name.resize(30);
|
|
|
|
const std::string avail = (**i.first)["available"];
|
|
|
|
//display unavailable players in red
|
|
if(avail == "no") {
|
|
name.insert(name.begin(),'#');
|
|
}
|
|
|
|
//if this user should be selected
|
|
if(user_selection-- == 0) {
|
|
name.insert(name.begin(),'*');
|
|
}
|
|
|
|
users.push_back(name);
|
|
}
|
|
|
|
if(users.empty()) {
|
|
users.push_back(preferences::login());
|
|
}
|
|
|
|
std::cerr << "have " << users.size() << " users\n";
|
|
|
|
if(users.empty()) {
|
|
std::cerr << "ERROR: empty user list received\n";
|
|
users.push_back("error");
|
|
}
|
|
|
|
gui::menu users_menu(disp,users);
|
|
|
|
// Set GUI locations
|
|
users_menu.set_loc(xscale(disp,869),yscale(disp,23));
|
|
users_menu.set_width(xscale(disp,129));
|
|
update_rect(xscale(disp,869),yscale(disp,23),xscale(disp,129),yscale(disp,725));
|
|
|
|
if(dlg != NULL) {
|
|
if(first_time) {
|
|
dlg->set_area(dlg_rect);
|
|
}
|
|
} else {
|
|
games_menu.set_loc(xscale(disp,19),yscale(disp,23));
|
|
games_menu.set_width(xscale(disp,832));
|
|
}
|
|
|
|
update_rect(xscale(disp,19),yscale(disp,23),xscale(disp,832),yscale(disp,520));
|
|
join_game.set_location(xscale(disp,19),yscale(disp,545));
|
|
observe_game.set_location(join_game.location().x + join_game.location().w + 5,yscale(disp,545));
|
|
new_game.set_location(observe_game.location().x + observe_game.location().w + 5,yscale(disp,545));
|
|
quit_game.set_location(new_game.location().x + new_game.location().w + 5,yscale(disp,545));
|
|
message_entry.set_location(xscale(disp,19),yscale(disp,725));
|
|
message_entry.set_width(xscale(disp,832));
|
|
|
|
update_whole_screen();
|
|
|
|
bool old_enter = true;
|
|
|
|
for(;;) {
|
|
int mousex, mousey;
|
|
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
|
|
|
|
const bool left_button = mouse_flags&SDL_BUTTON_LMASK;
|
|
|
|
if(dlg != NULL) {
|
|
const RESULT res = dlg->process();
|
|
if(res != CONTINUE) {
|
|
return res;
|
|
}
|
|
} else {
|
|
games_menu.process(mousex,mousey,left_button,
|
|
key[SDLK_UP],key[SDLK_DOWN],
|
|
key[SDLK_PAGEUP],key[SDLK_PAGEDOWN]);
|
|
|
|
if(games_menu.selection() >= 0 && games_menu.selection() < int(game_vacant_slots.size())) {
|
|
join_game.hide(!game_vacant_slots[games_menu.selection()]);
|
|
observe_game.hide(!game_observers[games_menu.selection()]);
|
|
}
|
|
}
|
|
|
|
users_menu.process(mousex,mousey,left_button,
|
|
key[SDLK_UP],key[SDLK_DOWN],
|
|
key[SDLK_PAGEUP],key[SDLK_PAGEDOWN]);
|
|
|
|
const bool observe = observe_game.pressed();
|
|
if(games_available && (observe || join_game.pressed() || games_menu.double_clicked())) {
|
|
const size_t index = size_t(games_menu.selection());
|
|
const config::const_child_itors i = gamelist->child_range("game");
|
|
assert(index < size_t(i.second - i.first));
|
|
const std::string& id = (**(i.first+index))["id"];
|
|
|
|
config response;
|
|
config& join = response.add_child("join");
|
|
join["id"] = id;
|
|
network::send_data(response);
|
|
return observe ? OBSERVE : JOIN;
|
|
}
|
|
|
|
if(dlg == NULL && new_game.pressed()) {
|
|
return CREATE;
|
|
break;
|
|
}
|
|
|
|
const bool enter = key[SDLK_RETURN] && !old_enter;
|
|
old_enter = key[SDLK_RETURN];
|
|
if(enter && message_entry.text().empty() == false) {
|
|
config msg;
|
|
config& child = msg.add_child("message");
|
|
child["message"] = message_entry.text();
|
|
child["sender"] = preferences::login();
|
|
network::send_data(msg);
|
|
message_entry.clear();
|
|
|
|
std::stringstream message;
|
|
message << "<" << child["sender"] << "> " << child["message"];
|
|
messages.push_back(message.str());
|
|
break;
|
|
}
|
|
|
|
if(dlg == NULL && (last_escape == false && key[SDLK_ESCAPE] || quit_game.process(mousex,mousey,left_button))){
|
|
return QUIT;
|
|
}
|
|
|
|
last_escape = bool(key[SDLK_ESCAPE]);
|
|
|
|
events::raise_process_event();
|
|
events::raise_draw_event();
|
|
|
|
chat_textbox.process();
|
|
|
|
user_selection = users_menu.selection();
|
|
game_selection = games_menu.selection();
|
|
|
|
//if the list is refreshed, we want to redraw the entire screen
|
|
config data;
|
|
bool got_data = false;
|
|
if(dlg == NULL || dlg->manages_network() == false) {
|
|
const network::connection res = network::receive_data(data);
|
|
if(res) {
|
|
got_data = true;
|
|
}
|
|
} else if(dlg != NULL && dlg->manages_network()) {
|
|
got_data = dlg->get_network_data(data);
|
|
}
|
|
|
|
if(got_data) {
|
|
if(data.child("gamelist")) {
|
|
game_data = data;
|
|
break;
|
|
} else if(data.child("gamelist_diff")) {
|
|
game_data.apply_diff(*data.child("gamelist_diff"));
|
|
break;
|
|
} else if(data.child("error")) {
|
|
throw network::error((*data.child("error"))["message"]);
|
|
} else if(data.child("message")) {
|
|
const config& msg = *data.child("message");
|
|
std::stringstream message;
|
|
message << "<" << msg["sender"] << "> " << msg["message"];
|
|
messages.push_back(message.str());
|
|
break;
|
|
}
|
|
|
|
update_whole_screen();
|
|
}
|
|
|
|
events::pump();
|
|
disp.video().flip();
|
|
SDL_Delay(20);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|