[Freeciv-Dev] (PR#2415) Patch: autoattack
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=2415 >
This patch:
- Changes the setting to situational.
- Removes unnecessary casts.
- In secfile_lookup_int, takes as default the default value rather than
the current value. (They could differ if you did /load twice. However
most other settings have this problem also.)
jason
? newtiles
? data/isotrident/selection.png
? data/isotrident/selection.spec
Index: ai/aiferry.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/ai/aiferry.c,v
retrieving revision 1.6
diff -u -r1.6 aiferry.c
--- ai/aiferry.c 29 Sep 2004 02:24:18 -0000 1.6
+++ ai/aiferry.c 19 Oct 2004 20:27:01 -0000
@@ -708,6 +708,7 @@
void ai_manage_ferryboat(struct player *pplayer, struct unit *punit)
{
struct city *pcity;
+ int sanity = punit->id;
CHECK_UNIT(punit);
@@ -773,7 +774,6 @@
if (punit->ai.passenger > 0) {
int bossid = punit->ai.passenger; /* Loop prevention */
struct unit *boss = find_unit_by_id(punit->ai.passenger);
- int id = punit->id; /* To check if survived */
assert(boss != NULL);
@@ -787,7 +787,7 @@
unit_type(boss)->name, boss->id);
ai_manage_unit(pplayer, boss);
- if (!find_unit_by_id(id) || punit->moves_left <= 0) {
+ if (!find_unit_by_id(sanity) || punit->moves_left <= 0) {
return;
}
if (find_unit_by_id(bossid)) {
@@ -844,7 +844,7 @@
UNIT_LOG(LOGLEVEL_FERRY, punit, "Passing control of ferry to explorer code");
(void) ai_manage_explorer(punit);
- if (punit->moves_left > 0) {
+ if (find_unit_by_id(sanity) && punit->moves_left > 0) {
struct city *pcity = find_nearest_safe_city(punit);
if (pcity) {
punit->goto_tile = pcity->tile;
Index: common/game.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.c,v
retrieving revision 1.187
diff -u -r1.187 game.c
--- common/game.c 29 Sep 2004 02:24:22 -0000 1.187
+++ common/game.c 19 Oct 2004 20:27:01 -0000
@@ -252,6 +252,7 @@
game.onsetbarbarian = GAME_DEFAULT_ONSETBARBARIAN;
game.nbarbarians = 0;
game.occupychance= GAME_DEFAULT_OCCUPYCHANCE;
+ game.autoattack = GAME_DEFAULT_AUTOATTACK;
game.revolution_length = GAME_DEFAULT_REVOLUTION_LENGTH;
game.heating = 0;
Index: common/game.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/game.h,v
retrieving revision 1.153
diff -u -r1.153 game.h
--- common/game.h 13 Oct 2004 15:47:42 -0000 1.153
+++ common/game.h 19 Oct 2004 20:27:01 -0000
@@ -95,6 +95,7 @@
int onsetbarbarian;
int nbarbarians;
int occupychance;
+ bool autoattack;
int unhappysize;
bool angrycitizen;
char *startmessage;
@@ -470,6 +471,8 @@
#define GAME_MIN_OCCUPYCHANCE 0
#define GAME_MAX_OCCUPYCHANCE 100
+#define GAME_DEFAULT_AUTOATTACK FALSE
+
#define GAME_DEFAULT_RULESETDIR "default"
#define GAME_DEFAULT_SAVE_NAME "civgame"
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.201
diff -u -r1.201 savegame.c
--- server/savegame.c 15 Oct 2004 21:34:24 -0000 1.201
+++ server/savegame.c 19 Oct 2004 20:27:02 -0000
@@ -3203,6 +3203,9 @@
1.10.0 */
game.occupychance = secfile_lookup_int_default(file, game.occupychance,
"game.occupychance");
+ game.autoattack = secfile_lookup_bool_default(file,
+ GAME_DEFAULT_AUTOATTACK,
+ "game.autoattack");
game.seed = secfile_lookup_int_default(file, game.seed,
"game.randseed");
game.allowed_city_names =
@@ -3655,6 +3658,7 @@
secfile_insert_int(file, game.onsetbarbarian, "game.onsetbarbs");
secfile_insert_int(file, game.revolution_length, "game.revolen");
secfile_insert_int(file, game.occupychance, "game.occupychance");
+ secfile_insert_bool(file, game.autoattack, "game.autoattack");
secfile_insert_str(file, game.demography, "game.demography");
secfile_insert_int(file, game.borders, "game.borders");
secfile_insert_bool(file, game.happyborders, "game.happyborders");
Index: server/settings.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/settings.c,v
retrieving revision 1.9
diff -u -r1.9 settings.c
--- server/settings.c 15 Oct 2004 09:39:06 -0000 1.9
+++ server/settings.c 19 Oct 2004 20:27:03 -0000
@@ -645,6 +645,13 @@
GAME_MIN_OCCUPYCHANCE, GAME_MAX_OCCUPYCHANCE,
GAME_DEFAULT_OCCUPYCHANCE)
+ GEN_BOOL("autoattack", game.autoattack, SSET_RULES_FLEXIBLE, SSET_MILITARY,
+ SSET_SITUATIONAL, SSET_TO_CLIENT,
+ N_("Turn on/off server-side autoattack"),
+ N_("If set to on, units with move left will automatically "
+ "consider attacking enemy units that move adjacent to them."),
+ NULL, GAME_DEFAULT_AUTOATTACK)
+
GEN_INT("killcitizen", game.killcitizen,
SSET_RULES, SSET_MILITARY, SSET_RARE, SSET_TO_CLIENT,
N_("Reduce city population after attack"),
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.204
diff -u -r1.204 srv_main.c
--- server/srv_main.c 18 Oct 2004 23:49:27 -0000 1.204
+++ server/srv_main.c 19 Oct 2004 20:27:03 -0000
@@ -68,7 +68,6 @@
#include "timing.h"
#include "version.h"
-#include "autoattack.h"
#include "barbarian.h"
#include "cityhand.h"
#include "citytools.h"
@@ -602,9 +601,6 @@
do_reveal_effects();
do_have_embassies_effect();
-
- freelog(LOG_DEBUG, "Auto-Attack phase");
- auto_attack();
}
/**************************************************************************
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.308
diff -u -r1.308 unittools.c
--- server/unittools.c 18 Oct 2004 22:40:02 -0000 1.308
+++ server/unittools.c 19 Oct 2004 20:27:04 -0000
@@ -55,6 +55,8 @@
#include "unittools.h"
+/* We need this global variable for our sort algorithm */
+static struct tile *autoattack_target;
static void unit_restore_hitpoints(struct player *pplayer, struct unit *punit);
static void unit_restore_movepoints(struct player *pplayer, struct unit
*punit);
@@ -2430,7 +2432,129 @@
}
/*****************************************************************
-Will wake up any neighboring enemy sentry units or patrolling units
+ This function is passed to unit_list_sort() to sort a list of
+ units according to their win chance against autoattack_x|y.
+ If the unit is being transported, then push it to the front of
+ the list, since we wish to leave its transport out of combat
+ if at all possible.
+*****************************************************************/
+static int compare_units(const void *p, const void *q)
+{
+ struct unit * const *p1 = p;
+ struct unit * const *q1 = q;
+ struct unit *p1def = get_defender(*p1, autoattack_target);
+ struct unit *q1def = get_defender(*q1, autoattack_target);
+ int p1uwc = unit_win_chance(*p1, p1def);
+ int q1uwc = unit_win_chance(*q1, q1def);
+
+ if (p1uwc < q1uwc || (*q1)->transported_by > 0) {
+ return -1; /* q is better */
+ } else if (p1uwc == q1uwc) {
+ return 0;
+ } else {
+ return 1; /* p is better */
+ }
+}
+
+/*****************************************************************
+ Check if unit survives enemy autoattacks. We assume that any
+ unit that is adjacent to us can see us.
+*****************************************************************/
+static bool unit_survive_autoattack(struct unit *punit)
+{
+ struct unit_list autoattack;
+ int moves = punit->moves_left;
+ int sanity1 = punit->id;
+
+ /* Kludge to prevent attack power from dropping to zero during calc */
+ punit->moves_left = MAX(punit->moves_left, 1);
+
+ unit_list_init(&autoattack);
+ adjc_iterate(punit->tile, ptile) {
+ /* First add all eligible units to a unit list */
+ unit_list_iterate(ptile->units, penemy) {
+ struct player *enemyplayer = unit_owner(penemy);
+ enum diplstate_type ds =
+ pplayer_get_diplstate(unit_owner(punit), enemyplayer)->type;
+
+ if ((enemyplayer->ai.control || game.autoattack)
+ && ai_handicap(enemyplayer, H_EXPERIMENTAL)
+ && penemy->moves_left > 0
+ && ds == DS_WAR
+ && can_unit_attack_unit_at_tile(penemy, punit, punit->tile)) {
+ unit_list_insert(&autoattack, penemy);
+ }
+ } unit_list_iterate_end;
+ } adjc_iterate_end;
+
+ /* The unit list is now sorted according to win chance against punit */
+ autoattack_target = punit->tile; /* global variable */
+ if (unit_list_size(&autoattack) >= 2) {
+ unit_list_sort(&autoattack, &compare_units);
+ }
+
+ unit_list_iterate_safe(autoattack, penemy) {
+ int sanity2 = penemy->id;
+ struct unit *enemy_defender = get_defender(punit, penemy->tile);
+ struct unit *punit_defender = get_defender(penemy, punit->tile);
+ double punitwin = unit_win_chance(punit, enemy_defender);
+ double penemywin = unit_win_chance(penemy, punit_defender);
+ double threshold = 0.25;
+ struct tile *ptile = penemy->tile;
+
+ if (ptile->city && unit_list_size(&ptile->units) == 1) {
+ /* Don't leave city defenseless */
+ threshold = 0.90;
+ }
+
+ if ((penemywin > 1.0 - punitwin
+ || unit_flag(punit, F_DIPLOMAT)
+ || get_transporter_capacity(punit) > 0)
+ && penemywin > threshold) {
+#ifdef REALLY_DEBUG_THIS
+ freelog(LOG_NORMAL, "AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
+ unit_type(penemy)->name, unit_type(punit)->name,
+ punit->tile->x, punit->tile->y, penemywin, 1.0 - punitwin,
+ threshold);
+#endif
+
+ handle_unit_activity_request(penemy, ACTIVITY_IDLE);
+ (void) handle_unit_move_request(penemy, punit->tile, FALSE, FALSE);
+ }
+#ifdef REALLY_DEBUG_THIS
+ else {
+ freelog(LOG_NORMAL, "!AA %s -> %s (%d,%d) %.2f > %.2f && > %.2f",
+ unit_type(penemy)->name, unit_type(punit)->name,
+ punit->tile->x, punit->tile->y, penemywin, 1.0 - punitwin,
+ threshold);
+ continue;
+ }
+#endif
+
+ if (find_unit_by_id(sanity2)) {
+ send_unit_info(NULL, penemy);
+ }
+ if (find_unit_by_id(sanity1)) {
+ send_unit_info(NULL, punit);
+ } else {
+ return FALSE; /* done, gone */
+ }
+ } unit_list_iterate_safe_end;
+
+ unit_list_unlink_all(&autoattack);
+ if (find_unit_by_id(sanity1)) {
+ /* We could have lost movement in combat */
+ punit->moves_left = MIN(punit->moves_left, moves);
+ send_unit_info(NULL, punit);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/*****************************************************************
+ Will wake up any neighboring enemy sentry units or patrolling
+ units.
*****************************************************************/
static void wakeup_neighbor_sentries(struct unit *punit)
{
@@ -2764,6 +2888,9 @@
handle_unit_move_consequences(punit, psrctile, pdesttile);
wakeup_neighbor_sentries(punit);
+ if (!unit_survive_autoattack(punit)) {
+ return FALSE;
+ }
maybe_make_contact(pdesttile, unit_owner(punit));
conn_list_do_unbuffer(&pplayer->connections);
|
|