Complete.Org: Mailing Lists: Archives: freeciv-ai: January 2003:
[freeciv-ai] AI diplomacy v5 (PR#2413)
Home

[freeciv-ai] AI diplomacy v5 (PR#2413)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Cc: freeciv-ai@xxxxxxxxxxx
Subject: [freeciv-ai] AI diplomacy v5 (PR#2413)
From: "Per I. Mathisen via RT" <rt@xxxxxxxxxxxxxx>
Date: Fri, 3 Jan 2003 19:22:38 -0800
Reply-to: rt@xxxxxxxxxxxxxx

AI Diplomacy patch v5. Notable changes:
  - We now get pissed at allies who don't help us (although we still don't
remember such insults).
  - We break shared vision before going to war or ditching useless allies.
  - We talk like humans do. Well, almost. We're not entirely Turing
certified yet.
  - We do NOT give away our capital!
  - We do NOT betray our allies. Well, at least not if we don't really
mean to.
  - We try to become best pals with everyone if we lead the space race.
  - We try to pick fights with civilizations closer to our homeland rather
than that other guy on the other side of the map. Try to.
  - We know about teams, and don't backstab team members anymore.
  - We go straight to war if that is what we mean to do, not stopping by
neutrality.
  - We bitch at our friends even if we can't suggest treaties to them, if
they can to us.
  - We have a lots less bugs now than we used to. Really. And we have lots
of new interesting bugs, too!

Lots of thanks to Jordi Negrevernis i Font for bug reporting and
playtesting.

All the big features are in except hatred. A lot of tuning work remains to
do be done, but for that it needs playtesting. So go for it!

  - Per

/********************************************************************** 
 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__ADVATTITUDE_H
#define FC__ADVATTITUDE_H

struct player;
struct ai_choice;
struct Treaty;
struct Clause;
struct ai_data;

void ai_diplomacy_calculate(struct player *pplayer, struct ai_data *ai);

void ai_treaty_react(struct player *pplayer, struct player *aplayer, 
                     struct Clause *pclause);
void ai_treaty_evaluate(struct player *pplayer, struct player *aplayer,
                        struct Treaty *ptreaty);

#endif  /* FC__ADVATTITUDE_H */
/********************************************************************** 
 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 "city.h"
#include "tech.h"
#include "diptreaty.h"
#include "player.h"
#include "game.h"
#include "support.h"
#include "shared.h"
#include "packets.h"
#include "rand.h"
#include "log.h"
#include "events.h"
#include "mem.h"

#include "citytools.h"
#include "diplhand.h"
#include "plrhand.h"
#include "maphand.h"
#include "settlers.h"  /* amortize */
#include "spaceship.h"

#include "aidata.h"
#include "aitools.h"
#include "advmilitary.h"

#include "advdiplomacy.h"

#define LOG_DIPL LOG_NORMAL

/* Prototypes */
static int ai_goldequiv_city(struct city *pcity);
static int ai_goldequiv_tech(struct player *pplayer, Tech_Type_id tech);
static int ai_war_desire(struct player *pplayer, struct player *aplayer,
                         struct ai_data *ai);
static int ai_war_fear(struct player *pplayer, struct player *aplayer,
                         struct ai_data *ai);
static bool ai_attitude(struct ai_data *at, enum diplomacy_type dtype);
static int ai_goldequiv_clause(struct player *pplayer, struct player *aplayer, 
                               struct Clause *pclause, struct ai_data *ai);

/* PATCH TODO LIST:
        -> make "away" AI mode where the AI doesn't do diplomacy
        -> advmilitary.c, fix diplomat tech want excess
        -> ai_suggest_clauses(...), if balance is not ok?
        -> allow AIs to cheat an embassy on meet in beginning?
*/

/********************************************************************** 
NOTES ON THIS AI DIPLOMACY FILE:
 -> Be very careful with infinities - they can lead to overflows.
 -> Everything is measured in gold, even treaties. However, treaties
    are meant to be broken, if that is measured profitable.
 -> Some players can be give attitudes (see aidata.h). These can
    severely impair an ai's ability to pursue a diplomacy to its
    own gain, but it is very good for modpacks and easy difficulties.
 -> We rely on omniscience here. Really.
***********************************************************************/

/********************************************************************** 
  Send a diplomatic message. Use this instead of notify because we
  may want to highligh/present these messages differently in the
  future.

  TODO: Replace E_DIPLOMATIC_INCIDENT with a new type.
  TODO: Rewrite ...
***********************************************************************/
#define diplo_notify(pplayer, text, ...) \
  notify_player_ex(pplayer, -1, -1, E_DIPLOMATIC_INCIDENT, text, __VA_ARGS__);

#define TALK(x) "*" #x "(AI)* "

/********************************************************************** 
  Evaluate gold worth of a single clause in a treaty. Note that it
  sometimes matter a great deal who is giving what to whom, and
  sometimes (such as with treaties) it does not matter at all.
***********************************************************************/
static int ai_goldequiv_clause(struct player *pplayer, 
                               struct player *aplayer,
                               struct Clause *pclause,
                               struct ai_data *ai)
{
  int worth[MAX_NUM_PLAYERS]; /* worth of what X gives */
  int i;
  bool give = (pplayer == pclause->from);
  int receiver, giver;

  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
    worth[i] = 0;
  }

  giver = pclause->from->player_no;
  if (give) {
    receiver = aplayer->player_no;
  } else {
    receiver = pplayer->player_no;
  }

  switch (pclause->type) {
  case CLAUSE_ADVANCE: {
    int tech_cost;

    if (give) {
      tech_cost = ai_goldequiv_tech(aplayer, pclause->value);
    } else {
      tech_cost = ai_goldequiv_tech(pplayer, pclause->value);
    }

    /* Share and expect being shared brotherly between allies */
    if (pplayers_allied(pplayer, aplayer)) {
      tech_cost /= 10;
    }

    /* Calculate in tech leak to our enemies, guess 50% chance */
    if (give) { 
      players_iterate(eplayer) {
        if (pplayers_allied(aplayer, eplayer) && aplayer != eplayer
            && get_invention(eplayer, pclause->value) != TECH_KNOWN) {
          worth[eplayer->player_no] -= 
              ai_goldequiv_tech(eplayer, pclause->value) / 2;
        }
      } players_iterate_end;
    }
    worth[receiver] += tech_cost;
    /* FIXME: We should calculate use of tech for allies too, but we
       need to look just how the tech exchange code turns out 
       first. - Per */
  } break;

  case CLAUSE_ALLIANCE:
  case CLAUSE_PEACE:
  case CLAUSE_CEASEFIRE: {
    /* TODO: Note that right now most of this code is dead code because
     * we set war_desire to zero for everyone but our no 1 target at
     * another place in the code. - Per */
    int war_desire = ai->diplomacy.other[aplayer->player_no].war_desire;

    /* Attitude adjustment: Don't be too eager to get into a relationship
     * that you can't stomach getting out of. */
    if (ai_attitude(ai, DIP_BACKSTABBER)) {
      war_desire /= 1.5;
    }
    if (ai_attitude(ai, DIP_TRUSTWORTHY)) {
      war_desire *= 1.5;
    }

    /* Breaking treaties give us penalties on future diplomacy, so
     * avoid flip-flopping treaty/war with our enemy. */
    if (aplayer == ai->diplomacy.target 
        && !ai_attitude(ai, DIP_BACKSTABBER)) {
      war_desire *= 3;
    }

    /* No peace to our chosen victim if we are militarist */
    if (aplayer == ai->diplomacy.target 
        && ai_attitude(ai, DIP_MILITARIST)) {
      worth[pplayer->player_no] = -FC_INFINITY;
    }

    /* We don't want treaties that obstruct our aims, but if war_desire
       is negative then we want 'em this much. */
    worth[pplayer->player_no] += -(war_desire * TRADE_WEIGHTING
                                   * city_list_size(&aplayer->cities));
    freelog(LOG_DIPL, "(%s ai diplo) Calculating pact with %s as (%d*%d*%d=)%d",
            pplayer->name, aplayer->name,
            war_desire, TRADE_WEIGHTING, city_list_size(&aplayer->cities),
            worth[pplayer->player_no]);

    /* Modify for peace */
    if (pclause->type == CLAUSE_PEACE) { 
      if (!pplayers_non_attack(pplayer, aplayer)) {
        diplo_notify(aplayer, TALK(%s) "Let us first cease hostilies, %s",
                     pplayer->name, aplayer->name);
        return -FC_INFINITY;
      } else {
        worth[pplayer->player_no] *= 1.5;
      }
    }

    /* Modify for alliance */
    if (pclause->type == CLAUSE_ALLIANCE) {
      bool player_is_allied_with_ally = FALSE;
      players_iterate(check_pl) {
        /* We want to ally our ally's allies to prevent
         * ugly wars between allies */
        if (check_pl != pplayer && check_pl != aplayer
            && pplayers_allied(pplayer, check_pl)
            && pplayers_allied(aplayer, check_pl)) {
          player_is_allied_with_ally = TRUE;
        }
      } players_iterate_end;
      if (!pplayers_in_peace(pplayer, aplayer)) {
        diplo_notify(aplayer, TALK(%s) "Let us first cease hostilies, %s",
                     pplayer->name, aplayer->name);
        return -FC_INFINITY;
      } else if (!player_is_allied_with_ally) {
        worth[pplayer->player_no] *= 3;
      } else {
        /* Let's all join hands! */
        worth[pplayer->player_no] = 1;
      }
    }

    /* Modify for reputation */
    i = (GAME_DEFAULT_REPUTATION - aplayer->reputation) 
        * city_list_size(&aplayer->cities) / 4;
    if (i != 0) {
      worth[pplayer->player_no] -= i;
      freelog(LOG_DIPL, "(%s ai diplo) %s has reputation %d, penalised with 
%d", 
              pplayer->name, aplayer->name, aplayer->reputation, i);
    }
  } break;

  case CLAUSE_GOLD:
    worth[receiver] += pclause->value;
    break;

  case CLAUSE_SEAMAP:
    /* Very silly algorithm 1: Sea map more worth if enemy has more
       cities. Reasoning is he has more use of seamap for settling
       new areas the more cities he has already. */
    if (!give || pplayers_allied(pplayer, aplayer)) {
      /* Useless to us - we're omniscient! And allies get it for free! */
      worth[receiver] = 0;
      break;
    }
    worth[receiver] += 25 * city_list_size(&aplayer->cities);
    if (give && ai_attitude(ai, DIP_XENOPHOBE)) {
      worth[receiver] *= 3; /* "And what exactly do you want with this...?" */
    }
    break;

  case CLAUSE_MAP:
    /* Very silly algorithm 2: Land map more worth the more cities
       we have, since we expose all of these to the enemy. */
    if (!give || pplayers_allied(pplayer, aplayer)) {
      /* Useless to us - we're omniscient! And allies get it for free! */
      worth[receiver] = 0;
      break;
    }
    worth[receiver] += 75 * city_list_size(&pplayer->cities);
    /* Inflate numbers if not peace */
    if (!pplayers_in_peace(pplayer, aplayer)) { 
      if (!give && ai_attitude(ai, DIP_TRADER)) {
        worth[receiver] *= 2;
      } else if (give && ai_attitude(ai, DIP_MILITARIST)) {
        worth[receiver] *= 10;
      } else {
        worth[receiver] *= 3;
      }
    }
    if (give && ai_attitude(ai, DIP_XENOPHOBE)) { 
      worth[giver] -= FC_INFINITY; /* NEVER!!! */
    }
    break;

  case CLAUSE_CITY: {
    struct city *offer = city_list_find_id(&(pclause->from)->cities, 
                                           pclause->value);

    if (!offer || offer->owner != giver) {
      /* City destroyed or taken during negotiations */
      break;
    }
    worth[receiver] += ai_goldequiv_city(offer);
    if (give) {
      /* AI must be crazy to trade away its cities, but traders do/are */
      if (ai_attitude(ai, DIP_TRADER) 
          && pplayers_in_peace(pplayer, aplayer)) {
        worth[receiver] *= 2;
      } else {
        worth[receiver] *= 15;
      }
      if (city_got_building(offer, B_PALACE)) {
        worth[receiver] = FC_INFINITY; /* never! */
      }
    }
    break;
  }

  case CLAUSE_VISION:
    if (give) {
      if (pplayers_allied(pplayer, aplayer)) {
        worth[receiver] = 0;
      } else {
        /* so out of the question */
        worth[receiver] += FC_INFINITY;
      }
    } else {
      worth[receiver] = 1; /* We are omniscient, so... */
    }
    break;
  } /* end of switch */

  i = 0; /* balance */

  /* Check externalities */
  players_iterate(eplayer) {
    /* We are supposed to give away something, check how this benefits
       our enemies */
    if (give && eplayer != aplayer && pplayers_at_war(eplayer, pplayer)) {
      i += worth[eplayer->player_no]; 
    }
    /* We receive something, check how this benefits our friends */
    if (!give && eplayer != pplayer && eplayer != aplayer 
        && pplayers_allied(eplayer, pplayer)) {
      i -= worth[eplayer->player_no];
    }
  } players_iterate_end;

  /* wrt pplayer */
  i += worth[pplayer->player_no]; 
  i -= worth[aplayer->player_no];

  /* Returns balance of what they offer vs what we offer */
  if (give) {
    freelog(LOG_DIPL, "(%s ai diplo) evaluating clause from %s to %s as worth 
%d",
            pplayer->name, pplayer->name, aplayer->name, i);
  } else {
    freelog(LOG_DIPL, "(%s ai diplo) evaluating clause from %s to %s as worth 
%d",
           pplayer->name, aplayer->name, pplayer->name, i);
  }
  return i;
}

/********************************************************************** 
  pplayer is AI player, aplayer is the other player involved, treaty
  is the treaty being considered. It is all a question about money :-)
***********************************************************************/
void ai_treaty_evaluate(struct player *pplayer, struct player *aplayer,
                        struct Treaty *ptreaty)
{
  struct packet_diplomacy_info packet;
  int balance = 0;
  bool has_treaty = FALSE;
  struct ai_data *ai = ai_data_get(pplayer);

  assert(!is_barbarian(pplayer));

  packet.plrno0 = pplayer->player_no;
  packet.plrno1 = aplayer->player_no;
  packet.plrno_from = pplayer->player_no;

  /* Evaluate clauses */
  clause_list_iterate(ptreaty->clauses, pclause) {
    balance += ai_goldequiv_clause(pplayer, aplayer, pclause, ai);
    if (is_pact_clause(pclause->type)) {
      has_treaty = TRUE;
    }
  } clause_list_iterate_end;

  /* If we are at war, and no peace is offered, then no deal */
  if (pplayers_at_war(pplayer, aplayer) && !has_treaty) {
    return;
  }

  /* Accept if balance is good */
  if (balance >= 0) {
    handle_diplomacy_accept_treaty(pplayer, &packet);
  }
}

/********************************************************************** 
  Reactions from AI on clauses being agreed on.
***********************************************************************/
void ai_treaty_react(struct player *pplayer,
                     struct player *aplayer,
                     struct Clause *pclause)
{
  switch (pclause->type) {
    case CLAUSE_ALLIANCE:
      diplo_notify(aplayer, TALK(%s) "Yes, may we forever stand united, %s",
                   pplayer->name, aplayer->name);
      freelog(LOG_NORMAL, "(%s ai diplo) %s allies with %s!",
              pplayer->name, pplayer->name, aplayer->name);
      break;
    case CLAUSE_PEACE:
      diplo_notify(aplayer, TALK(%s) "Yes, peace in our time!",
                   pplayer->name);
      freelog(LOG_NORMAL, "(%s ai diplo) %s makes peace with %s",
              pplayer->name, pplayer->name, aplayer->name);
      break;
    case CLAUSE_CEASEFIRE:
      diplo_notify(aplayer, TALK(%s) "Agreed. No more hostilities, %s",
                   pplayer->name, aplayer->name);
      freelog(LOG_NORMAL, "(%s ai diplo) %s agrees to ceasefire with %s",
              pplayer->name, pplayer->name, aplayer->name);
      break;
    default:
      break;
  }
}

/********************************************************************** 
  Return TRUE iff given player has given attitude.
***********************************************************************/
static bool ai_attitude(struct ai_data *ai, enum diplomacy_type dtype)
{
  return BOOL_VAL(ai->diplomacy.personality & dtype);
}

/********************************************************************** 
  Check if we can win by space race victory. We can do this if we have
  a spacerace lead.
***********************************************************************/
static bool ai_space_victory(struct player *pplayer, struct ai_data *ai)
{
  struct player_spaceship *our_ship = &pplayer->spaceship;
  int our_arrival = MAX((int) our_ship->travel_time -
                        - (game.year - our_ship->launch_year), 1);

  if (game.spacerace == FALSE || our_ship->state == SSHIP_NONE) {
    return FALSE;
  }

  players_iterate(aplayer) {
    struct player_spaceship *enemy_ship = &aplayer->spaceship;
    int enemy_arrival = MAX((int) enemy_ship->travel_time -
                            - (game.year - enemy_ship->launch_year), 1);

    if (enemy_ship->state > our_ship->state) {
      return FALSE;
    }
    if (enemy_ship->state == SSHIP_LAUNCHED
        && our_ship->state == SSHIP_LAUNCHED
        && enemy_arrival >= our_arrival) {
      return FALSE;
    }
  } players_iterate_end;

  return TRUE;
}

/********************************************************************** 
  Calculate our desire to go to war against aplayer (or our hatred of
  aplayer).
***********************************************************************/
static int ai_war_desire(struct player *pplayer, struct player *aplayer,
                         struct ai_data *ai)
{
  int kill_desire, arrival, our_arrival;
  struct player_spaceship *ship = &aplayer->spaceship;
  struct player_spaceship *our_ship = &pplayer->spaceship;

  /* Show some weakness */
  if (!pplayers_at_war(pplayer, aplayer)
      && ai_attitude(ai, DIP_TRUSTWORTHY)) {
    return 0;
  }

  /* We can aim for an allied victory */
  if (!ai_attitude(ai, DIP_MEGALOMANIAC)
      && pplayers_allied(pplayer, aplayer)) {
    return 0;
  }

  /* Number of cities is a player's base potential. */
  kill_desire = city_list_size(&aplayer->cities);

  /* Count settlers in production for us, indicating our expansionism,
   * while counting all enemy settlers as (worst case) indicators of
   * enemy expansionism */
  city_list_iterate(pplayer->cities, pcity) {
    if (pcity->is_building_unit 
        && unit_type_flag(pcity->currently_building, F_CITIES)) {
      kill_desire -= 1;
    }
  } city_list_iterate_end;
  unit_list_iterate(aplayer->units, punit) { 
    if (unit_flag(punit, F_CITIES)) { kill_desire += 1; }
  } unit_list_iterate_end;

  /* Count big cities as twice the threat */
  city_list_iterate(aplayer->cities, pcity) {
    kill_desire += pcity->size > 8 ? 1 : 0;
  } city_list_iterate_end;

  /* Tech lead is worrisome */
  kill_desire += MAX(aplayer->research.techs_researched -
                     pplayer->research.techs_researched, 0);

  /* Spacerace loss we will not allow! */
  if (ship->state >= SSHIP_STARTED) {
    /* add potential */
    kill_desire += city_list_size(&aplayer->cities);
  }
  if (our_ship->state >= SSHIP_LAUNCHED) { 
    our_arrival = MAX((int) our_ship->travel_time - 
        (game.year - our_ship->launch_year), 1);
  } else { our_arrival = FC_INFINITY; }
  if (ship->state >= SSHIP_LAUNCHED) { 
    arrival = MAX((int) ship->travel_time - 
        (game.year - ship->launch_year), 1);
    if (arrival < our_arrival) {
      /* The first division is for the unlikely case of several 
         simultaneous ship launches, the second to avoid overflows */
      kill_desire = FC_INFINITY / arrival / 2;
      ai->diplomacy.timer = FC_INFINITY;
      ai->diplomacy.strategy = WIN_CAPITAL;
    }
  }

  /* Jealousy */
  /* FIME: add score comparisons here, but add code for cacheing
     score results first, or we will spam the CPU - Per */

  /* Amortize by distance */
  return amortize(kill_desire, 
                  ai->diplomacy.other[aplayer->player_no].distance);
}

/********************************************************************** 
  Calculate relative military strength of us vs him
  TODO: special checks for nukes (they inflate our numbers), and 
  add in allies
***********************************************************************/
static int ai_war_fear(struct player *pplayer, struct player *aplayer,
                       struct ai_data *ai)
{
  int them = 1;

  /* relative military strength */
  unit_list_iterate(aplayer->units, punit) {
    them += ai_unit_attack_desirability(punit->type);
  } unit_list_iterate_end;

  return (them / ai->diplomacy.mil_strength) 
         - (ai->diplomacy.mil_strength / them);
}

/********************************************************************** 
  How much is tech worth to player measured in gold
***********************************************************************/
static int ai_goldequiv_tech(struct player *pplayer, Tech_Type_id tech)
{
  int worth;

  if (get_invention(pplayer, tech) == TECH_KNOWN) {
    return 0;
  }
  worth = total_bulbs_required_for_goal(pplayer, tech) * TRADE_WEIGHTING;
  worth += pplayer->ai.tech_want[tech] / 8; /* often way too much */
  if (get_invention(pplayer, tech) == TECH_REACHABLE) {
    worth /= 2;
  }
  freelog(LOG_DIPL, "(%s ai diplo) %s goldequiv'ed to %d (had want %d)",
          pplayer->name, get_tech_name(pplayer, tech), worth, 
          pplayer->ai.tech_want[tech]);

  return worth;
}

/********************************************************************** 
  How much is city worth measured in gold
***********************************************************************/
static int ai_goldequiv_city(struct city *pcity)
{
  int worth;
  struct player *pplayer = city_owner(pcity);

  worth = pcity->size * 150; /* reasonable base cost */
  built_impr_iterate(pcity, impr) {
    if (improvement_types[impr].is_wonder && !wonder_obsolete(impr)) {
      worth += improvement_types[impr].build_cost;
    } else {
      worth += (improvement_types[impr].build_cost / 4);
    }
  } built_impr_iterate_end;
  if (city_unhappy(pcity)) {
    worth *= 0.75;
  }
  freelog(LOG_DIPL, "(%s ai diplo) city %s goldequiv'ed to %d", 
          pplayer->name, pcity->name, worth);

  return worth;
}

/********************************************************************** 
  Suggest a treaty from pplayer to aplayer
***********************************************************************/
static void ai_diplomacy_suggest(struct player *pplayer, 
                                 struct player *aplayer,
                                 enum clause_type what)
{
  struct packet_diplomacy_info packet;

  if (!player_has_embassy(pplayer, aplayer)) {
    return;
  }

  packet.plrno_from = pplayer->player_no;
  packet.plrno0 = pplayer->player_no;
  packet.plrno1 = aplayer->player_no;
  packet.clause_type = what;
  packet.value = 0; /* dummy */

  handle_diplomacy_init(pplayer, &packet);
  handle_diplomacy_create_clause(pplayer, &packet);
}

/********************************************************************** 
  Only ever called for AI players and never for barbarians.
***********************************************************************/
void ai_diplomacy_calculate(struct player *pplayer, struct ai_data *ai)
{
  int war_desire = 0;
  int war_fear = 0;
  struct player *target = NULL;
  struct city *palace = find_palace(pplayer);

  if (!pplayer->is_alive) {
    return; /* doh */
  }

  /* Stop war against a dead player */
  if (ai->diplomacy.target && !ai->diplomacy.target->is_alive) {
    freelog(LOG_DIPL, "(%s ai diplo) Target player %s is dead. Victory!",
            pplayer->name, ai->diplomacy.target->name);
    ai->diplomacy.timer = 0;
    ai->diplomacy.target = NULL;
    if (ai->diplomacy.strategy == WIN_CAPITAL) {
      ai->diplomacy.strategy = WIN_OPEN;
    }
  }

  /* Calculate our military strength */
  ai->diplomacy.mil_strength = 1;
  unit_list_iterate(pplayer->units, punit) {
     ai->diplomacy.mil_strength += ai_unit_attack_desirability(punit->type);
  } unit_list_iterate_end;

  /* Ensure that we don't prematurely end an ongoing war */
  if (ai->diplomacy.timer-- > 0) {
    return;
  }

  /*
   * Calculate average distances to other players' empires. A
   * possibly unwarranted assumption here is that our palace will
   * be located in the middle of our empire. If we don't have one, punt.
   */
  players_iterate(aplayer) {
    int cities = 0;
    int dists = 0;

    if (pplayer == aplayer || !palace) {
      ai->diplomacy.other[aplayer->player_no].distance = 0;
      continue;
    }

    city_list_iterate(aplayer->cities, pcity) {
      cities++;
      dists += real_map_distance(palace->x, palace->y, pcity->x, pcity->y);
    } city_list_iterate_end;

    if (cities > 0) {
      ai->diplomacy.other[aplayer->player_no].distance = dists / cities;
    } else {
      ai->diplomacy.other[aplayer->player_no].distance = 0;
    }
  } players_iterate_end;

  /* Can we win by space race? */
  if (ai_space_victory(pplayer, ai)) {
    freelog(LOG_DIPL, "%s going for space race victory!", pplayer->name);
    ai->diplomacy.strategy = WIN_SPACE; /* Yes! */
  }

  /* Calculate our fears and desires, and find desired war target */
  players_iterate(aplayer) {
    enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
    bool want_avoid_war = FALSE;

    /* We don't fear/hate ourselves, those we don't know and those we're
     * allied to (unless we're the backstabbing type) or team members. */
    if (aplayer == pplayer
        || ds == DS_NO_CONTACT
        || (pplayer->team != TEAM_NONE && pplayer->team == aplayer->team)
        || (ds == DS_ALLIANCE && !ai_attitude(ai, DIP_BACKSTABBER))) {
      ai->diplomacy.other[aplayer->player_no].war_desire = 0;
      ai->diplomacy.other[aplayer->player_no].war_fear = 0;
      continue;
    }
    ai->diplomacy.other[aplayer->player_no].war_fear =
      ai_war_fear(pplayer, aplayer, ai);
    ai->diplomacy.other[aplayer->player_no].war_desire =
      ai_war_desire(pplayer, aplayer, ai);

    /* We don't want war if we can win through the space race. */
    if (ai->diplomacy.strategy == WIN_SPACE) {
      ai->diplomacy.other[aplayer->player_no].war_desire /= 3;
      want_avoid_war = TRUE;
      continue;
    }

    /* Loyalty: hate our allies' enemies */
    players_iterate(eplayer) {
      if (pplayers_allied(pplayer, eplayer)
          && !ai_attitude(ai, DIP_BACKSTABBER)
          && pplayers_at_war(aplayer, eplayer)) {
        ai->diplomacy.other[aplayer->player_no].war_desire *= 3;
        want_avoid_war = FALSE;
      }
    } players_iterate_end;

    /* Chicken out */
    if (want_avoid_war) {
      freelog(LOG_DIPL, "%s chickening out from war_desire with %s",
              pplayer->name, aplayer->name);
      ai->diplomacy.other[aplayer->player_no].war_desire = -1;
      continue;
    }

    /* Strongly prefer players we are at war with already */
    if (pplayers_non_attack(pplayer, aplayer)) {
      ai->diplomacy.other[aplayer->player_no].war_desire /= 2;
    }
    freelog(LOG_DIPL, "(%s ai diplo) Against %s we have war desire "
            "%d and fear %d", pplayer->name, aplayer->name,
            ai->diplomacy.other[aplayer->player_no].war_desire,
            ai->diplomacy.other[aplayer->player_no].war_fear);

    /* Find best target */
    if (ai->diplomacy.other[aplayer->player_no].war_desire > war_desire) {
      target = aplayer;
      war_desire = ai->diplomacy.other[aplayer->player_no].war_desire;
      war_fear = ai->diplomacy.other[aplayer->player_no].war_fear;
    }
  } players_iterate_end;

  if (!target) {
    freelog(LOG_DEBUG, "(%s ai diplo) Found no target.", pplayer->name);
    ai->diplomacy.target = NULL;
    return;
  }

  if (target != ai->diplomacy.target) {
    if (ai->diplomacy.target) {
      freelog(LOG_DIPL, "(%s ai diplo) Changing target from %s to %s",
              pplayer->name, ai->diplomacy.target->name, target->name);
    } else {
      freelog(LOG_DIPL, "(%s ai diplo) Setting target to %s",
              pplayer->name, target->name);
    }
    ai->diplomacy.target = target;
    players_iterate(aplayer) {
      ai->diplomacy.other[aplayer->player_no].ally_patience = 0;
    } players_iterate_end;
  }
  if (!pplayers_at_war(pplayer, target)) {
    freelog(LOG_DIPL, "(%s ai diplo) Declaring war on %s",
            pplayer->name, target->name);
    diplo_notify(target, TALK(%s) "Peace in ... some other time", 
                 pplayer->name);
    if (gives_shared_vision(pplayer, target)) {
      remove_shared_vision(pplayer, target);
    }
    while (!pplayers_at_war(pplayer, target)) {
      handle_player_cancel_pact(pplayer, target->player_no);
    }
    /* continue war at least in this arbitrary number of turns to show 
     * some spine */
    ai->diplomacy.timer = 6;
  }

  /* Opportunism, Inc */
  players_iterate(aplayer) {
    enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;

    if (is_barbarian(aplayer)    /* no barbarism */
        || aplayer == pplayer    /* no self-indulgence */
        || aplayer == target     /* no mercy */
        || !aplayer->is_alive    /* and no necromancy! */
        || aplayer->reputation < GAME_DEFAULT_REPUTATION / 2) {
      continue; /* hah! */
    }

    /* Is there a player with whom we are allied to which is at
     * war with this player? If so, keep war going. */
    players_iterate(eplayer) {
      if (pplayers_allied(pplayer, eplayer)
          && pplayers_at_war(aplayer, eplayer)) {
        continue;
      }
    } players_iterate_end;

    /* Talk is cheap, and so is peace, so fake friendliness */
    ai->diplomacy.other[aplayer->player_no].war_desire = -1;
    /* Spam control */
    if (ai->diplomacy.other[aplayer->player_no].spam > 0) {
      ai->diplomacy.other[aplayer->player_no].spam--;
    }
    if ((!player_has_embassy(pplayer, aplayer)
         && !player_has_embassy(aplayer, pplayer))
        || ds == DS_NO_CONTACT) {
      continue;
    }
    if (ai->diplomacy.other[aplayer->player_no].spam > 0) {
      /* Don't spam */
      continue;
    }
    /* Canvass support from existing friends for our war, and try to
     * make friends with enemies. Then we wait some turns until next time
     * we spam them with our gibbering chatter. */
    ai->diplomacy.other[aplayer->player_no].spam = myrand(4)+3;
    switch (ds) {
      case DS_ALLIANCE:
      if (pplayers_at_war(aplayer, target)) {
        break;
      }
      freelog(LOG_DIPL, "(%s ai diplo) demanding support from %s to crush %s",
              pplayer->name, aplayer->name, target->name);
      switch (ai->diplomacy.other[aplayer->player_no].ally_patience--) {
        case 0:
        diplo_notify(aplayer, TALK(%s) "Greetings our most trustworthy ally, "
                     "we call upon you to destroy our enemy, %s", pplayer->name,
                     target->name);
        break;
        case -1:
        diplo_notify(aplayer, TALK(%s) "Greetings ally, I see you have not yet "
                     "made war with our enemy, %s. Why do I need to remind "
                     "you of your promises?", pplayer->name, target->name);
        break;
        case -2:
        diplo_notify(aplayer, TALK(%s) "Dishonoured one, we made a pact of "
                     "alliance, and yet you remain at peace with our mortal "
                     "enemy, %s! This is unacceptable, our alliance is no "
                     "more!", pplayer->name, target->name);
        freelog(LOG_DIPL, "(%s ai diplo) breaking useless alliance with %s",
                pplayer->name, aplayer->name);
        handle_player_cancel_pact(pplayer, aplayer->player_no);
        if (gives_shared_vision(pplayer, aplayer)) {
          remove_shared_vision(pplayer, aplayer);
        }
        break;
      }
      break;

      case DS_PEACE:
      ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_ALLIANCE);
      diplo_notify(aplayer, TALK(%s) "Greetings friend, may we suggest "
                   "a joint campaign against %s?", pplayer->name, target->name);
      freelog(LOG_DIPL, "(%s ai diplo) requesting support from %s to crush %s",
              pplayer->name, aplayer->name, target->name);
      break;

      case DS_CEASEFIRE:
      case DS_NEUTRAL:
      ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_PEACE);
      diplo_notify(aplayer, TALK(%s) "Greetings friend, may we suggest "
                   "a joint campaign against %s?", pplayer->name, target->name);
      freelog(LOG_DIPL, "(%s ai diplo) requesting support from %s to crush %s",
              pplayer->name, aplayer->name, target->name);
      break;

      case DS_WAR:
      diplo_notify(aplayer, TALK(%s) "%s is threatening us both, may we suggest"
                   " a cessation of hostilities?", pplayer->name, target->name);
      freelog(LOG_DIPL, "(%s ai diplo) requesting peace from %s to crush %s",
              pplayer->name, aplayer->name, target->name);
      ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_CEASEFIRE);
      break;

      default:
      assert(FALSE);
      break;
    }
  } players_iterate_end;
}
? ai/advdiplomacy.c
? ai/advdiplomacy.h
Index: ai/Makefile.am
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/Makefile.am,v
retrieving revision 1.12
diff -u -r1.12 Makefile.am
--- ai/Makefile.am      2002/11/25 19:18:08     1.12
+++ ai/Makefile.am      2003/01/04 03:14:05
@@ -21,6 +21,8 @@
                advmilitary.h   \
                advscience.c    \
                advscience.h    \
+               advdiplomacy.c  \
+               advdiplomacy.h  \
                advspace.c      \
                advspace.h      \
                advtrade.c      \
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.7
diff -u -r1.7 aidata.c
--- ai/aidata.c 2003/01/02 11:59:29     1.7
+++ ai/aidata.c 2003/01/04 03:14:05
@@ -26,10 +26,12 @@
 #include "mem.h"
 
 #include "citytools.h"
+#include "diplhand.h"
+#include "maphand.h"
 #include "settlers.h"
 #include "unittools.h"
-#include "maphand.h"
 
+#include "advdiplomacy.h"
 #include "advmilitary.h"
 #include "aicity.h"
 #include "aitools.h"
@@ -192,6 +194,12 @@
     }
   } unit_list_iterate_end;
 
+  /* Diplomacy */
+
+  if (pplayer->ai.control && !is_barbarian(pplayer)) {
+    ai_diplomacy_calculate(pplayer, ai);
+  }
+
   /* 
    * Priorities. NEVER set these to zero! Weight values are usually
    * multiplied by these values, so be careful with them. They are
@@ -219,6 +227,33 @@
   free(ai->threats.continent); ai->threats.continent = NULL;
   free(ai->stats.workers);     ai->stats.workers = NULL;
   free(ai->stats.cities);      ai->stats.cities = NULL;
+
+  /* Otherwise our meeting schedule will be so full we won't have time
+   * for new offerings! Note that I find this acceptable for human players
+   * trying to talk to AI players, since AI players respond immediately. */
+  cancel_all_meetings(pplayer);
+}
+
+/**************************************************************************
+  Initialize with sane values
+**************************************************************************/
+void ai_data_init(struct player *pplayer) {
+  struct ai_data *ai = &aidata[pplayer->player_no];
+  int i;
+
+  ai->diplomacy.target = NULL;
+  ai->diplomacy.strategy = WIN_OPEN;
+  ai->diplomacy.timer = 0;
+  ai->diplomacy.personality = 0;
+  ai->diplomacy.mil_strength = 0;
+
+  for (i = 0; i < MAX_NUM_PLAYERS; i++) {
+    ai->diplomacy.other[i].war_desire = 0;
+    ai->diplomacy.other[i].war_fear = 0;
+    ai->diplomacy.other[i].spam = 0;
+    ai->diplomacy.other[i].distance = 0;
+    ai->diplomacy.other[i].ally_patience = 0;
+  }
 }
 
 /**************************************************************************
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.5
diff -u -r1.5 aidata.h
--- ai/aidata.h 2003/01/02 11:59:29     1.5
+++ ai/aidata.h 2003/01/04 03:14:05
@@ -24,7 +24,43 @@
  * start of every turn. 
  */
 
+enum winning_strategy {
+  WIN_OPEN,     /* still undetermined */
+  WIN_WAR,      /* we have no other choice than to crush all opposition */
+  WIN_SPACE,    /* we will race for space, peace very important */
+  WIN_CAPITAL   /* we cannot win unless we take war_target's capital */
+};
+
+/* FIXME: these should be set by difficulty and civworld */
+enum diplomacy_type {
+  DIP_NONE = 0,         /* No attitude */
+  DIP_PACIFIST = 1,     /* War desire -50% if positive */
+  DIP_MILITARIST = 2,   /* War desire +50% if positive */
+  DIP_TRADER = 4,       /* Worth of our offer -25%, trade cities */
+  DIP_GREEDY = 8,       /* Worth of our offer +50% */
+  DIP_XENOPHOBE = 16,   /* Only ever agrees to ceasefire and tech */
+  DIP_TRUSTWORTHY = 32, /* Does not break treaties unless violated */
+  DIP_BACKSTABBER = 64, /* Happily agrees to anything and then... */
+  DIP_MEGALOMANIAC = 128/* Does not share victory */
+};
+
 struct ai_data {
+  /* AI diplomacy */
+  struct {
+    enum winning_strategy strategy;
+    int timer; /* pursue our goals with some stubbornness, in turns */
+    struct {
+      int war_desire; /* desire for war or peace */
+      int war_fear;   /* fear of this player's military might */
+      int spam;       /* timer to avoid spamming a player with chat */
+      int distance;   /* average distance to that player's cities */
+      int ally_patience; /* we EXPECT our allies to help us! */
+    } other[MAX_NUM_PLAYERS];
+    struct player *target;    /* concentrate on this player */
+    int mil_strength;         /* Estimate of our military strength */
+    int personality;          /* Personality traits */
+  } diplomacy;
+
   /* Long-term threats, not to be confused with short-term danger */
   struct {
     bool invasions;   /* check if we need to consider invasions */
@@ -63,6 +99,8 @@
   int angry_priority;
   int pollution_priority;
 };
+
+void ai_data_init(struct player *pplayer);
 
 void ai_data_turn_init(struct player *pplayer);
 void ai_data_turn_done(struct player *pplayer);
Index: client/civclient.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v
retrieving revision 1.159
diff -u -r1.159 civclient.c
--- client/civclient.c  2003/01/01 11:51:32     1.159
+++ client/civclient.c  2003/01/04 03:14:05
@@ -815,6 +815,30 @@
 }
 
 /**************************************************************************
+  Returns TRUE iff the client can do diplomatic meetings with another 
+  given player.
+**************************************************************************/
+bool can_meet_with_player(struct player *pplayer)
+{
+  return (pplayer->is_alive
+          && pplayer != game.player_ptr
+          && player_has_embassy(game.player_ptr, pplayer)
+          && (pplayer->is_connected || pplayer->ai.control)
+          && can_client_issue_orders());
+}
+
+/**************************************************************************
+  Returns TRUE iff the client can get intelligence from another 
+  given player.
+**************************************************************************/
+bool can_intel_with_player(struct player *pplayer)
+{
+  return (pplayer->is_alive
+          && pplayer != game.player_ptr
+          && player_has_embassy(game.player_ptr, pplayer));
+}
+
+/**************************************************************************
   Return TRUE if the client can change the view; i.e. if the mapview is
   active.  This function should be called each time before allowing the
   user to do mapview actions.
Index: client/civclient.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/civclient.h,v
retrieving revision 1.25
diff -u -r1.25 civclient.h
--- client/civclient.h  2003/01/01 11:51:32     1.25
+++ client/civclient.h  2003/01/04 03:14:05
@@ -56,6 +56,8 @@
 void real_timer_callback(void);
 bool can_client_issue_orders(void);
 bool can_client_change_view(void);
+bool can_meet_with_player(struct player *pplayer);
+bool can_intel_with_player(struct player *pplayer);
 
 void client_game_init(void);
 void client_game_free(void);
Index: client/gui-gtk/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/plrdlg.c,v
retrieving revision 1.43
diff -u -r1.43 plrdlg.c
--- client/gui-gtk/plrdlg.c     2003/01/01 11:51:33     1.43
+++ client/gui-gtk/plrdlg.c     2003/01/04 03:14:05
@@ -499,20 +499,10 @@
                           can_client_issue_orders()
                           && gives_shared_vision(game.player_ptr, pplayer));
 
-  if (pplayer->is_alive 
-      && pplayer != game.player_ptr
-      && player_has_embassy(game.player_ptr, pplayer)) {
-    if (pplayer->is_connected)
-      gtk_widget_set_sensitive(players_meet_command,
-                              can_client_issue_orders());
-    else
-      gtk_widget_set_sensitive(players_meet_command, FALSE);
-    gtk_widget_set_sensitive(players_int_command, TRUE);
-    return;
-  }
-
-  gtk_widget_set_sensitive(players_meet_command, FALSE);
-  gtk_widget_set_sensitive(players_int_command, FALSE);
+  gtk_widget_set_sensitive(players_meet_command,
+                           can_meet_with_player(pplayer));
+  gtk_widget_set_sensitive(players_int_command,
+                           can_intel_with_player(pplayer));
 }
 
 void players_list_ucallback(GtkWidget *w, gint row, gint column)
Index: client/gui-gtk-2.0/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/plrdlg.c,v
retrieving revision 1.13
diff -u -r1.13 plrdlg.c
--- client/gui-gtk-2.0/plrdlg.c 2002/12/30 02:32:02     1.13
+++ client/gui-gtk-2.0/plrdlg.c 2003/01/04 03:14:05
@@ -161,13 +161,9 @@
     gtk_widget_set_sensitive(players_vision_command,
       gives_shared_vision(game.player_ptr, plr));
 
-    if (plr->is_alive
-        && plr != game.player_ptr
-        && player_has_embassy(game.player_ptr, plr)) {
-      gtk_widget_set_sensitive(players_meet_command, plr->is_connected);
-      gtk_widget_set_sensitive(players_int_command, TRUE);
-      return;
-    }
+    gtk_widget_set_sensitive(players_meet_command, can_meet_with_player(plr));
+    gtk_widget_set_sensitive(players_int_command, can_intel_with_player(plr));
+    return;
   }
 
   gtk_widget_set_sensitive(players_meet_command, FALSE);
Index: client/gui-mui/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-mui/plrdlg.c,v
retrieving revision 1.25
diff -u -r1.25 plrdlg.c
--- client/gui-mui/plrdlg.c     2002/11/14 09:14:57     1.25
+++ client/gui-mui/plrdlg.c     2003/01/04 03:14:05
@@ -208,17 +208,10 @@
     set(player_vision_button, MUIA_Disabled,
        !gives_shared_vision(game.player_ptr, pplayer));
 
-    if (pplayer->is_alive
-        && pplayer != game.player_ptr
-        && player_has_embassy(game.player_ptr, pplayer))
-    {
-      if (pplayer->is_connected)
-       set(player_meet_button, MUIA_Disabled, FALSE);
-      else
-       set(player_meet_button, MUIA_Disabled, TRUE);
-      set(player_intelligence_button, MUIA_Disabled, FALSE);
-      return;
-    }
+    set(player_meet_button, MUIA_Disabled, !can_meet_with_player(pplayer));
+    set(player_intelligence_button, MUIA_Disabled, 
+        !can_intel_with_player(pplayer));
+    return;
   }
 
   set(player_meet_button, MUIA_Disabled, TRUE);
Index: client/gui-win32/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-win32/plrdlg.c,v
retrieving revision 1.10
diff -u -r1.10 plrdlg.c
--- client/gui-win32/plrdlg.c   2002/11/14 09:14:59     1.10
+++ client/gui-win32/plrdlg.c   2003/01/04 03:14:05
@@ -237,19 +237,10 @@
   EnableWindow(GetDlgItem(players_dialog, ID_PLAYERS_VISION),
               gives_shared_vision(game.player_ptr, pplayer));
 
-  if (pplayer->is_alive 
-      && pplayer != game.player_ptr
-      && player_has_embassy(game.player_ptr, pplayer)) {
-    if (pplayer->is_connected)
-      EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_MEET), TRUE);
-    else
-      EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_MEET), FALSE);
-    EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_INT), TRUE);
-    return;
-  }
-
-  EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_MEET), FALSE);
-  EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_INT), FALSE);
+  EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_MEET),
+               can_meet_with_player(pplayer));
+  EnableWindow(GetDlgItem(players_dialog,ID_PLAYERS_INT),
+               can_intel_with_player(pplayer));
 }
 
 /******************************************************************
Index: client/gui-xaw/plrdlg.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/gui-xaw/plrdlg.c,v
retrieving revision 1.34
diff -u -r1.34 plrdlg.c
--- client/gui-xaw/plrdlg.c     2002/11/29 20:11:59     1.34
+++ client/gui-xaw/plrdlg.c     2003/01/04 03:14:06
@@ -310,16 +310,8 @@
     XtSetSensitive(players_vision_command,
                   gives_shared_vision(game.player_ptr, pplayer));
 
-    if (pplayer->is_alive
-        && pplayer != game.player_ptr
-        && player_has_embassy(game.player_ptr, pplayer)) {
-      if(pplayer->is_connected)
-       XtSetSensitive(players_meet_command, TRUE);
-      else
-       XtSetSensitive(players_meet_command, FALSE);
-      XtSetSensitive(players_int_command, TRUE);
-      return;
-    }
+    XtSetSensitive(players_meet_command, can_meet_with_player(pplayer));
+    XtSetSensitive(players_int_command, can_intel_with_player(pplayer));
   }
   XtSetSensitive(players_meet_command, FALSE);
   XtSetSensitive(players_int_command, FALSE);
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.105
diff -u -r1.105 player.c
--- common/player.c     2002/12/16 05:35:31     1.105
+++ common/player.c     2003/01/04 03:14:06
@@ -610,6 +610,23 @@
 }
 
 /***************************************************************
+  Returns true iff players are allied or at peace.
+***************************************************************/
+bool pplayers_in_peace(const struct player *pplayer,
+                       const struct player *pplayer2)
+{
+  enum diplstate_type ds = pplayer_get_diplstate(pplayer, pplayer2)->type;
+
+  if (pplayer == pplayer2) {
+    return TRUE;
+  }
+  if (is_barbarian(pplayer) || is_barbarian(pplayer2)) {
+    return FALSE;
+  }
+  return (ds == DS_ALLIANCE || ds == DS_PEACE);
+}
+
+/***************************************************************
 returns true iff players have peace or cease-fire
 ***************************************************************/
 bool pplayers_non_attack(const struct player *pplayer,
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.89
diff -u -r1.89 player.h
--- common/player.h     2002/12/16 05:35:31     1.89
+++ common/player.h     2003/01/04 03:14:06
@@ -257,6 +257,8 @@
                    const struct player *pplayer2);
 bool pplayers_allied(const struct player *pplayer,
                    const struct player *pplayer2);
+bool pplayers_in_peace(const struct player *pplayer,
+                    const struct player *pplayer2);
 bool pplayers_non_attack(const struct player *pplayer,
                        const struct player *pplayer2);
 
Index: server/diplhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v
retrieving revision 1.65
diff -u -r1.65 diplhand.c
--- server/diplhand.c   2002/11/15 21:24:30     1.65
+++ server/diplhand.c   2003/01/04 03:14:07
@@ -37,6 +37,8 @@
 #include "settlers.h"
 #include "unittools.h"
 
+#include "advdiplomacy.h"
+
 #include "diplhand.h"
 
 #define SPECLIST_TAG treaty
@@ -286,6 +288,8 @@
       pgiver = pclause->from;
       pdest = (plr0==pgiver) ? plr1 : plr0;
 
+      ai_treaty_react(pgiver, pdest, pclause);
+
       switch (pclause->type) {
       case CLAUSE_ADVANCE:
        notify_player_ex(pdest, -1, -1, E_TECH_GAIN,
@@ -425,6 +429,12 @@
                                 PACKET_DIPLOMACY_REMOVE_CLAUSE, packet);
       lsend_packet_diplomacy_info(&plr1->connections, 
                                 PACKET_DIPLOMACY_REMOVE_CLAUSE, packet);
+      if (plr0->ai.control) {
+        ai_treaty_evaluate(plr0, plr1, ptreaty);
+      }
+      if (plr1->ai.control) {
+        ai_treaty_evaluate(plr1, plr0, ptreaty);
+      }
     }
   }
 
@@ -468,6 +478,12 @@
       lsend_packet_diplomacy_info(&plr1->connections, 
                                 PACKET_DIPLOMACY_CREATE_CLAUSE, 
                                 packet);
+      if (plr0->ai.control) {
+        ai_treaty_evaluate(plr0, plr1, ptreaty);
+      }
+      if (plr1->ai.control) {
+        ai_treaty_evaluate(plr1, plr0, ptreaty);
+      }
     }
   }
 }
@@ -536,15 +552,18 @@
   plr0=&game.players[packet->plrno0];
   plr1=&game.players[packet->plrno1];
 
+  assert(plr0 != plr1);
+
   if (!find_treaty(plr0, plr1)) {
-    if (plr0->ai.control || plr1->ai.control) {
-      notify_player(plr0, _("AI controlled players cannot participate in "
-                           "diplomatic meetings."));
+    if (is_barbarian(plr0) || is_barbarian(plr1)) {
+      notify_player(plr0, _("Your diplomatic envoy was decapitated!"));
       return;
     }
-
-    if (player_has_embassy(plr0, plr1) && plr0->is_connected && 
-       plr0->is_alive && plr1->is_connected && plr1->is_alive) {
+    if (player_has_embassy(plr0, plr1) 
+        && (plr0->is_connected || plr0->ai.control)
+       && plr0->is_alive 
+        && (plr1->is_connected || plr1->ai.control) 
+       && plr1->is_alive) {
       struct Treaty *ptreaty;
 
       ptreaty=fc_malloc(sizeof(struct Treaty));
@@ -582,6 +601,7 @@
     return;
   }
   players_iterate(other_player) {
+
     if ( (ptreaty=find_treaty(pplayer, other_player))) {
       struct packet_diplomacy_info packet;
       
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.253
diff -u -r1.253 plrhand.c
--- server/plrhand.c    2002/12/18 17:36:20     1.253
+++ server/plrhand.c    2003/01/04 03:14:07
@@ -1328,6 +1328,7 @@
   if (initmap)
     player_map_allocate(pplayer);
   player_init(pplayer);
+  ai_data_init(pplayer);
 
   player_init_island_imprs(pplayer, map.num_continents);
 }
@@ -1573,10 +1574,10 @@
    * but for now AI players are always at war.
    */
   players_iterate(other_player) {
-    cplayer->diplstates[other_player->player_no].type = DS_WAR;
+    cplayer->diplstates[other_player->player_no].type = DS_NEUTRAL;
     cplayer->diplstates[other_player->player_no].has_reason_to_cancel = 0;
     cplayer->diplstates[other_player->player_no].turns_left = 0;
-    other_player->diplstates[cplayer->player_no].type = DS_WAR;
+    other_player->diplstates[cplayer->player_no].type = DS_NEUTRAL;
     other_player->diplstates[cplayer->player_no].has_reason_to_cancel = 0;
     other_player->diplstates[cplayer->player_no].turns_left = 0;
     
@@ -1602,7 +1603,7 @@
   for(i = 0; i<game.num_tech_types ; i++)
     cplayer->research.inventions[i] = pplayer->research.inventions[i];
   cplayer->turn_done = TRUE; /* Have other things to think about - paralysis*/
-  cplayer->embassy = 0;   /* all embassys destroyed */
+  cplayer->embassy = 0;   /* all embassies destroyed */
 
   /* Do the ai */
 
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.110
diff -u -r1.110 srv_main.c
--- server/srv_main.c   2002/12/18 17:36:20     1.110
+++ server/srv_main.c   2003/01/04 03:14:07
@@ -90,6 +90,7 @@
 #include "unithand.h"
 #include "unittools.h"
 
+#include "advdiplomacy.h"
 #include "advmilitary.h"
 #include "aidata.h"
 #include "aihand.h"

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