Feature #1791 » 1761.v2.patch
| 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(¶meter, 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(¶meter);
|
||
|
/* 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;
|
||