home *** CD-ROM | disk | FTP | other *** search
Wrap
/********************************************************************** Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold 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, 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. ***********************************************************************/ #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <assert.h> #include <game.h> #include <gamehand.h> #include <player.h> #include <civserver.h> #include <log.h> #include <sernet.h> #include <map.h> #include <mapgen.h> #include <registry.h> #include <plrhand.h> extern char metaserver_info_line[256]; void cut_player_connection(char *playername); void quit_game(void); void show_help(void); void show_players(void); struct proto_settings { char *name; char *help; int *value; int afterstart; int min_value, max_value, default_value; }; struct proto_settings settings[] = { { "xsize", "Width of map in squares", &map.xsize, 0, MAP_MIN_WIDTH, MAP_MAX_HEIGHT, MAP_DEFAULT_WIDTH}, { "ysize", "Height of map in squares", &map.ysize, 0, MAP_MIN_HEIGHT, MAP_MAX_HEIGHT, MAP_DEFAULT_HEIGHT}, { "seed", "This single number defines the random sequence that generate the map\nSame seed will always produce same map.", &map.seed, 0, MAP_MIN_SEED,MAP_MAX_SEED, MAP_DEFAULT_SEED}, { "landmass", "This number defines the percentage of the map that becomes land.", &map.landpercent, 0, MAP_MIN_LANDMASS, MAP_MAX_LANDMASS, MAP_DEFAULT_LANDMASS}, { "specials", "This number donates a percentage chance that a square is special.", &map.riches, 0, MAP_MIN_RICHES, MAP_MAX_RICHES, MAP_DEFAULT_RICHES}, { "swamps", "How many swamps to create on the map.", &map.swampsize, 0, MAP_MIN_SWAMPS, MAP_MAX_SWAMPS, MAP_DEFAULT_SWAMPS}, { "settlers", "How many settlers each player starts with.", &game.settlers, 0, GAME_MIN_SETTLERS, GAME_MAX_SETTLERS, GAME_DEFAULT_SETTLERS}, { "explorer", "How many explorer units the player starts with.", &game.explorer, 0, GAME_MIN_EXPLORER, GAME_MAX_EXPLORER, GAME_DEFAULT_EXPLORER}, { "deserts", "How many deserts to create on the map.", &map.deserts, 0, MAP_MIN_DESERTS, MAP_MAX_DESERTS, MAP_DEFAULT_DESERTS}, { "rivers", "Denotes the total length of the rivers on the map.", &map.riverlength, 0, MAP_MIN_RIVERS, MAP_MAX_RIVERS, MAP_DEFAULT_RIVERS}, { "mountains", "How flat/high is the map, higher values give more mountains.", &map.mountains, 0, MAP_MIN_MOUNTAINS, MAP_MAX_MOUNTAINS, MAP_DEFAULT_MOUNTAINS}, { "forests", "How much forest to create, higher values give more forest.", &map.forestsize, 0, MAP_MIN_FORESTS, MAP_MAX_FORESTS, MAP_DEFAULT_FORESTS}, { "huts", "how many 'bonus huts' should be created.", &map.huts, 0, MAP_MIN_HUTS, MAP_MAX_HUTS, MAP_DEFAULT_HUTS}, { "generator", "made a more fair mapgenerator (2), but it only supports 7 players, and works on 80x50 maps only", &map.generator, 0, MAP_MIN_GENERATOR, MAP_MAX_GENERATOR, MAP_DEFAULT_GENERATOR}, { "gold", "how much gold does each players start with.", &game.gold, 0, GAME_MIN_GOLD, GAME_MAX_GOLD, GAME_DEFAULT_GOLD}, { "techlevel", "How many initial advances does each player have.", &game.tech, 0, GAME_MIN_TECHLEVEL, GAME_MAX_TECHLEVEL, GAME_DEFAULT_TECHLEVEL}, { "researchspeed", "How fast do players gain technology.", &game.techlevel, 0, GAME_MIN_RESEARCHLEVEL, GAME_MAX_RESEARCHLEVEL, GAME_DEFAULT_RESEARCHLEVEL}, { "diplcost", "How many % of the price of researching a tech, does a tech cost when you exchange it in a diplomatic treaty.", &game.diplcost, 0, GAME_MIN_DIPLCOST, GAME_MAX_DIPLCOST, GAME_DEFAULT_DIPLCOST}, { "diplchance", "The 1:n chance of a diplomat/spy defeating a resident diplomat/spy while subverting or sabotaging a city. Also the chance of a Spy returning from a sucessful mission", &game.diplchance, 1, GAME_MIN_DIPLCHANCE, GAME_MAX_DIPLCHANCE, GAME_DEFAULT_DIPLCHANCE}, { "freecost", "How many % of the price of researching a tech, does a tech cost when you get it for free.", &game.freecost, 0, GAME_MIN_FREECOST, GAME_MAX_FREECOST, GAME_DEFAULT_FREECOST}, { "conquercost", "How many % of the price of researching a tech, does a tech cost when you get it by military force.", &game.conquercost, 0, GAME_MIN_CONQUERCOST, GAME_MAX_CONQUERCOST, GAME_DEFAULT_CONQUERCOST}, { "unhappysize", "When do people get angry in a city.", &game.unhappysize, 0, GAME_MIN_UNHAPPYSIZE, GAME_MAX_UNHAPPYSIZE, GAME_DEFAULT_UNHAPPYSIZE}, { "cityfactor", "How many cities will it take to increase unhappy faces in cities.", &game.cityfactor, 0, GAME_MIN_CITYFACTOR, GAME_MAX_CITYFACTOR, GAME_DEFAULT_CITYFACTOR}, { "railfood", "How many % railroads modifies food production.", &game.rail_food, 0, GAME_MIN_RAILFOOD, GAME_MAX_RAILFOOD, GAME_DEFAULT_RAILFOOD}, { "railprod", "How many % railroads modifies shield production.", &game.rail_prod, 0, GAME_MIN_RAILPROD, GAME_MAX_RAILPROD, GAME_DEFAULT_RAILPROD}, { "railtrade", "How many % railroads modifies trade production.", &game.rail_trade, 0, GAME_MIN_RAILTRADE, GAME_MAX_RAILTRADE, GAME_DEFAULT_RAILTRADE}, { "foodbox", "Size * this parameter is what it takes for a city to grow by 1" ,&game.foodbox, 0, GAME_MIN_FOODBOX, GAME_MAX_FOODBOX, GAME_DEFAULT_FOODBOX}, { "techpenalty", "% penalty if you change tech default it's 100%", &game.techpenalty, 0, GAME_MIN_TECHPENALTY, GAME_MAX_TECHPENALTY, GAME_DEFAULT_TECHPENALTY}, { "razechance", "% chance that each building in town is destroyed when conquered", &game.razechance, 0, GAME_MIN_RAZECHANCE, GAME_MAX_RAZECHANCE, GAME_DEFAULT_RAZECHANCE}, { "civstyle", "1= civ 1 (units, techs, buildings), 2= civ 2 style", &game.civstyle, 0, GAME_MIN_CIVSTYLE, GAME_MAX_CIVSTYLE, GAME_DEFAULT_CIVSTYLE}, { "endyear", "In what year is the game over.", &game.end_year, 1, GAME_MIN_END_YEAR, GAME_MAX_END_YEAR, GAME_DEFAULT_END_YEAR}, { "minplayers", "How many players are needed to start the game.", &game.min_players, 1, GAME_MIN_MIN_PLAYERS, GAME_MAX_MIN_PLAYERS, GAME_DEFAULT_MIN_PLAYERS}, { "maxplayers", "How many players are maximally wanted in game.", &game.max_players, 1, GAME_MIN_MAX_PLAYERS, GAME_MAX_MAX_PLAYERS, GAME_DEFAULT_MAX_PLAYERS}, { "saveturns", "How many turns between when the game is saved.", &game.save_nturns, 1, 0, 200, 10}, { "timeout", "How many seconds can a turn max take (0 is no timeout).", &game.timeout, 1, 0, 999, GAME_DEFAULT_TIMEOUT}, { "aifill", "Maximum number of AI players to create when game starts", &game.aifill, 1, GAME_MIN_AIFILL, GAME_MAX_AIFILL, GAME_DEFAULT_AIFILL}, { NULL, NULL, NULL, 0, 0, 0} }; /************************************************************************** ... **************************************************************************/ void meta_command(char *arg) { strncpy(metaserver_info_line, arg, 256); metaserver_info_line[256-1]='\0'; send_server_info_to_metaserver(1); } /************************************************************************** ... **************************************************************************/ void save_command(char *arg) { struct section_file file; if (server_state==SELECT_RACES_STATE || (server_state == PRE_GAME_STATE && !map_is_empty())) { printf("Please wait until the game has started to save.\n"); return; } section_file_init(&file); game_save(&file); if(!section_file_save(&file, arg)) printf("Failed saving game as %s\n", arg); else printf("Game saved as %s\n", arg); } /************************************************************************** ... **************************************************************************/ void toggle_ai_player(char *arg) { struct player *pplayer=find_player_by_name(arg); if (!pplayer) { puts("No player by that name."); return; } pplayer->ai.control = !pplayer->ai.control; if (pplayer->ai.control) { notify_player(0, "Option: %s is AI-controlled.", pplayer->name); printf("%s is now under AI control.\n",pplayer->name); } else { notify_player(0, "Option: %s is human.", pplayer->name); printf("%s is now under human control.\n",pplayer->name); } send_player_info(pplayer,0); } /************************************************************************** ... **************************************************************************/ void create_ai_player(char *arg) { struct player *pplayer; if (server_state==PRE_GAME_STATE) { if(game.nplayers==game.max_players) puts ("Can't add more players, server is full."); else if ((pplayer=find_player_by_name(arg))) puts("A player already exists by that name."); else { accept_new_player(arg, NULL); pplayer = find_player_by_name(arg); if (!pplayer) printf ("Error creating new ai player: %s\n", arg); else { pplayer->ai.control = !pplayer->ai.control; pplayer->is_connected=0; notify_player(0, "Option: %s has been added as an AI-controlled.", pplayer->name); } } } else puts ("Can't add AI players once the game has begun."); } /************************************************************************** ... **************************************************************************/ void remove_player(char *arg) { struct player *pplayer=find_player_by_name(arg); if(!pplayer) { puts("No player by that name."); return; } server_remove_player(pplayer); } int lookup_cmd(char *find) { int i; for (i=0;settings[i].name!=NULL;i++) if (!strcmp(find, settings[i].name)) return i; return -1; } void help_command(char *str) { char command[512], *cptr_s, *cptr_d; int cmd,i; for(cptr_s=str; *cptr_s && !isalnum(*cptr_s); cptr_s++); for(cptr_d=command; *cptr_s && isalnum(*cptr_s); cptr_s++, cptr_d++) *cptr_d=*cptr_s; *cptr_d='\0'; if (*command) { cmd=lookup_cmd(command); if (cmd==-1) { puts("No help on that (yet)."); return; } printf("%s: is set to %d\nEffect: %s\nMinimum %d, Maximum %d, Default %d\n" , settings[cmd].name, *settings[cmd].value, settings[cmd].help, settings[cmd].min_value, settings[cmd].max_value, settings[cmd].default_value); } else { puts("------------------------------------------------------------------------------"); puts("Help are defined on the following variables:"); puts("------------------------------------------------------------------------------"); for (i=0;settings[i].name;i++) { printf("%-19s%c",settings[i].name, ((i+1)%4) ? ' ' : '\n'); } if ((i)%4!=0) puts(""); puts("------------------------------------------------------------------------------"); } } void report_server_options(struct player *pplayer) { int i; char buffer[4096]; char buf2[4096]; char title[128]; buffer[0]=0; sprintf(title, "%-20svalue (min , max)\n", "Variable"); for (i=0;settings[i].name;i++) { sprintf(buf2, "%-20s%c%-6d (%d,%d)\n", settings[i].name,(*settings[i].value==settings[i].default_value) ? '*' : ' ', *settings[i].value, settings[i].min_value, settings[i].max_value); strcat(buffer, buf2); } page_player(pplayer, title, buffer); } void set_ai_level(char *arg, int level) { struct player *pplayer=find_player_by_name(arg); char *nm[11] = { "NONE", "NONE", "NONE", "easy", "NONE", "normal", "NONE", "hard", "NONE", "NONE", "NONE" }; int h[11] = { 0, 0, 0, H_RATES+H_TARGETS+H_HUTS, 0, H_RATES+H_TARGETS+H_HUTS, 0, 0, 0, 0, 0 }; int i; if (pplayer) { if (pplayer->ai.control) { pplayer->ai.handicap = h[level]; printf("%s is now %s.\n", pplayer->name, nm[level]); } else { printf("%s is not controlled by the AI.\n", pplayer->name); } } else { for (i = 0; i < game.nplayers; i++) { pplayer = get_player(i); if (pplayer->ai.control) { pplayer->ai.handicap = h[level]; printf("%s is now %s.\n", pplayer->name, nm[level]); } } } } void crash_and_burn(void) { printf("Crashing and burning.\n"); assert(0); } void show_command(char *str) { int i; puts("------------------------------------------------------------------------------"); printf("%-20svalue (min , max)\n", "Variable"); puts("------------------------------------------------------------------------------"); for (i=0;settings[i].name;i++) { printf("%-20s%c%-6d (%d,%d)\n", settings[i].name,(*settings[i].value==settings[i].default_value) ? '*' : ' ', *settings[i].value, settings[i].min_value, settings[i].max_value); } puts("------------------------------------------------------------------------------"); puts("* means that it's the default for the variable"); puts("------------------------------------------------------------------------------"); } void set_command(char *str) { char command[512], arg[512], *cptr_s, *cptr_d; int val, cmd; for(cptr_s=str; *cptr_s && !isalnum(*cptr_s); cptr_s++); for(cptr_d=command; *cptr_s && isalnum(*cptr_s); cptr_s++, cptr_d++) *cptr_d=*cptr_s; *cptr_d='\0'; for(; *cptr_s && (*cptr_s != '-' && !isalnum(*cptr_s)); cptr_s++); for(cptr_d=arg; *cptr_s && (*cptr_s == '-' || isalnum(*cptr_s)); cptr_s++ , cptr_d++) *cptr_d=*cptr_s; *cptr_d='\0'; cmd=lookup_cmd(command); if (cmd==-1) { puts("Undefined argument. Usage: set <variable> <value>."); return; } if (!settings[cmd].afterstart && !map_is_empty()) { puts("This setting can't be modified after game has started"); return; } val=atoi(arg); if (val>=settings[cmd].min_value && val<=settings[cmd].max_value) { *(settings[cmd].value)=val; notify_player(0, "Option: %s", str); } else puts("Value out of range. Usage: set <variable> <value>."); } /************************************************************************** ... **************************************************************************/ void handle_stdin_input(char *str) { char command[512], arg[512], *cptr_s, *cptr_d; int i; for(cptr_s=str; *cptr_s && !isalnum(*cptr_s); cptr_s++); for(cptr_d=command; *cptr_s && isalnum(*cptr_s); cptr_s++, cptr_d++) *cptr_d=*cptr_s; *cptr_d='\0'; for(; *cptr_s && !isalnum(*cptr_s); cptr_s++); strncpy(arg, cptr_s, 511); arg[511]='\0'; i=strlen(arg)-1; while(i>0 && isspace(arg[i])) arg[i--]='\0'; if(!strcmp("remove", command)) remove_player(arg); else if(!strcmp("save", command)) save_command(arg); else if(!strcmp("meta", command)) meta_command(arg); else if(!strcmp("h", command)) show_help(); else if(!strcmp("l", command)) show_players(); else if (!strcmp("ai", command)) toggle_ai_player(arg); else if (!strcmp("create", command)) create_ai_player(arg); else if (!strcmp("crash", command)) crash_and_burn(); /* else if (!strcmp("easy", command)) set_ai_level(arg, 3); not fair to tease people like this -- Syela */ else if (!strcmp("normal", command)) set_ai_level(arg, 5); else if (!strcmp("hard", command)) set_ai_level(arg, 7); else if(!strcmp("q", command)) quit_game(); else if(!strcmp("c", command)) cut_player_connection(arg); else if (!strcmp("show",command)) show_command(arg); else if (!strcmp("help",command)) help_command(arg); else if (!strcmp("set", command)) set_command(arg); else if(!strcmp("score", command)) { if(server_state==RUN_GAME_STATE) show_ending(); else printf("The game must be running, before you can see the score.\n"); } else if(server_state==PRE_GAME_STATE) { int plrs=0; int i; if(!strcmp("s", command)) { for (i=0;i<game.nplayers;i++) { if (game.players[i].conn || game.players[i].ai.control) plrs++ ; } if (plrs<game.min_players) printf("Not enough players, game will not start.\n"); else start_game(); } else printf("Unknown Command, try 'h' for help.\n"); } else printf("Unknown Command, try 'h' for help.\n"); printf(">"); fflush(stdout); } /************************************************************************** ... **************************************************************************/ void cut_player_connection(char *playername) { struct player *pplayer; pplayer=find_player_by_name(playername); if(pplayer && pplayer->conn) { log(LOG_NORMAL, "cutting connection to %s", playername); close_connection(pplayer->conn); pplayer->conn=NULL; } else puts("uh, no such player connected"); } /************************************************************************** ... **************************************************************************/ void quit_game(void) { int i; struct packet_generic_message gen_packet; gen_packet.message[0]='\0'; for(i=0; i<game.nplayers; i++) send_packet_generic_message(game.players[i].conn, PACKET_SERVER_SHUTDOWN, &gen_packet); close_connections_and_socket(); exit(1); } /************************************************************************** ... **************************************************************************/ void show_help(void) { puts("Available commands: (P=player, M=message, F=file)"); puts("-------------------------------------"); puts("c P - cut connection to player"); puts("h - this help"); puts("l - list players"); puts("q - quit game and shutdown server"); puts("remove P - fully remove player from game"); puts("score - show current score"); puts("save F - save game as file F"); puts("show - list server options"); puts("help - help on server options"); puts("meta T - Set meta-server infoline to T"); puts("ai P - toggles AI on player"); puts("create P - creates an AI player"); /* puts("easy P - AI player will be easy"); puts("easy - All AI players will be easy"); */ puts("normal P - AI player will be normal"); puts("normal - All AI players will be normal"); puts("hard P - AI player will be hard"); puts("hard - All AI players will be hard"); if(server_state==PRE_GAME_STATE) { puts("set - set options"); puts("s - start game"); } else { } } /************************************************************************** ... **************************************************************************/ void show_players(void) { int i; char aichar; puts("List of players:"); puts("-------------------------------------"); for(i=0; i<game.nplayers; i++) { if (game.players[i].ai.control) aichar = '*'; else aichar = ' '; printf("%c%s ", aichar, game.players[i].name); if(game.players[i].conn) printf("is connected from %s\n", game.players[i].addr); else printf("is not connected\n"); } }