From 030fa0a99b9a412bafc7f55bb018ff835b9536a5 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sat, 23 Sep 2023 23:04:30 +0300 Subject: [PATCH 33/33] Add "priority" property for goods Requested by bard See osdn #48253 Signed-off-by: Marko Lindqvist --- ai/default/daiunit.c | 8 ++-- client/gui-qt/menu.cpp | 2 +- client/gui-sdl2/menu.c | 3 +- client/text.c | 4 +- common/actres.c | 10 +++-- common/aicore/caravan.c | 54 ++++++++++++++----------- common/traderoutes.c | 65 +++++++++++++++++++++--------- common/traderoutes.h | 17 ++++++-- data/alien/game.ruleset | 7 +++- data/civ1/game.ruleset | 7 +++- data/civ2/game.ruleset | 7 +++- data/civ2civ3/game.ruleset | 3 ++ data/classic/game.ruleset | 6 ++- data/goldkeep/game.ruleset | 5 ++- data/granularity/game.ruleset | 5 ++- data/multiplayer/game.ruleset | 6 ++- data/ruledit/comments-3.3.txt | 2 + data/sandbox/game.ruleset | 70 +++++++++++++++++++-------------- data/stub/game.ruleset | 5 ++- data/webperimental/game.ruleset | 5 ++- server/citytools.c | 2 +- server/ruleset.c | 2 + server/unithand.c | 13 +++--- tools/ruleutil/rulesave.c | 1 + 24 files changed, 203 insertions(+), 106 deletions(-) diff --git a/ai/default/daiunit.c b/ai/default/daiunit.c index fd4d21bbf0..178b3b3556 100644 --- a/ai/default/daiunit.c +++ b/ai/default/daiunit.c @@ -2295,15 +2295,17 @@ static void dai_manage_caravan(struct ai_type *ait, struct player *pplayer, if ((unit_data->task == AIUNIT_TRADE || unit_data->task == AIUNIT_WONDER)) { - /* we are moving to our destination */ - /* we check to see if our current goal is feasible */ + /* We are moving to our destination */ + /* We check to see if our current goal is feasible */ struct city *city_dest = tile_city(punit->goto_tile); + struct goods_type *pgood = unit_current_goods(punit, homecity); if ((city_dest == NULL) || !pplayers_allied(unit_owner(punit), city_dest->owner) || (unit_data->task == AIUNIT_TRADE && !(can_cities_trade(homecity, city_dest) - && can_establish_trade_route(homecity, city_dest))) + && can_establish_trade_route(homecity, city_dest, + pgood->priority))) || (unit_data->task == AIUNIT_WONDER /* Helping the (new) production is illegal. */ && !city_production_gets_caravan_shields(&city_dest->production)) diff --git a/client/gui-qt/menu.cpp b/client/gui-qt/menu.cpp index 01914ecef9..a6cad0590f 100644 --- a/client/gui-qt/menu.cpp +++ b/client/gui-qt/menu.cpp @@ -217,7 +217,7 @@ void trade_generator::calculate_inner(trade_city *tc) foreach (ttc, cities) { if (!have_cities_trade_route(tc->city, ttc->city) - && can_establish_trade_route(tc->city, ttc->city)) { + && can_establish_trade_route(tc->city, ttc->city, GOODS_HIGH_PRIORITY)) { tc->poss_trade_num++; tc->pos_cities.append(ttc->city); } diff --git a/client/gui-sdl2/menu.c b/client/gui-sdl2/menu.c index 74c0c4af6b..2c0cffbd40 100644 --- a/client/gui-sdl2/menu.c +++ b/client/gui-sdl2/menu.c @@ -1138,8 +1138,9 @@ void real_menus_update(void) unit_type_get(punit), punit->carrying, TRUE); + struct goods_type *pgood = unit_current_goods(punit, homecity); - if (can_establish_trade_route(homecity, pcity)) { + if (can_establish_trade_route(homecity, pcity, pgood->priority)) { fc_snprintf(cbuf, sizeof(cbuf), _("%s With %s ( %d one time bonus + %d trade ) (R)"), action_id_name_translation(ACTION_TRADE_ROUTE), diff --git a/client/text.c b/client/text.c index 5a55adfeb5..7a50a2b36a 100644 --- a/client/text.c +++ b/client/text.c @@ -332,7 +332,9 @@ const char *popup_info_text(struct tile *ptile) if (utype_can_do_action(unit_type_get(pfocus_unit), ACTION_TRADE_ROUTE) && can_cities_trade(hcity, pcity) - && can_establish_trade_route(hcity, pcity)) { + && can_establish_trade_route(hcity, pcity, + unit_current_goods(pfocus_unit, + hcity)->priority)) { /* TRANS: "Trade from Warsaw: 5" */ astr_add_line(&str, _("Trade from %s: %d"), city_name_get(hcity), diff --git a/common/actres.c b/common/actres.c index 246f1f83de..48402aa5fa 100644 --- a/common/actres.c +++ b/common/actres.c @@ -356,9 +356,13 @@ enum fc_tristate actres_possible(enum action_result result, /* There are more restrictions on establishing a trade route than on * entering the market place. */ - if (result == ACTRES_TRADE_ROUTE - && !can_establish_trade_route(homecity, target->city)) { - return TRI_NO; + if (result == ACTRES_TRADE_ROUTE) { + struct goods_type *pgood = unit_current_goods(actor->unit, homecity); + + if (!can_establish_trade_route(homecity, target->city, + pgood->priority)) { + return TRI_NO; + } } } diff --git a/common/aicore/caravan.c b/common/aicore/caravan.c index f19c10b44e..3702070aef 100644 --- a/common/aicore/caravan.c +++ b/common/aicore/caravan.c @@ -254,13 +254,15 @@ static void caravan_search_from(const struct unit *caravan, static double windfall_benefit(const struct unit *caravan, const struct city *src, const struct city *dest, + const struct goods_type *pgood, const struct caravan_parameter *param) { if (!param->consider_windfall || !can_cities_trade(src, dest)) { return 0; } else { bool can_establish = (unit_can_do_action(caravan, ACTION_TRADE_ROUTE) - && can_establish_trade_route(src, dest)); + && can_establish_trade_route(src, dest, + pgood->priority)); int bonus = get_caravan_enter_city_trade_bonus(src, dest, unit_type_get(caravan), NULL, can_establish); @@ -285,30 +287,31 @@ static double windfall_benefit(const struct unit *caravan, ****************************************************************************/ static int one_city_trade_benefit(const struct city *pcity, const struct player *pplayer, + const struct goods_type *pgood, bool countloser, int newtrade) { int losttrade = 0; - /* if the city is owned by someone else, we don't benefit from the + /* If the city is owned by someone else, we don't benefit from the new trade (but we might still lose from a broken trade route) */ if (city_owner(pcity) != pplayer) { newtrade = 0; } if (city_num_trade_routes(pcity) < max_trade_routes(pcity)) { - /* if the city can handle this route, we don't break any old routes */ + /* If the city can handle this route, we don't break any old routes */ losttrade = 0; } else { struct trade_route_list *would_remove = (countloser ? trade_route_list_new() : NULL); - int oldtrade = city_trade_removable(pcity, would_remove); + int oldtrade = city_trade_removable(pcity, pgood->priority, would_remove); - /* if we own the city, the trade benefit is only by how much + /* If we own the city, the trade benefit is only by how much better we are than the old trade route */ if (city_owner(pcity) == pplayer) { newtrade -= oldtrade; } - /* if the cities that lost a trade route is one of ours, and if we + /* If the cities that lost a trade route is one of ours, and if we care about accounting for the lost trade, count it. */ if (countloser) { trade_route_list_iterate(would_remove, plost) { @@ -326,7 +329,7 @@ static int one_city_trade_benefit(const struct city *pcity, } } - /* find the increase or decrease in trade we benefit from */ + /* Find the increase or decrease in trade we benefit from */ return newtrade - losttrade; } @@ -338,15 +341,17 @@ static int one_city_trade_benefit(const struct city *pcity, static double trade_benefit(const struct player *caravan_owner, const struct city *src, const struct city *dest, + const struct goods_type *pgood, const struct caravan_parameter *param) { - /* do we care about trade at all? */ + /* Do we care about trade at all? */ if (!param->consider_trade) { return 0; } - /* first, see if a new route is made. */ - if (!can_cities_trade(src, dest) || !can_establish_trade_route(src, dest)) { + /* First, see if a new route is made. */ + if (!can_cities_trade(src, dest) + || !can_establish_trade_route(src, dest, pgood->priority)) { return 0; } if (max_trade_routes(src) <= 0 || max_trade_routes(dest) <= 0) { @@ -359,8 +364,10 @@ static double trade_benefit(const struct player *caravan_owner, bool countloser = param->account_for_broken_routes; int newtrade = trade_base_between_cities(src, dest); - return one_city_trade_benefit(src, caravan_owner, countloser, newtrade) - + one_city_trade_benefit(dest, caravan_owner, countloser, newtrade); + return one_city_trade_benefit(src, caravan_owner, pgood, + countloser, newtrade) + + one_city_trade_benefit(dest, caravan_owner, pgood, + countloser, newtrade); } else { /* Always fails. */ fc_assert_msg(!param->convert_trade, @@ -461,7 +468,7 @@ static bool does_foreign_trade_param_allow(const struct caravan_parameter *param /************************************************************************//** Compute the discounted reward from the trade route that is indicated - by the src, dest, and arrival_time fields of the result: Fills in + by the src, dest, and arrival_time fields of the result: Fills in the value and help_wonder fields. Assumes the owner of src is the owner of the caravan. ****************************************************************************/ @@ -482,6 +489,7 @@ static bool get_discounted_reward(const struct unit *caravan, bool consider_wonder; bool consider_trade; bool consider_windfall; + struct goods_type *pgood; /* if no foreign trade is allowed, just quit. */ if (!does_foreign_trade_param_allow(parameter, pplayer_src, pplayer_dest)) { @@ -514,7 +522,7 @@ static bool get_discounted_reward(const struct unit *caravan, if (consider_wonder) { wonder = wonder_benefit(caravan, arrival_time, dest, parameter); - /* we want to aid for wonder building */ + /* We want to aid for wonder building */ wonder *= 2; wonder = presentvalue(wonder, arrival_time, discount); @@ -522,8 +530,10 @@ static bool get_discounted_reward(const struct unit *caravan, wonder = -1.0; } + pgood = goods_from_city_to_unit(src, NULL); + if (consider_trade) { - trade = trade_benefit(pplayer_src, src, dest, parameter); + trade = trade_benefit(pplayer_src, src, dest, pgood, parameter); if (parameter->horizon == FC_INFINITY) { trade = perpetuity(trade, discount); } else { @@ -535,7 +545,7 @@ static bool get_discounted_reward(const struct unit *caravan, } if (consider_windfall) { - windfall = windfall_benefit(caravan, src, dest, parameter); + windfall = windfall_benefit(caravan, src, dest, pgood, parameter); windfall = presentvalue(windfall, arrival_time, discount); } else { windfall = 0.0; @@ -573,8 +583,8 @@ static bool get_discounted_reward(const struct unit *caravan, ****************************************************************************/ /************************************************************************//** - Ignoring the transit time, return the value of moving the caravan to - dest. + Ignoring the transit time, return the value of moving the caravan + to dest. ****************************************************************************/ static void caravan_evaluate_notransit(const struct unit *caravan, const struct city *dest, @@ -589,7 +599,7 @@ static void caravan_evaluate_notransit(const struct unit *caravan, /************************************************************************//** Structure and callback for the caravan_search invocation in - caravan_evaluate_withtransit. + caravan_evaluate_withtransit(). ****************************************************************************/ struct cewt_data { const struct unit *caravan; @@ -812,13 +822,13 @@ static bool cowt_callback(void *vdata, const struct city *pcity, caravan_result_init(¤t, game_city_by_number(caravan->homecity), pcity, arrival_time); - /* first, see what benefit we'd get from not changing home city */ + /* First, see what benefit we'd get from not changing home city */ get_discounted_reward(caravan, data->param, ¤t); if (caravan_result_compare(¤t, data->best) > 0) { *data->best = current; } - /* next, try changing home city (if we're allowed to) */ + /* Next, try changing home city (if we're allowed to) */ if (city_owner(pcity) == unit_owner(caravan)) { caravan_find_best_destination_withtransit( caravan, data->param, pcity, arrival_time, moves_left, data->omniscient, @@ -828,7 +838,7 @@ static bool cowt_callback(void *vdata, const struct city *pcity, } } - return FALSE; /* don't stop searching */ + return FALSE; /* Don't stop searching */ } /************************************************************************//** diff --git a/common/traderoutes.c b/common/traderoutes.c index c711d84ef3..e8e0fe894e 100644 --- a/common/traderoutes.c +++ b/common/traderoutes.c @@ -228,7 +228,7 @@ bool can_cities_trade(const struct city *pc1, const struct city *pc2) replaced by a new one. The target routes to be removed will be put into 'would_remove', if set. *************************************************************************/ -int city_trade_removable(const struct city *pcity, +int city_trade_removable(const struct city *pcity, int priority, struct trade_route_list *would_remove) { struct trade_route *sorted[MAX_TRADE_ROUTES]; @@ -237,21 +237,29 @@ int city_trade_removable(const struct city *pcity, /* Sort trade route values. */ num = 0; trade_routes_iterate(pcity, proute) { - for (j = num; j > 0 && (proute->value < sorted[j - 1]->value) ; j--) { - sorted[j] = sorted[j - 1]; + if (proute->goods->priority <= priority) { + for (j = num; j > 0 && proute->goods->priority > sorted[j - 1]->goods->priority; j--) ; + + /* Search place amoung same priority ones. */ + for (; j > 0 + && (proute->value < sorted[j - 1]->value) + && (proute->goods->priority == sorted[j - 1]->goods->priority) ; + j--) { + sorted[j] = sorted[j - 1]; + } + sorted[j] = proute; + num++; } - sorted[j] = proute; - num++; } trade_routes_iterate_end; /* No trade routes at all. */ - if (0 == num) { + if (num == 0) { return 0; } /* Adjust number of concerned trade routes. */ num += 1 - max_trade_routes(pcity); - if (0 >= num) { + if (num < 0) { num = 1; } @@ -267,12 +275,13 @@ int city_trade_removable(const struct city *pcity, } /*********************************************************************//** - Returns TRUE iff the two cities can establish a trade route. We look + Returns TRUE iff the two cities can establish a trade route. We look at the distance and ownership of the cities as well as their existing - trade routes. Should only be called if you already know that + trade routes. Should only be called if you already know that can_cities_trade(). *************************************************************************/ -bool can_establish_trade_route(const struct city *pc1, const struct city *pc2) +bool can_establish_trade_route(const struct city *pc1, const struct city *pc2, + int priority) { int trade = -1; int maxpc1; @@ -293,24 +302,24 @@ bool can_establish_trade_route(const struct city *pc1, const struct city *pc2) if (maxpc2 <= 0) { return FALSE; } - + if (city_num_trade_routes(pc1) >= maxpc1) { trade = trade_base_between_cities(pc1, pc2); - /* can we replace trade route? */ - if (city_trade_removable(pc1, NULL) >= trade) { + /* Can we replace trade route? */ + if (city_trade_removable(pc1, priority, NULL) >= trade) { return FALSE; } } - + if (city_num_trade_routes(pc2) >= maxpc2) { if (trade == -1) { trade = trade_base_between_cities(pc1, pc2); } - /* can we replace trade route? */ - if (city_trade_removable(pc2, NULL) >= trade) { + /* Can we replace trade route? */ + if (city_trade_removable(pc2, priority, NULL) >= trade) { return FALSE; } - } + } return TRUE; } @@ -674,7 +683,7 @@ bool goods_has_flag(const struct goods_type *pgood, enum goods_flag_id flag) *************************************************************************/ bool goods_can_be_provided(const struct city *pcity, const struct goods_type *pgood, - struct unit *punit) + const struct unit *punit) { return are_reqs_active(&(const struct req_context) { .player = city_owner(pcity), @@ -719,7 +728,8 @@ bool city_receives_goods(const struct city *pcity, /*********************************************************************//** Return goods type for the new trade route between given cities. *************************************************************************/ -struct goods_type *goods_from_city_to_unit(struct city *src, struct unit *punit) +struct goods_type *goods_from_city_to_unit(const struct city *src, + const struct unit *punit) { int i = 0; struct goods_type *potential[MAX_GOODS_TYPES]; @@ -736,3 +746,20 @@ struct goods_type *goods_from_city_to_unit(struct city *src, struct unit *punit) return potential[fc_rand(i)]; } + +/*********************************************************************//** + What goods unit would provide if it established trade route now? + + @param punit Unit to establish the trade route + @param homecity Homecity of the unit. Can be used speculatively. + @return What good unit would provide +*************************************************************************/ +struct goods_type *unit_current_goods(const struct unit *punit, + const struct city *homecity) +{ + if (game.info.goods_selection == GSM_ARRIVAL) { + return goods_from_city_to_unit(homecity, punit); + } + + return punit->carrying; +} diff --git a/common/traderoutes.h b/common/traderoutes.h index 3a1369fc4c..d826b1fc9c 100644 --- a/common/traderoutes.h +++ b/common/traderoutes.h @@ -112,7 +112,8 @@ struct trade_route_settings * trade_route_settings_by_type(enum trade_route_type type); bool can_cities_trade(const struct city *pc1, const struct city *pc2); -bool can_establish_trade_route(const struct city *pc1, const struct city *pc2); +bool can_establish_trade_route(const struct city *pc1, const struct city *pc2, + int priority); bool have_cities_trade_route(const struct city *pc1, const struct city *pc2); int trade_base_between_cities(const struct city *pc1, const struct city *pc2); int trade_from_route(const struct city *pc1, const struct trade_route *route, @@ -124,7 +125,7 @@ int get_caravan_enter_city_trade_bonus(const struct city *pc1, const struct unit_type *ut, struct goods_type *pgood, const bool establish_trade); -int city_trade_removable(const struct city *pcity, +int city_trade_removable(const struct city *pcity, int priority, struct trade_route_list *would_remove); #define trade_routes_iterate(c, proute) \ @@ -179,6 +180,9 @@ do { \ #define SPECENUM_BITVECTOR bv_goods_flags #include "specenum_gen.h" +/* Some places assume this to be bigger than any actual goods priority */ +#define GOODS_HIGH_PRIORITY 100 + struct goods_type { int id; @@ -191,6 +195,8 @@ struct goods_type int to_pct; int onetime_pct; + int priority; + bv_goods_flags flags; struct strvec *helptext; @@ -213,8 +219,11 @@ bool goods_has_flag(const struct goods_type *pgood, enum goods_flag_id flag); bool goods_can_be_provided(const struct city *pcity, const struct goods_type *pgood, - struct unit *punit); -struct goods_type *goods_from_city_to_unit(struct city *src, struct unit *punit); + const struct unit *punit); +struct goods_type *goods_from_city_to_unit(const struct city *src, + const struct unit *punit); +struct goods_type *unit_current_goods(const struct unit *punit, + const struct city *homecity); bool city_receives_goods(const struct city *pcity, const struct goods_type *pgood); diff --git a/data/alien/game.ruleset b/data/alien/game.ruleset index 211cd4a95b..79f61e76f7 100644 --- a/data/alien/game.ruleset +++ b/data/alien/game.ruleset @@ -544,6 +544,8 @@ goods_selection = "Arrival" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -559,8 +561,9 @@ goods_selection = "Arrival" ; ; */ <-- avoid gettext warnings -[goods_good] -name = _("Commodities") +[goods_commodities] +name = _("Commodities") +priority = 1 ; /* <-- avoid gettext warnings diff --git a/data/civ1/game.ruleset b/data/civ1/game.ruleset index bdf89fab8e..38db22ef13 100644 --- a/data/civ1/game.ruleset +++ b/data/civ1/game.ruleset @@ -576,6 +576,8 @@ goods_selection = "Arrival" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -592,8 +594,9 @@ goods_selection = "Arrival" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") -flags = "Bidirectional" +name = _("Goods") +priority = 1 +flags = "Bidirectional" ; /* <-- avoid gettext warnings diff --git a/data/civ2/game.ruleset b/data/civ2/game.ruleset index cef60d38a5..cd1a961e9b 100644 --- a/data/civ2/game.ruleset +++ b/data/civ2/game.ruleset @@ -507,6 +507,8 @@ goods_selection = "Arrival" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -523,8 +525,9 @@ goods_selection = "Arrival" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") -flags = "Bidirectional" +name = _("Goods") +priority = 1 +flags = "Bidirectional" ; /* <-- avoid gettext warnings diff --git a/data/civ2civ3/game.ruleset b/data/civ2civ3/game.ruleset index 3bc0936d1b..028646552b 100644 --- a/data/civ2civ3/game.ruleset +++ b/data/civ2civ3/game.ruleset @@ -641,6 +641,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -654,6 +656,7 @@ goods_selection = "Leaving" [goods_good] name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings ; diff --git a/data/classic/game.ruleset b/data/classic/game.ruleset index 2f973c9e79..070b221467 100644 --- a/data/classic/game.ruleset +++ b/data/classic/game.ruleset @@ -554,6 +554,8 @@ goods_selection = "Arrival" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -570,7 +572,9 @@ goods_selection = "Arrival" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 + ; /* <-- avoid gettext warnings ; diff --git a/data/goldkeep/game.ruleset b/data/goldkeep/game.ruleset index 9744220d29..9425804c23 100644 --- a/data/goldkeep/game.ruleset +++ b/data/goldkeep/game.ruleset @@ -572,6 +572,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -588,7 +590,8 @@ goods_selection = "Leaving" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings diff --git a/data/granularity/game.ruleset b/data/granularity/game.ruleset index fb500fe8d6..4dea681ee4 100644 --- a/data/granularity/game.ruleset +++ b/data/granularity/game.ruleset @@ -527,6 +527,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -543,7 +545,8 @@ goods_selection = "Leaving" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings diff --git a/data/multiplayer/game.ruleset b/data/multiplayer/game.ruleset index 724f0f56b2..519aa7b064 100644 --- a/data/multiplayer/game.ruleset +++ b/data/multiplayer/game.ruleset @@ -526,6 +526,8 @@ goods_selection = "Arrival" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -542,8 +544,8 @@ goods_selection = "Arrival" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") - +name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings ; diff --git a/data/ruledit/comments-3.3.txt b/data/ruledit/comments-3.3.txt index ae8cf968ba..74bc19a77e 100644 --- a/data/ruledit/comments-3.3.txt +++ b/data/ruledit/comments-3.3.txt @@ -1120,6 +1120,8 @@ goods = "\ ; to_pct = Income for the receiving end of the trade route. Default is 100\%\n\ ; This value is not used at all in case of bidirectional routes.\n\ ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100\%\n\ +; priority = Trade routes get replaced by higher priority goods, or higher\n\ +; trade value when priority is the same.\n\ ; flags\n\ ; - \"Bidirectional\" = Trade route carrying the goods does not have \"from\" and \"to\"\n\ ; ends, but both ends are considered the same.\n\ diff --git a/data/sandbox/game.ruleset b/data/sandbox/game.ruleset index 3da7710a52..7fad3ebbcc 100644 --- a/data/sandbox/game.ruleset +++ b/data/sandbox/game.ruleset @@ -639,6 +639,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -655,78 +657,86 @@ goods_selection = "Leaving" ; */ <-- avoid gettext warnings [goods_wares] -name = _("Wares") -flags = "Bidirectional" +name = _("Wares") +priority = 1 +flags = "Bidirectional" [goods_spice] -name = _("Spice") -reqs = +name = _("Spice") +priority = 1 +reqs = { "type", "name", "range" "Extra", "Spice", "City" } -from_pct = 135 -to_pct = 100 -flags = "Depletes" +from_pct = 135 +to_pct = 100 +flags = "Depletes" [goods_gems] -name = _("Gems") -reqs = +name = _("Gems") +priority = 1 +reqs = { "type", "name", "range" "Extra", "Gems", "City" } -from_pct = 135 -to_pct = 100 -flags = "Depletes" +from_pct = 135 +to_pct = 100 +flags = "Depletes" [goods_jewelry] -name = _("Jewelry") +name = _("Jewelry") +priority = 1 reqs = { "type", "name", "range" "Good", "Gems", "City" } -from_pct = 250 -to_pct = 150 -flags = "Depletes" +from_pct = 250 +to_pct = 150 +flags = "Depletes" [goods_ore] -name = _("Ore") +name = _("Ore") +priority = 1 reqs = { "type", "name", "range" "Extra", "Mine", "City" } -flags = "Depletes" +flags = "Depletes" [goods_metal] -name = _("Metal") +name = _("Metal") +priority = 1 reqs = { "type", "name", "range" "Good", "Ore", "City" } -from_pct = 135 -to_pct = 100 -flags = "Depletes" +from_pct = 135 +to_pct = 100 +flags = "Depletes" [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 reqs = { "type", "name", "range", "present" "Good", "Metal", "City", TRUE "Tech", "Electronics", "Player", FALSE } -from_pct = 150 -to_pct = 135 -flags = "Depletes" +from_pct = 150 +to_pct = 135 +flags = "Depletes" [goods_equipment] -name = _("Equipment") +name = _("Equipment") +priority = 1 reqs = { "type", "name", "range" "Good", "Metal", "City" "Tech", "Electronics", "Player" } -from_pct = 200 -to_pct = 150 -flags = "Depletes" +from_pct = 200 +to_pct = 150 +flags = "Depletes" ; /* <-- avoid gettext warnings diff --git a/data/stub/game.ruleset b/data/stub/game.ruleset index 480b2b4d84..31ccdfb9f6 100644 --- a/data/stub/game.ruleset +++ b/data/stub/game.ruleset @@ -519,6 +519,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -535,7 +537,8 @@ goods_selection = "Leaving" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings diff --git a/data/webperimental/game.ruleset b/data/webperimental/game.ruleset index 2581cb2aad..d27b397887 100644 --- a/data/webperimental/game.ruleset +++ b/data/webperimental/game.ruleset @@ -558,6 +558,8 @@ goods_selection = "Leaving" ; to_pct = Income for the receiving end of the trade route. Default is 100% ; This value is not used at all in case of bidirectional routes. ; onetime_pct = Onetime bonuses when trade route gets established. Default is 100% +; priority = Trade routes get replaced by higher priority goods, or higher +; trade value when priority is the same. ; flags ; - "Bidirectional" = Trade route carrying the goods does not have "from" and "to" ; ends, but both ends are considered the same. @@ -574,7 +576,8 @@ goods_selection = "Leaving" ; */ <-- avoid gettext warnings [goods_good] -name = _("Goods") +name = _("Goods") +priority = 1 ; /* <-- avoid gettext warnings diff --git a/server/citytools.c b/server/citytools.c index b9998f3ee5..197b15262f 100644 --- a/server/citytools.c +++ b/server/citytools.c @@ -964,7 +964,7 @@ static void reestablish_city_trade_routes(struct city *pcity) back = remove_trade_route(pcity, proute, FALSE, FALSE); keep_route = can_cities_trade(pcity, partner) - && can_establish_trade_route(pcity, partner); + && can_establish_trade_route(pcity, partner, proute->goods->priority); if (!keep_route) { enum trade_route_type type = cities_trade_route_type(pcity, partner); diff --git a/server/ruleset.c b/server/ruleset.c index 2481326127..b29bf6e2b8 100644 --- a/server/ruleset.c +++ b/server/ruleset.c @@ -7406,6 +7406,8 @@ static bool load_ruleset_game(struct section_file *file, bool act, "%s.to_pct", sec_name); pgood->onetime_pct = secfile_lookup_int_default(file, 100, "%s.onetime_pct", sec_name); + pgood->priority = secfile_lookup_int_default(file, 1, + "%s.priority", sec_name); slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec_name); BV_CLR_ALL(pgood->flags); diff --git a/server/unithand.c b/server/unithand.c index da7a774b4b..39b28650d6 100644 --- a/server/unithand.c +++ b/server/unithand.c @@ -5849,11 +5849,8 @@ static bool do_unit_establish_trade(struct player *pplayer, return FALSE; } - if (game.info.goods_selection == GSM_ARRIVAL) { - goods = goods_from_city_to_unit(pcity_homecity, punit); - } else { - goods = punit->carrying; - } + goods = unit_current_goods(punit, pcity_homecity); + if (goods == NULL) { notify_player(pplayer, unit_tile(punit), E_BAD_COMMAND, ftc_server, _("Sorry, your %s cannot establish" @@ -5881,7 +5878,7 @@ static bool do_unit_establish_trade(struct player *pplayer, routes_out_of_home = trade_route_list_new(); routes_out_of_dest = trade_route_list_new(); - /* This part of code works like can_establish_trade_route, except + /* This part of code works like can_establish_trade_route(), except * that we actually do the action of making the trade route. */ /* If we can't make a new trade route we can still get the trade bonus. */ @@ -5901,7 +5898,7 @@ static bool do_unit_establish_trade(struct player *pplayer, /* See if there's a trade route we can cancel at the home city. */ if (home_overbooked >= 0) { if (home_max <= 0 - || (city_trade_removable(pcity_homecity, routes_out_of_home) + || (city_trade_removable(pcity_homecity, goods->priority, routes_out_of_home) >= trade)) { notify_player(pplayer, city_tile(pcity_dest), E_BAD_COMMAND, ftc_server, @@ -5925,7 +5922,7 @@ static bool do_unit_establish_trade(struct player *pplayer, /* See if there's a trade route we can cancel at the dest city. */ if (can_establish && dest_overbooked >= 0) { if (dest_max <= 0 - || (city_trade_removable(pcity_dest, routes_out_of_dest) + || (city_trade_removable(pcity_dest, goods->priority, routes_out_of_dest) >= trade)) { notify_player(pplayer, city_tile(pcity_dest), E_BAD_COMMAND, ftc_server, diff --git a/tools/ruleutil/rulesave.c b/tools/ruleutil/rulesave.c index a98607f369..2514f6b82e 100644 --- a/tools/ruleutil/rulesave.c +++ b/tools/ruleutil/rulesave.c @@ -1767,6 +1767,7 @@ static bool save_game_ruleset(const char *filename, const char *name) save_default_int(sfile, pgood->from_pct, 100, path, "from_pct"); save_default_int(sfile, pgood->to_pct, 100, path, "to_pct"); save_default_int(sfile, pgood->onetime_pct, 100, path, "onetime_pct"); + save_default_int(sfile, pgood->priority, 1, path, "priority"); set_count = 0; for (flagi = 0; flagi < GF_COUNT; flagi++) { -- 2.40.1