Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] (PR#4202) No more allied-allied-war v2
Home

[Freeciv-Dev] (PR#4202) No more allied-allied-war v2

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: a-l@xxxxxxx
Subject: [Freeciv-Dev] (PR#4202) No more allied-allied-war v2
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Wed, 28 May 2003 14:05:41 -0700
Reply-to: rt@xxxxxxxxxxxxxx

This is an updated version of the "forbid alliance with an ally of my
enemy" patch. It fixes some bugs and adds sanity detection on savegame
load. Also attached are two savegames to prove that the patch works as
intended.

Arnstein's request that there be some way to figure out who is allied to
whom is more than reasonable. This information is already sent to the
client (if we have embassy). Can client authors add this information to
the intelligence dialog?

I think this patch is ready to go in. Please have a look at it, people.
This is one of the things I need resolved before I can make a new version
of the AI diplomacy patch.

  - Per

Attachment: allywithallyofenemy.sav.gz
Description: allywithallyofenemy.sav.gz

Attachment: allallied.sav.gz
Description: allallied.sav.gz

? acconfig.h
? aigovtfixp1.diff
? aigovtfixp2.diff
? aigovtfixp3.diff
? alliedtrans3.diff
? configure.old2
? emergency1.diff
? intlbugfix1.diff
? llh1.diff
? llh2.diff
? measureai1.diff
? moreintl3.diff
? moreintl4.diff
? moreintl5.diff
? nationrestrict8.diff
? nlist2s.diff
? test.serv
? union1.diff
? data/perrin
? data/strange
Index: common/connection.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/connection.h,v
retrieving revision 1.29
diff -u -r1.29 connection.h
--- common/connection.h 12 Apr 2003 18:24:42 -0000      1.29
+++ common/connection.h 28 May 2003 20:55:53 -0000
@@ -15,6 +15,9 @@
 
 #include <time.h>      /* time_t */
 
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
Index: common/diptreaty.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/diptreaty.h,v
retrieving revision 1.11
diff -u -r1.11 diptreaty.h
--- common/diptreaty.h  15 May 2003 15:16:07 -0000      1.11
+++ common/diptreaty.h  28 May 2003 20:55:53 -0000
@@ -18,7 +18,7 @@
 enum clause_type { CLAUSE_ADVANCE, CLAUSE_GOLD, CLAUSE_MAP,
                   CLAUSE_SEAMAP, CLAUSE_CITY, 
                   CLAUSE_CEASEFIRE, CLAUSE_PEACE, CLAUSE_ALLIANCE,
-                  CLAUSE_VISION};
+                  CLAUSE_VISION, CLAUSE_LAST };
 
 #define is_pact_clause(x) \
   ((x == CLAUSE_CEASEFIRE) || (x == CLAUSE_PEACE) || (x == CLAUSE_ALLIANCE))
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.117
diff -u -r1.117 player.c
--- common/player.c     18 Apr 2003 10:08:53 -0000      1.117
+++ common/player.c     28 May 2003 20:55:53 -0000
@@ -36,6 +36,29 @@
 #include "player.h"
 
 /***************************************************************
+  Returns true iff p1 can ally p2. There is only one condition:
+  We are not at war with any of p2's allies. Note that for an
+  alliance to be made, we need to check this both ways.
+
+  The reason for this is to avoid the dread 'love-love-hate' 
+  triad, in which p1 is allied to p2 is allied to p3 is at
+  war with p1. These lead to strange situations.
+***************************************************************/
+bool pplayer_can_ally(struct player *p1, struct player *p2)
+{
+  players_iterate(pplayer) {
+    if (pplayer != p1
+        && pplayer != p2
+        && pplayers_allied(p2, pplayer)
+        && pplayers_at_war(p1, pplayer)
+        && pplayer->is_alive) {
+      return FALSE;
+    }
+  } players_iterate_end;
+  return TRUE;
+}
+
+/***************************************************************
   Check if pplayer has an embassy with pplayer2. We always have
   an embassy with ourselves.
 ***************************************************************/
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.99
diff -u -r1.99 player.h
--- common/player.h     15 May 2003 12:26:52 -0000      1.99
+++ common/player.h     28 May 2003 20:55:53 -0000
@@ -257,6 +257,8 @@
                                                     *pplayer,
                                                     const struct player
                                                     *pplayer2);
+
+bool pplayer_can_ally(struct player *p1, struct player *p2);
 bool pplayers_at_war(const struct player *pplayer,
                    const struct player *pplayer2);
 bool pplayers_allied(const struct player *pplayer,
Index: server/diplhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v
retrieving revision 1.69
diff -u -r1.69 diplhand.c
--- server/diplhand.c   30 Apr 2003 21:14:35 -0000      1.69
+++ server/diplhand.c   28 May 2003 20:55:54 -0000
@@ -181,6 +181,15 @@
            return;
          }
          break;
+       case CLAUSE_ALLIANCE:
+          if (!pplayer_can_ally(pplayer, other)) {
+           notify_player(pplayer,
+                         _("Game: You are at war with one of %s's "
+                           "allies - an alliance with %s is impossible."),
+                         other->name, other->name);
+            return;
+          }
+          break;
        case CLAUSE_GOLD:
          if (pplayer->economic.gold < pclause->value) {
            notify_player(pplayer,
@@ -263,6 +272,19 @@
            goto cleanup;
          }
          break;
+       case CLAUSE_ALLIANCE:
+          if (!pplayer_can_ally(other, pplayer)) {
+           notify_player(pplayer,
+                         _("Game: %s is at war with one of your "
+                           "allies - an alliance with %s is impossible."),
+                         other->name, other->name);
+           notify_player(other,
+                         _("Game: You are at war with one of %s's "
+                           "allies - an alliance with %s is impossible."),
+                         pplayer->name, pplayer->name);
+           goto cleanup;
+          }
+          break;
        case CLAUSE_GOLD:
          if (other->economic.gold < pclause->value) {
            notify_player(plr0,
@@ -397,6 +419,9 @@
                         _("Game: %s gives you shared vision."),
                         pgiver->name);
        break;
+      case CLAUSE_LAST:
+        freelog(LOG_ERROR, "Received bad clause type");
+        break;
       }
 
     } clause_list_iterate_end;
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.274
diff -u -r1.274 plrhand.c
--- server/plrhand.c    15 May 2003 16:02:00 -0000      1.274
+++ server/plrhand.c    28 May 2003 20:55:54 -0000
@@ -800,6 +800,12 @@
 
 /**************************************************************************
   Handles a player cancelling a "pact" with another player.
+
+  packet.id is id of player we want to cancel a pact with
+  packet.val1 is a special value indicating what kind of treaty we want
+    to break. If this is CLAUSE_VISION we break shared vision. If it is
+    a pact treaty type, we break one pact level. If it is CLAUSE_LAST
+    we break _all_ treaties and go straight to war.
 **************************************************************************/
 void handle_player_cancel_pact(struct player *pplayer,
                                struct packet_generic_values *packet)
@@ -808,7 +814,7 @@
   enum diplstate_type new_type;
   struct player *pplayer2;
   int reppenalty = 0;
-  bool has_senate;
+  bool has_senate, repeat = FALSE;
   int other_player = packet->id;
   int clause = packet->value1;
 
@@ -842,9 +848,11 @@
 
   /* else, breaking a treaty */
 
+repeat_break_treaty:
   /* check what the new status will be, and what will happen to our
      reputation */
   switch(old_type) {
+  case DS_NO_CONTACT: /* possible if someone declares war on our ally */
   case DS_NEUTRAL:
     new_type = DS_WAR;
     reppenalty = 0;
@@ -869,10 +877,11 @@
   /* if there's a reason to cancel the pact, do it without penalty */
   if (pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel > 0) {
     pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel = 0;
-    if (has_senate)
+    if (has_senate && !repeat) {
       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
@@ -882,7 +891,7 @@
     pplayer->reputation = MAX(pplayer->reputation - reppenalty, 0);
     notify_player(pplayer, _("Game: Your reputation is now %s."),
                  reputation_text(pplayer->reputation));
-    if (has_senate) {
+    if (has_senate && pplayer->revolution == 0) {
       if (myrand(GAME_MAX_REPUTATION) > pplayer->reputation) {
        notify_player(pplayer, _("Game: The senate decides to dissolve "
                                 "rather than support your actions any 
longer."));
@@ -899,6 +908,15 @@
     pplayer2->diplstates[pplayer->player_no].turns_left =
     16;
 
+  /* We want to go all the way to war, whatever the cost! 
+   * This is only used when declaring war against an alliance 
+   * and by the AI. */
+  if (clause == CLAUSE_LAST && new_type != DS_WAR) {
+    repeat = TRUE;
+    old_type = new_type;
+    goto repeat_break_treaty;
+  }
+
   send_player_info(pplayer, NULL);
   send_player_info(pplayer2, NULL);
 
@@ -928,6 +946,22 @@
                   get_nation_name_plural(pplayer2->nation),
                   get_nation_name_plural(pplayer->nation),
                   diplstate_text(new_type));
+
+  /* Check fall-out of a war declaration. */
+  players_iterate(other) {
+    if (other->is_alive && other != pplayer && other != pplayer2
+        && (pplayer->team == TEAM_NONE || pplayer->team != pplayer2->team)
+        && new_type == DS_WAR && pplayers_allied(pplayer2, other)
+        && !pplayers_at_war(pplayer, other)) {
+      struct packet_generic_values packet;
+
+      /* A declaration of war by A against B also means A declares
+       * war against all of B's allies. Yes, A gets the blame. */
+      packet.id = other->player_no;
+      packet.value1 = CLAUSE_LAST;
+      handle_player_cancel_pact(pplayer, &packet);
+    }
+  } players_iterate_end;
 }
 
 /**************************************************************************
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.117
diff -u -r1.117 savegame.c
--- server/savegame.c   15 May 2003 12:26:53 -0000      1.117
+++ server/savegame.c   28 May 2003 20:55:54 -0000
@@ -719,7 +719,18 @@
     secfile_lookup_int_default(file, 0,
                           "player%d.diplstate%d.contact_turns_left", plrno, i);
   }
-  
+  /* Sanity check alliances, prevent allied-with-ally-of-enemy */
+  players_iterate(aplayer) {
+    if (pplayers_allied(plr, aplayer)
+        && !pplayer_can_ally(plr, aplayer)) {
+      freelog(LOG_ERROR, "Illegal alliance structure detected: "
+              "%s's alliance to %s reduced to peace treaty.",
+              plr->name, aplayer->name);
+      plr->diplstates[aplayer->player_no].type = DS_PEACE;
+      aplayer->diplstates[plr->player_no].type = DS_PEACE;
+    }
+  } players_iterate_end;
+
   { /* spacerace */
     struct player_spaceship *ship = &plr->spaceship;
     char prefix[32];

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#4202) No more allied-allied-war v2, Per I. Mathisen <=