Files
commandergenius/project/jni/application/lbreakout2-2.6.2/client/client_handlers.c
2010-12-24 12:04:06 +00:00

627 lines
19 KiB
C

/***************************************************************************
client_handlers.c - description
-------------------
begin : Sat Oct 26 12:02:57 CEST 2002
copyright : (C) 2002 by Michael Speck
email : kulkanie@gmx.net
***************************************************************************/
/***************************************************************************
* *
* 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. *
* *
***************************************************************************/
#include "lbreakout.h"
#include "config.h"
#include "../gui/gui.h"
#include "client_data.h"
#include "client_handlers.h"
#include "comm.h"
#include "game.h"
/*
====================================================================
Externals
====================================================================
*/
extern Config config;
extern List *client_users;
extern List *client_games;
extern List *client_channels;
extern List *client_levelsets;
extern char *client_levelset;
extern ClientUser *client_user;
extern char chatter[CHAT_LINE_COUNT][CHAT_LINE_WIDTH];
extern GuiWidget *dlg_connect;
extern GuiWidget *dlg_info;
extern GuiWidget *dlg_confirm;
extern GuiWidget *dlg_chatroom;
extern GuiWidget *dlg_channels;
extern GuiWidget *dlg_stats;
extern GuiWidget *dlg_pauseroom;
extern GuiWidget *dlg_help;
extern GuiWidget *label_info;
extern GuiWidget *label_stats;
extern GuiWidget *label_winner;
extern GuiWidget *label_channel;
extern GuiWidget *edit_server;
extern GuiWidget *edit_username;
extern GuiWidget *list_chatter;
extern GuiWidget *edit_chatter;
extern GuiWidget *list_levels;
extern GuiWidget *list_users;
extern GuiWidget *list_channels;
extern GuiWidget *edit_channel;
extern GuiWidget *edit_pausechatter;
extern GuiWidget *list_help;
extern int levelset_version, levelset_update;
extern List *levels;
extern void client_popup_info( char *format, ... );
extern void client_run_game( int challenger );
extern int client_topic_count;
extern char *client_helps[];
extern Text *client_help_text;
/*
====================================================================
Client
====================================================================
*/
#ifdef NETWORK_ENABLED
NetSocket client; /* client socket to the game server */
#endif
int client_is_connected; /* wether 'client' is a valid uplink */
char client_error[128]; /* error message */
int client_id; /* id assigned by server */
char client_name[16]; /* our local username */
int client_state = CLIENT_NONE;
int client_recv_limit;
/*
====================================================================
Challenge data
====================================================================
*/
char *mp_diff_names[] = { "Easy", "Medium", "Hard" };
char mp_levelset[16]; /* name of levelset we play */
int mp_peer_id;
char mp_peer_name[16]; /* remote player we want to play with */
int mp_levelset_version;
int mp_levelset_update; /* version of levelset */
int mp_level_count; /* number of levels in set */
int mp_diff, mp_rounds, mp_frags, mp_balls; /* game configuration */
extern void close_pause_chat( void );
/*
====================================================================
Disconnect from current server if any.
====================================================================
*/
void client_disconnect()
{
#ifdef NETWORK_ENABLED
char buf[128];
if ( !client_is_connected ) return;
/* disconnect */
socket_print_stats( &client );
sprintf( buf, _("disconnected from %s"),
net_addr_to_string(&client.remote_addr) );
client_add_chatter( buf, 1 );
buf[0] = MSG_DISCONNECT;
client_transmit( CODE_BLUE, 1, buf );
client_is_connected = 0;
client_data_clear();
gui_label_set_text( label_channel, "MAIN" );
#endif
}
/*
====================================================================
Try to connect to a game server. Retry twice every second
or quit then.
====================================================================
*/
void client_connect( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
NetAddr newaddr;
int attempt = 0;
int type;
char server[128];
if ( event->type != GUI_CLICKED ) return;
/* close the connect window */
gui_widget_hide( dlg_connect );
/* disconnect from current server */
client_disconnect();
/* extract ip and port and build a new socket out of it */
gui_edit_get_text( edit_server, server, 128, 0, -1 );
snprintf( config.server, 64, "%s", server );
if ( !net_build_addr( &newaddr, server, 0 ) ) {
client_printf_chatter( 1, _("ERROR: address %s does not resolve"), config.server );
return;
}
socket_init( &client, &newaddr );
/* get username */
gui_edit_get_text( edit_username,
config.username, 16, 0,-1 );
/* build connect message */
msg_begin_writing( msgbuf, &msglen, 64 );
msg_write_int8( MSG_CONNECT );
msg_write_int8( PROTOCOL );
msg_write_string( config.username );
msg_write_string( _("unused") ); /* passwd */
while ( attempt < 3 ) {
client_printf_chatter( 1, "%s: %s...",
config.server,
attempt==0?_("connecting"):_("retry") );
stk_display_update( STK_UPDATE_ALL );
net_transmit_connectionless( &newaddr, msglen, msgbuf );
SDL_Delay( 1000 );
while ( net_recv_packet() ) {
if ( msg_is_connectionless() )
msg_begin_connectionless_reading();
else
if ( !socket_process_header( &client ) )
continue;
type = msg_read_int8();
switch ( type ) {
case MSG_LOGIN_OKAY:
client_id = msg_read_int32();
strcpy( client_name, msg_read_string() );
client_printf_chatter( 1, _("%s: connected!"), config.server );
client_is_connected = 1;
return;
case MSG_ERROR:
client_printf_chatter( 1, _("ERROR: connection refused: %s"),
msg_read_string() );
return;
}
}
attempt++;
}
client_add_chatter( _("ERROR: server does not respond"), 1 );
#endif
}
/*
====================================================================
Open/close the connection window.
====================================================================
*/
void client_open_connect_window(
GuiWidget *widget, GuiEvent *event )
{
if ( event->type == GUI_CLICKED )
gui_widget_show( dlg_connect );
}
void client_close_connect_window(
GuiWidget *widget, GuiEvent *event )
{
if ( event->type == GUI_CLICKED )
gui_widget_hide( dlg_connect );
}
/*
====================================================================
Close chatroom and return to LBreakout's menu.
====================================================================
*/
void client_quit( GuiWidget *widget, GuiEvent *event )
{
if ( event->type == GUI_CLICKED )
gui_widget_hide( dlg_chatroom );
/* disconnect is handled in client_run to cover
* stk_quit_requests as well */
}
/*
====================================================================
Close the info window and clear state.
====================================================================
*/
void client_close_info( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
if ( event->type == GUI_CLICKED ) {
gui_widget_hide( dlg_info );
msg_begin_writing( msgbuf, &msglen, 128 );
switch ( client_state ) {
case CLIENT_AWAIT_ANSWER:
msg_write_int8( MSG_CANCEL_GAME );
break;
}
client_transmit( CODE_BLUE, msglen, msgbuf );
client_state = CLIENT_NONE;
}
#endif
}
/*
====================================================================
Send chatter this function is either called by the send button
or by the edit.
====================================================================
*/
void client_send_chatter(
GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
char buf[MAX_CHATTER_SIZE + 1];
if ( ( widget->type == GUI_EDIT &&
event->type == GUI_KEY_RELEASED &&
event->key.keysym == SDLK_RETURN ) ||
( widget->type == GUI_BUTTON &&
event->type == GUI_CLICKED ) ) {
/* get message */
gui_edit_get_text( edit_chatter,
buf, MAX_CHATTER_SIZE + 1, 0,-1 );
/* clear chat edit */
gui_edit_set_text( edit_chatter, "" );
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
/* a prepended '/' means this is a command */
if ( buf[0] == '/' ) {
msg_write_int8( MSG_COMMAND );
msg_write_string( buf+1 );
}
else {
msg_write_int8( MSG_CHATTER );
msg_write_string( buf );
}
client_transmit( CODE_BLUE, msglen, msgbuf );
}
#endif
}
/*
====================================================================
Whisper chatter if a user is selected.
====================================================================
*/
void client_whisper_chatter(
GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
char buf[MAX_CHATTER_SIZE + 1];
if ( event->type != GUI_CLICKED ) return;
/* get message */
gui_edit_get_text( edit_chatter,
buf, MAX_CHATTER_SIZE + 1, 0,-1 );
/* send to selected user */
if ( client_user ) {
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
msg_write_int8( MSG_WHISPER );
msg_write_int32( client_user->id );
msg_write_string( buf );
client_transmit( CODE_BLUE, msglen, msgbuf );
/* clear chat edit */
gui_edit_set_text( edit_chatter, "" );
}
else
client_add_chatter( _("You must select a user to whisper!"), 1 );
#endif
}
/*
====================================================================
Update selected peer and levelset.
====================================================================
*/
void client_handle_user_list(
GuiWidget *widget, GuiEvent *event )
{
if ( event->type == GUI_ITEM_SELECTED )
client_user = list_get( client_users, event->item.y );
else
if ( event->type == GUI_ITEM_UNSELECTED )
client_user = 0;
}
void client_handle_levelset_list(
GuiWidget *widget, GuiEvent *event )
{
if ( event->type == GUI_ITEM_SELECTED )
client_levelset = list_get( client_levelsets,
event->item.y );
else
if ( event->type == GUI_ITEM_UNSELECTED )
client_levelset = 0;
}
/*
====================================================================
Handle confirmation/cancelling of confirmation dialogue.
====================================================================
*/
void client_confirm( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_confirm );
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
switch ( client_state ) {
case CLIENT_ANSWER:
msg_write_int8( MSG_ACCEPT_CHALLENGE );
client_transmit( CODE_BLUE, msglen, msgbuf );
/* play */
gui_disable_event_filter();
if ( client_game_init_network( mp_peer_name, mp_diff ) )
client_game_run();
client_game_finalize();
gui_enable_event_filter();
gui_widget_draw( dlg_chatroom );
stk_display_fade( STK_FADE_IN, STK_FADE_DEFAULT_TIME );
break;
}
#endif
}
void client_cancel( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_confirm );
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
switch ( client_state ) {
case CLIENT_ANSWER:
msg_write_int8( MSG_REJECT_CHALLENGE );
break;
}
client_transmit( CODE_BLUE, msglen, msgbuf );
client_state = CLIENT_NONE;
#endif
}
/*
====================================================================
Challenge selected user.
====================================================================
*/
void client_challenge( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
if ( event->type != GUI_CLICKED ) return;
/* everything valid? */
if ( client_user == 0 ) {
client_popup_info( _("You must select a user for a challenge.") );
return;
}
if ( client_levelset == 0 ) {
client_popup_info( _("You must select a levelset for a challenge.") );
return;
}
if ( client_user->id == client_id ) {
client_popup_info( _("You can't challenge yourself.") );
return;
}
strcpy( mp_peer_name, client_user->name );
mp_peer_id = client_user->id;
strcpy( mp_levelset, client_levelset );
mp_diff = config.mp_diff;
mp_rounds = config.mp_rounds;
mp_balls = config.mp_balls;
mp_frags = config.mp_frags;
/* challenger, challenged, levelset, diff, rounds, frags, balls */
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
msg_write_int8( MSG_OPEN_GAME );
msg_write_int32( mp_peer_id );
msg_write_string( mp_levelset );
msg_write_int8( mp_diff );
msg_write_int8( mp_rounds );
msg_write_int8( mp_frags );
msg_write_int8( mp_balls );
client_transmit( CODE_BLUE, msglen, msgbuf );
client_popup_info( _("You have challenged %s. Let's see what (s)he says..."), mp_peer_name );
client_state = CLIENT_AWAIT_ANSWER;
#endif
}
/*
====================================================================
Update multiplayer network configuration.
====================================================================
*/
void client_update_difficulty( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CHANGED ) return;
gui_spinbutton_get_value( widget, &config.mp_diff );
config.mp_diff--;
}
void client_update_rounds( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CHANGED ) return;
gui_spinbutton_get_value( widget, &config.mp_rounds );
}
void client_update_frags( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CHANGED ) return;
gui_spinbutton_get_value( widget, &config.mp_frags );
}
void client_update_balls( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CHANGED ) return;
gui_spinbutton_get_value( widget, &config.mp_balls );
}
/*
====================================================================
Open channel selector
====================================================================
*/
void client_select_channel( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
/* select first channel (we always have MAIN) */
gui_list_update( list_channels, client_channels->count );
if ( client_channels->count > 0 ) {
gui_edit_set_text( edit_channel, list_first( client_channels ) );
gui_list_select( list_channels, 0,0, 1 );
}
gui_widget_show( dlg_channels );
client_state = CLIENT_SELECT_CHANNEL;
}
/*
====================================================================
Handle channel (un)selection.
====================================================================
*/
void client_handle_channel_list(
GuiWidget *widget, GuiEvent *event )
{
char *name;
/* if a channel is selected the name is copied into the edit.
unselecting does not change anything. the channel by the
caption in the edit is opened on enter_channel() */
if ( event->type == GUI_ITEM_SELECTED ) {
name = list_get( client_channels, event->item.y );
if ( name ) gui_edit_set_text( edit_channel, name );
}
}
/*
====================================================================
Close channel selector or enter new channel.
====================================================================
*/
void client_enter_channel( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
char buf[16];
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_channels );
client_state = CLIENT_NONE;
/* retreive name of channel we want to enter */
buf[0] = 0;
gui_edit_get_text( edit_channel, buf, 16, 0,-1 );
/* send it */
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
msg_write_int8( MSG_ENTER_CHANNEL );
msg_write_string( buf );
client_transmit( CODE_BLUE, msglen, msgbuf );
#endif
}
void client_cancel_channel( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_channels );
client_state = CLIENT_NONE;
}
/*
====================================================================
Close statistics
====================================================================
*/
void client_close_stats( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_stats );
client_state = CLIENT_NONE;
gui_label_set_text( label_stats, _("Awaiting stats...") );
gui_label_set_text( label_winner, "..." );
}
/*
====================================================================
Send chatter to gamepeer in pauseroom when ENTER was pressed.
====================================================================
*/
void client_send_pausechatter( GuiWidget *widget, GuiEvent *event )
{
#ifdef NETWORK_ENABLED
char buf[MAX_CHATTER_SIZE + 1];
if ( widget->type == GUI_EDIT &&
event->type == GUI_KEY_RELEASED &&
event->key.keysym == SDLK_RETURN ) {
/* get message */
sprintf( buf, "<%s> ", client_name );
gui_edit_get_text( edit_pausechatter,
buf+strlen(buf), MAX_CHATTER_SIZE + 1, 0,-1 );
/* clear chat edit */
gui_edit_set_text( edit_pausechatter, "" );
/* deliver message to remote ... */
msg_begin_writing( msgbuf, &msglen, MAX_MSG_SIZE );
msg_write_int8( MSG_CHATTER );
msg_write_string( buf );
client_transmit( CODE_BLUE, msglen, msgbuf );
client_add_pausechatter( buf, 0 );
}
#endif
}
/*
====================================================================
Close pauseroom.
====================================================================
*/
void client_close_pauseroom( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
close_pause_chat();
comm_send_short( MSG_UNPAUSE );
}
/*
====================================================================
Popup help dialogue.
====================================================================
*/
void client_popup_help( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
gui_widget_show( dlg_help );
client_state = CLIENT_HELP;
}
/*
====================================================================
Close help dialogue.
====================================================================
*/
void client_close_help( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_CLICKED ) return;
gui_widget_hide( dlg_help );
}
/*
====================================================================
Select topic and display help text.
====================================================================
*/
void client_handle_topic_list( GuiWidget *widget, GuiEvent *event )
{
if ( event->type != GUI_ITEM_SELECTED ) return;
if ( event->item.y >= client_topic_count ) return;
gui_list_goto( list_help, 0 );
if ( client_help_text ) delete_text( client_help_text );
client_help_text = create_text( client_helps[event->item.y], 41 );
gui_list_update( list_help, client_help_text->count );
}