diff -uNrX freeciv/diff_ignore freeciv/ai/advdomestic.c freeciv-phased/ai/advdomestic.c --- freeciv/ai/advdomestic.c 2002-07-22 13:05:52.000000000 +0000 +++ freeciv-phased/ai/advdomestic.c 2002-08-08 04:44:52.000000000 +0000 @@ -1036,11 +1036,6 @@ /* Oh dear, better think of something! */ unit_type = best_role_unit(pcity, F_TRADE_ROUTE); - if (unit_type == U_LAST) { - unit_type = best_role_unit(pcity, F_DIPLOMAT); - /* Someday, real diplomat code will be here! */ - } - if (unit_type != U_LAST) { choice->want = 1; choice->type = CT_NONMIL; diff -uNrX freeciv/diff_ignore freeciv/ai/advmilitary.c freeciv-phased/ai/advmilitary.c --- freeciv/ai/advmilitary.c 2002-08-07 12:50:17.000000000 +0000 +++ freeciv-phased/ai/advmilitary.c 2002-08-08 04:46:37.000000000 +0000 @@ -23,10 +23,13 @@ #include "cityturn.h" #include "gotohand.h" /* warmap has been redeployed */ #include "settlers.h" +#include "diplomats.h" +#include "player.h" #include "aicity.h" #include "aitools.h" #include "aiunit.h" +#include "aidiplomat.h" #include "advmilitary.h" @@ -282,8 +285,6 @@ int danger5 = 0; /* linear for SDI */ struct player *pplayer; bool pikemen = FALSE; - bool diplomat = FALSE; /* TRUE mean that this town can defend - * against diplomats or spies */ int urgency = 0; bool igwall; int badmojo = 0; @@ -300,10 +301,11 @@ pcity->ai.grave_danger = 0; pcity->ai.diplomat_threat = FALSE; + pcity->ai.has_diplomat = FALSE; unit_list_iterate(map_get_tile(pcity->x, pcity->y)->units, punit) if (unit_flag(punit, F_PIKEMEN)) pikemen = TRUE; - if (unit_flag(punit, F_DIPLOMAT)) diplomat = TRUE; + if (unit_flag(punit, F_DIPLOMAT)) pcity->ai.has_diplomat = TRUE; unit_list_iterate_end; players_iterate(aplayer) { @@ -351,8 +353,9 @@ (v * m / (dist*2))); } - if (unit_flag(funit, F_DIPLOMAT) && (dist <= 2 * m)) - pcity->ai.diplomat_threat = !diplomat; + if (unit_flag(funit, F_DIPLOMAT) && (dist <= 2 * m)) { + pcity->ai.diplomat_threat = TRUE; + } v *= v; @@ -394,7 +397,7 @@ } if (unit_flag(punit, F_DIPLOMAT) && (dist <= 2 * m)) - pcity->ai.diplomat_threat = !diplomat; + pcity->ai.diplomat_threat = TRUE; v *= v; @@ -1103,6 +1106,138 @@ } /********************************************************************** + Calculates our need for diplomats as defensive units. May replace + values in choice. The values 16000 and 3000 used below are totally + arbitrary but seem to work. +***********************************************************************/ +void ai_choose_diplomat_defensive(struct player *pplayer, struct city *pcity, + struct ai_choice *choice, int def) +{ + /* Build a diplomat if our city is threatened by enemy diplomats, and + we have other defensive troops, and we don't already have a diplomat + to protect us. If we see an enemy diplomat and we don't have diplomat + tech... race it! */ + if (def != 0 && pcity->ai.diplomat_threat && !pcity->ai.has_diplomat) { + Unit_Type_id u = best_role_unit(pcity, F_DIPLOMAT); + if (uname); + choice->want = 16000; /* diplomat more important than soldiers */ + pcity->ai.urgency = 1; + choice->type = CT_DEFENDER; + choice->choice = u; + } else if (num_role_units(F_DIPLOMAT) > 0) { + /* We don't know diplomats yet... */ + freelog(LOG_VERBOSE, "A defensive diplomat is wanted badly in city %s.", + pcity->name); + u = get_role_unit(F_DIPLOMAT, 0); + /* 3000 is a just a large number, but not hillariously large as the + previously used one. This is important for diplomacy later - Per */ + pplayer->ai.tech_want[get_unit_type(u)->tech_requirement] += 3000; + } + } +} + +/********************************************************************** + Calculates our need for diplomats as offensive units. May replace + values in choice. Note that we only build diplomats as long as we can + establish embassies and steal technology. +***********************************************************************/ +void ai_choose_diplomat_offensive(struct player *pplayer, struct city *pcity, + struct ai_choice *choice) +{ + Unit_Type_id u = best_role_unit(pcity, F_DIPLOMAT); + + /* FIXME */ + if (!ai_handicap(pplayer, H_EXPERIMENTAL)) return; + + if (u >= U_LAST) { + /* We don't know diplomats yet! */ + return; + } + + if (ai_handicap(pplayer, H_DIPLOMAT)) { + /* Diplomats are too tough on newbies */ + return; + } + + /* Do we have a good reason for building diplomats? */ + { + struct unit_type *ut = get_unit_type(u); + struct city *acity = find_city_to_diplomat(pplayer, pcity->x, + pcity->y, FALSE); + int want, loss, p_success, p_failure, time_to_dest; + int gain_incite = 0, gain_theft = 0, gain = 1; + + if (acity == NULL || acity->ai.already_considered_for_diplomat) { + /* Found no target or city already considered */ + return; + } + city_incite_cost(acity); /* prime variable */ + if (pplayers_at_war(pplayer, city_owner(acity)) + && (find_palace(city_owner(acity)) != acity) + && !government_has_flag(get_gov_pplayer(city_owner(acity)), + G_UNBRIBABLE) + && (acity->incite_revolt_cost < + pplayer->economic.gold - pplayer->ai.est_upkeep)) { + /* incite gain (FIXME: we should count wonders too but need to + cache that somehow to avoid CPU hog -- Per) */ + gain_incite = acity->food_prod * FOOD_WEIGHTING + + acity->shield_prod * SHIELD_WEIGHTING + + (acity->luxury_total + + acity->tax_total + + acity->science_total) * TRADE_WEIGHTING; + gain_incite *= SHIELD_WEIGHTING; /* cost to take city otherwise */ + gain_incite -= acity->incite_revolt_cost; + } + if (city_owner(acity)->research.techs_researched < + pplayer->research.techs_researched + && !pplayers_allied(pplayer, city_owner(acity))) { + /* tech theft gain */ + gain_theft = total_bulbs_required(pplayer) * TRADE_WEIGHTING; + } + gain = MAX(gain_incite, gain_theft); + loss = ut->build_cost * SHIELD_WEIGHTING; + + /* Probability to succeed, assuming no defending diplomat */ + p_success = game.diplchance; + /* Probability to lose our unit */ + p_failure = (unit_type_flag(u, F_SPY) ? 100 - p_success : 100); + + /* FIXME: Use warmap and unit_move_turns */ + time_to_dest = real_map_distance(pcity->x, pcity->y, acity->x, acity->y) + * SINGLE_MOVE / ut->move_rate; + time_to_dest *= (time_to_dest/2); /* No long treks, please */ + + /* Almost kill_desire */ + want = (p_success * gain - p_failure * loss) / 100 + - SHIELD_WEIGHTING * time_to_dest; + if (want <= 0) { + return; + } + + want = military_amortize(want, time_to_dest, ut->build_cost); + + if (!player_has_embassy(pplayer, city_owner(acity))) { + freelog(LOG_VERBOSE, "A diplomat desired in %s to establish an " + "embassy with %s in %s", pcity->name, + city_owner(acity)->name, acity->name); + want = MAX(want, 99); + } + if (want > choice->want) { + freelog(LOG_DEBUG, "%s,%s: %s is desired with want %d (was %d) to spy " + "in %s (incite desire %d, tech theft desire %d)", + pplayer->name, pcity->name, ut->name, want, choice->want, + acity->name, gain_incite, gain_theft); + choice->want = want; + choice->type = CT_ATTACKER; + choice->choice = u; + acity->ai.already_considered_for_diplomat = TRUE; + } + } +} + +/********************************************************************** ... this function should assign a value to choice and want and type, where want is a value between 1 and 100. if want is 0 this advisor doesn't want anything @@ -1129,22 +1264,7 @@ freelog(LOG_DEBUG, "Assessed danger for %s = %d, Def = %d", pcity->name, danger, def); - if (pcity->ai.diplomat_threat && def != 0){ - /* It's useless to build a diplomat as the last defender of a town. --nb */ - - Unit_Type_id u = best_role_unit(pcity, F_DIPLOMAT); - if (uname); - choice->want = 16000; /* diplomat more important than soldiers */ - pcity->ai.urgency = 1; - choice->type = CT_DEFENDER; - choice->choice = u; - return; - } else if (num_role_units(F_DIPLOMAT)>0) { - u = get_role_unit(F_DIPLOMAT, 0); - pplayer->ai.tech_want[get_unit_type(u)->tech_requirement] += 16000; - } - } + ai_choose_diplomat_defensive(pplayer, pcity, choice, def); if (danger != 0) { /* otherwise might be able to wait a little longer to defend */ /* old version had danger -= def in it, which was necessary before disband/upgrade @@ -1251,6 +1371,7 @@ virtualunit.hp = unit_types[v].hp; kill_something_with(pplayer, pcity, &virtualunit, choice); } /* ok. can now mung seamap for ferryboat code. Proceed! */ + ai_choose_diplomat_offensive(pplayer, pcity, choice); v = ai_choose_attacker_ground(pcity); virtualunit.type = v; /* virtualunit.veteran = do_make_unit_veteran(pcity, v);*/ diff -uNrX freeciv/diff_ignore freeciv/ai/aidiplomat.c freeciv-phased/ai/aidiplomat.c --- freeciv/ai/aidiplomat.c 1970-01-01 00:00:00.000000000 +0000 +++ freeciv-phased/ai/aidiplomat.c 2002-08-08 04:46:52.000000000 +0000 @@ -0,0 +1,412 @@ +/********************************************************************** + 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. +***********************************************************************/ + +#include +#include +#include +#include + +#include "city.h" +#include "combat.h" +#include "game.h" +#include "government.h" +#include "log.h" +#include "map.h" +#include "mem.h" +#include "packets.h" +#include "player.h" +#include "rand.h" +#include "shared.h" +#include "timing.h" +#include "unit.h" + +#include "barbarian.h" +#include "citytools.h" +#include "cityturn.h" +#include "diplomats.h" +#include "gotohand.h" +#include "maphand.h" +#include "settlers.h" +#include "unithand.h" +#include "unittools.h" + +#include "advmilitary.h" +#include "aicity.h" +#include "aihand.h" +#include "aitools.h" + +#include "aiunit.h" + +#define LOG_AI LOG_DEBUG + +/****************************************************************************** + ... +******************************************************************************/ +static int count_sabotagable_improvements(struct city *pcity) +{ + int count = 0; + built_impr_iterate(pcity, index) { + if (!is_wonder(index) && index != B_PALACE) { + count++; + } + } built_impr_iterate_end; + return count; +} + +/****************************************************************************** + ... +******************************************************************************/ +static int count_stealable_techs(struct player *pplayer, struct player *tplayer) +{ + int index, count = 0; + for (index = A_FIRST; index < game.num_tech_types; index++) { + if ((get_invention(pplayer, index) != TECH_KNOWN) && + (get_invention(tplayer, index) == TECH_KNOWN)) { + count++; + } + } + return count; +} + +/************************************************************************** + ... +**************************************************************************/ +static bool diplomat_can(struct unit *punit, int x, int y, + enum diplomat_actions action) +{ + return (diplomat_can_do_action(punit, action, x, y) + && is_diplomat_action_available(punit, action, x, y)); +} + +/************************************************************************** + Check if something is on our receiving end for some nasty diplomat + business! Note that pdiplomat may be die or be moved during this + function. + + We try to make embassy first, and abort if we already have one and target + is allied. Then we incite, steal, sabotage or poison the city, in that + order of priority. +**************************************************************************/ +static void auto_diplomat_city(struct unit *pdiplomat, struct city *ctarget) +{ + struct packet_diplomat_action dact; + struct player *pplayer = unit_owner(pdiplomat); + struct player *tplayer = city_owner(ctarget); + int count_impr = count_sabotagable_improvements(ctarget); + int count_tech = count_stealable_techs(pplayer, tplayer); + int gold_avail = pplayer->economic.gold; + + if (pplayer->ai.control) gold_avail -= pplayer->ai.est_upkeep; + dact.diplomat_id = pdiplomat->id; + dact.target_id = ctarget->id; + +#define T(my_act,my_val) \ + if (diplomat_can(pdiplomat, ctarget->x, ctarget->y, my_act)) { \ + dact.action_type = my_act; \ + dact.value = my_val; \ + freelog(LOG_AI, "Player %s's diplomat %d does " #my_act " on %s", \ + pplayer->name, pdiplomat->id, ctarget->name); \ + handle_diplomat_action(pplayer, &dact); \ + return; \ + } + + if (!pdiplomat->foul) T(DIPLOMAT_EMBASSY,0); + if (pplayers_allied(pplayer, tplayer)) return; + city_incite_cost(ctarget); + if (ctarget->incite_revolt_cost + pplayer->ai.est_upkeep <= gold_avail) { + T(DIPLOMAT_INCITE,0); + } + if (count_tech > 0 + && (ctarget->steal == 0 || unit_flag(pdiplomat, F_SPY))) { + T(DIPLOMAT_STEAL,0); + } + if (count_impr > 0) T(DIPLOMAT_SABOTAGE, B_LAST+1); + T(SPY_POISON, 0); /* absolutely last resort */ +#undef T + + /* This can happen for a number of odd and esoteric reasons */ + freelog(LOG_AI, "Player %s's diplomat %d decides to stand " + "idle outside enemy city %s!", pplayer->name, pdiplomat->id, + ctarget->name); + handle_unit_activity_request(pdiplomat, ACTIVITY_IDLE); +} + +/************************************************************************** + Find a city to send diplomats against, or NULL if none available on + this continent. x,y are coordinates of diplomat or city which wishes + to build diplomats, and foul is TRUE if diplomat has done something bad + before. +**************************************************************************/ +struct city *find_city_to_diplomat(struct player *pplayer, int x, int y, + bool foul) +{ + bool has_emb; + int oic = 0; /* incite cost */ + int rmd = 0; /* real map distance */ + int dist=MAX(map.xsize, map.ysize); + int continent = map_get_continent(x, y); + bool dipldef; /* whether target is protected by diplomats */ + bool handicap = ai_handicap(pplayer, H_TARGETS); + struct city *ctarget = NULL; + + players_iterate(aplayer) { + /* sneaky way of avoiding foul diplomat capture -AJS */ + has_emb = player_has_embassy(pplayer, aplayer) || foul; + + /* Note: it is possible to lose an embassy to an allied player */ + if (aplayer == pplayer || is_barbarian(aplayer) + || (pplayers_allied(pplayer,aplayer) && has_emb)) { + continue; + } + city_list_iterate(aplayer->cities, acity) { + struct city *capital = find_palace(city_owner(acity)); + if (handicap && !map_get_known(acity->x, acity->y, pplayer)) { + /* Target is not visible */ + continue; + } + if (continent != map_get_continent(acity->x, acity->y)) { + continue; + } + /* Figure out incite cost */ + city_incite_cost(acity); /* FIXME: remove need for this */ + oic = acity->incite_revolt_cost; + if (pplayer->player_no == acity->original) oic = oic / 2; + rmd = real_map_distance(x, y, acity->x, acity->y); + dipldef = (count_diplomats_on_tile(acity->x, acity->y) > 0); + if (!ctarget || (dist > rmd)) { + if (!has_emb + || (acity->steal == 0 && pplayer->research.techs_researched < + city_owner(acity)->research.techs_researched && !dipldef) + || (oic < (pplayer->economic.gold - pplayer->ai.est_upkeep) + && !government_has_flag(get_gov_pplayer(city_owner(acity)), + G_UNBRIBABLE) + && acity != capital && !dipldef)) { + /* We have the closest enemy city so far on the same continent */ + ctarget = acity; + dist = rmd; + } + } + } city_list_iterate_end; + } players_iterate_end; + return ctarget; +} + +/************************************************************************** + Attempt to find a city that needs reinforcent on this continent. + Currently only used by diplomats. Not tested with other units. - Per +**************************************************************************/ +static struct city *find_city_to_defend(struct player *pplayer, int x, int y, + Unit_Type_id utype) +{ + int dist, urgency; + int best_dist = 30; /* any city closer than this is better than none */ + int best_urgency = 0; + struct city *ctarget = NULL; + int continent = map_get_continent(x, y); + + city_list_iterate(pplayer->cities, acity) { + if (continent != map_get_continent(acity->x, acity->y)) continue; + urgency = acity->ai.urgency + 1; + if (unit_type_flag(utype, F_DIPLOMAT)) { + if (!acity->ai.has_diplomat && acity->ai.diplomat_threat) { + urgency *= 5; /* we can help */ + } else if (acity->ai.has_diplomat) { + urgency /= 3; /* we are not really needed there */ + } + } + dist = real_map_distance(x, y, acity->x, acity->y); + /* I don't know if this formula is optimal, but it works. */ + if (dist > best_dist) { + /* punish city for being so far away */ + urgency /= (float)(dist/best_dist); + } + if (urgency > best_urgency) { + ctarget = acity; + best_urgency = urgency; + best_dist = MAX(dist,1); /* squelch divide-by-zero */ + } + } city_list_iterate_end; + return ctarget; +} + +/************************************************************************** + Bribe any and all adjacent hostile units if we have enough gold and we + think they are worth it. + + FIXME: use warmap to lunge out for nearby but not adjacent units +**************************************************************************/ +static void ai_diplomat_bribe_nearby(struct player *pplayer, + struct unit *pdiplomat) +{ + struct packet_diplomat_action dact; + Unit_Type_id sanity = pdiplomat->id; + struct city *pcity = map_get_city(pdiplomat->x, pdiplomat->y); + + adjc_iterate(pdiplomat->x, pdiplomat->y, x, y) { + if (diplomat_can(pdiplomat, x, y, DIPLOMAT_BRIBE)) { + /* A lone trespasser! Seize him! -AJS */ + int subjective_cost; + int gold_avail = pplayer->economic.gold - pplayer->ai.est_upkeep; + struct tile *ptile = map_get_tile(x, y); + struct unit *ptres = unit_list_get(&ptile->units, 0); + + subjective_cost = ptres->bribe_cost = unit_bribe_cost(ptres); + if (ptres->bribe_cost >= gold_avail/2) { + subjective_cost *= 1.5; + } + if (pcity != NULL) { + /* not so interested. notice how we are not going to buy it if we are + outside a city and victim costs more than half our funds */ + subjective_cost *= 2; + } + if (unit_flag(ptres, F_SPY) || unit_flag(ptres, F_DIPLOMAT) + || (unit_flag(ptres, F_IGWALL) && pcity != NULL)) { + /* these three types of units are generally very dangerous */ + subjective_cost *= 2; + } + if (subjective_cost < gold_avail) { + dact.diplomat_id = pdiplomat->id; + dact.target_id = ptres->id; + dact.action_type = DIPLOMAT_BRIBE; + handle_diplomat_action(pplayer, &dact); + if (find_unit_by_id(sanity) == NULL) { + /* we somehow died. oops! */ + return; + } + /* if we came out of a city, try to return */ + if (pcity != NULL) { + ai_unit_move(pdiplomat, pcity->x, pcity->y); + } + break; + } + } + } adjc_iterate_end; + return; +} + +/************************************************************************** + If we are the only diplomat in a threatened city, defend against enemy + actions. The passive defense is set by game.diplchance. The active + defense is to bribe units which end their move nearby. Our next trick is + to look for enemy cities on our continent and do our diplomat things. + FIXME: It is important to establish contact with all civilizations, so + we should send diplomats by boat eventually. I just don't know how that + part of the code works, yet - Per +**************************************************************************/ +void ai_manage_diplomat(struct player *pplayer, struct unit *pdiplomat) +{ + struct city *pcity, *ctarget = NULL; + Unit_Type_id sanity = pdiplomat->id; + + assert((pplayer != NULL) && (pdiplomat != NULL)); + + /* Look for someone to bribe */ + ai_diplomat_bribe_nearby(pplayer, pdiplomat); + + /* Sanity check */ + if (find_unit_by_id(sanity) == NULL) { return; } + + /* If we are the only diplomat in a threatened city, then stay to defend */ + pcity = map_get_city(pdiplomat->x, pdiplomat->y); + if (pcity && (count_diplomats_on_tile(pdiplomat->x, pdiplomat->y) == 1) + && pcity->ai.diplomat_threat) { + freelog(LOG_AI, "%s: diplomat %d stays to defend %s", + pplayer->name, pdiplomat->id, pcity->name); + return; + } + + if (!normalize_map_pos(&pdiplomat->goto_dest_x, &pdiplomat->goto_dest_y)) { + freelog(LOG_AI, "Diplomat %i had non-normalized map pos", pdiplomat->id); + } + + ctarget = map_get_city(pdiplomat->goto_dest_x, pdiplomat->goto_dest_y); + freelog(LOG_AI, "%s's diplomat %d aims for (%d,%d), and is at " + "(%d,%d) with distance %d to %s (%s goto)", + pplayer->name, pdiplomat->id, + pdiplomat->goto_dest_x, pdiplomat->goto_dest_y, pdiplomat->x, + pdiplomat->y, real_map_distance(pdiplomat->x, pdiplomat->y, + pdiplomat->goto_dest_x, pdiplomat->goto_dest_y), ctarget ? + ctarget->name : "(none)", pdiplomat->activity == ACTIVITY_GOTO ? + "has" : "no"); + + /* Check if we can do something with our destination now. */ + if (ctarget && real_map_distance(pdiplomat->x, pdiplomat->y, + pdiplomat->goto_dest_x, pdiplomat->goto_dest_y) == 1) { + set_unit_activity(pdiplomat, ACTIVITY_IDLE); + auto_diplomat_city(pdiplomat, ctarget); + } + + /* Sanity check */ + if (find_unit_by_id(sanity) == NULL) { return; } + + /* If we are not busy, acquire a target. */ + if (pdiplomat->activity != ACTIVITY_GOTO) { + if ((ctarget = find_city_to_diplomat(pplayer, pdiplomat->x, pdiplomat->y, + pdiplomat->foul)) == NULL) { + if ((ctarget = find_city_to_defend(pplayer, pdiplomat->x, pdiplomat->y, + pdiplomat->type)) == NULL) { + /* + * This should only happen if the entire continent was suddenly + * conquered. So we head for closest coastal city and wait for someone + * to code ferrying for diplomats, or hostile attacks from the sea. + */ + ctarget = find_closest_owned_city(pplayer, pdiplomat->x, pdiplomat->y, + TRUE, NULL); + } + } + } + + /* GOTO */ + if (ctarget) { + enum goto_result cause; + pdiplomat->goto_dest_x=ctarget->x; + pdiplomat->goto_dest_y=ctarget->y; + set_unit_activity(pdiplomat, ACTIVITY_GOTO); +#define T(s) \ + freelog(LOG_AI, "%s's diplomat %d started goto towards %s " \ + "and " #s, pplayer->name, pdiplomat->id, ctarget->name); + cause = do_unit_goto(pdiplomat, GOTO_MOVE_ANY, FALSE); + switch (cause) { + case GR_ARRIVED: + T(arrived at target); /* very unlikely */ + handle_unit_activity_request(pdiplomat, ACTIVITY_IDLE); + break; + case GR_OUT_OF_MOVEPOINTS: + T(ran out of movepoints); + break; + case GR_DIED: + T(died); + break; + case GR_FAILED: + T(stopped before reaching it); + handle_unit_activity_request(pdiplomat, ACTIVITY_IDLE); + /* check if we can achieve something */ + if (real_map_distance(pdiplomat->x, pdiplomat->y, + pdiplomat->goto_dest_x, pdiplomat->goto_dest_y) == 1) { + auto_diplomat_city(pdiplomat, ctarget); + } else { + ai_diplomat_bribe_nearby(pplayer, pdiplomat); + } + break; + case GR_FOUGHT: + assert(FALSE); /* impossible */ + break; + } +#undef T + } else { + /* Very unlikely but remotely possible */ + freelog(LOG_NORMAL, "%s's diplomat %d could not find a target, " + "a city to defend or even a coastal city!", pplayer->name, + pdiplomat->id); + } +} diff -uNrX freeciv/diff_ignore freeciv/ai/aidiplomat.h freeciv-phased/ai/aidiplomat.h --- freeciv/ai/aidiplomat.h 1970-01-01 00:00:00.000000000 +0000 +++ freeciv-phased/ai/aidiplomat.h 2002-08-08 04:44:52.000000000 +0000 @@ -0,0 +1,23 @@ +/********************************************************************** + 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__AIDIPLOMAT_H +#define FC__AIDIPLOMAT_H + +struct player; +struct unit; + +struct city *find_city_to_diplomat(struct player *pplayer, int x, int y, + bool foul); +void ai_manage_diplomat(struct player *pplayer, struct unit *pdiplomat); + +#endif /* FC__AIDIPLOMAT_H */ diff -uNrX freeciv/diff_ignore freeciv/ai/aitools.c freeciv-phased/ai/aitools.c --- freeciv/ai/aitools.c 2002-08-08 04:44:44.000000000 +0000 +++ freeciv-phased/ai/aitools.c 2002-08-08 05:21:07.000000000 +0000 @@ -142,7 +142,10 @@ assert(punit); assert(unit_owner(punit)->ai.control); assert(is_normal_map_pos(x, y)); - assert(is_tiles_adjacent(punit->x, punit->y, x, y)); + if (!is_tiles_adjacent(punit->x, punit->y, x, y)) { + freelog(LOG_ERROR, "ai_unit_move: move to non-adjacent coords"); + return FALSE; + } /* if enemy, stop and let ai attack function take this case */ if (is_enemy_unit_tile(ptile, pplayer) @@ -237,13 +240,15 @@ } /************************************************************************** -... Credits the AI wants to have in reserves. + Credits the AI wants to have in reserves. We need some gold to bribe + and incite cities. + + "I still don't trust this function" -- Syela **************************************************************************/ int ai_gold_reserve(struct player *pplayer) { - int i = total_player_citizens(pplayer)*2; + int i = total_player_citizens(pplayer)*15; return MAX(pplayer->ai.maxbuycost, i); -/* I still don't trust this function -- Syela */ } /************************************************************************** diff -uNrX freeciv/diff_ignore freeciv/ai/aiunit.c freeciv-phased/ai/aiunit.c --- freeciv/ai/aiunit.c 2002-08-08 04:44:44.000000000 +0000 +++ freeciv-phased/ai/aiunit.c 2002-08-08 04:54:15.000000000 +0000 @@ -44,10 +44,11 @@ #include "aicity.h" #include "aihand.h" #include "aitools.h" +#include "aidiplomat.h" #include "aiunit.h" -static void ai_manage_diplomat(struct player *pplayer, struct unit *pdiplomat); +static void ai_manage_diplomat_old(struct player *pplayer, struct unit *pdiplomat); static void ai_manage_military(struct player *pplayer,struct unit *punit); static void ai_manage_caravan(struct player *pplayer, struct unit *punit); static void ai_manage_barbarian_leader(struct player *pplayer, @@ -2277,12 +2278,11 @@ if ((unit_flag(punit, F_DIPLOMAT)) || (unit_flag(punit, F_SPY))) { - ai_manage_diplomat(pplayer, punit); - /* the right test if the unit is in a city and - there is no other diplomat it musn't move. - This unit is a bodyguard against enemy diplomats. - Right now I don't know how to use bodyguards! (17/12/98) (--NB) - */ + /* FIXME!!! */ + if (ai_handicap(pplayer, H_EXPERIMENTAL)) + ai_manage_diplomat(pplayer, punit); + else + ai_manage_diplomat_old(pplayer, punit); return; } else if (unit_flag(punit, F_SETTLERS) ||unit_flag(punit, F_CITIES)) { @@ -2432,7 +2432,7 @@ information gained this way is assumed to be more useful than anything else we could do. Making this come true is for future code. -AJS **************************************************************************/ -static void ai_manage_diplomat(struct player *pplayer, struct unit *pdiplomat) +static void ai_manage_diplomat_old(struct player *pplayer, struct unit *pdiplomat) { bool handicap, has_emb; int continent, dist, rmd, oic, did; diff -uNrX freeciv/diff_ignore freeciv/ai/Makefile.am freeciv-phased/ai/Makefile.am --- freeciv/ai/Makefile.am 2001-12-11 16:16:25.000000000 +0000 +++ freeciv-phased/ai/Makefile.am 2002-08-08 04:44:53.000000000 +0000 @@ -34,4 +34,6 @@ aitools.c \ aitools.h \ aiunit.c \ - aiunit.h + aiunit.h \ + aidiplomat.c \ + aidiplomat.h diff -uNrX freeciv/diff_ignore freeciv/client/control.c freeciv-phased/client/control.c --- freeciv/client/control.c 2002-07-22 00:22:41.000000000 +0000 +++ freeciv-phased/client/control.c 2002-08-08 04:44:53.000000000 +0000 @@ -513,8 +513,10 @@ pcity = find_city_by_id(victim_id); punit = find_unit_by_id(victim_id); - if (!pdiplomat || !unit_flag(pdiplomat, F_DIPLOMAT)) + if (!pdiplomat || !unit_flag(pdiplomat, F_DIPLOMAT)) { + assert(0); /* this is always an error */ continue; + } if (punit && is_diplomat_action_available(pdiplomat, DIPLOMAT_ANY_ACTION, diff -uNrX freeciv/diff_ignore freeciv/common/city.h freeciv-phased/common/city.h --- freeciv/common/city.h 2002-08-07 13:23:41.000000000 +0000 +++ freeciv-phased/common/city.h 2002-08-08 04:44:53.000000000 +0000 @@ -186,8 +186,8 @@ /* building desirabilities - easiest to handle them here -- Syela */ int building_want[B_LAST]; /* not sure these will always be < 256 */ int danger; /* danger to be compared to assess_defense */ - bool diplomat_threat; /* an enemy diplomat or spy is near the city, - and this city has no diplomat or spy defender */ + bool diplomat_threat; /* an enemy diplomat or spy is near the city */ + bool has_diplomat; /* this city has diplomat or spy defender */ int urgency; /* how close the danger is; if zero, bodyguards can leave */ int grave_danger; /* danger that is upon us, should show positive feedback */ int wallvalue; /* how much it helps for defenders to be ground units */ @@ -212,6 +212,9 @@ int invasion; /* who's coming to kill us, for attack co-ordination */ int attack, bcost; /* This is also for invasion - total power and value of * all units coming to kill us. */ + + /* Used by _other_ cities temporarily while assigning diplomat targets */ + bool already_considered_for_diplomat; }; struct city { diff -uNrX freeciv/diff_ignore freeciv/common/player.h freeciv-phased/common/player.h --- freeciv/common/player.h 2002-08-07 23:19:43.000000000 +0000 +++ freeciv-phased/common/player.h 2002-08-08 04:44:53.000000000 +0000 @@ -40,7 +40,7 @@ enum handicap_type { H_NONE=0, /* no handicaps */ - H_RIGIDPROD=1, /* can't switch to/from building_unit without penalty */ + H_DIPLOMAT=1, /* can't build offensive diplomats */ H_MAP=2, /* only knows map_get_known tiles */ H_TECH=4, /* doesn't know what enemies have researched */ H_CITYBUILDINGS=8, /* doesn't know what buildings are in enemy cities */ diff -uNrX freeciv/diff_ignore freeciv/server/cityturn.c freeciv-phased/server/cityturn.c --- freeciv/server/cityturn.c 2002-08-04 17:08:30.000000000 +0000 +++ freeciv-phased/server/cityturn.c 2002-08-08 04:44:53.000000000 +0000 @@ -397,6 +397,7 @@ void begin_cities_turn(struct player *pplayer) { city_list_iterate(pplayer->cities, pcity) + pcity->ai.already_considered_for_diplomat = FALSE; /* ai hack */ define_orig_production_values(pcity); city_list_iterate_end; } diff -uNrX freeciv/diff_ignore freeciv/server/diplomats.c freeciv-phased/server/diplomats.c --- freeciv/server/diplomats.c 2002-08-07 13:23:41.000000000 +0000 +++ freeciv-phased/server/diplomats.c 2002-08-08 04:44:53.000000000 +0000 @@ -1370,3 +1370,25 @@ unit_list_iterate_end; return count; } + +/************************************************************************** + Return TRUE if a tile is protected by a spy +**************************************************************************/ +bool is_spy_on_tile(int x, int y) +{ + unit_list_iterate(map_get_tile(x, y)->units, punit) + if (unit_flag(punit, F_SPY)) { return TRUE; } + unit_list_iterate_end; + return FALSE; +} + +/************************************************************************** + Return TRUE if a tile is protected by a diplomat +**************************************************************************/ +bool is_diplomat_on_tile(int x, int y) +{ + unit_list_iterate(map_get_tile(x, y)->units, punit) + if (unit_flag(punit, F_DIPLOMAT)) { return TRUE; } + unit_list_iterate_end; + return FALSE; +} diff -uNrX freeciv/diff_ignore freeciv/server/diplomats.h freeciv-phased/server/diplomats.h --- freeciv/server/diplomats.h 2001-01-08 23:44:33.000000000 +0000 +++ freeciv-phased/server/diplomats.h 2002-08-08 04:44:53.000000000 +0000 @@ -39,6 +39,8 @@ struct city *pcity, int improvement); int count_diplomats_on_tile(int x, int y); +bool is_spy_on_tile(int x, int y); +bool is_diplomat_on_tile(int x, int y); int unit_bribe_cost(struct unit *punit); #endif /* FC__DIPLOMATS_H */ diff -uNrX freeciv/diff_ignore freeciv/server/stdinhand.c freeciv-phased/server/stdinhand.c --- freeciv/server/stdinhand.c 2002-08-07 23:43:40.000000000 +0000 +++ freeciv-phased/server/stdinhand.c 2002-08-08 04:44:53.000000000 +0000 @@ -1614,7 +1614,7 @@ int h[11] = { -1, H_NONE, H_NONE, - H_RATES | H_TARGETS | H_HUTS | H_DEFENSIVE, + H_RATES | H_TARGETS | H_HUTS | H_DEFENSIVE | H_DIPLOMAT, H_NONE, H_RATES | H_TARGETS | H_HUTS, H_NONE,