Complete.Org: Mailing Lists: Archives: freeciv-dev: May 2003:
[Freeciv-Dev] Re: (PR#4328) Disallow attacking tiles with not-at-war uni
Home

[Freeciv-Dev] Re: (PR#4328) Disallow attacking tiles with not-at-war uni

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: per@xxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#4328) Disallow attacking tiles with not-at-war units
From: "Gregory Berkolaiko" <Gregory.Berkolaiko@xxxxxxxxxxxx>
Date: Sat, 31 May 2003 09:45:20 -0700
Reply-to: rt@xxxxxxxxxxxxxx

Some alterations done to Per's patch:

On Fri, 30 May 2003, Per I. Mathisen wrote:

> This patch
>  1) Moves can_unit_attack_unit_at_tile() from server to common.

Also move can_unit_attack_tile

>  2) Does some style changes to said function.

Much more style changes (major clean I would say)

>  3) Adds check to said function and handle_unit_move_request() to disallow
> a unit from attacking a tile that contains any unit that we are not at war
> with.

Such check is written as a separate function in common.  I didn't change 
much in handle_unit_move_request though, as this function is a pandora box 
and should be cleaned asap!

G.

? ai/aisettler.c
? ai/aisettler.h
? ai/aiunit.cy
? common/aicore/citymap.c
? common/aicore/citymap.h
Index: common/combat.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v
retrieving revision 1.30
diff -u -r1.30 combat.c
--- common/combat.c     2003/05/06 08:13:21     1.30
+++ common/combat.c     2003/05/31 16:36:35
@@ -26,6 +26,121 @@
 #include "combat.h"
 
 /***********************************************************************
+  Checks if player is restricted diplomatically from attacking the tile.
+  Returns FLASE if
+  1) the tile is empty or
+  2) the tile contains a non-enemy city or
+  3) the tile contains a non-enemy unit
+***********************************************************************/
+bool can_player_attack_tile(struct player *pplayer, int x, int y)
+{
+  struct city *pcity = map_get_city(x, y);
+  struct tile *ptile = map_get_tile(x, y);
+  
+  /* 1. Is there anyone there at all? */
+  if (!pcity && unit_list_size(&(ptile->units)) == 0) {
+    return FALSE;
+  }
+
+  /* 2. If there is a city there, can we attack it? */
+  if (pcity && !pplayers_at_war(city_owner(pcity), pplayer)) {
+    return FALSE;
+  }
+
+  /* 3. Are we allowed to attack _all_ cities there? */
+  unit_list_iterate(ptile->units, aunit) {
+    if (!pplayers_at_war(unit_owner(aunit), pplayer)) {
+      /* Enemy hiding behind a human/diplomatic shield */
+      return FALSE;
+    }
+  } unit_list_iterate_end;
+
+  return TRUE;
+}
+
+/***********************************************************************
+  Checks if a unit can physically attack pdefender at the tile 
+  (assuming it is adjacent and at war).
+
+  Unit can NOT attack if:
+  1) it does not have any attack power.
+  2) it is not a fighter and defender is a flying unit (except city/airbase).
+  3) it is a ground unit without marine ability and it attacks from ocean.
+  4) it is a ground unit and it attacks a target on an ocean square.
+  5) it is a sailing unit without shore bombardment capability and it
+     attempts to attack land.
+
+  Does NOT check:
+  1) Moves left
+  2) Adjacency
+  3) Diplomatic status
+***********************************************************************/
+bool can_unit_attack_unit_at_tile(struct unit *punit, struct unit *pdefender,
+                                  int dest_x, int dest_y)
+{
+  enum tile_terrain_type fromtile;
+  enum tile_terrain_type totile;
+  struct city *pcity = map_get_city(dest_x, dest_y);
+
+  fromtile = map_get_terrain(punit->x, punit->y);
+  totile   = map_get_terrain(dest_x, dest_y);
+
+  /* 1. Can we attack _anything_ ? */
+  if (!is_military_unit(punit) || unit_type(punit)->attack_strength == 0) {
+    return FALSE;
+  }
+
+  /* 2. Only fighters can attack planes, except in city or airbase attacks */
+  if (!unit_flag(punit, F_FIGHTER) && is_air_unit(pdefender)
+      && !(pcity || map_has_special(dest_x, dest_y, S_AIRBASE))) {
+    return FALSE;
+  }
+
+  /* 3. Can't attack with ground unit from ocean, except for marines */
+  if (is_ocean(fromtile)
+      && is_ground_unit(punit)
+      && !unit_flag(punit, F_MARINES)) {
+    return FALSE;
+  }
+
+  /* 4. Ground units cannot attack water units */
+  if (is_ocean(totile) && is_ground_unit(punit)) {
+    return FALSE;
+  }
+
+  /* 5. Shore bombardement can be done by certain units only */
+  if (unit_flag(punit, F_NO_LAND_ATTACK) && !is_ocean(totile)) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+/***********************************************************************
+  Is unit (1) diplomatically allowed to attack and (2) physically able
+  to do so?
+
+  FIXME: Will need to check if can physically attack every unit in the
+  target tile in the future (layers etc).
+***********************************************************************/
+bool can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y)
+{
+  struct unit *pdefender;
+
+  if (!can_player_attack_tile(unit_owner(punit), dest_x, dest_y)) {
+    return FALSE;
+  }
+
+  pdefender = get_defender(punit, dest_x, dest_y);
+  if (!pdefender) {
+    /* It must be the empty city! */
+    return TRUE;
+  }
+
+  return can_unit_attack_unit_at_tile(punit, pdefender, dest_x, dest_y);
+}
+
+/***********************************************************************
 Returns the chance of the attacker winning, a number between 0 and 1.
 If you want the chance that the defender wins just use 1-chance(...)
 
Index: common/combat.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/combat.h,v
retrieving revision 1.8
diff -u -r1.8 combat.h
--- common/combat.h     2003/05/06 08:13:21     1.8
+++ common/combat.h     2003/05/31 16:36:35
@@ -26,6 +26,11 @@
 struct unit;
 struct player;
 
+bool can_player_attack_tile(struct player *pplayer, int x, int y);
+bool can_unit_attack_unit_at_tile(struct unit *punit, struct unit *pdefender,
+                                  int dest_x, int dest_y);
+bool can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y);
+
 double win_chance(int as, int ahp, int afp, int ds, int dhp, int dfp);
 
 void get_modified_firepower(struct unit *attacker, struct unit *defender,
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.259
diff -u -r1.259 unithand.c
--- server/unithand.c   2003/05/06 08:13:21     1.259
+++ server/unithand.c   2003/05/31 16:36:35
@@ -923,6 +923,8 @@
   'move_diplomat_city' is another special case which should normally be
   FALSE.  If TRUE, try to move diplomat (or spy) into city (should be
   allied) instead of telling client to popup diplomat/spy dialog.
+
+  FIXME: This function needs a good cleaning.
 **************************************************************************/
 bool handle_unit_move_request(struct unit *punit, int dest_x, int dest_y,
                             bool igzoc, bool move_diplomat_city)
@@ -1010,8 +1012,23 @@
       how_to_declare_war(pplayer);
       return FALSE;
     }
+
+    /* Tile must contain ONLY enemy units. */
+    unit_list_iterate(pdesttile->units, aunit) {
+      if (!pplayers_at_war(unit_owner(aunit), unit_owner(punit))) {
+        notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
+                        _("Game: Can't attack %s's unit since it is "
+                          "stacked with %s's unit(s) and you are not "
+                           "at war with %s."), 
+                         unit_owner(pdefender)->name,
+                         unit_owner(aunit)->name, 
+                         unit_owner(aunit)->name);
+        how_to_declare_war(pplayer);
+        return FALSE;
+      }
+    } unit_list_iterate_end;
 
-    if (!can_unit_attack_tile(punit, dest_x , dest_y)) {
+    if (!can_unit_attack_unit_at_tile(punit, pdefender, dest_x , dest_y)) {
       notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT,
                       _("Game: You can't attack there."));
       return FALSE;
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.224
diff -u -r1.224 unittools.c
--- server/unittools.c  2003/05/30 18:17:01     1.224
+++ server/unittools.c  2003/05/31 16:36:35
@@ -104,87 +104,6 @@
 }
 
 /**************************************************************************
- Unit can not attack if:
- 1) it does not have any attack power.
- 2) it is not a fighter and defender is a flying unit (except city/airbase).
- 3) it is a ground unit without marine ability and it attacks from ocean.
- 4) it is a ground unit and it attacks a ship on an ocean square.
- 5) the players are not at war.
- 6) a city there is owned by non-attack player
-
- Does NOT check:
- 1) Moves left
- 2) Adjacency
-**************************************************************************/
-bool can_unit_attack_unit_at_tile(struct unit *punit, struct unit *pdefender,
-                                  int dest_x, int dest_y)
-{
-  enum tile_terrain_type fromtile;
-  enum tile_terrain_type totile;
-  struct city *pcity = map_get_city(dest_x, dest_y);
-
-  fromtile = map_get_terrain(punit->x, punit->y);
-  totile   = map_get_terrain(dest_x, dest_y);
-
-  if (!is_military_unit(punit) || unit_type(punit)->attack_strength == 0) {
-    return FALSE;
-  }
-
-  /* only fighters can attack planes, except for city or airbase attacks */
-  if (!unit_flag(punit, F_FIGHTER) && is_air_unit(pdefender) &&
-      !(map_get_city(dest_x, dest_y) || map_has_special(dest_x, dest_y, 
S_AIRBASE))) {
-    return FALSE;
-  }
-  /* can't attack with ground unit from ocean, except for marines */
-  if (is_ocean(fromtile)
-      && is_ground_unit(punit)
-      && !unit_flag(punit, F_MARINES)) {
-    return FALSE;
-  }
-
-  if (is_ocean(totile) && is_ground_unit(punit)) {
-    return FALSE;
-  }
-
-  if (unit_flag(punit, F_NO_LAND_ATTACK) && !is_ocean(totile)) {
-    return FALSE;
-  }
-  
-  if (!pplayers_at_war(unit_owner(punit), unit_owner(pdefender)))
-    return FALSE;
-
-  /* Shore bombardement */
-  if (is_ocean(fromtile) && is_sailing_unit(punit) && !is_ocean(totile)) {
-    return (get_attack_power(punit)>0);
-  }
-
-  if (pcity && !pplayers_at_war(city_owner(pcity), unit_owner(punit))) {
-    return FALSE;
-  }
-
-  return TRUE;
-}
-
-/**************************************************************************
-...
-**************************************************************************/
-bool can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y)
-{
-  struct unit *pdefender;
-  pdefender=get_defender(punit, dest_x, dest_y);
-  if (!pdefender) {
-    struct city *pcity = map_get_city(dest_x, dest_y);
-    if (pcity && pplayers_at_war(city_owner(pcity), unit_owner(punit))) {
-      /* empty city, yummy! */
-      return TRUE;
-    }
-    /* nothing to attack */
-    return FALSE;
-  }
-  return(can_unit_attack_unit_at_tile(punit, pdefender, dest_x, dest_y));
-}
-
-/**************************************************************************
   after a battle this routine is called to decide whether or not the unit
   should become a veteran, if unit isn't already.
   there is a 50/50% chance for it to happend, (100% if player got SUNTZU)
Index: server/unittools.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.h,v
retrieving revision 1.50
diff -u -r1.50 unittools.h
--- server/unittools.h  2003/05/06 05:06:07     1.50
+++ server/unittools.h  2003/05/31 16:36:35
@@ -23,8 +23,6 @@
 
 /* battle related */
 int find_a_unit_type(int role, int role_tech);
-bool can_unit_attack_unit_at_tile(struct unit *punit, struct unit *pdefender, 
int dest_x, int dest_y);
-bool can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y);
 void maybe_make_veteran(struct unit *punit);
 void unit_versus_unit(struct unit *attacker, struct unit *defender);
 

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