? ai/aisettler.c ? ai/aisettler.h ? common/aicore/citymap.c ? common/aicore/citymap.h Index: ai/Makefile.am =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/Makefile.am,v retrieving revision 1.13 diff -u -r1.13 Makefile.am --- ai/Makefile.am 2003/03/11 17:59:26 1.13 +++ ai/Makefile.am 2003/05/07 19:12:43 @@ -35,6 +35,8 @@ aihand.h \ ailog.c \ ailog.h \ + aisettler.c \ + aisettler.h \ aitech.c \ aitech.h \ aitools.c \ Index: ai/aidata.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aidata.c,v retrieving revision 1.14 diff -u -r1.14 aidata.c --- ai/aidata.c 2003/05/06 05:18:49 1.14 +++ ai/aidata.c 2003/05/07 19:12:43 @@ -255,12 +255,31 @@ ai->food_priority = FOOD_WEIGHTING; ai->shield_priority = SHIELD_WEIGHTING; ai->luxury_priority = 1; - ai->science_priority = TRADE_WEIGHTING; + ai->science_priority = TRADE_WEIGHTING + 10; ai->gold_priority = TRADE_WEIGHTING; ai->happy_priority = 1; ai->unhappy_priority = TRADE_WEIGHTING; /* danger */ ai->angry_priority = TRADE_WEIGHTING * 3; /* grave danger */ ai->pollution_priority = POLLUTION_WEIGHTING; + + /* The values below are WAGs that have been optimized to the + * default rules. They are not changed during the game. */ + + /* Perfection gives us an idea of how long to search for optimal + * solutions, instead of going for quick and dirty solutions that + * waste valuable time. Decrease for maps where good city placements + * are hard to find. Lower means more perfection. */ + ai->perfection = 12; + /* How much to emphasise the potential for city growth for city + * placements. Decrease this value if large cities are important + * or planned. Increase if running strict smallpox. */ + ai->growth_potential_emphasis = 8; + /* Percentage bonus to city locations near an ocean. */ + ai->naval_emphasis = 20; + /* Modifier for defense bonus that is applied to city location want. + * Increase this to lower emphasis on defensive positions, increase + * it if you want more emphasis on heavily defended cities. */ + ai->defense_emphasis = 4000; /* Goals */ ai_best_government(pplayer); Index: ai/aidata.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aidata.h,v retrieving revision 1.8 diff -u -r1.8 aidata.h --- ai/aidata.h 2003/05/06 05:18:49 1.8 +++ ai/aidata.h 2003/05/07 19:12:43 @@ -79,6 +79,10 @@ int unhappy_priority; int angry_priority; int pollution_priority; + int perfection; + int growth_potential_emphasis; + int naval_emphasis; + int defense_emphasis; /* Goals */ struct { Index: ai/aitools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/ai/aitools.c,v retrieving revision 1.85 diff -u -r1.85 aitools.c --- ai/aitools.c 2003/05/06 08:13:21 1.85 +++ ai/aitools.c 2003/05/07 19:12:43 @@ -45,6 +45,7 @@ #include "aidata.h" #include "ailog.h" #include "aiunit.h" +#include "citymap.h" #include "aitools.h" @@ -149,6 +150,7 @@ if (punit->ai.ai_role == AIUNIT_BUILD_CITY) { assert(is_normal_map_pos(punit->goto_dest_x, punit->goto_dest_y)); remove_city_from_minimap(punit->goto_dest_x, punit->goto_dest_y); + citymap_free_city_spot(punit->goto_dest_x, punit->goto_dest_y, punit->id); } if (charge && (charge->ai.bodyguard == punit->id)) { @@ -175,9 +177,11 @@ ai_unit_new_role(bodyguard, AIUNIT_NONE, -1, -1); } - if (punit->ai.ai_role == AIUNIT_BUILD_CITY) { + /* Reserve city spot, _unless_ we want to add ourselves to a city. */ + if (punit->ai.ai_role == AIUNIT_BUILD_CITY && !map_get_city(x, y)) { assert(is_normal_map_pos(x, y)); add_city_to_minimap(x, y); + citymap_reserve_city_spot(x, y, punit->id); } } Index: common/aicore/Makefile.am =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/aicore/Makefile.am,v retrieving revision 1.4 diff -u -r1.4 Makefile.am --- common/aicore/Makefile.am 2003/03/11 17:59:26 1.4 +++ common/aicore/Makefile.am 2003/05/07 19:12:44 @@ -10,4 +10,6 @@ pf_tools.c \ pf_tools.h \ cm.c \ - cm.h + cm.h \ + citymap.c \ + citymap.h Index: server/settlers.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/settlers.c,v retrieving revision 1.166 diff -u -r1.166 settlers.c --- server/settlers.c 2003/04/04 15:47:50 1.166 +++ server/settlers.c 2003/05/07 19:12:44 @@ -38,8 +38,10 @@ #include "aicity.h" #include "aidata.h" #include "ailog.h" +#include "aisettler.h" #include "aitools.h" #include "aiunit.h" +#include "citymap.h" #include "settlers.h" @@ -51,7 +53,6 @@ BV_DEFINE(enemy_mask, MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS); static enemy_mask enemies[MAX_NUM_PLAYERS + MAX_NUM_BARBARIANS]; -static void auto_settlers_player(struct player *pplayer); static bool is_already_assigned(struct unit *myunit, struct player *pplayer, int x, int y); static int city_desirability(struct player *pplayer, int x, int y); @@ -66,6 +67,11 @@ struct packet_unit_request req; struct city *pcity; + handle_unit_activity_request(punit, ACTIVITY_IDLE); + + /* Free city reservations */ + ai_unit_new_role(punit, AIUNIT_NONE, -1, -1); + req.unit_id = punit->id; sz_strlcpy(req.name, city_name_suggestion(pplayer, x, y)); handle_unit_build_city(pplayer, &req); @@ -1261,7 +1267,7 @@ } /************************************************************************** - find some work for the settler + Find some work for the settler **************************************************************************/ static void auto_settler_findwork(struct player *pplayer, struct unit *punit) { @@ -1306,15 +1312,14 @@ return; } - /* If we intent on building a city then reserve the square. */ - if (unit_flag(punit, F_CITIES) && - best_act == ACTIVITY_UNKNOWN /* flag */) { + /* If we intend to build a city then reserve the square. */ + if (unit_flag(punit, F_CITIES) + && best_act == ACTIVITY_UNKNOWN /* flag */) { ai_unit_new_role(punit, AIUNIT_BUILD_CITY, gx, gy); } else { ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, gx, gy); } - /* We've now worked out what to do; go to it! */ if (!ai_gothere(punit, gx, gy, ferryboat)) { /* died */ return; @@ -1325,7 +1330,6 @@ && same_pos(gx, gy, punit->x, punit->y)) { if (best_act == ACTIVITY_UNKNOWN) { remove_city_from_minimap(gx, gy); /* yeah, I know. -- Syela */ - handle_unit_activity_request(punit, ACTIVITY_IDLE); (void) ai_do_build_city(pplayer, punit); return; } @@ -1336,6 +1340,104 @@ } /************************************************************************** + New implementation of server/settlers.c function with same name +**************************************************************************/ +#define LOG_SETTLER LOG_DEBUG +static void auto_settler_findwork2(struct player *pplayer, struct unit *punit) +{ + struct cityresult result; + int best_impr = 0; /* best terrain improvement we can do */ + enum unit_activity best_act = ACTIVITY_IDLE; /* compat. kludge */ + int gx = -1, gy = -1; + + result.total = 0; + + assert(pplayer && punit); + assert(unit_flag(punit, F_CITIES) || unit_flag(punit, F_SETTLERS)); + + /*** If we are on a city mission: Go where we should ***/ + + if (punit->ai.ai_role == AIUNIT_BUILD_CITY) { + /* Go there */ + if (do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) { + return; + } + if (punit->moves_left <= 0) { + return; + } + if (same_pos(punit->x, punit->y, punit->goto_dest_x, punit->goto_dest_y)) { + if (!ai_do_build_city(pplayer, punit)) { + UNIT_LOG(LOG_ERROR, punit, "could not make city on %s", + map_get_tile_info_text(punit->x, punit->y)); + ai_unit_new_role(punit, AIUNIT_NONE, -1, -1); + } else { + return; + } + } else { + UNIT_LOG(LOG_VERBOSE, punit, "could not go to target"); + ai_unit_new_role(punit, AIUNIT_NONE, -1, -1); + return; + } + } + + /*** Try find some work ***/ + + if (unit_flag(punit, F_SETTLERS)) { + best_impr = evaluate_improvements(punit, &best_act, &gx, &gy); + } + + if (unit_flag(punit, F_CITIES)) { + find_best_city_placement(punit, &result); + UNIT_LOG(LOG_SETTLER, punit, "city want %d (impr want %d)", result.total, + best_impr); + if (result.total > best_impr) { + if (map_get_city(result.x, result.y)) { + UNIT_LOG(LOG_SETTLER, punit, "immigrates to %s (%d, %d)", + map_get_city(result.x, result.y), result.x, result.y); + } else { + UNIT_LOG(LOG_SETTLER, punit, "makes city at (%d, %d)", + result.x, result.y); + } + /* Go make a city! */ + ai_unit_new_role(punit, AIUNIT_BUILD_CITY, result.x, result.y); + punit->goto_dest_x = result.x; /* TMP */ + punit->goto_dest_y = result.y; /* TMP */ + } else { + UNIT_LOG(LOG_SETTLER, punit, "improves terrain"); + /* Terrain improvements follows the old model, and is recalculated + * each turn. */ + ai_unit_new_role(punit, AIUNIT_AUTO_SETTLER, gx, gy); + punit->goto_dest_x = gx; /* TMP */ + punit->goto_dest_y = gy; /* TMP */ + /* Mark the square as taken. */ + if (gx != -1 && gy != -1) { + map_get_tile(gx, gy)->assigned = + map_get_tile(gx, gy)->assigned | 1<player_no; + } else { + UNIT_LOG(LOG_NORMAL, punit, "giving up trying to improve terrain"); + return; /* We cannot do anything */ + } + if (do_unit_goto(punit, GOTO_MOVE_ANY, FALSE) == GR_DIED) { + return; + } + if (punit->moves_left > 0 + && same_pos(gx, gy, punit->x, punit->y)) { + handle_unit_activity_request(punit, best_act); + send_unit_info(NULL, punit); + return; + } + } + } + + /*** Recurse if we want to found a city ***/ + + if (punit->ai.ai_role == AIUNIT_BUILD_CITY) { + auto_settler_findwork2(pplayer, punit); + } +} +#undef LOG_SETTLER + +/************************************************************************** Do all tile improvement calculations and cache them for later. **************************************************************************/ void initialize_infrastructure_cache(struct city *pcity) @@ -1370,15 +1472,20 @@ } /************************************************************************** - run through all the players settlers and let those on ai.control work - automagically + Run through all the players settlers and let those on ai.control work + automagically. **************************************************************************/ -static void auto_settlers_player(struct player *pplayer) +void auto_settlers_player(struct player *pplayer) { static struct timer *t = NULL; /* alloc once, never free */ t = renew_timer_start(t, TIMER_CPU, TIMER_DEBUG); + if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) { + /* Set up our city map. */ + citymap_turn_init(pplayer); + } + city_list_iterate(pplayer->cities, pcity) initialize_infrastructure_cache(pcity); /* saves oodles of time -- Syela */ city_list_iterate_end; @@ -1400,9 +1507,12 @@ handle_unit_activity_request(punit, ACTIVITY_IDLE); } if (punit->activity == ACTIVITY_IDLE) { - auto_settler_findwork(pplayer, punit); + if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) { + auto_settler_findwork2(pplayer, punit); + } else { + auto_settler_findwork(pplayer, punit); + } } - freelog(LOG_DEBUG, "Has been processed."); } } unit_list_iterate_end; @@ -1523,7 +1633,6 @@ */ } - /************************************************************************** Recalculate enemies[] table **************************************************************************/ @@ -1539,22 +1648,18 @@ } /************************************************************************** - Do the auto_settler stuff for all the players. + Initialize autosettler code. **************************************************************************/ -void auto_settlers(void) +void auto_settlers_init(void) { - int i; assign_settlers(); assign_territory(); recount_enemy_masks(); - for (i = 0; i < game.nplayers; i++) { - auto_settlers_player(shuffled_player(i)); - } } /************************************************************************** -used to use old crappy formulas for settler want, but now using actual -want! + Return want for city settler. Note that we rely here on the fact that + ai_settler_init() has been run while doing autosettlers. **************************************************************************/ void contemplate_new_city(struct city *pcity) { @@ -1579,7 +1684,15 @@ } virtualunit.moves_left = unit_type(&virtualunit)->move_rate; virtualunit.hp = unit_type(&virtualunit)->hp; - want = evaluate_city_building(&virtualunit, &gx, &gy, &ferryboat); + if (pplayer->ai.control && ai_handicap(pplayer, H_EXPERIMENTAL)) { + struct cityresult result; + + find_best_city_placement(&virtualunit, &result); + pcity->ai.founder_want = result.total; + return; + } else { + want = evaluate_city_building(&virtualunit, &gx, &gy, &ferryboat); + } unit_list_iterate(pplayer->units, qpass) { /* We want a ferryboat with want 199 */ if (qpass->ai.ferryboat == pcity->id) Index: server/settlers.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/settlers.h,v retrieving revision 1.22 diff -u -r1.22 settlers.h --- server/settlers.h 2002/12/18 17:36:20 1.22 +++ server/settlers.h 2003/05/07 19:12:44 @@ -19,7 +19,8 @@ struct unit; struct city; -void auto_settlers(void); +void auto_settlers_init(void); +void auto_settlers_player(struct player *pplayer); int find_boat(struct player *pplayer, int *x, int *y, int cap); #define MORT 24 Index: server/srv_main.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v retrieving revision 1.126 diff -u -r1.126 srv_main.c --- server/srv_main.c 2003/05/05 12:11:13 1.126 +++ server/srv_main.c 2003/05/07 19:12:44 @@ -94,6 +94,8 @@ #include "advmilitary.h" #include "aidata.h" #include "aihand.h" +#include "aisettler.h" +#include "citymap.h" #include "srv_main.h" @@ -428,6 +430,7 @@ for (i = 0; i < game.nplayers; i++) { struct player *pplayer = shuffled_player(i); + if (pplayer->ai.control) { ai_do_first_activities(pplayer); flush_packets(); /* AIs can be such spammers... */ @@ -482,8 +485,13 @@ nocity_send = TRUE; /* AI end of turn activities */ + auto_settlers_init(); players_iterate(pplayer) { if (pplayer->ai.control) { + ai_settler_init(pplayer); + } + auto_settlers_player(pplayer); + if (pplayer->ai.control) { ai_do_last_activities(pplayer); } } players_iterate_end; @@ -1478,10 +1486,6 @@ freelog(LOG_DEBUG, "Season of native unrests"); summon_barbarians(); /* wild guess really, no idea where to put it, but I want to give them chance to move their units */ - freelog(LOG_DEBUG, "Autosettlers"); - auto_settlers(); /* moved this after ai_start_turn for efficiency -- Syela */ - /* moved after sniff_packets for even more efficiency. - What a guy I am. -- Syela */ /* and now, we must manage our remaining units BEFORE the cities that are empty get to refresh and defend themselves. How totally stupid. */ ai_start_turn(); /* Misleading name for manage_units -- Syela */