diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/ai/aiunit.c workdir/ai/aiunit.c --- freeciv/ai/aiunit.c Wed May 17 17:41:34 2000 +++ workdir/ai/aiunit.c Wed May 17 17:49:02 2000 @@ -178,10 +178,11 @@ x = punit->x; y = punit->y; for (i = -1; i <= 1; i++) { for (j = -1; j <= 1; j++) { + struct tile *ptile = map_get_tile(x + i, y + j); ok = (unit_flag(punit->type, F_TRIREME) ? 0 : 1); if (map_get_continent(x + i, y + j) == con && - !is_enemy_unit_tile(x + i, y + j, punit->owner) && - !map_get_city(x + i, y + j)) { + !is_non_allied_unit_tile(ptile, punit->owner) && + (!ptile->city || is_allied_city_tile(ptile, punit->owner))) { cur = 0; for (a = i - 1; a <= i + 1; a++) { for (b = j - 1; b <= j + 1; b++) { @@ -219,9 +220,11 @@ best = 0; for (x = 0; x < map.xsize; x++) { for (y = 0; y < map.ysize; y++) { - if (map_get_continent(x, y) == con && map_get_known(x, y, pplayer) && - !is_enemy_unit_tile(x, y, punit->owner) && !map_get_city(x, y) && - tile_is_accessible(punit, x, y)) { + struct tile *ptile = map_get_tile(x,y); + if (map_get_continent(x, y) == con && map_get_known(x, y, pplayer) + && !is_non_allied_unit_tile(ptile, punit->owner) + && (!ptile->city || is_allied_city_tile(ptile, punit->owner)) + && tile_is_accessible(punit, x, y)) { cur = 0; for (a = -1; a <= 1; a++) for (b = -1; b <= 1; b++) @@ -1684,7 +1687,7 @@ return 0; } - if( is_friendly_city_tile( punit->x, punit->y, punit->owner) ) + if (is_allied_city_tile(map_get_tile(punit->x, punit->y), punit->owner)) return 0; /* check if there is enemy nearby */ @@ -1693,8 +1696,8 @@ if( y < 0 || y > map.ysize ) continue; x1 = map_adjust_x(x); - if( is_enemy_city_tile(x1,y,punit->owner) || - is_enemy_unit_tile(x1,y,punit->owner) ) + if (is_enemy_city_tile(map_get_tile(x1, y), punit->owner) || + is_enemy_unit_tile(map_get_tile(x1, y), punit->owner)) return 0; } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/climisc.c workdir/client/climisc.c --- freeciv/client/climisc.c Wed May 17 17:41:38 2000 +++ workdir/client/climisc.c Wed May 17 17:49:02 2000 @@ -15,7 +15,6 @@ This module contains various general - mostly highlevel - functions used throughout the client. ***********************************************************************/ - #ifdef HAVE_CONFIG_H #include #endif @@ -31,11 +30,14 @@ #endif #include "astring.h" +#include "diptreaty.h" +#include "fcintl.h" #include "game.h" #include "log.h" #include "map.h" #include "city.h" #include "packets.h" +#include "support.h" #include "chatline_g.h" #include "citydlg_g.h" @@ -314,4 +316,49 @@ } } city_list_iterate_end; +} + +/************************************************************************** +Copy a string that describes the given clause into the return buffer. +**************************************************************************/ +void client_diplomacy_clause_string(char *buf, int bufsiz, + struct Clause *pclause) +{ + switch(pclause->type) { + case CLAUSE_ADVANCE: + my_snprintf(buf, bufsiz, _("The %s give %s"), + get_nation_name_plural(pclause->from->nation), + advances[pclause->value].name); + break; + case CLAUSE_CITY: + my_snprintf(buf, bufsiz, _("The %s give %s"), + get_nation_name_plural(pclause->from->nation), + find_city_by_id(pclause->value)->name); + break; + case CLAUSE_GOLD: + my_snprintf(buf, bufsiz, _("The %s give %d gold"), + get_nation_name_plural(pclause->from->nation), + pclause->value); + break; + case CLAUSE_MAP: + my_snprintf(buf, bufsiz, _("The %s give their worldmap"), + get_nation_name_plural(pclause->from->nation)); + break; + case CLAUSE_SEAMAP: + my_snprintf(buf, bufsiz, _("The %s give their seamap"), + get_nation_name_plural(pclause->from->nation)); + break; + case CLAUSE_CEASEFIRE: + my_snprintf(buf, bufsiz, _("The parties agree on a cease-fire")); + break; + case CLAUSE_PEACE: + my_snprintf(buf, bufsiz, _("The parties agree on a peace")); + break; + case CLAUSE_ALLIANCE: + my_snprintf(buf, bufsiz, _("The parties create an alliance")); + break; + default: + if (bufsiz > 0) *buf = '\0'; + break; + } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/climisc.h workdir/client/climisc.h --- freeciv/client/climisc.h Wed May 17 17:41:38 2000 +++ workdir/client/climisc.h Wed May 17 17:49:02 2000 @@ -14,6 +14,7 @@ #define FC__CLIMISC_H struct city; +struct Clause; void client_remove_player(int plr_id); void client_remove_city(struct city *pcity); @@ -22,6 +23,9 @@ void climap_init_continents(void); void climap_update_continents(int x, int y); void client_change_all(int x, int y); + +void client_diplomacy_clause_string(char *buf, int bufsiz, + struct Clause *pclause); #endif /* FC__CLIMISC_H */ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/control.c workdir/client/control.c --- freeciv/client/control.c Wed May 17 17:41:38 2000 +++ workdir/client/control.c Wed May 17 17:49:02 2000 @@ -229,6 +229,8 @@ **************************************************************************/ struct unit *find_visible_unit(struct tile *ptile) { + struct unit *panyowned = NULL, *panyother = NULL, *ptptother = NULL; + if(unit_list_size(&ptile->units)==0) return NULL; /* If a unit is attacking we should show that on top */ @@ -252,19 +254,30 @@ unit_list_iterate_end; } - /* If there is a transporter in the stack we will show that on top */ - unit_list_iterate(ptile->units, punit) - if (get_transporter_capacity(punit) && - player_can_see_unit(game.player_ptr, punit)) - return punit; - unit_list_iterate_end; - - /* Else just return the first unit we can see */ + /* Iterate through the units to find the best one we prioritize this way: + 1: owned transporter. + 2: any owned unit + 3: any transporter + 4: any unit + (always return first in stack). */ unit_list_iterate(ptile->units, punit) - if(player_can_see_unit(game.player_ptr, punit)) return punit; + if (unit_owner(punit) == game.player_ptr) { + if (get_transporter_capacity(punit)) { + return punit; + } else if (!panyowned) { + panyowned = punit; + } + } else if (!ptptother && + player_can_see_unit(game.player_ptr, punit)) { + if (get_transporter_capacity(punit)) { + ptptother = punit; + } else if (!panyother) { + panyother = punit; + } + } unit_list_iterate_end; - return NULL; + return (panyowned ? panyowned : (ptptother ? ptptother : panyother)); } /************************************************************************** @@ -935,8 +948,12 @@ } } else if(unit_list_size(&ptile->units)>=2) { - if(unit_list_get(&ptile->units, 0)->owner==game.player_idx) - popup_unit_select_dialog(ptile); + unit_list_iterate(ptile->units, punit) + if (punit->owner == game.player_idx) { + popup_unit_select_dialog(ptile); + return; + } + unit_list_iterate_end; } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-gtk/citydlg.c workdir/client/gui-gtk/citydlg.c --- freeciv/client/gui-gtk/citydlg.c Wed May 17 17:41:38 2000 +++ workdir/client/gui-gtk/citydlg.c Wed May 17 17:49:02 2000 @@ -614,14 +614,17 @@ struct city_dialog *pdialog = (struct city_dialog *)data; int x=pdialog->pcity->x,y=pdialog->pcity->y; struct unit_list *punit_list = &map_get_tile(x,y)->units; + struct unit *pmyunit = NULL; if(unit_list_size(punit_list)) { unit_list_iterate((*punit_list), punit) { if(game.player_idx==punit->owner) { - request_new_unit_activity(punit, ACTIVITY_IDLE); + pmyunit = punit; + request_new_unit_activity(punit, ACTIVITY_IDLE); } } unit_list_iterate_end; - set_unit_focus(unit_list_get(punit_list, 0)); + if (pmyunit) + set_unit_focus(pmyunit); } } 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 Wed May 17 17:41:38 2000 +++ workdir/client/gui-gtk/diplodlg.c Wed May 17 17:49:02 2000 @@ -32,6 +32,7 @@ #include "support.h" #include "chatline.h" +#include "climisc.h" #include "clinet.h" #include "diptreaty.h" #include "gui_stuff.h" @@ -63,7 +64,8 @@ GtkWidget *dip_gold_frame1; GtkWidget *dip_gold_entry0; GtkWidget *dip_gold_entry1; - + GtkWidget *dip_pact_menu; + GtkWidget *dip_label; GtkWidget *dip_clauselabel; GtkWidget *dip_clauselist; @@ -94,6 +96,9 @@ void diplomacy_dialog_accept_callback(GtkWidget *w, gpointer data); void diplomacy_dialog_tech_callback(GtkWidget *w, gpointer data); void diplomacy_dialog_city_callback(GtkWidget *w, gpointer data); +void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data); +void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data); +void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data); void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog); void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog); static gint diplomacy_dialog_mbutton_callback(GtkWidget *w, GdkEvent *event); @@ -402,7 +407,36 @@ gtk_box_pack_start(GTK_BOX(pdialog->dip_vbox1), pdialog->dip_gold_frame1, FALSE,FALSE,2); - + + /* Start of pact button insertion */ + + pdialog->dip_pact_menu=gtk_menu_new(); + + item=gtk_menu_item_new_with_label(_("Cease-fire")); + gtk_menu_append(GTK_MENU(pdialog->dip_pact_menu),item); + gtk_signal_connect(GTK_OBJECT(item),"activate", + GTK_SIGNAL_FUNC(diplomacy_dialog_ceasefire_callback),(gpointer)pdialog); + + item=gtk_menu_item_new_with_label(_("Peace")); + gtk_menu_append(GTK_MENU(pdialog->dip_pact_menu),item); + gtk_signal_connect(GTK_OBJECT(item),"activate", + GTK_SIGNAL_FUNC(diplomacy_dialog_peace_callback),(gpointer)pdialog); + + item=gtk_menu_item_new_with_label(_("Allience")); + 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); + + gtk_widget_show_all(pdialog->dip_pact_menu); + + button=gtk_button_new_with_label(_("Pacts")); + gtk_box_pack_start(GTK_BOX(pdialog->dip_vbox0),button, FALSE,FALSE,2); + gtk_signal_connect_object(GTK_OBJECT(button), "event", + GTK_SIGNAL_FUNC(diplomacy_dialog_mbutton_callback), + GTK_OBJECT(pdialog->dip_pact_menu)); + + /* End of pact button insertion */ + my_snprintf(buf, sizeof(buf), _("This Eternal Treaty\n" "marks the results of the diplomatic work between\n" @@ -507,32 +541,7 @@ for(i=0; itype) { - case CLAUSE_ADVANCE: - my_snprintf(buf, sizeof(buf), _("The %s give %s"), - get_nation_name_plural(pclause->from->nation), - advances[pclause->value].name); - break; - case CLAUSE_CITY: - my_snprintf(buf, sizeof(buf), _("The %s give %s"), - get_nation_name_plural(pclause->from->nation), - find_city_by_id(pclause->value)->name); - break; - case CLAUSE_GOLD: - my_snprintf(buf, sizeof(buf), _("The %s give %d gold"), - get_nation_name_plural(pclause->from->nation), - pclause->value); - break; - case CLAUSE_MAP: - my_snprintf(buf, sizeof(buf), _("The %s give their worldmap"), - get_nation_name_plural(pclause->from->nation)); - break; - case CLAUSE_SEAMAP: - my_snprintf(buf, sizeof(buf), _("The %s give their seamap"), - get_nation_name_plural(pclause->from->nation)); - break; - } + client_diplomacy_clause_string(buf, sizeof(buf), pclause); gtk_clist_append(GTK_CLIST(pdialog->dip_clauselist),row); i++; } @@ -685,7 +694,47 @@ &pa); } +/**************************************************************** +... +*****************************************************************/ +static void diplomacy_dialog_add_pact_clause(GtkWidget *w, gpointer data, + int type) +{ + struct Diplomacy_dialog *pdialog=(struct Diplomacy_dialog *)data; + struct packet_diplomacy_info pa; + + pa.plrno0 = pdialog->treaty.plr0->player_no; + pa.plrno1 = pdialog->treaty.plr1->player_no; + pa.clause_type = type; + pa.plrno_from = pdialog->treaty.plr0->player_no; + pa.value = 0; + send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_CREATE_CLAUSE, + &pa); +} + +/**************************************************************** +... +*****************************************************************/ +void diplomacy_dialog_ceasefire_callback(GtkWidget *w, gpointer data) +{ + diplomacy_dialog_add_pact_clause(w, data, CLAUSE_CEASEFIRE); +} +/**************************************************************** +... +*****************************************************************/ +void diplomacy_dialog_peace_callback(GtkWidget *w, gpointer data) +{ + diplomacy_dialog_add_pact_clause(w, data, CLAUSE_PEACE); +} + +/**************************************************************** +... +*****************************************************************/ +void diplomacy_dialog_alliance_callback(GtkWidget *w, gpointer data) +{ + diplomacy_dialog_add_pact_clause(w, data, CLAUSE_ALLIANCE); +} 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 Wed May 17 17:41:38 2000 +++ workdir/client/gui-gtk/plrdlg.c Wed May 17 17:49:02 2000 @@ -44,6 +44,7 @@ static GtkWidget *players_close_command; static GtkWidget *players_int_command; static GtkWidget *players_meet_command; +static GtkWidget *players_war_command; static GtkWidget *players_sship_command; static int list_index_to_player_index[MAX_NUM_PLAYERS]; @@ -52,11 +53,13 @@ static void create_players_dialog(void); static void players_button_callback(GtkWidget *w, gpointer data); static void players_meet_callback(GtkWidget *w, gpointer data); +static void players_war_callback(GtkWidget *w, gpointer data); static void players_intel_callback(GtkWidget *w, gpointer data); static void players_list_callback(GtkWidget *w, gint row, gint column); static void players_list_ucallback(GtkWidget *w, gint row, gint column); static void players_sship_callback(GtkWidget *w, gpointer data); +#define NUM_COLOUMS 8 /**************************************************************** popup the dialog 10% inside the main-window @@ -77,13 +80,14 @@ *****************************************************************/ void create_players_dialog(void) { - static gchar *titles_[6] = { N_("Name"), N_("Race"), N_("Embassy"), + static gchar *titles_[NUM_COLOUMS] = { N_("Name"), N_("Race"), N_("Embassy"), + N_("Dipl.State"), N_("Reputation"), N_("State"), N_("Host"), N_("Idle") }; static gchar **titles; int i; GtkAccelGroup *accel=gtk_accel_group_new(); - if (!titles) titles = intl_slist(6, titles_); + if (!titles) titles = intl_slist(NUM_COLOUMS, titles_); players_dialog_shell = gtk_dialog_new(); gtk_signal_connect( GTK_OBJECT(players_dialog_shell),"delete_event", @@ -92,10 +96,10 @@ gtk_window_set_title(GTK_WINDOW(players_dialog_shell), _("Players")); - players_list=gtk_clist_new_with_titles(6, titles); + players_list=gtk_clist_new_with_titles(NUM_COLOUMS, titles); gtk_clist_column_titles_passive(GTK_CLIST(players_list)); - for(i=0; i<6; i++) + for(i=0; ivbox), @@ -119,6 +123,12 @@ players_meet_command, TRUE, TRUE, 0); GTK_WIDGET_SET_FLAGS(players_meet_command, GTK_CAN_DEFAULT); + players_war_command=gtk_accelbutton_new(_("_Cancel Treaty"), accel); + gtk_widget_set_sensitive(players_war_command, FALSE); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(players_dialog_shell)->action_area), + players_war_command, TRUE, TRUE, 0); + GTK_WIDGET_SET_FLAGS(players_war_command, GTK_CAN_DEFAULT); + players_sship_command=gtk_accelbutton_new(_("_Spaceship"), accel); gtk_widget_set_sensitive(players_sship_command, FALSE); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(players_dialog_shell)->action_area), @@ -127,6 +137,7 @@ gtk_signal_connect(GTK_OBJECT(players_list), "select_row", GTK_SIGNAL_FUNC(players_list_callback), NULL); + gtk_signal_connect(GTK_OBJECT(players_list), "unselect_row", GTK_SIGNAL_FUNC(players_list_ucallback), NULL); @@ -136,6 +147,9 @@ gtk_signal_connect(GTK_OBJECT(players_meet_command), "clicked", GTK_SIGNAL_FUNC(players_meet_callback), NULL); + gtk_signal_connect(GTK_OBJECT(players_war_command), "clicked", + GTK_SIGNAL_FUNC(players_war_callback), NULL); + gtk_signal_connect(GTK_OBJECT(players_int_command), "clicked", GTK_SIGNAL_FUNC(players_intel_callback), NULL); @@ -159,23 +173,27 @@ { if(players_dialog_shell) { int i,j; - char *row[6]; + char *row[NUM_COLOUMS]; + const struct player_diplstate *pds; gtk_clist_freeze(GTK_CLIST(players_list)); gtk_clist_clear(GTK_CLIST(players_list)); for(i=0,j=0; i3) { my_snprintf(idlebuf, sizeof(idlebuf), _("(idle %d turns)"), game.players[i].nturns_idle-1); } else { idlebuf[0]='\0'; } - + + /* text for state */ if(game.players[i].is_alive) { if(game.players[i].is_connected) { if(game.players[i].turn_done) @@ -189,17 +207,39 @@ else sz_strlcpy(statebuf, _("R.I.P")); + /* text for name, plus AI marker */ if(game.players[i].ai.control) my_snprintf(namebuf, sizeof(namebuf), "*%-15s", game.players[i].name); else my_snprintf(namebuf, sizeof(namebuf), "%-16s", game.players[i].name); + /* text for diplstate type and turns -- not applicable if this is me */ + if (i == game.player_idx) { + strcpy(dsbuf, "-"); + } else { + pds = player_get_diplstate(game.player_idx, i); + if (pds->type == DS_CEASEFIRE) { + my_snprintf(dsbuf, sizeof(dsbuf), "%s (%d)", + diplstate_text(pds->type), pds->turns_left); + } else { + my_snprintf(dsbuf, sizeof(dsbuf), "%s", + diplstate_text(pds->type)); + } + } + + /* text for reputation */ + my_snprintf(repbuf, sizeof(repbuf), + reputation_text(game.players[i].reputation)); + + /* assemble the whole lot */ row[0] = namebuf; row[1] = get_nation_name(game.players[i].nation); row[2] = player_has_embassy(game.player_ptr, &game.players[i]) ? "X":" "; - row[3] = statebuf; - row[4] = game.players[i].addr; - row[5] = idlebuf; + row[3] = dsbuf; + row[4] = repbuf; + row[5] = statebuf; + row[6] = game.players[i].addr; + row[7] = idlebuf; gtk_clist_append(GTK_CLIST(players_list), row); @@ -220,19 +260,25 @@ int player_index = list_index_to_player_index[row]; struct player *pplayer = &game.players[player_index]; - if(pplayer->spaceship.state != SSHIP_NONE) - gtk_widget_set_sensitive(players_sship_command, TRUE); + if(pplayer->spaceship.state != SSHIP_NONE) + gtk_widget_set_sensitive(players_sship_command, TRUE); + 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 + gtk_widget_set_sensitive(players_war_command, FALSE); + + if(pplayer->is_alive && player_has_embassy(game.player_ptr, pplayer)) { + if(pplayer->is_connected) + gtk_widget_set_sensitive(players_meet_command, TRUE); else - gtk_widget_set_sensitive(players_sship_command, FALSE); - - if(pplayer->is_alive && player_has_embassy(game.player_ptr, pplayer)) { - if(pplayer->is_connected) - gtk_widget_set_sensitive(players_meet_command, TRUE); - else - gtk_widget_set_sensitive(players_meet_command, FALSE); - gtk_widget_set_sensitive(players_int_command, TRUE); - return; - } + gtk_widget_set_sensitive(players_meet_command, FALSE); + gtk_widget_set_sensitive(players_int_command, TRUE); + return; + } gtk_widget_set_sensitive(players_meet_command, FALSE); gtk_widget_set_sensitive(players_int_command, FALSE); @@ -278,6 +324,29 @@ } else { append_output_window(_("Game: You need an embassy to establish a diplomatic meeting.")); + } +} + +/************************************************************************** +... +**************************************************************************/ +void players_war_callback(GtkWidget *w, gpointer data) +{ + GList *selection = GTK_CLIST(players_list)->selection; + gint row; + int player_index; + + if (!selection) + return; + else { + struct packet_generic_integer pa; + + row = (gint)selection->data; + player_index = list_index_to_player_index[row]; + + pa.value = player_index; + send_packet_generic_integer(&aconnection, PACKET_PLAYER_CANCEL_PACT, + &pa); } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-xaw/citydlg.c workdir/client/gui-xaw/citydlg.c --- freeciv/client/gui-xaw/citydlg.c Wed May 17 17:41:48 2000 +++ workdir/client/gui-xaw/citydlg.c Wed May 17 17:49:02 2000 @@ -1097,14 +1097,17 @@ struct city_dialog *pdialog = (struct city_dialog *)client_data; int x=pdialog->pcity->x,y=pdialog->pcity->y; struct unit_list *punit_list = &map_get_tile(x,y)->units; + struct unit *pmyunit = NULL; if( unit_list_size(punit_list) ) { unit_list_iterate((*punit_list), punit) { if(game.player_idx==punit->owner) { request_new_unit_activity(punit, ACTIVITY_IDLE); + pmyunit = punit; } } unit_list_iterate_end; - set_unit_focus(unit_list_get(punit_list, 0)); + if (pmyunit) + set_unit_focus(pmyunit); } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-xaw/diplodlg.c workdir/client/gui-xaw/diplodlg.c --- freeciv/client/gui-xaw/diplodlg.c Wed May 17 17:41:48 2000 +++ workdir/client/gui-xaw/diplodlg.c Wed May 17 17:49:02 2000 @@ -45,6 +45,7 @@ #include "support.h" #include "chatline.h" +#include "climisc.h" #include "clinet.h" #include "diptreaty.h" #include "gui_stuff.h" @@ -77,6 +78,7 @@ Widget dip_gold_label1; Widget dip_gold_input0; Widget dip_gold_input1; + Widget dip_pact_menubutton; Widget dip_label; Widget dip_clauselabel; @@ -120,6 +122,12 @@ XtPointer call_data); void diplomacy_dialog_city_callback(Widget w, XtPointer client_data, XtPointer call_data); +void diplomacy_dialog_ceasefire_callback(Widget w, XtPointer client_data, + XtPointer call_data); +void diplomacy_dialog_peace_callback(Widget w, XtPointer client_data, + XtPointer call_data); +void diplomacy_dialog_alliance_callback(Widget w, XtPointer client_data, + XtPointer call_data); void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog); void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog); @@ -460,6 +468,27 @@ XtNlabel, buf, NULL); + pdialog->dip_pact_menubutton= + I_L(XtVaCreateManagedWidget("dippactmenubutton", + menuButtonWidgetClass, + pdialog->dip_form0, + NULL)); + popupmenu=XtVaCreatePopupShell("menu", + simpleMenuWidgetClass, + pdialog->dip_pact_menubutton, + NULL); + entry=XtVaCreateManagedWidget(_("Cease-fire"), smeBSBObjectClass, popupmenu, + NULL); + XtAddCallback(entry, XtNcallback, diplomacy_dialog_ceasefire_callback, + (XtPointer)pdialog); + entry=XtVaCreateManagedWidget(_("Peace"), smeBSBObjectClass, popupmenu, + NULL); + XtAddCallback(entry, XtNcallback, diplomacy_dialog_peace_callback, + (XtPointer)pdialog); + entry=XtVaCreateManagedWidget(_("Alliance"), smeBSBObjectClass, popupmenu, + NULL); + XtAddCallback(entry, XtNcallback, diplomacy_dialog_alliance_callback, + (XtPointer)pdialog); my_snprintf(buf, sizeof(buf), _("This Eternal Treaty\n" @@ -591,34 +620,7 @@ for(i=0; itype) { - case CLAUSE_ADVANCE: - my_snprintf(pdialog->clauselist_strings[i], n, _("The %s give %s"), - get_nation_name_plural(pclause->from->nation), - advances[pclause->value].name); - break; - case CLAUSE_CITY: - my_snprintf(pdialog->clauselist_strings[i], n, _("The %s give %s"), - get_nation_name_plural(pclause->from->nation), - find_city_by_id(pclause->value)->name); - break; - case CLAUSE_GOLD: - my_snprintf(pdialog->clauselist_strings[i], n, _("The %s give %d gold"), - get_nation_name_plural(pclause->from->nation), - pclause->value); - break; - case CLAUSE_MAP: - my_snprintf(pdialog->clauselist_strings[i], n, - _("The %s give their worldmap"), - get_nation_name_plural(pclause->from->nation)); - break; - case CLAUSE_SEAMAP: - my_snprintf(pdialog->clauselist_strings[i], n, - _("The %s give their seamap"), - get_nation_name_plural(pclause->from->nation)); - break; - } + client_diplomacy_clause_string(pdialog->clauselist_strings[i], n, pclause); pdialog->clauselist_strings_ptrs[i]=pdialog->clauselist_strings[i]; i++; } @@ -767,8 +769,60 @@ &pa); } +/**************************************************************** +Generic add-a-clause function for adding pact types +*****************************************************************/ +static void diplomacy_dialog_add_pact_clause(Widget w, XtPointer client_data, + XtPointer call_data, int type) +{ + struct Diplomacy_dialog *pdialog=(struct Diplomacy_dialog *)client_data; + struct packet_diplomacy_info pa; + struct player *pgiver; + + pgiver=(XtParent(XtParent(w))==pdialog->dip_pact_menubutton) ? + pdialog->treaty.plr0 : pdialog->treaty.plr1; + + pa.plrno0=pdialog->treaty.plr0->player_no; + pa.plrno1=pdialog->treaty.plr1->player_no; + pa.clause_type=type; + pa.plrno_from=pgiver->player_no; + pa.value=0; + send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_CREATE_CLAUSE, + &pa); +} +/**************************************************************** +The cease-fire widget was selected; add a cease-fire to the +clauses +*****************************************************************/ +void diplomacy_dialog_ceasefire_callback(Widget w, XtPointer client_data, + XtPointer call_data) +{ + diplomacy_dialog_add_pact_clause(w, client_data, call_data, + CLAUSE_CEASEFIRE); +} +/**************************************************************** +The peace widget was selected; add a peace treaty to the +clauses +*****************************************************************/ +void diplomacy_dialog_peace_callback(Widget w, XtPointer client_data, + XtPointer call_data) +{ + diplomacy_dialog_add_pact_clause(w, client_data, call_data, + CLAUSE_PEACE); +} + +/**************************************************************** +The alliance widget was selected; add an alliance to the +clauses +*****************************************************************/ +void diplomacy_dialog_alliance_callback(Widget w, XtPointer client_data, + XtPointer call_data) +{ + diplomacy_dialog_add_pact_clause(w, client_data, call_data, + CLAUSE_ALLIANCE); +} /**************************************************************** diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/gui-xaw/plrdlg.c workdir/client/gui-xaw/plrdlg.c --- freeciv/client/gui-xaw/plrdlg.c Wed May 17 17:41:48 2000 +++ workdir/client/gui-xaw/plrdlg.c Wed May 17 17:49:02 2000 @@ -53,6 +53,7 @@ static Widget players_close_command; static Widget players_int_command; static Widget players_meet_command; +static Widget players_war_command; static Widget players_sship_command; static int list_index_to_player_index[MAX_NUM_PLAYERS]; @@ -67,6 +68,8 @@ XtPointer call_data); static void players_list_callback(Widget w, XtPointer client_data, XtPointer call_data); +static void players_war_callback(Widget w, XtPointer client_data, + XtPointer call_data); static void players_sship_callback(Widget w, XtPointer client_data, XtPointer call_data); @@ -124,6 +127,12 @@ XtNsensitive, False, NULL)); + players_war_command = + I_L(XtVaCreateManagedWidget("playerswarcommand", commandWidgetClass, + players_form, + XtNsensitive, False, + NULL)); + players_sship_command = I_L(XtVaCreateManagedWidget("playerssshipcommand", commandWidgetClass, players_form, @@ -142,6 +151,9 @@ XtAddCallback(players_int_command, XtNcallback, players_intel_callback, NULL); + XtAddCallback(players_war_command, XtNcallback, players_war_callback, + NULL); + XtAddCallback(players_sship_command, XtNcallback, players_sship_callback, NULL); @@ -166,19 +178,24 @@ Dimension width; static char *namelist_ptrs[MAX_NUM_PLAYERS]; static char namelist_text[MAX_NUM_PLAYERS][256]; + const struct player_diplstate *pds; for(i=0,j=0; i3) { my_snprintf(idlebuf, sizeof(idlebuf), _("(idle %d turns)"), game.players[i].nturns_idle-1); } else { idlebuf[0]='\0'; } - + + /* text for state */ if(game.players[i].is_alive) { if(game.players[i].is_connected) { if(game.players[i].turn_done) @@ -191,17 +208,40 @@ } else sz_strlcpy(statebuf, _("R.I.P")); - + + /* text for name, plus AI marker */ if(game.players[i].ai.control) my_snprintf(namebuf, sizeof(namebuf), "*%-15s",game.players[i].name); else my_snprintf(namebuf, sizeof(namebuf), "%-16s",game.players[i].name); namebuf[16] = '\0'; + + /* text for diplstate type and turns -- not applicable if this is me */ + if (i == game.player_idx) { + strcpy(dsbuf, "-"); + } else { + pds = player_get_diplstate(game.player_idx, i); + if (pds->type == DS_CEASEFIRE) { + my_snprintf(dsbuf, sizeof(dsbuf), "%s (%d)", + diplstate_text(pds->type), pds->turns_left); + } else { + my_snprintf(dsbuf, sizeof(dsbuf), "%s", + diplstate_text(pds->type)); + } + } + + /* text for reputation */ + my_snprintf(repbuf, sizeof(repbuf), + reputation_text(game.players[i].reputation)); + + /* assemble the whole lot */ my_snprintf(namelist_text[j], sizeof(namelist_text[j]), - "%-16s %-12s %c %-6s %-15s%s", + "%-16s %-12s %c %-15s %-13s %-6s %-15s%s", namebuf, get_nation_name(game.players[i].nation), player_has_embassy(game.player_ptr, &game.players[i]) ? 'X':' ', + dsbuf, + repbuf, statebuf, game.players[i].addr, idlebuf); @@ -238,6 +278,14 @@ else XtSetSensitive(players_sship_command, FALSE); + if(pplayer->is_alive) { + if (players_at_war(game.player_idx, player_index) || + game.player_idx == player_index) + XtSetSensitive(players_war_command, FALSE); + else + XtSetSensitive(players_war_command, TRUE); + } + if(pplayer->is_alive && player_has_embassy(game.player_ptr, pplayer)) { if(pplayer->is_connected) XtSetSensitive(players_meet_command, TRUE); @@ -311,6 +359,23 @@ int player_index = list_index_to_player_index[ret->list_index]; if(player_has_embassy(game.player_ptr, &game.players[player_index])) popup_intel_dialog(&game.players[player_index]); + } +} + +/************************************************************************** +... +**************************************************************************/ +void players_war_callback(Widget w, XtPointer client_data, + XtPointer call_data) +{ + XawListReturnStruct *ret; + + ret=XawListShowCurrent(players_list); + if(ret->list_index!=XAW_LIST_NONE) { + struct packet_generic_integer pa; + pa.value=ret->list_index; + send_packet_generic_integer(&aconnection, PACKET_PLAYER_CANCEL_PACT, + &pa); } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/options.c workdir/client/options.c --- freeciv/client/options.c Wed May 17 17:41:38 2000 +++ workdir/client/options.c Wed May 17 17:49:02 2000 @@ -108,6 +108,8 @@ 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 */ }; /************************************************************************** diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/client/packhand.c workdir/client/packhand.c --- freeciv/client/packhand.c Wed May 17 17:41:38 2000 +++ workdir/client/packhand.c Wed May 17 17:49:02 2000 @@ -728,6 +728,16 @@ pplayer->embassy=pinfo->embassy; pplayer->city_style=pinfo->city_style; + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + pplayer->diplstates[i].type = + pinfo->diplstates[i].type; + pplayer->diplstates[i].turns_left = + pinfo->diplstates[i].turns_left; + pplayer->diplstates[i].has_reason_to_cancel = + pinfo->diplstates[i].has_reason_to_cancel; + } + pplayer->reputation = pinfo->reputation; + for (i = 0; i < MAX_NUM_WORKLISTS; i++) copy_worklist(&pplayer->worklists[i], &pinfo->worklists[i]); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/capstr.c workdir/common/capstr.c --- freeciv/common/capstr.c Wed May 17 17:41:52 2000 +++ workdir/common/capstr.c Wed May 17 17:49:02 2000 @@ -72,7 +72,7 @@ #define CAPABILITY "+1.10 +fog_of_war +fortify_two_step +get_sabotage_list \ ocean_reclamation +dipl_cli_pop_dlg advance_focus_packet +30players \ -submarine_flags" +submarine_flags +dipl_states" /* "+1.10" is protocol for 1.10.0 stable release @@ -96,6 +96,9 @@ "submarine_flags" is F_SUBMARINE split into F_PARTIAL_INVIS, F_MISSILE_CARRIER, F_NO_LAND_ATTACK + + "dipl_states" is for servers and clients that understand diplomatic + states: alliances, cease-fires, and what-have-you. */ void init_our_capability(void) diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/diptreaty.c workdir/common/diptreaty.c --- freeciv/common/diptreaty.c Wed May 17 17:41:52 2000 +++ workdir/common/diptreaty.c Wed May 17 17:49:02 2000 @@ -61,7 +61,6 @@ } - /**************************************************************** ... *****************************************************************/ @@ -88,6 +87,14 @@ ptreaty->accept0=0; ptreaty->accept1=0; pclause->value=val; + return 1; + } + if(is_pact_clause(type) && + is_pact_clause(pclause->type)) { + /* pact clause already there */ + ptreaty->accept0=0; + ptreaty->accept1=0; + pclause->type=type; return 1; } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/diptreaty.h workdir/common/diptreaty.h --- freeciv/common/diptreaty.h Wed May 17 17:41:52 2000 +++ workdir/common/diptreaty.h Wed May 17 17:49:02 2000 @@ -16,7 +16,11 @@ #include "genlist.h" enum clause_type { CLAUSE_ADVANCE, CLAUSE_GOLD, CLAUSE_MAP, - CLAUSE_SEAMAP, CLAUSE_CITY}; + CLAUSE_SEAMAP, CLAUSE_CITY, + CLAUSE_CEASEFIRE, CLAUSE_PEACE, CLAUSE_ALLIANCE }; + +#define is_pact_clause(x) \ + ((x == CLAUSE_CEASEFIRE) || (x == CLAUSE_PEACE) || (x == CLAUSE_ALLIANCE)) struct Clause { enum clause_type type; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/events.h workdir/common/events.h --- freeciv/common/events.h Wed May 17 17:41:52 2000 +++ workdir/common/events.h Wed May 17 17:49:02 2000 @@ -51,6 +51,8 @@ E_SPACESHIP, E_UPRISING, E_WORKLIST, + E_CANCEL_PACT, + E_DIPL_INCIDENT, /* 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 Wed May 17 17:41:52 2000 +++ workdir/common/game.c Wed May 17 22:58:27 2000 @@ -922,7 +922,7 @@ } city_list_iterate_end; } - + if(game.player_idx>plrno) { game.player_idx--; game.player_ptr=&game.players[game.player_idx]; @@ -930,10 +930,19 @@ game.nplayers--; + for (i=0; idiplstates[j] = pplayer->diplstates[j+1]; + } + pplayer->diplstates[game.nplayers-1].type = DS_NEUTRAL; + pplayer->diplstates[game.nplayers-1].has_reason_to_cancel = 0; + } + for(i=0; iplayerno); cptr=put_string(cptr, pinfo->name); + cptr=put_uint8(cptr, pinfo->is_male); cptr=put_uint8(cptr, pinfo->government); cptr=put_uint32(cptr, pinfo->embassy); @@ -1308,7 +1310,14 @@ cptr=put_uint8(cptr, pinfo->turn_done?1:0); cptr=put_uint16(cptr, pinfo->nturns_idle); cptr=put_uint8(cptr, pinfo->is_alive?1:0); - + + cptr=put_uint32(cptr, pinfo->reputation); + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + cptr=put_uint32(cptr, pinfo->diplstates[i].type); + cptr=put_uint32(cptr, pinfo->diplstates[i].turns_left); + cptr=put_uint32(cptr, pinfo->diplstates[i].has_reason_to_cancel); + } + cptr=put_uint32(cptr, pinfo->gold); cptr=put_uint8(cptr, pinfo->tax); cptr=put_uint8(cptr, pinfo->science); @@ -1317,6 +1326,7 @@ cptr=put_uint32(cptr, pinfo->researched); cptr=put_uint32(cptr, pinfo->researchpoints); cptr=put_uint8(cptr, pinfo->researching); + cptr=put_bit_string(cptr, (char*)pinfo->inventions); cptr=put_uint16(cptr, pinfo->future_tech); @@ -1354,6 +1364,7 @@ iget_uint8(&iter, &pinfo->playerno); iget_string(&iter, pinfo->name, sizeof(pinfo->name)); + iget_uint8(&iter, &pinfo->is_male); iget_uint8(&iter, &pinfo->government); iget_uint32(&iter, &pinfo->embassy); @@ -1363,6 +1374,13 @@ iget_uint16(&iter, &pinfo->nturns_idle); iget_uint8(&iter, &pinfo->is_alive); + iget_uint32(&iter, &pinfo->reputation); + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + iget_uint32(&iter, (int*)&pinfo->diplstates[i].type); + iget_uint32(&iter, &pinfo->diplstates[i].turns_left); + iget_uint32(&iter, &pinfo->diplstates[i].has_reason_to_cancel); + } + iget_uint32(&iter, &pinfo->gold); iget_uint8(&iter, &pinfo->tax); iget_uint8(&iter, &pinfo->science); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/packets.h workdir/common/packets.h --- freeciv/common/packets.h Wed May 17 17:41:52 2000 +++ workdir/common/packets.h Wed May 17 17:49:02 2000 @@ -89,6 +89,7 @@ PACKET_INCITE_INQ, PACKET_INCITE_COST, PACKET_UNIT_UPGRADE, + PACKET_PLAYER_CANCEL_PACT, PACKET_RULESET_TECH, PACKET_RULESET_UNIT, PACKET_RULESET_BUILDING, @@ -408,6 +409,8 @@ int nation; int turn_done, nturns_idle; int is_alive; + int reputation; + struct player_diplstate diplstates[MAX_NUM_PLAYERS]; int gold, tax, science, luxury; int researched; int researchpoints; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/player.c workdir/common/player.c --- freeciv/common/player.c Wed May 17 17:41:52 2000 +++ workdir/common/player.c Wed May 17 17:49:02 2000 @@ -10,14 +10,20 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ***********************************************************************/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include #include #include -#include #include "city.h" +#include "fcintl.h" #include "game.h" #include "government.h" #include "idex.h" +#include "log.h" #include "map.h" #include "rand.h" #include "shared.h" @@ -69,6 +75,11 @@ sz_strlcpy(plr->addr, "---.---.---.---"); plr->is_alive=1; plr->embassy=0; + plr->reputation=GAME_DEFAULT_REPUTATION; + for(i = 0; i < MAX_NUM_PLAYERS; i++) { + plr->diplstates[i].type = DS_NEUTRAL; + plr->diplstates[i].has_reason_to_cancel = 0; + } plr->city_style=0; /* should be first basic style */ plr->ai.control=0; plr->ai.tech_goal = A_NONE; @@ -401,9 +412,140 @@ } /************************************************************************** +Return a reputation level as a human-readable string +**************************************************************************/ +const char *reputation_text(const int rep) +{ + if (rep == -1) + return "-"; + else if (rep > GAME_MAX_REPUTATION * 0.95) + return _("Spotless"); + else if (rep > GAME_MAX_REPUTATION * 0.85) + return _("Excellent"); + else if (rep > GAME_MAX_REPUTATION * 0.75) + return _("Honorable"); + else if (rep > GAME_MAX_REPUTATION * 0.55) + return _("Questionable"); + else if (rep > GAME_MAX_REPUTATION * 0.30) + return _("Dishonorable"); + else if (rep > GAME_MAX_REPUTATION * 0.15) + return _("Poor"); + else if (rep > GAME_MAX_REPUTATION * 0.07) + return _("Despicable"); + else + return _("Atrocious"); +} + +/************************************************************************** +Return a diplomatic state as a human-readable string +**************************************************************************/ +const char *diplstate_text(const enum diplstate_type type) +{ + static char *ds_names[DS_LAST] = + { + N_("Neutral"), + N_("War"), + N_("Cease-fire"), + N_("Peace"), + N_("Alliance") + }; + + if (type < DS_LAST) + return _(ds_names[type]); + freelog(LOG_FATAL, "Bad diplstate_type in diplstate_text: %d", type); + abort(); +} + +/*************************************************************** +returns diplomatic state type between two players +***************************************************************/ +const struct player_diplstate *pplayer_get_diplstate(const struct player *pplayer, + const struct player *pplayer2) +{ + return &(pplayer->diplstates[pplayer2->player_no]); +} + +/*************************************************************** +same as above, using player id's +***************************************************************/ +const struct player_diplstate *player_get_diplstate(const int player, + const int player2) +{ + return pplayer_get_diplstate(&game.players[player], &game.players[player2]); +} + +/*************************************************************** +returns true iff players can attack each other. Note that this +returns true if either player doesn't have the "dipl_states" +capability, so anyone can beat on them; this is for backward +compatibility with non-dipl_states-speaking clients. +***************************************************************/ +int pplayers_at_war(const struct player *pplayer, + const struct player *pplayer2) +{ + enum diplstate_type ds = pplayer_get_diplstate(pplayer, pplayer2)->type; + if (pplayer == pplayer2) return 0; + if (is_barbarian(pplayer) || is_barbarian(pplayer2)) + return TRUE; + return ((ds == DS_WAR) || (ds == DS_NEUTRAL)); +} + +/*************************************************************** +same as above, using player id's +***************************************************************/ +int players_at_war(const int player, const int player2) +{ + return pplayers_at_war(&game.players[player], &game.players[player2]); +} + +/*************************************************************** +returns true iff players are allied +***************************************************************/ +int pplayers_allied(const struct player *pplayer, + const struct player *pplayer2) +{ + enum diplstate_type ds = pplayer_get_diplstate(pplayer, pplayer2)->type; + if (pplayer == pplayer2) + return TRUE; + if (is_barbarian(pplayer) || is_barbarian(pplayer2)) + return FALSE; + return ((pplayer == pplayer2) || (ds == DS_ALLIANCE)); +} + +/*************************************************************** +same as above, using player id's +***************************************************************/ +int players_allied(const int player, const int player2) +{ + return pplayers_allied(&game.players[player], &game.players[player2]); +} + +/*************************************************************** +returns true iff players have peace or cease-fire +***************************************************************/ +int pplayers_non_attack(const struct player *pplayer, + const struct player *pplayer2) +{ + enum diplstate_type ds = pplayer_get_diplstate(pplayer, pplayer2)->type; + if (pplayer == pplayer2) + return FALSE; + if (is_barbarian(pplayer) || is_barbarian(pplayer2)) + return FALSE; + return (ds == DS_PEACE || ds == DS_CEASEFIRE); +} + +/*************************************************************** +same as above, using player id's +***************************************************************/ +int players_non_attack(const int player, const int player2) +{ + return pplayers_non_attack(&game.players[player], &game.players[player2]); +} + +/************************************************************************** ... **************************************************************************/ -int is_barbarian(struct player *pplayer) +int is_barbarian(const struct player *pplayer) { return (pplayer->ai.is_barbarian > 0); } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/player.h workdir/common/player.h --- freeciv/common/player.h Wed May 17 17:41:52 2000 +++ workdir/common/player.h Wed May 17 17:49:02 2000 @@ -97,6 +97,28 @@ int is_barbarian; }; +/* Diplomatic states (how one player views another). + * (Some diplomatic states are "pacts" (mutual agreements), others aren't.) + */ +enum diplstate_type { + DS_NEUTRAL = 0, + DS_WAR, + DS_CEASEFIRE, + DS_PEACE, + DS_ALLIANCE, + 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 */ + /* the following are for "pacts" */ + int turns_left; /* until pact (e.g., cease-fire) ends */ + int has_reason_to_cancel; /* 0: no, 1: this turn, 2: this or next turn */ +}; + /************************************************************************** command access levels for client-side use; at present, they are only used for server commands typed at the client chatline @@ -133,6 +155,8 @@ int revolution; int capital; /* bool used to give player capital in first city. */ int embassy; + int reputation; + struct player_diplstate diplstates[MAX_NUM_PLAYERS]; int city_style; struct unit_list units; struct city_list cities; @@ -177,9 +201,27 @@ int ai_handicap(struct player *pplayer, enum handicap_type htype); int ai_fuzzy(struct player *pplayer, int normal_decision); +const char *reputation_text(const int rep); +const char *diplstate_text(const enum diplstate_type type); + +/* we have an int in some contexts, a pointer in others. Yuk! */ +const struct player_diplstate *pplayer_get_diplstate(const struct player *pplayer, + const struct player *pplayer2); +const struct player_diplstate *player_get_diplstate(const int player, + const int player2); +int pplayers_at_war(const struct player *pplayer, + const struct player *pplayer2); +int players_at_war(const int player, const int player2); +int pplayers_allied(const struct player *pplayer, + const struct player *pplayer2); +int players_allied(const int player, const int player2); +int pplayers_non_attack(const struct player *pplayer, + const struct player *pplayer2); +int players_non_attack(const int player, const int player2); + const char *cmdlevel_name(enum cmdlevel_id lvl); enum cmdlevel_id cmdlevel_named(const char *token); -int is_barbarian(struct player *pplayer); +int is_barbarian(const struct player *pplayer); #endif /* FC__PLAYER_H */ diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/common/unit.c workdir/common/unit.c --- freeciv/common/unit.c Wed May 17 17:41:52 2000 +++ workdir/common/unit.c Wed May 17 17:49:02 2000 @@ -14,10 +14,10 @@ #include #endif +#include #include #include /* free */ #include -#include #include "astring.h" #include "fcintl.h" @@ -147,12 +147,13 @@ int destx, int desty) { struct city *pcity=map_get_city(destx, desty); + int playerid = pdiplomat->owner; if(pcity) { if(pcity->owner!=pdiplomat->owner && real_map_distance(pdiplomat->x, pdiplomat->y, pcity->x, pcity->y) <= 1) { if(action==DIPLOMAT_SABOTAGE) - return 1; + return players_at_war(playerid, pcity->owner); if(action==DIPLOMAT_EMBASSY && !is_barbarian(&game.players[pcity->owner]) && !player_has_embassy(&game.players[pdiplomat->owner], @@ -161,35 +162,40 @@ if(action==SPY_POISON && pcity->size>1 && unit_flag(pdiplomat->type, F_SPY)) - return 1; + return players_at_war(playerid, pcity->owner); if(action==DIPLOMAT_INVESTIGATE) return 1; if(action==DIPLOMAT_STEAL && !is_barbarian(&game.players[pcity->owner])) return 1; if(action==DIPLOMAT_INCITE) - return 1; + return !players_allied(pcity->owner, pdiplomat->owner); if(action==DIPLOMAT_ANY_ACTION) return 1; if (action==SPY_GET_SABOTAGE_LIST && unit_flag(pdiplomat->type, F_SPY)) - return 1; + return players_at_war(playerid, pcity->owner); + } + } else { /* Action against a unit at a tile */ + struct tile *ptile = map_get_tile(destx, desty); + struct unit *punit; + + if ((action==SPY_SABOTAGE_UNIT || action==DIPLOMAT_ANY_ACTION) && + unit_list_size(&ptile->units)==1 && + unit_flag(pdiplomat->type, F_SPY)) { + punit = unit_list_get(&ptile->units, 0); + return players_at_war(playerid, punit->owner); + } + + if ((action==DIPLOMAT_BRIBE || action==DIPLOMAT_ANY_ACTION) && + unit_list_size(&ptile->units)==1) { + punit = unit_list_get(&ptile->units, 0); + return !players_allied(punit->owner, pdiplomat->owner); } - } else { - struct tile *ptile=map_get_tile(destx, desty); - if((action==SPY_SABOTAGE_UNIT || action==DIPLOMAT_ANY_ACTION) && - unit_list_size(&ptile->units)==1 && - unit_list_get(&ptile->units, 0)->owner!=pdiplomat->owner && - unit_flag(pdiplomat->type, F_SPY)) - return 1; - if((action==DIPLOMAT_BRIBE || action==DIPLOMAT_ANY_ACTION) && - unit_list_size(&ptile->units)==1 && - unit_list_get(&ptile->units, 0)->owner!=pdiplomat->owner) - return 1; } return 0; } /************************************************************************** -... +FIXME: Maybe we should allow airlifts between allies **************************************************************************/ int unit_can_airlift_to(struct unit *punit, struct city *pcity) { @@ -648,6 +654,8 @@ if(!pcity) return 0; if(pcity->size > game.add_to_size_limit) + return 0; + if(pcity->owner != punit->owner) return 0; if(improvement_exists(B_AQUEDUCT) diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/data/Freeciv workdir/data/Freeciv --- freeciv/data/Freeciv Wed May 17 17:41:35 2000 +++ workdir/data/Freeciv Wed May 17 17:49:03 2000 @@ -429,6 +429,15 @@ Freeciv*dipgoldlabel1.left: chainLeft Freeciv*dipgoldlabel1.right: chainLeft +Freeciv*dippactmenubutton.label: _("Pacts") +Freeciv*dippactmenubutton.fromVert: dipgoldinput0 +Freeciv*dippactmenubutton.foreground: white +Freeciv*dippactmenubutton.background: blue +Freeciv*dippactmenubutton.top: chainTop +Freeciv*dippactmenubutton.bottom: chainTop +Freeciv*dippactmenubutton.left: chainLeft +Freeciv*dippactmenubutton.right: chainLeft + Freeciv*dipacceptcommand.label: _("Accept treaty") Freeciv*dipacceptcommand.fromVert: dipmainform Freeciv*dipacceptcommand.foreground: white @@ -3065,7 +3074,7 @@ Freeciv*playerslabel.left: chainLeft Freeciv*playerslabel.right: chainRight Freeciv*playerslabel.label: _("\ -Name Race Embassy State Host") +Name Race Embassy Dipl.State Reputation State Host") Freeciv*playerslist.fromVert: playerslabel Freeciv*playerslist.forceColumns: true @@ -3100,8 +3109,16 @@ Freeciv*playersmeetcommand.left: chainLeft Freeciv*playersmeetcommand.right: chainLeft +Freeciv*playerswarcommand.label: _("Cancel pact") +Freeciv*playerswarcommand.fromHoriz: playersmeetcommand +Freeciv*playerswarcommand.fromVert: playerslist +Freeciv*playerswarcommand.top: chainBottom +Freeciv*playerswarcommand.bottom: chainBottom +Freeciv*playerswarcommand.left: chainLeft +Freeciv*playerswarcommand.right: chainRight + Freeciv*playerssshipcommand.label: _("Spaceship") -Freeciv*playerssshipcommand.fromHoriz: playersmeetcommand +Freeciv*playerssshipcommand.fromHoriz: playerswarcommand Freeciv*playerssshipcommand.fromVert: playerslist Freeciv*playerssshipcommand.top: chainBottom Freeciv*playerssshipcommand.bottom: chainBottom diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/autoattack.c workdir/server/autoattack.c --- freeciv/server/autoattack.c Wed May 17 17:41:58 2000 +++ workdir/server/autoattack.c Wed May 17 17:49:03 2000 @@ -90,7 +90,8 @@ targets = &(map_get_tile(x, y)->units); if (unit_list_size(targets) == 0) continue; - if (unit_list_get(targets, 0)->owner == punit->owner) continue; + if (!is_enemy_unit_tile(map_get_tile(x, y), pplayer->player_no)) + continue; if (debug) freelog(LOG_DEBUG, "found enemy unit/stack at %d,%d", x, y); enemy = get_defender(pplayer, punit, x, y); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/barbarian.c workdir/server/barbarian.c --- freeciv/server/barbarian.c Wed May 17 17:41:58 2000 +++ workdir/server/barbarian.c Wed May 17 17:49:03 2000 @@ -184,7 +184,7 @@ { if( y < 0 || y >= map.ysize || map_get_terrain(x,y) == T_OCEAN || - is_enemy_unit_on_tile(x, y, who) ) + is_non_allied_unit_tile(map_get_tile(x, y), who) ) return 0; else return 1; @@ -197,7 +197,7 @@ { if( y < 0 || y >= map.ysize || map_get_terrain(x,y) != T_OCEAN || - is_enemy_unit_on_tile(x, y, who) ) + is_non_allied_unit_tile(map_get_tile(x, y), who) ) return 0; else return 1; diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/citytools.c workdir/server/citytools.c --- freeciv/server/citytools.c Wed May 17 17:41:58 2000 +++ workdir/server/citytools.c Thu May 18 00:34:37 2000 @@ -608,8 +608,8 @@ /* Transfer enemy units in the city to the new owner */ unit_list_iterate(map_get_tile(x, y)->units, vunit) { - /* 000608 wegge Dont transfer units already owned by new city-owner */ - if (unit_owner(vunit) != pplayer && pcity) { + /* Dont transfer units already owned by new city-owner --wegge */ + if (unit_owner(vunit) == pvictim && pcity) { freelog(LOG_VERBOSE, "Transfered %s in %s from %s to %s", unit_name(vunit->type), vcity->name, pvictim->name, pplayer->name); if (verbose) { diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.c workdir/server/cityturn.c --- freeciv/server/cityturn.c Wed May 17 17:41:58 2000 +++ workdir/server/cityturn.c Wed May 17 17:49:03 2000 @@ -1393,13 +1393,14 @@ if(unit_list_size(&ptile->units)>0) { struct unit *punit=unit_list_get(&ptile->units, 0); - if(pplayer->player_no!=punit->owner) { - if(get_worker_city(pcity, x, y)==C_TILE_WORKER) { + if (players_at_war(pplayer->player_no, punit->owner)) { + if (get_worker_city(pcity, x, y)==C_TILE_WORKER) { /* pcity->ppl_elvis++; -- this is really not polite -- Syela */ set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); add_adjust_workers(pcity); /* will place the displaced */ city_refresh(pcity); /* may be unnecessary; can't hurt */ - } else set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); + } else + set_worker_city(pcity, x, y, C_TILE_UNAVAILABLE); continue; } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/civserver.c workdir/server/civserver.c --- freeciv/server/civserver.c Wed May 17 17:41:58 2000 +++ workdir/server/civserver.c Wed May 17 17:49:03 2000 @@ -767,6 +767,44 @@ } /************************************************************************** + check for cease-fires running out; update reputation; update cancelling + reasons +**************************************************************************/ +static void update_diplomatics() +{ + int p, p2; + + for(p = 0; p < game.nplayers; p++) { + for(p2 = 0; p2 < game.nplayers; p2++) { + game.players[p].diplstates[p2].has_reason_to_cancel = + MAX(game.players[p].diplstates[p2].has_reason_to_cancel - 1, 0); + + if(game.players[p].diplstates[p2].type == DS_CEASEFIRE) { + switch(--game.players[p].diplstates[p2].turns_left) { + case 1: + notify_player(&game.players[p], + _("Game: Concerned citizens point " + "out that the cease-fire with %s will run out soon."), + game.players[p2].name); + break; + case -1: + notify_player(&game.players[p], + _("Game: The cease-fire with %s has " + "run out. You are now neutral towards the %s."), + game.players[p2].name, + get_nation_name_plural(game.players[p2].nation)); + game.players[p].diplstates[p2].type = DS_NEUTRAL; + break; + } + } + game.players[p].reputation = + MIN(game.players[p].reputation + GAME_REPUTATION_INCR, + GAME_MAX_REPUTATION); + } + } +} + +/************************************************************************** ... **************************************************************************/ static void before_end_year(void) @@ -839,6 +877,7 @@ send_player_cities(&game.players[i]); } update_pollution(); + update_diplomatics(); do_apollo_program(); make_history_report(); freelog(LOG_DEBUG, "Turn ended."); @@ -1126,6 +1165,10 @@ break; case PACKET_UNIT_PARADROP_TO: handle_unit_paradrop_to(pplayer, (struct packet_unit_request *)packet); + break; + case PACKET_PLAYER_CANCEL_PACT: + handle_player_cancel_pact(pplayer, + ((struct packet_generic_integer *)packet)->value); break; case PACKET_UNIT_CONNECT: handle_unit_connect(pplayer, (struct packet_unit_connect *)packet); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/diplhand.c workdir/server/diplhand.c --- freeciv/server/diplhand.c Wed May 17 17:41:58 2000 +++ workdir/server/diplhand.c Wed May 17 17:49:03 2000 @@ -199,6 +199,33 @@ } break; } + case CLAUSE_CEASEFIRE: + pgiver->diplstates[pdest->player_no].type=DS_CEASEFIRE; + pgiver->diplstates[pdest->player_no].turns_left=16; + pdest->diplstates[pgiver->player_no].type=DS_CEASEFIRE; + pdest->diplstates[pgiver->player_no].turns_left=16; + notify_player(pgiver, _("Game: You agree on a cease-fire with %s."), + pdest->name); + notify_player(pdest, _("Game: You agree on a cease-fire with %s."), + pgiver->name); + break; + case CLAUSE_PEACE: + pgiver->diplstates[pdest->player_no].type=DS_PEACE; + pdest->diplstates[pgiver->player_no].type=DS_PEACE; + notify_player(pgiver, _("Game: You agree on peace with %s."), + pdest->name); + notify_player(pdest, _("Game: You agree on peace with %s."), + pgiver->name); + break; + case CLAUSE_ALLIANCE: + pgiver->diplstates[pdest->player_no].type=DS_ALLIANCE; + pdest->diplstates[pgiver->player_no].type=DS_ALLIANCE; + notify_player(pgiver, _("Game: You agree on an alliance with %s."), + pdest->name); + notify_player(pdest, _("Game: You agree on an alliance with %s."), + pgiver->name); + break; + } } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/gotohand.c workdir/server/gotohand.c --- freeciv/server/gotohand.c Wed May 17 17:41:58 2000 +++ workdir/server/gotohand.c Wed May 17 17:59:58 2000 @@ -347,7 +347,7 @@ if (same_pos(x0, y0, myunit->x, myunit->y)) return 0; /* can't be my zoc */ if (is_tiles_adjacent(x0, y0, myunit->x, myunit->y) - && !is_enemy_unit_tile(x0, y0, owner)) + && !is_non_allied_unit_tile(map_get_tile(x0, y0), owner)) return 0; for (k = 0; k < 8; k++) { @@ -358,7 +358,8 @@ continue; /* don't care too much about ZOC of units we've already gone past -- Syela */ - if ((map_get_terrain(ax,ay)!=T_OCEAN) && is_enemy_unit_tile(ax,ay,owner)) + if ((map_get_terrain(ax,ay)!=T_OCEAN) && + is_non_allied_unit_tile(map_get_tile(ax,ay),owner)) return 0; } @@ -392,11 +393,12 @@ if(!is_tiles_adjacent(x0, y0, x, y)) return 0; - if(is_enemy_unit_tile(x,y,punit->owner)) - return 0; - ptile=map_get_tile(x, y); ptile2=map_get_tile(x0, y0); + + if(is_non_allied_unit_tile(ptile,punit->owner)) + return 0; + if(is_ground_unit(punit)) { /* Check condition 4 */ if(ptile->terrain==T_OCEAN && @@ -406,21 +408,23 @@ /* Moving from ocean */ if(ptile2->terrain==T_OCEAN) { /* Can't attack a city from ocean unless marines */ - if(!unit_flag(punit->type, F_MARINES) && is_enemy_city_tile(x,y,punit->owner)) { + if(!unit_flag(punit->type, F_MARINES) && is_enemy_city_tile(ptile, punit->owner)) { return 0; } } } else if(is_sailing_unit(punit)) { if(ptile->terrain!=T_OCEAN && ptile->terrain!=T_UNKNOWN) - if(!is_friendly_city_tile(x,y,punit->owner)) + if(!is_allied_city_tile(ptile, punit->owner)) return 0; - } + } - if((pcity=map_get_city(x, y))) { - if ((pcity->owner!=punit->owner && (is_air_unit(punit) || - !is_military_unit(punit)))) { - return 0; + if((pcity = map_get_city(x, y))) { + if (!is_allied_city_tile(ptile, punit->owner) && + (is_air_unit(punit) || !is_military_unit(punit))) { + return 0; } + if (is_non_attack_city_tile(ptile, punit->owner)) + return 0; } if (zoc_ok_move_gen(punit, x0, y0, x, y)) @@ -581,11 +585,11 @@ if (move_type == SEA_MOVING) { passenger = other_passengers(punit); if (passenger) - if (map_get_terrain(dest_x, dest_y) == T_OCEAN - || is_friendly_unit_tile(dest_x, dest_y, passenger->owner) - || is_friendly_city_tile(dest_x, dest_y, passenger->owner) - || unit_flag(passenger->type, F_MARINES) - || is_my_zoc(passenger, dest_x, dest_y)) + if (map_get_terrain(dest_x, dest_y) == T_OCEAN || + !is_non_allied_unit_tile(map_get_tile(dest_x, dest_y), passenger->owner) || + is_allied_city_tile(map_get_tile(dest_x, dest_y), passenger->owner) || + unit_flag(passenger->type, F_MARINES) || + is_my_zoc(passenger, dest_x, dest_y)) passenger = NULL; } else passenger = NULL; @@ -850,7 +854,7 @@ d0 = (d0 * n) / 2; h0 = punit->hp; h1 = 0; d1 = 0; u = 1; unit_list_iterate(ptile->units, aunit) - if (aunit->owner != punit->owner) d1 = -1; /* MINIMUM priority */ + if (!players_allied(aunit->owner, punit->owner)) d1 = -1; /* MINIMUM priority */ else { u++; a = get_simple_defense_power(aunit->type, x, y) * n / 2; @@ -877,7 +881,8 @@ else d[k]++; /* nice but not important */ } else { /* NOTE: Not being omniscient here!! -- Syela */ unit_list_iterate(adjtile->units, aunit) /* lookin for trouble */ - if (aunit->owner != punit->owner && (a = get_attack_power(aunit))) { + if (players_at_war(aunit->owner, punit->owner) + && (a = get_attack_power(aunit))) { if (punit->moves_left < c + 3) { /* can't fight */ if (passenger && !is_ground_unit(aunit)) d[k] = -99; else d[k] -= d1 * (aunit->hp * a * a / (a * a + d1 * d1)); @@ -1032,9 +1037,7 @@ freelog(LOG_DEBUG, "Going %s", d[k]); x = map_adjust_x(punit->x + ii[k]); y = punit->y + jj[k]; /* no need to adjust this */ - penemy = unit_list_get(&(map_get_tile(x,y)->units), 0); - if (penemy && penemy->owner == pplayer->player_no) - penemy = NULL; + penemy = is_enemy_unit_tile(map_get_tile(x, y), pplayer->player_no); if(!punit->moves_left) return; if(!handle_unit_move_request(pplayer, punit, x, y, FALSE)) { @@ -1050,7 +1053,7 @@ if (!player_find_unit_by_id(pplayer, unit_id)) return; /* unit died during goto! */ - /* Don't attack more than once per goto*/ + /* Don't attack more than once per goto */ if (penemy && !pplayer->ai.control) { /* Should I cancel for ai's too? */ punit->activity = ACTIVITY_IDLE; send_unit_info(0, punit); @@ -1161,7 +1164,9 @@ for (x = 0; x < map.xsize; x++) { for (y = 0; y < map.ysize; y++) { - if ((pcity = map_get_city(x,y)) && pcity->owner == playerid) { + ptile = map_get_tile(x,y); + if ((pcity = is_allied_city_tile(ptile, playerid)) + && !is_non_allied_unit_tile(ptile, playerid)) { prefuel = fc_malloc(sizeof(struct refuel)); prefuel->x = x; prefuel->y = y; prefuel->type = FUEL_CITY; @@ -1171,7 +1176,7 @@ continue; } if ((ptile = map_get_tile(x,y))->special&S_AIRBASE) { - if (is_enemy_unit_tile(x, y, playerid)) + if (is_non_allied_unit_tile(ptile, playerid)) continue; prefuel = fc_malloc(sizeof(struct refuel)); prefuel->x = x; prefuel->y = y; @@ -1414,8 +1419,6 @@ x = src_x; y = src_y; movescount = moves; while (real_map_distance(x, y, dest_x, dest_y) > 1) { - struct unit *punit; - if (movescount <= 1) goto TRYFULL; @@ -1430,8 +1433,7 @@ for (i = x-1 ; i <= x+1; i++) if ((ptile = map_get_tile(i, y+go_y)) /* && is_real_tile(i, y+go_y) */ - && (!(punit = unit_list_get(&(ptile->units), 0)) - || punit->owner == playerid)) { + && ! is_non_allied_unit_tile(ptile, playerid)) { x = i; y++; goto NEXTCYCLE; @@ -1441,8 +1443,7 @@ for (i = y-1 ; i <= y+1; i++) if ((ptile = map_get_tile(x+go_x, i)) && is_real_tile(x+go_x, i) - && (!(punit = unit_list_get(&(ptile->units), 0)) - || punit->owner == playerid)) { + && ! is_non_allied_unit_tile(ptile, playerid)) { x += go_x; y = i; goto NEXTCYCLE; @@ -1452,8 +1453,7 @@ /* (x+go_x, y+go_y) is always real, given (x, y) is real */ ptile = map_get_tile(x+go_x, y+go_y); - punit = unit_list_get(&(ptile->units), 0); - if (!punit || punit->owner == playerid) { + if (! is_non_allied_unit_tile(ptile, playerid)) { x += go_x; y += go_y; goto NEXTCYCLE; @@ -1461,16 +1461,14 @@ /* (x+go_x, y) is always real, given (x, y) is real */ ptile = map_get_tile(x+go_x, y); - punit = unit_list_get(&(ptile->units), 0); - if (!punit || punit->owner == playerid) { + if (! is_non_allied_unit_tile(ptile, playerid)) { x += go_x; goto NEXTCYCLE; } /* (x, y+go_y) is always real, given (x, y) is real */ ptile = map_get_tile(x, y+go_y); - punit = unit_list_get(&(ptile->units), 0); - if (!punit || punit->owner == playerid) { + if (! is_non_allied_unit_tile(ptile, playerid)) { y += go_y; goto NEXTCYCLE; } @@ -1494,7 +1492,6 @@ int ii[8] = { 0, 1, 2, 0, 2, 0, 1, 2 }; int jj[8] = { 0, 0, 0, 1, 1, 2, 2, 2 }; int xx[3], yy[3], x1, y1, k; - struct unit *punit; init_gotomap(src_x, src_y); warstacksize = 0; @@ -1512,8 +1509,7 @@ if (warmap.cost[x1][y1] == 255) { ptile = map_get_tile(x1,y1); - punit = unit_list_get(&(ptile->units), 0); - if (!punit || punit->owner == playerid + if (! is_non_allied_unit_tile(ptile, playerid) || (x1 == dest_x && y1 == dest_y)) {/* allow attack goto's */ warmap.cost[x1][y1] = warmap.cost[x][y] + 1; add_to_stack(x1, y1); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/plrhand.c workdir/server/plrhand.c --- freeciv/server/plrhand.c Wed May 17 17:41:58 2000 +++ workdir/server/plrhand.c Thu May 18 00:36:05 2000 @@ -1765,9 +1765,7 @@ { struct player_economic old_econ = pplayer->economic; int changed = FALSE; - player_limit_to_government_rates(pplayer); - if (pplayer->economic.tax != old_econ.tax) { changed = TRUE; notify_player(pplayer, @@ -1795,9 +1793,130 @@ } /************************************************************************** -... +Handles a player cancelling a "pact" with another player. +(It is a fatal error to call this when in a non-pact diplstate.) **************************************************************************/ +void handle_player_cancel_pact(struct player *pplayer, int other_player) +{ + 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 has_senate = + government_has_flag(get_gov_pplayer(pplayer), G_HAS_SENATE); + + /* can't break a pact with yourself */ + if (pplayer == pplayer2) + return; + + /* check what the new status will be, and what will happen to our + reputation */ + switch(old_type) { + case DS_CEASEFIRE: + new_type = DS_WAR; + reppenalty = GAME_MAX_REPUTATION/6; + break; + case DS_PEACE: + new_type = DS_WAR; + reppenalty = GAME_MAX_REPUTATION/5; + break; + case DS_ALLIANCE: + new_type = DS_PEACE; + reppenalty = GAME_MAX_REPUTATION/4; + break; + default: + freelog(LOG_FATAL, "non-pact diplstate in handle_player_cancel_pact"); + abort(); + } + + /* if there's a reason to cancel the pact, do it without penalty */ + if (pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel) { + pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel = 0; + if (has_senate) + notify_player(pplayer, _("The senate passes your bill because of the " + "constant provocations of the %s."), + get_nation_name_plural(pplayer2->nation)); + } + /* no reason to cancel, apply penalty (and maybe suffer a revolution) */ + /* FIXME: according to civII rules, republics and democracies + have different chances of revolution; maybe we need to + extend the govt rulesets to mimic this -- pt */ + else { + pplayer->reputation = MAX(pplayer->reputation - reppenalty, 0); + notify_player(pplayer, _("Game: Your reputation is now %s."), + reputation_text(pplayer->reputation)); + if (has_senate) { + if (myrand(GAME_MAX_REPUTATION) > pplayer->reputation) { + notify_player(pplayer, _("Game: The senate decides to dissolve " + "rather than support your actions any longer.")); + handle_player_revolution(pplayer); + } + } + } + + /* do the change */ + pplayer->diplstates[pplayer2->player_no].type = + pplayer2->diplstates[pplayer->player_no].type = + new_type; + pplayer->diplstates[pplayer2->player_no].turns_left = + pplayer2->diplstates[pplayer->player_no].turns_left = + 16; + + send_player_info(pplayer, 0); + send_player_info(pplayer2, 0); + + /* If the old state was alliance the players' units can share tiles + illegally, and we need to call resolve_unit_stack() on all the players' + units. We can't just iterate through the unitlist as it could get + corrupted when resolve_unit_stack() deletes units. */ + if (old_type == DS_ALLIANCE) { + int *resolve_list = NULL; + int tot_units = unit_list_size(&(pplayer->units)) + + unit_list_size(&(pplayer2->units)); + int no_units = unit_list_size(&(pplayer->units)); + int i; + if (tot_units > 0) + resolve_list = fc_malloc(no_units * 2 * sizeof(int)); + + i = 0; + unit_list_iterate(pplayer->units, punit) { + resolve_list[i] = punit->x; + resolve_list[i+1] = punit->y; + i += 2; + } unit_list_iterate_end; + + no_units = unit_list_size(&(pplayer2->units)); + unit_list_iterate(pplayer2->units, punit) { + resolve_list[i] = punit->x; + resolve_list[i+1] = punit->y; + i += 2; + } unit_list_iterate_end; + + if (resolve_list) { + for (i = 0; i < tot_units * 2; i += 2) + resolve_unit_stack(resolve_list[i], resolve_list[i+1], + 1); + free(resolve_list); + } + } + + notify_player(pplayer, + _("Game: There's now %s between the %s and the %s."), + diplstate_text(new_type), + get_nation_name_plural(pplayer->nation), + get_nation_name_plural(pplayer2->nation)); + 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), + get_nation_name_plural(pplayer2->nation), + get_nation_name_plural(pplayer->nation)); +} +/************************************************************************** +... +**************************************************************************/ void notify_player_ex(const struct player *pplayer, int x, int y, int event, const char *format, ...) { @@ -1927,6 +2046,14 @@ info.embassy=game.players[i].embassy; info.city_style=game.players[i].city_style; + info.reputation=game.players[i].reputation; + for(j=0; jreputation=secfile_lookup_int_default(file, GAME_DEFAULT_REPUTATION, + "player%d.reputation", plrno); + for(i=0; idiplstates[i].type = + secfile_lookup_int_default(file, DS_NEUTRAL, + "player%d.diplstate%d.type", plrno, i); + plr->diplstates[i].turns_left = + secfile_lookup_int_default(file, 0, + "player%d.diplstate%d.turns_left", plrno, i); + plr->diplstates[i].has_reason_to_cancel = + secfile_lookup_int_default(file, 0, + "player%d.diplstate%d.has_reason_to_cancel", + plrno, i); + } if (has_capability("spacerace", savefile_options)) { struct player_spaceship *ship = &plr->spaceship; @@ -2541,6 +2683,16 @@ invs[i]=(get_invention(plr, i)==TECH_KNOWN) ? '1' : '0'; invs[i]='\0'; secfile_insert_str(file, invs, "player%d.invs", plrno); + + secfile_insert_int(file, plr->reputation, "player%d.reputation", plrno); + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + secfile_insert_int(file, plr->diplstates[i].type, + "player%d.diplstate%d.type", plrno, i); + secfile_insert_int(file, plr->diplstates[i].turns_left, + "player%d.diplstate%d.turns_left", plrno, i); + secfile_insert_int(file, plr->diplstates[i].has_reason_to_cancel, + "player%d.diplstate%d.has_reason_to_cancel", plrno, i); + } secfile_insert_int(file, ship->state, "player%d.spaceship.state", plrno); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/plrhand.h workdir/server/plrhand.h --- freeciv/server/plrhand.h Wed May 17 17:41:59 2000 +++ workdir/server/plrhand.h Wed May 17 17:49:03 2000 @@ -28,6 +28,7 @@ void handle_player_rates(struct player *pplayer, 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 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 Wed May 17 17:41:59 2000 +++ workdir/server/stdinhand.c Wed May 17 17:49:03 2000 @@ -1350,6 +1350,32 @@ 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; + } + } +} + /************************************************************************** ... **************************************************************************/ @@ -1377,6 +1403,7 @@ /* The following is sometimes necessary to avoid using uninitialized data... */ assess_danger_player(pplayer); + neutralize_ai_player(pplayer); } else { notify_player(0, _("Game: %s is now human."), pplayer->name); cmd_reply(CMD_AITOGGLE, caller, C_OK, diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unitfunc.c workdir/server/unitfunc.c --- freeciv/server/unitfunc.c Wed May 17 17:41:59 2000 +++ workdir/server/unitfunc.c Wed May 17 20:01:34 2000 @@ -64,6 +64,8 @@ struct unit *pdiplomat, struct city *pcity); static void diplomat_escape (struct player *pplayer, struct unit *pdiplomat, struct city *pcity); +static void maybe_cause_incident(enum diplomat_actions action, struct player *offender, + struct unit *victim_unit, struct city *victim_city); static int upgrade_would_strand(struct unit *punit, int upgrade_type); @@ -71,6 +73,7 @@ Poison a city's water supply. - Only a Spy can poison a city's water supply. + - Only allowed against players you are at war with. - Check for infiltration success. Our poisoner may not survive this. - Only cities of size greater than one may be poisoned. @@ -86,8 +89,8 @@ /* Fetch target city's player. Sanity checks. */ if (!pcity) return; - cplayer = city_owner (pcity); - if ((cplayer == pplayer) || (cplayer == NULL)) + cplayer = city_owner(pcity); + if (cplayer == NULL || !pplayers_at_war(pplayer, cplayer)) return; freelog (LOG_DEBUG, "poison: unit: %d", pdiplomat->id); @@ -131,6 +134,9 @@ city_refresh (pcity); send_city_info (0, pcity); + /* this may cause a diplomatic incident */ + maybe_cause_incident(SPY_POISON, pplayer, NULL, pcity); + /* Now lets see if the spy survives. */ diplomat_escape (pplayer, pdiplomat, pcity); } @@ -139,6 +145,7 @@ Investigate a city. - Either a Diplomat or Spy can investigate a city. + - Allowed against all players. - It costs some minimal movement to investigate a city. @@ -173,6 +180,9 @@ pdiplomat->moves_left = 0; } + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_INVESTIGATE, pplayer, NULL, pcity); + /* Spies always survive. Diplomats never do. */ if (!unit_flag (pdiplomat->type, F_SPY)) { wipe_unit (pdiplomat); @@ -205,6 +215,9 @@ packet.diplomat_id = pdiplomat->id; packet.city_id = pcity->id; send_packet_sabotage_list(pplayer->conn, &packet); + + /* this may cause a diplomatic incident */ + maybe_cause_incident(SPY_GET_SABOTAGE_LIST, pplayer, NULL, pcity); } /****************************************************************************** @@ -221,7 +234,7 @@ - Spies always survive. ****************************************************************************/ void diplomat_embassy(struct player *pplayer, struct unit *pdiplomat, - struct city *pcity) + struct city *pcity) { struct player *cplayer; @@ -287,6 +300,9 @@ pdiplomat->moves_left = 0; } + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_EMBASSY, pplayer, NULL, pcity); + /* Spies always survive. Diplomats never do. */ if (!unit_flag (pdiplomat->type, F_SPY)) { wipe_unit (pdiplomat); @@ -299,6 +315,7 @@ Sabotage an enemy unit. - Only a Spy can sabotage an enemy unit. + - Only allowed against players you are at war with. - Can't sabotage a unit if: - It has only one hit point left. @@ -317,7 +334,7 @@ if (!pvictim) return; uplayer = get_player (pvictim->owner); - if ((uplayer == pplayer) || (uplayer == NULL)) + if (uplayer == NULL || pplayers_allied(pplayer, uplayer)) return; freelog (LOG_DEBUG, "sabotage-unit: unit: %d", pdiplomat->id); @@ -353,6 +370,9 @@ _("Game: Your %s was sabotaged by %s!"), unit_name (pvictim->type), pplayer->name); + /* this may cause a diplomatic incident */ + maybe_cause_incident(SPY_SABOTAGE_UNIT, pplayer, pvictim, NULL); + /* Now lets see if the spy survives. */ diplomat_escape (pplayer, pdiplomat, NULL); } @@ -360,13 +380,14 @@ /****************************************************************************** Bribe an enemy unit. - - Either a Diplomat or Spy can bribe an enemy unit. - + - Either a Diplomat or Spy can bribe an other players unit. + - Can't bribe a unit if: - Owner runs an unbribable government (e.g., democracy). - Player doesn't have enough money. - It's not the only unit on the square (this is handled outside this function). + - You are allied with the unit owner. - Otherwise, the unit will be bribed. - A successful briber will try to move onto the victim's square. @@ -380,8 +401,9 @@ /* Fetch target unit's player. Sanity checks. */ if (!pvictim) return; - uplayer = get_player (pvictim->owner); - if ((uplayer == pplayer) || (uplayer == NULL)) + uplayer = get_player(pvictim->owner); + /* We might make it allowable in peace with a liss of reputaion */ + if (uplayer == NULL || pplayers_allied(pplayer, uplayer)) return; freelog (LOG_DEBUG, "bribe-unit: unit: %d", pdiplomat->id); @@ -446,8 +468,11 @@ send_unit_info (pplayer, pdiplomat); } + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_BRIBE, pplayer, pvictim, NULL); + /* Update clients. */ - send_player_info (pplayer, pplayer); + send_player_info (pplayer, 0); } /**************************************************************************** @@ -467,6 +492,9 @@ - Steal technology! - The thief may be captured and executed, or escape to its home town. + + FIXME: It should give a loss of reputaion to steal from a player you are + not at war with ****************************************************************************/ void diplomat_get_tech(struct player *pplayer, struct unit *pdiplomat, struct city *pcity, int technology) @@ -654,6 +682,9 @@ /* Record the theft. */ (pcity->steal)++; + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_STEAL, pplayer, NULL, pcity); + /* Check if a spy survives her mission. Diplomats never do. */ diplomat_escape (pplayer, pdiplomat, pcity); } @@ -666,6 +697,7 @@ - Can't incite a city to disaffect if: - Owner runs an unbribable government (e.g., democracy). - Player doesn't have enough money. + - You are allied with the city owner. - Check for infiltration success. Our provocateur may not survive this. - Check for basic success. Again, our provocateur may not survive this. - Otherwise, the city will disaffect: @@ -686,7 +718,7 @@ if (!pcity) return; cplayer = city_owner (pcity); - if ((cplayer == pplayer) || (cplayer == NULL)) + if (cplayer == NULL || pplayers_allied(cplayer, pplayer)) return; freelog (LOG_DEBUG, "incite: unit: %d", pdiplomat->id); @@ -777,6 +809,9 @@ /* You get a technology advance, too! */ get_a_tech (pplayer, cplayer); + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_INCITE, pplayer, NULL, pcity); + /* Check if a spy survives her mission. Diplomats never do. */ diplomat_escape (pplayer, pdiplomat, pcity); @@ -798,6 +833,7 @@ (Note: Only Spies can select what to sabotage.) - Either a Diplomat or Spy can sabotage an enemy city. + - The players must be at war - Check for infiltration success. Our saboteur may not survive this. - Check for basic success. Again, our saboteur may not survive this. @@ -819,7 +855,7 @@ if (!pcity) return; cplayer = city_owner (pcity); - if ((cplayer == pplayer) || (cplayer == NULL)) + if (cplayer == NULL || !pplayers_at_war(pplayer, cplayer)) return; freelog (LOG_DEBUG, "sabotage: unit: %d", pdiplomat->id); @@ -1010,6 +1046,9 @@ /* Update clients. */ send_city_info (0, pcity); + /* this may cause a diplomatic incident */ + maybe_cause_incident(DIPLOMAT_SABOTAGE, pplayer, NULL, pcity); + /* Check if a spy survives her mission. Diplomats never do. */ diplomat_escape (pplayer, pdiplomat, pcity); } @@ -1182,6 +1221,104 @@ wipe_unit (pdiplomat); } +/************************************************************************** +... +**************************************************************************/ +static void maybe_cause_incident(enum diplomat_actions action, struct player *offender, + struct unit *victim_unit, struct city *victim_city) +{ + struct player *victim_player; + int x,y; + if (victim_city) { + x = victim_city->x; + y = victim_city->y; + victim_player = city_owner(victim_city); + } else if (victim_unit) { + x = victim_unit->x; + y = victim_unit->y; + victim_player = unit_owner(victim_unit); + } else { + freelog(LOG_FATAL, "No victim in call to maybe_cause_incident()"); + abort(); + } + + if (!pplayers_at_war(offender, victim_player) && + (myrand(GAME_MAX_REPUTATION) - offender->reputation > + GAME_MAX_REPUTATION/2 - victim_player->reputation)) { + enum diplstate_type ds = pplayer_get_diplstate(offender, victim_player)->type; + int punishment = 0; + switch (action) { + case DIPLOMAT_BRIBE: + notify_player_ex(offender, x, y, E_DIPL_INCIDENT, + _("Game: You have caused an incident while bribing " + "%s's %s."), + victim_player->name, + unit_name(victim_unit->type)); + notify_player_ex(victim_player, x, y, E_DIPL_INCIDENT, + _("Game: %s has caused an incident while bribing " + "your %s."), + offender->name, + unit_name(victim_unit->type)); + break; + case DIPLOMAT_STEAL: + notify_player_ex(offender, x, y, E_DIPL_INCIDENT, + _("Game: You have caused an incident while stealing " + "tech from %s."), + victim_player->name); + notify_player_ex(victim_player, x, y, E_DIPL_INCIDENT, + _("Game: %s has caused an incident while stealing " + "tech from you."), + offender->name); + break; + case DIPLOMAT_INCITE: + notify_player_ex(offender, x, y, E_DIPL_INCIDENT, + _("Game: You have caused an incident while inciting a " + "revolt in %s."), victim_city->name); + notify_player_ex(victim_player, x, y, E_DIPL_INCIDENT, + _("Game: %s have caused an incident while inciting a " + "revolt in %s."), offender->name, victim_city->name); + break; + case DIPLOMAT_EMBASSY: + case DIPLOMAT_INVESTIGATE: + case SPY_GET_SABOTAGE_LIST: + return; /* These are not considered offences */ + case DIPLOMAT_ANY_ACTION: + case SPY_POISON: + case SPY_SABOTAGE_UNIT: + case DIPLOMAT_SABOTAGE: + /* You can only do these when you are at war, so we should never + get inside this "if" */ + freelog(LOG_FATAL, "Bug in maybe_cause_incident()"); + abort(); + } + switch (ds) { + case DS_NEUTRAL: + case DS_WAR: + freelog(LOG_VERBOSE,"Trying to cause an incident between players at war"); + punishment = 0; + break; + case DS_CEASEFIRE: + case DS_PEACE: + punishment = GAME_MAX_REPUTATION/10; + break; + 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."); + abort(); + } + offender->reputation = MAX(offender->reputation - punishment, 0); + victim_player->diplstates[offender->player_no].has_reason_to_cancel = 2; + /* FIXME: Maybe we should try to cause a revolution is the offender's + government has a senate */ + send_player_info(offender, 0); + send_player_info(victim_player, 0); + } + + return; +} + /***************************************************************** Will wake up any neighboring enemy sentry units *****************************************************************/ @@ -1193,18 +1330,16 @@ for (x = cent_x-1;x <= cent_x+1;x++) for (y = cent_y-1;y <= cent_y+1;y++) - if ((x != cent_x)||(y != cent_y)) - { - unit_list_iterate(map_get_tile(x,y)->units, punit) { - if ((pplayer->player_no != punit->owner)&& - (punit->activity == ACTIVITY_SENTRY)) - { - set_unit_activity(punit, ACTIVITY_IDLE); - send_unit_info(0,punit); - } - } - unit_list_iterate_end; - } + if ((x != cent_x)||(y != cent_y)) { + unit_list_iterate(map_get_tile(x,y)->units, punit) { + if (!players_allied(pplayer->player_no, punit->owner) + && punit->activity == ACTIVITY_SENTRY) { + set_unit_activity(punit, ACTIVITY_IDLE); + send_unit_info(0,punit); + } + } + unit_list_iterate_end; + } } /*************************************************************************** @@ -1237,10 +1372,12 @@ tile_cap = 0; tile_ncargo = 0; unit_list_iterate(map_get_tile(punit->x, punit->y)->units, punit2) { - if (is_sailing_unit(punit2) && is_ground_units_transport(punit2)) { - tile_cap += get_transporter_capacity(punit2); - } else if (is_ground_unit(punit2)) { - tile_ncargo++; + if (punit2->owner == punit->owner) { + if (is_sailing_unit(punit2) && is_ground_units_transport(punit2)) { + tile_cap += get_transporter_capacity(punit2); + } else if (is_ground_unit(punit2)) { + tile_ncargo++; + } } } unit_list_iterate_end; @@ -1356,7 +1493,8 @@ to leave space on co-located Carriers for normal air units */ unit_list_iterate(map_get_tile(punit->x, punit->y)->units, punit2) if (!done && unit_flag(punit2->type, F_MISSILE_CARRIER) - && punit2->fuel) { + && punit2->fuel + && punit2->owner == punit->owner) { punit->fuel = get_unit_type(punit->type)->fuel; punit2->fuel--; done = 1; @@ -2169,15 +2307,6 @@ return 0; } - /* FIXME: this is a fog-of-war cheat. - You get to know if there is an enemy on the tile*/ - if (is_enemy_unit_tile(dest_x, dest_y, punit->owner)) { - notify_player_ex(unit_owner(punit), dest_x, dest_y, E_NOEVENT, - _("Game: Cannot paradrop because there are" - " enemy units on the destination location.")); - return 0; - } - { int range = get_unit_type(punit->type)->paratroopers_range; int distance = real_map_distance(punit->x, punit->y, dest_x, dest_y); @@ -2190,6 +2319,15 @@ } } + /* FIXME: this is a fog-of-war cheat. + You get to know if there is an enemy on the tile*/ + if (is_non_attack_unit_tile(map_get_tile(dest_x, dest_y), punit->owner)) { + notify_player_ex(unit_owner(punit), dest_x, dest_y, E_NOEVENT, + _("Game: Cannot paradrop because there are" + " enemy units on the destination location.")); + return 0; + } + /* All ok */ { int move_cost = get_unit_type(punit->type)->paratroopers_mr_sub; @@ -2432,13 +2570,14 @@ struct city *incity = map_get_city(punit->x, punit->y); struct player *pplayer = get_player(punit->owner); struct player *destroyer = get_player(pkiller->owner); - char *loc_str = get_location_str_in(pplayer, punit->x, punit->y, ", "); - int num_killed = unit_list_size(&(map_get_tile(punit->x, punit->y)->units)); - int ransom; + char *loc_str = get_location_str_in(pplayer, punit->x, punit->y, ", "); + int num_killed[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; + int ransom, unitcount = 0; /* barbarian leader ransom hack */ - if( is_barbarian(pplayer) && unit_has_role(punit->type, L_BARBARIAN_LEADER) && - (num_killed==1) && (is_ground_unit(pkiller) || is_heli_unit(pkiller)) ) { + if( is_barbarian(pplayer) && unit_has_role(punit->type, L_BARBARIAN_LEADER) + && (unit_list_size(&(map_get_tile(punit->x, punit->y)->units)) == 1) + && (is_ground_unit(pkiller) || is_heli_unit(pkiller)) ) { ransom = (pplayer->economic.gold >= 100)?100:pplayer->economic.gold; notify_player_ex(destroyer, pkiller->x, pkiller->y, E_UNIT_WIN_ATT, _("Game: Barbarian leader captured, %d gold ransom paid."), @@ -2446,12 +2585,20 @@ destroyer->economic.gold += ransom; pplayer->economic.gold -= ransom; send_player_info(destroyer,0); /* let me see my new money :-) */ + unitcount = 1; + } + + if (!unitcount) { + unit_list_iterate(map_get_tile(punit->x, punit->y)->units, vunit) + if (players_at_war(pkiller->owner, vunit->owner)) + unitcount++; + unit_list_iterate_end; } if( (incity) || (map_get_special(punit->x, punit->y)&S_FORTRESS) || (map_get_special(punit->x, punit->y)&S_AIRBASE) || - (num_killed == 1)) { + unitcount == 1) { notify_player_ex(pplayer, punit->x, punit->y, E_UNIT_LOST, _("Game: You lost a%s %s under an attack from %s's %s%s."), n_if_vowel(get_unit_type(punit->type)->name[0]), @@ -2462,34 +2609,58 @@ n_if_vowel(get_unit_type(punit->type)->name[0]), get_unit_type(punit->type)->name, get_nation_name_plural(destroyer->nation)); - + send_remove_unit(0, punit->id); server_remove_unit(punit); - } - else { - notify_player_ex(pplayer, punit->x, punit->y, E_UNIT_LOST, - _("Game: You lost %d units under an attack" - " from %s's %s%s."), - num_killed, destroyer->name, - unit_name(pkiller->type), loc_str); + } else { /* unitcount > 1 */ + int i; + if (!(unitcount > 1)) { + freelog(LOG_FATAL, "Error in kill_unit, unitcount is %i", unitcount); + abort(); + } + /* initialize */ + for (i = 0; ix ,punit->y)->units), vunit) + if (players_at_war(pkiller->owner, vunit->owner)) + num_killed[vunit->owner]++; + unit_list_iterate_end; + + /* inform the owners */ + for (i = 0; i0) { + notify_player_ex(get_player(i), punit->x, punit->y, E_UNIT_LOST, + _("Game: You lost %d units under an attack" + " from %s's %s%s."), + num_killed[i], destroyer->name, + unit_name(pkiller->type), loc_str); + } + } + + /* remove the units */ unit_list_iterate(map_get_tile(punit->x, punit->y)->units, punit2) { - notify_player_ex(&game.players[punit2->owner], + if (players_at_war(pkiller->owner, punit2->owner)) { + notify_player_ex(unit_owner(punit2), punit2->x, punit2->y, E_UNIT_LOST, _("Game: You lost a%s %s under an attack" " from %s's %s."), n_if_vowel(get_unit_type(punit2->type)->name[0]), get_unit_type(punit2->type)->name, destroyer->name, - unit_name(pkiller->type)); + unit_name(pkiller->type)); gamelog(GAMELOG_UNITL, "%s lose a%s %s to the %s", - get_nation_name_plural(pplayer->nation), + get_nation_name_plural(get_player(punit2->owner)->nation), n_if_vowel(get_unit_type(punit2->type)->name[0]), get_unit_type(punit2->type)->name, get_nation_name_plural(destroyer->nation)); send_remove_unit(0, punit2->id); server_remove_unit(punit2); + } } unit_list_iterate_end; - } + } } /************************************************************************** @@ -2761,7 +2932,7 @@ /*** Allocate air and missile units ***/ } else if (is_air_units_transport(ptrans)) { struct player_tile *plrtile = map_get_player_tile(get_player(playerid), x, y); - int is_refuel_point = is_friendly_city_tile(x, y, playerid) + int is_refuel_point = is_allied_city_tile(map_get_tile(x, y), playerid) || plrtile->special&S_AIRBASE; int missiles_only = unit_flag(ptrans->type, F_MISSILE_CARRIER) && !unit_flag(ptrans->type, F_CARRIER); diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unithand.c workdir/server/unithand.c --- freeciv/server/unithand.c Wed May 17 17:41:59 2000 +++ workdir/server/unithand.c Wed May 17 17:49:03 2000 @@ -293,14 +293,15 @@ { struct unit *punit; - if((punit=player_find_unit_by_id(pplayer, req->unit_id))) { + if ((punit=player_find_unit_by_id(pplayer, req->unit_id))) { struct city *pcity; - if((pcity=player_find_city_by_id(pplayer, req->city_id))) { + if ((pcity=player_find_city_by_id(pplayer, req->city_id)) + && pcity->owner == punit->owner) { unit_list_insert(&pcity->units_supported, punit); - + if((pcity=player_find_city_by_id(pplayer, punit->homecity))) unit_list_unlink(&pcity->units_supported, punit); - + punit->homecity=req->city_id; send_unit_info(pplayer, punit); } @@ -494,6 +495,20 @@ game.players[pdefender->owner].name, unit_types[pdefender->type].name); + if (players_non_attack(punit->owner, pdefender->owner)) { + freelog(LOG_FATAL, + "Trying to attack a unit with which you have peace or cease-fire at %i, %i", + def_x, def_y); + abort(); + } + + if (players_allied(punit->owner, pdefender->owner)) { + freelog(LOG_FATAL, + "Trying to attack a unit with which you have allience at %i, %i", + def_x, def_y); + abort(); + } + if(unit_flag(punit->type, F_NUCLEAR)) { struct packet_nuke_tile packet; @@ -627,7 +642,7 @@ destroying) a city. -GJW */ if (pwinner == punit && myrand(100) < game.occupychance && - !is_enemy_unit_tile (def_x, def_y, punit->owner)) { + !is_non_allied_unit_tile (map_get_tile(def_x, def_y), punit->owner)) { /* Hack: make sure the unit has enough moves_left for the move to succeed, and adjust moves_left to afterward (if successful). */ @@ -845,7 +860,7 @@ } /*** Try to attack if there is an enemy unit on the target tile ***/ - if (pdefender && pdefender->owner!=punit->owner) { + if (pdefender) { if (!can_unit_attack_tile(punit, dest_x , dest_y)) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, _("Game: You can't attack there.")); @@ -858,6 +873,16 @@ return 0; } + if (pcity && !players_at_war(pcity->owner, punit->owner)) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: Can't attack %s's unit in the city of %s " + "because you are not at war with %s."), + unit_owner(pdefender)->name, + pcity->name, + city_owner(pcity)->name); + return 0; + } + /* DO NOT Auto-attack. Findvictim routine will decide if we should. */ if (pplayer->ai.control && punit->activity == ACTIVITY_GOTO) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, @@ -873,7 +898,7 @@ return 0; } - /* This is for debuging only, and seems to be obsolete as the error message + /* This is for debugging only, and seems to be obsolete as the error message never appears */ if (pplayer->ai.control && punit->ai.passenger) { struct unit *passenger; @@ -892,6 +917,18 @@ return 1; } /* End attack case */ + /* There are no players we are at war with at desttile. But if there is a unit + we have a treaty!=alliance with we can't move there */ + pdefender = is_non_allied_unit_tile(pdesttile, punit->owner); + if (pdefender) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: No war declared against %s, cannot attack."), + game.players[pdefender->owner].name); + return 0; + } + + + { struct unit *bodyguard; if (pplayer->ai.control && @@ -919,12 +956,21 @@ /* If there is a city it is empty. If not it would have been caught in the attack case. */ - if (pcity && - pcity->owner!=punit->owner && - (is_air_unit(punit) || !is_military_unit(punit))) { - notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, - _("Game: Only ground troops can take over a city.")); - return 0; + if(pcity && !players_allied(pcity->owner, punit->owner)) { + if (is_air_unit(punit) || !is_military_unit(punit)) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: Only ground troops can take over " + "a city.")); + return 0; + } + + if (!players_at_war(pcity->owner, punit->owner)) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: No war declared against %s, cannot take " + "over city."), + game.players[pcity->owner].name); + return 0; + } } /******* ok now move the unit *******/ @@ -1093,7 +1139,7 @@ struct player *cplayer; struct city *pnewcity; - if (punit->owner==pcity->owner) + if (!players_at_war(pplayer->player_no, pcity->owner)) return; cplayer = city_owner(pcity); @@ -1329,7 +1375,7 @@ city_refresh(phomecity); send_city_info(get_player(phomecity->owner), phomecity); } - if (pcity && pcity != phomecity) { + if (pcity && pcity != phomecity && pcity->owner == punit->owner) { city_refresh(pcity); send_city_info(get_player(pcity->owner), pcity); } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.c workdir/server/unittools.c --- freeciv/server/unittools.c Wed May 17 17:41:59 2000 +++ workdir/server/unittools.c Thu May 18 00:02:15 2000 @@ -46,126 +46,202 @@ /************************************************************************** unit can be moved if: - 1) the unit is idle or on goto + 1) the unit is idle or on goto or connecting. 2) the target location is on the map 3) the target location is next to the unit - 4) ground unit can only move to ocean squares if there is a transporter - with free capacity - 5) marines are the only units that can attack from a ocean square - 6) naval units can only be moved to ocean squares or city squares - 7) if there is no enemy units blocking (zoc) [or igzoc is true] + 4) there are no non-allied units on the target tile + 5) a ground unit can only move to ocean squares if there + is a transporter with free capacity + 6) marines are the only units that can attack from a ocean square + 7) naval units can only be moved to ocean squares or city squares + 8) there are no peaceful but un-allied units on the target tile + 9) there is not a peaceful but un-allied city on the target tile + 10) there is no non-allied unit blocking (zoc) [or igzoc is true] **************************************************************************/ -int can_unit_move_to_tile(struct unit *punit, int x, int y, int igzoc) +int can_unit_move_to_tile(struct unit *punit, int dest_x, int dest_y, int igzoc) { - struct tile *ptile,*ptile2; + struct tile *pfromtile,*ptotile; int zoc; + struct city *pcity; + int src_x = punit->x; + int src_y = punit->y; - if(punit->activity!=ACTIVITY_IDLE && punit->activity!=ACTIVITY_GOTO && !punit->connecting) + /* 1) */ + if (punit->activity!=ACTIVITY_IDLE + && punit->activity!=ACTIVITY_GOTO + && !punit->connecting) return 0; - - if(x<0 || x>=map.xsize || y<0 || y>=map.ysize) + + /* 2) */ + if (dest_x<0 || dest_x>=map.xsize || dest_y<0 || dest_y>=map.ysize) return 0; - - if(!is_tiles_adjacent(punit->x, punit->y, x, y)) + + /* 3) */ + if (!is_tiles_adjacent(src_x, src_y, dest_x, dest_y)) return 0; - if(is_enemy_unit_tile(x,y,punit->owner)) + pfromtile = map_get_tile(src_x, src_y); + ptotile = map_get_tile(dest_x, dest_y); + + /* 4) */ + if (is_non_allied_unit_tile(ptotile, punit->owner)) return 0; - ptile=map_get_tile(x, y); - ptile2=map_get_tile(punit->x, punit->y); - if(is_ground_unit(punit)) { - /* Check condition 4 */ - if(ptile->terrain==T_OCEAN && - !is_transporter_with_free_space(&game.players[punit->owner], x, y)) - return 0; + if (is_ground_unit(punit)) { + /* 5) */ + if (ptotile->terrain==T_OCEAN && + !is_transporter_with_free_space(unit_owner(punit), dest_x, dest_y)) + return 0; + /* Moving from ocean */ - if(ptile2->terrain==T_OCEAN) { - /* Can't attack a city from ocean unless marines */ - if(!unit_flag(punit->type, F_MARINES) - && is_enemy_city_tile(x,y,punit->owner)) { - char *units_str = get_units_with_flag_string(F_MARINES); - if (units_str) { - notify_player_ex(&game.players[punit->owner], punit->x, punit->y, + if (pfromtile->terrain==T_OCEAN) { + /* 6) */ + if (!unit_flag(punit->type, F_MARINES) + && is_enemy_city_tile(ptotile, punit->owner)) { + char *units_str = get_units_with_flag_string(F_MARINES); + if (units_str) { + notify_player_ex(unit_owner(punit), src_x, src_y, E_NOEVENT, _("Game: Only %s can attack from sea."), units_str); free(units_str); } else { - notify_player_ex(&game.players[punit->owner], punit->x, punit->y, + notify_player_ex(unit_owner(punit), src_x, src_y, E_NOEVENT, _("Game: Cannot attack from sea.")); } return 0; } } - } else if(is_sailing_unit(punit)) { - if(ptile->terrain!=T_OCEAN && ptile->terrain!=T_UNKNOWN) - if(!is_friendly_city_tile(x,y,punit->owner)) - return 0; + } else if (is_sailing_unit(punit)) { + /* 7) */ + if (ptotile->terrain!=T_OCEAN + && ptotile->terrain!=T_UNKNOWN + && !is_allied_city_tile(ptotile, punit->owner)) + return 0; } - zoc = igzoc || zoc_ok_move(punit, x, y); - if (!zoc) - notify_player_ex(&game.players[punit->owner], punit->x, punit->y, E_NOEVENT, + + /* 8) */ + if (is_non_attack_unit_tile(ptotile, punit->owner)) { + notify_player_ex(unit_owner(punit), src_x, src_y, + E_NOEVENT, + _("Game: Cannot attack unless you declare war first.")); + return 0; + } + + /* 9) */ + pcity = ptotile->city; + if (pcity && players_non_attack(pcity->owner, punit->owner)) { + notify_player_ex(unit_owner(punit), src_x, src_y, + E_NOEVENT, + _("Game: Cannot attack unless you declare war first.")); + return 0; + } + + /* 10) */ + zoc = igzoc || zoc_ok_move(punit, dest_x, dest_y); + if (!zoc) { + notify_player_ex(unit_owner(punit), src_x, src_y, E_NOEVENT, _("Game: %s can only move into your own zone of control."), unit_types[punit->type].name); + } + return zoc; } /************************************************************************** is there an enemy city on this tile? **************************************************************************/ -int is_enemy_city_tile(int x, int y, int owner) +struct city *is_enemy_city_tile(struct tile *ptile, int playerid) { - struct city *pcity; + struct city *pcity = ptile->city; - pcity=map_get_city(x,y); + if (pcity && players_at_war(playerid, pcity->owner)) + return pcity; + else + return NULL; +} - if(pcity==NULL) return 0; +/************************************************************************** + is there an friendly city on this tile? +**************************************************************************/ +struct city *is_allied_city_tile(struct tile *ptile, int playerid) +{ + struct city *pcity = ptile->city; - return(pcity->owner != owner); + if (pcity && players_allied(playerid, pcity->owner)) + return pcity; + else + return NULL; } /************************************************************************** - is there an enemy unit on this tile? + is there an enemy city on this tile? **************************************************************************/ -int is_enemy_unit_tile(int x, int y, int owner) +struct city *is_non_attack_city_tile(struct tile *ptile, int playerid) { - struct unit_list *punit_list; - struct unit *punit; - - punit_list=&map_get_tile(x, y)->units; - punit = unit_list_get(punit_list, 0); + struct city *pcity = ptile->city; - if(!punit) return 0; - return(punit->owner != owner); + if (pcity && players_non_attack(playerid, pcity->owner)) + return pcity; + else + return NULL; } /************************************************************************** - is there an friendly unit on this tile? +Returns true if the tile contains an allied unit and only allied units. +(ie, if your nation A is allied with B, and B is allied with C, a tile +containing units from B and C will return false) **************************************************************************/ -int is_friendly_unit_tile(int x, int y, int owner) +struct unit *is_allied_unit_tile(struct tile *ptile, int playerid) { - struct unit_list *punit_list; - struct unit *punit; + struct unit *punit = NULL; - punit_list=&map_get_tile(x, y)->units; - punit = unit_list_get(punit_list, 0); + unit_list_iterate(ptile->units, cunit) + if (players_allied(playerid, cunit->owner)) + punit = cunit; + else + return NULL; + unit_list_iterate_end; - if(!punit) return 0; - return(punit->owner == owner); + return punit; } /************************************************************************** - is there an friendly city on this tile? + is there an enemy unit on this tile? +**************************************************************************/ +struct unit *is_enemy_unit_tile(struct tile *ptile, int playerid) +{ + unit_list_iterate(ptile->units, punit) + if (players_at_war(punit->owner, playerid)) + return punit; + unit_list_iterate_end; + + return NULL; +} + +/************************************************************************** + is there an non-allied unit on this tile? **************************************************************************/ -int is_friendly_city_tile(int x, int y, int owner) +struct unit *is_non_allied_unit_tile(struct tile *ptile, int playerid) { - struct city *pcity; + unit_list_iterate(ptile->units, punit) + if (!players_allied(punit->owner, playerid)) + return punit; + unit_list_iterate_end; - pcity=map_get_city(x,y); + return NULL; +} - if(pcity==NULL) return 0; +/************************************************************************** + is there an unit we have peace or ceasefire with on this tile? +**************************************************************************/ +struct unit *is_non_attack_unit_tile(struct tile *ptile, int playerid) +{ + unit_list_iterate(ptile->units, punit) + if (players_non_attack(punit->owner, playerid)) + return punit; + unit_list_iterate_end; - return(pcity->owner == owner); + return NULL; } /************************************************************************** @@ -188,7 +264,8 @@ for (x=x0-1;xowner)) + if (is_allied_unit_tile(ptotile, punit->owner)) return 1; - if (map_get_city(x1, y1) || map_get_city(x2, y2)) + if (pfromtile->city || is_allied_city_tile(ptotile, punit->owner)) return 1; if (map_get_terrain(x1,y1)==T_OCEAN) return 1; @@ -233,7 +312,6 @@ settlers are half price Plus, the damage to the unit reduces the price. - **************************************************************************/ int unit_bribe_cost(struct unit *punit) { @@ -347,8 +425,8 @@ unit_list_iterate(map_get_tile(x, y)->units, punit) { debug_unit = punit; - if (pplayer->player_no==punit->owner) - return 0; + if (!players_at_war(pplayer->player_no, punit->owner)) + continue; ct++; if (unit_can_defend_here(punit)) { unit_d = rate_unit_d(punit, aunit); @@ -389,7 +467,7 @@ struct unit *bestatt = 0; int bestvalue=-1, unit_a; unit_list_iterate(map_get_tile(x, y)->units, punit) { - if (pplayer->player_no==punit->owner) + if (players_allied(pplayer->player_no, punit->owner)) return 0; unit_a=rate_unit_a(punit, aunit); if(unit_a>bestvalue) { @@ -576,6 +654,7 @@ 2) it's not a fighter and the defender is a flying unit (except city/airbase) 3) if it's not a marine (and ground unit) and it attacks from ocean 4) a ground unit can't attack a ship on an ocean square (except marines) + 5) the players are not at war **************************************************************************/ int can_unit_attack_unit_at_tile(struct unit *punit, struct unit *pdefender, int dest_x, int dest_y) @@ -607,6 +686,10 @@ /* Shore bombardement */ if (fromtile==T_OCEAN && is_sailing_unit(punit) && totile!=T_OCEAN) return (get_attack_power(punit)>0); + + if (!players_at_war(punit->owner, pdefender->owner)) + return 0; + return 1; } @@ -644,8 +727,10 @@ { int i, j, a = 0, d, db; struct player *pplayer = get_player(punit->owner); + struct city *pcity = map_get_tile(x,y)->city; - if (is_friendly_city_tile(x, y, punit->owner)) return 0; + if (pcity && pcity->owner == punit->owner) + return 0; db = get_tile_type(map_get_terrain(x, y))->defense_bonus; if (map_get_special(x, y) & S_RIVER) @@ -656,9 +741,9 @@ for (i = x - 1; i <= x + 1; i++) { if (same_pos(i, j, x, y)) continue; /* after some contemplation */ if (!pplayer->ai.control && !map_get_known_and_seen(x, y, pplayer)) continue; - if (is_enemy_city_tile(i, j, punit->owner)) return 1; + if (is_enemy_city_tile(map_get_tile(i, j), punit->owner)) return 1; unit_list_iterate(map_get_tile(i, j)->units, enemy) - if (enemy->owner != punit->owner && + if (players_at_war(enemy->owner, punit->owner) && can_unit_attack_unit_at_tile(enemy, punit, x, y)) { a += unit_belligerence_basic(enemy); if ((a * a * 10) >= d) return 1; @@ -686,20 +771,6 @@ } /************************************************************************** - Return first unit on square that is not owned by player. - - Kris Bubendorfer -**************************************************************************/ -struct unit *is_enemy_unit_on_tile(int x, int y, int owner) -{ - unit_list_iterate(map_get_tile(x, y)->units, punit) - if (owner!=punit->owner) - return punit; - unit_list_iterate_end; - - return 0; -} - -/************************************************************************** Teleport punit to city at cost specified. Returns success. (If specified cost is -1, then teleportation costs all movement.) - Kris Bubendorfer @@ -746,22 +817,22 @@ void resolve_unit_stack(int x, int y, int verbose) { struct unit *punit, *cunit; + struct tile *ptile = map_get_tile(x,y); - /* We start by reducing the unit list until we only have units from one nation */ + /* We start by reducing the unit list until we only have allied units */ while(1) { struct city *pcity, *ccity; - punit = unit_list_get(&map_get_tile(x, y)->units, 0); + punit = unit_list_get(&(ptile->units), 0); if (!punit) return; - pcity = find_closest_owned_city(get_player(punit->owner), x, y, + pcity = find_closest_owned_city(unit_owner(punit), x, y, is_sailing_unit(punit), NULL); /* If punit is in an enemy city we send it to the closest friendly city This is not always caught by the other checks which require that there are units from two nations on the tile */ - ccity = map_get_city(x,y); - if (ccity && ccity->owner != punit->owner) { + if (ptile->city && !is_allied_city_tile(ptile, punit->owner)) { if (pcity) teleport_unit_to_city(punit, pcity, 0, verbose); else @@ -769,7 +840,7 @@ continue; } - cunit = is_enemy_unit_on_tile(x, y, punit->owner); + cunit = is_non_allied_unit_tile(ptile, punit->owner); if (!cunit) break; @@ -810,26 +881,28 @@ } } /* end while */ - /* There is only one player's units left on this square. If there is not + /* There is only one allied units left on this square. If there is not enough transporter capacity left send surplus to the closest friendly city. */ - punit = unit_list_get(&map_get_tile(x, y)->units, 0); + punit = unit_list_get(&(ptile->units), 0); - if(punit && map_get_terrain(x, y) == T_OCEAN) { - while(ground_unit_transporter_capacity(x, y, punit->owner) < 0) { - unit_list_iterate(map_get_tile(x, y)->units, vunit) { - if(is_ground_unit(vunit)) { - struct city *vcity = - find_closest_owned_city(get_player(vunit->owner), x, y, 0, NULL); - if (vcity) - teleport_unit_to_city(vunit, vcity, 0, verbose); - else - disband_stack_conflict_unit(vunit, verbose); - break; /* break out of unit_list_iterate loop */ - } + if (ptile->terrain == T_OCEAN) { + START: + unit_list_iterate(ptile->units, vunit) { + if (ground_unit_transporter_capacity(x, y, punit->owner) < 0) { + unit_list_iterate(ptile->units, wunit) { + if (is_ground_unit(wunit) && wunit->owner == vunit->owner) { + struct city *wcity = + find_closest_owned_city(get_player(wunit->owner), x, y, 0, NULL); + if (wcity) + teleport_unit_to_city(wunit, wcity, 0, verbose); + else + disband_stack_conflict_unit(wunit, verbose); + goto START; + } + } unit_list_iterate_end; /* End of find a unit from that player to disband*/ } - unit_list_iterate_end; - } + } unit_list_iterate_end; /* End of find a player */ } } @@ -841,9 +914,10 @@ { struct player_tile *plrtile = map_get_player_tile(&game.players[playerid],x,y); - if (is_friendly_city_tile(x, y, playerid) + if ((is_allied_city_tile(map_get_tile(x, y), playerid) + && !is_non_allied_unit_tile(map_get_tile(x, y), playerid)) || (plrtile->special&S_AIRBASE - && !is_enemy_unit_tile(x, y, playerid))) + && !is_non_allied_unit_tile(map_get_tile(x, y), playerid))) return 1; if (unit_flag(type, F_MISSILE)) { @@ -857,6 +931,4 @@ cap++; return cap>0; } - - return 0; } diff -Nur -X/home/thue/freeciv-dev/freeciv/diff_ignore freeciv/server/unittools.h workdir/server/unittools.h --- freeciv/server/unittools.h Wed May 17 17:41:59 2000 +++ workdir/server/unittools.h Wed May 17 19:43:25 2000 @@ -17,11 +17,14 @@ struct player; struct unit; -int can_unit_move_to_tile(struct unit *punit, int x, int y, int igzoc); -int is_enemy_city_tile(int x, int y, int owner); -int is_friendly_city_tile(int x, int y, int owner); -int is_enemy_unit_tile(int x, int y, int owner); -int is_friendly_unit_tile(int x, int y, int owner); +int can_unit_move_to_tile(struct unit *punit, int dest_x, int dest_y, int igzoc); +struct city *is_enemy_city_tile(struct tile *ptile, int playerid); +struct city *is_allied_city_tile(struct tile *ptile, int playerid); +struct city *is_non_attack_city_tile(struct tile *ptile, int playerid); +struct unit *is_allied_unit_tile(struct tile *ptile, int playerid); +struct unit *is_enemy_unit_tile(struct tile *ptile, int playerid); +struct unit *is_non_allied_unit_tile(struct tile *ptile, int playerid); +struct unit *is_non_attack_unit_tile(struct tile *ptile, int playerid); int is_my_zoc(struct unit *myunit, int x0, int y0); int zoc_ok_move(struct unit *punit,int x, int y); int zoc_ok_move_gen(struct unit *punit, int x1, int y1, int x2, int y2); @@ -53,7 +56,6 @@ int enemies_at(struct unit *punit, int x, int y); int teleport_unit_to_city(struct unit *punit, struct city *pcity, int move_cost, int verbose); -struct unit *is_enemy_unit_on_tile(int x, int y, int owner); void resolve_unit_stack(int x, int y, int verbose); int is_airunit_refuel_point(int x, int y, int playerid, Unit_Type_id type, int unit_is_on_tile);