Feature #1375 » main-superspecialists-basic3.patch
| ai/default/daieffects.c | ||
|---|---|---|
|
{
|
||
|
int providers = 0;
|
||
|
specialist_type_iterate(i) {
|
||
|
normal_specialist_type_iterate(i) {
|
||
|
if (get_specialist_output(pcity, i, O_LUXURY) >= game.info.happy_cost) {
|
||
|
providers += pcity->specialists[i];
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return providers;
|
||
|
}
|
||
| ... | ... | |
|
case VUT_SPECIALIST:
|
||
|
if (preq->present) {
|
||
|
if (is_super_specialist(preq->source.value.specialist)
|
||
|
&& pcity->specialists[specialist_index(preq->source.value.specialist)] > 0) {
|
||
|
/* The superspecialist won't leave */
|
||
|
break;
|
||
|
}
|
||
|
requirement_vector_iterate(&(preq->source.value.specialist)->reqs,
|
||
|
sreq) {
|
||
|
if (!dai_can_requirement_be_met_in_city(sreq, pplayer, pcity)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
} requirement_vector_iterate_end;
|
||
|
} /* It is always possible to remove a specialist. */
|
||
|
break;
|
||
|
} /* Almost always there can be a specialist other than given one */
|
||
|
break;
|
||
|
case VUT_NATIONALITY:
|
||
|
/* Crude, but the right answer needs to consider civil wars. */
|
||
| ai/default/daimilitary.c | ||
|---|---|---|
|
}
|
||
|
if (!martial_need) {
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
if (pcity->specialists[sp] > 0
|
||
|
&& get_specialist_output(pcity, sp, O_LUXURY) > 0) {
|
||
|
martial_need = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
}
|
||
|
if (martial_need
|
||
| ai/default/daiunit.c | ||
|---|---|---|
|
int entertainers = 0;
|
||
|
bool enough = FALSE;
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
if (get_specialist_output(pcity, sp, O_LUXURY) > 0) {
|
||
|
entertainers += pcity->specialists[sp];
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
martless_unhappy += entertainers; /* We want to use martial law instead
|
||
|
* of entertainers. */
|
||
| client/agents/cma_core.c | ||
|---|---|---|
|
T(disorder);
|
||
|
T(happy);
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
T(specialists[sp]);
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
output_type_iterate(ot) {
|
||
|
T(surplus[ot]);
|
||
| ... | ... | |
|
} city_tile_iterate_skip_free_worked_end;
|
||
|
/* Change the excess non-default specialists to default. */
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
int i;
|
||
|
if (sp == DEFAULT_SPECIALIST) {
|
||
| ... | ... | |
|
first_request_id = last_request_id;
|
||
|
}
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
/* now all surplus people are DEFAULT_SPECIALIST */
|
||
| ... | ... | |
|
/* Set all specialists except DEFAULT_SPECIALIST (all the unchanged
|
||
|
* ones remain as DEFAULT_SPECIALIST). */
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
int i;
|
||
|
if (sp == DEFAULT_SPECIALIST) {
|
||
| ... | ... | |
|
first_request_id = last_request_id;
|
||
|
}
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
if (last_request_id == 0 || ALWAYS_APPLY_AT_SERVER) {
|
||
|
/*
|
||
| client/citydlg_common.c | ||
|---|---|---|
|
should be the happiness index from FEELING_BASE to FEELING_FINAL.
|
||
|
"categories" should be an array large enough to hold all citizens
|
||
|
(use MAX_CITY_SIZE to be on the safe side).
|
||
|
Note that superspecialists are not included. There can be theoretically
|
||
|
times more superspecialists working than MAX_CITY_SIZE.
|
||
|
Return number of categories filled (presumed equal to city size).
|
||
|
**************************************************************************/
|
||
|
int get_city_citizen_types(struct city *pcity, enum citizen_feeling idx,
|
||
| ... | ... | |
|
categories[i] = CITIZEN_ANGRY;
|
||
|
}
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
for (n = 0; n < pcity->specialists[sp]; n++, i++) {
|
||
|
categories[i] = CITIZEN_SPECIALIST + sp;
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
if (city_size_get(pcity) != i) {
|
||
|
log_error("get_city_citizen_types() %d citizens "
|
||
| ... | ... | |
|
return i;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Try to fill city superspecialists into categories[cat_len] array.
|
||
|
If succeeds, return how many are filled.
|
||
|
If there are too many of them, fill as many as fits
|
||
|
and return negative value.
|
||
|
**************************************************************************/
|
||
|
int city_try_fill_superspecialists(struct city *pcity, int cat_len,
|
||
|
enum citizen_category *categories)
|
||
|
{
|
||
|
int i = 0, n;
|
||
|
super_specialist_type_iterate(sp) {
|
||
|
for (n = 0; n < pcity->specialists[sp]; n++, i++) {
|
||
|
if (i >= cat_len) {
|
||
|
return -1;
|
||
|
}
|
||
|
categories[i] = CITIZEN_SPECIALIST + sp;
|
||
|
}
|
||
|
} super_specialist_type_iterate_end;
|
||
|
return i;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Rotate the given specialist citizen to the next type of citizen.
|
||
|
**************************************************************************/
|
||
| ... | ... | |
|
/* Loop through all specialists in order until we find a usable one
|
||
|
* (or run out of choices). */
|
||
|
to = from;
|
||
|
fc_assert(to >= 0 && to < specialist_count());
|
||
|
fc_assert(is_normal_specialist_id(to));
|
||
|
do {
|
||
|
to = (to + 1) % specialist_count();
|
||
|
to = (to + 1) % normal_specialist_count();
|
||
|
} while (to != from && !city_can_use_specialist(pcity, to));
|
||
|
if (from != to) {
|
||
| client/citydlg_common.h | ||
|---|---|---|
|
int get_city_citizen_types(struct city *pcity, enum citizen_feeling index,
|
||
|
enum citizen_category *categories);
|
||
|
int city_try_fill_superspecialists(struct city *pcity, int cat_len,
|
||
|
enum citizen_category *categories);
|
||
|
void city_rotate_specialist(struct city *pcity, int citizen_index);
|
||
|
void activate_all_units(struct tile *ptile);
|
||
| client/gui-gtk-3.22/citydlg.c | ||
|---|---|---|
|
int citizen_bar_width, citizen_bar_height;
|
||
|
struct city *pcity = pdialog->pcity;
|
||
|
int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
|
||
|
int num_supers
|
||
|
= city_try_fill_superspecialists(pcity,
|
||
|
ARRAY_SIZE(categories) - num_citizens,
|
||
|
&categories[num_citizens]);
|
||
|
cairo_t *cr;
|
||
|
if (num_supers >= 0) {
|
||
|
/* Just draw superspecialists in the common roster */
|
||
|
num_citizens += num_supers;
|
||
|
} else {
|
||
|
/* FIXME: show them in some compact way */
|
||
|
num_citizens = ARRAY_SIZE(categories);
|
||
|
}
|
||
|
/* If there is not enough space we stack the icons. We draw from left to */
|
||
|
/* right. width is how far we go to the right for each drawn pixmap. The */
|
||
|
/* last icon is always drawn in full, and so has reserved */
|
||
| ... | ... | |
|
struct city *pcity = pdialog->pcity;
|
||
|
int granaryturns;
|
||
|
int non_workers = city_specialists(pcity);
|
||
|
int supers = city_superspecialists(pcity);
|
||
|
/* fill the buffers with the necessary info */
|
||
|
if (non_workers) {
|
||
|
if (supers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d+%d)",
|
||
|
pcity->size, non_workers, supers);
|
||
|
} else if (non_workers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d)",
|
||
|
pcity->size, non_workers);
|
||
|
} else {
|
||
| client/gui-gtk-4.0/citydlg.c | ||
|---|---|---|
|
int citizen_bar_width, citizen_bar_height;
|
||
|
struct city *pcity = pdialog->pcity;
|
||
|
int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
|
||
|
int num_supers
|
||
|
= city_try_fill_superspecialists(pcity,
|
||
|
ARRAY_SIZE(categories) - num_citizens,
|
||
|
&categories[num_citizens]);
|
||
|
cairo_t *cr;
|
||
|
if (num_supers >= 0) {
|
||
|
/* Just draw superspecialists in the common roster */
|
||
|
num_citizens += num_supers;
|
||
|
} else {
|
||
|
/* FIXME: show them in some compact way */
|
||
|
num_citizens = ARRAY_SIZE(categories);
|
||
|
}
|
||
|
/* If there is not enough space we stack the icons. We draw from left to */
|
||
|
/* right. width is how far we go to the right for each drawn pixmap. The */
|
||
|
/* last icon is always drawn in full, and so has reserved */
|
||
| ... | ... | |
|
struct city *pcity = pdialog->pcity;
|
||
|
int granaryturns;
|
||
|
int non_workers = city_specialists(pcity);
|
||
|
int supers = city_superspecialists(pcity);
|
||
|
/* fill the buffers with the necessary info */
|
||
|
if (non_workers) {
|
||
|
if (supers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d+%d)",
|
||
|
pcity->size, non_workers, supers);
|
||
|
} else if (non_workers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d)",
|
||
|
pcity->size, non_workers);
|
||
|
} else {
|
||
| client/gui-gtk-5.0/citydlg.c | ||
|---|---|---|
|
int citizen_bar_width, citizen_bar_height;
|
||
|
struct city *pcity = pdialog->pcity;
|
||
|
int num_citizens = get_city_citizen_types(pcity, FEELING_FINAL, categories);
|
||
|
int num_supers
|
||
|
= city_try_fill_superspecialists(pcity,
|
||
|
ARRAY_SIZE(categories) - num_citizens,
|
||
|
&categories[num_citizens]);
|
||
|
cairo_t *cr;
|
||
|
if (num_supers >= 0) {
|
||
|
/* Just draw superspecialists in the common roster */
|
||
|
num_citizens += num_supers;
|
||
|
} else {
|
||
|
/* FIXME: show them in some compact way */
|
||
|
num_citizens = ARRAY_SIZE(categories);
|
||
|
}
|
||
|
/* If there is not enough space we stack the icons. We draw from left to */
|
||
|
/* right. width is how far we go to the right for each drawn pixmap. The */
|
||
|
/* last icon is always drawn in full, and so has reserved */
|
||
| ... | ... | |
|
struct city *pcity = pdialog->pcity;
|
||
|
int granaryturns;
|
||
|
int non_workers = city_specialists(pcity);
|
||
|
int supers = city_superspecialists(pcity);
|
||
|
/* fill the buffers with the necessary info */
|
||
|
if (non_workers) {
|
||
|
if (supers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d+%d)",
|
||
|
pcity->size, non_workers, supers);
|
||
|
} else if (non_workers) {
|
||
|
fc_snprintf(buf[INFO_SIZE], sizeof(buf[INFO_SIZE]), "%3d (%3d)",
|
||
|
pcity->size, non_workers);
|
||
|
} else {
|
||
| client/gui-qt/citydlg.cpp | ||
|---|---|---|
|
QPainter p;
|
||
|
QPixmap *pix;
|
||
|
int num_citizens = get_city_citizen_types(dlgcity, FEELING_FINAL, categories);
|
||
|
int num_supers
|
||
|
= city_try_fill_superspecialists(dlgcity,
|
||
|
ARRAY_SIZE(categories) - num_citizens,
|
||
|
&categories[num_citizens]);
|
||
|
int w = tileset_small_sprite_width(tileset) / gui()->map_scale;
|
||
|
int h = tileset_small_sprite_height(tileset) / gui()->map_scale;
|
||
|
if (num_supers >= 0) {
|
||
|
/* Just draw superspecialists in the common roster */
|
||
|
num_citizens += num_supers;
|
||
|
} else {
|
||
|
/* FIXME: show them in some compact way */
|
||
|
num_citizens = ARRAY_SIZE(categories);
|
||
|
}
|
||
|
i = 1 + (num_citizens * 5 / 200);
|
||
|
w = w / i;
|
||
|
QRect source_rect(0, 0, w, h);
|
||
| ... | ... | |
|
char buf_info[NUM_INFO_FIELDS][512];
|
||
|
char buf_tooltip[NUM_INFO_FIELDS][512];
|
||
|
int granaryturns;
|
||
|
int spec;
|
||
|
int spec, supers;
|
||
|
for (int i = 0; i < NUM_INFO_FIELDS; i++) {
|
||
|
buf_info[i][0] = '\0';
|
||
| ... | ... | |
|
// Fill the buffers with the necessary info
|
||
|
spec = city_specialists(dlgcity);
|
||
|
supers = city_superspecialists(dlgcity);
|
||
|
fc_snprintf(buf_info[INFO_CITIZEN], sizeof(buf_info[INFO_CITIZEN]),
|
||
|
"%3d (%4d)", dlgcity->size, spec);
|
||
|
fc_snprintf(buf_tooltip[INFO_CITIZEN], sizeof(buf_tooltip[INFO_CITIZEN]),
|
||
|
_("Population: %d, Specialists: %d"),
|
||
|
dlgcity->size, spec);
|
||
|
if (supers) {
|
||
|
fc_snprintf(buf_tooltip[INFO_CITIZEN], sizeof(buf_tooltip[INFO_CITIZEN]),
|
||
|
_("Population: %d, Specialists: %d + %d"),
|
||
|
dlgcity->size, spec, supers);
|
||
|
} else {
|
||
|
fc_snprintf(buf_tooltip[INFO_CITIZEN], sizeof(buf_tooltip[INFO_CITIZEN]),
|
||
|
_("Population: %d, Specialists: %d"),
|
||
|
dlgcity->size, spec);
|
||
|
}
|
||
|
fc_snprintf(buf_info[INFO_FOOD], sizeof(buf_info[INFO_FOOD]), "%3d (%+4d)",
|
||
|
dlgcity->prod[O_FOOD], dlgcity->surplus[O_FOOD]);
|
||
|
fc_snprintf(buf_info[INFO_SHIELD], sizeof(buf_info[INFO_SHIELD]),
|
||
| client/gui-sdl2/citydlg.c | ||
|---|---|---|
|
/* count != 0 */
|
||
|
/* ==================================================== */
|
||
|
/* Draw Citizens */
|
||
|
/* Draw Citizens and Superspecialists*/
|
||
|
count = (pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] + pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]
|
||
|
+ pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]
|
||
|
+ city_specialists(pcity));
|
||
|
+ city_specialists(pcity) + city_superspecialists(pcity));
|
||
|
/* FIXME: at great counts of superspecialists, the roster gets too crowded. */
|
||
|
/* Currently, we just truncate the roster. */
|
||
|
count = MAX(count, MAX_CITY_SIZE);
|
||
|
buf = get_citizen_surface(CITIZEN_HAPPY, 0);
|
||
|
if (count > 13) {
|
||
| ... | ... | |
|
pcity_dlg->spec_area.y = pwindow->dst->dest_rect.y + dest.y;
|
||
|
pcity_dlg->spec_area.w = count * step;
|
||
|
pcity_dlg->spec_area.h = buf->h;
|
||
|
limit = dest.x + pcity_dlg->spec_area.w - step; /* Max dest.x to draw */
|
||
|
if (pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]) {
|
||
|
for (i = 0; i < pcity->feel[CITIZEN_HAPPY][FEELING_FINAL]; i++) {
|
||
| ... | ... | |
|
buf = adj_surf(get_citizen_surface(CITIZEN_SPECIALIST + spe, i));
|
||
|
for (i = 0; i < pcity->specialists[spe]; i++) {
|
||
|
if (dest.x > limit) {
|
||
|
/* No place to draw the rest */
|
||
|
break;
|
||
|
}
|
||
|
alphablit(buf, NULL, pwindow->dst->surface, &dest, 255);
|
||
|
dest.x += step;
|
||
|
}
|
||
| client/gui-sdl3/citydlg.c | ||
|---|---|---|
|
/* count != 0 */
|
||
|
/* ==================================================== */
|
||
|
/* Draw Citizens */
|
||
|
/* Draw Citizens and Superspecialists*/
|
||
|
count = (pcity->feel[CITIZEN_HAPPY][FEELING_FINAL] + pcity->feel[CITIZEN_CONTENT][FEELING_FINAL]
|
||
|
+ pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] + pcity->feel[CITIZEN_ANGRY][FEELING_FINAL]
|
||
|
+ city_specialists(pcity));
|
||
|
+ city_specialists(pcity) + city_superspecialists(pcity));
|
||
|
buf = get_citizen_surface(CITIZEN_HAPPY, 0);
|
||
| client/helpdata.c | ||
|---|---|---|
|
cat_snprintf(buf, bufsz, "%s\n\n", _(text));
|
||
|
} strvec_iterate_end;
|
||
|
}
|
||
|
if (is_super_specialist(pspec)) {
|
||
|
cat_snprintf(buf, bufsz,
|
||
|
_("Superspecialist: is not counted within city population,"
|
||
|
"\ncan not be assigned to or from another occupation.\n"));
|
||
|
}
|
||
|
/* Requirements for this specialist. */
|
||
|
requirement_vector_iterate(&pspec->reqs, preq) {
|
||
| client/packhand.c | ||
|---|---|---|
|
}
|
||
|
specialist_type_iterate(sp) {
|
||
|
pcity->specialists[sp] = packet->specialists[sp];
|
||
|
city_size_add(pcity, pcity->specialists[sp]);
|
||
|
if (is_normal_specialist_id(sp)) {
|
||
|
city_size_add(pcity, pcity->specialists[sp]);
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
if (city_size_get(pcity) != packet->size) {
|
||
| common/aicore/cm.c | ||
|---|---|---|
|
fc_assert_ret(0 == soln->idle);
|
||
|
/* Clear all specialists, and remove all workers from fields (except
|
||
|
* the city center). */
|
||
|
memset(&pcity->specialists, 0, sizeof(pcity->specialists));
|
||
|
* the city center). Don't touch superspecialists. */
|
||
|
memset(&pcity->specialists, 0,
|
||
|
sizeof(pcity->specialists[0]) * normal_specialist_count());
|
||
|
city_map_iterate(city_radius_sq, cindex, x, y) {
|
||
|
if (is_free_worked_index(cindex)) {
|
||
| ... | ... | |
|
/* for each specialist type, create a tile_type that has as production
|
||
|
* the bonus for the specialist (if the city is allowed to use it) */
|
||
|
specialist_type_iterate(i) {
|
||
|
normal_specialist_type_iterate(i) {
|
||
|
if (city_can_use_specialist(pcity, i)) {
|
||
|
type.spec = i;
|
||
|
output_type_iterate(output) {
|
||
| ... | ... | |
|
tile_type_lattice_add(lattice, &type, 0);
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
}
|
||
|
/************************************************************************//**
|
||
| ... | ... | |
|
{
|
||
|
int count = 0;
|
||
|
specialist_type_iterate(spec) {
|
||
|
normal_specialist_type_iterate(spec) {
|
||
|
count += result->specialists[spec];
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return count;
|
||
|
}
|
||
| common/city.c | ||
|---|---|---|
|
}
|
||
|
/**********************************************************************//**
|
||
|
Give the number of specialists in a city.
|
||
|
Give the number of citizens who are specialists in a city.
|
||
|
Does not count superspecialists
|
||
|
**************************************************************************/
|
||
|
citizens city_specialists(const struct city *pcity)
|
||
|
{
|
||
|
citizens count = 0;
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
fc_assert_ret_val(MAX_CITY_SIZE - count > pcity->specialists[sp], 0);
|
||
|
count += pcity->specialists[sp];
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return count;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Give the number of superspecialists in a city
|
||
|
**************************************************************************/
|
||
|
int city_superspecialists(const struct city *pcity)
|
||
|
{
|
||
|
int count = 0;
|
||
|
super_specialist_type_iterate(sp) {
|
||
|
count += pcity->specialists[sp];
|
||
|
} super_specialist_type_iterate_end;
|
||
|
return count;
|
||
|
}
|
||
| ... | ... | |
|
int best = DEFAULT_SPECIALIST;
|
||
|
int val = get_specialist_output(pcity, best, otype);
|
||
|
specialist_type_iterate(i) {
|
||
|
normal_specialist_type_iterate(i) {
|
||
|
if (!pcity || city_can_use_specialist(pcity, i)) {
|
||
|
int val2 = get_specialist_output(pcity, i, otype);
|
||
| ... | ... | |
|
val = val2;
|
||
|
}
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return best;
|
||
|
}
|
||
| common/city.h | ||
|---|---|---|
|
void city_size_set(struct city *pcity, citizens size);
|
||
|
citizens city_specialists(const struct city *pcity);
|
||
|
int city_superspecialists(const struct city *pcity);
|
||
|
citizens player_content_citizens(const struct player *pplayer);
|
||
|
citizens player_angry_citizens(const struct player *pplayer);
|
||
| common/networking/packets.def | ||
|---|---|---|
|
UINT16 num_city_styles;
|
||
|
UINT16 terrain_count;
|
||
|
UINT16 num_specialist_types;
|
||
|
UINT16 num_normal_specialists;
|
||
|
UINT16 num_nation_groups;
|
||
|
UINT16 num_nation_sets;
|
||
| common/specialist.c | ||
|---|---|---|
|
return game.control.num_specialist_types;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Return the number of normal specialist_types.
|
||
|
**************************************************************************/
|
||
|
Specialist_type_id normal_specialist_count(void)
|
||
|
{
|
||
|
return game.control.num_normal_specialists;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Return the specialist index.
|
||
| ... | ... | |
|
return name_translation_get(&sp->abbreviation);
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
If this is a superspecialist: is not included into city population,
|
||
|
is not controlled by player.
|
||
|
**************************************************************************/
|
||
|
bool is_super_specialist_id(Specialist_type_id sp)
|
||
|
{
|
||
|
if (sp >= game.control.num_specialist_types) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
return sp >= game.control.num_normal_specialists;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
If this is a normal specialist: included into city population,
|
||
|
can be reassigned by player.
|
||
|
**************************************************************************/
|
||
|
bool is_normal_specialist_id(Specialist_type_id sp)
|
||
|
{
|
||
|
if (sp < 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
return sp < game.control.num_normal_specialists;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
If this is a superspecialist: is not included into city population,
|
||
|
is not controlled by player. Assumes a valid specialist pointer.
|
||
|
**************************************************************************/
|
||
|
bool is_super_specialist(const struct specialist *sp)
|
||
|
{
|
||
|
return is_super_specialist_id(specialist_index(sp));
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
If this is a normal specialist: included into city population,
|
||
|
can be reassigned by player. Assumes a valid specialist pointer.
|
||
|
**************************************************************************/
|
||
|
bool is_normal_specialist(const struct specialist *sp)
|
||
|
{
|
||
|
return is_normal_specialist_id(specialist_index(sp));
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Return a string containing all the specialist abbreviations, for instance
|
||
|
"E/S/T".
|
||
| common/specialist.h | ||
|---|---|---|
|
/* General specialist accessor functions. */
|
||
|
Specialist_type_id specialist_count(void);
|
||
|
Specialist_type_id normal_specialist_count(void);
|
||
|
Specialist_type_id specialist_index(const struct specialist *sp);
|
||
|
Specialist_type_id specialist_number(const struct specialist *sp);
|
||
| ... | ... | |
|
const char *specialist_plural_translation(const struct specialist *sp);
|
||
|
const char *specialist_abbreviation_translation(const struct specialist *sp);
|
||
|
bool is_super_specialist_id(Specialist_type_id sp);
|
||
|
bool is_normal_specialist_id(Specialist_type_id sp);
|
||
|
bool is_super_specialist(const struct specialist *sp);
|
||
|
bool is_normal_specialist(const struct specialist *sp);
|
||
|
/* Ancillary routines */
|
||
|
const char *specialists_abbreviation_string(void);
|
||
|
const char *specialists_string(const citizens *specialist_list);
|
||
| ... | ... | |
|
} \
|
||
|
}
|
||
|
#define normal_specialist_type_iterate(sp) \
|
||
|
{ \
|
||
|
Specialist_type_id sp; \
|
||
|
\
|
||
|
for (sp = 0; sp < normal_specialist_count(); sp++) {
|
||
|
#define normal_specialist_type_iterate_end \
|
||
|
} \
|
||
|
}
|
||
|
#define super_specialist_type_iterate(sp) \
|
||
|
{ \
|
||
|
Specialist_type_id sp; \
|
||
|
\
|
||
|
for (sp = normal_specialist_count(); sp < specialist_count(); sp++) {
|
||
|
#define super_specialist_type_iterate_end \
|
||
|
} \
|
||
|
}
|
||
|
#define specialist_type_re_active_iterate(_p) \
|
||
|
specialist_type_iterate(_p##_) { \
|
||
|
struct specialist *_p = specialist_by_number(_p##_); \
|
||
| server/cityhand.c | ||
|---|---|---|
|
return;
|
||
|
}
|
||
|
if (to < 0 || to >= specialist_count()
|
||
|
|| from < 0 || from >= specialist_count()
|
||
|
if (!is_normal_specialist_id(to)
|
||
|
|| !is_normal_specialist_id(from)
|
||
|
|| !city_can_use_specialist(pcity, to)
|
||
|
|| pcity->specialists[from] == 0) {
|
||
|
/* This could easily just be due to clicking faster on the specialist
|
||
| ... | ... | |
|
city_map_update_worker(pcity, ptile);
|
||
|
specialist_type_iterate(i) {
|
||
|
normal_specialist_type_iterate(i) {
|
||
|
if (pcity->specialists[i] > 0) {
|
||
|
pcity->specialists[i]--;
|
||
|
break;
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
city_refresh(pcity);
|
||
|
sanity_check_city(pcity);
|
||
| server/citytools.c | ||
|---|---|---|
|
bool dipl_invest)
|
||
|
{
|
||
|
int i;
|
||
|
int ppl = 0;
|
||
|
int ppl = 0; /* Counter of citizens for sanity check */
|
||
|
fc_assert(!pcity->server.needs_arrange);
|
||
| ... | ... | |
|
packet->specialists_size = specialist_count();
|
||
|
specialist_type_iterate(sp) {
|
||
|
packet->specialists[sp] = pcity->specialists[sp];
|
||
|
ppl += packet->specialists[sp];
|
||
|
if (is_normal_specialist_id(sp)) {
|
||
|
ppl += packet->specialists[sp];
|
||
|
}
|
||
|
} specialist_type_iterate_end;
|
||
|
/* The nationality of the citizens. */
|
||
| server/cityturn.c | ||
|---|---|---|
|
}
|
||
|
} city_tile_iterate_skip_free_worked_end;
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
pcity->specialists[sp] = cmr->specialists[sp];
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
| ... | ... | |
|
fc_assert_ret_val(0 < change, 0);
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
citizens fix = MIN(want, pcity->specialists[sp]);
|
||
|
pcity->specialists[sp] -= fix;
|
||
|
want -= fix;
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return change - want;
|
||
|
}
|
||
| server/ruleset/ruleload.c | ||
|---|---|---|
|
#define RESOURCE_SECTION_PREFIX "resource_"
|
||
|
#define GOODS_SECTION_PREFIX "goods_"
|
||
|
#define SPECIALIST_SECTION_PREFIX "specialist_"
|
||
|
#define SUPER_SPECIALIST_SECTION_PREFIX "super_specialist_"
|
||
|
#define TERRAIN_SECTION_PREFIX "terrain_"
|
||
|
#define UNIT_CLASS_SECTION_PREFIX "unitclass_"
|
||
|
#define UNIT_SECTION_PREFIX "unit_"
|
||
| ... | ... | |
|
const char *path,
|
||
|
struct veteran_system **vsystem, char *err,
|
||
|
size_t err_len);
|
||
|
static bool load_specialist(const struct section *psection,
|
||
|
struct specialist *s,
|
||
|
struct section_file *file);
|
||
|
char *script_buffer = NULL;
|
||
|
char *parser_buffer = NULL;
|
||
| ... | ... | |
|
filename));
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Load a single specialist or superspecialist section
|
||
|
**************************************************************************/
|
||
|
static bool load_specialist(const struct section *psection,
|
||
|
struct specialist *s,
|
||
|
struct section_file *file)
|
||
|
{
|
||
|
struct requirement_vector *reqs;
|
||
|
const char *sec_name = section_name(psection);
|
||
|
const char *item, *tag;
|
||
|
if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
item = secfile_lookup_str_default(file, untranslated_name(&s->name),
|
||
|
"%s.short_name", sec_name);
|
||
|
name_set(&s->abbreviation, NULL, item);
|
||
|
tag = secfile_lookup_str(file, "%s.graphic", sec_name);
|
||
|
if (tag == NULL) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": No graphic tag for specialist at %s.",
|
||
|
secfile_name(file), sec_name);
|
||
|
return FALSE;
|
||
|
}
|
||
|
sz_strlcpy(s->graphic_str, tag);
|
||
|
sz_strlcpy(s->graphic_alt,
|
||
|
secfile_lookup_str_default(file, "-",
|
||
|
"%s.graphic_alt", sec_name));
|
||
|
reqs = lookup_req_list(file, sec_name, "reqs", specialist_rule_name(s));
|
||
|
if (reqs == NULL) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
requirement_vector_copy(&s->reqs, reqs);
|
||
|
s->helptext = lookup_strvec(file, sec_name, "helptext");
|
||
|
return TRUE;
|
||
|
}
|
||
|
/**********************************************************************//**
|
||
|
Load cities.ruleset file
|
||
|
**************************************************************************/
|
||
| ... | ... | |
|
struct rscompat_info *compat)
|
||
|
{
|
||
|
const char *filename = secfile_name(file);
|
||
|
const char *item;
|
||
|
struct section_list *sec;
|
||
|
struct section_list *sec, *ssec;
|
||
|
int specs_count;
|
||
|
bool ok = TRUE;
|
||
|
int i = 0;
|
||
|
if (!rscompat_check_cap_and_version(file, filename, compat)) {
|
||
|
return FALSE;
|
||
| ... | ... | |
|
/* Specialist options */
|
||
|
sec = secfile_sections_by_name_prefix(file, SPECIALIST_SECTION_PREFIX);
|
||
|
if (section_list_size(sec) >= SP_MAX) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": Too many specialists (%d, max %d).",
|
||
|
filename, section_list_size(sec), SP_MAX);
|
||
|
if (!sec) {
|
||
|
ruleset_error(NULL, LOG_ERROR, "\"%s\": No specialists.", filename);
|
||
|
ok = FALSE;
|
||
|
} else {
|
||
|
specs_count = section_list_size(sec);
|
||
|
ssec = secfile_sections_by_name_prefix(file, SUPER_SPECIALIST_SECTION_PREFIX);
|
||
|
/* Superspecialists are optional */
|
||
|
if (ssec) {
|
||
|
specs_count += section_list_size(ssec);
|
||
|
}
|
||
|
if (specs_count >= SP_MAX) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": Too many specialists (%d, max %d).",
|
||
|
filename, specs_count, SP_MAX);
|
||
|
ok = FALSE;
|
||
|
}
|
||
|
}
|
||
|
if (ok) {
|
||
|
int i = 0;
|
||
|
const char *tag;
|
||
|
game.control.num_specialist_types = section_list_size(sec);
|
||
|
if (ok) {
|
||
|
game.control.num_specialist_types = specs_count;
|
||
|
section_list_iterate(sec, psection) {
|
||
|
struct specialist *s = specialist_by_number(i);
|
||
|
struct requirement_vector *reqs;
|
||
|
const char *sec_name = section_name(psection);
|
||
|
if (!ruleset_load_names(&s->name, NULL, file, sec_name)) {
|
||
|
ok = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
item = secfile_lookup_str_default(file, untranslated_name(&s->name),
|
||
|
"%s.short_name", sec_name);
|
||
|
name_set(&s->abbreviation, NULL, item);
|
||
|
tag = secfile_lookup_str(file, "%s.graphic", sec_name);
|
||
|
if (tag == NULL) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": No graphic tag for specialist at %s.",
|
||
|
filename, sec_name);
|
||
|
ok = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
sz_strlcpy(s->graphic_str, tag);
|
||
|
sz_strlcpy(s->graphic_alt,
|
||
|
secfile_lookup_str_default(file, "-",
|
||
|
"%s.graphic_alt", sec_name));
|
||
|
ok = load_specialist(psection, s, file);
|
||
|
reqs = lookup_req_list(file, sec_name, "reqs", specialist_rule_name(s));
|
||
|
if (reqs == NULL) {
|
||
|
ok = FALSE;
|
||
|
if (!ok) {
|
||
|
break;
|
||
|
}
|
||
|
requirement_vector_copy(&s->reqs, reqs);
|
||
|
s->helptext = lookup_strvec(file, sec_name, "helptext");
|
||
|
if (requirement_vector_size(&s->reqs) == 0 && DEFAULT_SPECIALIST == -1) {
|
||
|
DEFAULT_SPECIALIST = i;
|
||
| ... | ... | |
|
} section_list_iterate_end;
|
||
|
}
|
||
|
if (ok && DEFAULT_SPECIALIST == -1) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": must give a min_size of 0 for at least one "
|
||
|
"specialist type.", filename);
|
||
|
ok = FALSE;
|
||
|
if (ok){
|
||
|
if (DEFAULT_SPECIALIST == -1) {
|
||
|
ruleset_error(NULL, LOG_ERROR,
|
||
|
"\"%s\": must have zero reqs for at least one "
|
||
|
"specialist type.", filename);
|
||
|
ok = FALSE;
|
||
|
} else {
|
||
|
game.control.num_normal_specialists = i;
|
||
|
}
|
||
|
}
|
||
|
section_list_destroy(sec);
|
||
|
sec = NULL;
|
||
|
if (ssec) {
|
||
|
if (ok) {
|
||
|
section_list_iterate(ssec, psection) {
|
||
|
struct specialist *s = specialist_by_number(i);
|
||
|
ok = load_specialist(psection, s, file);
|
||
|
if (!ok) {
|
||
|
break;
|
||
|
}
|
||
|
i++;
|
||
|
} section_list_iterate_end;
|
||
|
}
|
||
|
section_list_destroy(ssec);
|
||
|
ssec = NULL;
|
||
|
}
|
||
|
if (ok) {
|
||
|
/* City Parameters */
|
||
| server/savegame/savegame3.c | ||
|---|---|---|
|
city_size_set(pcity, size);
|
||
|
for (i = 0; i < loading->specialist.size; i++) {
|
||
|
Specialist_type_id si = specialist_index(loading->specialist.order[i]);
|
||
|
sg_warn_ret_val(secfile_lookup_int(loading->file, &value, "%s.nspe%d",
|
||
|
citystr, i),
|
||
|
FALSE, "%s", secfile_error());
|
||
|
pcity->specialists[specialist_index(loading->specialist.order[i])]
|
||
|
= (citizens)value;
|
||
|
sp_count += value;
|
||
|
pcity->specialists[si] = (citizens)value;
|
||
|
if (is_normal_specialist_id(si)) {
|
||
|
sp_count += value;
|
||
|
}
|
||
|
}
|
||
|
partner = secfile_lookup_int_default(loading->file, 0, "%s.traderoute0", citystr);
|
||
| server/score.c | ||
|---|---|---|
|
+ pplayer->score.unhappy
|
||
|
+ pplayer->score.angry);
|
||
|
specialist_type_iterate(sp) {
|
||
|
normal_specialist_type_iterate(sp) {
|
||
|
count += pplayer->score.specialists[sp];
|
||
|
} specialist_type_iterate_end;
|
||
|
} normal_specialist_type_iterate_end;
|
||
|
return count;
|
||
|
}
|
||
| tools/ruleutil/rulesave.c | ||
|---|---|---|
|
struct specialist *s = specialist_by_number(sp);
|
||
|
char path[512];
|
||
|
fc_snprintf(path, sizeof(path), "specialist_%d", sect_idx++);
|
||
|
fc_snprintf(path, sizeof(path),
|
||
|
is_super_specialist_id(sp)
|
||
|
? "super_specialist_%d" : "specialist_%d", sect_idx++);
|
||
|
save_name_translation(sfile, &(s->name), path);
|
||