/* client/client.cc This file is part of the Osirion project and is distributed under the terms and conditions of the GNU General Public License version 2 */ #include #include #include #include #include #include "audio/audio.h" #include "audio/sources.h" #include "client/client.h" #include "client/video.h" #include "client/input.h" #include "core/core.h" #include "core/loader.h" #include "core/zone.h" #include "render/render.h" #include "ui/ui.h" namespace client { core::Cvar *cl_framerate = 0; core::Cvar *cl_frametime = 0; Client app; //--- public ------------------------------------------------------ Client *client() { return &app; } void run(int count, char **arguments) { std::cout << core::name() << " " << core::version() << std::endl; for (int i = 0; i < count; i++) std::cout << arguments[i] << " "; std::cout << std::endl; app.init(count, arguments); app.run(); app.shutdown(); } //--- private ----------------------------------------------------- void Client::quit(int status) { SDL_Quit(); core::Application::quit(status); } void Client::init(int count, char **arguments) { client_worldview = 0; con_print << "^BInitializing client..." << std::endl; // initialize core core::Cvar::sv_private = core::Cvar::set("sv_private", "0"); core::Application::init(count, arguments); // engine variables cl_framerate = core::Cvar::get("cl_framerate", "125", core::Cvar::Archive); cl_framerate->set_info("[int] client framerate in frames/sec"); // player info variables core::Cvar *cvar = 0; cvar = core::Cvar::get("cl_name", "Player", core::Cvar::Archive | core::Cvar::Info); cvar->set_info("[str] player name"); cvar = core::Cvar::get("cl_color", "1.0 1.0 1.0", core::Cvar::Archive | core::Cvar::Info); cvar->set_info("[r g b] player primary color"); cvar = core::Cvar::get("cl_colorsecond", "1.0 1.0 1.0", core::Cvar::Archive | core::Cvar::Info); cvar->set_info("[r g b] player secondary color"); cvar = core::Cvar::get("rconpassword", "", core::Cvar::Archive | core::Cvar::Info); cvar->set_info("[string] password for remote console access"); // initialize SDL, but do not initialize any subsystems SDL_Init(0); // initialize user interface ui::init(); client_worldview = new WorldView(ui::root()); // Initialize the video subsystem if (!video::init()) { quit(1); } // initialize input input::init(); // initialize audio audio::init(); // add engine functions core::Func *func = 0; func = core::Func::add("r_restart", Client::func_r_restart); func->set_info("restart render subsystem"); func = core::Func::add("snd_restart", Client::func_snd_restart); func->set_info("restart audio subsystem"); func = core::Func::add("list_ui", func_list_ui); func->set_info("list user interface widgets"); func = core::Func::add("list_menu", func_list_menu); func->set_info("list available menus"); func = core::Func::add("ui", func_ui); func->set_info("[command] user interface functions"); func = core::Func::add("ui_restart", func_ui_restart); func->set_info("reload user interface files"); func = core::Func::add("ui_console", func_ui_console); func->set_info("toggle console"); func = core::Func::add("ui_chat", Client::func_ui_chat); func->set_info("toggle chat window"); func = core::Func::add("ui_chatbar", Client::func_ui_chatbar); func->set_info("toggle chat bar"); func = core::Func::add("ui_map", Client::func_ui_map); func->set_info("toggle map"); func = core::Func::add("ui_menu", Client::func_ui_menu); func->set_info("toggle main menu"); func = core::Func::add("menu", func_menu); func->set_info("[command] menu functions"); func = core::Func::add("view", func_view); func->set_info("[command] view menu functions"); previous_timestamp = 0; } void Client::run() { con_print << "^BRunning client..." << std::endl; // seed random generator unsigned int seed = (unsigned int) SDL_GetTicks(); srand(seed); // default framerate 125fps, 8 milliseconds Uint32 client_frame_lenght = 8; Uint32 client_current_timestamp = 0; Uint32 client_previous_timestamp = 0; while (true) { // current time in microseconds client_current_timestamp = SDL_GetTicks(); // calculate the desired frame length if (cl_framerate->value() < 0) { (*cl_framerate) = 0.0f; } else if (cl_framerate->value() > 1000.0f) { (*cl_framerate) = 1000.0f; } if (cl_framerate->value()) { client_frame_lenght = (Uint32) roundf(1000.0f / cl_framerate->value()); } else { client_frame_lenght = 0; } // only advance per microsecond frame Uint32 d = client_current_timestamp - client_previous_timestamp; if ((d > 0)) { if (d >= client_frame_lenght) { frame(client_current_timestamp); client_previous_timestamp = client_current_timestamp; } else { SDL_Delay(client_frame_lenght - d); } } else { SDL_Delay(1); } } } void Client::frame(unsigned long timestamp) { input::frame(); core::Application::frame(timestamp); if (!connected()) { std::string module_label(core::Loader::label()); // load the intro if nothing is running if (load("intro")) { connect(""); if (module_label.size()) load(module_label); } // show the console if everything fails if (!connected() && !ui::console()->visible()) { ui::console()->toggle(); } } else if (!ui::root()->active()) { // show the main menu on non-interactive modules if (!core::game()->interactive()) { ui::root()->show_menu("main"); // show the join menu when player does not control an entity } else if (core::game()->time() && !core::localcontrol()) { ui::root()->show_menu("join"); } } else { if (core::localcontrol()) { // hide join menu if (ui::root()->active()->label().compare("join") == 0) { ui::root()->hide_menu(); } } } video::frame((float)(timestamp - previous_timestamp) / 1000.0f); previous_timestamp = timestamp; } void Client::shutdown() { con_print << "^BShutting down client..." << std::endl; if (connected()) disconnect(); core::Func::remove("r_restart"); core::Func::remove("snd_restart"); core::Func::remove("list_menu"); core::Func::remove("list_ui"); core::Func::remove("ui"); core::Func::remove("ui_restart"); core::Func::remove("ui_console"); core::Func::remove("ui_chat"); core::Func::remove("ui_chatbar"); core::Func::remove("ui_map"); core::Func::remove("ui_menu"); core::Func::remove("menu"); core::Func::remove("view"); audio::shutdown(); input::shutdown(); video::shutdown(); ui::shutdown(); core::Application::shutdown(); quit(0); } /* -- notifications from core::Application ------------------------- */ void Client::notify_connect() { video::set_loader_message(); video::frame_loader(); worldview()->clear(); ui::root()->hide_menu(); video::set_caption(); } void Client::notify_disconnect() { audio::reset(); render::reset(); input::reset(); worldview()->clear(); video::set_caption(); } void Client::notify_zonechange() { video::set_loader_message(); video::frame_loader(); // unload entity sounds for (core::Entity::Registry::iterator it = core::Entity::registry().begin(); it != core::Entity::registry().end(); it++) { core::Entity *entity = (*it).second; if (ext_sound(entity)) delete ext_sound(entity); } render::unload(); } void Client::notify_sound(const char *name) { audio::play(name); } void Client::notify_message(const char *message) { std::string text(message); notify_message(core::Message::Info, text); } void Client::notify_message(const std::string &message) { notify_message(core::Message::Info, message); } void Client::notify_message(const core::Message::Channel channel, const std::string &message) { switch (channel) { case core::Message::Info: // Info message break; case core::Message::Local: // Chat message in the local zone break; case core::Message::RCon: // RCon message break; case core::Message::Public: // Public chat message audio::play("com/chat"); break; case core::Message::Private: // Private chat message audio::play("com/priv"); break; default: break; } if (worldview()) { worldview()->event_text(message); } con_print << message << std::endl; } void Client::notify_loader(const std::string &message) { video::set_loader_message(message.c_str()); } //--- engine functions -------------------------------------------- void Client::func_snd_restart(std::string const &args) { // unload entity sounds for (core::Entity::Registry::iterator it = core::Entity::registry().begin(); it != core::Entity::registry().end(); it++) { core::Entity *entity = (*it).second; if (ext_sound(entity)) delete ext_sound(entity); } audio::reset(); } void Client::func_r_restart(std::string const &args) { video::restart(); video::set_loader_message(); video::frame_loader(); } /* ---- func_ui ---------------------------------------------------- */ void Client::func_list_ui(std::string const &args) { if (ui::root()) { ui::root()->list(); } } void Client::func_ui_restart(std::string const &args) { if (ui::root()) { ui::root()->load_menus(); ui::root()->load_settings(); ui::root()->apply_render_options(); } } void Client::func_ui_console(std::string const &args) { ui::console()->toggle(); } void Client::func_list_menu(std::string const &args) { if (ui::root()) { ui::root()->list_menus(); } } void Client::func_ui_help() { con_print << "^BUser interface functions" << std::endl; con_print << " ui help show this help" << std::endl; con_print << " ui debug toggle debug mode" << std::endl; con_print << " ui list list widgets" << std::endl; con_print << " ui visible list visible widgets" << std::endl; con_print << " ui restart reload user interface files" << std::endl; } void Client::func_ui(std::string const &args) { if (!ui::root()) { con_warn << "User Interface not available!" << std::endl; return; } if (!args.size()) { func_ui_help(); return; } std::stringstream argstr(args); std::string command; argstr >> command; aux::to_label(command); if (command.compare("help") == 0) { func_ui_help(); } else if (command.compare("debug") == 0) { ui::UI::ui_debug = !ui::UI::ui_debug; } else if (command.compare("list") == 0) { ui::root()->list(); } else if (command.compare("visible") == 0) { ui::root()->list_visible(); } else if (command.compare("restart") == 0) { ui::root()->load_menus(); ui::root()->load_settings(); ui::root()->apply_render_options(); } else { func_ui_help(); } } void Client::func_ui_chat(std::string const &args) { if (client()->connected() && client()->worldview()->playerview()->visible()) { client()->worldview()->playerview()->toggle_chat(); } } void Client::func_ui_chatbar(std::string const &args) { if (client()->connected() && client()->worldview()->playerview()->visible()) { client()->worldview()->playerview()->toggle_chatbar(); } } void Client::func_ui_map(std::string const &args) { if (client()->connected() && client()->worldview()->playerview()->visible()) { client()->worldview()->playerview()->toggle_map(); } } void Client::func_ui_menu(std::string const &args) { if (client()->connected()) { if (ui::root()->active()) { ui::root()->hide_menu(); } else { // show the main menu on non-interactive modules if (!core::game()->interactive()) { ui::root()->show_menu("main"); } else { ui::root()->show_menu("game"); } } } else { con_print << "Not connected." << std::endl; } } // entity menus void Client::func_view(std::string const &args) { if (client()->worldview()) { client()->worldview()->playerview()->show_menu(args); } } // global menus void Client::func_menu(std::string const &args) { if (!ui::root()) { con_warn << "User Interface not available!" << std::endl; return; } if (!args.size()) { con_print << "^Bmenu functions" << std::endl; con_print << " menu help show this help" << std::endl; con_print << " menu list list available menus" << std::endl; con_print << " menu [name] show a menu" << std::endl; con_print << " menu back return to the previous menu" << std::endl; con_print << " menu previous return to the previous menu" << std::endl; con_print << " menu close close the current menu" << std::endl; con_print << " menu hide hide the current menu" << std::endl; ui::root()->list_menus(); } std::stringstream argstr(args); std::string command; argstr >> command; aux::to_label(command); if (command.compare("hide") == 0) { ui::root()->hide_menu(); } else if (command.compare("close") == 0) { ui::root()->hide_menu(); } else if (command.compare("back") == 0) { ui::root()->previous_menu(); } else if (command.compare("previous") == 0) { ui::root()->previous_menu(); } else if (command.compare("list") == 0) { ui::root()->list_menus(); } else { ui::root()->show_menu(command.c_str()); } } } // namespace client