diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/TODO workdir/TODO --- freeciv/TODO Sun Jun 4 23:17:35 2000 +++ workdir/TODO Sun Jun 4 23:18:06 2000 @@ -11,9 +11,17 @@ ===== - Sound support. -- Fog Of War. - Server-side player scripting. -- Alliances between players. +- Alliances between players: + * AI should learn to make peace + * AI should learn to evaluate treaties + * AI should learn to suggest treaties + * Senate may dissolve on incidents (-> Anarchy) + * Show other player's pacts in diplomacy window + * Inform players who have embassies about diplomatic state changes + * Force to help allies if they are attacked + * Consistencialize namings: "Pact", "Diplomatic State", "Treaty" + * Trade routes are two-way in Alliances - Better graphics for city styles. - Better internationalization (fix some problems, modify those English sentences which can not be translated into most other diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-gtk/diplodlg.c workdir/client/gui-gtk/diplodlg.c --- freeciv/client/gui-gtk/diplodlg.c Sun Jun 4 23:17:36 2000 +++ workdir/client/gui-gtk/diplodlg.c Sun Jun 4 23:18:06 2000 @@ -422,7 +422,7 @@ gtk_signal_connect(GTK_OBJECT(item),"activate", GTK_SIGNAL_FUNC(diplomacy_dialog_peace_callback),(gpointer)pdialog); - item=gtk_menu_item_new_with_label(_("Allience")); + item=gtk_menu_item_new_with_label(_("Alliance")); gtk_menu_append(GTK_MENU(pdialog->dip_pact_menu),item); gtk_signal_connect(GTK_OBJECT(item),"activate", GTK_SIGNAL_FUNC(diplomacy_dialog_alliance_callback),(gpointer)pdialog); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-gtk/plrdlg.c workdir/client/gui-gtk/plrdlg.c --- freeciv/client/gui-gtk/plrdlg.c Sun Jun 4 23:17:36 2000 +++ workdir/client/gui-gtk/plrdlg.c Sun Jun 4 23:18:06 2000 @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -265,11 +266,13 @@ else gtk_widget_set_sensitive(players_sship_command, FALSE); - if (!players_at_war(game.player_idx, player_index) - && game.player_idx != player_index) - gtk_widget_set_sensitive(players_war_command, TRUE); - else + switch(player_get_diplstate(game.player_idx, player_index)->type) { + case DS_WAR: case DS_NO_CONTACT: gtk_widget_set_sensitive(players_war_command, FALSE); + break; + default: + gtk_widget_set_sensitive(players_war_command, game.player_idx != player_index); + } if(pplayer->is_alive && player_has_embassy(game.player_ptr, pplayer)) { if(pplayer->is_connected) diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/options.c workdir/client/options.c --- freeciv/client/options.c Sun Jun 4 23:17:35 2000 +++ workdir/client/options.c Sun Jun 4 23:18:06 2000 @@ -95,21 +95,22 @@ N_("Collapse to Anarchy "), N_("Diplomat Actions - Enemy "), N_("Tech from Great Library "), - N_("Player Destroyed "), /* E_DESTROYED */ - N_("Improvement Bought "), /* E_IMP_BUY */ - N_("Improvement Sold "), /* E_IMP_SOLD */ - N_("Unit Bought "), /* E_UNIT_BUY */ - N_("Wonder Stopped "), /* E_WONDER_STOPPED */ - N_("City Needs Aq Being Built"), /* E_CITY_AQ_BUILDING */ - N_("Diplomat Actions - Own "), /* E_MY_DIPLOMAT */ - N_("Unit Attack Failed "), /* E_UNIT_LOST_ATT */ - N_("Unit Attack Succeeded "), /* E_UNIT_WIN_ATT */ - N_("Suggest Growth Throttling"), /* E_CITY_GRAN_THROTTLE */ - N_("Spaceship Events "), /* E_SPACESHIP */ - N_("Barbarian Uprising "), /* E_UPRISING */ - N_("Worklist Events "), /* E_WORKLIST */ - N_("Pact Cancelled "), /* E_CANCEL_PACT */ - N_("Diplomatic Incident "), /* E_DIPL_INCIDENT */ + N_("Player Destroyed "), /* E_DESTROYED */ + N_("Improvement Bought "), /* E_IMP_BUY */ + N_("Improvement Sold "), /* E_IMP_SOLD */ + N_("Unit Bought "), /* E_UNIT_BUY */ + N_("Wonder Stopped "), /* E_WONDER_STOPPED */ + N_("City Needs Aq Being Built"), /* E_CITY_AQ_BUILDING */ + N_("Diplomat Actions - Own "), /* E_MY_DIPLOMAT */ + N_("Unit Attack Failed "), /* E_UNIT_LOST_ATT */ + N_("Unit Attack Succeeded "), /* E_UNIT_WIN_ATT */ + N_("Suggest Growth Throttling"), /* E_CITY_GRAN_THROTTLE */ + N_("Spaceship Events "), /* E_SPACESHIP */ + N_("Barbarian Uprising "), /* E_UPRISING */ + N_("Worklist Events "), /* E_WORKLIST */ + N_("Pact Cancelled "), /* E_CANCEL_PACT */ + N_("Diplomatic Incident "), /* E_DIPL_INCIDENT */ + N_("First Contact ") /* E_FIRST_CONTACT */ }; /************************************************************************** diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/events.h workdir/common/events.h --- freeciv/common/events.h Sun Jun 4 23:17:57 2000 +++ workdir/common/events.h Sun Jun 4 23:18:06 2000 @@ -53,6 +53,7 @@ E_WORKLIST, E_CANCEL_PACT, E_DIPL_INCIDENT, + E_FIRST_CONTACT, /* Note: If you add a new event, make sure you make a similar change to message_text in client/options.c */ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/game.c workdir/common/game.c --- freeciv/common/game.c Sun Jun 4 23:17:57 2000 +++ workdir/common/game.c Sun Jun 4 23:18:06 2000 @@ -936,7 +936,7 @@ for (j=plrno; jdiplstates[j] = pplayer->diplstates[j+1]; } - pplayer->diplstates[game.nplayers].type = DS_NEUTRAL; + pplayer->diplstates[game.nplayers].type = DS_NO_CONTACT; pplayer->diplstates[game.nplayers].has_reason_to_cancel = 0; } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/map.h workdir/common/map.h --- freeciv/common/map.h Sun Jun 4 23:17:57 2000 +++ workdir/common/map.h Sun Jun 4 23:49:05 2000 @@ -305,6 +305,27 @@ } \ } +/* Iterate through all tiles in a square with given center and radius. + Positions returned will have adjusted x, and positions with illegal y will be + automatically discarded. + */ +#define square_iterate(SI_center_x, SI_center_y, radius, SI_x_itr, SI_y_itr) \ +{ \ + int SI_x_itr1; \ + for (SI_y_itr = SI_center_y - radius; \ + SI_y_itr <= SI_center_y + radius; SI_y_itr++) { \ + if (SI_y_itr < 0 || SI_y_itr >= map.ysize) \ + continue; \ + for (SI_x_itr1 = SI_center_x - radius; \ + SI_x_itr1 <= SI_center_x + radius; SI_x_itr1++) { \ + SI_x_itr = map_adjust_x(SI_x_itr1); + +#define square_iterate_end \ + } \ + } \ +} + + #define MAP_DEFAULT_HUTS 50 #define MAP_MIN_HUTS 0 #define MAP_MAX_HUTS 500 diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/player.c workdir/common/player.c --- freeciv/common/player.c Sun Jun 4 23:17:57 2000 +++ workdir/common/player.c Mon Jun 5 14:26:25 2000 @@ -77,7 +77,7 @@ plr->embassy=0; plr->reputation=GAME_DEFAULT_REPUTATION; for(i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { - plr->diplstates[i].type = DS_NEUTRAL; + plr->diplstates[i].type = DS_NO_CONTACT; plr->diplstates[i].has_reason_to_cancel = 0; } plr->city_style=0; /* should be first basic style */ @@ -443,11 +443,12 @@ { static char *ds_names[DS_LAST] = { - N_("Neutral"), + N_("Neutral"), N_("War"), N_("Cease-fire"), N_("Peace"), - N_("Alliance") + N_("Alliance"), + N_("No Contact") }; if (type < DS_LAST) @@ -487,7 +488,7 @@ if (pplayer == pplayer2) return 0; if (is_barbarian(pplayer) || is_barbarian(pplayer2)) return TRUE; - return ((ds == DS_WAR) || (ds == DS_NEUTRAL)); + return ds == DS_WAR || ds == DS_NO_CONTACT; } /*************************************************************** @@ -531,7 +532,7 @@ return FALSE; if (is_barbarian(pplayer) || is_barbarian(pplayer2)) return FALSE; - return (ds == DS_PEACE || ds == DS_CEASEFIRE); + return (ds == DS_PEACE || ds == DS_CEASEFIRE || ds == DS_NEUTRAL); } /*************************************************************** diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/player.h workdir/common/player.h --- freeciv/common/player.h Sun Jun 4 23:17:57 2000 +++ workdir/common/player.h Mon Jun 5 02:05:19 2000 @@ -106,11 +106,9 @@ DS_CEASEFIRE, DS_PEACE, DS_ALLIANCE, + DS_NO_CONTACT, DS_LAST /* leave this last */ }; - -#define is_pact_diplstate(x) \ - ((x == DS_CEASEFIRE) || (x == DS_PEACE) || (x == DS_ALLIANCE)) struct player_diplstate { enum diplstate_type type; /* this player's disposition towards other */ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/barbarian.c workdir/server/barbarian.c --- freeciv/server/barbarian.c Sun Jun 4 23:18:04 2000 +++ workdir/server/barbarian.c Mon Jun 5 15:30:54 2000 @@ -151,11 +151,6 @@ barbarians->government = game.government_when_anarchy; barbarians->capital = 0; barbarians->economic.gold = 100; - for(i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) { - barbarians->diplstates[i].type = DS_NEUTRAL; - barbarians->diplstates[i].has_reason_to_cancel = 0; - } - barbarians->embassy = 0; barbarians->turn_done = 1; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/cityhand.c workdir/server/cityhand.c --- freeciv/server/cityhand.c Sun Jun 4 23:18:04 2000 +++ workdir/server/cityhand.c Mon Jun 5 00:47:11 2000 @@ -235,6 +235,7 @@ send_adjacent_cities(pcity); send_city_info(0, pcity); + maybe_make_first_contact(x, y, pcity->owner); /* if anyone changing to ocean here, stop them */ pcitytile = get_tile_type(map_get_terrain(x, y)); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/civserver.c workdir/server/civserver.c --- freeciv/server/civserver.c Sun Jun 4 23:18:04 2000 +++ workdir/server/civserver.c Mon Jun 5 01:40:01 2000 @@ -732,6 +732,19 @@ /************************************************************************** ... **************************************************************************/ +static void marco_polo_make_contact(void) +{ + int cityid = game.global_wonders[B_MARCO]; + int o; + struct city *pcity; + if (cityid && (pcity = find_city_by_id(cityid))) + for (o = 0; o < game.nplayers; o++) + make_contact(pcity->owner, o, pcity->x, pcity->y); +} + +/************************************************************************** +... +**************************************************************************/ static void update_pollution(void) { int x,y,count=0; @@ -874,6 +887,7 @@ update_pollution(); update_diplomatics(); do_apollo_program(); + marco_polo_make_contact(); make_history_report(); freelog(LOG_DEBUG, "Turn ended."); return 1; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/gamehand.c workdir/server/gamehand.c --- freeciv/server/gamehand.c Sun Jun 4 23:18:04 2000 +++ workdir/server/gamehand.c Mon Jun 5 15:38:38 2000 @@ -501,6 +501,11 @@ player map we do this afterwards */ for(i=0; iai.control) + neutralize_ai_player(pplayer); } initialize_globals(); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/plrhand.c workdir/server/plrhand.c --- freeciv/server/plrhand.c Sun Jun 4 23:18:04 2000 +++ workdir/server/plrhand.c Mon Jun 5 16:21:16 2000 @@ -1801,7 +1801,7 @@ enum diplstate_type old_type = pplayer->diplstates[other_player].type; enum diplstate_type new_type; struct player *pplayer2 = &game.players[other_player]; - int reppenalty; + int reppenalty = 0; int has_senate = government_has_flag(get_gov_pplayer(pplayer), G_HAS_SENATE); @@ -1812,12 +1812,16 @@ /* check what the new status will be, and what will happen to our reputation */ switch(old_type) { - case DS_CEASEFIRE: + case DS_NEUTRAL: new_type = DS_WAR; + reppenalty = 0; + break; + case DS_CEASEFIRE: + new_type = DS_NEUTRAL; reppenalty = GAME_MAX_REPUTATION/6; break; case DS_PEACE: - new_type = DS_WAR; + new_type = DS_NEUTRAL; reppenalty = GAME_MAX_REPUTATION/5; break; case DS_ALLIANCE: @@ -1900,17 +1904,18 @@ } notify_player(pplayer, - _("Game: There's now %s between the %s and the %s."), - diplstate_text(new_type), + _("Game: The diplomatic state between %s and the %s is now %s."), get_nation_name_plural(pplayer->nation), - get_nation_name_plural(pplayer2->nation)); + get_nation_name_plural(pplayer2->nation), + diplstate_text(new_type)); + notify_player_ex(pplayer2, 0, 0, E_NOEVENT, + _("Game: %s cancelled the diplomatic agreement!"), + pplayer->name); notify_player_ex(pplayer2, 0, 0, E_CANCEL_PACT, - _("Game: %s cancelled the pact! There's now %s between " - "the %s and the %s."), - pplayer->name, - diplstate_text(new_type), + _("Game: The diplomatic state between the %s and the %s is now %s."), get_nation_name_plural(pplayer2->nation), - get_nation_name_plural(pplayer->nation)); + get_nation_name_plural(pplayer->nation), + diplstate_text(new_type)); } /************************************************************************** @@ -2172,7 +2177,7 @@ "player%d.reputation", plrno); for(i=0; idiplstates[i].type = - secfile_lookup_int_default(file, DS_NEUTRAL, + secfile_lookup_int_default(file, DS_NO_CONTACT, "player%d.diplstate%d.type", plrno, i); plr->diplstates[i].turns_left = secfile_lookup_int_default(file, 0, @@ -2983,5 +2988,81 @@ ptile->sent = WIPEBIT(ptile->sent, idx); ptile->assigned = WIPEBIT(ptile->assigned, idx); } + } +} + +/************************************************************************** +... +**************************************************************************/ +void make_contact(int player1, int player2, int x, int y) +{ + struct player *pplayer1 = get_player(player1); + struct player *pplayer2 = get_player(player2); + + if (pplayer1 == pplayer2 + || !pplayer1->is_alive || !pplayer2->is_alive + || is_barbarian(pplayer1) || is_barbarian(pplayer2) + || pplayer_get_diplstate(pplayer1, pplayer2)->type != DS_NO_CONTACT) + return; + + /* FIXME: Always declairing war for the AI is a kludge untill AI + diplomacy is implemented. */ + pplayer1->diplstates[player2].type + = pplayer2->diplstates[player1].type + = pplayer1->ai.control || pplayer2->ai.control ? DS_WAR : DS_NEUTRAL; + notify_player_ex(pplayer1, x, y, + E_FIRST_CONTACT, + _("Game: You have made contact with the %s, ruled by %s."), + get_nation_name_plural(pplayer2->nation), pplayer2->name); + notify_player_ex(pplayer2, x, y, + E_FIRST_CONTACT, + _("Game: You have made contact with the %s, ruled by %s."), + get_nation_name_plural(pplayer1->nation), pplayer1->name); + send_player_info(pplayer1, pplayer1); + send_player_info(pplayer1, pplayer2); + send_player_info(pplayer2, pplayer1); + send_player_info(pplayer2, pplayer2); +} + +/************************************************************************** +... +**************************************************************************/ +void maybe_make_first_contact(int x, int y, int playerid) +{ + int x_itr, y_itr; + + square_iterate(x, y, 1, x_itr, y_itr) { + struct tile *ptile = map_get_tile(x_itr, y_itr); + struct city *pcity = ptile->city; + if (pcity) + make_contact(playerid, pcity->owner, x, y); + unit_list_iterate(ptile->units, punit) { + make_contact(playerid, punit->owner, x, y); + } unit_list_iterate_end; + } square_iterate_end; +} + +/*************************************************************************** +FIXME: This is a kluge to keep the AI working for the moment. +When the AI is taught to handle diplomacy, remove this and the call to it. +***************************************************************************/ +void neutralize_ai_player(struct player *pplayer) +{ + int other_player; + /* To make sure the rulesets are loaded we must do this. + If the game is a new game all players (inclusive ai's) would be + DS_NO_CONTACT, which is just as good as war. + */ + if (game.is_new_game) + return; + + for (other_player = 0; other_player < game.nplayers; other_player++) { + struct player *pother = get_player(other_player); + if (!pother->is_alive || pplayer == pother + || pplayer_get_diplstate(pplayer, pother)->type == DS_NO_CONTACT) + continue; + while (pplayers_non_attack(pplayer, pother) || pplayers_allied(pplayer, pother)) { + handle_player_cancel_pact(pplayer, other_player); + } } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/plrhand.h workdir/server/plrhand.h --- freeciv/server/plrhand.h Sun Jun 4 23:18:04 2000 +++ workdir/server/plrhand.h Mon Jun 5 00:59:21 2000 @@ -29,6 +29,9 @@ struct packet_player_request *preq); void check_player_government_rates(struct player *pplayer); void handle_player_cancel_pact(struct player *pplayer, int other_player); +void make_contact(int player1, int player2, int x, int y); +void maybe_make_first_contact(int x, int y, int playerid); +void neutralize_ai_player(struct player *pplayer); void send_player_info(struct player *src, struct player *dest); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/stdinhand.c workdir/server/stdinhand.c --- freeciv/server/stdinhand.c Sun Jun 4 23:18:04 2000 +++ workdir/server/stdinhand.c Mon Jun 5 01:56:19 2000 @@ -1350,32 +1350,6 @@ save_game(arg); } -/*************************************************************************** -FIXME: This is a kluge to keep the AI working for the moment. -When the AI is taught to handle diplomacy, remove this and the call to it. -***************************************************************************/ -static void neutralize_ai_player(struct player *pplayer) -{ - int other_player; - /* To make sure the rulesets are loaded we must do this. - If the game is a new game all players (inclusive ai's) would be - DS_NEUTRAL, which is just as good as war. - */ - if (game.is_new_game) - return; - - for (other_player = 0; other_player < game.nplayers; other_player++) { - struct player *pother = get_player(other_player); - enum diplstate_type ds = pplayer->diplstates[other_player].type; - if (!pother->is_alive || is_barbarian(pplayer) || pplayer == pother) - continue; - while (is_pact_diplstate(ds)) { - handle_player_cancel_pact(pplayer, other_player); - ds = pplayer->diplstates[other_player].type; - } - } -} - /************************************************************************** ... **************************************************************************/ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unitfunc.c workdir/server/unitfunc.c --- freeciv/server/unitfunc.c Sun Jun 4 23:18:04 2000 +++ workdir/server/unitfunc.c Mon Jun 5 15:50:00 2000 @@ -1292,11 +1292,14 @@ abort(); } switch (ds) { - case DS_NEUTRAL: case DS_WAR: + case DS_NO_CONTACT: freelog(LOG_VERBOSE,"Trying to cause an incident between players at war"); punishment = 0; break; + case DS_NEUTRAL: + punishment = GAME_MAX_REPUTATION/20; + break; case DS_CEASEFIRE: case DS_PEACE: punishment = GAME_MAX_REPUTATION/10; @@ -1304,8 +1307,8 @@ case DS_ALLIANCE: punishment = GAME_MAX_REPUTATION/5; break; - case DS_LAST: - freelog(LOG_FATAL, "DS_LAST is not a diplstate in maybe_cause_incident."); + default: + freelog(LOG_FATAL, "Illegal diplstate in maybe_cause_incident."); abort(); } offender->reputation = MAX(offender->reputation - punishment, 0); @@ -1872,6 +1875,7 @@ unfog_area(pplayer,x,y,get_unit_type(punit->type)->vision_range); send_unit_info(0, punit); + maybe_make_first_contact(x, y, punit->owner); } /************************************************************************** @@ -2706,12 +2710,14 @@ info.connecting=punit->connecting; info.carried = carried; - for(o=0; oconn, &info); } + } + } } /************************************************************************** @@ -3113,6 +3119,7 @@ teleport_unit_sight_points(src_x, src_y, dest_x, dest_y, punit); wakeup_neighbor_sentries(pplayer, dest_x, dest_y); + maybe_make_first_contact(dest_x, dest_y, punit->owner); if (tocity) handle_unit_enter_city(punit, tocity); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unithand.c workdir/server/unithand.c --- freeciv/server/unithand.c Sun Jun 4 23:18:04 2000 +++ workdir/server/unithand.c Sun Jun 4 23:18:07 2000 @@ -506,7 +506,7 @@ if (players_allied(punit->owner, pdefender->owner) && !(unit_flag(punit->type, F_NUCLEAR) && punit == pdefender)) { freelog(LOG_FATAL, - "Trying to attack a unit with which you have allience at %i, %i", + "Trying to attack a unit with which you have alliance at %i, %i", def_x, def_y); abort(); }