[freeciv-ai] AI Diplomacy v7 (PR#2413)
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: |
undisclosed-recipients:; |
Subject: |
[freeciv-ai] AI Diplomacy v7 (PR#2413) |
From: |
"Per I. Mathisen" <per@xxxxxxxxxxx> |
Date: |
Thu, 20 Feb 2003 16:17:38 -0800 |
Reply-to: |
rt@xxxxxxxxxxxxxx |
This is an update. CHANGES:
- I've simplified some of the code.
- We don't give away techs to someone who is allied to someone we are at
war with.
- We evaluate the value of offered techs to our allies.
- Fixed some bugs.
Please playtest and report back.
- Per
? 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/02/21 00:10:13
@@ -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.10
diff -u -r1.10 aidata.c
--- ai/aidata.c 2003/02/10 21:43:40 1.10
+++ ai/aidata.c 2003/02/21 00:10:13
@@ -22,14 +22,17 @@
#include "game.h"
#include "government.h"
#include "map.h"
+#include "rand.h"
#include "unit.h"
#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"
@@ -195,6 +198,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
@@ -223,6 +232,28 @@
free(ai->threats.continent); ai->threats.continent = NULL;
free(ai->stats.workers); ai->stats.workers = NULL;
free(ai->stats.cities); ai->stats.cities = NULL;
+}
+
+/**************************************************************************
+ 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.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 = i; /* pseudorandom */
+ ai->diplomacy.other[i].distance = 1;
+ ai->diplomacy.other[i].ally_patience = 0;
+ ai->diplomacy.other[i].hatred = 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/02/21 00:10:13
@@ -24,7 +24,30 @@
* 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 */
+};
+
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! */
+ int hatred; /* like negative reputation, only worse */
+ } other[MAX_NUM_PLAYERS];
+ struct player *target; /* concentrate on this player */
+ int mil_strength; /* Estimate of our military strength */
+ } diplomacy;
+
/* Long-term threats, not to be confused with short-term danger */
struct {
bool invasions; /* check if we need to consider invasions */
@@ -63,6 +86,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.163
diff -u -r1.163 civclient.c
--- client/civclient.c 2003/02/13 00:48:45 1.163
+++ client/civclient.c 2003/02/21 00:10:13
@@ -820,7 +820,7 @@
return (pplayer->is_alive
&& pplayer != game.player_ptr
&& player_has_embassy(game.player_ptr, pplayer)
- && pplayer->is_connected
+ && (pplayer->is_connected || pplayer->ai.control)
&& can_client_issue_orders());
}
Index: client/options.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/options.c,v
retrieving revision 1.77
diff -u -r1.77 options.c
--- client/options.c 2002/12/21 14:19:05 1.77
+++ client/options.c 2003/02/21 00:10:13
@@ -278,6 +278,7 @@
GEN_EV(N_("Wonder: Started"), E_WONDER_STARTED),
GEN_EV(N_("Wonder: Stopped"), E_WONDER_STOPPED),
GEN_EV(N_("Wonder: Will Finish Next Turn"), E_WONDER_WILL_BE_BUILT),
+ GEN_EV(N_("Diplomatic Message"), E_DIPLOMACY),
GEN_EV_TERMINATOR
};
Index: common/events.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/events.h,v
retrieving revision 1.22
diff -u -r1.22 events.h
--- common/events.h 2002/05/07 07:40:53 1.22
+++ common/events.h 2003/02/21 00:10:14
@@ -102,6 +102,7 @@
E_WONDER_STARTED,
E_WONDER_STOPPED,
E_WONDER_WILL_BE_BUILT,
+ E_DIPLOMACY,
/*
* Note: If you add a new event, make sure you make a similar change
* to the events array in client/options.c using GEN_EV and to
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.111
diff -u -r1.111 player.c
--- common/player.c 2003/02/12 22:22:33 1.111
+++ common/player.c 2003/02/21 00:10:14
@@ -561,6 +561,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.94
diff -u -r1.94 player.h
--- common/player.h 2003/02/15 15:35:02 1.94
+++ common/player.h 2003/02/21 00:10:14
@@ -260,6 +260,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/02/21 00:10:14
@@ -37,6 +37,8 @@
#include "settlers.h"
#include "unittools.h"
+#include "advdiplomacy.h"
+
#include "diplhand.h"
#define SPECLIST_TAG treaty
@@ -286,8 +288,16 @@
pgiver = pclause->from;
pdest = (plr0==pgiver) ? plr1 : plr0;
+ ai_treaty_react(pgiver, pdest, pclause);
+
switch (pclause->type) {
case CLAUSE_ADVANCE:
+ /* It is possible that two players open the diplomacy dialog
+ * and try to give us the same tech at the same time. This
+ * should be handled discreetly instead of giving a core dump. */
+ if (get_invention(pdest, pclause->value) == TECH_KNOWN) {
+ break;
+ }
notify_player_ex(pdest, -1, -1, E_TECH_GAIN,
_("Game: You are taught the knowledge of %s."),
get_tech_name(pdest, pclause->value));
@@ -425,6 +435,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 +484,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 +558,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 +607,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.260
diff -u -r1.260 plrhand.c
--- server/plrhand.c 2003/02/12 22:22:34 1.260
+++ server/plrhand.c 2003/02/21 00:10:14
@@ -1327,6 +1327,7 @@
player_map_allocate(pplayer);
}
player_init(pplayer);
+ ai_data_init(pplayer);
}
/**********************************************************************
@@ -1570,10 +1571,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;
@@ -1599,7 +1600,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.114
diff -u -r1.114 srv_main.c
--- server/srv_main.c 2003/02/12 22:22:35 1.114
+++ server/srv_main.c 2003/02/21 00:10:14
@@ -90,6 +90,7 @@
#include "unithand.h"
#include "unittools.h"
+#include "advdiplomacy.h"
#include "advmilitary.h"
#include "aidata.h"
#include "aihand.h"
@@ -465,6 +466,9 @@
} players_iterate_end;
players_iterate(pplayer) {
+ if (pplayer->ai.control && !is_barbarian(pplayer)) {
+ ai_diplomacy_actions(pplayer);
+ }
send_player_cities(pplayer);
} players_iterate_end;
/**********************************************************************
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_diplomacy_actions(struct player *pplayer);
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) 2002 - 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)
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 "diptreaty.h"
#include "events.h"
#include "game.h"
#include "packets.h"
#include "player.h"
#include "rand.h"
#include "log.h"
#include "mem.h"
#include "nation.h"
#include "shared.h"
#include "support.h"
#include "tech.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_DEBUG
#define LOG_DIPL2 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 int ai_goldequiv_clause(struct player *pplayer, struct player *aplayer,
struct Clause *pclause, struct ai_data *ai);
/* one hundred thousand */
#define BIG_NUMBER 100000
/**********************************************************************
Send a diplomatic message. Use this instead of notify directly
because we may want to highligh/present these messages differently
in the future.
***********************************************************************/
#define diplo_notify(pplayer, text, ...) \
notify_player_ex(pplayer, -1, -1, E_DIPLOMACY, 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 = 0; /* worth for pplayer of what aplayer gives */
bool give = (pplayer == pclause->from);
int receiver, giver;
giver = pclause->from->player_no;
if (give) {
receiver = aplayer->player_no;
} else {
receiver = pplayer->player_no;
}
switch (pclause->type) {
case CLAUSE_ADVANCE:
if (give) {
worth -= ai_goldequiv_tech(aplayer, pclause->value);
} else {
worth += ai_goldequiv_tech(pplayer, pclause->value);
}
/* Share and expect being shared brotherly between allies */
if (pplayers_allied(pplayer, aplayer)) {
return 0;
}
/* Calculate in tech leak to our opponents, guess 50% chance */
players_iterate(eplayer) {
if (eplayer == aplayer
|| eplayer == pplayer
|| !eplayer->is_alive
|| get_invention(eplayer, pclause->value) == TECH_KNOWN) {
continue;
}
if (give && pplayers_allied(aplayer, eplayer)) {
if (pplayers_at_war(aplayer, eplayer)) {
/* Don't risk it falling into enemy hands */
return -BIG_NUMBER;
}
worth -= ai_goldequiv_tech(eplayer, pclause->value) / 2;
} else if (!give && pplayers_allied(pplayer, eplayer)) {
/* We can enrichen our side with this tech */
worth += ai_goldequiv_tech(eplayer, pclause->value) / 4;
}
} players_iterate_end;
break;
case CLAUSE_ALLIANCE:
case CLAUSE_PEACE:
case CLAUSE_CEASEFIRE:
worth = ai->diplomacy.other[aplayer->player_no].war_desire;
/* Breaking treaties give us penalties on future diplomacy, so
* avoid flip-flopping treaty/war with our enemy. */
if (aplayer == ai->diplomacy.target) {
worth *= 3;
}
/* We don't want treaties that obstruct our aims, but if cost
is negative then we want 'em this much. */
worth -= worth * TRADE_WEIGHTING * MIN(city_list_size(&aplayer->cities),
20);
freelog(LOG_DIPL, "(%s ai diplo) Calculating pact with %s as (%d*%d*%d=)%d",
pplayer->name, aplayer->name, worth, TRADE_WEIGHTING,
MIN(20, city_list_size(&aplayer->cities)),
worth);
/* 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 {
/* Big decision */
worth *= 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
&& check_pl->is_alive
&& pplayers_allied(pplayer, check_pl)) {
if (pplayers_allied(aplayer, check_pl)) {
player_is_allied_with_ally = TRUE;
} else if (pplayers_at_war(aplayer, check_pl)) {
diplo_notify(aplayer, TALK(%s) "First make peace with %s, %s",
pplayer->name, check_pl->name, aplayer->name);
return -FC_INFINITY;
}
}
} players_iterate_end;
if (!pplayers_in_peace(pplayer, aplayer)) {
diplo_notify(aplayer, TALK(%s) "Let us first make peace, %s",
pplayer->name, aplayer->name);
return -FC_INFINITY;
} else if (!player_is_allied_with_ally) {
/* Really big decision */
worth *= 3;
} else {
/* An ally's ally: Let's all join hands! */
worth = MAX(1, worth);
}
}
/* Modify for reputation (this one hurts hard) */
worth -= (GAME_DEFAULT_REPUTATION - aplayer->reputation)
* city_list_size(&aplayer->cities) / 4;
break;
case CLAUSE_GOLD:
if (give) {
worth -= pclause->value;
} else {
worth += pclause->value;
}
break;
case CLAUSE_SEAMAP:
if (!give || pplayers_allied(pplayer, aplayer)) {
/* Useless to us - we're omniscient! And allies get it for free! */
return 0;
}
/* 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. */
worth -= 25 * city_list_size(&aplayer->cities);
break;
case CLAUSE_MAP:
if (!give || pplayers_allied(pplayer, aplayer)) {
/* Useless to us - we're omniscient! And allies get it for free! */
return 0;
}
/* Very silly algorithm 2: Land map more worth the more cities
we have, since we expose all of these to the enemy. */
worth -= 75 * city_list_size(&pplayer->cities);
/* Inflate numbers if not peace */
if (!pplayers_in_peace(pplayer, aplayer)) {
worth *= 3;
}
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 */
diplo_notify(aplayer, TALK(%s) "You don't have the offered city!",
pplayer->name);
return 0;
}
if (give) {
/* AI must be crazy to trade away its cities */
worth -= ai_goldequiv_city(offer);
if (city_got_building(offer, B_PALACE)) {
return -FC_INFINITY; /* Never! Ever! */
} else {
return (worth * 15);
}
} else {
return ai_goldequiv_city(offer);
}
break;
}
case CLAUSE_VISION:
if (give) {
if (pplayers_allied(pplayer, aplayer)) {
return 0;
} else {
/* so out of the question */
return -FC_INFINITY;
}
} else {
worth = 0; /* We are omniscient, so... */
}
break;
} /* end of switch */
return worth;
}
/**********************************************************************
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);
}
}
/**********************************************************************
Comments to player from AI on clauses being agreed on. Does not
alter any state.
***********************************************************************/
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_DIPL2, "(%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_DIPL2, "(%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_DIPL2, "(%s ai diplo) %s agrees to ceasefire with %s",
pplayer->name, pplayer->name, aplayer->name);
break;
default:
break;
}
}
/**********************************************************************
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 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 (!aplayer->is_alive) {
continue;
}
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;
enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
bool cancel_excuse =
pplayer->diplstates[aplayer->player_no].has_reason_to_cancel;
/* 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 division is for the unlikely case of several
simultaneous ship launches. */
kill_desire = BIG_NUMBER / arrival / 2;
ai->diplomacy.timer = BIG_NUMBER;
ai->diplomacy.strategy = WIN_CAPITAL;
}
}
/* Modify by which treaties we would have to break, and what
* excuses we have to do so. */
if (!cancel_excuse) {
if (ds == DS_CEASEFIRE) {
kill_desire -= kill_desire / 10; /* 10% off */
} else if (ds == DS_NEUTRAL) {
kill_desire -= kill_desire / 7; /* 15% off */
} else if (ds == DS_PEACE) {
kill_desire -= kill_desire / 5; /* 20% off */
} else if (ds == DS_ALLIANCE) {
kill_desire -= kill_desire / 3; /* 33% off here, more later */
}
}
/* Modify by hatred */
kill_desire += kill_desire / 100
* ai->diplomacy.other[aplayer->player_no].hatred * 10;
/* Amortize by distance */
return amortize(kill_desire,
ai->diplomacy.other[aplayer->player_no].distance);
}
/**********************************************************************
Calculate relative military strength of us vs him. This is not the
place to calculate the worth of his 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 a 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,
int value)
{
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 = value;
handle_diplomacy_init(pplayer, &packet);
handle_diplomacy_create_clause(pplayer, &packet);
}
/**********************************************************************
Calculate our diplomatic predispositions here. Don't do anything.
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);
assert(pplayer->ai.control);
if (!pplayer->is_alive) {
return; /* doh */
}
/* If we have been wronged, crank up hatred. If allied, may reduce. */
players_iterate(aplayer) {
ai->diplomacy.other[aplayer->player_no].hatred +=
pplayer->diplstates[aplayer->player_no].has_reason_to_cancel;
if (pplayers_allied(pplayer, aplayer) && myrand(4)) {
ai->diplomacy.other[aplayer->player_no].hatred--;
}
} players_iterate_end;
/* Stop war against a dead player */
if (ai->diplomacy.target && !ai->diplomacy.target->is_alive) {
freelog(LOG_DIPL2, "(%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 || !aplayer->is_alive) {
ai->diplomacy.other[aplayer->player_no].distance = 1;
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 = MAX(dists / cities, 1);
} else {
ai->diplomacy.other[aplayer->player_no].distance = 1;
}
} players_iterate_end;
/* Can we win by space race? */
if (ai_space_victory(pplayer)) {
freelog(LOG_DIPL2, "%s going for space race victory!", pplayer->name);
ai->diplomacy.strategy = WIN_SPACE; /* Yes! */
} else {
if (ai->diplomacy.strategy == WIN_SPACE) {
ai->diplomacy.strategy = WIN_OPEN;
}
}
/* 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 or team members. */
if (aplayer == pplayer
|| !aplayer->is_alive
|| ds == DS_NO_CONTACT
|| (pplayer->team != TEAM_NONE && pplayer->team == aplayer->team)
|| ds == DS_ALLIANCE) {
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)
&& pplayers_at_war(aplayer, eplayer)
&& eplayer->is_alive) {
ai->diplomacy.other[aplayer->player_no].war_desire *= 3;
want_avoid_war = FALSE;
}
} players_iterate_end;
/* Chicken out */
if (want_avoid_war) {
freelog(LOG_DIPL2, "%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_DEBUG, "(%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;
}
}
/**********************************************************************
Balance a suggested treaty. TODO: Suggest other things than gold.
***********************************************************************/
static void ai_balance_treaty(struct player *pplayer, struct ai_data *ai,
struct player *aplayer)
{
int gold = myrand((pplayer->economic.gold - pplayer->ai.est_upkeep) / 2)
+ (pplayer->economic.gold - pplayer->ai.est_upkeep) / 2;
struct Treaty *ptreaty = find_treaty(pplayer, aplayer);
int balance = 0;
if (!ptreaty) {
/* No treaty to balance out */
return;
}
clause_list_iterate(ptreaty->clauses, pclause) {
balance += ai_goldequiv_clause(pplayer, aplayer, pclause, ai);
} clause_list_iterate_end;
balance--;
if (balance > 0) {
gold = MIN(balance, gold);
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_GOLD, gold);
}
}
/**********************************************************************
Offer techs to other player and ask for techs we need.
***********************************************************************/
static void ai_share_techs(struct player *pplayer,
struct player *aplayer)
{
int index;
for (index = A_FIRST; index < game.num_tech_types; index++) {
if ((get_invention(pplayer, index) != TECH_KNOWN)
&& (get_invention(aplayer, index) == TECH_KNOWN)) {
ai_diplomacy_suggest(aplayer, pplayer, CLAUSE_ADVANCE, index);
} else if ((get_invention(pplayer, index) == TECH_KNOWN)
&& (get_invention(aplayer, index) != TECH_KNOWN)) {
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_ADVANCE, index);
}
}
if (!gives_shared_vision(pplayer, aplayer)) {
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_VISION, 0);
}
if (!gives_shared_vision(aplayer, pplayer)) {
ai_diplomacy_suggest(aplayer, pplayer, CLAUSE_VISION, 0);
}
}
/**********************************************************************
Go to war.
***********************************************************************/
static void ai_go_to_war(struct player *pplayer, struct ai_data *ai,
struct player *target)
{
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 = myrand(4) + 3
+ ai->diplomacy.other[target->player_no].hatred;
}
/**********************************************************************
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 ai_diplomacy_actions(struct player *pplayer)
{
struct ai_data *ai = ai_data_get(pplayer);
struct player *target = ai->diplomacy.target;
assert(pplayer->ai.control);
if (!pplayer->is_alive) {
return;
}
/*** If we are greviously insulted, go to war. ***/
players_iterate(aplayer) {
if (aplayer->reputation < GAME_DEFAULT_REPUTATION / 2
&& ai->diplomacy.other[aplayer->player_no].hatred > 2
&& pplayer->diplstates[aplayer->player_no].has_reason_to_cancel == 2) {
freelog(LOG_DIPL2, "(%s ai diplo) Declaring war on %s in revenge",
pplayer->name, target->name);
diplo_notify(target, TALK(%s) "I will NOT accept such behaviour! This "
"means WAR!", pplayer->name);
ai_go_to_war(pplayer, ai, aplayer);
}
} players_iterate_end;
/*** Stop other players from winning by space race ***/
if (ai->diplomacy.strategy != WIN_SPACE) {
players_iterate(aplayer) {
if (!aplayer->is_alive || aplayer == pplayer) {
continue;
}
/* A spaceship victory is always one single player's victory */
if (ai_space_victory(aplayer)) {
if (pplayer->spaceship.state == SSHIP_LAUNCHED
&& pplayers_allied(pplayer, aplayer)) {
diplo_notify(aplayer, TALK(%s) "Your attempt to conquer space for "
"yourself alone betray your true intentions, and I "
"will have no more of our alliance!", pplayer->name);
handle_player_cancel_pact(pplayer, aplayer->player_no);
if (gives_shared_vision(pplayer, aplayer)) {
remove_shared_vision(pplayer, aplayer);
}
} else {
diplo_notify(aplayer, TALK(%s) "Your attempt to unilaterally "
"dominate outer space is highly offensive. If you "
"do not stop constructing your spaceship, "
"I may be forced to take action!", pplayer->name);
}
}
} players_iterate_end;
}
/*** Declare war ***/
if (target && !pplayers_at_war(pplayer, target)) {
freelog(LOG_DIPL2, "(%s ai diplo) Declaring war on %s",
pplayer->name, target->name);
if (pplayer->diplstates[target->player_no].has_reason_to_cancel > 0) {
/* We have good reason */
diplo_notify(target, TALK(%s) "Your despicable actions will not go "
"unpunished!", pplayer->name);
} if (ai->diplomacy.other[target->player_no].hatred > 2) {
/* We once had good reason */
diplo_notify(target, TALK(%s) "Finally I get around to taking "
"revenge for the things you have done to me!",
pplayer->name);
} else {
/* We have no good reason... so what? */
diplo_notify(target, TALK(%s) "Peace in ... some other time",
pplayer->name);
}
ai_go_to_war(pplayer, ai, target);
}
/*** Opportunism, Inc. Try to make peace with everyone else ***/
players_iterate(aplayer) {
enum diplstate_type ds = pplayer_get_diplstate(pplayer, aplayer)->type;
bool transitive_war = FALSE;
if (is_barbarian(aplayer) /* no barbarism */
|| aplayer == pplayer /* no self-indulgence */
|| aplayer == target /* no mercy */
|| !aplayer->is_alive) { /* and no necromancy! */
continue; /* hah! */
}
/* Is there a player that we are allied to which is at
* war with this player? If so, keep war going. */
players_iterate(eplayer) {
if (pplayers_allied(pplayer, eplayer)
&& eplayer->is_alive
&& pplayers_at_war(eplayer, aplayer)) {
transitive_war = TRUE;
}
} players_iterate_end;
if (transitive_war) {
continue;
}
/* Some players we want treaties with badly */
if (ai->diplomacy.other[aplayer->player_no].hatred == 0
&& ai->diplomacy.other[aplayer->player_no].war_fear > 0
&& aplayer->reputation > GAME_DEFAULT_REPUTATION / 2) {
ai->diplomacy.other[aplayer->player_no].war_desire =
-(ai->diplomacy.other[aplayer->player_no].war_fear
* aplayer->reputation / GAME_DEFAULT_REPUTATION);
} else {
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. */
if (!pplayers_allied(pplayer, aplayer)) {
ai->diplomacy.other[aplayer->player_no].spam = myrand(4)+3;
} else {
/* Less important. */
ai->diplomacy.other[aplayer->player_no].spam = myrand(12)+6;
}
switch (ds) {
case DS_ALLIANCE:
if ((pplayer->team != TEAM_NONE && aplayer->team == pplayer->team)
|| (target && pplayers_at_war(aplayer, target))) {
/* Share techs only with team mates and _reliable_ allies */
ai_share_techs(pplayer, aplayer);
break;
} else if (!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_DIPL2, "(%s ai diplo) breaking useless alliance with %s",
pplayer->name, aplayer->name);
handle_player_cancel_pact(pplayer, aplayer->player_no); /* peace */
ai->diplomacy.other[aplayer->player_no].hatred++;
if (pplayer->diplstates[aplayer->player_no].has_reason_to_cancel > 0) {
handle_player_cancel_pact(pplayer, aplayer->player_no); /* neutral */
}
if (gives_shared_vision(pplayer, aplayer)) {
remove_shared_vision(pplayer, aplayer);
}
break;
}
break;
case DS_PEACE:
if (aplayer->reputation < GAME_DEFAULT_REPUTATION / 2
|| ai->diplomacy.other[aplayer->player_no].hatred > 2) {
break; /* never */
}
/* If war desire > 0 we may not accept the treaty which we ourselves
* propose! */
ai->diplomacy.other[aplayer->player_no].war_desire =
MIN(0, ai->diplomacy.other[aplayer->player_no].war_desire);
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_ALLIANCE, 0);
ai_balance_treaty(pplayer, ai, aplayer);
if (target) {
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);
} else {
diplo_notify(aplayer, TALK(%s) "You have proven a good friend, %s. How "
"about going into an alliance?", pplayer->name,
aplayer->name);
freelog(LOG_DIPL, "(%s ai diplo) requesting alliance from %s",
pplayer->name, aplayer->name);
}
break;
case DS_CEASEFIRE:
case DS_NEUTRAL:
if (aplayer->reputation < GAME_DEFAULT_REPUTATION / 4
|| ai->diplomacy.other[aplayer->player_no].hatred > 4) {
break;
}
/* If war desire > 0 we may not accept the treaty which we ourselves
* propose! */
ai->diplomacy.other[aplayer->player_no].war_desire =
MIN(0, ai->diplomacy.other[aplayer->player_no].war_desire);
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_PEACE, 0);
ai_balance_treaty(pplayer, ai, aplayer);
if (target) {
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 peace from %s to crush %s",
pplayer->name, aplayer->name, target->name);
} else {
diplo_notify(aplayer, TALK(%s) "I have seen little aggression from you,
"
"%s. Maybe you can be trusted. Shall we sign a peace
treaty?",
pplayer->name, aplayer->name);
freelog(LOG_DIPL, "(%s ai diplo) requesting peace from %s",
pplayer->name, aplayer->name);
}
break;
case DS_WAR:
if (!target && ai->diplomacy.strategy != WIN_SPACE) {
/* Don't end wars if we don't have other targets, or we can win
* through other means. */
break;
}
ai->diplomacy.other[aplayer->player_no].war_desire =
MIN(0, ai->diplomacy.other[aplayer->player_no].war_desire);
ai_diplomacy_suggest(pplayer, aplayer, CLAUSE_CEASEFIRE, 0);
ai_balance_treaty(pplayer, ai, aplayer);
if (target) {
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 ceasefire from %s to crush
%s",
pplayer->name, aplayer->name, target->name);
} else {
diplo_notify(aplayer, TALK(%s) "War is such a terrible waste. Perhaps
we "
"can find a more civilized way of dealing with each
other?",
pplayer->name);
freelog(LOG_DIPL, "(%s ai diplo) requesting ceasefire from %s",
pplayer->name, aplayer->name);
}
break;
default:
assert(FALSE);
break;
}
} players_iterate_end;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [freeciv-ai] AI Diplomacy v7 (PR#2413),
Per I. Mathisen <=
|
|