/* * $Id: client.cc,v 1.10 2002/09/19 00:18:43 aeneas Exp $ * Copyright (c) 2002, Dominik Schnitzer * * JFK - JFK Fucking Killerz, a massive multiplayer 2d shoot'em-up game * http://relax.ath.cx/jfk/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include "exception.h" #include "clock.h" #include "level.h" #include "panel.h" #include "game.h" #include "network.h" #include "parse.h" #include "output.h" #include "objects_c.h" #include "debug.h" #include "console.h" #include "conffile.h" using namespace std; using namespace JFK::client; namespace JFK { namespace client { class program { public: program(); ~program(); bool init_game(); bool init_graphics(); void start_game(); void start_splash(); private: void process_network(); void process_events(); /* Visible objects to be managed */ output *out; level *lvl; panel *pnl; console *cons; /* The network backend */ JFK::network_client *nc; event_t evd; string playername; JFK::conffile cf; }; } } static const JFK::variable vars[] = { { "server", "localhost", NULL }, { "port", JFK::DEFAULT_PORT, NULL }, { "name", NULL, NULL }, #if !defined(_WIN32) { "artdir", JFKARTDIR, NULL }, #else { "artdir", "art", NULL }, #endif { "output", defaultplugin_name(), NULL }, }; #if !defined(_WIN32) #define CONFFILE "~/.jfkclientrc" #else #define CONFFILE "jfkclient.ini" #endif program::program() : out(NULL), lvl(NULL), pnl(NULL), cons(NULL), nc(NULL), cf(vars, sizeof vars / sizeof *vars, CONFFILE) { } program::~program() { delete nc; delete lvl; delete pnl; delete cons; delete out; } bool program::init_graphics() { /* suck in the configuration file */ cf.read(); output_plugins out_plugins; out = out_plugins.get_plugin(cf.getvar("output"), cf); return out; } void program::start_splash() { image splash = out->load_image("splash", "screen.png"); do { out->draw_image(splash, 0, 0); out->show(); out->poll_events(&evd); } while (evd.ev[EVENT_FIRE] != EVENTSTATE_DONE); out->free_image(splash); } bool program::init_game() { pnl = new panel(out); cons = new console(out, 2); JFK::clock cl; string msg; nc = new JFK::network_client(cf.getvar("server"), cf.getvar("port")); playername = cf.getvar("name"); /* Establishing Network Connection to Server */ LOG(("Establishing network-connection...")); nc->send(playername); while (!nc->receive(&msg)) { nc->dispatch(); cl.delay(1000); LOG(("Trying to connect to server...")); }; istringstream fiss(msg); string xssize; string yssize; fiss >> xssize; fiss >> yssize; int maxx = JFK::strtoint(JFK::value(xssize)); int maxy = JFK::strtoint(JFK::value(yssize)); lvl = new level(out, maxx, maxy); return true; } void program::process_network() { nc->dispatch(); string msg; while (nc->receive(&msg)) { istringstream iss(msg); string action; string tmp; string rest(""); unsigned long id; LOG(("Received: %s", msg.c_str())); if (msg == JFK::CMD_LEVEL_TRANSFERRED) continue; iss >> action; if (iss.fail()) { LOG(("Received: bad string")); continue; } /* Need to create a new object */ if (action == JFK::CMD_NEW) { lvl->create_object(msg.substr(action.length() + 1)); continue; } /* A message arrived, display it */ if (action == JFK::CMD_MSG) { string m = msg.substr(action.length() + 1); m.replace(m.find(":"), 1, ": "); cons->add_log(m); continue; } /* If we've come that far, try to read the object id for the object * to deal with */ iss >> id; if (iss.fail()) { LOG(("Received: bad string.")); continue; } /* Update the given object with new data */ if (action == JFK::CMD_UPDATE) { while (iss >> tmp) rest += ' ' + tmp; lvl->update_object(id, rest); } /* Delete an object */ if (action == JFK::CMD_DELETE) { lvl->delete_object(id); } } } void program::process_events() { out->poll_events(&evd); if (evd.ev[EVENT_UP] == EVENTSTATE_BEGIN) nc->send(JFK::CMD_MOVE_FORWARD); if (evd.ev[EVENT_DOWN] == EVENTSTATE_BEGIN) nc->send(JFK::CMD_MOVE_BACK); if ((evd.ev[EVENT_UP] == EVENTSTATE_DONE) || (evd.ev[EVENT_DOWN] == EVENTSTATE_DONE)) nc->send(JFK::CMD_MOVE_STOP); if (evd.ev[EVENT_LEFT] == EVENTSTATE_BEGIN) nc->send(JFK::CMD_TURN_LEFT); if (evd.ev[EVENT_RIGHT] == EVENTSTATE_BEGIN) nc->send(JFK::CMD_TURN_RIGHT); if ((evd.ev[EVENT_RIGHT] == EVENTSTATE_DONE) || (evd.ev[EVENT_LEFT] == EVENTSTATE_DONE)) nc->send(JFK::CMD_TURN_STOP); if (evd.ev[EVENT_FIRE] == EVENTSTATE_BEGIN) nc->send(JFK::CMD_FIRE_START); if (evd.ev[EVENT_FIRE] == EVENTSTATE_DONE) nc->send(JFK::CMD_FIRE_STOP); if (evd.ev[EVENT_CHANGE_WEAPON] == EVENTSTATE_DONE) nc->send(JFK::CMD_CHANGE_WEAPON); if (evd.ev[EVENT_MESSAGE] == EVENTSTATE_BEGIN) cons->set_input("Your Message: " + evd.msg, CONSOLE_INPUTEXT); if (evd.ev[EVENT_MESSAGE] == EVENTSTATE_DONE) { cons->set_input("", CONSOLE_INPUTDONE); if (evd.msg != "") nc->send(JFK::CMD_MSG + " " + evd.msg); } } void program::start_game() { JFK::clock clock; clock.start(); do { /* Process Network */ process_network(); /* Process Events */ process_events(); /* Now draw & show everything */ lvl->draw(); pnl->draw(lvl->get_player()); cons->set_players(lvl->get_players()); cons->draw(); out->show(); /* Process all Objects (Move them) */ lvl->move_objects(clock.diff()); } while (evd.ev[EVENT_ESC] != EVENTSTATE_DONE); } extern "C" { int main(int argc, char* argv[]) { const char* progname = "jfkclient"; if (argc >= 1) progname = argv[0]; if (argc > 1 && strcmp(argv[1], "--plugins") == 0) { output_plugins op; cerr << "Available video output drivers are:" << endl << op.list_plugins() << endl; return 0; } /* Main jfkclient loop */ try { program prog; /* For now, we try to initialize the game, if it fails exit. Actually * if initialization fails the user should be thrown back to the main * menu to enter another server etc. But this doesn't work at this * time */ if (prog.init_graphics()) { prog.start_splash(); if (prog.init_game()) prog.start_game(); } } catch (const JFK::exception& e) { cerr << progname << ": " << e.msg() << endl; return EXIT_FAILURE; } return EXIT_SUCCESS; } }