/* 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 "audio/audio.h" #include "audio/sources.h" #include "client/client.h" #include "client/video.h" #include "client/input.h" #include "client/view.h" #include "core/core.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_view = 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_view = new View(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("ui_chat", Client::func_ui_chat); func->set_info("toggle chat window"); func = core::Func::add("ui_chatsmall", Client::func_ui_chatsmall); func->set_info("toggle small chat window"); func = core::Func::add("snd_restart", Client::func_snd_restart); func->set_info("restart audio subsystem"); previous_timestamp = 0; } void Client::run() { con_print << "^BRunning client..." << std::endl; // 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) { core::Application::frame(timestamp); if (!core::application()->connected()) { // load the intro if nothing is running if (core::application()->load("intro")) { core::application()->connect(""); } // show the console if everything fails if (!core::application()->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()) { if (ui::root()->active()->label().compare("join") == 0) { ui::root()->hide_menu(); } } } video::frame((float)(timestamp - previous_timestamp) / 1000.0f); input::frame(); previous_timestamp = timestamp; } void Client::shutdown() { con_print << "^BShutting down client..." << std::endl; if (connected()) disconnect(); core::Func::remove("r_restart"); core::Func::remove("ui_chat"); core::Func::remove("ui_chatsmall"); core::Func::remove("snd_restart"); audio::shutdown(); input::shutdown(); video::shutdown(); ui::shutdown(); core::Application::shutdown(); quit(0); } /* -- notifications from core::Application ------------------------- */ void Client::notify_connect() { view()->notify()->clear(); ui::root()->hide_menu(); } void Client::notify_disconnect() { audio::reset(); render::reset(); input::reset(); // TODO clear chat and notifications } void Client::notify_zonechange() { 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 (view()) { view()->chat()->event_text(message); view()->notify()->event_text(message); } con_print << message << std::endl; } /* FIXME these notifications are hacks and need to be fixed */ void Client::notify_remove_sound(size_t source) { audio::Sources::remove(source); } //--- 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 (entity->state()) entity->state()->clearsound(); } audio::reset(); } void Client::func_r_restart(std::string const &args) { video::restart(); } void Client::func_ui_chat(std::string const &args) { if (core::application()->connected()) { client()->view()->chat()->set_small_view(false); client()->view()->chat()->toggle(); } } void Client::func_ui_chatsmall(std::string const &args) { if (core::application()->connected()) { client()->view()->chat()->set_small_view(true); client()->view()->chat()->toggle(); } } } // namespace client