[freeciv-ai] Re: paratroopers
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<<< text/html; charset=unknown-8bit: Unrecognized >>>
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore
freeciv-cvs-Feb-27/ai/advmilitary.c
freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c
--- freeciv-cvs-Feb-27/ai/advmilitary.c 2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/advmilitary.c 2004-03-18
02:37:15.000000000 +0100
@@ -35,6 +35,7 @@
#include "aidiplomat.h"
#include "aihand.h"
#include "ailog.h"
+#include "aiparatrooper.h"
#include "aitools.h"
#include "aiunit.h"
@@ -1306,6 +1307,9 @@
/* Consider making an airplane */
(void) ai_choose_attacker_air(pplayer, pcity, choice);
+ /* Consider making a paratrooper */
+ ai_choose_paratrooper(pplayer, pcity, choice);
+
/* Check if we want a sailing attacker. Have to put sailing first
before we mung the seamap */
unit_type = ai_choose_attacker(pcity, SEA_MOVING);
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore
freeciv-cvs-Feb-27/ai/aiparatrooper.c
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c
--- freeciv-cvs-Feb-27/ai/aiparatrooper.c 1970-01-01 01:00:00.000000000
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.c 2004-04-05
16:37:53.000000000 +0200
@@ -0,0 +1,389 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+ 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 <assert.h>
+
+#include "city.h"
+#include "citytools.h"
+#include "log.h"
+#include "pf_tools.h"
+#include "player.h"
+#include "unit.h"
+#include "unittools.h"
+
+#include "ailog.h"
+#include "aiparatrooper.h"
+#include "aiunit.h"
+#include "aitools.h"
+
+#define LOGLEVEL_PARATROOPER LOG_NORMAL
+
+/**********************************************************************
+ Find own city to go there to recover and paradroop.
+
+ TODO: Actually check how safe the city is. This is a difficult
+ decision not easily taken, since we also want to protect unsafe
+ cities, at least most of the time.
+**********************************************************************/
+static struct city *find_nearest_own_city_at(struct player *pplayer,
+ int x, int y)
+{ int best = 0, cur = 100;
+ int continent = map_get_continent(x, y);
+ struct city *acity = NULL;
+
+ city_list_iterate(pplayer->cities, pcity) {
+ cur = real_map_distance(pcity->x, pcity->y, x ,y);
+ if (city_got_building(pcity, B_BARRACKS)
+ || city_got_building(pcity, B_BARRACKS2)
+ || city_got_building(pcity, B_BARRACKS3)) {
+ cur /= 3;
+ }
+ if (continent != map_get_continent(pcity->x, pcity->y)) {
+ /* it must be in the same continent */
+ cur = 0;
+ }
+ if (cur < best && (cur > 0) ) {
+ best = cur;
+ acity = pcity;
+ }
+ } city_list_iterate_end;
+
+ return acity;
+}
+
+/**********************************************************************
+ This function does manage the paratrooper units of the AI.
+ 1st.- checks for cities left alone without defenders
+ 2nd.- checks for enemy cities left alone
+ 3th.- checks for enemy units in range
+**********************************************************************/
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit)
+{
+ struct city *pcity = map_get_city(punit->x, punit->y);
+ struct city *acity = NULL;
+ int sanity = punit->id;
+ int x_dest = 0, y_dest = 0, best = 0;
+
+ CHECK_UNIT(punit);
+
+ /* defend attacking (and be opportunistic too)*/
+ if (!ai_military_rampage(punit, RAMPAGE_ANYTHING,
+ RAMPAGE_FREE_CITY_OR_BETTER)) {
+ /* dead */
+ return;
+ }
+
+ /* check to recover hit points */
+ if ((punit->hp < unit_type(punit)->hp) && pcity) {
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "recovering hit points.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ return;
+ }
+
+ /* nothing to do! */
+ if (punit->moves_left == 0) {
+ return;
+ }
+
+ /* we must defend the city! */
+ if (stay_and_defend(punit)) {
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "defending the city.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ return;
+ }
+
+ if (can_unit_paradrop(punit)) {
+ /* unit can paradrop, so use it! */
+ int range = unit_type(punit)->paratroopers_range;
+
+ /* first, we search for undefended cities in danger */
+ square_iterate(punit->x, punit->y, range, x, y) {
+ acity = map_get_city(x,y);
+ if ((acity) && (city_owner(acity) == pplayer) &&
+ (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+ /* own city and empty! */
+ if ((acity->size * acity->ai.urgency) > best) {
+ best = acity->size * acity->ai.urgency;
+ x_dest = acity->x; y_dest = acity->y;
+ }
+ }
+ } square_iterate_end;
+
+ /* second, we search for undefended enemy cities near us */
+ if (best == 0) {
+ square_iterate(punit->x, punit->y, range, x, y) {
+ acity = map_get_city(x,y);
+ if ((acity) && pplayers_at_war(pplayer, city_owner(acity)) &&
+ (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+ /* enemy empty city! */
+ if (acity->size > best) {
+ best = acity->size;
+ x_dest = acity->x; y_dest = acity->y;
+ }
+ }
+ } square_iterate_end;
+ }
+
+ /* third, we search for enemy units near us,
+ if we don't find any own empty city */
+ if (best == 0) {
+ square_iterate(punit->x, punit->y, range, x, y) {
+ struct tile *ptile = map_get_tile(x, y);
+ if (unit_list_size(&(ptile->units)) > 0) {
+ struct unit *pdef = unit_list_get(&ptile->units, 0);
+ if (pplayers_at_war(pplayer, unit_owner(pdef))) {
+ int benefit = stack_cost(pdef);
+ benefit = (benefit * punit->hp) / unit_type(punit)->hp;
+ if (benefit > best) {
+ /* best enemy unit to kill! */
+ best = benefit;
+ x_dest = x; y_dest = y;
+ }
+ }
+ }
+ } square_iterate_end;
+
+ if (best > 0) {
+ /* now we have the location of the enemy unit,
+ we find the best tile around it,
+ to attack him */
+ struct city *acity = find_nearest_own_city_at(unit_owner(punit),
+ x_dest, y_dest);
+ int xd = 0, yd = 0, dist = 0;
+
+ if (acity) {
+ /* we continue if we find a city in that continent */
+ dist = real_map_distance(x_dest, y_dest, acity->x, acity->y);
+ best = 0;
+ square_iterate(x_dest, y_dest, 1, x, y) {
+ int rating = 0;
+ if (is_ocean(map_get_terrain(x, y))) {
+ /* do not paradroop to ocean! */
+ continue;
+ }
+ if (is_non_allied_unit_tile(map_get_tile(x, y), pplayer)) {
+ /* do not paradroop on an enemy unit! */
+ continue;
+ }
+ if (real_map_distance(punit->x, punit->y, x, y) > range) {
+ /* do not paradroop outside the range */
+ continue;
+ }
+
+ switch(map_get_terrain(x, y)) {
+ case T_FOREST:
+ case T_HILLS:
+ case T_JUNGLE:
+ rating = 2; break;
+ case T_MOUNTAINS:
+ rating = 4; break;
+ default:
+ rating = 0; break;
+ };
+ rating += (dist - real_map_distance(x, y, acity->x, acity->y));
+
+ if (rating > best) {
+ /* we assign the best location to attack the unit */
+ best = rating;
+ xd = x; yd = y;
+ }
+
+ } square_iterate_end;
+
+ /* we assign the last best values */
+ if (best) {
+ x_dest = xd; y_dest = yd;
+ }
+ } else {
+ best = 0;
+ x_dest = 0; y_dest = 0;
+ }
+ }
+ }
+
+ if (best) {
+ /* we move the unit */
+ set_goto_dest(punit, x_dest, y_dest);
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "paradroping.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ if (do_paradrop(punit, x_dest, y_dest)) {
+ /* successfull! */
+ if (!find_unit_by_id(sanity)) {
+ /* the unit did not survive the move */
+ return;
+ }
+ /* and we attack the target */
+ (void)ai_military_rampage(punit, RAMPAGE_ANYTHING, RAMPAGE_ANYTHING);
+ }
+ if (find_unit_by_id(sanity)) {
+ clear_goto_dest(punit);
+ }
+ } else {
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "dind't find objective to paradrop
to.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ /* go to zones in danger */
+ square_iterate(punit->x, punit->y, range, x, y) {
+ struct city *acity = map_get_city(x, y);
+ if (acity && pplayers_allied(city_owner(acity), pplayer)) {
+ if (acity->ai.danger > best) {
+ best = acity->ai.danger;
+ x_dest = acity->x; y_dest = acity->y;
+ }
+ }
+ } square_iterate_end;
+
+ if (best && ((punit->x != x_dest) && (punit->y != y_dest))) {
+ set_goto_dest(punit, x_dest, y_dest);
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "moving to zones in danger.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ (void)do_paradrop(punit, x_dest, y_dest);
+ if (find_unit_by_id(sanity)) {
+ clear_goto_dest(punit);
+ }
+ }
+ }
+ } else {
+ /* we can't paradrop :-( */
+ struct city *acity = NULL;
+
+ /* we are in a city, so don't try to find another */
+ if (pcity) {
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "waiting in a city for next turn.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ return;
+ }
+
+ /* find a city to go to recover and paradrop from */
+ acity = find_nearest_own_city_at(unit_owner(punit), punit->x, punit->y);
+
+ if (acity) {
+ if (!ai_unit_goto(punit, acity->x, acity->y)) {
+ /* die or unsuccessfull move */
+ return;
+ }
+ } else {
+ UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "didn't find city to go and
recover.",
+ pplayer->name, unit_type(punit)->name,
+ punit->id, punit->x, punit->y);
+ /* TODO: decide what to do now! */
+ }
+ }
+}
+
+/*******************************************************************
+ Computes the want for an operation
+ ******************************************************************/
+static int find_something_to_paradrop(struct unit *punit, int x, int y)
+{ int profit = 0;
+ int range = unit_type(punit)->paratroopers_range;
+ struct city *acity = NULL;
+ struct player *pplayer = unit_owner(punit);
+
+ /* first, we search for undefended cities */
+ square_iterate(punit->x, punit->y, range, x, y) {
+ acity = map_get_city(x,y);
+ if ((acity) && (city_owner(acity) == pplayer) &&
+ (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+ /* own city and empty! */
+ if ((acity->size *
+ (acity->trade_prod + acity->shield_prod + acity->food_prod) *
+ acity->ai.urgency) > profit) {
+ profit = (acity->size *
+ (acity->trade_prod + acity->shield_prod + acity->food_prod) *
+ acity->ai.urgency);
+ }
+ }
+ } square_iterate_end;
+
+ /* second, we search for undefended enemy cities near us */
+ square_iterate(punit->x, punit->y, range, x, y) {
+ acity = map_get_city(x,y);
+ if ((acity) && pplayers_at_war(city_owner(acity), pplayer) &&
+ (unit_list_size(&(map_get_tile(x, y)->units)) == 0)) {
+ /* enemy city and empty! */
+ if ((acity->size *
+ (acity->trade_prod + acity->shield_prod + acity->food_prod)) >
profit) {
+ profit = (acity->size *
+ (acity->trade_prod + acity->shield_prod + acity->food_prod));
+ }
+ }
+ } square_iterate_end;
+
+ /* third, we search for enemy units near us */
+ square_iterate(punit->x, punit->y, range, x, y) {
+ struct tile *ptile = map_get_tile(x, y);
+ if (unit_list_size(&(ptile->units)) > 0) {
+ struct unit *pdef = unit_list_get(&ptile->units, 0);
+ if (pplayers_at_war(pplayer, unit_owner(pdef))) {
+ int benefit = stack_cost(pdef);
+ benefit = (benefit * punit->hp) / unit_type(punit)->hp;
+ if (benefit > profit) {
+ /* best enemy unit to kill! */
+ profit = benefit;
+ }
+ }
+ }
+ } square_iterate_end;
+
+ return profit;
+}
+
+/*******************************************************************
+ * Chooses to build a paratroop if necessary
+ ******************************************************************/
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+ struct ai_choice *choice)
+{
+
+ /* military_advisor_choose_build does something idiotic,
+ * this function should not be called if there is danger... */
+ if (choice->want >= 100 && choice->type != CT_ATTACKER) {
+ return;
+ }
+
+ unit_type_iterate(u_type) {
+ if (!unit_type_flag(u_type, F_PARATROOPERS)) {
+ continue;
+ }
+
+ if (!can_build_unit(pcity, u_type)) {
+ continue;
+ }
+
+ struct unit *virtual_unit =
+ create_unit_virtual(pplayer, pcity, u_type,
+ do_make_unit_veteran(pcity, u_type));
+ int profit = find_something_to_paradrop(virtual_unit, pcity->x, pcity->y);
+ if (profit > choice->want){
+ /* Update choice */
+ choice->want = profit;
+ choice->choice = u_type;
+ choice->type = CT_ATTACKER;
+ freelog(LOGLEVEL_PARATROOPER, "%s wants to build %s (want=%d)",
+ pcity->name, get_unit_type(u_type)->name, profit);
+ }
+ destroy_unit_virtual(virtual_unit);
+ } unit_type_iterate_end;
+
+ return;
+}
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore
freeciv-cvs-Feb-27/ai/aiparatrooper.h
freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h
--- freeciv-cvs-Feb-27/ai/aiparatrooper.h 1970-01-01 01:00:00.000000000
+0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiparatrooper.h 2004-03-18
02:34:36.000000000 +0100
@@ -0,0 +1,25 @@
+/**********************************************************************
+ Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
+ 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__AIPARATROOPER_H
+#define FC__AIPARATROOPER_H
+
+struct ai_choice;
+struct city;
+struct player;
+struct unit;
+
+void ai_manage_paratrooper(struct player *pplayer, struct unit *punit);
+void ai_choose_paratrooper(struct player *pplayer, struct city *pcity,
+ struct ai_choice *choice);
+
+#endif /* FC__AIPARATROOPER_H */
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.c
freeciv-cvs-Feb-27-paratroop/ai/aiunit.c
--- freeciv-cvs-Feb-27/ai/aiunit.c 2004-02-26 07:01:21.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.c 2004-03-30 14:26:38.000000000
+0200
@@ -55,6 +55,7 @@
#include "aidiplomat.h"
#include "aihand.h"
#include "ailog.h"
+#include "aiparatrooper.h"
#include "aitools.h"
#include "aiunit.h"
@@ -67,11 +68,6 @@
static void ai_manage_barbarian_leader(struct player *pplayer,
struct unit *leader);
-#define RAMPAGE_ANYTHING 1
-#define RAMPAGE_HUT_OR_BETTER 99998
-#define RAMPAGE_FREE_CITY_OR_BETTER 99999
-static bool ai_military_rampage(struct unit *punit, int thresh_adj,
- int thresh_move);
static void ai_military_findjob(struct player *pplayer,struct unit *punit);
static void ai_military_gohome(struct player *pplayer,struct unit *punit);
static void ai_military_attack(struct player *pplayer,struct unit *punit);
@@ -665,7 +661,7 @@
FIXME: We should check for fortresses here.
**************************************************************************/
-static bool stay_and_defend(struct unit *punit)
+bool stay_and_defend(struct unit *punit)
{
struct city *pcity = map_get_city(punit->x, punit->y);
bool has_defense = FALSE;
@@ -1052,7 +1048,7 @@
Returns TRUE if survived the rampage session.
**************************************************************************/
-static bool ai_military_rampage(struct unit *punit, int thresh_adj,
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
int thresh_move)
{
int count = punit->moves_left + 1; /* break any infinite loops */
@@ -2653,6 +2649,9 @@
} else if (unit_has_role(punit->type, L_BARBARIAN_LEADER)) {
ai_manage_barbarian_leader(pplayer, punit);
return;
+ } else if (unit_flag(punit, F_PARATROOPERS)) {
+ ai_manage_paratrooper(pplayer, punit);
+ return;
} else if (get_transporter_capacity(punit) > 0) {
ai_manage_ferryboat(pplayer, punit);
return;
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/aiunit.h
freeciv-cvs-Feb-27-paratroop/ai/aiunit.h
--- freeciv-cvs-Feb-27/ai/aiunit.h 2004-01-12 07:16:15.000000000 +0100
+++ freeciv-cvs-Feb-27-paratroop/ai/aiunit.h 2004-03-30 14:27:31.000000000
+0200
@@ -46,6 +46,11 @@
extern Unit_Type_id simple_ai_types[U_LAST];
+#define RAMPAGE_ANYTHING 1
+#define RAMPAGE_HUT_OR_BETTER 99998
+#define RAMPAGE_FREE_CITY_OR_BETTER 99999
+bool ai_military_rampage(struct unit *punit, int thresh_adj,
+ int thresh_move);
void ai_manage_units(struct player *pplayer);
int could_unit_move_to_tile(struct unit *punit, int dest_x, int dest_y);
int look_for_charge(struct player *pplayer, struct unit *punit,
@@ -64,6 +69,7 @@
int *x, int *y);
int build_cost_balanced(Unit_Type_id type);
+bool stay_and_defend(struct unit *punit);
int unittype_att_rating(Unit_Type_id type, int veteran,
int moves_left, int hp);
int unit_att_rating(struct unit *punit);
diff -NurEbB -Xfreeciv-cvs-Feb-27/diff_ignore freeciv-cvs-Feb-27/ai/Makefile.am
freeciv-cvs-Feb-27-paratroop/ai/Makefile.am
--- freeciv-cvs-Feb-27/ai/Makefile.am 2003-09-22 07:00:04.000000000 +0200
+++ freeciv-cvs-Feb-27-paratroop/ai/Makefile.am 2004-03-18 01:07:19.000000000
+0100
@@ -25,6 +25,8 @@
aihand.h \
ailog.c \
ailog.h \
+ aiparatrooper.c \
+ aiparatrooper.h \
aitech.c \
aitech.h \
aitools.c \
|
|