//================================================== // X11Interface.C // // Ugly hack to turn the Motif interface // into a X11-only interface. This is // really awfull, and doesn't work anyway. // // ZNibbles // Vincent Mallet 1997 //================================================== // $Id: X11Interface.C,v 1.11 1999/05/12 11:43:41 vmallet Exp $ /* ZNibbles - a small multiplayer game * Copyright (C) 1997, 1998, 1999 Vincent Mallet - vmallet@enst.fr * * 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 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ //@@ this is almost dead code.. //@@ I don't think I'll ever finish it //@@ Maybe someone else ? :) #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "creer_socket.h" #include "Options.H" #include "LongObject.H" #include "Nibble.H" #include "Player.H" #include "Trame.H" #include "World.H" #include "NibblesArea.H" #include "X11Interface.H" int X11Interface::dead_server = 0; void X11Interface::init(int argc, char *argv[]) { struct sockaddr_in server_address; struct sockaddr_in client_address; int port; // server port we should connect to struct hostent * hp; // server address struct sigaction action; Options & options = * new Options(); options.set_option_set(OPTIONS_CLIENT_SET); if (!options.parse(argc, argv)) { fprintf(stderr, "Usage: %s [OPTION].. PLAYERNAME\n\n", *argv); fprintf(stderr, "Try `%s --help` for more options.\n", *argv); exit(2); } if (options.is_help()) { display_help(*argv); exit(0); } if (options.is_version()) { display_version_short(); exit(0); } _two_key = options.is_twokey(); // debug = options.is_debug(); _stdin_input = options.is_stdin_input(); own_name = options.get_player_name(); display_version(); if (_two_key) std::cout << "Two-key mode enabled" << std::endl; // connect pipe_handler to SIGPIPE signal // ('broken pipe' signal) memset(&action, 0, sizeof(action)); action.sa_handler = pipe_handler; sigaction(SIGPIPE, &action, NULL); // get IP address of server if (NULL == (hp = gethostbyname(options.get_host_name()))) { fprintf(stderr,"unknown host: %s\n", options.get_host_name()); exit(2); } std::cout << "Connecting to ZNibbles server: " \ << options.get_host_name() << ":" << options.get_port() << "... " << std::endl; // create and bind socket to any port port = 0; if ((socket_client = creer_socket(SOCK_STREAM, &port, &client_address)) == -1) { fprintf(stderr,"Unable to create client socket\n"); exit(2); } // if (debug) // std::cout << "Client socket created on port: " << ntohs(client_address.sin_port) << std::endl; // Build server address server_address.sin_family = AF_INET; server_address.sin_port = htons(options.get_port()); memcpy(&server_address.sin_addr.s_addr, hp->h_addr, hp->h_length); // try to connect to server if(connect(socket_client, (struct sockaddr *) & server_address, sizeof(server_address)) == -1) { perror("Connection to server failed"); fprintf(stderr, "Have you started the ZNibbles Server ?\n"); exit(2); } display_play_help(); std::cout << "Connection accepted\n" << std::endl; // hack_socket_client = socket_client; // hack for signal handling // action.sa_handler = stop_handler; // sigaction(SIGINT, &action, NULL); // sigaction(SIGTERM, &action, NULL); // sigaction(SIGUSR1, &action, NULL); init_messages(options.get_message_file()); std::cout << "initializing interface..." << std::endl; X11Init(argc, argv); } void X11Interface::X11Init(int argc, char **argv) { argc++; argv--; //@@ CHECK ME: just for the warnings display = XOpenDisplay(display_name); if (NULL == display) { printf("Unable to connect to display: %s\n", XDisplayName(display_name)); exit(1); } screen = DefaultScreen(display); display_width = DisplayWidth(display, screen); display_height = DisplayHeight(display, screen); /* Initialiser la taille de la fenetre en fonction de la taille de l'ecran */ width = display_width >> 1; height = display_height >> 1; win = XCreateSimpleWindow(display, RootWindow(display, screen), x, y, width, height, border_width, BlackPixel(display, screen), WhitePixel(display, screen)); XSelectInput(display, win, ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask); } // display version number (long format) void X11Interface::display_version() { std::cerr << "ZNibbles v" VERSION " - A little silly game - " << "(c) Vincent Mallet 1997, 1998, 1999 - vmallet@enst.fr" << std::endl << std::endl; } // display version number (short format) void X11Interface::display_version_short() { std::cout << "ZNibbles X11 Client -experimental- " VERSION << std::endl; } //display small help for invocation void X11Interface::display_help(char *name) { std::cout << "Usage: " << name << " [OPTION].. PLAYERNAME" << std::endl; std::cout << std::endl; std::cout << "Start a ZNibbles X11 client and connect to the specified nibbles server." << std::endl; std::cout << std::endl; std::cout << " -n, --host-name=HOST connect to server HOST [default is localhost]" << std::endl; std::cout << " -p, --port=NUM connect to port NUM of server [default is 5051]" << std::endl; std::cout << " -m, --message-file=FILE load predefined messages from file FILE" << std::endl; std::cout << " -t, --twokey control worm with only two keys, LEFT and RIGHT" << std::endl; std::cout << " -i, --enable-stdin enable standard input for sending messages" << std::endl; std::cout << " -d, --debug enable debug output" << std::endl; std::cout << " -V, --version print version number, then exit" << std::endl; std::cout << " -h, --help show this message and exit" << std::endl; std::cout << std::endl; std::cout << "Report bugs to ." << std::endl; } // display help on key used void X11Interface::display_play_help() { std::cout << std::endl; std::cout << "Welcome to ZNibbles!" << std::endl; std::cout << std::endl; std::cout << "Valid keys while playing:" << std::endl << std::endl << " Up, Down, Left, Right: move worm 1" << std::endl << std::endl << " p/u : pause/unpause game" << std::endl << std::endl << " P/U : pause/unpause _your_ worm" << std::endl << std::endl << " 1, 2, ... 0 : send predefined messages to other players" << std::endl << std::endl << " Ctrl+Q : quit game" << std::endl << std::endl << " Have fun!" << std::endl; } void X11Interface::pipe_handler(int sig) { std::cerr << "--- Lost Server Connection! ---" << std::endl; sig++; // warnings.. dead_server = 1; } void X11Interface::run() { World &w = world; join_game(); XMapWindow(display, win); nibblesarea.make(win, display); nibblesarea.set_config(); int z = 0; int done = 0; while (!done && !dead_server) { z++; if (t.receive_from(socket_client)) { // std::cout << "receive error, errno=" << errno << std::endl; handle_Xevent(); if (_stdin_input && read_ready(STDIN_FILENO)) { char s[500]; int dir = 0; fgets(s, 499, stdin); if (strcmp(s, "\x1b\x5b\x43") == 0) dir = D_RIGHT; else if (strcmp(s, "\x1b\x5b\x44") == 0) dir = D_LEFT; else if (strcmp(s, "\x1b\x5b\x41") == 0) dir = D_UP; else if (strcmp(s, "\x1b\x5b\x42") == 0) dir = D_DOWN; else { // broadcast message tx.put_char(TEXT_MESSAGE); tx.put_int(0); // broadcast tx.put_string(s); tx.send_to(socket_client); } if (dir) { std::cout << "Sending Direction ==" << dir << std::endl; tx.reset(); tx.put_char(PLAYER_CHANGEDIR); tx.put_char(dir); tx.send_to(socket_client); } } } else { switch(t.peek_char()) { case TRAME_ERROR: break; // on verra ca plus tard. case WORLD_DESC: std::cout << std::endl << "got WORLD_DESC " << std::endl; w.read_description(t); tx.reset(); tx.put_char(CYCLE_ACK); tx.send_to(socket_client); nibblesarea.make2(w.x_dim, w.y_dim); w.display(); break; case CHANGE_NOTIFY: //FAST std::cout << std::endl << "got CHANGE_NOTIFY " << std::endl; t.get_char(); w.read_changes(t); break; case VOID_TRAME: { std::cout << "got VOID_TRAME " << std::endl; t.get_char(); char *p = t.get_string(); if (p && strcmp(p, "w") == 0) w.display(); if (p && strcmp(p, "d") == 0) { w.draw(); w.map.display(); } if (p && strcmp(p, "D") == 0) { w.build_maptype(); w.map.display_t(); } } break; case TEXT_MESSAGE: { std::cout << "got *private* TEXT_MESSAGE == '"; t.get_char(); // skip packet id char *msg = t.get_string(); std::cout << msg << "'" << std::endl; } break; case YOUR_OTHER_PLAYER: { t.get_char(); int my_other_player_id = t.get_int(); my_other_player_id++; // @@ for warnings //@@ do something } break; case CYCLE_NOTIFY: { sent = 0; t.get_char(); w.cycle(); w.read_changes(t); tx.reset(); tx.put_char(CYCLE_ACK); send_direction(); tx.send_to(socket_client); w.draw(); nibblesarea.draw_from_map(w.map); handle_Xevent(); } break; case QUIT_GAME: std::cout << "Got QUIT_GAME" << std::endl; std::cout << "Client shutting down.... " << std::endl; done = 1; break; default: std::cout << "got unknown frame type: " << (int) t.peek_char() << std::endl; break; } } } w.display(); XCloseDisplay(display); close(socket_client); } void X11Interface::handle_Xevent() { XEvent report; while (XPending(display)) { XNextEvent(display, &report); switch(report.type) { case Expose: if (report.xexpose.count == 0) nibblesarea.redraw2(); break; case ButtonPress: std::cout << "ButtonPress" << std::endl; break; case KeyPress: nibblesarea.handle_key(&report); break; case ConfigureNotify: std::cout << "Configure" << std::endl; break; } } } void X11Interface::add_player(Player& p) { std::cout << "Player <" << p.get_name() <<"> joined the game!" << std::endl; } void X11Interface::kill_player(Player& p, int reason) { std::cout << "Player <" << p.get_name() <<"> LEFT the game! (reason=" << reason << ")" << std::endl; } void X11Interface::display_message(Player& from, char *msg, int priv) { if (priv) std::cout << "*private* Message: " << from.get_name() << "> " << msg << std::endl; else std::cout << "Message: " << from.get_name() << "> " << msg << std::endl; } void X11Interface::display_system_message(char *msg, Player *p, int color) // default p=NULL, color=0 { color++; std::cout << "*** "; if (p) std::cout << p->get_name() << " "; std::cout << msg; } void X11Interface::init_messages(char *filename) { FILE *f; predefined_messages[0] = "Hmmmmmmmmmmmmmmmmmmmmm.............."; predefined_messages[1] = "Chacal.............."; predefined_messages[2] = "Renard.............."; predefined_messages[3] = "Lezard.............."; predefined_messages[4] = "Tetard.............."; predefined_messages[5] = "Blatte.............."; predefined_messages[6] = "Belette.............."; predefined_messages[7] = "Giraffe.............."; predefined_messages[8] = "Pingouin.............."; predefined_messages[9] = "Loutre.............."; if (filename && (f = fopen(filename, "rt"))) { char buf[200]; for (int i = 0; i < 10 && fgets(buf, 300, f); i++) predefined_messages[i] = strdup(buf); fclose(f); } } void X11Interface::send_direction(Direction direction) // default direction=0 { if (direction) dirs.append(direction); if (!sent && dirs.length()) { send_direction0(dirs.front(), !direction); dirs.remove_front(); sent = 1; } } void X11Interface::send_direction0(Direction direction, int do_append) { if (!do_append) tx.reset(); tx.put_char(PLAYER_CHANGEDIR); tx.put_char(direction); if (!do_append) tx.send_to(socket_client); } void X11Interface::send_predefined_message(int num) { tx.reset(); tx.put_char(TEXT_MESSAGE); tx.put_int(0); // broadcast tx.put_string(predefined_messages[num]); tx.send_to(socket_client); } void X11Interface::pause_request(int pause_type) { tx.reset(); tx.put_char(pause_type); tx.send_to(socket_client); } void X11Interface::join_game() { t.put_char(JOIN_GAME); t.put_string(own_name); t.put_byte(_two_key); t.send_to(socket_client); t.set_timeout(4); }