Index: common/capstr.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v retrieving revision 1.98 diff -u -r1.98 capstr.c --- common/capstr.c 2002/04/05 05:56:48 1.98 +++ common/capstr.c 2002/04/08 09:31:05 @@ -73,7 +73,7 @@ #define CAPABILITY "+1.11.6 conn_info pop_cost +turn +attributes"\ " new_bonus_tech fund_added +processing_packets angrycitizen +tile_trade"\ " init_techs short_worklists tech_cost_style +short_city_tile_trade"\ -" +trade_size +new_nation_selection +client_worklists" +" +trade_size +new_nation_selection +client_worklists u32timeout" /* "+1.11.6" is protocol for 1.11.6 beta release. @@ -122,6 +122,9 @@ bit mask "client_worklists" the client keeps the global worklists not the server + + "u32timeout" designates that game.timeout is packeted as a uint32 + instead of a uint16 */ void init_our_capability(void) Index: common/game.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.c,v retrieving revision 1.137 diff -u -r1.137 game.c --- common/game.c 2002/04/04 18:53:28 1.137 +++ common/game.c 2002/04/08 09:31:05 @@ -646,6 +646,11 @@ game.tech = GAME_DEFAULT_TECHLEVEL; game.skill_level = GAME_DEFAULT_SKILL_LEVEL; game.timeout = GAME_DEFAULT_TIMEOUT; + game.timeoutint = GAME_DEFAULT_TIMEOUTINT; + game.timeoutintinc = GAME_DEFAULT_TIMEOUTINTINC; + game.timeoutinc = GAME_DEFAULT_TIMEOUTINC; + game.timeoutincmult= GAME_DEFAULT_TIMEOUTINCMULT; + game.timeoutcounter= 1; game.tcptimeout = GAME_DEFAULT_TCPTIMEOUT; game.netwait = GAME_DEFAULT_NETWAIT; game.last_ping = 0; Index: common/game.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/game.h,v retrieving revision 1.103 diff -u -r1.103 game.h --- common/game.h 2002/03/21 05:17:20 1.103 +++ common/game.h 2002/04/08 09:31:06 @@ -60,6 +60,11 @@ int tech; int skill_level; int timeout; + int timeoutint; /* increase timeout every N turns... */ + int timeoutinc; /* ... by this amount ... */ + int timeoutincmult; /* ... and multiply timeoutinc by this amount ... */ + int timeoutintinc; /* ... and increase timeoutint by this amount */ + int timeoutcounter; /* timeoutcounter - timeoutint = turns to next inc. */ int tcptimeout; int netwait; time_t last_ping; @@ -361,6 +366,11 @@ #define GAME_DEFAULT_AUTO_AI_TOGGLE FALSE #define GAME_DEFAULT_TIMEOUT 0 +#define GAME_DEFAULT_TIMEOUTINT 0 +#define GAME_DEFAULT_TIMEOUTINTINC 0 +#define GAME_DEFAULT_TIMEOUTINC 0 +#define GAME_DEFAULT_TIMEOUTINCMULT 1 + #ifndef NDEBUG #define GAME_MIN_TIMEOUT -1 #else Index: common/packets.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/packets.c,v retrieving revision 1.203 diff -u -r1.203 packets.c --- common/packets.c 2002/04/05 05:56:48 1.203 +++ common/packets.c 2002/04/08 09:31:08 @@ -2028,9 +2028,12 @@ cptr=put_uint16(cptr, pinfo->gold); cptr=put_uint32(cptr, pinfo->tech); cptr=put_uint8(cptr, pinfo->researchcost); - cptr=put_uint32(cptr, pinfo->skill_level); - cptr=put_uint16(cptr, pinfo->timeout); + if (has_capability("u32timeout", pc->capability)) { + cptr=put_uint32(cptr, pinfo->timeout); + } else { + cptr=put_uint16(cptr, pinfo->timeout); + } cptr=put_uint32(cptr, pinfo->end_year); cptr=put_uint32(cptr, pinfo->year); cptr=put_uint8(cptr, pinfo->min_players); @@ -2087,7 +2090,11 @@ iget_uint32(&iter, &pinfo->tech); iget_uint8(&iter, &pinfo->researchcost); iget_uint32(&iter, &pinfo->skill_level); - iget_uint16(&iter, &pinfo->timeout); + if (has_capability("u32timeout", pc->capability)) { + iget_uint32(&iter, &pinfo->timeout); + } else { + iget_uint16(&iter, &pinfo->timeout); + } iget_uint32(&iter, &pinfo->end_year); iget_uint32(&iter, &pinfo->year); iget_uint8(&iter, &pinfo->min_players); Index: common/shared.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/shared.c,v retrieving revision 1.82 diff -u -r1.82 shared.c --- common/shared.c 2002/04/06 11:02:11 1.82 +++ common/shared.c 2002/04/08 09:31:09 @@ -166,6 +166,81 @@ } /*************************************************************** + Like strcspn but also handles quotes. +***************************************************************/ +static size_t my_strcspn(const char *s, const char *reject) +{ + bool in_single_quotes = FALSE, in_double_quotes = FALSE; + size_t i, len = strlen(s); + + for (i = 0; i < len; i++) { + if (s[i] == '"' && !in_single_quotes) { + in_double_quotes = !in_double_quotes; + } else if (s[i] == '\'' && !in_double_quotes) { + in_single_quotes = !in_single_quotes; + } + + if (in_single_quotes || in_double_quotes) { + continue; + } + + if (strchr(reject, s[i])) { + break; + } + } + + return i; +} + +/*************************************************************** + Splits the string into tokens. The individual tokens are + returned. The delimeterset can freely be choosen. + + i.e. "34 abc 54 87" with a delimeterset of " " will yield + tokens={"34", "abc", "54", "87"} + + Part of the input string can be quoted (single or double) to embedded + delimeter into tokens. For example, + command 'a name' hard "1,2,3,4,5" 99 + will yield 5 tokens using the delimeterset " ,". + + Tokens which aren't used aren't modified. If the string would yield + more tokens only the first num_tokens are extracted. +***************************************************************/ +int get_tokens(const char *str, char **tokens, size_t num_tokens, + size_t token_length, const char *delimeterset) +{ + int token = 0; + + assert(str != NULL); + + for(;;) { + size_t len; + + /* Skip leading delimeters */ + str += strspn(str, delimeterset); + + if (*str == '\0') { + break; + } + + len = my_strcspn(str, delimeterset); + + if (token >= num_tokens) { + break; + } + memcpy(tokens[token], str, MIN(token_length, len)); + tokens[token][MIN(token_length, len)] = '\0'; + + token++; + + str += len; + } + + return token; +} + +/*************************************************************** Returns a statically allocated string containing a nicely-formatted version of the given number according to the user's locale. (Only works for numbers >= zero.) The actually number used for the Index: common/shared.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/shared.h,v retrieving revision 1.92 diff -u -r1.92 shared.h --- common/shared.h 2002/03/07 05:24:53 1.92 +++ common/shared.h 2002/04/08 09:31:09 @@ -77,6 +77,8 @@ char * get_option(const char *option_name,char **argv,int *i,int argc); bool is_option(const char *option_name,char *option); +int get_tokens(const char *str, char **tokens, size_t num_tokens, + size_t token_length, const char *delimeterset); char *general_int_to_text(int nr, int decade_exponent); char *int_to_text(int nr); char *population_to_text(int thousand_citizen); Index: server/gamehand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gamehand.c,v retrieving revision 1.110 diff -u -r1.110 gamehand.c --- server/gamehand.c 2002/03/07 05:24:55 1.110 +++ server/gamehand.c 2002/04/08 09:31:10 @@ -196,7 +196,6 @@ lsend_packet_generic_integer(dest, PACKET_GAME_STATE, &pack); } - /************************************************************************** Send game_info packet; some server options and various stuff... dest==NULL means game.est_connections @@ -247,4 +246,56 @@ send_packet_game_info(pconn, &ginfo); } conn_list_iterate_end; +} + +/************************************************************************** + adjusts game.timeout based on various server options + + timeoutint: adjust game.timeout every timeoutint turns + timeoutinc: adjust game.timeout by adding timeoutinc to it. + timeoutintinc: every time we adjust game.timeout, we add timeoutintinc + to timeoutint. + timeoutincmult: every time we adjust game.timeout, we multiply timeoutinc + by timeoutincmult +**************************************************************************/ +int update_timeout(void) +{ + /* if there's no timer or we're doing autogame, do nothing */ + if (game.timeout < 1 || game.timeoutint == 0) { + return game.timeout; + } + + if (game.timeoutcounter >= game.timeoutint) { + game.timeout += game.timeoutinc; + game.timeoutinc *= game.timeoutincmult; + + game.timeoutcounter = 1; + game.timeoutint += game.timeoutintinc; + + if(game.timeout > GAME_MAX_TIMEOUT) { + notify_conn_ex(&game.est_connections, -1, -1, E_NOEVENT, + _("The turn timeout has exceeded its maximum value, " + "fixing at its maximum")); + freelog(LOG_DEBUG, "game.timeout exceeded maximum value"); + game.timeout = GAME_MAX_TIMEOUT; + game.timeoutint = 0; + game.timeoutinc = 0; + } else if (game.timeout < 0) { + notify_conn_ex(&game.est_connections, -1, -1, E_NOEVENT, + _("The turn timeout is smaller than zero, " + "fixing at zero.")); + freelog(LOG_DEBUG, "game.timeout less than zero"); + game.timeout = 0; + } + } else { + game.timeoutcounter++; + } + + freelog(LOG_DEBUG, "timeout=%d, inc=%d incmult=%d\n " + "int=%d, intinc=%d, turns till next=%d", + game.timeout, game.timeoutinc, game.timeoutincmult, + game.timeoutint, game.timeoutintinc, + game.timeoutint - game.timeoutcounter); + + return game.timeout; } Index: server/gamehand.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/gamehand.h,v retrieving revision 1.9 diff -u -r1.9 gamehand.h --- server/gamehand.h 2001/10/18 16:45:34 1.9 +++ server/gamehand.h 2002/04/08 09:31:10 @@ -22,4 +22,6 @@ void send_game_state(struct conn_list *dest, int state); void send_start_turn_to_clients(void); +int update_timeout(void); + #endif /* FC__GAMEHAND_H */ Index: server/savegame.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v retrieving revision 1.76 diff -u -r1.76 savegame.c --- server/savegame.c 2002/04/06 05:48:16 1.76 +++ server/savegame.c 2002/04/08 09:31:11 @@ -1680,7 +1680,19 @@ game.skill_level = secfile_lookup_int(file, "game.skill_level"); if (game.skill_level==0) game.skill_level = GAME_OLD_DEFAULT_SKILL_LEVEL; + game.timeout = secfile_lookup_int(file, "game.timeout"); + game.timeoutint = secfile_lookup_int_default(file, + GAME_DEFAULT_TIMEOUTINT, "game.timeoutint"); + game.timeoutintinc = secfile_lookup_int_default(file, + GAME_DEFAULT_TIMEOUTINTINC, "game.timeoutintinc"); + game.timeoutinc = secfile_lookup_int_default(file, + GAME_DEFAULT_TIMEOUTINC, "game.timeoutinc"); + game.timeoutincmult = secfile_lookup_int_default(file, + GAME_DEFAULT_TIMEOUTINCMULT, "game.timeoutincmult"); + game.timeoutcounter = secfile_lookup_int_default(file, 1, + "game.timeoutcounter"); + game.end_year = secfile_lookup_int(file, "game.end_year"); game.researchcost = secfile_lookup_int_default(file, 0, "game.researchcost"); if (game.researchcost == 0) @@ -2045,6 +2057,11 @@ secfile_insert_int(file, game.tech, "game.tech"); secfile_insert_int(file, game.skill_level, "game.skill_level"); secfile_insert_int(file, game.timeout, "game.timeout"); + secfile_insert_int(file, game.timeoutint, "game.timeoutint"); + secfile_insert_int(file, game.timeoutintinc, "game.timeoutintinc"); + secfile_insert_int(file, game.timeoutinc, "game.timeoutinc"); + secfile_insert_int(file, game.timeoutincmult, "game.timeoutincmult"); + secfile_insert_int(file, game.timeoutcounter, "game.timeoutcounter"); secfile_insert_int(file, game.end_year, "game.end_year"); secfile_insert_int(file, game.year, "game.year"); secfile_insert_int(file, game.turn, "game.turn"); Index: server/sernet.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/sernet.c,v retrieving revision 1.89 diff -u -r1.89 sernet.c --- server/sernet.c 2002/03/05 15:46:27 1.89 +++ server/sernet.c 2002/04/08 09:31:12 @@ -63,6 +63,7 @@ #endif #include "fcintl.h" +#include "gamehand.h" #include "log.h" #include "mem.h" #include "netintf.h" @@ -619,9 +620,9 @@ } con_prompt_off(); - if(game.timeout != 0 - && (time(NULL)>game.turn_start + game.timeout)) + if(game.timeout != 0 && (time(NULL) > game.turn_start + game.timeout)) { return 0; + } return 1; } Index: server/srv_main.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v retrieving revision 1.78 diff -u -r1.78 srv_main.c --- server/srv_main.c 2002/04/06 10:44:18 1.78 +++ server/srv_main.c 2002/04/08 09:31:13 @@ -1720,6 +1720,8 @@ end_turn(); freelog(LOG_DEBUG, "Gamenextyear"); game_advance_year(); + freelog(LOG_DEBUG, "Updatetimeout"); + update_timeout(); check_spaceship_arrivals(); freelog(LOG_DEBUG, "Sendplayerinfo"); send_player_info(NULL, NULL); Index: server/stdinhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v retrieving revision 1.219 diff -u -r1.219 stdinhand.c --- server/stdinhand.c 2002/04/04 03:51:06 1.219 +++ server/stdinhand.c 2002/04/08 09:31:16 @@ -660,14 +660,16 @@ N_("If all players have not hit \"Turn Done\" before this " "time is up, then the turn ends automatically. Zero " "means there is no timeout. In DEBUG servers, a timeout " - "of -1 sets the autogame test mode."), NULL, + "of -1 sets the autogame test mode. Use this with the command " + "\"timeoutincrease\" to have a dynamic timer."), NULL, GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT) #else GEN_INT( "timeout", game.timeout, SSET_META, SSET_TO_CLIENT, N_("Maximum seconds per turn"), N_("If all players have not hit \"Turn Done\" before this " "time is up, then the turn ends automatically. Zero " - "means there is no timeout."), NULL, + "means there is no timeout. Use this with the command " + "\"timeoutincrease\" to have a dynamic timer."), NULL, GAME_MIN_TIMEOUT, GAME_MAX_TIMEOUT, GAME_DEFAULT_TIMEOUT) #endif @@ -894,6 +896,7 @@ CMD_HARD, CMD_CMDLEVEL, CMD_FIRSTLEVEL, + CMD_TIMEOUT, /* potentially harmful: */ CMD_END_GAME, @@ -1105,10 +1108,14 @@ "firstlevel", N_("Grab the 'first come' command access level."), N_("If 'cmdlevel first come' has been used to set a special 'first come'\n" - "command access level, this is the command to grab it with." - ) + "command access level, this is the command to grab it with.") }, - + {"timeoutincrease", ALLOW_CTRL, "timeoutincrease " + "", N_("See \"help timeoutincrease\"."), + N_("Every turns, add to timeout timer, then add " + "to and multiply by . Use this command in " + "concert with the option \"timeout\". Defaults are 0 0 0 1") + }, {"endgame", ALLOW_CTRL, "endgame", N_("End the game."), @@ -2197,6 +2204,59 @@ static const char *optname_accessor(int i) { return settings[i].name; } + +/************************************************************************** + Set timeout options. +**************************************************************************/ +static void timeout_command(struct connection *caller, char *str) +{ + char buf[MAX_LEN_CONSOLE_LINE]; + int i = 0, val[4]; + int *timeouts[4]; + char *arg[4]; + char storage[4][100]; + int tokens_extracted; + + timeouts[0] = &game.timeoutint; + timeouts[1] = &game.timeoutintinc; + timeouts[2] = &game.timeoutinc; + timeouts[3] = &game.timeoutincmult; + + for (i = 0; i < 4; i++) { + arg[i] = &storage[i][0]; + } + + sz_strlcpy(buf, str); + tokens_extracted = + get_tokens(buf, arg, ARRAY_SIZE(arg), sizeof(storage[0]), " \t\n,"); + + if (tokens_extracted != 4) { + cmd_reply(CMD_TIMEOUT, caller, C_SYNTAX, + _("Usage: timeoutincrease " + " .")); + } + + for (i = 0; i < tokens_extracted; i++) { + if (sscanf(arg[i], "%d", &val[i]) != 1) { + cmd_reply(CMD_TIMEOUT, caller, C_FAIL, _("Invalid argument %d."), + i + 1); + return; + } + } + + for (i = 0; i < 4; i++) { + *timeouts[i] = val[i]; + } + + cmd_reply(CMD_TIMEOUT, caller, C_OK, _("Dynamic timeout set to " + "%d %d %d %d"), + game.timeoutint, game.timeoutintinc, + game.timeoutinc, game.timeoutincmult); + + /* if we set anything here, reset the counter */ + game.timeoutcounter = 1; +} + /************************************************************************** Find option index by name. Return index (>=0) on success, -1 if no suitable options were found, -2 if several matches were found. @@ -2784,7 +2844,7 @@ for (i = 0; i < strlen(str); i++) { if (str[i] == '"' && !in_single_quotes) { in_double_quotes = !in_double_quotes; - } else if (str[i] == '\'' && in_double_quotes) { + } else if (str[i] == '\'' && !in_double_quotes) { in_single_quotes = !in_single_quotes; } else if (str[i] == '#' && !(in_single_quotes || in_double_quotes) && (i == 0 || str[i - 1] != '\\')) { @@ -2803,7 +2863,8 @@ **************************************************************************/ void handle_stdin_input(struct connection *caller, char *str) { - char command[MAX_LEN_CONSOLE_LINE], arg[MAX_LEN_CONSOLE_LINE], *cptr_s, *cptr_d; + char command[MAX_LEN_CONSOLE_LINE], arg[MAX_LEN_CONSOLE_LINE], + allargs[MAX_LEN_CONSOLE_LINE], *cptr_s, *cptr_d; int i; enum command_id cmd; @@ -2872,6 +2933,10 @@ cut_comment(arg); + /* keep this before we cut everything after a space */ + sz_strlcpy(allargs, cptr_s); + cut_comment(allargs); + i=strlen(arg)-1; while(i>0 && isspace(arg[i])) arg[i--]='\0'; @@ -2970,6 +3035,9 @@ break; case CMD_FIRSTLEVEL: firstlevel_command(caller); + break; + case CMD_TIMEOUT: + timeout_command(caller, allargs); break; case CMD_START_GAME: if (server_state==PRE_GAME_STATE) {