Complete.Org: Mailing Lists: Archives: freeciv-dev: April 2005:
[Freeciv-Dev] Re: (PR#12781) Create AI guard API
Home

[Freeciv-Dev] Re: (PR#12781) Create AI guard API

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] Re: (PR#12781) Create AI guard API
From: "Benedict Adamson" <badamson@xxxxxxxxxxx>
Date: Wed, 13 Apr 2005 15:51:40 -0700
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12781 >

Here is an initial version of the API. This has not been properly 
tested: I'm posting it to get feedback rather than have it committed.

diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/Makefile.am freeciv.PR12781/ai/Makefile.am
--- vendor.freeciv.current/ai/Makefile.am       2005-01-24 20:43:05.000000000 
+0000
+++ freeciv.PR12781/ai/Makefile.am      2005-04-13 23:54:53.000000000 +0100
@@ -25,6 +25,8 @@
                aiexplorer.h    \
                aiferry.c       \
                aiferry.h       \
+               aiguard.c       \
+               aiguard.h       \
                aihand.c        \
                aihand.h        \
                aihunt.c        \
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aiferry.c freeciv.PR12781/ai/aiferry.c
--- vendor.freeciv.current/ai/aiferry.c 2005-04-05 22:40:45.000000000 +0100
+++ freeciv.PR12781/ai/aiferry.c        2005-04-13 23:54:53.000000000 +0100
@@ -27,6 +27,7 @@
 #include "unittools.h"
 
 #include "aidata.h"
+#include "aiguard.h"
 #include "aiexplorer.h"
 #include "ailog.h"
 #include "aitools.h"
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aiguard.c freeciv.PR12781/ai/aiguard.c
--- vendor.freeciv.current/ai/aiguard.c 1970-01-01 01:00:00.000000000 +0100
+++ freeciv.PR12781/ai/aiguard.c        2005-04-13 23:54:53.000000000 +0100
@@ -0,0 +1,219 @@
+/********************************************************************** 
+ Freeciv - Copyright (C) 2004 - The Freeciv Project
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "log.h"
+#include "unit.h"
+
+#include "ailog.h"
+#include "aitools.h"
+
+#include "aiguard.h"
+
+
+
+/**************************************************************************
+  Do sanity checks on a guard, reporting error messages to the log
+  if necessary.
+**************************************************************************/
+void aiguard_check_guard(const struct unit *guard)
+{
+  const struct unit *charge_unit = find_unit_by_id(guard->ai.charge);
+  const struct city *charge_city = find_city_by_id(guard->ai.charge);
+  assert(BODYGUARD_NONE <= guard->ai.charge);
+  if (charge_unit && charge_unit->ai.bodyguard == BODYGUARD_WANTED
+      && charge_unit->tile != guard->tile) {
+    BODYGUARD_LOG(LOG_VERBOSE, (struct unit *)guard,
+                 "guard probably en route to charge");
+  } else if (charge_unit && charge_unit->ai.bodyguard == BODYGUARD_WANTED) {
+    BODYGUARD_LOG(LOG_ERROR, (struct unit *)guard,
+                 "guard unknown to co-located charge");
+  } else if (charge_unit && charge_unit->ai.bodyguard != guard->id) {
+    BODYGUARD_LOG(LOG_VERBOSE, (struct unit *)guard,
+                 "inconsistent guard references");
+  } else if (!charge_unit && !charge_city && 0 < guard->ai.charge) {
+    BODYGUARD_LOG(LOG_ERROR, (struct unit *)guard,
+                 "dangling guard reference");
+  }
+}
+
+/**************************************************************************
+  Do sanity checks on a charge, reporting error messages to the log
+  if necessary.
+**************************************************************************/
+void aiguard_check_charge_unit(const struct unit *charge)
+{
+  struct unit *guard = find_unit_by_id(charge->ai.bodyguard);
+  assert(BODYGUARD_WANTED <= guard->ai.bodyguard);
+  if (guard && guard->ai.charge != charge->id) {
+    UNIT_LOG(LOG_ERROR, (struct unit *)charge,
+            "inconsistent guard references");
+  }
+}
+
+/**************************************************************************
+  Remove the assignment of a charge to a guard.
+**************************************************************************/
+void aiguard_clear_charge(struct unit *guard)
+{
+  struct unit *charge_unit = find_unit_by_id(guard->ai.charge);
+  struct city *charge_city = find_city_by_id(guard->ai.charge);
+  CHECK_GUARD(guard);
+  if (charge_unit) {
+    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "unassigned");
+    /* Our previous charge will have to look for a new body guard */
+    aiguard_request_guard(charge_unit);
+  } else if (charge_city) {
+    BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "unassigned");
+  }
+  /* else not assigned or charge was destroyed */
+  guard->ai.charge = BODYGUARD_NONE;
+}
+
+/**************************************************************************
+  Remove assignment of bodyguard for a unit.
+**************************************************************************/
+void aiguard_clear_guard(struct unit *charge)
+{
+  CHECK_CHARGE_UNIT(charge);
+  if (0 < charge->ai.bodyguard) {
+    struct unit *guard = find_unit_by_id(charge->ai.bodyguard);
+
+    if (guard && guard->ai.charge == charge->id) {
+      /* charge doesn't want us anymore */
+      guard->ai.charge = BODYGUARD_NONE;
+    }
+  }
+
+  charge->ai.bodyguard = BODYGUARD_NONE;
+}
+
+/**************************************************************************
+  Assign a bodyguard to a unit.
+**************************************************************************/
+void aiguard_assign_guard_unit(struct unit *charge, struct unit *guard)
+{
+  assert(charge);
+  assert(guard);
+  assert(guard != charge);
+  /* Usually, same_pos(charge->tile, guard->tile),
+   * but that need not be so. */
+
+  CHECK_GUARD(guard);
+  CHECK_GUARD(charge);
+  /* Remove previous assignment: */
+  aiguard_clear_charge(guard);
+  aiguard_clear_guard(charge);
+
+  ai_unit_new_role(guard, AIUNIT_ESCORT, charge->tile);
+  guard->ai.charge = charge->id;
+  charge->ai.bodyguard = guard->id;
+  BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "assigned charge");
+}
+
+/**************************************************************************
+  Assign a guard to a city.
+  Use this function rather than simply setting the unit role to
+  AIUNIT_DEFEND_HOME.
+**************************************************************************/
+void aiguard_assign_guard_city(struct city *charge, struct unit *guard)
+{
+  enum ai_unit_task task;
+  assert(charge);
+  assert(guard);
+  CHECK_GUARD(guard);
+
+  if (guard->ai.charge != charge->id) {
+    /* Remove previous assignment: */
+    aiguard_clear_charge(guard);
+  }
+
+  if (guard->tile == charge->tile && guard->homecity != charge->id
+      && guard->owner == charge->owner) {
+    /* Try to rationalise home city assignments;
+     * may fail. */
+    (void) ai_unit_make_homecity(guard, charge);
+  }
+  if (guard->homecity == charge->id) {
+    task = AIUNIT_DEFEND_HOME;
+  } else {
+    task = AIUNIT_ESCORT;
+  }
+  ai_unit_new_role(guard, task, charge->tile);
+  guard->ai.charge = charge->id;
+  BODYGUARD_LOG(LOGLEVEL_BODYGUARD, guard, "assigned charge");
+}
+
+/**************************************************************************
+  Request a (new) bodyguard for the unit.
+**************************************************************************/
+void aiguard_request_guard(struct unit *punit)
+{
+  CHECK_CHARGE_UNIT(punit);
+  /* Remove previous assignment */
+  aiguard_clear_guard(punit);
+
+  UNIT_LOG(LOGLEVEL_BODYGUARD, punit, "requests a guard");
+  punit->ai.bodyguard = BODYGUARD_WANTED;
+}
+
+/**************************************************************************
+  Has a unit requested a guard and not (yet) been provided with one?
+**************************************************************************/
+bool aiguard_wanted(struct unit *charge)
+{
+  CHECK_CHARGE_UNIT(charge);
+  return charge->ai.bodyguard == BODYGUARD_WANTED;
+}
+
+/**************************************************************************
+  Has a (guard) unit been assigned a charge?
+**************************************************************************/
+bool aiguard_has_charge(struct unit *guard)
+{
+  CHECK_GUARD(guard);
+  return guard->ai.bodyguard != BODYGUARD_NONE;
+}
+
+/**************************************************************************
+  Which unit, if any, is the body guard of a unit?
+  Returns NULL if the unit has not been assigned a guard.
+**************************************************************************/
+struct unit *aiguard_guard_of(struct unit *charge)
+{
+  CHECK_CHARGE_UNIT(charge);
+  return find_unit_by_id(charge->ai.bodyguard);
+}
+
+/**************************************************************************
+  Which unit (if any) has a guard been assigned to.
+  Returns NULL if the unit is not the guard for a unit.
+**************************************************************************/
+struct unit *aiguard_charge_unit(struct unit *guard)
+{
+  CHECK_GUARD(guard);
+  return find_unit_by_id(guard->ai.charge);
+}
+
+/**************************************************************************
+  Which city (if any) has a guard been assigned to.
+  Returns NULL if the unit is not a guard for a city.
+**************************************************************************/
+struct city *aiguard_charge_city(struct unit *guard)
+{
+  CHECK_GUARD(guard);
+  return find_city_by_id(guard->ai.charge);
+}
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aiguard.h freeciv.PR12781/ai/aiguard.h
--- vendor.freeciv.current/ai/aiguard.h 1970-01-01 01:00:00.000000000 +0100
+++ freeciv.PR12781/ai/aiguard.h        2005-04-13 23:54:53.000000000 +0100
@@ -0,0 +1,58 @@
+/********************************************************************** 
+ Freeciv - Copyright (C) 2002 - The Freeciv Project
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+***********************************************************************/
+#ifndef FC__AIGUARD_H
+#define FC__AIGUARD_H
+
+#include "shared.h"            /* bool type */
+
+#include "fc_types.h"
+
+#ifndef NDEBUG
+#define CHECK_GUARD(guard) aiguard_check_guard(guard)
+#define CHECK_CHARGE_UNIT(charge) aiguard_check_charge_unit(charge)
+#else
+#define CHECK_GUARD(guard) {}
+#define CHECK_CHARGE_UNIT(charge) {}
+#endif
+
+
+enum bodyguard_enum {
+  BODYGUARD_WANTED = -1,
+  BODYGUARD_NONE
+};
+
+void aiguard_check_guard(const struct unit *guard);
+
+void aiguard_check_charge_unit(const struct unit *charge);
+
+void aiguard_clear_charge(struct unit *guard);
+
+void aiguard_clear_guard(struct unit *charge);
+
+void aiguard_assign_guard_unit(struct unit *charge, struct unit *guard);
+
+void aiguard_assign_guard_city(struct city *charge, struct unit *guard);
+
+void aiguard_request_guard(struct unit *punit);
+
+bool aiguard_wanted(struct unit *charge);
+
+bool aiguard_has_charge(struct unit *charge);
+
+struct unit *aiguard_guard_of(struct unit *charge);
+
+struct unit *aiguard_charge_unit(struct unit *guard);
+
+struct city *aiguard_charge_city(struct unit *guard);
+
+#endif /* FC__AIGUARD_H */
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/ailog.c freeciv.PR12781/ai/ailog.c
--- vendor.freeciv.current/ai/ailog.c   2005-04-12 20:48:41.000000000 +0100
+++ freeciv.PR12781/ai/ailog.c  2005-04-13 23:54:53.000000000 +0100
@@ -221,7 +221,8 @@
   struct unit *pcharge;
   struct city *pcity;
   int id = -1;
-  struct tile *ptile = NULL;
+  int charge_x = -1;
+  int charge_y = -1;
   const char *s = "none";
 
   if (punit->debug) {
@@ -233,19 +234,23 @@
   pcity = find_city_by_id(punit->ai.charge);
   pcharge = find_unit_by_id(punit->ai.charge);
   if (pcharge) {
-    ptile = pcharge->tile;
+    charge_x = pcharge->tile->x;
+    charge_y = pcharge->tile->y;
     id = pcharge->id;
     s = unit_type(pcharge)->name;
   } else if (pcity) {
-    ptile = pcity->tile;
+    charge_x = pcity->tile->x;
+    charge_y = pcity->tile->y;
     id = pcity->id;
     s = pcity->name;
   }
+  /* else perhaps the charge died */
+
   my_snprintf(buffer, sizeof(buffer),
               "%s's bodyguard %s[%d] (%d,%d){%s:%d@%d,%d} ",
               unit_owner(punit)->name, unit_type(punit)->name,
               punit->id, punit->tile->x, punit->tile->y,
-             s, id, ptile->x, ptile->y);
+             s, id, charge_x, charge_y);
   cat_snprintf(buffer, sizeof(buffer), msg);
   if (punit->debug) {
     notify_conn(game.est_connections, buffer);
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aitools.c freeciv.PR12781/ai/aitools.c
--- vendor.freeciv.current/ai/aitools.c 2005-04-12 20:48:41.000000000 +0100
+++ freeciv.PR12781/ai/aitools.c        2005-04-13 23:54:53.000000000 +0100
@@ -50,6 +50,7 @@
 #include "aicity.h"
 #include "aidata.h"
 #include "aiferry.h"
+#include "aiguard.h"
 #include "ailog.h"
 #include "aitech.h"
 #include "aiunit.h"
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aitools.h freeciv.PR12781/ai/aitools.h
--- vendor.freeciv.current/ai/aitools.h 2005-04-05 22:40:45.000000000 +0100
+++ freeciv.PR12781/ai/aitools.h        2005-04-13 23:54:53.000000000 +0100
@@ -40,11 +40,6 @@
 #define CHECK_UNIT(punit) assert(TRUE)
 #endif
 
-enum bodyguard_enum {
-  BODYGUARD_WANTED=-1,
-  BODYGUARD_NONE
-};
-
 /*
  * Initialise using ai_avoid_risks()
  */
diff -ruN -Xvendor.freeciv.current/diff_ignore 
vendor.freeciv.current/ai/aiunit.c freeciv.PR12781/ai/aiunit.c
--- vendor.freeciv.current/ai/aiunit.c  2005-04-12 20:48:41.000000000 +0100
+++ freeciv.PR12781/ai/aiunit.c 2005-04-13 23:54:53.000000000 +0100
@@ -54,6 +54,7 @@
 #include "aidiplomat.h"
 #include "aiexplorer.h"
 #include "aiferry.h"
+#include "aiguard.h"
 #include "aihand.h"
 #include "aihunt.h"
 #include "ailog.h"
@@ -734,6 +735,7 @@
   struct tile *ptile;
 
   CHECK_UNIT(punit);
+  CHECK_GUARD(punit);
 
   if (aunit && aunit->owner == punit->owner) {
     /* protect a unit */
@@ -1009,6 +1011,12 @@
       ai_unit_new_role(punit, AIUNIT_ESCORT, aunit->tile);
       punit->ai.charge = aunit->id;
       BODYGUARD_LOG(LOG_DEBUG, punit, "going to defend unit");
+      /* FIXME: There is nothing to prevent many guards choosing the same
+       * unit to defend, so swarms of potential guards can converge
+       * on a unit. */
+      /* FIXME: At some point (when we arrive at the tile of the charge?)
+       * we should set aunit->ai.bodyguard to punit->id.
+       * That seems *never* to happen, which is a bug */
     }
   }
   TIMING_LOG(AIT_BODYGUARD, TIMER_STOP);

[Prev in Thread] Current Thread [Next in Thread]