Project

General

Profile

Feature #1791 » 1761.v2.patch

John Robertson, 12/03/2025 03:21 AM

View differences:

ai/default/daiferry.c
aiferry_psngr_meet_boat(ait, punit, ferryboat);
punit->goto_tile = dest_tile;
punit->worker_activity = ACTIVITY_LAST;
punit->worker_target = NULL;
/* Grab bodyguard */
if (bodyguard
&& !same_pos(unit_tile(punit), unit_tile(bodyguard))) {
......
aunit->id,
TILE_XY(unit_tile(aunit)));
pferry->goto_tile = unit_tile(aunit);
pferry->worker_activity = ACTIVITY_LAST;
pferry->worker_target = NULL;
/* Exchange phone numbers */
aiferry_psngr_meet_boat(ait, aunit, pferry);
pf_map_destroy(pfm);
......
"find something better",
city_name_get(pcity));
pferry->goto_tile = pos.tile;
pferry->worker_activity = ACTIVITY_IDLE;
pferry->worker_target = NULL;
turns_horizon = turns;
needed = TRUE;
}
......
if (safe_city != nullptr) {
punit->goto_tile = safe_city->tile;
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = NULL;
UNIT_LOG(LOGLEVEL_FERRY, punit, "No work, going home");
unit_data->done = TRUE;
dai_unit_new_task(ait, punit, AIUNIT_NONE, nullptr);
ai/default/daisettler.c
struct unit *punit, struct workermap *state)
{
adv_want best_impr = 0; /* Value of best terrain improvement we can do */
enum unit_activity best_act;
struct extra_type *best_target;
enum unit_activity best_act = ACTIVITY_IDLE;
struct extra_type *best_target = NULL;
struct tile *best_tile = NULL;
struct pf_path *path = NULL;
struct city *pcity = NULL;
/* Time it will take worker to complete its given task */
int completion_time = 0;
......
/*** Try find some work ***/
if (unit_has_type_flag(punit, UTYF_WORKERS)) {
struct worker_task *best_task;
TIMING_LOG(AIT_WORKERS, TIMER_START);
/* Have nearby cities requests? */
pcity = worker_evaluate_city_requests(punit, &best_task, &path, state);
worker_evaluate_city_requests(punit, &path, state);
if (pcity != NULL) {
if (punit->worker_activity != ACTIVITY_IDLE) {
if (path != NULL) {
completion_time = pf_path_last_position(path)->turn;
best_impr = 1;
best_act = best_task->act;
best_target = best_task->tgt;
best_tile = best_task->ptile;
best_act = punit->worker_activity;
best_target = punit->worker_target;
best_tile = punit->goto_tile;
} else {
pcity = NULL;
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = NULL;
punit->goto_tile = NULL;
}
}
if (pcity == NULL) {
if (best_impr) {
best_impr = worker_evaluate_improvements(nmap, punit,
&best_act, &best_target,
&best_tile, &path, state);
......
citymap_reserve_tile(result->best_other.tile, punit->id);
}
punit->goto_tile = result->tile; /* TMP */
punit->worker_activity = ACTIVITY_LAST;
punit->worker_target = NULL;
cityresult_destroy(result);
......
adv_unit_new_task(punit, AUT_AUTO_WORKER, best_tile);
}
if (best_tile != NULL
&& auto_worker_setup_work(nmap, pplayer, punit, state, 0, &path,
best_tile, best_act, &best_target,
completion_time)) {
if (pcity != NULL) {
clear_worker_tasks(pcity);
}
if (best_impr && best_tile != NULL) {
auto_worker_setup_work(nmap, pplayer, punit, state, 0, &path, best_tile,
best_act, best_target, completion_time);
}
CLEANUP:
ai/default/daitools.c
* if we are on a ferry */
if (goto_is_sane(punit, dest_tile) && punit->moves_left > 0) {
punit->goto_tile = dest_tile;
punit->worker_activity = ACTIVITY_LAST;
punit->worker_target = NULL;
UNIT_LOG(LOGLEVEL_GOTHERE, punit, "Walking to (%d,%d)", TILE_XY(dest_tile));
if (!dai_unit_goto(ait, punit, dest_tile)) {
/* Died */
......
if (is_ferry) {
/* Show the destination in the client when watching an AI: */
punit->goto_tile = ptile;
punit->worker_activity = ACTIVITY_LAST;
punit->worker_target = NULL;
}
}
ai/default/daiunit.c
* adv_follow_path(). This way other units will know we're
* on our way even if we don't reach target yet. */
punit->goto_tile = dest_tile;
punit->worker_activity = ACTIVITY_LAST;
punit->worker_target = NULL;
unit_activity_handling(punit, ACTIVITY_GOTO, ACTION_NONE);
if (path != nullptr && !adv_follow_path(punit, path, dest_tile)) {
/* Died. */
ai/tex/texaicity.c
data->task.ptile = task.ptile;
data->task.act = task.act;
data->task.tgt = task.tgt;
data->task.want = task.want;
data->task.wanted = task.wanted;
data->task.enroute = task.enroute;
data->task.placed = task.placed;
texai_send_req(TEXAI_REQ_WORKER_TASK, pplayer, data);
}
......
action_id_get_activity(act));
if (tile_worked(ptile) == pcity) {
if ((value - orig_value) * TWMP > worked->want) {
worked->want = TWMP * (value - orig_value);
if ((value - orig_value) * TWMP > worked->wanted) {
worked->wanted = TWMP * (value - orig_value);
worked->ptile = ptile;
worked->act = action_id_get_activity(act);
worked->tgt = NULL;
......
ptile,
TRUE,
ptile, tgt))) {
state->wants[utype_index(unit_type_get(punit))] += worked->want;
state->wants[utype_index(unit_type_get(punit))]
+= worked->wanted;
}
} unit_list_iterate_end;
}
......
if (value > orig_value && value > state->uw_max) {
state->uw_max = value;
state->uw_max_base = value;
unworked->want = TWMP * (value - orig_value);
unworked->wanted = TWMP * (value - orig_value);
unworked->ptile = ptile;
unworked->act = action_id_get_activity(act);
unworked->tgt = NULL;
......
ptile,
TRUE,
ptile, tgt))) {
state->wants[utype_index(unit_type_get(punit))] += unworked->want;
state->wants[utype_index(unit_type_get(punit))]
+= unworked->wanted;
}
} unit_list_iterate_end;
}
......
value = base_value + extra;
if (tile_worked(ptile) == pcity) {
if ((value - orig_value) * TWMP > worked->want) {
worked->want = TWMP * (value - orig_value);
if ((value - orig_value) * TWMP > worked->wanted) {
worked->wanted = TWMP * (value - orig_value);
worked->ptile = ptile;
worked->act = action_get_activity(paction);
worked->tgt = tgt;
......
punit, unit_home(punit), ptile,
TRUE,
ptile, tgt))) {
state->wants[utype_index(unit_type_get(punit))] += worked->want;
state->wants[utype_index(unit_type_get(punit))]
+= worked->wanted;
}
} unit_list_iterate_end;
}
......
if (value > orig_value && value > state->uw_max) {
state->uw_max = value;
state->uw_max_base = base_value;
unworked->want = TWMP * (value - orig_value);
unworked->wanted = TWMP * (value - orig_value);
unworked->ptile = ptile;
unworked->act = action_get_activity(paction);
unworked->tgt = tgt;
......
punit, unit_home(punit), ptile,
TRUE,
ptile, tgt))) {
state->wants[utype_index(unit_type_get(punit))] += unworked->want;
state->wants[utype_index(unit_type_get(punit))]
+= unworked->wanted;
}
} unit_list_iterate_end;
}
......
enum texai_worker_task_limitation limit)
{
struct worker_task *selected;
struct worker_task worked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
struct worker_task unworked = { .ptile = NULL, .want = 0, .act = ACTIVITY_IDLE, .tgt = NULL };
struct texai_tile_state state = { .uw_max = 0, .uw_max_base = 0, .worst_worked = FC_INFINITY,
.orig_worst_worked = 0, .old_worst_worked = FC_INFINITY };
struct worker_task worked = { .ptile = NULL,
.wanted = 0,
.enroute = 0,
.placed = 0,
.act = ACTIVITY_IDLE,
.tgt = NULL };
struct worker_task unworked = { .ptile = NULL,
.wanted = 0,
.enroute = 0,
.placed = 0,
.act = ACTIVITY_IDLE,
.tgt = NULL };
struct texai_tile_state state = { .uw_max = 0,
.uw_max_base = 0,
.worst_worked = FC_INFINITY,
.orig_worst_worked = 0,
.old_worst_worked = FC_INFINITY };
struct unit_list *units = NULL;
const struct civ_map *nmap = &(wld.map);
......
units = unit_list_new();
unit_type_iterate(ptype) {
if (can_city_build_unit_now(nmap, pcity, ptype)) {
unit_list_append(units, unit_virtual_create(pplayer, pcity, ptype, 0));
unit_list_append(units, unit_virtual_create(pplayer, pcity, ptype,
0));
}
} unit_type_iterate_end;
state.wants = texai_city_data(ait, pcity)->unit_wants;
......
if (worked.ptile == NULL
|| (state.old_worst_worked < state.uw_max
&& (state.uw_max - state.orig_worst_worked) * TWMP > worked.want)
|| (state.uw_max - state.uw_max_base * TWMP > worked.want)) {
&& (state.uw_max - state.orig_worst_worked) * TWMP > worked.wanted)
|| (state.uw_max - state.uw_max_base * TWMP > worked.wanted)) {
/* It's better to improve best yet unworked tile and take it to use after that,
than to improve already worked tile. OR it's more important to
improve road connectivity outside worked tiles than improve worked tiles */
......
task->ptile = selected->ptile;
task->act = selected->act;
task->tgt = target;
task->want = selected->want;
task->wanted = selected->wanted;
task->enroute = selected->enroute;
task->placed = selected->placed;
return TRUE;
}
......
if (pcity != NULL && city_owner(pcity) == req->plr) {
/* City has not been lost meanwhile */
struct worker_task *ptask = worker_task_list_get(pcity->task_reqs, 0);
if (ptask == NULL) {
ptask = fc_malloc(sizeof(struct worker_task));
worker_task_init(ptask);
worker_task_list_append(pcity->task_reqs, ptask);
}
worker_task_new(pcity->task_reqs, data->task.ptile, data->task.act,
data->task.tgt, data->task.wanted );
log_debug("%s storing req for act %d at (%d,%d)",
pcity->name, data->task.act, TILE_XY(data->task.ptile));
ptask->ptile = data->task.ptile;
ptask->act = data->task.act;
ptask->tgt = data->task.tgt;
ptask->want = data->task.want;
/* Send info to observers */
package_and_send_worker_tasks(pcity);
client/gui-gtk-3.22/citydlg.c
if (act == ACTIVITY_LAST) {
task.tgt = -1;
task.want = 0;
task.wanted = 0;
} else {
enum extra_cause cause = activity_to_extra_cause(act);
enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
......
}
task.tgt = -1;
task.wanted = 0;
} else {
task.tgt = extra_index(tgt);
switch (task.activity)
{
case ACTIVITY_CLEAN:
task.wanted = CITY_ACTIVITY_MEDIUM_WANTED;
break;
case ACTIVITY_CONVERT:
case ACTIVITY_CULTIVATE:
case ACTIVITY_PLANT:
case ACTIVITY_TRANSFORM:
task.wanted = CITY_ACTIVITY_MAX_WANTED;
break;
default:
task.wanted = CITY_ACTIVITY_DEFAULT_WANTED;
break;
}
}
task.want = 100;
}
task.tile_id = ptile->index;
client/gui-gtk-4.0/citydlg.c
if (act == ACTIVITY_LAST) {
task.tgt = -1;
task.want = 0;
task.wanted = 0;
} else {
enum extra_cause cause = activity_to_extra_cause(act);
enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
......
}
task.tgt = -1;
task.wanted = 0;
} else {
task.tgt = extra_index(tgt);
switch (task.activity)
{
case ACTIVITY_CLEAN:
task.wanted = CITY_ACTIVITY_MEDIUM_WANTED;
break;
case ACTIVITY_CONVERT:
case ACTIVITY_CULTIVATE:
case ACTIVITY_PLANT:
case ACTIVITY_TRANSFORM:
task.wanted = CITY_ACTIVITY_MAX_WANTED;
break;
default:
task.wanted = CITY_ACTIVITY_DEFAULT_WANTED;
break;
}
}
task.want = 100;
}
task.tile_id = ptile->index;
client/gui-gtk-5.0/citydlg.c
if (act == ACTIVITY_LAST) {
task.tgt = -1;
task.want = 0;
task.wanted = 0;
} else {
enum extra_cause cause = activity_to_extra_cause(act);
enum extra_rmcause rmcause = activity_to_extra_rmcause(act);
......
}
task.tgt = -1;
task.wanted = 0;
} else {
task.tgt = extra_index(tgt);
switch (task.activity)
{
case ACTIVITY_CLEAN:
task.wanted = CITY_ACTIVITY_MEDIUM_WANTED;
break;
case ACTIVITY_CONVERT:
case ACTIVITY_CULTIVATE:
case ACTIVITY_PLANT:
case ACTIVITY_TRANSFORM:
task.wanted = CITY_ACTIVITY_MAX_WANTED;
break;
default:
task.wanted = CITY_ACTIVITY_DEFAULT_WANTED;
break;
}
}
task.want = 100;
}
task.tile_id = ptile->index;
client/gui-qt/citydlg.cpp
return;
}
task.want = 100;
if (target) {
enum extra_cause cause = activity_to_extra_cause(task.activity);
enum extra_rmcause rmcause = activity_to_extra_rmcause(task.activity);
......
if (tgt != nullptr) {
task.tgt = extra_index(tgt);
switch (task.activity)
{
case ACTIVITY_CLEAN:
task.wanted = CITY_ACTIVITY_MEDIUM_WANTED;
break;
case ACTIVITY_CONVERT:
case ACTIVITY_CULTIVATE:
case ACTIVITY_PLANT:
case ACTIVITY_TRANSFORM:
task.wanted = CITY_ACTIVITY_MAX_WANTED;
break;
default:
task.wanted = CITY_ACTIVITY_DEFAULT_WANTED;
break;
}
} else {
task.tgt = -1;
task.wanted = 0;
}
} else {
task.tgt = -1;
task.wanted = 0;
}
task.tile_id = ptile->index;
client/packhand.c
if (packet->activity == ACTIVITY_LAST) {
return;
} else {
ptask = fc_malloc(sizeof(struct worker_task));
worker_task_list_append(pcity->task_reqs, ptask);
ptask = worker_task_new(pcity->task_reqs, NULL, ACTIVITY_IDLE,
nullptr, 0);
}
} else {
if (packet->activity == ACTIVITY_LAST) {
worker_task_list_remove(pcity->task_reqs, ptask);
free(ptask);
worker_task_destroy(pcity->task_reqs, ptask);
ptask = NULL;
}
}
......
} else {
ptask->tgt = NULL;
}
ptask->want = packet->want;
ptask->wanted = packet->wanted;
ptask->enroute = packet->enroute;
}
if (ptask && !worker_task_is_sane(ptask)) {
log_debug("Bad worker task");
worker_task_list_remove(pcity->task_reqs, ptask);
free(ptask);
worker_task_destroy(pcity->task_reqs, ptask);
ptask = NULL;
return;
}
common/city.c
/* Get city tile information using the city tile coordinates. This is an
* [x][y] array of integer values corresponding to city_map_index. The
* coordinates x and y are in the range [0, CITY_MAP_MAX_SIZE] */
static int city_map_xy[CITY_MAP_MAX_SIZE][CITY_MAP_MAX_SIZE];
static int city_map_xy[CITY_MAP_UBER_SIZE][CITY_MAP_UBER_SIZE];
/* Number of tiles of a city; depends on the squared city radius */
static int city_map_numtiles[CITY_MAP_MAX_RADIUS_SQ + 1];
static int city_map_numtiles[CITY_MAP_UBER_RADIUS_SQ + 1];
/* Definitions and functions for the tile_cache */
struct tile_cache {
......
int city_tile_index, int city_radius_sq)
{
fc_assert_ret_val(city_radius_sq >= CITY_MAP_MIN_RADIUS_SQ, FALSE);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_MAX_RADIUS_SQ, FALSE);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_UBER_RADIUS_SQ, FALSE);
/* tile indices are sorted from smallest to largest city radius */
if (city_tile_index < 0
......
int city_radius_sq)
{
fc_assert_ret_val(city_radius_sq >= CITY_MAP_MIN_RADIUS_SQ, 0);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_MAX_RADIUS_SQ, 0);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_UBER_RADIUS_SQ, 0);
fc_assert_ret_val(is_valid_city_coords(city_radius_sq, city_map_x,
city_map_y), 0);
......
}
fc_assert_ret_val(city_radius_sq >= CITY_MAP_MIN_RADIUS_SQ, -1);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_MAX_RADIUS_SQ, -1);
fc_assert_ret_val(city_radius_sq <= CITY_MAP_UBER_RADIUS_SQ, -1);
return city_map_numtiles[city_radius_sq];
}
......
void generate_city_map_indices(void)
{
int i, dx, dy, city_x, city_y, dist, city_count_tiles = 0;
struct iter_index city_map_index_tmp[CITY_MAP_MAX_SIZE
* CITY_MAP_MAX_SIZE];
struct iter_index city_map_index_tmp[CITY_MAP_UBER_SIZE
* CITY_MAP_UBER_SIZE];
/* initialise map information for each city radii */
for (i = 0; i <= CITY_MAP_MAX_RADIUS_SQ; i++) {
for (i = 0; i <= CITY_MAP_UBER_RADIUS_SQ; i++) {
city_map_numtiles[i] = 0; /* will be set below */
}
......
* we don't know the number of tiles within the city radius, so we need
* an temporary city_map_index array. Its content will be copied into
* the real array below. */
for (dx = -CITY_MAP_MAX_RADIUS; dx <= CITY_MAP_MAX_RADIUS; dx++) {
for (dy = -CITY_MAP_MAX_RADIUS; dy <= CITY_MAP_MAX_RADIUS; dy++) {
for (dx = -CITY_MAP_UBER_RADIUS; dx <= CITY_MAP_UBER_RADIUS; dx++) {
for (dy = -CITY_MAP_UBER_RADIUS; dy <= CITY_MAP_UBER_RADIUS; dy++) {
dist = map_vector_to_sq_distance(dx, dy);
if (dist <= CITY_MAP_MAX_RADIUS_SQ) {
if (dist <= CITY_MAP_UBER_RADIUS_SQ) {
city_map_index_tmp[city_count_tiles].dx = dx;
city_map_index_tmp[city_count_tiles].dy = dy;
city_map_index_tmp[city_count_tiles].dist = dist;
for (i = CITY_MAP_MAX_RADIUS_SQ; i >= 0; i--) {
for (i = CITY_MAP_UBER_RADIUS_SQ; i >= 0; i--) {
if (dist <= i) {
/* increase number of tiles within this squared city radius */
city_map_numtiles[i]++;
......
/* Free worker tasks */
while (worker_task_list_size(pcity->task_reqs) > 0) {
struct worker_task *ptask = worker_task_list_get(pcity->task_reqs, 0);
worker_task_list_remove(pcity->task_reqs, ptask);
free(ptask);
worker_task_destroy(pcity->task_reqs, ptask);
}
worker_task_list_destroy(pcity->task_reqs);
common/city.h
#include "specenum_gen.h"
/* The city includes all tiles dx^2 + dy^2 <= CITY_MAP_*_RADIUS_SQ */
#define CITY_MAP_DEFAULT_RADIUS_SQ \
(CITY_MAP_DEFAULT_RADIUS * CITY_MAP_DEFAULT_RADIUS + 1)
#define CITY_MAP_MIN_RADIUS_SQ \
(CITY_MAP_MIN_RADIUS * CITY_MAP_MIN_RADIUS + 1)
#define CITY_MAP_DEFAULT_RADIUS_SQ \
(CITY_MAP_DEFAULT_RADIUS * CITY_MAP_DEFAULT_RADIUS + 1)
#define CITY_MAP_LARGE_RADIUS_SQ \
(CITY_MAP_LARGE_RADIUS * CITY_MAP_LARGE_RADIUS + 1)
#define CITY_MAP_HUGE_RADIUS_SQ \
(CITY_MAP_HUGE_RADIUS * CITY_MAP_HUGE_RADIUS + 1)
#define CITY_MAP_MAX_RADIUS_SQ \
(CITY_MAP_MAX_RADIUS * CITY_MAP_MAX_RADIUS + 1)
#define CITY_MAP_UBER_RADIUS_SQ \
(CITY_MAP_UBER_RADIUS * CITY_MAP_UBER_RADIUS + 13)
/* The id for the city center */
#define CITY_MAP_CENTER_RADIUS_SQ -1
/* The tile index of the city center */
......
/* Maximum diameter of the workable city area. */
#define CITY_MAP_MAX_SIZE (CITY_MAP_MAX_RADIUS * 2 + 1)
#define CITY_MAP_UBER_SIZE (CITY_MAP_UBER_RADIUS * 2 + 1)
#define CITY_ACTIVITY_MIN_WANTED 1
#define CITY_ACTIVITY_DEFAULT_WANTED 5
#define CITY_ACTIVITY_MEDIUM_WANTED 9
#define CITY_ACTIVITY_MAX_WANTED 13
#define INCITE_IMPOSSIBLE_COST (1000 * 1000 * 1000)
common/fc_types.h
* in incompatible savefiles. */
#define CITY_MAP_MIN_RADIUS 0
#define CITY_MAP_DEFAULT_RADIUS 2
#define CITY_MAP_LARGE_RADIUS 3
#define CITY_MAP_HUGE_RADIUS 4
#define CITY_MAP_MAX_RADIUS 5
#define CITY_MAP_UBER_RADIUS (CITY_MAP_MAX_RADIUS + 1)
/* Below size of city tiles array is big enough for radius 5 city */
FC_STATIC_ASSERT(CITY_MAP_MAX_RADIUS <= 5, too_many_city_tiles);
common/networking/packets.def
TILE tile_id;
ACTIVITY activity;
EXTRA tgt;
UINT16 want;
UINT16 wanted;
UINT16 enroute;
end
/************** Player packets **********************/
common/unit.c
memset(punit->upkeep, 0, O_LAST * sizeof(*punit->upkeep));
punit->goto_tile = nullptr;
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = NULL;
max_vet_lvl = utype_veteran_levels(punittype) - 1;
punit->veteran = MIN(veteran_level, max_vet_lvl);
/* A unit new and fresh ... */
......
{
if (punit->has_orders) {
punit->goto_tile = NULL;
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = NULL;
free(punit->orders.list);
punit->orders.list = NULL;
}
common/unit.h
enum unit_activity activity;
enum gen_action action;
enum unit_activity worker_activity;
struct extra_type *worker_target; /* May be NULL */
/* The amount of work that has been done on the current activity. This
* is counted in turns but is multiplied by ACTIVITY_FACTOR (which allows
* fractional values in some cases). */
common/workertask.c
****************************************************************************/
void worker_task_init(struct worker_task *ptask)
{
ptask->act = ACTIVITY_IDLE;
ptask->ptile = NULL;
ptask->want = 0;
ptask->tgt = nullptr;
ptask->wanted = 0;
ptask->enroute = 0;
ptask->placed = 0;
}
/************************************************************************//**
.
****************************************************************************/
struct worker_task * worker_task_new(struct worker_task_list *task_reqs,
struct tile *ptile, enum unit_activity act, struct extra_type * target,
int want)
{
struct worker_task *ptask = fc_malloc(sizeof(struct worker_task));
ptask->ptile = ptile;
ptask->act = act;
ptask->tgt = target;
ptask->wanted = want;
ptask->enroute = 0;
ptask->placed = 0;
worker_task_list_append(task_reqs, ptask);
return ptask;
}
/************************************************************************//**
.
****************************************************************************/
void worker_task_destroy(struct worker_task_list *task_reqs, struct worker_task *ptask)
{
if (task_reqs != nullptr) worker_task_list_remove(task_reqs, ptask);
if (ptask != nullptr) free(ptask);
}
/************************************************************************//**
common/workertask.h
struct tile *ptile;
enum unit_activity act;
struct extra_type *tgt;
int want;
int wanted;
int enroute;
int placed;
};
/* get 'struct worker_task_list' and related functions: */
......
#define worker_task_list_iterate_end LIST_ITERATE_END
void worker_task_init(struct worker_task *ptask);
struct worker_task * worker_task_new(struct worker_task_list *task_reqs,
struct tile *ptile, enum unit_activity act, struct extra_type * target,
int want );
void worker_task_destroy(struct worker_task_list *task_reqs,
struct worker_task *ptask);
bool worker_task_is_sane(struct worker_task *ptask);
server/advisors/autoworkers.c
/* server */
#include "citytools.h"
#include "cityturn.h"
#include "maphand.h"
#include "plrhand.h"
#include "srv_log.h"
......
static struct timer *aw_timer = NULL;
#define LOG_WORKER LOG_DEBUG
/**********************************************************************//**
Free resources allocated for autoworkers system
**************************************************************************/
......
i = 0;
action_array_add_all_by_result(aw_actions_rmextra, &i,
ACTRES_CLEAN);
action_array_add_all_by_result(aw_actions_rmextra, &i,
ACTRES_PILLAGE);
/* We could have ACTRES_PILLAGE here, but currently we don't */
action_array_end(aw_actions_rmextra, i);
}
......
< inbound_distance))) {
if (enroute) {
UNIT_LOG(LOG_DEBUG, punit,
UNIT_LOG(LOG_WORKER, punit,
"Considering (%d, %d) because we're closer "
"(%d, %d) than %d (%d, %d)",
TILE_XY(ptile), pos.turn,
......
return best_newv;
}
static struct extra_type *ecoal = NULL;
static struct extra_type *efallout = NULL;
static struct extra_type *efarmland = NULL;
static struct extra_type *efruit = NULL;
static struct extra_type *efurs = NULL;
static struct extra_type *egame = NULL;
static struct extra_type *egems = NULL;
static struct extra_type *eirrigation = NULL;
static struct extra_type *eivory = NULL;
static struct extra_type *emine = NULL;
static struct extra_type *eoasis = NULL;
static struct extra_type *eoil = NULL;
static struct extra_type *eoilwell = NULL;
static struct extra_type *epeat = NULL;
static struct extra_type *epollution = NULL;
static struct extra_type *erailroad = NULL;
static struct extra_type *eroad = NULL;
static struct extra_type *eruins = NULL;
static struct extra_type *esilk = NULL;
static struct extra_type *espice = NULL;
static struct extra_type *ewine = NULL;
static struct terrain *tdesert = NULL;
static struct terrain *tforest = NULL;
static struct terrain *tglacier = NULL;
static struct terrain *thills = NULL;
static struct terrain *tjungle = NULL;
static struct terrain *tmountains = NULL;
static struct terrain *tswamp = NULL;
static struct terrain *ttundra = NULL;
static struct cm_parameter cmp;
static struct tile *request_compare_tile = NULL; //! NOT thread safe
/**********************************************************************//**
.
**************************************************************************/
int city_proximity_compare(const struct city *const *left,
const struct city *const *right)
{
if (request_compare_tile == NULL) return 0;
int left_dist = map_distance(request_compare_tile, city_tile(*left));
int right_dist = map_distance(request_compare_tile, city_tile(*right));
if (left_dist == right_dist) return 0;
if (left_dist < right_dist) return -1;
return 1;
}
/**********************************************************************//**
.
**************************************************************************/
int worker_tasks_compare(const struct worker_task *const *left,
const struct worker_task *const *right)
{
if (request_compare_tile == NULL) return 0;
int left_dist = map_distance(request_compare_tile, (*left)->ptile);
int right_dist = map_distance(request_compare_tile, (*right)->ptile);
if (left_dist == right_dist) return 0;
if (left_dist < right_dist) return -1;
return 1;
}
struct unreachable
{
struct city *pcity;
struct worker_task *ptask;
};
#define SPECLIST_TAG unreachable
#define SPECLIST_TYPE struct unreachable
#include "speclist.h"
#define unreachable_list_iterate(tasklist, ptask) \
TYPED_LIST_ITERATE(struct unreachable, tasklist, ptask)
#define unreachable_list_iterate_end LIST_ITERATE_END
/************************************************************************//**
.
****************************************************************************/
void unreachable_new(struct unreachable_list *unreachables,
struct city *pcity, struct worker_task *ptask)
{
struct unreachable *punreachable = fc_malloc(sizeof(struct unreachable));
punreachable->pcity = pcity;
punreachable->ptask = ptask;
unreachable_list_append(unreachables, punreachable);
}
/************************************************************************//**
.
****************************************************************************/
void unreachable_destroy(struct unreachable_list *unreachables,
struct unreachable *punreachable)
{
if (unreachables != nullptr) {
unreachable_list_remove(unreachables, punreachable);
}
if (punreachable != nullptr) {
free(punreachable);
}
}
/**********************************************************************//**
Return best city request to fulfill.
**************************************************************************/
struct city *worker_evaluate_city_requests(struct unit *punit,
struct worker_task **best_task,
void worker_evaluate_city_requests(struct unit *punit,
struct pf_path **ppath,
struct workermap *state)
{
......
struct pf_parameter parameter;
struct pf_map *pfm;
struct pf_position pos;
int best_value = -1;
struct worker_task *best = NULL;
struct city *taskcity = NULL;
int dist = FC_INFINITY;
const struct civ_map *nmap = &(wld.map);
pft_fill_unit_parameter(&parameter, nmap, punit);
parameter.omniscience = !has_handicap(pplayer, H_MAP);
parameter.get_TB = autoworker_tile_behavior;
if (tjungle == NULL) {
ecoal = extra_type_by_rule_name(_("Coal"));
efallout = extra_type_by_rule_name(_("Fallout"));
efarmland = extra_type_by_rule_name(_("Farmland"));
efruit = extra_type_by_rule_name(_("Fruit"));
efurs = extra_type_by_rule_name(_("Furs"));
egame = extra_type_by_rule_name(_("?animals:Game"));
egems = extra_type_by_rule_name(_("Gems"));
eirrigation = extra_type_by_rule_name(_("Irrigation"));
eivory = extra_type_by_rule_name(_("Ivory"));
emine = extra_type_by_rule_name(_("?extra:Mine"));
eoasis = extra_type_by_rule_name(_("Oasis"));
eoil = extra_type_by_rule_name(_("Oil"));
eoilwell = extra_type_by_rule_name(_("Oil Well"));
epeat = extra_type_by_rule_name(_("Peat"));
epollution = extra_type_by_rule_name(_("?extra:Pollution"));
erailroad = extra_type_by_rule_name(_("Railroad"));
eroad = extra_type_by_rule_name(_("Road"));
eruins = extra_type_by_rule_name(_("Ruins"));
esilk = extra_type_by_rule_name(_("Silk"));
espice = extra_type_by_rule_name(_("Spice"));
ewine = extra_type_by_rule_name(_("Wine"));
tdesert = terrain_by_rule_name(_("Desert"));
tforest = terrain_by_rule_name(_("Forest"));
tglacier = terrain_by_rule_name(_("Glacier"));
thills = terrain_by_rule_name(_("Hills"));
tjungle = terrain_by_rule_name(_("Jungle"));
tmountains = terrain_by_rule_name(_("Mountains"));
tswamp = terrain_by_rule_name(_("Swamp"));
ttundra = terrain_by_rule_name(_("Tundra"));
cm_init_parameter(&cmp);
}
if (punit->worker_activity != ACTIVITY_IDLE) {
if (punit->goto_tile == nullptr
|| punit->worker_activity == ACTIVITY_LAST) {
UNIT_LOG(LOG_WORKER, punit, "%s \x1b[33m%s\x1b[0m",
unit_activity_name(punit->worker_activity),
(punit->worker_activity == ACTIVITY_LAST)
? "confused" : "lost");
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = nullptr;
punit->goto_tile = nullptr;
unit_activity_handling(punit, ACTIVITY_IDLE,
activity_default_action(ACTIVITY_IDLE));
send_unit_info(NULL, punit); /* FIXME: Probably duplicate */
} else if (same_pos(unit_tile(punit), punit->goto_tile)) {
if (punit->worker_activity == ACTIVITY_TRANSFORM
&& tdesert != tile_terrain(unit_tile(punit))
&& tglacier != tile_terrain(unit_tile(punit))
&& tswamp != tile_terrain(unit_tile(punit))
&& ttundra != tile_terrain(unit_tile(punit))) {
UNIT_LOG(LOG_WORKER, punit,
"%s \x1b[33mretracted\x1b[0m (removing remainders)",
unit_activity_name(punit->worker_activity));
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = nullptr;
punit->goto_tile = nullptr;
unit_activity_handling(punit, ACTIVITY_IDLE,
activity_default_action(ACTIVITY_IDLE));
send_unit_info(NULL, punit); /* FIXME: Probably duplicate */
} else if (auto_workers_speculate_can_act_at(punit,
punit->worker_activity,
parameter.omniscience,
punit->worker_target,
unit_tile(punit))) {
if (activity_requires_target(punit->worker_activity)) {
unit_activity_handling_targeted(punit, punit->worker_activity,
&punit->worker_target,
activity_default_action(punit->worker_activity));
} else {
unit_activity_handling(punit, punit->worker_activity,
activity_default_action(punit->worker_activity));
}
send_unit_info(NULL, punit); /* FIXME: Probably duplicate */
UNIT_LOG(LOG_WORKER, punit, "already at worksite — starting work");
} else {
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = nullptr;
punit->goto_tile = nullptr;
unit_activity_handling(punit, ACTIVITY_IDLE,
activity_default_action(ACTIVITY_IDLE));
send_unit_info(NULL, punit); /* FIXME: Probably duplicate */
UNIT_LOG(LOG_WORKER, punit,
"reached its worksite \x1b[33munworkable\x1b[0m");
}
}
if (punit->worker_activity != ACTIVITY_IDLE) {
UNIT_LOG(LOG_WORKER, punit, "\x1b[32m%s\x1b[0m",
unit_activity_name(punit->worker_activity));
return;
}
} else if (punit->goto_tile != nullptr && punit->moves_left > 0) {
UNIT_LOG(LOG_WORKER, punit, "\x1b[32mpossible stalled goto\x1b[0m");
}
pfm = pf_map_new(&parameter);
/* Have nearby cities requests? */
city_list_iterate(pplayer->cities, pcity) {
struct tile *utile = unit_tile(punit);
struct city_list *unit_cities = city_list_new();
city_tile_iterate(nmap, CITY_MAP_UBER_RADIUS_SQ, utile, ptile) {
if (is_allied_city_tile(ptile, unit_owner(punit))) {
city_list_append(unit_cities, tile_city(ptile));
}
} city_tile_iterate_end;
request_compare_tile = unit_tile(punit);
city_list_sort(unit_cities, city_proximity_compare);
city_list_iterate(unit_cities, pcity) {
int tasks_appended = 0;
struct tile *acenter = city_tile(pcity);
int city_radius_sq = city_map_radius_sq_get(pcity);
int city_radius_sq_plus = 10; //game.info.init_city_radius_sq
//+ get_city_bonus(pcity, EFT_CITY_RADIUS_SQ);
struct cm_parameter *pcmp;
struct unreachable_list *unreachables = unreachable_list_new();
CITY_LOG(LOG_WORKER, pcity, "(%d) tasks in queue: %d", city_radius_sq,
worker_task_list_size(pcity->task_reqs));
if (pcity->cm_parameter) {
pcmp = pcity->cm_parameter;
} else {
pcmp = &cmp;
set_default_city_manager(&cmp, pcity);
}
switch (city_radius_sq) {
case CITY_MAP_MIN_RADIUS_SQ:
city_radius_sq_plus = CITY_MAP_DEFAULT_RADIUS_SQ;
break;
case CITY_MAP_DEFAULT_RADIUS_SQ:
city_radius_sq_plus = CITY_MAP_LARGE_RADIUS_SQ;
break;
case CITY_MAP_LARGE_RADIUS_SQ:
city_radius_sq_plus = CITY_MAP_HUGE_RADIUS_SQ;
break;
case CITY_MAP_HUGE_RADIUS_SQ:
city_radius_sq_plus = CITY_MAP_MAX_RADIUS_SQ;
break;
case CITY_MAP_MAX_RADIUS_SQ:
city_radius_sq_plus = CITY_MAP_UBER_RADIUS_SQ;
break;
default:
fc_assert_exit_msg(FALSE, "unhandled city_radius_sq (%d) in %s:%d",
city_radius_sq, __FILE__, __LINE__); break;
}
city_tile_iterate(nmap, city_radius_sq, acenter, ptile) {
bool clean_tasked = false;
bool pillage_tasked = false;
if (tile_has_extra(ptile, epollution)
|| tile_has_extra(ptile, efallout)
|| tile_has_extra(ptile, eruins)) {
worker_task_list_iterate(pcity->task_reqs, ptask) {
bool consider = TRUE;
if (ptask->ptile == ptile) {
if (ptask->act == ACTIVITY_CLEAN) {
clean_tasked = true;
}
if (ptask->act == ACTIVITY_PILLAGE) {
pillage_tasked = true;
}
if (clean_tasked && pillage_tasked) {
break;
}
}
} worker_task_list_iterate_end;
if (!clean_tasked) {
if (tile_has_extra(ptile, epollution)) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_CLEAN,
epollution, CITY_ACTIVITY_MAX_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_CLEAN));
}
if (tile_has_extra(ptile, efallout)) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_CLEAN,
efallout, CITY_ACTIVITY_MAX_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_CLEAN));
}
}
/* Do not go to tiles that already have workers there. */
if (!pillage_tasked) {
if (tile_has_extra(ptile, eruins)) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_PILLAGE,
eruins, CITY_ACTIVITY_MIN_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_PILLAGE));
}
}
}
} city_tile_iterate_end;
if (worker_task_list_size(pcity->task_reqs) <= tasks_appended) {
CITY_LOG(LOG_WORKER, pcity, "size %d, radius_sq %d (%d)",
city_size_get(pcity), city_radius_sq, city_radius_sq_plus);
city_tile_iterate(nmap, city_radius_sq_plus, acenter, ptile) {
if (!is_ocean_tile(ptile)) {
struct extra_type *tgt = eroad;
struct road_type *proad = extra_road_get(tgt);
if (!road_can_be_built(proad, ptile)) {
tgt = erailroad;
proad = extra_road_get(tgt);
}
if (road_can_be_built(proad, ptile)) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_GEN_ROAD,
tgt, CITY_ACTIVITY_DEFAULT_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_GEN_ROAD));
}
}
} city_tile_iterate_end;
city_tile_iterate(nmap, city_radius_sq, acenter, ptile) {
if (!is_ocean_tile(ptile)
&& tforest != tile_terrain(ptile)
&& tmountains != tile_terrain(ptile)
&& tglacier != tile_terrain(ptile)
&& ttundra != tile_terrain(ptile)
&& tjungle != tile_terrain(ptile)
&& !tile_has_extra(ptile, ecoal)
&& !tile_has_extra(ptile, eoil)) {
enum unit_activity act = ACTIVITY_IRRIGATE;
struct extra_type *tgt = eirrigation;
if (thills == tile_terrain(ptile)
&& (pcmp->factor[O_SHIELD] > pcmp->factor[O_FOOD]
|| (pcmp->factor[O_SHIELD] == pcmp->factor[O_FOOD]
&& (ptile->index % 2))
)
) {
act = ACTIVITY_MINE;
tgt = emine;
} else if (!extra_can_be_built(tgt, ptile)) {
tgt = efarmland;
}
if (extra_can_be_built(tgt, ptile)) {
worker_task_new(pcity->task_reqs, ptile, act, tgt,
CITY_ACTIVITY_DEFAULT_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(act));
}
}
if ((tile_has_extra(ptile, ecoal)
|| tile_has_extra(ptile, eoil)
|| tmountains == tile_terrain(ptile))) {
enum unit_activity act = ACTIVITY_MINE;
struct extra_type *tgt = emine;
if (!extra_can_be_built(tgt, ptile)
&& tile_has_extra(ptile, eoil)) {
tgt = eoilwell;
}
if (extra_can_be_built(tgt, ptile)) {
worker_task_new(pcity->task_reqs, ptile, act, tgt,
CITY_ACTIVITY_DEFAULT_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(act));
}
} else if (tjungle == tile_terrain(ptile)
&& !tile_has_extra(ptile, egems)
&& !tile_has_extra(ptile, efruit)) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_CULTIVATE,
nullptr, CITY_ACTIVITY_MAX_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_CULTIVATE));
} else if ((tdesert == tile_terrain(ptile)
|| tglacier == tile_terrain(ptile)
|| tswamp == tile_terrain(ptile)
|| ttundra == tile_terrain(ptile))
&& (!tile_has_extra(ptile, efurs)
&& !tile_has_extra(ptile, egame)
&& !tile_has_extra(ptile, eivory)
&& !tile_has_extra(ptile, eoasis)
&& !tile_has_extra(ptile, eoil)
&& !tile_has_extra(ptile, epeat)
&& !tile_has_extra(ptile, espice))) {
worker_task_new(pcity->task_reqs, ptile, ACTIVITY_TRANSFORM,
nullptr, CITY_ACTIVITY_MAX_WANTED);
++tasks_appended;
log_normal("%s(%d, %d) « %s", terrain_rule_name(ptile->terrain),
TILE_XY(ptile), unit_activity_name(ACTIVITY_TRANSFORM));
}
} city_tile_iterate_end;
CITY_LOG(LOG_WORKER, pcity, "tasks added %d", tasks_appended);
}
worker_task_list_sort(pcity->task_reqs, worker_tasks_compare);
worker_task_list_iterate(pcity->task_reqs, ptask) {
ptask->placed = 0;
unit_list_iterate(ptask->ptile->units, aunit) {
if (unit_owner(aunit) == pplayer
&& aunit->id != punit->id
&& unit_has_type_flag(aunit, UTYF_WORKERS)) {
consider = FALSE;
&& unit_has_type_flag(aunit, UTYF_WORKERS)
&& aunit->activity == ptask->act) {
++ptask->placed;
}
} unit_list_iterate_end;
if (consider
UNIT_LOG(LOG_WORKER, punit,
"considering \x1b[94m%s\x1b[0m @ (%d, %d) %0d:%0d:%0d",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile),
ptask->wanted, ptask->enroute, ptask->placed);
if (ptask->act == ACTIVITY_CULTIVATE
&& tjungle != tile_terrain(ptask->ptile)) {
unreachable_new(unreachables, pcity, ptask);
UNIT_LOG(LOG_WORKER, punit,
"\x1b[33mculling activity\x1b[0m %s (%d, %d)",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
} else if (ptask->act == ACTIVITY_TRANSFORM
&& tdesert != tile_terrain(ptask->ptile)
&& tglacier != tile_terrain(ptask->ptile)
&& tswamp != tile_terrain(ptask->ptile)
&& ttundra != tile_terrain(ptask->ptile)) {
unreachable_new(unreachables, pcity, ptask);
UNIT_LOG(LOG_WORKER, punit,
"\x1b[33mculling activity\x1b[0m %s (%d, %d)",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
} else if (ptask->placed >= ptask->wanted) {
unreachable_new(unreachables, pcity, ptask);
UNIT_LOG(LOG_WORKER, punit,
"%s (%d, %d) \x1b[33msaturated\x1b[0m",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
} else if ( ptask->enroute < ptask->wanted
&& real_map_distance(ptask->ptile,
unit_tile(punit)) <= CITY_MAP_UBER_RADIUS_SQ
&& auto_workers_speculate_can_act_at(punit, ptask->act,
parameter.omniscience,
ptask->tgt, ptask->ptile)) {
/* Closest worker, if any, headed towards target tile */
struct unit *enroute = NULL;
if (state) {
enroute = player_unit_by_number(pplayer,
state[tile_index(ptask->ptile)].enroute);
}
if (pf_map_position(pfm, ptask->ptile, &pos)) {
int value = (ptask->want + 1) * 10 / (pos.turn + 1);
punit->goto_tile = ptask->ptile;
punit->worker_activity = ptask->act;
punit->worker_target = ptask->tgt;
++ptask->enroute;
UNIT_LOG(LOG_WORKER, punit, "planning \x1b[92m%s\x1b[0m (%d, %d)",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
break;
if (value > best_value) {
int eta = FC_INFINITY, inbound_distance = FC_INFINITY;
if (enroute) {
eta = state[tile_index(ptask->ptile)].eta;
inbound_distance = real_map_distance(ptask->ptile, unit_tile(enroute));
} else {
unreachable_new(unreachables, pcity, ptask);
UNIT_LOG(LOG_WORKER, punit,
"%s (%d, %d) \x1b[31mno map position\x1b[0m",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
}
/* Only consider this tile if we are closer in time and space to
* it than our other worker (if any) travelling to the site. */
if (pos.turn < dist
&& ((enroute && enroute->id == punit->id)
|| pos.turn < eta
|| (pos.turn == eta
&& (real_map_distance(ptask->ptile, unit_tile(punit))
< inbound_distance)))) {
dist = pos.turn;
best = ptask;
best_value = value;
taskcity = pcity;
}
}
} else {
unreachable_new(unreachables, pcity, ptask);
if ( ptask->enroute >= ptask->wanted ) {
UNIT_LOG(LOG_WORKER, punit,
"%s (%d, %d) \x1b[33mothers enroute\x1b[0m",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
} else {
UNIT_LOG(LOG_WORKER, punit,
"%s (%d, %d) \x1b[31mwork impossible\x1b[0m",
unit_activity_name(ptask->act), TILE_XY(ptask->ptile));
}
}
} worker_task_list_iterate_end;
struct unreachable *punreachable = nullptr;
while((punreachable = unreachable_list_front(unreachables)) != nullptr) {
CITY_LOG(LOG_WORKER, punreachable->pcity,
"\x1b[31mremoved unreachable\x1b[0m %s (%d, %d)",
unit_activity_name(punreachable->ptask->act),
TILE_XY(punreachable->ptask->ptile));
worker_task_destroy(punreachable->pcity->task_reqs,
punreachable->ptask);
unreachable_destroy(unreachables, punreachable);
}
unreachable_list_destroy(unreachables);
if (punit->worker_activity != ACTIVITY_IDLE) break;
} city_list_iterate_end;
city_list_destroy(unit_cities);
*best_task = best;
if (punit->worker_activity != ACTIVITY_IDLE) {
UNIT_LOG(LOG_WORKER, punit, " » %s", unit_activity_name(punit->worker_activity));
} else {
punit->ssa_controller = SSA_NONE;
unit_activity_handling(punit, ACTIVITY_IDLE, ACTION_NONE);
punit->goto_tile = nullptr;
punit->worker_activity = ACTIVITY_IDLE;
punit->worker_target = nullptr;
UNIT_LOG(LOG_WORKER, punit, "\x1b[33mIDLE·ING\x1b[0m");
}
if (ppath != NULL) {
if (*ppath != NULL) {
pf_path_destroy(*ppath);
}
*ppath = best ? pf_map_path(pfm, best->ptile) : NULL;
*ppath = (punit->worker_activity != ACTIVITY_IDLE)
? pf_map_path(pfm, punit->goto_tile) : NULL;
}
pf_map_destroy(pfm);
return taskcity;
}
/**********************************************************************//**
Find some work for our workers.
**************************************************************************/
#define LOG_WORKER LOG_DEBUG
void auto_worker_findwork(const struct civ_map *nmap,
struct player *pplayer,
struct unit *punit,
struct workermap *state,
int recursion)
{
struct worker_task *best_task;
... This diff was truncated because it exceeds the maximum size that can be displayed.
(2-2/3)