diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/client/gui-xaw/diplodlg.c pacts/client/gui-xaw/diplodlg.c --- freeciv/client/gui-xaw/diplodlg.c Wed Apr 12 17:10:57 2000 +++ pacts/client/gui-xaw/diplodlg.c Wed Apr 12 17:13:06 2000 @@ -77,6 +77,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 +121,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 +467,26 @@ XtNlabel, buf, NULL); + pdialog->dip_pact_menubutton=XtVaCreateManagedWidget("dippactmenubutton", + menuButtonWidgetClass, + pdialog->dip_form0, + NULL); + popupmenu=XtVaCreatePopupShell("menu", + simpleMenuWidgetClass, + pdialog->dip_pact_menubutton, + NULL); + entry=XtVaCreateManagedWidget(_("Ceasefire"), 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" @@ -618,6 +645,18 @@ _("The %s give their seamap"), get_nation_name_plural(pclause->from->nation)); break; + case CLAUSE_CEASEFIRE: + sprintf(pdialog->clauselist_strings[i], + _("The parties agree on a ceasefire")); + break; + case CLAUSE_PEACE: + sprintf(pdialog->clauselist_strings[i], + _("The parties agree on peace")); + break; + case CLAUSE_ALLIANCE: + sprintf(pdialog->clauselist_strings[i], + _("The parties create an alliance")); + break; } pdialog->clauselist_strings_ptrs[i]=pdialog->clauselist_strings[i]; i++; @@ -766,6 +805,62 @@ send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_CREATE_CLAUSE, &pa); } + +/**************************************************************** +Generic add-a-clause function for adding pact types +*****************************************************************/ +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 ceasefire widget was selected; add a ceasefire 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/no.freeciv freeciv/client/gui-xaw/plrdlg.c pacts/client/gui-xaw/plrdlg.c --- freeciv/client/gui-xaw/plrdlg.c Wed Apr 12 17:10:57 2000 +++ pacts/client/gui-xaw/plrdlg.c Wed Apr 12 19:29:49 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]; + struct player_pact pact; 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,41 @@ } 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 pact type and turns -- not applicable if this is me */ + if (i == game.player_idx) { + strcpy(pactbuf, "-"); + } else { + pact = player_get_pact(game.player_idx, i); + if (pact.type == PACT_CEASEFIRE) { + my_snprintf(pactbuf, sizeof(pactbuf), "%s (%d)", + pact_type_text(pact.type), pact.turns_left); + } else { + my_snprintf(pactbuf, sizeof(pactbuf), "%s", + pact_type_text(pact.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 %-14s %-13s %-6s %-15s%s", namebuf, get_nation_name(game.players[i].nation), player_has_embassy(game.player_ptr, &game.players[i]) ? 'X':' ', + pactbuf, + repbuf, statebuf, game.players[i].addr, idlebuf); @@ -238,6 +279,13 @@ else XtSetSensitive(players_sship_command, FALSE); + if(pplayer->is_alive) { + if (players_at_war(game.player_idx, ret->list_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/no.freeciv freeciv/client/options.c pacts/client/options.c --- freeciv/client/options.c Wed Apr 12 17:10:55 2000 +++ pacts/client/options.c Wed Apr 12 17:12:33 2000 @@ -106,6 +106,8 @@ N_("Unit Attack Succeeded "), /* E_UNIT_WIN_ATT */ N_("Suggest Growth Throttling"), /* E_CITY_GRAN_THROTTLE */ N_("Spaceship Events "), /* E_SPACESHIP */ + N_("Pact Cancelled "), /* E_CANCEL_PACT */ + N_("Diplomatic Incident "), /* E_INCIDENT */ N_("Barbarian Uprising "), /* E_UPRISING */ N_("Worklist Events "), /* E_WORKLIST */ }; diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/client/packhand.c pacts/client/packhand.c --- freeciv/client/packhand.c Wed Apr 12 17:10:55 2000 +++ pacts/client/packhand.c Wed Apr 12 17:12:39 2000 @@ -703,6 +703,15 @@ pplayer->embassy=pinfo->embassy; pplayer->city_style=pinfo->city_style; + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + pplayer->pacts[i].type = + pinfo->pact_types[i]; + pplayer->pacts[i].turns_left = + pinfo->pact_turns_left[i]; + pplayer->pacts[i].has_reason_to_cancel = + pinfo->pact_has_reason_to_cancel[i]; + } + for (i = 0; i < MAX_NUM_WORKLISTS; i++) copy_worklist(&pplayer->worklists[i], &pinfo->worklists[i]); diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/capstr.c pacts/common/capstr.c --- freeciv/common/capstr.c Wed Apr 12 17:10:58 2000 +++ pacts/common/capstr.c Wed Apr 12 20:06:48 2000 @@ -70,9 +70,12 @@ * are not directly related to the capability strings discussed here.) */ -#define CAPABILITY "+1.10 +fog_of_war +fortify_two_step +get_sabotage_list" +#define CAPABILITY "+1.10 +fog_of_war +fortify_two_step +get_sabotage_list pacts" /* "+1.10" is protocol for 1.10.0 stable release + + "pacts" is for servers and clients that understand alliances, + ceasefires, and what-have-you. "fog_of_war" is protocol extension for Fog of War. diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/diptreaty.c pacts/common/diptreaty.c --- freeciv/common/diptreaty.c Wed Apr 12 17:10:58 2000 +++ pacts/common/diptreaty.c Wed Apr 12 17:13:37 2000 @@ -65,6 +65,10 @@ /**************************************************************** ... *****************************************************************/ + +#define alliance_clause(x) \ + ((x == CLAUSE_CEASEFIRE) || (x == CLAUSE_PEACE) || (x == CLAUSE_ALLIANCE)) + int add_clause(struct Treaty *ptreaty, struct player *pfrom, enum clause_type type, int val) { @@ -88,6 +92,14 @@ ptreaty->accept0=0; ptreaty->accept1=0; pclause->value=val; + return 1; + } + if(alliance_clause(type) && + alliance_clause(pclause->type)) { + /* alliance clause already there */ + ptreaty->accept0=0; + ptreaty->accept1=0; + pclause->type=type; return 1; } } diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/diptreaty.h pacts/common/diptreaty.h --- freeciv/common/diptreaty.h Wed Apr 12 17:10:58 2000 +++ pacts/common/diptreaty.h Wed Apr 12 17:13:45 2000 @@ -16,7 +16,8 @@ #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 }; struct Clause { enum clause_type type; diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/events.h pacts/common/events.h --- freeciv/common/events.h Wed Apr 12 17:10:58 2000 +++ pacts/common/events.h Wed Apr 12 17:13:54 2000 @@ -49,6 +49,8 @@ E_UNIT_WIN_ATT, E_CITY_GRAN_THROTTLE, E_SPACESHIP, + E_CANCEL_PACT, + E_INCIDENT, E_UPRISING, E_WORKLIST, /* Note: If you add a new event, make sure you make a similar change to diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/game.h pacts/common/game.h --- freeciv/common/game.h Wed Apr 12 17:10:58 2000 +++ pacts/common/game.h Wed Apr 12 17:13:58 2000 @@ -294,6 +294,8 @@ #define GAME_DEFAULT_DEMOGRAPHY "NASRLPEMOqrb" +#define GAME_DEFAULT_REPUTATION 50 + #define GAME_START_YEAR -4000 #endif /* FC__GAME_H */ diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/packets.c pacts/common/packets.c --- freeciv/common/packets.c Wed Apr 12 17:10:58 2000 +++ pacts/common/packets.c Wed Apr 12 17:14:04 2000 @@ -235,6 +235,7 @@ case PACKET_CITY_REFRESH: case PACKET_INCITE_INQ: case PACKET_CITY_NAME_SUGGEST_REQ: + case PACKET_PLAYER_CANCEL_PACT: return receive_packet_generic_integer(pc); case PACKET_ALLOC_NATION: @@ -1299,6 +1300,7 @@ cptr=put_uint8(buffer+2, PACKET_PLAYER_INFO); cptr=put_uint8(cptr, pinfo->playerno); 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,6 +1310,16 @@ cptr=put_uint16(cptr, pinfo->nturns_idle); cptr=put_uint8(cptr, pinfo->is_alive?1:0); + if (pc && has_capability("pacts", pc->capability)) { + int i; + cptr=put_uint32(cptr, pinfo->reputation); + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + cptr=put_uint32(cptr, pinfo->pact_types[i]); + cptr=put_uint32(cptr, pinfo->pact_turns_left[i]); + cptr=put_uint32(cptr, pinfo->pact_has_reason_to_cancel[i]); + } + } + cptr=put_uint32(cptr, pinfo->gold); cptr=put_uint8(cptr, pinfo->tax); cptr=put_uint8(cptr, pinfo->science); @@ -1316,6 +1328,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); @@ -1353,6 +1366,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); @@ -1362,6 +1376,22 @@ iget_uint16(&iter, &pinfo->nturns_idle); iget_uint8(&iter, &pinfo->is_alive); + if (pc && has_capability("pacts", pc->capability)) { + int i; + iget_uint32(&iter, &pinfo->reputation); + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + iget_uint32(&iter, &pinfo->pact_types[i]); + iget_uint32(&iter, &pinfo->pact_turns_left[i]); + iget_uint32(&iter, &pinfo->pact_has_reason_to_cancel[i]); + } + } else { + int i; + pinfo->reputation = -1; + for (i = 0; i < MAX_NUM_PLAYERS; i++) { + pinfo->pact_types[i] = PACT_NO_CAPABILITY; + } + } + iget_uint32(&iter, &pinfo->gold); iget_uint8(&iter, &pinfo->tax); iget_uint8(&iter, &pinfo->science); diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/packets.h pacts/common/packets.h --- freeciv/common/packets.h Wed Apr 12 17:10:58 2000 +++ pacts/common/packets.h Wed Apr 12 17:14:11 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, @@ -407,6 +408,10 @@ int nation; int turn_done, nturns_idle; int is_alive; + int reputation; + int pact_types[MAX_NUM_PLAYERS]; + int pact_turns_left[MAX_NUM_PLAYERS]; + int pact_has_reason_to_cancel[MAX_NUM_PLAYERS]; int gold, tax, science, luxury; int researched; int researchpoints; diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/common/player.c pacts/common/player.c --- freeciv/common/player.c Wed Apr 12 17:10:58 2000 +++ pacts/common/player.c Wed Apr 12 17:14:16 2000 @@ -17,6 +17,7 @@ #include "city.h" #include "game.h" #include "government.h" +#include "log.h" #include "map.h" #include "rand.h" #include "shared.h" @@ -68,6 +69,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->pacts[i].type = PACT_NEUTRAL; + plr->pacts[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; @@ -392,9 +398,110 @@ } /************************************************************************** +Return a reputation level as a human-readable string +**************************************************************************/ +const char *reputation_text(const int rep) +{ + if (rep == -1) + return "-"; + else if (rep > 90) + return "Spotless"; + else if (rep > 75) + return "Excellent"; + else if (rep > 60) + return "Honourable"; + else if (rep > 45) + return "Questionable"; + else if (rep > 30) + return "Dishonourable"; + else if (rep > 15) + return "Poor"; + else if (rep > 7) + return "Despicable"; + else + return "Atrocious"; +} + +/************************************************************************** +Return a pact type as a human-readable string +**************************************************************************/ +static char *pact_names[PACT_NUM] = +{ + "-", + "Neutral", + "War", + "Ceasefire", + "Peace", + "Alliance" +}; + +const char *pact_type_text(const enum pact_type type) +{ + if (type < PACT_NUM) + return pact_names[type]; + freelog(LOG_FATAL, "Odd pact type: %d", type); + exit(0); +} + +/*************************************************************** +returns pact type between two players +***************************************************************/ +struct player_pact pplayer_get_pact(const struct player *pplayer, + const struct player *pplayer2) +{ + return pplayer->pacts[pplayer2->player_no]; +} + +struct player_pact player_get_pact(const int player, const int player2) +{ + return pplayer_get_pact(&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 "pacts" +capability, so anyone can beat on them; this is for backward +compatibility with non-pact-speaking clients. +***************************************************************/ +int pplayers_at_war(const struct player *pplayer, + const struct player *pplayer2) +{ + enum pact_type pt = pplayer_get_pact(pplayer, pplayer2).type; + if (pplayer == pplayer2) return 0; + if (is_barbarian(pplayer) || is_barbarian(pplayer2)) + return TRUE; + return ((pt == PACT_WAR) || + (pt == PACT_NEUTRAL) || + (pt == PACT_NO_CAPABILITY)); +} + +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 pact_type pt = pplayer_get_pact(pplayer, pplayer2).type; + if (is_barbarian(pplayer) || is_barbarian(pplayer2)) + return FALSE; + return ((pplayer == pplayer2) || (pt == PACT_ALLIANCE)); +} + +int players_allied(const int player, const int player2) +{ + return pplayers_allied(&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/no.freeciv freeciv/common/player.h pacts/common/player.h --- freeciv/common/player.h Wed Apr 12 17:10:59 2000 +++ pacts/common/player.h Wed Apr 12 17:14:21 2000 @@ -97,6 +97,17 @@ int is_barbarian; }; +enum pact_type { + PACT_NO_CAPABILITY = 0, PACT_NEUTRAL, PACT_WAR, PACT_CEASEFIRE, + PACT_PEACE, PACT_ALLIANCE, PACT_NUM +}; + +struct player_pact { + enum pact_type type; + int turns_left; /* until ceasefire 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 +144,8 @@ int revolution; int capital; /* bool used to give player capital in first city. */ int embassy; + int reputation; + struct player_pact pacts[MAX_NUM_PLAYERS]; int city_style; struct unit_list units; struct city_list cities; @@ -175,9 +188,23 @@ 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 *pact_type_text(const enum pact_type type); + +/* we have an int in some contexts, a pointer in others. Yuk! */ +struct player_pact pplayer_get_pact(const struct player *pplayer, + const struct player *pplayer2); +struct player_pact player_get_pact(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); + 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/no.freeciv freeciv/data/Freeciv pacts/data/Freeciv --- freeciv/data/Freeciv Wed Apr 12 17:10:51 2000 +++ pacts/data/Freeciv Wed Apr 12 17:14:28 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 Pact 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/no.freeciv freeciv/server/cityturn.c pacts/server/cityturn.c --- freeciv/server/cityturn.c Wed Apr 12 17:11:08 2000 +++ pacts/server/cityturn.c Wed Apr 12 17:14:34 2000 @@ -1379,7 +1379,7 @@ if(unit_list_size(&ptile->units)>0) { struct unit *punit=unit_list_get(&ptile->units, 0); - if(pplayer->player_no!=punit->owner) { + if(!players_allied(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); diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/civserver.c pacts/server/civserver.c --- freeciv/server/civserver.c Wed Apr 12 17:11:08 2000 +++ pacts/server/civserver.c Wed Apr 12 17:14:39 2000 @@ -753,6 +753,40 @@ } /************************************************************************** + check for ceasefires running out; update reputation; update cancelling + reasons +**************************************************************************/ +void update_diplomatics() +{ + int p, p2; + + for(p = 0; p < game.nplayers; p++) { + for(p2 = 0; p2 < game.nplayers; p2++) { + game.players[p].pacts[p2].has_reason_to_cancel = + MAX(game.players[p].pacts[p2].has_reason_to_cancel - 1, 0); + + if(game.players[p].pacts[p2].type == PACT_CEASEFIRE) { + switch(--game.players[p].pacts[p2].turns_left) { + case 1: + notify_player(&game.players[p], _("Game: Concerned citizens point " + "out that the ceasefire with %s will run out soon."), + game.players[p2].name); + break; + case -1: + notify_player(&game.players[p], _("Game: The ceasefire 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].pacts[p2].type = PACT_NEUTRAL; + break; + } + } + game.players[p].reputation = MIN(game.players[p].reputation + 1, 100); + } + } +} + +/************************************************************************** ... **************************************************************************/ static void before_end_year(void) @@ -825,6 +859,7 @@ send_player_cities(&game.players[i]); } update_pollution(); + update_diplomatics(); do_apollo_program(); make_history_report(); freelog(LOG_DEBUG, "Turn ended."); @@ -1112,6 +1147,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/no.freeciv freeciv/server/diplhand.c pacts/server/diplhand.c --- freeciv/server/diplhand.c Wed Apr 12 17:11:08 2000 +++ pacts/server/diplhand.c Wed Apr 12 17:14:44 2000 @@ -199,6 +199,33 @@ } break; } + case CLAUSE_CEASEFIRE: + pgiver->pacts[pdest->player_no].type=PACT_CEASEFIRE; + pgiver->pacts[pdest->player_no].turns_left=16; + pdest->pacts[pgiver->player_no].type=PACT_CEASEFIRE; + pdest->pacts[pgiver->player_no].turns_left=16; + notify_player(pgiver, _("Game: You agree on a ceasefire with %s."), + pdest->name); + notify_player(pdest, _("Game: You agree on a ceasefire with %s."), + pgiver->name); + break; + case CLAUSE_PEACE: + pgiver->pacts[pdest->player_no].type=PACT_PEACE; + pdest->pacts[pgiver->player_no].type=PACT_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->pacts[pdest->player_no].type=PACT_ALLIANCE; + pdest->pacts[pgiver->player_no].type=PACT_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/no.freeciv freeciv/server/gamehand.c pacts/server/gamehand.c --- freeciv/server/gamehand.c Wed Apr 12 17:11:08 2000 +++ pacts/server/gamehand.c Wed Apr 12 17:14:48 2000 @@ -44,7 +44,7 @@ extern char metaserver_addr[]; #define SAVEFILE_OPTIONS "1.7 startoptions unirandom spacerace2 rulesets \ -diplchance_percent" +diplchance_percent pacts" /************************************************************************** ... diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/plrhand.c pacts/server/plrhand.c --- freeciv/server/plrhand.c Wed Apr 12 17:11:08 2000 +++ pacts/server/plrhand.c Wed Apr 12 20:26:12 2000 @@ -1758,9 +1758,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, @@ -1788,6 +1786,107 @@ } /************************************************************************** + ... +**************************************************************************/ +void handle_player_cancel_pact(struct player *pplayer, int other_player) +{ + enum pact_type old_type = pplayer->pacts[other_player].type, new_type; + struct player *pplayer2 = &game.players[other_player]; + int reppenalty = 0; + 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 PACT_NEUTRAL: + new_type = PACT_WAR; + break; + case PACT_CEASEFIRE: + new_type = PACT_WAR; + reppenalty = 10; + break; + case PACT_PEACE: + new_type = PACT_WAR; + reppenalty = 20; + break; + case PACT_ALLIANCE: + new_type = PACT_PEACE; + reppenalty = 20; + break; + default: + notify_player(pplayer, _("Game: There's no pact with the %s to break."), + get_nation_name_plural(pplayer2->nation)); + return; + } + + /* if there's a reason to cancel the pact, do it without penalty */ + if (pplayer->pacts[pplayer2->player_no].has_reason_to_cancel) { + pplayer->pacts[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 the penalty (and maybe suffer a + revolution) */ + /* XXX 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(100) > 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->pacts[pplayer2->player_no].type = + pplayer2->pacts[pplayer->player_no].type = + new_type; + pplayer->pacts[pplayer2->player_no].turns_left = + pplayer2->pacts[pplayer->player_no].turns_left = + 16; + + send_player_info(pplayer, 0); + send_player_info(pplayer2, 0); + + if (old_type == PACT_ALLIANCE) { + unit_list_iterate(pplayer->units, punit) + resolve_unit_stack(punit->x, punit->y, 1); + unit_list_iterate_end; + + unit_list_iterate(pplayer2->units, punit) + resolve_unit_stack(punit->x, punit->y, 1); + unit_list_iterate_end; + } + + notify_player(pplayer, + _("Game: There's now %s between the %s and the %s."), + pact_type_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, + pact_type_text(new_type), + get_nation_name_plural(pplayer2->nation), + get_nation_name_plural(pplayer->nation)); +} + +/************************************************************************** ... **************************************************************************/ @@ -1920,6 +2019,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; ipacts[i].type = + secfile_lookup_int_default(file, PACT_NEUTRAL, + "player%d.pact%d.type", plrno, i); + plr->pacts[i].turns_left = + secfile_lookup_int_default(file, 0, + "player%d.pact%d.turns_left", plrno, i); + plr->pacts[i].has_reason_to_cancel = + secfile_lookup_int_default(file, 0, + "player%d.pact%d.has_reason_to_cancel", + plrno, i); + } if (has_capability("spacerace", savefile_options)) { struct player_spaceship *ship = &plr->spaceship; @@ -2514,6 +2636,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->pacts[i].type, + "player%d.pact%d.type", plrno, i); + secfile_insert_int(file, plr->pacts[i].turns_left, + "player%d.pact%d.turns_left", plrno, i); + secfile_insert_int(file, plr->pacts[i].has_reason_to_cancel, + "player%d.pact%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/no.freeciv freeciv/server/plrhand.h pacts/server/plrhand.h --- freeciv/server/plrhand.h Wed Apr 12 17:11:08 2000 +++ pacts/server/plrhand.h Wed Apr 12 17:14:55 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/no.freeciv freeciv/server/unitfunc.c pacts/server/unitfunc.c --- freeciv/server/unitfunc.c Wed Apr 12 17:11:08 2000 +++ pacts/server/unitfunc.c Wed Apr 12 17:14:59 2000 @@ -351,13 +351,32 @@ /* Now lets see if the spy survives. */ diplomat_escape (pplayer, pdiplomat, NULL); + + /** this may cause a diplomatic incident */ + if (government_has_flag(get_gov_pplayer(pplayer), G_HAS_SENATE) && + pplayers_at_war(pplayer, uplayer) && + (myrand(100) - pplayer->reputation > 50 - uplayer->reputation)) { + notify_player_ex(pplayer, pvictim->x, pvictim->y, E_INCIDENT, + _("Game: You have caused an incident while bribing " + "%s's %s."), + uplayer->name, + unit_name(pvictim->type)); + notify_player_ex(uplayer, pvictim->x, pvictim->y, E_INCIDENT, + _("Game: %s has caused an incident while bribing " + "your %s."), + pplayer->name, + unit_name(pvictim->type)); + pplayer->reputation = MAX(pplayer->reputation - 5, 0); + uplayer->pacts[pplayer->player_no].has_reason_to_cancel = 2; + send_player_info(pplayer, 0); + send_player_info(uplayer, 0); + } } /****************************************************************************** Bribe an enemy unit. - Either a Diplomat or Spy can bribe an enemy unit. - - Can't bribe a unit if: - Owner runs an unbribable government (e.g., democracy). - Player doesn't have enough money. @@ -1772,8 +1791,6 @@ punit->activity_count = 0; do_unit_goto (pplayer, punit, get_activity_move_restriction(activity)); } - - /* if connecting, automagically build prerequisities first */ if (punit->connecting && activity == ACTIVITY_RAILROAD && diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unithand.c pacts/server/unithand.c --- freeciv/server/unithand.c Wed Apr 12 17:11:09 2000 +++ pacts/server/unithand.c Wed Apr 12 18:44:56 2000 @@ -836,7 +836,7 @@ pdefender=get_defender(pplayer, punit, dest_x, dest_y); - if(pdefender && pdefender->owner!=punit->owner) { + if(pdefender && !players_allied(pdefender->owner, punit->owner)) { if(can_unit_attack_tile(punit,dest_x , dest_y)) { if(punit->moves_left<=0) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, @@ -847,6 +847,11 @@ notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, _("Game: Aborting GOTO for AI attack procedures.")); return 0; + } else if (!players_at_war(punit->owner, pdefender->owner)) { + 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; } else { if (pplayer->ai.control && punit->ai.passenger) { /* still trying to track down this weird bug. I can't find anything in @@ -904,11 +909,19 @@ int src_x, src_y; if((pcity=map_get_city(dest_x, dest_y))) { - if (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 (!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; + } else 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; + } } } @@ -1152,7 +1165,7 @@ struct player *cplayer; struct city *pnewcity; - if(pplayer->player_no==pcity->owner) + if (!players_at_war(pplayer->player_no, pcity->owner)) return; cplayer=city_owner(pcity); diff -Nur -X/home/thue/freeciv-dev/no.freeciv freeciv/server/unittools.c pacts/server/unittools.c --- freeciv/server/unittools.c Wed Apr 12 17:11:09 2000 +++ pacts/server/unittools.c Wed Apr 12 17:48:43 2000 @@ -122,7 +122,7 @@ if(pcity==NULL) return 0; - return(pcity->owner != owner); + return(players_at_war(pcity->owner, owner)); } /************************************************************************** @@ -137,7 +137,7 @@ punit = unit_list_get(punit_list, 0); if(!punit) return 0; - return(punit->owner != owner); + return(players_at_war(punit->owner, owner)); } /************************************************************************** @@ -152,7 +152,7 @@ punit = unit_list_get(punit_list, 0); if(!punit) return 0; - return(punit->owner == owner); + return(players_allied(punit->owner, owner)); } /************************************************************************** @@ -166,7 +166,7 @@ if(pcity==NULL) return 0; - return(pcity->owner == owner); + return(players_allied(pcity->owner, owner)); } /************************************************************************** @@ -348,7 +348,7 @@ unit_list_iterate(map_get_tile(x, y)->units, punit) { debug_unit = punit; - if (pplayer->player_no==punit->owner) + if (players_allied(pplayer->player_no, punit->owner)) return 0; ct++; if (unit_can_defend_here(punit)) { @@ -390,7 +390,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) { @@ -659,7 +659,7 @@ if (!pplayer->ai.control && !map_get_known_and_seen(x, y, pplayer)) continue; if (is_enemy_city_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; @@ -677,11 +677,10 @@ - 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) + if (!players_allied(owner, punit->owner)) return punit; unit_list_iterate_end;