diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/client/options.c codeciv/client/options.c --- freeciv/client/options.c Tue Jan 23 19:12:04 2001 +++ codeciv/client/options.c Wed Jan 24 17:53:47 2001 @@ -136,6 +136,7 @@ N_("Famine Feared in City"), /* E_CITY_FAMINE_FEARED */ N_("Wonder Will Be Finished Next Turn"), /* E_CITY_WONDER_WILL_BE_BUILT */ N_("Learned New Government"), /* E_NEW_GOVERNMENT */ + N_("Citypref worklist events"), /* E_WORKLIST_CITYPREF */ }; /************************************************************************** diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/common/events.h codeciv/common/events.h --- freeciv/common/events.h Tue Jan 23 19:12:18 2001 +++ codeciv/common/events.h Wed Jan 24 17:52:15 2001 @@ -59,6 +59,7 @@ E_CITY_FAMINE_FEARED, E_CITY_WONDER_WILL_BE_BUILT, E_NEW_GOVERNMENT, + E_WORKLIST_CITYPREF, /* Note: If you add a new event, make sure you make a similar change to message_text in client/options.c */ diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/common/worklist.c codeciv/common/worklist.c --- freeciv/common/worklist.c Tue Jan 23 19:12:19 2001 +++ codeciv/common/worklist.c Wed Jan 24 17:51:15 2001 @@ -16,6 +16,7 @@ #include "city.h" #include "mem.h" +#include "player.h" #include "unit.h" #include "worklist.h" @@ -151,4 +152,22 @@ pwl->wlefs[MAX_LEN_WORKLIST-1] = WEF_END; pwl->wlids[MAX_LEN_WORKLIST-1] = 0; +} + +/**************************************************************** +... +****************************************************************/ +struct worklist *get_default_worklist(struct player *pplayer) +{ + int i; + int found = -1; + for (i=0; i<=MAX_NUM_WORKLISTS; i++) { + if (!strcmp(pplayer->worklists[i].name, "default")) + found = i; + } + if (found != -1) { + return &pplayer->worklists[found]; + } else { + return NULL; + } } diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/common/worklist.h codeciv/common/worklist.h --- freeciv/common/worklist.h Tue Jan 23 19:12:19 2001 +++ codeciv/common/worklist.h Wed Jan 24 17:51:15 2001 @@ -48,4 +48,6 @@ void copy_worklist(struct worklist *dst, struct worklist *src); void worklist_remove(struct worklist *pwl, int idx); +struct worklist *get_default_worklist(struct player *pplayer); + #endif /* FC__WORKLIST_H */ diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityhand.c codeciv/server/cityhand.c --- freeciv/server/cityhand.c Tue Jan 23 19:12:27 2001 +++ codeciv/server/cityhand.c Wed Jan 24 17:54:52 2001 @@ -148,6 +148,7 @@ { struct city *pcity, *othercity; int i, x_itr, y_itr; + struct worklist *default_worklist = get_default_worklist(pplayer); freelog(LOG_DEBUG, "Creating city %s", name); gamelog(GAMELOG_FOUNDC,"%s (%i, %i) founded by the %s", name, @@ -179,8 +180,11 @@ pcity->airlift=0; pcity->currently_building=best_role_unit(pcity, L_FIRSTBUILD); - /* Set up the worklist */ + /* Set up the worklist. We change to a build target below */ pcity->worklist = create_worklist(); + if (default_worklist) { + copy_worklist(pcity->worklist, default_worklist); + } for (y_itr = 0; y_itr < CITY_MAP_SIZE; y_itr++) for (x_itr = 0; x_itr < CITY_MAP_SIZE; x_itr++) @@ -255,6 +259,10 @@ send_city_info(0, pcity); maybe_make_first_contact(x, y, pcity->owner); + if (default_worklist) { + worklist_change_build_target(pcity, 0); + } + /* Catch fortress building, transforming into ocean, etc. */ unit_list_iterate(map_get_tile(x, y)->units, punit) { if (punit->activity != ACTIVITY_FORTIFIED @@ -558,12 +566,14 @@ /************************************************************************** Change the build target. + "verbose_trivial" is whether a message is send to the player. Note that + notification about started/stopped wonders is sent regardless of "verbose_trivial" **************************************************************************/ void change_build_target(struct player *pplayer, struct city *pcity, - int target, int is_unit, int event) + int target, int is_unit, int event, + int verbose_trivial) { char *name; - char *source; /* If the city is already building this thing, don't do anything */ if (pcity->is_building_unit == is_unit && @@ -598,23 +608,27 @@ else name = improvement_types[pcity->currently_building].name; - switch (event) { + if (verbose_trivial) { + char *source; + switch (event) { case E_WORKLIST: source = _(" from the worklist"); break; -/* Should we give the AI auto code credit? - case E_IMP_AUTO: source = _(" as suggested by the AI advisor"); break; -*/ + case E_WORKLIST_CITYPREF: source = _(" from the global citypref worklist"); break; + /* Should we give the AI auto code credit? + case E_IMP_AUTO: source = _(" as suggested by the AI advisor"); break; + */ default: source = ""; break; - } + } - /* Tell the player what's up. */ - if (event) - notify_player_ex(pplayer, pcity->x, pcity->y, event, - _("Game: %s is building %s%s."), - pcity->name, name, source); - else - notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_BUILD, - _("Game: %s is building %s."), - pcity->name, name); + /* Tell the player what's up. */ + if (event) + notify_player_ex(pplayer, pcity->x, pcity->y, event, + _("Game: %s is building %s%s."), + pcity->name, name, source); + else + notify_player_ex(pplayer, pcity->x, pcity->y, E_UNIT_BUILD, + _("Game: %s is building %s."), + pcity->name, name); + } /* If the city is building a wonder, tell the rest of the world about it. */ @@ -652,7 +666,7 @@ } change_build_target(pplayer, pcity, preq->build_id, - preq->is_build_id_unit_id, E_NOEVENT); + preq->is_build_id_unit_id, E_NOEVENT, 1); city_refresh(pcity); send_city_info(pplayer, pcity); diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityhand.h codeciv/server/cityhand.h --- freeciv/server/cityhand.h Tue Jan 23 19:12:27 2001 +++ codeciv/server/cityhand.h Wed Jan 24 17:51:15 2001 @@ -45,7 +45,7 @@ void really_handle_city_buy(struct player *pplayer, struct city *pcity); void handle_city_refresh(struct player *pplayer, struct packet_generic_integer *preq); void change_build_target(struct player *pplayer, struct city *pcity, - int target, int is_unit, int event); + int target, int is_unit, int event, int verbose_trivial); void handle_city_change(struct player *pplayer, struct packet_city_request *preq); void handle_city_worklist(struct player *pplayer, diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.c codeciv/server/cityturn.c --- freeciv/server/cityturn.c Tue Jan 23 19:12:27 2001 +++ codeciv/server/cityturn.c Wed Jan 24 18:24:02 2001 @@ -67,9 +67,6 @@ static void city_increase_size(struct city *pcity); static void city_reduce_size(struct city *pcity); -static int worklist_change_build_target(struct player *pplayer, - struct city *pcity); - static int city_build_stuff(struct player *pplayer, struct city *pcity); static int improvement_upgrades_to(struct city *pcity, int imp); static void upgrade_building_prod(struct city *pcity); @@ -1042,7 +1039,7 @@ want = choice.want; if (id!=-1 && id != B_LAST && want > 0) { - change_build_target(pplayer, pcity, id, 0, E_IMP_AUTO); + change_build_target(pplayer, pcity, id, 0, E_IMP_AUTO, 1); return 1; /* making something. return value = 1 */ } @@ -1056,19 +1053,123 @@ } /************************************************************************** + Implement citypref feature: + + If a global worklist named "citypref" exists, then use that worklist + and change build target. Return 0 if no targets are available, otherwise + return non-zero. Makes no changes to the citypref worklist +**************************************************************************/ +static int citypref_change_build_target (struct city *pcity) +{ + struct player *pplayer = city_owner(pcity); + int success = 0; + int i; + int citypref_idx = -1; + + /* which global worklist is named "citypref"? */ + + freelog(LOG_DEBUG, "citypref: entered citypref_change_build_target"); + + for (i=0; i<=MAX_NUM_WORKLISTS; i++) { + freelog(LOG_DEBUG, "citypref: looking at worklist %s", pplayer->worklists[i].name); + if (!strcmp(pplayer->worklists[i].name,"citypref")) citypref_idx = i; + } + + if (citypref_idx == -1) return 0; + + /* get a valid target from the citypref worklist + use the same algorithm as worklist_change_build_target, + but don't delete locally invalid entries from the global + citypref worklist */ + + i = 0; + while (1) { + int target, is_unit; + + /* What's the next item in the worklist? */ + if (!worklist_peek_ith( &pplayer->worklists[citypref_idx], &target, &is_unit, i)) + /* Nothing more in the worklist. Ah, well. */ + break; + + i++; + + /* Sanity checks. First, target is a unit but the city can't build it */ + if (is_unit && !can_build_unit(pcity, target)) { + int new_target = unit_upgrades_to(pcity, target); + + /* Maybe we can just upgrade the target to what the city /can/ build. */ + if (new_target == target) { + /* No upgrade available. Advise the player and proceed to + next item in the worklist */ + notify_player_ex(pplayer, pcity->x, pcity->y, E_CITY_CANTBUILD, + _("Game: %s cannot build %s from the citypref worklist. "), + pcity->name, get_unit_type(target)->name); + continue; + } else { + /* Yes, we can go after new_target instead. */ + notify_player_ex(pplayer, pcity->x, pcity->y, E_WORKLIST, + _("Game: Production of %s is upgraded to %s in %s."), + get_unit_type(target)->name, get_unit_type(new_target)->name, + pcity->name); + target = new_target; + } + } else if (!is_unit && !can_build_improvement(pcity, target)) { + int new_target = improvement_upgrades_to(pcity, target); + + /* Maybe this improvement has been obsoleted by something that we can build. */ + if (new_target == target) { + /* No. Warn the player and move to next id in worklist */ + + /* Does the city already have that improvement? */ + if (city_got_building(pcity, target)) { + freelog(LOG_DEBUG, "citypref: %s already has %s", pcity->name, + get_impr_name_ex(pcity, target)); + } else { + freelog(LOG_DEBUG, "citypref: %s can't build %s", pcity-> name, + get_impr_name_ex(pcity, target)); + notify_player_ex(pplayer, pcity->x, pcity->y, E_CITY_CANTBUILD, + _("Game: %s can't build %s from the citypref worklist; "), + pcity->name, get_impr_name_ex(pcity, target)); + } + continue; + } else { + /* Hey, we can build the improvement! */ + notify_player_ex(pplayer, pcity->x, pcity->y, E_WORKLIST, + _("Game: Production of %s is upgraded to %s in %s."), + get_impr_name_ex(pcity, target), + get_impr_name_ex(pcity, new_target), + pcity->name); + target = new_target; + } + } + + /* All okay. Switch targets. */ + change_build_target(pplayer, pcity, target, is_unit, E_WORKLIST_CITYPREF, 1); + + success = 1; + break; + } + + freelog(LOG_DEBUG, "Exiting citypref_change_build_target"); + return success; +} + +/************************************************************************** Examine the worklist and change the build target. Return 0 if no targets are available to change to. Otherwise return non-zero. Has the side-effect of removing from the worklist any no-longer-available targets as well as the target actually selected, if any. + "verbose_trivial" is whether the trivial messages "changed build" and + "worklist empty" is sent to the client. **************************************************************************/ -static int worklist_change_build_target(struct player *pplayer, struct city *pcity) +int worklist_change_build_target(struct city *pcity, int verbose_trivial) { + struct player *pplayer = city_owner(pcity); int success = 0; int i; if (worklist_is_empty(pcity->worklist)) - /* Nothing in the worklist; bail now. */ - return 0; + return citypref_change_build_target(pcity); i = 0; while (1) { @@ -1148,6 +1249,8 @@ we can build. */ if (new_target == target) { /* Nope, no use. *sigh* */ + /* FIXME: This can also happen if fx you are trying to build + a bank before you have a markedplace. */ notify_player_ex(pplayer, pcity->x, pcity->y, E_CITY_CANTBUILD, _("Game: %s can't build %s from the worklist; " "tech not yet available. Postponing..."), @@ -1166,7 +1269,8 @@ } /* All okay. Switch targets. */ - change_build_target(pplayer, pcity, target, is_unit, E_WORKLIST); + change_build_target(pplayer, pcity, target, is_unit, + E_WORKLIST, verbose_trivial); success = 1; break; @@ -1178,7 +1282,7 @@ worklist_remove(pcity->worklist, i-1); } - if (worklist_is_empty(pcity->worklist)) { + if (worklist_is_empty(pcity->worklist) && verbose_trivial) { /* There *was* something in the worklist, but it's empty now. Bug the player about it. */ notify_player_ex(pplayer, pcity->x, pcity->y, E_WORKLIST, @@ -1186,6 +1290,8 @@ pcity->name); } + if (!success) success = citypref_change_build_target(pcity); + return success; } @@ -1374,7 +1480,7 @@ * (Fixme? - doesn't check whether spaceship part is still sensible.) * Else co-opt AI routines as "city advisor". */ - if (!worklist_change_build_target(pplayer, pcity) && !space_part) { + if (!worklist_change_build_target(pcity, 1) && !space_part) { /* Fall back to the good old ways. */ freelog(LOG_DEBUG, "Trying advisor_choose_build."); advisor_choose_build(pplayer, pcity); @@ -1430,7 +1536,7 @@ /* If there's something in the worklist, change the build target. If there's nothing there, worklist_change_build_target won't do anything. */ - worklist_change_build_target(pplayer, pcity); + worklist_change_build_target(pcity, 1); gamelog(GAMELOG_UNIT, "%s build %s in %s (%i,%i)", diff -Nur -X/data/freeciv-dev/freeciv/diff_ignore freeciv/server/cityturn.h codeciv/server/cityturn.h --- freeciv/server/cityturn.h Tue Jan 23 19:12:27 2001 +++ codeciv/server/cityturn.h Wed Jan 24 17:51:15 2001 @@ -37,5 +37,6 @@ void city_incite_cost(struct city *pcity); void remove_obsolete_buildings_city(struct city *pcity, int refresh); void remove_obsolete_buildings(struct player *plr); +int worklist_change_build_target(struct city *pcity, int verbose_trivial); #endif /* FC__CITYTURN_H */