Feature #1399 ยป lua-superspecialists-edit.patch
common/scriptcore/api_game_methods.c | ||
---|---|---|
return specialist_plural_translation(s);
|
||
}
|
||
/**********************************************************************//**
|
||
Return if specialist is a superspecialist
|
||
**************************************************************************/
|
||
bool api_methods_specialist_is_super(lua_State *L, Specialist *s)
|
||
{
|
||
LUASCRIPT_CHECK_STATE(L, FALSE);
|
||
LUASCRIPT_CHECK_SELF(L, s, FALSE);
|
||
return is_super_specialist(s);
|
||
}
|
||
/**********************************************************************//**
|
||
Return the native x coordinate of the tile.
|
||
**************************************************************************/
|
common/scriptcore/api_game_methods.h | ||
---|---|---|
const char *api_methods_specialist_rule_name(lua_State *L, Specialist *s);
|
||
const char *api_methods_specialist_name_translation(lua_State *L,
|
||
Specialist *s);
|
||
bool api_methods_specialist_is_super(lua_State *L, Specialist *s);
|
||
/* Tile */
|
||
int api_methods_tile_nat_x(lua_State *L, Tile *ptile);
|
common/scriptcore/tolua_game.pkg | ||
---|---|---|
/* Module Specialist */
|
||
module Specialist {
|
||
module properties {
|
||
bool api_methods_specialist_is_super
|
||
@ is_super (lua_State *L, Specialist *s);
|
||
}
|
||
const char *api_methods_specialist_rule_name
|
||
@ rule_name (lua_State *L, Specialist *self);
|
||
const char *api_methods_specialist_name_translation
|
server/cityturn.c | ||
---|---|---|
Increase city size by one. We do not refresh borders or send info about
|
||
the city to the clients as part of this function. There might be several
|
||
calls to this function at once, and those actions are needed only once.
|
||
If s is not supplied, adds a specialist respecting the city preferences
|
||
**************************************************************************/
|
||
static bool city_increase_size(struct city *pcity)
|
||
static bool city_increase_size(struct city *pcity, Specialist_type_id sid)
|
||
{
|
||
int new_food;
|
||
int savings_pct = city_growth_granary_savings(pcity);
|
||
... | ... | |
}
|
||
pcity->food_stock = MIN(pcity->food_stock, new_food);
|
||
/* If there is enough food, and the city is big enough,
|
||
* make new citizens into scientists or taxmen -- Massimo */
|
||
if (sid >= 0) {
|
||
fc_assert_action(is_normal_specialist_id(sid), sid = DEFAULT_SPECIALIST);
|
||
pcity->specialists[sid]++;
|
||
} else {
|
||
/* If there is enough food, and the city is big enough,
|
||
* make new citizens into scientists or taxmen -- Massimo */
|
||
/* Ignore food if no square can be worked */
|
||
city_tile_iterate_skip_free_worked(nmap, city_map_radius_sq_get(pcity), pcenter,
|
||
ptile, _index, _x, _y) {
|
||
if (tile_worked(ptile) != pcity /* Quick test */
|
||
&& city_can_work_tile(pcity, ptile)) {
|
||
have_square = TRUE;
|
||
}
|
||
} city_tile_iterate_skip_free_worked_end;
|
||
/* Ignore food if no square can be worked */
|
||
city_tile_iterate_skip_free_worked(nmap, city_map_radius_sq_get(pcity), pcenter,
|
||
ptile, _index, _x, _y) {
|
||
if (tile_worked(ptile) != pcity /* Quick test */
|
||
&& city_can_work_tile(pcity, ptile)) {
|
||
have_square = TRUE;
|
||
if ((pcity->surplus[O_FOOD] >= 2 || !have_square)
|
||
&& is_city_option_set(pcity, CITYO_SCIENCE_SPECIALISTS)) {
|
||
pcity->specialists[best_specialist(O_SCIENCE, pcity)]++;
|
||
} else if ((pcity->surplus[O_FOOD] >= 2 || !have_square)
|
||
&& is_city_option_set(pcity, CITYO_GOLD_SPECIALISTS)) {
|
||
pcity->specialists[best_specialist(O_GOLD, pcity)]++;
|
||
} else {
|
||
pcity->specialists[DEFAULT_SPECIALIST]++; /* or else city is !sane */
|
||
}
|
||
} city_tile_iterate_skip_free_worked_end;
|
||
if ((pcity->surplus[O_FOOD] >= 2 || !have_square)
|
||
&& is_city_option_set(pcity, CITYO_SCIENCE_SPECIALISTS)) {
|
||
pcity->specialists[best_specialist(O_SCIENCE, pcity)]++;
|
||
} else if ((pcity->surplus[O_FOOD] >= 2 || !have_square)
|
||
&& is_city_option_set(pcity, CITYO_GOLD_SPECIALISTS)) {
|
||
pcity->specialists[best_specialist(O_GOLD, pcity)]++;
|
||
} else {
|
||
pcity->specialists[DEFAULT_SPECIALIST]++; /* or else city is !sane */
|
||
}
|
||
/* Deprecated signal. Connect your lua functions to "city_size_change" that's
|
||
... | ... | |
/**********************************************************************//**
|
||
Do the city refresh after its size has increased, by any amount.
|
||
Any added citizens detected during check belong to nationality.
|
||
aaw means that the workers in the city will be auto-arranged.
|
||
**************************************************************************/
|
||
static void city_refresh_after_city_size_increase(struct city *pcity,
|
||
struct player *nationality)
|
||
struct player *nationality,
|
||
bool aaw)
|
||
{
|
||
struct player *powner = city_owner(pcity);
|
||
... | ... | |
/* Refresh the city data; this also checks the squared city radius. */
|
||
city_refresh(pcity);
|
||
auto_arrange_workers(pcity);
|
||
if (aaw) {
|
||
auto_arrange_workers(pcity);
|
||
}
|
||
/* Update cities that have trade routes with us */
|
||
trade_partners_iterate(pcity, pcity2) {
|
||
... | ... | |
/**********************************************************************//**
|
||
Change the city size. Return TRUE iff the city is still alive afterwards.
|
||
If the size increases, the new citizens belong to nationality.
|
||
If sid is negative, tries to take best specialist according to city setting
|
||
but most times overwrites this selection in following auto-arrangement.
|
||
reason for signal ("script" or nullptr)
|
||
**************************************************************************/
|
||
bool city_change_size(struct city *pcity, citizens size,
|
||
struct player *nationality, const char *reason)
|
||
struct player *nationality,
|
||
Specialist_type_id sid, const char *reason)
|
||
{
|
||
int change = size - city_size_get(pcity);
|
||
... | ... | |
int id = pcity->id;
|
||
/* Increase city size until size reached, or increase fails */
|
||
while (size > current_size && city_increase_size(pcity)) {
|
||
while (size > current_size && city_increase_size(pcity, sid)) {
|
||
/* TODO: This is currently needed only because there's
|
||
* deprecated script signal "city_growth" emitted.
|
||
* Check the need after signal has been dropped completely. */
|
||
... | ... | |
current_size++;
|
||
}
|
||
city_refresh_after_city_size_increase(pcity, nationality);
|
||
city_refresh_after_city_size_increase(pcity, nationality, sid < 0);
|
||
real_change = current_size - old_size;
|
||
... | ... | |
} else {
|
||
bool success;
|
||
success = city_increase_size(pcity);
|
||
success = city_increase_size(pcity, -1);
|
||
map_claim_border(pcity->tile, pcity->owner, -1);
|
||
if (success) {
|
||
city_refresh_after_city_size_increase(pcity, nationality);
|
||
city_refresh_after_city_size_increase(pcity, nationality, TRUE);
|
||
script_server_signal_emit("city_size_change", pcity,
|
||
(lua_Integer)1, "growth");
|
||
}
|
||
... | ... | |
/* Increase size of receiver city */
|
||
if (city_exist(to_id)) {
|
||
bool incr_success = city_increase_size(pcity_to);
|
||
bool incr_success = city_increase_size(pcity_to, -1);
|
||
if (city_exist(to_id)) {
|
||
city_refresh_after_city_size_increase(pcity_to, pplayer_citizen);
|
||
city_refresh_after_city_size_increase(pcity_to, pplayer_citizen, TRUE);
|
||
city_refresh_vision(pcity_to);
|
||
if (city_refresh(pcity_to)) {
|
||
auto_arrange_workers(pcity_to);
|
server/cityturn.h | ||
---|---|---|
void auto_arrange_workers(struct city *pcity); /* Will arrange the workers */
|
||
void apply_cmresult_to_city(struct city *pcity, const struct cm_result *cmr);
|
||
bool city_change_size(struct city *pcity, citizens new_size,
|
||
struct player *nationality, const char *reason);
|
||
bool city_change_size(struct city *pcity, citizens size,
|
||
struct player *nationality,
|
||
Specialist_type_id sid, const char *reason);
|
||
bool city_reduce_size(struct city *pcity, citizens pop_loss,
|
||
struct player *destroyer, const char *reason);
|
||
void city_repair_size(struct city *pcity, int change);
|
server/edithand.c | ||
---|---|---|
if (size > 1) {
|
||
/* FIXME: Slow and inefficient for large size changes. */
|
||
city_change_size(pcity, CLIP(1, size, MAX_CITY_SIZE), pplayer, NULL);
|
||
city_change_size(pcity, CLIP(1, size, MAX_CITY_SIZE), pplayer,
|
||
-1, nullptr);
|
||
send_city_info(NULL, pcity);
|
||
}
|
||
... | ... | |
packet->size, city_link(pcity));
|
||
} else {
|
||
/* FIXME: Slow and inefficient for large size changes. */
|
||
city_change_size(pcity, packet->size, NULL, NULL);
|
||
city_change_size(pcity, packet->size, nullptr, -1, nullptr);
|
||
changed = TRUE;
|
||
}
|
||
}
|
server/scripting/api_server_edit.c | ||
---|---|---|
}
|
||
/**********************************************************************//**
|
||
Reduce specialists of given type s in a way like toggling in the client.
|
||
Reduce specialists of given type s. Superspecialists are just reduced,
|
||
normal specialists are toggled in a way like toggling in the client.
|
||
Does not place workers on map, just switches to another specialist.
|
||
Does nothing if there is less than amount specialists s in pcity.
|
||
Return if given number could be repurposed.
|
||
Return if given number could be removed/repurposed.
|
||
**************************************************************************/
|
||
bool api_edit_city_reduce_specialists(lua_State *L, City *pcity,
|
||
Specialist *s, int amount)
|
||
{
|
||
Specialist_type_id from, to;
|
||
Specialist_type_id from;
|
||
LUASCRIPT_CHECK_STATE(L, FALSE);
|
||
LUASCRIPT_CHECK_SELF(L, pcity, FALSE);
|
||
... | ... | |
if (pcity->specialists[from] < amount) {
|
||
return FALSE;
|
||
}
|
||
to = from;
|
||
do {
|
||
to = (to + 1) % specialist_count();
|
||
} while (to != from && !city_can_use_specialist(pcity, to));
|
||
if (to == from) {
|
||
/* We can use only the default specialist */
|
||
return FALSE;
|
||
} else {
|
||
/* City population must be correct */
|
||
fc_assert_ret_val_msg(pcity->specialists[to] <= MAX_CITY_SIZE - amount,
|
||
FALSE, "Wrong specialist number in %s",
|
||
city_name_get(pcity));
|
||
if (is_super_specialist_id(from)) {
|
||
/* Just reduce superspecialists */
|
||
pcity->specialists[from] -= amount;
|
||
pcity->specialists[to] += amount;
|
||
} else {
|
||
/* Toggle normal specialist */
|
||
Specialist_type_id to = from;
|
||
do {
|
||
to = (to + 1) % normal_specialist_count();
|
||
} while (to != from && !city_can_use_specialist(pcity, to));
|
||
if (to == from) {
|
||
/* We can use only the default specialist */
|
||
return FALSE;
|
||
} else {
|
||
/* City population must be correct */
|
||
fc_assert_ret_val_msg(pcity->specialists[to] <= amount - MAX_CITY_SIZE,
|
||
FALSE, "Wrong specialist number in %s",
|
||
city_name_get(pcity));
|
||
pcity->specialists[from] -= amount;
|
||
pcity->specialists[to] += amount;
|
||
}
|
||
}
|
||
city_refresh(pcity);
|
||
/* sanity_check_city(pcity); -- hopefully we don't break things here? */
|
||
send_city_info(city_owner(pcity), pcity);
|
||
return TRUE;
|
||
}
|
||
/**********************************************************************//**
|
||
Add amount specialists of given type s to pcity, return true iff done.
|
||
For normal specialists, also increases city size at amount.
|
||
Fails if either pcity does not fulfill s->reqs or it does not have
|
||
enough space for given specialists or citizens number.
|
||
**************************************************************************/
|
||
bool api_edit_city_add_specialist(lua_State *L, City *pcity,
|
||
Specialist *s, int amount)
|
||
{
|
||
Specialist_type_id sid;
|
||
int csize = 0;
|
||
LUASCRIPT_CHECK_STATE(L, FALSE);
|
||
LUASCRIPT_CHECK_SELF(L, pcity, FALSE);
|
||
LUASCRIPT_CHECK_ARG_NIL(L, s, 2, Specialist, FALSE);
|
||
LUASCRIPT_CHECK_ARG(L, amount >= 0, 3, "must be non-negative", FALSE);
|
||
sid = specialist_index(s);
|
||
if (!city_can_use_specialist(pcity, sid)) {
|
||
/* Can't employ this one */
|
||
return FALSE;
|
||
}
|
||
if (is_super_specialist(s)) {
|
||
if (pcity->specialists[sid] > MAX_CITY_SIZE - amount) {
|
||
/* No place for the specialist */
|
||
return FALSE;
|
||
}
|
||
pcity->specialists[sid] += amount;
|
||
city_refresh(pcity);
|
||
/* sanity_check_city(pcity); -- hopefully we don't break things here? */
|
||
send_city_info(city_owner(pcity), pcity);
|
||
} else {
|
||
csize = city_size_get(pcity);
|
||
return TRUE;
|
||
if (csize > MAX_CITY_SIZE - amount) {
|
||
/* No place for the specialist */
|
||
return FALSE;
|
||
}
|
||
city_change_size(pcity, csize + amount, city_owner(pcity), sid, "script");
|
||
city_refresh(pcity);
|
||
send_city_info(nullptr, pcity);
|
||
}
|
||
return TRUE;
|
||
}
|
||
/**********************************************************************//**
|
||
... | ... | |
nationality = city_owner(pcity);
|
||
}
|
||
city_change_size(pcity, city_size_get(pcity) + change, nationality, "script");
|
||
city_change_size(pcity, city_size_get(pcity) + change, nationality,
|
||
-1, "script");
|
||
}
|
||
/**********************************************************************//**
|
server/scripting/api_server_edit.h | ||
---|---|---|
void api_edit_remove_building(lua_State *L, City *pcity, Building_Type *impr);
|
||
bool api_edit_city_reduce_specialists(lua_State *L, City *pcity,
|
||
Specialist *s, int amount);
|
||
bool api_edit_city_add_specialist(lua_State *L, City *pcity,
|
||
Specialist *s, int amount);
|
||
Player *api_edit_create_player(lua_State *L, const char *username,
|
||
Nation_Type *pnation, const char *ai);
|
||
void api_edit_change_gold(lua_State *L, Player *pplayer, int amount);
|
server/scripting/tolua_server.pkg | ||
---|---|---|
bool api_edit_city_reduce_specialists
|
||
@ reduce_specialists (lua_State *L, City *pcity, Specialist *s,
|
||
int amount = 1);
|
||
bool api_edit_city_add_specialist
|
||
@ add_specialist (lua_State *L, City *pcity, Specialist *s,
|
||
int amount = 1);
|
||
void api_edit_create_owned_extra
|
||
@ create_owned_extra (lua_State *L, Tile *ptile,
|
||
const char *name, Player *pplayer);
|
||
... | ... | |
return edit.reduce_specialists(self, spec, amount or 1)
|
||
end
|
||
function City:add_specialist(spec, amount)
|
||
return edit.add_specialist(self, spec, amount or 1)
|
||
end
|
||
function City:change_size(change, nationality)
|
||
edit.change_city_size(self, change, nationality)
|
||
end
|
server/unithand.c | ||
---|---|---|
fc_assert_ret_val(pcity != NULL, FALSE);
|
||
city_change_size(pcity, size, nationality, NULL);
|
||
city_change_size(pcity, size, nationality, -1, nullptr);
|
||
}
|
||
/* May cause an incident even if the target tile is unclaimed. A ruleset
|