Index: ai/advmilitary.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/advmilitary.c,v retrieving revision 1.113 diff -u -r1.113 advmilitary.c --- ai/advmilitary.c 2002/09/04 09:56:25 1.113 +++ ai/advmilitary.c 2002/09/04 19:41:10 @@ -206,7 +206,11 @@ int danger; bool sailing; - if (unit_flag(punit, F_NO_LAND_ATTACK)) return 0; + if (unit_flag(punit, F_NO_LAND_ATTACK) + && city_got_building(pcity, B_COASTAL)) { + /* FIXME: Also no danger if city has no ships */ + return 0; + } sailing = is_sailing_unit(punit); if (sailing && !is_terrain_near_tile(pcity->x, pcity->y, T_OCEAN)) return 0; @@ -954,6 +958,10 @@ acity = map_get_city(x, y); if (!acity) { aunit = get_defender(myunit, x, y); + if (!aunit) { + freelog(LOG_ERROR, "ksw called with no target"); + return; + } } else { aunit = NULL; } Index: ai/aiunit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aiunit.c,v retrieving revision 1.213 diff -u -r1.213 aiunit.c --- ai/aiunit.c 2002/09/03 22:00:07 1.213 +++ ai/aiunit.c 2002/09/04 19:41:11 @@ -1018,7 +1018,7 @@ } } - } else { + } else if (!is_enemy_unit_tile(map_get_tile(x1, y1), pplayer)) { struct city *pcity = map_get_city(x1, y1); /* No defender... */ @@ -2773,7 +2773,6 @@ unit_type_iterate(id) { if (unit_type_exists(id) && !unit_type_flag(id, F_NONMIL) && !unit_type_flag(id, F_MISSILE) - && !unit_type_flag(id, F_NO_LAND_ATTACK) && get_unit_type(id)->move_type != AIR_MOVING && get_unit_type(id)->transport_capacity < 8) { simple_ai_types[i] = id; Index: client/agents/agents.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/agents/agents.c,v retrieving revision 1.16 diff -u -r1.16 agents.c --- client/agents/agents.c 2002/08/24 14:37:36 1.16 +++ client/agents/agents.c 2002/09/04 19:41:11 @@ -473,6 +473,9 @@ { int i; + if (!punit) { + return; + } freelog(LOG_DEBUG, "A: agents_remove_unit(unit=%d) type=%s pos=(%d,%d) owner=%s", punit->id, unit_types[punit->type].name, punit->x, punit->y, Index: common/combat.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/combat.c,v retrieving revision 1.25 diff -u -r1.25 combat.c --- common/combat.c 2002/04/16 03:15:27 1.25 +++ common/combat.c 2002/09/04 19:41:12 @@ -14,7 +14,6 @@ #include #include -#include "log.h" #include "map.h" #include "unit.h" @@ -444,7 +443,9 @@ } /************************************************************************** -Finds the best defender on the square, given an attacker. +Returns the best defender on the square, given an attacker, or NULL if +there is no valid defender against the attacker. A NULL result does not +mean the tile is ready for the taking. This is simply done by calling win_chance with all the possible defenders in turn. @@ -456,6 +457,10 @@ making it able to fx choose a 1a/9d unit over a 10a/10d unit. It should also be able to spare units without full hp's to some extend, as these could be more valuable later. + +A seaborne unit must attempt to defend against attacks from a +NO_LAND_ATTACK unit. An airborne unit must attempt to defend against +attacks from a FIGHTER unit. **************************************************************************/ struct unit *get_defender(struct unit *attacker, int x, int y) { @@ -463,9 +468,22 @@ int bestvalue = -1, count = 0, best_cost = 0, rating_of_best = 0; struct player *att_owner = unit_owner(attacker); + if(!is_military_unit(attacker)) { + /* has no valid targets */ + return FALSE; + } + unit_list_iterate(map_get_tile(x, y)->units, defender) { - if (pplayers_allied(att_owner, unit_owner(defender))) - continue; + if (pplayers_allied(att_owner, unit_owner(defender))) { + continue; /* don't target allies */ + } + if (unit_flag(attacker, F_NO_LAND_ATTACK) + && !is_sailing_unit(defender)) { + continue; /* F_NO_LAND_ATTACK can only attack sailing units */ + } + if (is_air_unit(defender) && !unit_flag(attacker, F_FIGHTER)) { + continue; /* omit air units unless F_FIGHTER attacker */ + } count++; if (unit_can_defend_here(defender)) { bool change = FALSE; @@ -484,7 +502,9 @@ } else if (build_cost == best_cost) { if (rating_of_best < defense_rating) { change = TRUE; - } + } else if (is_air_unit(attacker) && is_air_unit(defender)) { + change = TRUE; /* air-to-air if possible */ + } } } @@ -496,14 +516,6 @@ } } } unit_list_iterate_end; - - if (count > 0 && !bestdef) { - struct unit *debug_unit = unit_list_get(&map_get_tile(x, y)->units, 0); - freelog(LOG_ERROR, "Get_def bugged at (%d,%d). The most likely course" - " is a unit on an ocean square without a transport. The owner" - " of the unit is %s", x, y, unit_owner(debug_unit)->name); - } - return bestdef; } Index: common/player.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/player.h,v retrieving revision 1.81 diff -u -r1.81 player.h --- common/player.h 2002/08/25 11:36:52 1.81 +++ common/player.h 2002/09/04 19:41:12 @@ -47,7 +47,7 @@ H_CITYUNITS=16, /* doesn't know what units are in enemy cities */ H_DEFENSIVE=32, /* builds lots of defensive buildings without calculating need */ H_EXPERIMENTAL=64, /* enable experimental AI features (for testing) */ - H_SUB=128, /* doesn't know where subs may be lurking */ + H_SUB=128, /* doesn't know where partially invisible units may be lurking */ /* below this point are milder handicaps that I can actually implement -- Syela */ H_RATES=256, /* can't set its rates beyond government limits */ H_TARGETS=512, /* can't target anything it doesn't know exists */ Index: common/unittype.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unittype.h,v retrieving revision 1.15 diff -u -r1.15 unittype.h --- common/unittype.h 2002/08/07 11:21:49 1.15 +++ common/unittype.h 2002/09/04 19:41:12 @@ -105,7 +105,7 @@ F_CITIES, /* Can build cities */ F_IGTIRED, /* Ignore tired negative bonus when attacking */ F_MISSILE_CARRIER, /* Like F_CARRIER, but missiles only (Submarine) */ - F_NO_LAND_ATTACK, /* Cannot attack vs land squares (Submarine) */ + F_NO_LAND_ATTACK, /* Cannot attack ground units (eg Submarine) */ F_ADD_TO_CITY, /* unit can add to city population */ F_FANATIC, /* Only Fundamentalist government can build these units */ Index: data/default/units.ruleset =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/default/units.ruleset,v retrieving revision 1.38 diff -u -r1.38 units.ruleset --- data/default/units.ruleset 2002/07/23 19:01:17 1.38 +++ data/default/units.ruleset 2002/09/04 19:41:12 @@ -1368,13 +1368,13 @@ sound_move_alt = "m_generic" sound_fight = "f_submarine" sound_fight_alt = "f_generic" -build_cost = 60 +build_cost = 50 pop_cost = 0 attack = 10 -defense = 2 +defense = 1 hitpoints = 30 -firepower = 2 -move_rate = 3 +firepower = 3 +move_rate = 4 vision_range = 2 transport_cap = 8 fuel = 0 Index: server/stdinhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v retrieving revision 1.246 diff -u -r1.246 stdinhand.c --- server/stdinhand.c 2002/09/01 20:27:06 1.246 +++ server/stdinhand.c 2002/09/04 19:41:13 @@ -1612,9 +1612,9 @@ int h[11] = { -1, H_NONE, H_NONE, - H_RATES | H_TARGETS | H_HUTS | H_DEFENSIVE, + H_RATES | H_TARGETS | H_HUTS | H_DEFENSIVE | H_SUB, H_NONE, - H_RATES | H_TARGETS | H_HUTS, + H_RATES | H_TARGETS | H_HUTS | H_SUB, H_NONE, H_NONE, H_NONE, Index: server/unithand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v retrieving revision 1.232 diff -u -r1.232 unithand.c --- server/unithand.c 2002/08/14 00:01:58 1.232 +++ server/unithand.c 2002/09/04 19:41:13 @@ -943,14 +943,19 @@ } /*** Try to attack if there is an enemy unit on the target tile ***/ - if (pdefender - && pplayers_at_war(unit_owner(punit), unit_owner(pdefender))) { + if (pdefender) { if (!can_unit_attack_tile(punit, dest_x , dest_y)) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, - _("Game: You can't attack there.")); + _("Game: You cannot attack there.")); return FALSE; } - + if (!pplayers_at_war(unit_owner(punit), unit_owner(pdefender))) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: You are not at war with that player.")); + how_to_declare_war(pplayer); + return FALSE; + } + if (punit->moves_left<=0) { notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, _("Game: This unit has no moves left.")); @@ -980,6 +985,14 @@ return TRUE; } /* End attack case */ + /* If there are still enemy units in target tile, we have been + unable to target them and therefore cannot proceed */ + if (is_enemy_unit_tile(pdesttile, unit_owner(punit))) { + notify_player_ex(pplayer, punit->x, punit->y, E_NOEVENT, + _("Game: You cannot attack there.")); + return FALSE; + } + /* There are no players we are at war with at desttile. But if there is a unit we have a treaty!=alliance with we can't move there */ pdefender = is_non_allied_unit_tile(pdesttile, unit_owner(punit)); Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.181 diff -u -r1.181 unittools.c --- server/unittools.c 2002/08/31 02:24:34 1.181 +++ server/unittools.c 2002/09/04 19:41:14 @@ -121,7 +121,11 @@ fromtile = map_get_terrain(punit->x, punit->y); totile = map_get_terrain(dest_x, dest_y); - + + if (pdefender == NULL) { + return FALSE; + } + if(!is_military_unit(punit)) return FALSE; @@ -130,6 +134,7 @@ !(map_get_city(dest_x, dest_y) || map_has_special(dest_x, dest_y, S_AIRBASE))) { return FALSE; } + /* can't attack with ground unit from ocean, except for marines */ if(fromtile==T_OCEAN && is_ground_unit(punit) && !unit_flag(punit, F_MARINES)) { return FALSE; @@ -139,10 +144,16 @@ return FALSE; } - if (unit_flag(punit, F_NO_LAND_ATTACK) && totile!=T_OCEAN) { - return FALSE; + if (unit_flag(punit, F_NO_LAND_ATTACK)) { + if (map_get_city(dest_x, dest_y) + && city_got_building(map_get_city(dest_x, dest_y), B_COASTAL)) { + return FALSE; + } + if (!is_sailing_unit(pdefender)) { + return FALSE; + } } - + if (!pplayers_at_war(unit_owner(punit), unit_owner(pdefender))) return FALSE; @@ -159,7 +170,7 @@ bool can_unit_attack_tile(struct unit *punit, int dest_x, int dest_y) { struct unit *pdefender; - pdefender=get_defender(punit, dest_x, dest_y); + pdefender = get_defender(punit, dest_x, dest_y); if (!pdefender) { struct city *pcity = map_get_city(dest_x, dest_y); if (pcity && pplayers_at_war(city_owner(pcity), unit_owner(punit))) { @@ -1917,7 +1928,9 @@ wipe_unit(punit); } else { /* unitcount > 1 */ - int i; + int i, x = punit->x, y = punit->y; + struct unit *vunit; + if (!(unitcount > 1)) { freelog(LOG_FATAL, "Error in kill_unit, unitcount is %i", unitcount); abort(); @@ -1928,10 +1941,16 @@ } /* count killed units */ - unit_list_iterate((map_get_tile(punit->x ,punit->y)->units), vunit) - if (pplayers_at_war(unit_owner(pkiller), unit_owner(vunit))) - num_killed[vunit->owner]++; - unit_list_iterate_end; + vunit = punit; /* first remove dead unit */ + do { + /* All eligible defenders get killed */ + num_killed[vunit->owner]++; + gamelog(GAMELOG_UNITL, _("%s lose %s to the %s"), + get_nation_name_plural(unit_owner(vunit)->nation), + unit_type(vunit)->name, + get_nation_name_plural(destroyer->nation)); + wipe_unit(vunit); + } while ((vunit = get_defender(pkiller, x, y))); /* inform the owners */ for (i = 0; ix, punit->y)->units, punit2) { - if (pplayers_at_war(unit_owner(pkiller), unit_owner(punit2))) { - notify_player_ex(unit_owner(punit2), - punit2->x, punit2->y, E_UNIT_LOST, - _("Game: %s lost to an attack" - " from %s's %s."), - unit_type(punit2)->name, destroyer->name, - unit_name(pkiller->type)); - gamelog(GAMELOG_UNITL, _("%s lose %s to the %s"), - get_nation_name_plural(unit_owner(punit2)->nation), - unit_type(punit2)->name, - get_nation_name_plural(destroyer->nation)); - wipe_unit_spec_safe(punit2, NULL, FALSE); - } - } - unit_list_iterate_end; } } @@ -2944,9 +2945,9 @@ } } /* A transporter should not take units with it when on an attack goto -- fisch */ - if ((punit->activity == ACTIVITY_GOTO) && - get_defender(punit, punit->goto_dest_x, punit->goto_dest_y) && - psrctile->terrain != T_OCEAN) { + if (punit->activity == ACTIVITY_GOTO + && get_defender(punit, punit->goto_dest_x, punit->goto_dest_y) + && psrctile->terrain != T_OCEAN) { transport_units = FALSE; }