[Freeciv-Dev] Re: (PR#13524) AI Diplomacy revisited
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: |
[Freeciv-Dev] Re: (PR#13524) AI Diplomacy revisited |
From: |
"Per I. Mathisen" <per@xxxxxxxxxxx> |
Date: |
Thu, 28 Jul 2005 06:15:33 -0700 |
Reply-to: |
bugs@xxxxxxxxxxx |
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=13524 >
Another version. I fixed the overzealousness for treaties, gave it back
its backbone, fixed a ton of bugs and hopefully made it not want war too
early.
- Per
Index: ai/advdiplomacy.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdiplomacy.c,v
retrieving revision 1.86
diff -u -r1.86 advdiplomacy.c
--- ai/advdiplomacy.c 26 Jul 2005 16:35:56 -0000 1.86
+++ ai/advdiplomacy.c 28 Jul 2005 13:09:49 -0000
@@ -1,5 +1,5 @@
/**********************************************************************
- Freeciv - Copyright (C) 2003 - The Freeciv Team
+ Freeciv - Copyright (C) 2005 - The Freeciv Team
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)
@@ -43,38 +43,23 @@
#include "aidata.h"
#include "ailog.h"
+#include "aiunit.h"
#include "aitools.h"
#include "advmilitary.h"
#include "advdiplomacy.h"
-/*
-
- "When a lobsterman leaves a trap out in the sea and can't get
- to it for a while, he will find the remains of many lobsters,
- but only one survivor. You might think that the survivor of the
- lobster-battles would be the biggest lobster, but actually it
- will always be the SECOND-SMALLEST. That's because when there
- are a bunch of lobsters in the tank, they always gang up on the
- biggest one first, until there are only two left, and then the
- bigger one wins."
- (Anecdote by banjo@xxxxxxxxxx)
-
-Although the AIs are not this flawlessly deterministic in choosing their
-enemies (they respect alliances and try to preserve treaties among other
-things), this is the basic premise. Gang up on the biggest threat and
-bring it down. Don't be too afraid to ally up with the others and don't
-worry about our own safety. If everyone think the same way, there'll be
-safety in numbers :-) If not, well, at least it makes a good show.
-
-*/
-
#define LOG_DIPL LOG_DEBUG
#define LOG_DIPL2 LOG_DEBUG
-/* one hundred thousand */
+/* One hundred thousand. Basically a number of gold that no player is
+ * ever likely to have, but not so big that we get integer overflows. */
#define BIG_NUMBER 100000
+/* This is how much negative AI love we need before we decide to embark
+ * on opportunistic war for spoils. */
+#define WAR_THRESHOLD -(MAX_AI_LOVE / 8)
+
/* turn this off when we don't want functions to message players */
static bool diplomacy_verbose = TRUE;
@@ -107,8 +92,7 @@
/* Don't change the operation order here.
* We do not want integer overflows */
return -((missing_love * MAX_AI_LOVE) / 1000) *
- ((missing_love * MAX_AI_LOVE) / 1000) /
- 50;
+ ((missing_love * MAX_AI_LOVE) / 1000) / 10;
}
}
@@ -136,7 +120,6 @@
static int ai_goldequiv_tech(struct player *pplayer, Tech_type_id tech)
{
int bulbs, tech_want, worth;
- struct ai_data *ai = ai_data_get(pplayer);
if (get_invention(pplayer, tech) == TECH_KNOWN) {
return 0;
@@ -147,9 +130,6 @@
if (get_invention(pplayer, tech) == TECH_REACHABLE) {
worth /= 2;
}
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "eval tech %s to %d (bulbs=%d, "
- "tech_want=%d)", get_tech_name(pplayer, tech), worth, bulbs,
- tech_want);
return worth;
}
@@ -185,14 +165,10 @@
static bool ai_players_can_agree_on_ceasefire(struct player* player1,
struct player* player2)
{
- struct ai_data *ai1 = ai_data_get(player1);
+ struct ai_data *ai = ai_data_get(player1);
- return (ai1->diplomacy.target != player2 &&
- (player1 == ai1->diplomacy.alliance_leader ||
- !pplayers_at_war(player2, ai1->diplomacy.alliance_leader)) &&
- player1->ai.love[player2->player_no] > - (MAX_AI_LOVE * 4 / 10) &&
- (ai1->diplomacy.target == NULL ||
- !pplayers_allied(ai1->diplomacy.target, player2)));
+ return (player1->ai.love[player2->player_no] > - (MAX_AI_LOVE * 4 / 10)
+ && ai->diplomacy.player_intel[player2->player_no].countdown == -1);
}
/**********************************************************************
@@ -271,12 +247,11 @@
assert(pplayer != aplayer);
diplomacy_verbose = verbose;
-
+ ds_after = MAX(ds_after, pplayer->diplstates[aplayer->player_no].type);
giver = pclause->from;
switch (pclause->type) {
case CLAUSE_ADVANCE:
-
if (give) {
worth -= compute_tech_sell_price(pplayer, aplayer, pclause->value,
&is_dangerous);
@@ -287,8 +262,9 @@
worth += compute_tech_sell_price(aplayer, pplayer, pclause->value,
&is_dangerous);
}
-
- break;
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "%s clause worth %d",
+ get_tech_name(pplayer, pclause->value), worth);
+ break;
case CLAUSE_ALLIANCE:
case CLAUSE_PEACE:
@@ -301,18 +277,7 @@
break;
}
- /* This guy is at war with our alliance and we're not alliance
- * leader. */
- if (pplayer != ai->diplomacy.alliance_leader
- && pplayers_at_war(aplayer, ai->diplomacy.alliance_leader)) {
- notify(aplayer, _("*%s (AI)* %s leads our alliance. You must contact "
- "and make peace with him first."), pplayer->name,
- ai->diplomacy.alliance_leader->name);
- worth = -BIG_NUMBER;
- break;
- }
-
- /* And this guy is allied to one of our enemies. Only accept
+ /* This guy is allied to one of our enemies. Only accept
* ceasefire. */
if (adip->is_allied_with_enemy
&& pclause->type != CLAUSE_CEASEFIRE) {
@@ -336,57 +301,41 @@
}
}
- /* Let's all hold hands in one happy family! */
- if (adip->is_allied_with_ally) {
- worth = 0;
- break;
- }
-
- /* If this lucky fella got a ceasefire or peace with da boss, then
- * let him live. */
- if ((pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
- == DS_CEASEFIRE
- || pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
- == DS_PEACE)
- && pclause->type == CLAUSE_CEASEFIRE) {
- if (ai->diplomacy.target == aplayer) {
- /* Damn, we lost our target, too! Stupid boss! */
- /* FIXME: We shouldn't do this here - the other player may not
- * accept the whole treaty! */
- ai->diplomacy.target = NULL;
- ai->diplomacy.timer = 0;
- ai->diplomacy.countdown = 0;
- }
- worth = 0;
- break;
- }
-
- /* Breaking treaties give us penalties on future diplomacy, so
- * avoid flip-flopping treaty/war with our chosen enemy. */
- if (aplayer == ai->diplomacy.target) {
- worth = -BIG_NUMBER;
- break;
- }
-
- /* Steps of the ladder */
+ /* Steps of the treaty ladder */
if (pclause->type == CLAUSE_PEACE) {
+ struct player_diplstate *ds = &pplayer->diplstates[aplayer->player_no];
+
if (!pplayers_non_attack(pplayer, aplayer)) {
notify(aplayer, _("*%s (AI)* Let us first cease hostilies, %s"),
pplayer->name, aplayer->name);
worth = -BIG_NUMBER;
+ } else if (ds->type == DS_CEASEFIRE && ds->turns_left > 2) {
+ notify(aplayer, _("*%s (AI)* I wish to see you keep the current "
+ "ceasefire first, %s"), pplayer->name, aplayer->name);
+ worth = -BIG_NUMBER;
+ } else if (adip->countdown >= 0 && adip->countdown < -1) {
+ worth = -BIG_NUMBER; /* but say nothing */
} else {
worth = greed(pplayer->ai.love[aplayer->player_no]
- ai->diplomacy.req_love_for_peace);
}
} else if (pclause->type == CLAUSE_ALLIANCE) {
if (!pplayers_in_peace(pplayer, aplayer)) {
- notify(aplayer, _("*%s (AI)* Let us first make peace, %s"),
- pplayer->name, aplayer->name);
- worth = -BIG_NUMBER;
- } else {
worth = greed(pplayer->ai.love[aplayer->player_no]
- - ai->diplomacy.req_love_for_alliance);
+ - ai->diplomacy.req_love_for_peace);
}
+ if (adip->countdown >= 0 || adip->countdown < -1) {
+ worth = -BIG_NUMBER; /* but say nothing */
+ } else {
+ worth += greed(pplayer->ai.love[aplayer->player_no]
+ - ai->diplomacy.req_love_for_alliance);
+ }
+ if (pplayer->ai.love[aplayer->player_no] < MAX_AI_LOVE / 10) {
+ notify(aplayer, _("*%s (AI)* I simply do not trust you with an "
+ "alliance yet, %s"), pplayer->name, aplayer->name);
+ worth = -BIG_NUMBER;
+ }
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "ally clause worth %d", worth);
} else {
if (pplayer->ai.control && aplayer->ai.control &&
ai_players_can_agree_on_ceasefire(pplayer, aplayer)) {
@@ -396,6 +345,14 @@
- ai->diplomacy.req_love_for_ceasefire);
}
}
+
+ /* Let's all hold hands in one happy family! */
+ if (adip->is_allied_with_ally) {
+ worth /= 2;
+ break;
+ }
+
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "treaty clause worth %d", worth);
break;
case CLAUSE_GOLD:
@@ -407,7 +364,7 @@
break;
case CLAUSE_SEAMAP:
- if (!give || pplayers_allied(pplayer, aplayer)) {
+ if (!give || ds_after == DS_ALLIANCE) {
/* Useless to us - we're omniscient! And allies get it for free! */
worth = 0;
} else {
@@ -415,31 +372,38 @@
cities. Reasoning is he has more use of seamap for settling
new areas the more cities he has already. */
worth -= 15 * city_list_size(aplayer->cities);
-
+ /* Don't like him? Don't give him! */
+ worth = MIN(pplayer->ai.love[aplayer->player_no] * 7, worth);
/* Make maps from novice player cheap */
if (ai_handicap(pplayer, H_DIPLOMACY)) {
worth /= 2;
}
}
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "seamap clause worth %d",
+ worth);
break;
case CLAUSE_MAP:
- if (!give || pplayers_allied(pplayer, aplayer)) {
+ if (!give || ds_after == DS_ALLIANCE) {
/* Useless to us - we're omniscient! And allies get it for free! */
worth = 0;
} else {
/* Very silly algorithm 2: Land map more worth the more cities
we have, since we expose all of these to the enemy. */
- worth -= 50 * MAX(city_list_size(pplayer->cities), 3);
+ worth -= 40 * MAX(city_list_size(pplayer->cities), 1);
/* Inflate numbers if not peace */
if (!pplayers_in_peace(pplayer, aplayer)) {
- worth *= 4;
+ worth *= 2;
}
+ /* Don't like him? Don't give him! */
+ worth = MIN(pplayer->ai.love[aplayer->player_no] * 10, worth);
/* Make maps from novice player cheap */
if (ai_handicap(pplayer, H_DIPLOMACY)) {
worth /= 6;
}
}
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "landmap clause worth %d",
+ worth);
break;
case CLAUSE_CITY: {
@@ -466,13 +430,14 @@
} else {
worth = city_gold_worth(offer);
}
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "worth of %s is %d", offer->name, worth);
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "worth of %s is %d",
+ offer->name, worth);
break;
}
case CLAUSE_VISION:
if (give) {
- if (pplayers_allied(pplayer, aplayer) || ds_after == DS_ALLIANCE) {
+ if (ds_after == DS_ALLIANCE) {
if (!shared_vision_is_safe(pplayer, aplayer)) {
notify(aplayer, _("*%s (AI)* Sorry, sharing vision with you "
"is not safe."),
@@ -489,17 +454,25 @@
worth = 0; /* We are omniscient, so... */
}
break;
+
case CLAUSE_EMBASSY:
if (give) {
- if (ds_after == DS_PEACE || ds_after == DS_ALLIANCE) {
+ if (ds_after == DS_ALLIANCE) {
worth = 0;
+ } else if (ds_after == DS_PEACE) {
+ worth = -5 * game.info.turn;
} else {
- worth = -BIG_NUMBER; /* No. */
+ worth = MIN(-50 * game.info.turn
+ + pplayer->ai.love[aplayer->player_no],
+ -5 * game.info.turn);
}
} else {
worth = 0; /* We don't need no stinkin' embassy, do we? */
}
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "embassy clause worth %d",
+ worth);
break;
+
case CLAUSE_LAST:
break;
} /* end of switch */
@@ -592,14 +565,17 @@
notify(aplayer, _("*%s (AI)* Yes, may we forever stand united, %s"),
pplayer->name, aplayer->name);
}
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "become allies");
break;
case CLAUSE_PEACE:
notify(aplayer, _("*%s (AI)* Yes, peace in our time!"),
pplayer->name);
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "sign peace treaty");
break;
case CLAUSE_CEASEFIRE:
notify(aplayer, _("*%s (AI)* Agreed. No more hostilities, %s"),
pplayer->name, aplayer->name);
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "sign ceasefire");
break;
default:
break;
@@ -638,8 +614,11 @@
total_balance += balance;
gift = (gift && (balance >= 0));
ai_treaty_react(pplayer, aplayer, pclause);
- if (pclause->type == CLAUSE_ALLIANCE && ai->diplomacy.target == aplayer) {
- ai->diplomacy.target = NULL; /* Oooops... */
+ if (is_pact_clause(pclause->type)
+ && ai->diplomacy.player_intel[aplayer->player_no].countdown >= 0) {
+ /* Cancel a countdown towards war if we just agreed to peace... */
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "countdown cancelled");
+ ai->diplomacy.player_intel[aplayer->player_no].countdown = -1;
}
} clause_list_iterate_end;
@@ -651,60 +630,89 @@
i = MIN(i, ai->diplomacy.love_incr * 150) * 10;
pplayer->ai.love[aplayer->player_no] += i;
- DIPLO_LOG(LOG_DIPL2, pplayer, ai, "%s's gift to %s increased love by %d",
- aplayer->name, pplayer->name, i);
+ DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "gift increased love by %d", i);
}
}
/**********************************************************************
- Calculate our desire to go to war against aplayer.
+ Calculate our desire to go to war against aplayer. We want to
+ attack a player that is easy to beat and will yield a nice profit.
+
+ This function is full of hardcoded constants by necessity. They are
+ not #defines since they are not used anywhere else.
***********************************************************************/
-static int ai_war_desire(struct player *pplayer, struct player *aplayer,
+static int ai_war_desire(struct player *pplayer, struct player *target,
struct ai_data *ai)
{
- int kill_desire;
- struct player_spaceship *ship = &aplayer->spaceship;
- struct ai_dip_intel *adip = &ai->diplomacy.player_intel[aplayer->player_no];
+ int want = 0, fear = 0, distance = 0, settlers = 0, cities = 0;
+ struct player_spaceship *ship = &target->spaceship;
- /* 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->production.is_unit
- && unit_type_flag(get_unit_type(pcity->production.value),
- F_CITIES)) {
- kill_desire -= 1;
- }
+ city_list_iterate(target->cities, pcity) {
+ want += 100; /* base city want */
+ want += pcity->size * 20;
+ want += pcity->surplus[O_SHIELD] * 8;
+ want += pcity->surplus[O_TRADE] * 6;
+ fear += get_city_bonus(pcity, EFT_LAND_DEFEND);
+ fear += get_city_bonus(pcity, EFT_SEA_DEFEND);
+ built_impr_iterate(pcity, id) {
+ want += impr_build_shield_cost(id);
+ if (is_great_wonder(id)) {
+ want += impr_build_shield_cost(id) * 2;
+ } else if (is_small_wonder(id)) {
+ want += impr_build_shield_cost(id);
+ }
+ } built_impr_iterate_end;
} city_list_iterate_end;
- unit_list_iterate(aplayer->units, punit) {
+ unit_list_iterate(target->units, punit) {
+ fear += ATTACK_POWER(punit);
+
+ /* Fear enemy expansionism */
if (unit_flag(punit, F_CITIES)) {
- kill_desire += 1;
+ want += 100;
}
} unit_list_iterate_end;
+ unit_list_iterate(pplayer->units, punit) {
+ fear -= ATTACK_POWER(punit) / 2;
- /* Count big cities as twice the threat */
- city_list_iterate(aplayer->cities, pcity) {
- kill_desire += pcity->size > 8 ? 1 : 0;
+ /* Our own expansionism reduces want for war */
+ if (unit_flag(punit, F_CITIES)) {
+ want -= 200;
+ settlers++;
+ }
+ } unit_list_iterate_end;
+ city_list_iterate(pplayer->cities, pcity) {
+ if (pcity->production.is_unit
+ && unit_type_flag(get_unit_type(pcity->production.value),
+ F_CITIES)) {
+ want -= 150;
+ settlers++;
+ }
+ cities++;
} city_list_iterate_end;
- /* Tech lead is worrisome */
- kill_desire += MAX(get_player_research(aplayer)->techs_researched
- - get_player_research(pplayer)->techs_researched, 0);
+ /* Modify by settler/cities ratio to prevent early wars when
+ * we should be expanding. This will eliminate want if we
+ * produce settlers in all cities (ie full expansion). */
+ want -= abs(want) / MAX(cities - settlers, 1);
+
+ /* Calculate average distances to other player's empire. */
+ distance = player_distance_to_player(pplayer, target);
+ ai->diplomacy.player_intel[target->player_no].distance = distance;
+
+ /* Tech lead is worrisome. FIXME: Only consider 'military' techs. */
+ fear += MAX(get_player_research(target)->techs_researched
+ - get_player_research(target)->techs_researched, 0) * 100;
/* Spacerace loss we will not allow! */
if (ship->state >= SSHIP_STARTED) {
- /* add potential */
- kill_desire += city_list_size(aplayer->cities);
+ want *= 2;
}
- if (ai->diplomacy.spacerace_leader == aplayer) {
+ if (ai->diplomacy.spacerace_leader == target) {
ai->diplomacy.strategy = WIN_CAPITAL;
return BIG_NUMBER; /* do NOT amortize this number! */
}
- /* Modify by which treaties we would have to break, and what
+ /* Modify by which treaties we would break to other players, and what
* excuses we have to do so. FIXME: We only consider immediate
* allies, but we might trigger a wider chain reaction. */
players_iterate(eplayer) {
@@ -716,32 +724,39 @@
continue;
}
- /* Remember: pplayers_allied() returns true when aplayer == eplayer */
- if (!cancel_excuse && pplayers_allied(aplayer, eplayer)) {
+ /* Remember: pplayers_allied() returns true when target == eplayer */
+ if (!cancel_excuse && pplayers_allied(target, eplayer)) {
if (ds == DS_NEUTRAL) {
- kill_desire -= kill_desire / 10; /* 10% off */
+ want -= abs(want) / 10; /* 10% off */
} else if (ds == DS_CEASEFIRE) {
- kill_desire -= kill_desire / 7; /* 15% off */
+ want -= abs(want) / 7; /* 15% off */
} else if (ds == DS_PEACE) {
- kill_desire -= kill_desire / 5; /* 20% off */
+ want -= abs(want) / 5; /* 20% off */
} else if (ds == DS_ALLIANCE) {
- kill_desire -= kill_desire / 3; /* 33% off here, more later */
+ want -= abs(want) / 3; /* 33% off */
}
}
} players_iterate_end;
/* Modify by love. Increase the divisor to make ai go to war earlier */
- kill_desire -= MAX(0, kill_desire
- * pplayer->ai.love[aplayer->player_no]
- / (2 * MAX_AI_LOVE));
+ want -= MAX(0, want * pplayer->ai.love[target->player_no]
+ / (2 * MAX_AI_LOVE));
/* Make novice AI more peaceful with human players */
- if (ai_handicap(pplayer, H_DIPLOMACY) && !aplayer->ai.control) {
- kill_desire = kill_desire / 2 - 5;
+ if (ai_handicap(pplayer, H_DIPLOMACY) && !target->ai.control) {
+ want /= 2;
}
/* Amortize by distance */
- return amortize(kill_desire, adip->distance);
+ want = amortize(want, distance);
+
+ if (pplayers_allied(pplayer, target)) {
+ want /= 4;
+ }
+
+ DIPLO_LOG(LOG_DEBUG, pplayer, target, "War want %d, war fear %d",
+ want, fear);
+ return (want - fear);
}
/**********************************************************************
@@ -777,8 +792,7 @@
{
int war_desire[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
int best_desire = 0;
- struct player *target = NULL;
- int mult;
+ struct player *best_target = NULL;
memset(war_desire, 0, sizeof(war_desire));
@@ -787,86 +801,94 @@
return; /* duh */
}
+ /* Calculate our desires, and find desired war target */
+ players_iterate(aplayer) {
+ /* We don't hate ourselves, those we don't know or team members. */
+ if (aplayer == pplayer
+ || !aplayer->is_alive
+ || NEVER_MET(pplayer, aplayer)
+ || players_on_same_team(pplayer, aplayer)) {
+ continue;
+ }
+ war_desire[aplayer->player_no] = ai_war_desire(pplayer, aplayer, ai);
+ if (war_desire[aplayer->player_no] > best_desire) {
+ best_desire = war_desire[aplayer->player_no];
+ best_target = aplayer;
+ }
+ } players_iterate_end;
+
/* Time to make love. If we've been wronged, hold off that love
* for a while. Also, cool our head each turn with love_coeff. */
players_iterate(aplayer) {
int a = aplayer->player_no;
struct ai_dip_intel *adip = &ai->diplomacy.player_intel[a];
+ int amount = 0;
if (pplayer == aplayer || !aplayer->is_alive) {
continue;
}
- pplayer->ai.love[aplayer->player_no] -=
- pplayer->diplstates[a].has_reason_to_cancel;
if ((pplayers_non_attack(pplayer, aplayer)
|| pplayers_allied(pplayer, aplayer))
&& pplayer->diplstates[a].has_reason_to_cancel == 0
+ && adip->countdown == -1
&& !adip->is_allied_with_enemy
&& !adip->at_war_with_ally
- && aplayer != ai->diplomacy.target
+ && aplayer != best_target
&& adip->ally_patience >= 0) {
- pplayer->ai.love[aplayer->player_no] += ai->diplomacy.love_incr;
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Increased love for %s (now %d)",
- aplayer->name, pplayer->ai.love[aplayer->player_no]);
- } else if (pplayer->diplstates[aplayer->player_no].type == DS_WAR) {
- pplayer->ai.love[aplayer->player_no] -= ai->diplomacy.love_incr;
- if (ai->diplomacy.target != aplayer &&
- pplayer->ai.love[aplayer->player_no] < 0) {
- /* Give him a better chance for a cease fire */
- pplayer->ai.love[aplayer->player_no] += (MAX_AI_LOVE) * 3 / 100;
- }
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Reduced love for %s (now %d) ",
- aplayer->name, pplayer->ai.love[aplayer->player_no]);
+ amount += ai->diplomacy.love_incr / 2;
+ if (pplayers_allied(pplayer, aplayer)) {
+ amount += ai->diplomacy.love_incr / 3;
+ }
+ /* Increase love by each enemy he is at war with */
+ players_iterate(eplayer) {
+ if (WAR(eplayer, aplayer) && WAR(pplayer, eplayer)) {
+ amount += ai->diplomacy.love_incr / 4;
+ }
+ } players_iterate_end;
+ pplayer->ai.love[aplayer->player_no] += amount;
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Increased love by %d", amount);
+ } else if (WAR(pplayer, aplayer)) {
+ amount -= ai->diplomacy.love_incr / 2;
+ pplayer->ai.love[aplayer->player_no] += amount;
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost to war", amount);
} else if (pplayer->diplstates[a].has_reason_to_cancel != 0) {
/* Provoked in time of peace */
if (pplayer->ai.love[aplayer->player_no] > 0) {
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Provoked by %s! Love halved "
- "(was %d)", aplayer->name,
- pplayer->ai.love[aplayer->player_no]);
- pplayer->ai.love[aplayer->player_no] /= 2;
+ amount -= pplayer->ai.love[aplayer->player_no] / 2;
}
- pplayer->ai.love[aplayer->player_no] -= ai->diplomacy.love_incr;
+ amount -= ai->diplomacy.love_incr * 6;
+ pplayer->ai.love[aplayer->player_no] += amount;
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Provoked! %d love lost!",
+ amount);
}
-
- /* Reduce love by number of units in our territory.
+ if (pplayer->ai.love[aplayer->player_no] > MAX_AI_LOVE * 8 / 10
+ && !pplayers_allied(pplayer, aplayer)) {
+ int amount = ai->diplomacy.love_incr / 3;
+
+ /* Upper levels of AI trust and love is reserved for allies. */
+ pplayer->ai.love[aplayer->player_no] -= amount;
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost from excess",
+ amount);
+ }
+ amount = 0;
+
+ /* Reduce love due to units in our territory.
* AI is so naive, that we have to count it even if players are allied */
- mult =
- pplayers_at_war(pplayer, aplayer) || adip->is_allied_with_enemy ?
- 2 : 1;
-
- pplayer->ai.love[aplayer->player_no] -=
- MIN(player_in_territory(pplayer, aplayer) * (MAX_AI_LOVE / 100),
- pplayers_allied(aplayer, pplayer) ?
- ai->diplomacy.love_incr - 1 : (MAX_AI_LOVE / 2)) * mult;
-
+ amount -= MIN(player_in_territory(pplayer, aplayer) * (MAX_AI_LOVE / 200),
+ ai->diplomacy.love_incr
+ * ((adip->is_allied_with_enemy != NULL) + 1));
+ pplayer->ai.love[aplayer->player_no] += amount;
+ if (amount != 0) {
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "%d love lost due to units inside
"
+ "our borders", amount);
+ }
+
/* Increase the love if aplayer has got a building that makes
* us love him more. Typically it's Eiffel Tower */
pplayer->ai.love[aplayer->player_no] +=
get_player_bonus(aplayer, EFT_GAIN_AI_LOVE) * MAX_AI_LOVE / 1000;
-
- /* Massage our numbers to keep love and its opposite on the ground.
- * Gravitate towards zero. */
- pplayer->ai.love[aplayer->player_no] -=
- (pplayer->ai.love[aplayer->player_no] * ai->diplomacy.love_coeff / 100);
-
- /* ai love should always be in range [-MAX_AI_LOVE..MAX_AI_LOVE] */
- pplayer->ai.love[aplayer->player_no] =
- MAX(-MAX_AI_LOVE,
- MIN(MAX_AI_LOVE, pplayer->ai.love[aplayer->player_no]));
} players_iterate_end;
- /* Stop war against a dead player */
- if (ai->diplomacy.target && !ai->diplomacy.target->is_alive) {
- DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Target player %s is dead! Victory!",
- ai->diplomacy.target->name);
- ai->diplomacy.timer = 0;
- ai->diplomacy.countdown = 0;
- ai->diplomacy.target = NULL;
- if (ai->diplomacy.strategy == WIN_CAPITAL) {
- ai->diplomacy.strategy = WIN_OPEN;
- }
- }
-
/* Can we win by space race? */
if (ai->diplomacy.spacerace_leader == pplayer) {
freelog(LOG_DIPL2, "%s going for space race victory!", pplayer->name);
@@ -877,90 +899,26 @@
}
}
- if (ai->diplomacy.countdown > 0) {
- ai->diplomacy.countdown--;
- }
-
- /* Ensure that we don't prematurely end an ongoing war */
- if (ai->diplomacy.timer-- > 0) {
- return;
- }
-
- /* Calculate average distances to other players' empires. */
players_iterate(aplayer) {
- ai->diplomacy.player_intel[aplayer->player_no].distance =
- player_distance_to_player(pplayer, aplayer);
- } players_iterate_end;
+ int *love = &pplayer->ai.love[aplayer->player_no];
- /* Calculate our desires, and find desired war target */
- players_iterate(aplayer) {
- enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
- struct ai_dip_intel *adip =
&ai->diplomacy.player_intel[aplayer->player_no];
-
- /* We don't hate ourselves, those we don't know or team members
- * Defer judgement on alliance members we're not (yet) allied to
- * to the alliance leader. Always respect ceasefires the boss has signed.
- */
- if (aplayer == pplayer
- || !aplayer->is_alive
- || ds == DS_NO_CONTACT
- || players_on_same_team(pplayer, aplayer)
- || (pplayer != ai->diplomacy.alliance_leader &&
- aplayer != ai->diplomacy.alliance_leader &&
- adip->is_allied_with_ally)
- || (pplayer_get_diplstate(aplayer, ai->diplomacy.alliance_leader)->type
- == DS_CEASEFIRE)) {
- continue;
- }
- war_desire[aplayer->player_no] = ai_war_desire(pplayer, aplayer, ai);
+ if (aplayer == best_target && best_desire > 0) {
+ int reduction = MIN(best_desire, MAX_AI_LOVE / 20);
- /* We don't want war if we can win through the space race. */
- if (ai->diplomacy.strategy == WIN_SPACE && !adip->at_war_with_ally) {
- continue;
+ *love -= reduction;
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "Wants war, reducing "
+ "love by %d ", reduction);
}
- /* Strongly prefer players we are at war with already. */
- if (!pplayers_at_war(pplayer, aplayer)) {
- war_desire[aplayer->player_no] /= 2;
- }
-
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Against %s we have war desire "
- "%d ", aplayer->name, war_desire[aplayer->player_no]);
+ /* Massage our numbers to keep love and its opposite on the ground.
+ * Gravitate towards zero. */
+ *love -= *love * (ai->diplomacy.love_coeff / 100);
- /* Find best target */
- if (war_desire[aplayer->player_no] > best_desire) {
- target = aplayer;
- best_desire = war_desire[aplayer->player_no];
- }
+ /* ai love should always be in range [-MAX_AI_LOVE..MAX_AI_LOVE] */
+ *love = MAX(-MAX_AI_LOVE, MIN(MAX_AI_LOVE, *love));
} players_iterate_end;
-
- if (!target) {
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Found no target.");
- ai->diplomacy.target = NULL;
- return;
- }
-
- /* Switch to target */
- if (target != ai->diplomacy.target) {
- DIPLO_LOG(LOG_DIPL, pplayer, ai, "Setting target to %s", target->name);
- ai->diplomacy.target = target;
- if (ai->diplomacy.strategy == WIN_CAPITAL) {
- ai->diplomacy.countdown = 1; /* Quickly!! */
- } else if (pplayer->diplstates[target->player_no].has_reason_to_cancel >
1) {
- /* Turns until we lose our casus bellum, exploit that. */
- ai->diplomacy.countdown =
- pplayer->diplstates[target->player_no].has_reason_to_cancel
- - 1;
- } else {
- ai->diplomacy.countdown = 6; /* Take the time we need - WAG */
- }
- /* Don't reevaluate too often. */
- ai->diplomacy.timer = myrand(6) + 6 + ai->diplomacy.countdown;
- players_iterate(aplayer) {
- ai->diplomacy.player_intel[aplayer->player_no].ally_patience = 0;
- } players_iterate_end;
- }
}
+
/**********************************************************************
Find two techs that can be exchanged and suggest that
***********************************************************************/
@@ -1000,7 +958,6 @@
}
} tech_type_iterate_end;
-
tech_type_iterate(tech) {
if (worth[tech] <= 0) {
continue;
@@ -1028,6 +985,7 @@
} tech_type_iterate_end;
} tech_type_iterate_end;
}
+
/**********************************************************************
Offer techs and stuff to other player and ask for techs we need.
***********************************************************************/
@@ -1068,13 +1026,63 @@
}
/**********************************************************************
- Go to war.
+ Go to war. Explain to target why we did it, and set countdown to
+ some negative value to make us a bit stubborn to avoid immediate
+ reversal to ceasefire.
***********************************************************************/
static void ai_go_to_war(struct player *pplayer, struct ai_data *ai,
- struct player *target)
+ struct player *target, enum war_reason reason)
{
+ struct ai_dip_intel *adip = &ai->diplomacy.player_intel[target->player_no];
+
assert(pplayer != target);
+ switch (reason) {
+ case WAR_REASON_SPACE:
+ notify(target, _("*%s (AI)* Space will never be yours. "), pplayer->name);
+ adip->countdown = -10;
+ break;
+ case WAR_REASON_BEHAVIOUR:
+ notify(target, _("*%s (AI)* I have tolerated your vicious antics "
+ "long enough! To war!"), pplayer->name);
+ adip->countdown = -20;
+ break;
+ case WAR_REASON_NONE:
+ notify(target, _("*%s (AI)* Peace in ... some other time"),
+ pplayer->name);
+ adip->countdown = -10;
+ break;
+ case WAR_REASON_HATRED:
+ notify(target, _("*%s (AI)* Finally I get around to you! Did "
+ "you really think you could get away with your crimes?"),
+ pplayer->name);
+ adip->countdown = -20;
+ break;
+ case WAR_REASON_EXCUSE:
+ notify(target, _("*%s (AI)* Your covert hostilities brought "
+ "this war upon you!"), pplayer->name);
+ adip->countdown = -20;
+ break;
+ case WAR_REASON_ALLIANCE:
+ if (adip->at_war_with_ally) {
+ notify(target, _("*%s (AI)* Your aggression against %s was "
+ "your last mistake!"),
+ pplayer->name,
+ adip->at_war_with_ally->name);
+ adip->countdown = -3;
+ } else {
+ /* Ooops! */
+ DIPLO_LOG(LOG_DIPL, pplayer, target, "Wanted to declare war "
+ "for his war against an ally, but can no longer find "
+ "this ally! War declaration aborted.");
+ adip->countdown = -1;
+ return;
+ }
+ break;
+ }
+
+ assert(adip->countdown < 0);
+
if (gives_shared_vision(pplayer, target)) {
remove_shared_vision(pplayer, target);
}
@@ -1088,16 +1096,87 @@
/* This will take us straight to war. */
handle_diplomacy_cancel_pact(pplayer, target->player_no, CLAUSE_LAST);
- /* Continue war at least in this arbitrary number of turns to show
- * some spine */
- ai->diplomacy.timer = myrand(4) + 3;
- if (pplayer->ai.love[target->player_no] < 0) {
- ai->diplomacy.timer -= pplayer->ai.love[target->player_no] / 10;
- } else {
- /* We DO NOT love our enemies! AIs are heatens! */
- pplayer->ai.love[target->player_no] = -1;
+ /* Throw a tantrum */
+ if (pplayer->ai.love[target->player_no] > 0) {
+ pplayer->ai.love[target->player_no] = -1;
}
+ pplayer->ai.love[target->player_no] -= MAX_AI_LOVE / 8;
+
assert(!gives_shared_vision(pplayer, target));
+ DIPLO_LOG(LOG_DIPL, pplayer, target, "war declared");
+}
+
+/**********************************************************************
+ Do diplomatic actions. Must be called only after calculate function
+ above has been run for _all_ AI players.
+
+ Only ever called for AI players and never for barbarians.
+***********************************************************************/
+void static war_countdown(struct player *pplayer, struct player *target,
+ int countdown, enum war_reason reason)
+{
+ struct ai_data *ai = ai_data_get(pplayer);
+ struct ai_dip_intel *adip = &ai->diplomacy.player_intel[target->player_no];
+
+ DIPLO_LOG(LOG_DIPL, pplayer, target, "countdown to war in %d", countdown);
+
+ /* Otherwise we're resetting an existing countdown, which is very bad */
+ assert(adip->countdown == -1);
+
+ adip->countdown = countdown;
+ adip->war_reason = reason;
+
+ players_iterate(ally) {
+ if (!pplayers_allied(pplayer, ally) || !ally->is_alive) {
+ continue;
+ }
+
+ switch (reason) {
+ case WAR_REASON_SPACE:
+ notify(ally, _("*%s (AI)* We will be launching an all-out war "
+ "against %s in %d turns to stop the spaceship "
+ "launch."), pplayer->name, target->name, countdown);
+ notify(ally, _("*%s (AI)* Your aid in this matter will be expected. "
+ "Long live our glorious alliance!"), pplayer->name);
+ break;
+ case WAR_REASON_BEHAVIOUR:
+ case WAR_REASON_EXCUSE:
+ notify(ally, _("*%s (AI)* %s has grossly violated his treaties with us "
+ "for own gain. We will answer in force in %d turns "
+ "and expect you to honour your alliance with us and do "
+ "likewise!"), pplayer->name, target->name, countdown);
+ break;
+ case WAR_REASON_NONE:
+ notify(ally, _("*%s (AI)* We intend to pillage and plunder the rich "
+ "civilization of %s. We declare war in %d turns."),
+ pplayer->name, target->name, countdown);
+ notify(ally, _("*%s (AI)* If you want a piece of the loot, feel "
+ "free to join in the action!"), pplayer->name);
+ break;
+ case WAR_REASON_HATRED:
+ notify(ally, _("*%s (AI)* We have had it with %s. Let us tear this "
+ "pathetic civilization apart. We declare war in %d "
+ "turns."), pplayer->name, target->name, countdown);
+ notify(ally, _("*%s (AI)* As our glorious allies, we expect your "
+ "help in this war."), pplayer->name);
+ break;
+ case WAR_REASON_ALLIANCE:
+ if (WAR(ally, target)) {
+ notify(ally, _("*%s (AI)* We will honour our alliance and declare "
+ "war on %s in %d turns. Hold on - we are coming!"),
+ pplayer->name, target->name, countdown);
+ } else if (adip->at_war_with_ally) {
+ notify(ally, _("*%s (AI)* We will honour our alliance with %s and "
+ "declare war on %s in %d turns. We expect you to "
+ "do likewise."), pplayer->name,
+ adip->at_war_with_ally->name, target->name,
+ countdown);
+ } else {
+ assert(FALSE); /* Huh? */
+ }
+ break;
+ }
+ } players_iterate_end;
}
/**********************************************************************
@@ -1109,7 +1188,9 @@
void ai_diplomacy_actions(struct player *pplayer)
{
struct ai_data *ai = ai_data_get(pplayer);
- struct player *target = ai->diplomacy.target;
+ bool need_targets = TRUE;
+ struct player *target = NULL;
+ int most_hatred = MAX_AI_LOVE;
assert(pplayer->ai.control);
if (!pplayer->is_alive) {
@@ -1120,12 +1201,10 @@
players_iterate(aplayer) {
if (pplayer->ai.love[aplayer->player_no] < 0
- && pplayer->diplstates[aplayer->player_no].has_reason_to_cancel >= 2) {
- DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Declaring war on %s in revenge",
- target->name);
- notify(target, _("*%s (AI)* I will NOT accept such behaviour! This "
- "means WAR!"), pplayer->name);
- ai_go_to_war(pplayer, ai, aplayer);
+ && pplayer->diplstates[aplayer->player_no].has_reason_to_cancel >= 2
+ && ai->diplomacy.player_intel[aplayer->player_no].countdown == -1) {
+ DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "Plans war in revenge");
+ war_countdown(pplayer, aplayer, map.size, WAR_REASON_BEHAVIOUR);
}
} players_iterate_end;
@@ -1139,7 +1218,9 @@
if (!aplayer->is_alive || aplayer == pplayer
|| players_on_same_team(pplayer, aplayer)
- || ship->state == SSHIP_NONE) {
+ || adip->countdown >= 0
+ || ship->state == SSHIP_NONE
+ || NEVER_MET(pplayer, aplayer)) {
continue;
}
/* A spaceship victory is always one single player's or team's victory */
@@ -1158,6 +1239,7 @@
pplayer->ai.love[aplayer->player_no] = -(BIG_NUMBER);
} else if (ship->state == SSHIP_STARTED
&& adip->warned_about_space == 0) {
+ pplayer->ai.love[aplayer->player_no] -= MAX_AI_LOVE / 10;
adip->warned_about_space = 10 + myrand(6);
notify(aplayer, _("*%s (AI)* Your attempt to unilaterally "
"dominate outer space is highly offensive."), pplayer->name);
@@ -1167,38 +1249,44 @@
if (aplayer->spaceship.state == SSHIP_LAUNCHED
&& aplayer == ai->diplomacy.spacerace_leader) {
/* This means war!!! */
- ai->diplomacy.timer = 0; /* Force reevaluation next turn */
+ pplayer->ai.love[aplayer->player_no] -= MAX_AI_LOVE / 2;
+ DIPLO_LOG(LOG_DIPL, pplayer, aplayer, "plans war due to spaceship");
+ war_countdown(pplayer, aplayer, 4 + map.size, WAR_REASON_SPACE);
}
} players_iterate_end;
}
- /*** Declare war - against target ***/
+ /*** Declare war against somebody if we are out of targets ***/
+
+ players_iterate(aplayer) {
+ if (aplayer->is_alive
+ && WAR(pplayer, aplayer)) {
+ need_targets = FALSE;
+ } else if (aplayer->is_alive
+ && pplayer->ai.love[aplayer->player_no] < most_hatred) {
+ most_hatred = pplayer->ai.love[aplayer->player_no];
+ target = aplayer;
+ }
+ } players_iterate_end;
+ if (need_targets && target && most_hatred < WAR_THRESHOLD
+ && ai->diplomacy.player_intel[target->player_no].countdown == -1) {
+ enum war_reason war_reason;
- if (target && pplayers_at_war(pplayer, target)) {
- ai->diplomacy.countdown = 0; /* cosmetic */
- }
- if (target && !pplayers_at_war(pplayer, target)
- && ai->diplomacy.countdown <= 0
- && !ai_handicap(pplayer, H_AWAY)) {
if (pplayers_allied(pplayer, target)) {
- DIPLO_LOG(LOG_DEBUG, pplayer, ai, "Went to war against %s, who is "
- "an ally!", target->name); /* Oh, my. */
+ DIPLO_LOG(LOG_DEBUG, pplayer, target, "Plans war against an ally!");
}
if (pplayer->diplstates[target->player_no].has_reason_to_cancel > 0) {
/* We have good reason */
- notify(target, _("*%s (AI)* Your despicable actions will not go "
- "unpunished!"), pplayer->name);
+ war_reason = WAR_REASON_EXCUSE;
} if (pplayer->ai.love[target->player_no] < 0) {
- /* We have a reason of sorts from way back. */
- notify(target, _("*%s (AI)* Finally I get around to you! Did "
- "you really think you could get away with your crimes?"),
- pplayer->name);
+ /* We have a reason of sorts from way back, maybe? */
+ war_reason = WAR_REASON_HATRED;
} else {
/* We have no legimitate reason... So what? */
- notify(target, _("*%s (AI)* Peace in ... some other time"),
- pplayer->name);
+ war_reason = WAR_REASON_NONE;
}
- ai_go_to_war(pplayer, ai, target);
+ DIPLO_LOG(LOG_DEBUG, pplayer, target, "plans war for spoils");
+ war_countdown(pplayer, target, 4 + map.size, war_reason);
}
/*** Declare war - against enemies of allies ***/
@@ -1208,19 +1296,37 @@
if (aplayer->is_alive
&& adip->at_war_with_ally
+ && adip->countdown == -1
&& !adip->is_allied_with_ally
&& !pplayers_at_war(pplayer, aplayer)
&& (pplayer_get_diplstate(pplayer, aplayer)->type != DS_CEASEFIRE ||
myrand(5) < 1)) {
- notify(aplayer, _("*%s (AI)* Your aggression against %s was "
- "your last mistake!"),
- pplayer->name,
- adip->at_war_with_ally->name);
- ai_go_to_war(pplayer, ai, aplayer);
+ DIPLO_LOG(LOG_DEBUG, pplayer, aplayer, "plans war to help ally %s",
+ adip->at_war_with_ally->name);
+ war_countdown(pplayer, aplayer, 2 + map.size, WAR_REASON_ALLIANCE);
+ }
+ } players_iterate_end;
+
+ /*** Actually declare war (when we have moved units into position) ***/
+
+ players_iterate(aplayer) {
+ struct ai_dip_intel *adip =
+ &ai->diplomacy.player_intel[aplayer->player_no];
+
+ if (adip->countdown > 0) {
+ adip->countdown--;
+ } else if (adip->countdown == 0) {
+ if (!WAR(pplayer, aplayer)) {
+ DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "Declaring war!");
+ ai_go_to_war(pplayer, ai, aplayer, adip->war_reason);
+ }
+ } else if (adip->countdown < -1) {
+ /* negative countdown less than -1 is war stubbornness */
+ adip->countdown++;
}
} players_iterate_end;
- /*** Opportunism, Inc. Try to make peace with everyone else ***/
+ /*** Try to make peace with everyone we love ***/
players_iterate(aplayer) {
enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
@@ -1248,6 +1354,7 @@
|| aplayer == pplayer
|| aplayer == target /* no mercy */
|| !aplayer->is_alive
+ || adip->countdown >= 0
|| !could_meet_with_player(pplayer, aplayer)
|| adip->at_war_with_ally) {
continue;
@@ -1280,13 +1387,26 @@
ai_share(pplayer, aplayer);
break;
case DS_ALLIANCE:
- if (players_on_same_team(pplayer, aplayer)
- || (target && (!pplayers_at_war(pplayer, target)
- || pplayers_at_war(aplayer, target)))) {
- /* Share techs only with team mates and _reliable_ allies.
- * This means, if we have a target, then unless we are still
- * in countdown mode, we _except_ our allies to be at war
- * with our target too! */
+ /* See if our allies are diligently declaring war on our enemies... */
+ target = NULL;
+ players_iterate(eplayer) {
+ int e = eplayer->player_no;
+
+ /* Read the countdown check below carefully... Note that we check
+ * our ally's intentions directly here. */
+ if (WAR(pplayer, eplayer)
+ && (ai_data_get(aplayer)->diplomacy.player_intel[e].countdown
+ == -1)
+ && !pplayers_at_war(aplayer, eplayer)) {
+ target = eplayer;
+ break;
+ }
+ } players_iterate_end;
+
+ if ((players_on_same_team(pplayer, aplayer)
+ || pplayer->ai.love[aplayer->player_no] > MAX_AI_LOVE / 2)
+ && !target) {
+ /* Share techs only with team mates and allies we really like. */
ai_share(pplayer, aplayer);
adip->ally_patience = 0;
break;
@@ -1294,14 +1414,7 @@
adip->ally_patience = 0;
break;
}
- if (target && pplayer->ai.control) {
- DIPLO_LOG(LOG_DIPL2, pplayer, ai, "Ally %s not at war with enemy %s "
- "(patience %d, %s %s)", aplayer->name,
- target->name, adip->ally_patience, adip->at_war_with_ally
- ? "war_with_ally" : "", adip->is_allied_with_ally ?
- "allied_with_ally" : "");
- }
switch (adip->ally_patience--) {
case 0:
notify(aplayer, _("*%s (AI)* Greetings our most trustworthy "
@@ -1318,8 +1431,7 @@
"alliance, and yet you remain at peace with our mortal "
"enemy, %s! This is unacceptable, our alliance is no "
"more!"), pplayer->name, target->name);
- DIPLO_LOG(LOG_DIPL2, pplayer, ai, "breaking useless alliance with "
- "%s", aplayer->name);
+ DIPLO_LOG(LOG_DIPL2, pplayer, aplayer, "breaking useless alliance");
/* to peace */
handle_diplomacy_cancel_pact(pplayer, aplayer->player_no,
CLAUSE_ALLIANCE);
@@ -1337,15 +1449,14 @@
clause.type = CLAUSE_ALLIANCE;
if (ai_goldequiv_clause(pplayer, aplayer,
&clause, ai, FALSE, DS_ALLIANCE) < 0
- || (adip->asked_about_alliance > 0 && !aplayer->ai.control)
- || !target) {
- /* Note that we don't ever ask for alliance unless we have a target */
+ || (adip->asked_about_alliance > 0 && !aplayer->ai.control)) {
break;
}
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_ALLIANCE, 0);
adip->asked_about_alliance = !aplayer->ai.control ? 13 : 0;
notify(aplayer, _("*%s (AI)* Greetings friend, may we suggest "
- "a joint campaign against %s?"), pplayer->name, target->name);
+ "making a common cause and join in an alliance?"),
+ pplayer->name);
break;
case DS_CEASEFIRE:
@@ -1353,15 +1464,13 @@
clause.type = CLAUSE_PEACE;
if (ai_goldequiv_clause(pplayer, aplayer, &clause,
ai, FALSE, CLAUSE_PEACE) < 0
- || (adip->asked_about_peace > 0 && !aplayer->ai.control)
- || !target) {
- /* Note that we don't ever ask for peace unless we have a target */
+ || (adip->asked_about_peace > 0 && !aplayer->ai.control)) {
break; /* never */
}
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_PEACE, 0);
adip->asked_about_peace = !aplayer->ai.control ? 12 : 0;
notify(aplayer, _("*%s (AI)* Greetings neighbour, may we suggest "
- "a joint campaign against %s?"), pplayer->name, target->name);
+ "more peaceful relations?"), pplayer->name);
break;
case DS_NO_CONTACT: /* but we do have embassy! weird. */
@@ -1369,15 +1478,14 @@
clause.type = CLAUSE_CEASEFIRE;
if (ai_goldequiv_clause(pplayer, aplayer,
&clause, ai, FALSE, CLAUSE_CEASEFIRE) < 0
- || (adip->asked_about_ceasefire > 0 && !aplayer->ai.control)
- || !target) {
+ || (adip->asked_about_ceasefire > 0 && !aplayer->ai.control)) {
break; /* Fight until the end! */
}
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_CEASEFIRE, 0);
adip->asked_about_ceasefire = !aplayer->ai.control ? 9 : 0;
- notify(aplayer, _("*%s (AI)* %s is threatening us both, may we "
- "suggest a cessation of hostilities?"), pplayer->name,
- target->name);
+ notify(aplayer, _("*%s (AI)* we grow weary of this constant "
+ "bloodshed, may we suggest a cessation of hostilities?"),
+ pplayer->name);
break;
default:
die("Unknown pact type");
@@ -1386,6 +1494,23 @@
} players_iterate_end;
}
+/**********************************************************************
+ Are we going to be declaring war in a few turns time? If so, go
+ on a war footing, and try to buy out as many units as possible.
+***********************************************************************/
+bool ai_on_war_footing(struct player *pplayer)
+{
+ struct ai_data *ai = ai_data_get(pplayer);
+
+ players_iterate(plr) {
+ if (ai->diplomacy.player_intel[plr->player_no].countdown >= 0) {
+ return TRUE;
+ }
+ } players_iterate_end;
+
+ return FALSE;
+}
+
/* AI attitude call-backs */
/**********************************************************************
@@ -1396,6 +1521,10 @@
{
if (violator == victim) {
players_iterate(pplayer) {
+ if (!pplayer->ai.control) {
+ continue;
+ }
+
if (pplayer != violator) {
pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 20;
}
@@ -1403,6 +1532,10 @@
return;
} else {
players_iterate(pplayer) {
+ if (!pplayer->ai.control) {
+ continue;
+ }
+
if (pplayer != violator) {
pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 10;
if (victim == pplayer) {
@@ -1419,6 +1552,10 @@
void ai_incident_diplomat(struct player *violator, struct player *victim)
{
players_iterate(pplayer) {
+ if (!pplayer->ai.control) {
+ continue;
+ }
+
if (pplayer != violator) {
/* Dislike backstabbing bastards */
pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 100;
@@ -1440,6 +1577,10 @@
void ai_incident_war(struct player *violator, struct player *victim)
{
players_iterate(pplayer) {
+ if (!pplayer->ai.control) {
+ continue;
+ }
+
if (pplayer != violator) {
/* Dislike backstabbing bastards */
pplayer->ai.love[violator->player_no] -= MAX_AI_LOVE / 30;
@@ -1454,6 +1595,16 @@
if (victim == pplayer) {
pplayer->ai.love[violator->player_no] -=
MIN(pplayer->ai.love[violator->player_no] - MAX_AI_LOVE / 3, -1);
+ /* Scream for help!! */
+ players_iterate(ally) {
+ if (!pplayers_allied(pplayer, ally) || !ally->is_alive) {
+ continue;
+ }
+ notify(ally, _("*%s (AI)* We have been savagely attacked by "
+ "%s, and we need your help! Honour our glorious "
+ "alliance and your name will never be forgotten!"),
+ victim->name, violator->name);
+ } players_iterate_end;
}
}
} players_iterate_end;
Index: ai/advdiplomacy.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/advdiplomacy.h,v
retrieving revision 1.4
diff -u -r1.4 advdiplomacy.h
--- ai/advdiplomacy.h 20 Jul 2005 18:28:48 -0000 1.4
+++ ai/advdiplomacy.h 28 Jul 2005 13:09:49 -0000
@@ -20,6 +20,11 @@
struct Clause;
struct ai_data;
+enum war_reason {
+ WAR_REASON_BEHAVIOUR, WAR_REASON_SPACE, WAR_REASON_EXCUSE,
+ WAR_REASON_HATRED, WAR_REASON_ALLIANCE, WAR_REASON_NONE
+};
+
void ai_diplomacy_begin_new_phase(struct player *pplayer,
struct ai_data *ai);
void ai_diplomacy_actions(struct player *pplayer);
@@ -33,4 +38,6 @@
void ai_incident_diplomat(struct player *violator, struct player *victim);
void ai_incident_nuclear(struct player *violator, struct player *victim);
+bool ai_on_war_footing(struct player *pplayer);
+
#endif
Index: ai/aicity.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aicity.c,v
retrieving revision 1.233
diff -u -r1.233 aicity.c
--- ai/aicity.c 26 Jul 2005 17:21:53 -0000 1.233
+++ ai/aicity.c 28 Jul 2005 13:09:50 -0000
@@ -933,6 +933,7 @@
static void ai_city_choose_build(struct player *pplayer, struct city *pcity)
{
struct ai_choice newchoice;
+ struct ai_data *ai = ai_data_get(pplayer);
init_choice(&newchoice);
@@ -947,7 +948,9 @@
ai_barbarian_choose_build(pplayer, &(pcity->ai.choice));
} else {
/* FIXME: 101 is the "overriding military emergency" indicator */
- if (pcity->ai.choice.want <= 100 || pcity->ai.urgency == 0) {
+ if ((pcity->ai.choice.want <= 100 || pcity->ai.urgency == 0)
+ && !(ai_on_war_footing(pplayer) && pcity->ai.choice.want > 0
+ && pcity->id != ai->wonder_city)) {
domestic_advisor_choose_build(pplayer, pcity, &newchoice);
copy_if_better_choice(&newchoice, &(pcity->ai.choice));
}
@@ -1046,11 +1049,10 @@
unit_list_iterate(pcity->tile->units, punit) {
struct unit_type *punittype = can_upgrade_unittype(pplayer, punit->type);
- if (military && (!is_military_unit(punit) || !is_ground_unit(punit))) {
+ if (military && !IS_ATTACKER(punit)) {
/* Only upgrade military units this round */
continue;
- } else if (!military && is_military_unit(punit)
- && unit_type(punit)->transport_capacity == 0) {
+ } else if (!military && IS_ATTACKER(punit)) {
/* Only civilians or tranports this round */
continue;
}
@@ -1081,6 +1083,7 @@
{
struct ai_choice bestchoice;
int cached_limit = ai_gold_reserve(pplayer);
+ bool war_footing = ai_on_war_footing(pplayer);
/* Disband explorers that are at home but don't serve a purpose.
* FIXME: This is a hack, and should be removed once we
@@ -1132,6 +1135,7 @@
} else {
/* If we have urgent want, spend more */
int upgrade_limit = limit;
+
if (pcity->ai.urgency > 1) {
upgrade_limit = pplayer->ai.est_upkeep;
}
@@ -1160,10 +1164,12 @@
/* Don't buy settlers in size 1 cities unless we grow next turn */
continue;
} else if (city_list_size(pplayer->cities) > 6) {
- /* Don't waste precious money buying settlers late game
- * since this raises taxes, and we want science. Adjust this
- * again when our tax algorithm is smarter. */
- continue;
+ /* Don't waste precious money buying settlers late game
+ * since this raises taxes, and we want science. Adjust this
+ * again when our tax algorithm is smarter. */
+ continue;
+ } else if (war_footing) {
+ continue;
}
} else {
/* We are not a settler. Therefore we increase the cash need we
@@ -1177,8 +1183,9 @@
|| (pplayer->economic.gold - buycost < limit);
if (bestchoice.type == CT_ATTACKER
- && buycost
- > unit_build_shield_cost(get_unit_type(bestchoice.choice)) * 2) {
+ && buycost
+ > unit_build_shield_cost(get_unit_type(bestchoice.choice)) * 2
+ && !war_footing) {
/* Too expensive for an offensive unit */
continue;
}
@@ -1214,10 +1221,12 @@
}
} while (TRUE);
- /* Civilian upgrades now */
- city_list_iterate(pplayer->cities, pcity) {
- ai_upgrade_units(pcity, cached_limit, FALSE);
- } city_list_iterate_end;
+ if (!war_footing) {
+ /* Civilian upgrades now */
+ city_list_iterate(pplayer->cities, pcity) {
+ ai_upgrade_units(pcity, cached_limit, FALSE);
+ } city_list_iterate_end;
+ }
freelog(LOG_BUY, "%s wants to keep %d in reserve (tax factor %d)",
pplayer->name, cached_limit, pplayer->ai.maxbuycost);
@@ -1258,6 +1267,9 @@
TIMING_LOG(AIT_CITY_MILITARY, TIMER_START);
military_advisor_choose_build(pplayer, pcity, &pcity->ai.choice);
TIMING_LOG(AIT_CITY_MILITARY, TIMER_STOP);
+ if (ai_on_war_footing(pplayer) && pcity->ai.choice.want > 0) {
+ continue; /* Go, soldiers! */
+ }
/* Will record its findings in pcity->settler_want */
TIMING_LOG(AIT_CITY_TERRAIN, TIMER_START);
contemplate_terrain_improvements(pcity);
Index: ai/aidata.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v
retrieving revision 1.75
diff -u -r1.75 aidata.c
--- ai/aidata.c 26 Jul 2005 17:21:53 -0000 1.75
+++ ai/aidata.c 28 Jul 2005 13:09:50 -0000
@@ -226,8 +226,6 @@
struct ai_data *ai = &aidata[pplayer->player_no];
int i, nuke_units = num_role_units(F_NUCLEAR);
bool danger_of_nukes = FALSE;
- int ally_strength = -1;
- struct player *ally_strongest = NULL;
/*** Threats ***/
@@ -399,14 +397,6 @@
ai->diplomacy.player_intel[i].at_war_with_ally = NULL;
ai->diplomacy.player_intel[i].is_allied_with_ally = NULL;
- /* Determine who is the leader of our alliance. That is,
- * whoever has the more cities. */
- if (pplayers_allied(pplayer, aplayer)
- && city_list_size(aplayer->cities) > ally_strength) {
- ally_strength = city_list_size(aplayer->cities);
- ally_strongest = aplayer;
- }
-
players_iterate(check_pl) {
if (check_pl == pplayer
|| check_pl == aplayer
@@ -427,9 +417,6 @@
}
} players_iterate_end;
}
- if (ally_strongest != ai->diplomacy.alliance_leader) {
- ai->diplomacy.alliance_leader = ally_strongest;
- }
ai->diplomacy.spacerace_leader = player_leading_spacerace();
ai->diplomacy.production_leader = NULL;
@@ -586,19 +573,18 @@
(game.control.government_count + 1) * sizeof(*ai->government_want));
ai->wonder_city = 0;
- ai->diplomacy.target = NULL;
ai->diplomacy.strategy = WIN_OPEN;
ai->diplomacy.timer = 0;
- ai->diplomacy.countdown = 0;
ai->diplomacy.love_coeff = 4; /* 4% */
- ai->diplomacy.love_incr = MAX_AI_LOVE * 4 / 100;
- ai->diplomacy.req_love_for_peace = MAX_AI_LOVE * 8 / 100;
- ai->diplomacy.req_love_for_alliance = MAX_AI_LOVE * 16 / 100;
+ ai->diplomacy.love_incr = MAX_AI_LOVE * 3 / 100;
+ ai->diplomacy.req_love_for_peace = MAX_AI_LOVE / 8;
+ ai->diplomacy.req_love_for_alliance = MAX_AI_LOVE / 4;
ai->diplomacy.req_love_for_ceasefire = 0;
- ai->diplomacy.alliance_leader = pplayer;
for (i = 0; i < MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS; i++) {
ai->diplomacy.player_intel[i].spam = i % 5; /* pseudorandom */
+ ai->diplomacy.player_intel[i].countdown = -1;
+ ai->diplomacy.player_intel[i].war_reason = WAR_REASON_NONE;
ai->diplomacy.player_intel[i].distance = 1;
ai->diplomacy.player_intel[i].ally_patience = 0;
pplayer->ai.love[i] = 1;
Index: ai/aidata.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v
retrieving revision 1.32
diff -u -r1.32 aidata.h
--- ai/aidata.h 26 Jul 2005 17:21:53 -0000 1.32
+++ ai/aidata.h 28 Jul 2005 13:09:51 -0000
@@ -21,6 +21,8 @@
#include "fc_types.h"
#include "improvement.h"
+#include "advdiplomacy.h"
+
/*
* This file and aidata.c contains global data structures for the AI
* and some of the functions that fill them with useful values at the
@@ -49,6 +51,8 @@
char spam; /* timer to avoid spamming a player with chat */
int distance; /* average distance to that player's cities */
+ int countdown; /* we're on a countdown to war declaration */
+ enum war_reason war_reason; /* why we declare war */
char ally_patience; /* we EXPECT our allies to help us! */
char asked_about_peace; /* don't ask again */
char asked_about_alliance; /* don't nag! */
@@ -70,14 +74,11 @@
struct ai_dip_intel player_intel[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS];
enum winning_strategy strategy;
int timer; /* pursue our goals with some stubbornness, in turns */
- int countdown; /* countdown to we actually declare war */
- struct player *target; /* Concentrate on this player */
char love_coeff; /* Reduce love with this % each turn */
char love_incr; /* Modify love with this fixed amount */
int req_love_for_peace;
int req_love_for_alliance;
int req_love_for_ceasefire;
- struct player *alliance_leader; /* Who is leading our alliance */
struct player *spacerace_leader; /* who is leading the space pack */
struct player *production_leader;
} diplomacy;
Index: ai/aihand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aihand.c,v
retrieving revision 1.118
diff -u -r1.118 aihand.c
--- ai/aihand.c 29 Jun 2005 08:21:25 -0000 1.118
+++ ai/aihand.c 28 Jul 2005 13:09:51 -0000
@@ -242,7 +242,7 @@
/* Ok, we now have the desired tax and luxury rates. Do we really want
* science? If not, swap it with tax if it is bigger. */
- if (ai_wants_no_science(pplayer)
+ if ((ai_wants_no_science(pplayer) || ai_on_war_footing(pplayer))
&& pplayer->economic.science > pplayer->economic.tax) {
int science = pplayer->economic.science;
/* Swap science and tax */
Index: ai/ailog.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.c,v
retrieving revision 1.28
diff -u -r1.28 ailog.c
--- ai/ailog.c 7 May 2005 13:35:25 -0000 1.28
+++ ai/ailog.c 28 Jul 2005 13:09:51 -0000
@@ -76,37 +76,32 @@
/**************************************************************************
Log player messages, they will appear like this
- 2: perrin [ti12 co6 lo5 e] Increased love for a (now 9)
+
where ti is timer, co countdown and lo love for target, who is e.
**************************************************************************/
-void DIPLO_LOG(int level, struct player *pplayer, struct ai_data *ai,
+void DIPLO_LOG(int level, struct player *pplayer, struct player *aplayer,
const char *msg, ...)
{
- char targetbuffer[250];
char buffer[500];
char buffer2[500];
va_list ap;
int minlevel = MIN(LOGLEVEL_PLAYER, level);
+ struct ai_data *ai;
+ struct ai_dip_intel *adip;
if (BV_ISSET(pplayer->debug, PLAYER_DEBUG_DIPLOMACY)) {
minlevel = LOG_NORMAL;
} else if (minlevel > fc_log_level) {
return;
}
+ ai = ai_data_get(pplayer);
+ adip = &ai->diplomacy.player_intel[aplayer->player_no];
- if (ai->diplomacy.target) {
- my_snprintf(targetbuffer, sizeof(targetbuffer), "[ti%d co%d lo%d %s] ",
- ai->diplomacy.timer, ai->diplomacy.countdown,
- pplayer->ai.love[ai->diplomacy.target->player_no],
- ai->diplomacy.target->name);
- }
- my_snprintf(buffer, sizeof(buffer), "%s %s%s%s ", pplayer->name,
- ai->diplomacy.target ? targetbuffer : "",
- ai->diplomacy.spacerace_leader &&
- ai->diplomacy.spacerace_leader->player_no == pplayer->player_no
?
- "(spacelead) " : "",
- ai->diplomacy.alliance_leader->player_no == pplayer->player_no ?
- "(*)" : "");
+ my_snprintf(buffer, sizeof(buffer), "%s->%s(l%d,c%d,d%d%s): ",
+ pplayer->name, aplayer->name,
+ pplayer->ai.love[aplayer->player_no], adip->countdown,
+ adip->distance, adip->is_allied_with_enemy ? "?" :
+ (adip->at_war_with_ally ? "!" : ""));
va_start(ap, msg);
my_vsnprintf(buffer2, sizeof(buffer2), msg, ap);
Index: ai/ailog.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/ailog.h,v
retrieving revision 1.14
diff -u -r1.14 ailog.h
--- ai/ailog.h 7 May 2005 13:35:25 -0000 1.14
+++ ai/ailog.h 28 Jul 2005 13:09:51 -0000
@@ -74,7 +74,7 @@
void TECH_LOG(int level, struct player *pplayer, Tech_type_id id,
const char *msg, ...)
fc__attribute((format (printf, 4, 5)));
-void DIPLO_LOG(int level, struct player *pplayer, struct ai_data *ai,
+void DIPLO_LOG(int level, struct player *pplayer, struct player *aplayer,
const char *msg, ...)
fc__attribute((format (printf, 4, 5)));
void CITY_LOG(int level, struct city *pcity, const char *msg, ...)
Index: ai/aitools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v
retrieving revision 1.158
diff -u -r1.158 aitools.c
--- ai/aitools.c 25 Jul 2005 11:58:33 -0000 1.158
+++ ai/aitools.c 28 Jul 2005 13:09:52 -0000
@@ -123,7 +123,7 @@
return (pplayer != aplayer
&& (pplayers_at_war(pplayer, aplayer)
- || ai->diplomacy.target == aplayer
+ || adip->countdown >= 0
|| reason != 0
|| adip->is_allied_with_enemy));
}
@@ -1159,6 +1159,8 @@
choice->want = want;
choice->choice = id;
choice->type = CT_BUILDING;
+ CITY_LOG(LOG_DEBUG, pcity, "wants most to build %s at %d",
+ get_improvement_name(id), want);
}
/**********************************************************************
Index: ai/aiunit.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.h,v
retrieving revision 1.60
diff -u -r1.60 aiunit.h
--- ai/aiunit.h 22 Jul 2005 16:18:04 -0000 1.60
+++ ai/aiunit.h 28 Jul 2005 13:09:52 -0000
@@ -25,7 +25,14 @@
*/
#define POWER_DIVIDER (POWER_FACTOR * 3)
-/* Simple military power macros */
+/* Simple military macros */
+
+/* pplayers_at_war() thinks no contacts equals war, which often is
+ * very annoying. */
+#define WAR(plr1, plr2) \
+ (plr1->diplstates[plr2->player_no].type == DS_WAR)
+#define NEVER_MET(plr1, plr2) \
+ (plr1->diplstates[plr2->player_no].type == DS_NO_CONTACT)
#define DEFENCE_POWER(punit) \
(unit_type(punit)->defense_strength * unit_type(punit)->hp \
* unit_type(punit)->firepower)
@@ -36,8 +43,8 @@
(unit_type(punit)->attack_strength \
> unit_type(punit)->transport_capacity)
#define HOSTILE_PLAYER(pplayer, ai, aplayer) \
- (pplayers_at_war(pplayer, aplayer) \
- || ai->diplomacy.target == aplayer)
+ (WAR(pplayer, aplayer) \
+ || ai->diplomacy.player_intel[aplayer->player_no].countdown >= 0)
#define UNITTYPE_COSTS(ut) \
(ut->pop_cost * 3 + ut->happy_cost \
+ ut->upkeep[O_SHIELD] + ut->upkeep[O_FOOD] + ut->upkeep[O_GOLD])
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.403
diff -u -r1.403 plrhand.c
--- server/plrhand.c 22 Jul 2005 02:51:30 -0000 1.403
+++ server/plrhand.c 28 Jul 2005 13:09:59 -0000
@@ -516,6 +516,10 @@
old_type = pplayer->diplstates[other_player_id].type;
pplayer2 = get_player(other_player_id);
+ if (old_type == DS_WAR) {
+ return; /* Duh */
+ }
+
/* can't break a pact with yourself */
if (pplayer == pplayer2) {
return;
@@ -568,6 +572,7 @@
break;
default:
freelog(LOG_ERROR, "non-pact diplstate in handle_player_cancel_pact");
+ assert(FALSE);
return;
}
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.269
diff -u -r1.269 savegame.c
--- server/savegame.c 26 Jul 2005 16:36:00 -0000 1.269
+++ server/savegame.c 28 Jul 2005 13:10:04 -0000
@@ -1737,7 +1737,6 @@
struct ai_data *ai;
struct government *gov;
int id;
- int target_no;
struct team *pteam;
struct player_research *research;
@@ -1888,6 +1887,10 @@
= secfile_lookup_int_default(file, 1, "player%d.ai%d.love", plrno, i);
ai->diplomacy.player_intel[i].spam
= secfile_lookup_int_default(file, 0, "player%d.ai%d.spam", plrno, i);
+ ai->diplomacy.player_intel[i].countdown
+ = secfile_lookup_int_default(file, -1, "player%d.ai%d.countdown",
plrno, i);
+ ai->diplomacy.player_intel[i].war_reason
+ = secfile_lookup_int_default(file, 0, "player%d.ai%d.war_reason",
plrno, i);
ai->diplomacy.player_intel[i].ally_patience
= secfile_lookup_int_default(file, 0, "player%d.ai%d.patience",
plrno, i);
ai->diplomacy.player_intel[i].warned_about_space
@@ -1899,10 +1902,6 @@
ai->diplomacy.player_intel[i].asked_about_ceasefire
= secfile_lookup_int_default(file, 0, "player%d.ai%d.ask_ceasefire",
plrno, i);
}
- /* Diplomacy target is saved as player number or -1 if none */
- target_no = secfile_lookup_int_default(file, -1,
- "player%d.ai.target", plrno);
- ai->diplomacy.target = target_no == -1 ? NULL : &game.players[target_no];
/* Backwards-compatibility: the tech goal value is still stored in the
* "ai" section even though it was moved into the research struct. */
@@ -2690,6 +2689,10 @@
"player%d.ai%d.love", plrno, i);
secfile_insert_int(file, ai->diplomacy.player_intel[i].spam,
"player%d.ai%d.spam", plrno, i);
+ secfile_insert_int(file, ai->diplomacy.player_intel[i].countdown,
+ "player%d.ai%d.countdown", plrno, i);
+ secfile_insert_int(file, ai->diplomacy.player_intel[i].war_reason,
+ "player%d.ai%d.war_reason", plrno, i);
secfile_insert_int(file, ai->diplomacy.player_intel[i].ally_patience,
"player%d.ai%d.patience", plrno, i);
secfile_insert_int(file, ai->diplomacy.player_intel[i].warned_about_space,
@@ -2701,10 +2704,6 @@
secfile_insert_int(file,
ai->diplomacy.player_intel[i].asked_about_ceasefire,
"player%d.ai%d.ask_ceasefire", plrno, i);
}
- secfile_insert_int(file,
- ai->diplomacy.target == NULL ?
- -1 : ai->diplomacy.target->player_no,
- "player%d.ai.target", plrno);
save_technology(file, "player%d.ai.tech_goal",
plrno, get_player_research(plr)->tech_goal);
secfile_insert_int(file, plr->ai.skill_level,
|
|