Project

General

Profile

Feature #1546 » 3_4-specialist_unit1.patch

Alexandr Ignatiev, 06/29/2025 07:26 PM

View differences:

client/helpdata.c
" %s initial population: %d.\n",
utype->city_size),
BULLET, utype->city_size);
if (is_super_specialist(utype->spec_type)) {
cat_snprintf(buf, bufsz,
/* FIXME: Here we'd better have a singular specialist
* but the translated name is plural by definition. */
/* TRANS: * ... Great Artist(s) ... */
_(" %s the city starts with a %s superspecialist.\n"),
BULLET, specialist_plural_translation(utype->spec_type));
}
break;
case ACTRES_JOIN_CITY:
cat_snprintf(buf, bufsz,
/* TRANS: the %d is population. */
PL_(" %s max target size: %d.\n",
" %s max target size: %d.\n",
game.info.add_to_size_limit - utype->pop_cost),
BULLET, game.info.add_to_size_limit - utype->pop_cost);
cat_snprintf(buf, bufsz,
/* TRANS: the %d is the population added. */
PL_(" %s adds %d population.\n",
" %s adds %d population.\n",
utype->pop_cost),
BULLET, utype->pop_cost);
if (utype->pop_cost > 0 ){
cat_snprintf(buf, bufsz,
/* TRANS: the %d is population. */
PL_(" %s max target size: %d.\n",
" %s max target size: %d.\n",
game.info.add_to_size_limit - utype->pop_cost),
BULLET, game.info.add_to_size_limit - utype->pop_cost);
cat_snprintf(buf, bufsz,
/* TRANS: the %d is the population added. */
PL_(" %s adds %d population.\n",
" %s adds %d population.\n",
utype->pop_cost),
BULLET, utype->pop_cost);
}
if (is_super_specialist(utype->spec_type)) {
cat_snprintf(buf, bufsz,
/* FIXME: Here we'd better have a singular specialist
* but the translated name is plural by definition. */
/* TRANS: * ... Great Artist(s) ... */
_(" %s adds a %s superspecialist to the city.\n"),
BULLET, specialist_plural_translation(utype->spec_type));
} else if (DEFAULT_SPECIALIST != specialist_index(utype->spec_type)) {
cat_snprintf(buf, bufsz,
/* TRANS: * ... Scientists */
_(" %s adds to cities as %s.\n"),
BULLET, specialist_plural_translation(utype->spec_type));
}
break;
case ACTRES_BOMBARD:
cat_snprintf(buf, bufsz,
client/packhand.c
u->uclass = uclass_by_number(p->unit_class_id);
u->build_cost = p->build_cost;
u->pop_cost = p->pop_cost;
u->spec_type = specialist_by_number(p->spectype_id);
u->attack_strength = p->attack_strength;
u->defense_strength = p->defense_strength;
u->move_rate = p->move_rate;
common/actions.c
#include "oblig_reqs.h"
#include "research.h"
#include "server_settings.h"
#include "specialist.h"
#include "unit.h"
......
{
switch (paction->result) {
case ACTRES_JOIN_CITY:
if (actor_unittype->pop_cost <= 0) {
/* Reason: Must have population to add. */
if (actor_unittype->pop_cost <= 0 && !is_super_specialist(actor_unittype->spec_type)) {
/* Reason: Must have something to add. */
return FALSE;
}
break;
common/actres.c
#include "movement.h"
#include "player.h"
#include "requirements.h"
#include "specialist.h"
#include "tile.h"
#include "traderoutes.h"
......
case ACTRES_JOIN_CITY:
{
int new_pop;
Specialist_type_id sid;
if (!omniscient
&& !player_can_see_city_externals(actor->player, target->city)) {
......
* VisibleByOthers. */
return TRI_NO;
}
sid = specialist_index(unit_type_get(actor->unit)->spec_type);
if (DEFAULT_SPECIALIST != sid) {
if (!city_can_use_specialist(target->city, sid)) {
/* Respect specialist reqs */
/* Potential info leak about if they are fulfilled */
return TRI_NO;
}
if (is_super_specialist_id(sid)
&& target->city->specialists[sid] >= MAX_CITY_SIZE) {
/* No place to add a superspecialist */
/* Info leak on city superspecialists but it happens too rarely */
return TRI_NO;
}
}
}
break;
common/networking/packets.def
UINT8 unit_class_id;
UINT16 build_cost;
UINT8 pop_cost;
UINT8 spectype_id;
UINT8 attack_strength;
UINT8 defense_strength;
MOVEFRAGS move_rate;
common/unittype.h
int build_cost; /* Use wrappers to access this. */
int pop_cost; /* Number of workers the unit contains
* (e.g., settlers, engineers) */
struct specialist *spec_type; /* affects only founding and adding to cities */
int attack_strength;
int defense_strength;
int move_rate;
data/alien/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/civ1/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/civ2/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/civ2civ3/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/classic/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/goldkeep/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/granularity/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/multiplayer/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/ruledit/comments-3.4.txt
; build_cost = production shields required to build\n\
; pop_cost = population removed from city when built; for \'Join City\'\n\
; units this is also the population added to the destination\n\
; specialist = optional: add a superspecialist of this type when joining to\n\
; or creating a city (if normal specialist: join as this type)\n\
; attack = base attack strength (0 = cannot attack)\n\
; defense = base defense strength (0 = cannot defend)\n\
; hitpoints = how much damage unit can withstand\n\
data/sandbox/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/stub/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
data/webperimental/units.ruleset
; build_cost = production shields required to build
; pop_cost = population removed from city when built; for 'Join City'
; units this is also the population added to the destination
; specialist = optional: add a superspecialist of this type when joining to
; or creating a city (if normal specialist: join as this type)
; attack = base attack strength (0 = cannot attack)
; defense = base defense strength (0 = cannot defend)
; hitpoints = how much damage unit can withstand
server/ruleset/ruleload.c
"%s.city_slots", sec_name);
u->city_size = secfile_lookup_int_default(file, 1,
"%s.city_size", sec_name);
if ((sval
= secfile_lookup_str_default(file, nullptr, "%s.specialist", sec_name))) {
if (!(u->spec_type = specialist_by_rule_name(sval))) {
ruleset_error(nullptr, LOG_ERROR,
"\"%s\" unit_type \"%s\":"
" bad specialist \"%s\".",
filename, utype_rule_name(u), sval);
ok = FALSE;
}
} else {
/* Specialists must have been processed before */
fc_assert_action(DEFAULT_SPECIALIST >= 0
&& specialist_by_number(DEFAULT_SPECIALIST),
ok = FALSE; break);
u->spec_type = specialist_by_number(DEFAULT_SPECIALIST);
}
sval = secfile_lookup_str_default(file, transp_def_type_name(TDT_ALIGHT),
"%s.tp_defense", sec_name);
......
packet.unit_class_id = uclass_number(utype_class(u));
packet.build_cost = u->build_cost;
packet.pop_cost = u->pop_cost;
packet.spectype_id = specialist_index(u->spec_type);
packet.attack_strength = u->attack_strength;
packet.defense_strength = u->defense_strength;
packet.move_rate = u->move_rate;
server/unithand.c
city_size_get(target_city)
+ unit_pop_value(punit))))) {
explnat->kind = ANEK_CITY_POP_LIMIT;
} else if (target_city
&& (action_has_result_safe(paction, ACTRES_JOIN_CITY)
&& action_actor_utype_hard_reqs_ok(paction,
unit_type_get(punit))
&& is_super_specialist(unit_type_get(punit)->spec_type)
&& MAX_CITY_SIZE
<= target_city->specialists
[specialist_index(unit_type_get(punit)->spec_type)])) {
explnat->kind = ANEK_CITY_NO_CAPACITY;
} else if ((action_has_result_safe(paction, ACTRES_NUKE_UNITS)
|| action_has_result_safe(paction, ACTRES_ATTACK)
|| action_has_result_safe(paction, ACTRES_WIPE_UNITS))
......
{
int amount = unit_pop_value(punit);
const struct unit_type *act_utype;
Specialist_type_id spec_id = DEFAULT_SPECIALIST;
/* Sanity check: The actor is still alive. */
fc_assert_ret_val(punit, FALSE);
......
/* Sanity check: The target city still exists. */
fc_assert_ret_val(pcity, FALSE);
fc_assert_ret_val(amount > 0, FALSE);
city_size_add(pcity, amount);
if (is_super_specialist(act_utype->spec_type)) {
Specialist_type_id sspec = specialist_index(act_utype->spec_type);
fc_assert_ret_val(pcity->specialists[sspec] < MAX_CITY_SIZE, FALSE);
pcity->specialists[sspec]++;
} else {
fc_assert_ret_val(amount > 0, FALSE);
/* Hardly much needed but let it be */
spec_id = specialist_index(act_utype->spec_type);
}
/* Make the new people something, otherwise city fails the checks */
pcity->specialists[DEFAULT_SPECIALIST] += amount;
fc_assert_ret_val(MAX_CITY_SIZE - pcity->specialists[spec_id] >= amount,
FALSE);
pcity->specialists[spec_id] += amount;
citizens_update(pcity, unit_nationality(punit));
/* Refresh the city data. */
city_refresh(pcity);
......
struct player *nationality;
struct player *towner;
const struct unit_type *act_utype;
Specialist_type_id sid;
struct city *pcity;
/* Sanity check: The actor still exists. */
fc_assert_ret_val(pplayer, FALSE);
......
}
act_utype = unit_type_get(punit);
sid = specialist_index(act_utype->spec_type);
nationality = unit_nationality(punit);
create_city(pplayer, ptile, name, nationality);
size = unit_type_get(punit)->city_size;
if (size > 1) {
struct city *pcity = tile_city(ptile);
fc_assert_ret_val(pcity != NULL, FALSE);
city_change_size(pcity, size, nationality, -1, nullptr);
size = act_utype->city_size;
pcity = tile_city(ptile); /* A callback may destroy or replace it any time */
if (nullptr != pcity) {
if (is_super_specialist_id(sid) && pcity->specialists[sid] < MAX_CITY_SIZE) {
pcity->specialists[sid]++;
}
if (size > 1) {
city_change_size(pcity, size, nationality, -1, nullptr);
}
}
/* May cause an incident even if the target tile is unclaimed. A ruleset
tools/ruleutil/rulesave.c
secfile_insert_int(sfile, put->build_cost, "%s.build_cost", path);
secfile_insert_int(sfile, put->pop_cost, "%s.pop_cost", path);
if (DEFAULT_SPECIALIST < 0 || DEFAULT_SPECIALIST != specialist_index(put->spec_type)) {
secfile_insert_str(sfile, specialist_rule_name(put->spec_type),
"%s.specialist", path);
}
secfile_insert_int(sfile, put->attack_strength, "%s.attack", path);
secfile_insert_int(sfile, put->defense_strength, "%s.defense", path);
secfile_insert_int(sfile, put->move_rate / SINGLE_MOVE, "%s.move_rate", path);
(3-3/3)