remove stealing from economy.c (that file is too big).

This commit is contained in:
Enno Rehling 2017-12-04 20:01:08 +01:00
parent 05425b5101
commit 3864a00482
5 changed files with 315 additions and 255 deletions

View File

@ -109,6 +109,7 @@ set (ERESSEA_SRC
json.c json.c
creport.c creport.c
report.c report.c
steal.c
economy.c economy.c
give.c give.c
items.c items.c

View File

@ -83,12 +83,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
static int working; static int working;
static production entertainers[1024]; static econ_request entertainers[1024];
static production *nextentertainer; static econ_request *nextentertainer;
static int entertaining; static int entertaining;
static unsigned int norders; static unsigned int norders;
static production *g_requests; static econ_request *g_requests;
#define RECRUIT_MERGE 1 #define RECRUIT_MERGE 1
static int rules_recruit = -1; static int rules_recruit = -1;
@ -141,10 +141,11 @@ static void scramble(void *data, unsigned int n, size_t width)
} }
} }
static void expandorders(region * r, production * requests) unsigned int expand_production(region * r, econ_request * requests, econ_request **results)
{ {
unit *u; unit *u;
production *o; econ_request *o;
unsigned int norders = 0;
/* Alle Units ohne production haben ein -1, alle units mit orders haben ein /* Alle Units ohne production haben ein -1, alle units mit orders haben ein
* 0 hier stehen */ * 0 hier stehen */
@ -152,8 +153,6 @@ static void expandorders(region * r, production * requests)
for (u = r->units; u; u = u->next) for (u = r->units; u; u = u->next)
u->n = -1; u->n = -1;
norders = 0;
for (o = requests; o; o = o->next) { for (o = requests; o; o = o->next) {
if (o->qty > 0) { if (o->qty > 0) {
norders += o->qty; norders += o->qty;
@ -162,28 +161,35 @@ static void expandorders(region * r, production * requests)
if (norders > 0) { if (norders > 0) {
int i = 0; int i = 0;
g_requests = (production *)calloc(norders, sizeof(production)); econ_request *split;
split = (econ_request *)calloc(norders, sizeof(econ_request));
for (o = requests; o; o = o->next) { for (o = requests; o; o = o->next) {
if (o->qty > 0) { if (o->qty > 0) {
unsigned int j; unsigned int j;
for (j = o->qty; j; j--) { for (j = o->qty; j; j--) {
g_requests[i] = *o; split[i] = *o;
g_requests[i].unit->n = 0; split[i].unit->n = 0;
i++; i++;
} }
} }
} }
scramble(g_requests, norders, sizeof(production)); scramble(split, norders, sizeof(econ_request));
*results = split;
} }
else { else {
g_requests = NULL; *results = NULL;
} }
while (requests) { while (requests) {
production *o = requests->next; econ_request *o = requests->next;
free_order(requests->ord); free_order(requests->ord);
free(requests); free(requests);
requests = o; requests = o;
} }
return norders;
}
static void expandorders(region * r, econ_request * requests) {
norders = expand_production(r, requests, &g_requests);
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
@ -191,21 +197,21 @@ static void expandorders(region * r, production * requests)
typedef struct recruitment { typedef struct recruitment {
struct recruitment *next; struct recruitment *next;
faction *f; faction *f;
production *requests; econ_request *requests;
int total, assigned; int total, assigned;
} recruitment; } recruitment;
/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable production /** Creates a list of recruitment structs, one for each faction. Adds every quantifyable production
* to the faction's struct and to total. * to the faction's struct and to total.
*/ */
static recruitment *select_recruitment(production ** rop, static recruitment *select_recruitment(econ_request ** rop,
int(*quantify) (const struct race *, int), int *total) int(*quantify) (const struct race *, int), int *total)
{ {
recruitment *recruits = NULL; recruitment *recruits = NULL;
while (*rop) { while (*rop) {
recruitment *rec = recruits; recruitment *rec = recruits;
production *ro = *rop; econ_request *ro = *rop;
unit *u = ro->unit; unit *u = ro->unit;
const race *rc = u_race(u); const race *rc = u_race(u);
int qty = quantify(rc, ro->qty); int qty = quantify(rc, ro->qty);
@ -318,7 +324,7 @@ static int do_recruiting(recruitment * recruits, int available)
/* do actual recruiting */ /* do actual recruiting */
for (rec = recruits; rec != NULL; rec = rec->next) { for (rec = recruits; rec != NULL; rec = rec->next) {
production *req; econ_request *req;
int get = rec->assigned; int get = rec->assigned;
for (req = rec->requests; req; req = req->next) { for (req = rec->requests; req; req = req->next) {
@ -367,7 +373,7 @@ void free_recruitments(recruitment * recruits)
recruitment *rec = recruits; recruitment *rec = recruits;
recruits = rec->next; recruits = rec->next;
while (rec->requests) { while (rec->requests) {
production *req = rec->requests; econ_request *req = rec->requests;
rec->requests = req->next; rec->requests = req->next;
free_order(req->ord); free_order(req->ord);
free(req); free(req);
@ -377,7 +383,7 @@ void free_recruitments(recruitment * recruits)
} }
/* Rekrutierung */ /* Rekrutierung */
static void expandrecruit(region * r, production * recruitorders) static void expandrecruit(region * r, econ_request * recruitorders)
{ {
recruitment *recruits = NULL; recruitment *recruits = NULL;
@ -418,11 +424,11 @@ static int recruit_cost(const faction * f, const race * rc)
return -1; return -1;
} }
static void recruit(unit * u, struct order *ord, production ** recruitorders) static void recruit(unit * u, struct order *ord, econ_request ** recruitorders)
{ {
region *r = u->region; region *r = u->region;
plane *pl; plane *pl;
production *o; econ_request *o;
int recruitcost = -1; int recruitcost = -1;
const faction *f = u->faction; const faction *f = u->faction;
const struct race *rc = u_race(u); const struct race *rc = u_race(u);
@ -543,7 +549,7 @@ static void recruit(unit * u, struct order *ord, production ** recruitorders)
return; return;
} }
o = (production *)calloc(1, sizeof(production)); o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = n; o->qty = n;
o->unit = u; o->unit = u;
o->ord = copy_order(ord); o->ord = copy_order(ord);
@ -739,7 +745,7 @@ void maintain_buildings(region * r)
void economics(region * r) void economics(region * r)
{ {
unit *u; unit *u;
production *recruitorders = NULL; econ_request *recruitorders = NULL;
/* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle. /* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle.
* Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern * Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern
@ -1429,7 +1435,7 @@ const attrib_type at_luxuries = {
"luxuries", NULL, free_luxuries, NULL, NULL, NULL "luxuries", NULL, free_luxuries, NULL, NULL, NULL
}; };
static void expandbuying(region * r, production * buyorders) static void expandbuying(region * r, econ_request * buyorders)
{ {
const resource_type *rsilver = get_resourcetype(R_SILVER); const resource_type *rsilver = get_resourcetype(R_SILVER);
int max_products; int max_products;
@ -1542,12 +1548,12 @@ attrib_type at_trades = {
NO_READ NO_READ
}; };
static void buy(unit * u, production ** buyorders, struct order *ord) static void buy(unit * u, econ_request ** buyorders, struct order *ord)
{ {
char token[128]; char token[128];
region *r = u->region; region *r = u->region;
int n, k; int n, k;
production *o; econ_request *o;
attrib *a; attrib *a;
const item_type *itype = NULL; const item_type *itype = NULL;
const luxury_type *ltype = NULL; const luxury_type *ltype = NULL;
@ -1638,7 +1644,7 @@ static void buy(unit * u, production ** buyorders, struct order *ord)
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", "")); ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "luxury_notsold", ""));
return; return;
} }
o = (production *)calloc(1, sizeof(production)); o = (econ_request *)calloc(1, sizeof(econ_request));
o->type.ltype = ltype; /* sollte immer gleich sein */ o->type.ltype = ltype; /* sollte immer gleich sein */
o->unit = u; o->unit = u;
@ -1647,18 +1653,18 @@ static void buy(unit * u, production ** buyorders, struct order *ord)
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
static void add_income(unit * u, int type, int want, int qty) void add_income(unit * u, income_t type, int want, int qty)
{ {
if (want == INT_MAX) if (want == INT_MAX)
want = qty; want = qty;
ADDMSG(&u->faction->msgs, msg_message("income", ADDMSG(&u->faction->msgs, msg_message("income",
"unit region mode wanted amount", u, u->region, type, want, qty)); "unit region mode wanted amount", u, u->region, (int)type, want, qty));
} }
/* Steuers<72>tze in % bei Burggr<67><72>e */ /* Steuers<72>tze in % bei Burggr<67><72>e */
static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 }; static int tax_per_size[7] = { 0, 6, 12, 18, 24, 30, 36 };
static void expandselling(region * r, production * sellorders, int limit) static void expandselling(region * r, econ_request * sellorders, int limit)
{ {
int money, price, max_products; int money, price, max_products;
unsigned int j; unsigned int j;
@ -1847,7 +1853,7 @@ static void expandselling(region * r, production * sellorders, int limit)
} }
} }
static bool sell(unit * u, production ** sellorders, struct order *ord) static bool sell(unit * u, econ_request ** sellorders, struct order *ord)
{ {
char token[128]; char token[128];
bool unlimited = true; bool unlimited = true;
@ -1940,7 +1946,7 @@ static bool sell(unit * u, production ** sellorders, struct order *ord)
} }
else { else {
attrib *a; attrib *a;
production *o; econ_request *o;
int k, available; int k, available;
if (!r_demand(r, ltype)) { if (!r_demand(r, ltype)) {
@ -1988,7 +1994,7 @@ static bool sell(unit * u, production ** sellorders, struct order *ord)
assert(n >= 0); assert(n >= 0);
/* die Menge der verkauften G<>ter merken */ /* die Menge der verkauften G<>ter merken */
a->data.i += n; a->data.i += n;
o = (production *)calloc(1, sizeof(production)); o = (econ_request *)calloc(1, sizeof(econ_request));
o->unit = u; o->unit = u;
o->qty = n; o->qty = n;
o->type.ltype = ltype; o->type.ltype = ltype;
@ -1998,48 +2004,6 @@ static bool sell(unit * u, production ** sellorders, struct order *ord)
} }
} }
/* ------------------------------------------------------------- */
static void expandstealing(region * r, production * stealorders)
{
const resource_type *rsilver = get_resourcetype(R_SILVER);
unsigned int j;
assert(rsilver);
expandorders(r, stealorders);
if (!norders) return;
/* F<>r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
* Beklauen-Orders ist. Jedes Opfer mu<EFBFBD> einzeln behandelt werden.
*
* u ist die beklaute unit. oa.unit ist die klauende unit.
*/
for (j = 0; j != norders && g_requests[j].unit->n <= g_requests[j].unit->wants; j++) {
unit *u = findunitg(g_requests[j].no, r);
int n = 0;
if (u && u->region == r) {
n = get_pooled(u, rsilver, GET_ALL, INT_MAX);
}
if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) {
/* In Questen nur reduziertes Klauen */
n = 10;
}
if (n > 0) {
n = MIN(n, g_requests[j].unit->wants);
use_pooled(u, rsilver, GET_ALL, n);
g_requests[j].unit->n = n;
change_money(g_requests[j].unit, n);
ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount",
u, u->region, n));
}
add_income(g_requests[j].unit, IC_STEAL, g_requests[j].unit->wants, g_requests[j].unit->n);
fset(g_requests[j].unit, UFL_LONGACTION | UFL_NOTMOVING);
}
free(g_requests);
}
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
static void plant(unit * u, int raw) static void plant(unit * u, int raw)
{ {
@ -2359,162 +2323,11 @@ static void research_cmd(unit * u, struct order *ord)
} }
} }
static int max_skill(region * r, faction * f, skill_t sk)
{
unit *u;
int w = 0;
for (u = r->units; u; u = u->next) {
if (u->faction == f) {
int effsk = effskill(u, sk, 0);
if (effsk > w) {
w = effsk;
}
}
}
return w;
}
message * check_steal(const unit * u, struct order *ord) {
plane *pl;
if (fval(u_race(u), RCF_NOSTEAL)) {
return msg_feedback(u, ord, "race_nosteal", "race", u_race(u));
}
if (fval(u->region->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) {
return msg_feedback(u, ord, "error_onlandonly", "");
}
pl = rplane(u->region);
if (pl && fval(pl, PFL_NOATTACK)) {
return msg_feedback(u, ord, "error270", "");
}
return 0;
}
static void steal_cmd(unit * u, struct order *ord, production ** stealorders)
{
const resource_type *rring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
int n, i, id, effsk;
bool goblin = false;
production *o;
unit *u2 = NULL;
region *r = u->region;
faction *f = NULL;
message * msg;
keyword_t kwd;
kwd = init_order_depr(ord);
assert(kwd == K_STEAL);
assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH));
msg = check_steal(u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
return;
}
id = read_unitid(u->faction, r);
if (id > 0) {
u2 = findunitr(r, id);
}
if (u2 && u2->region == u->region) {
f = u2->faction;
}
else {
/* TODO: is this really necessary? it's the only time we use faction.c/deadhash
* it allows stealing from a unit in a dead faction, but why? */
f = dfindhash(id);
}
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction == f && cansee(u->faction, r, u2, 0))
break;
}
if (!u2) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
""));
return;
}
if (IsImmune(u2->faction)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "newbie_immunity_error", "turns", NewbieImmunity()));
return;
}
if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) {
cmistake(u, ord, 47, MSG_INCOME);
return;
}
assert(u->region == u2->region);
if (!can_contact(r, u, u2)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
return;
}
effsk = effskill(u, SK_STEALTH, 0);
n = effsk - max_skill(r, f, SK_PERCEPTION);
if (n <= 0) {
/* Wahrnehmung == Tarnung */
if (u_race(u) != get_race(RC_GOBLIN) || effsk <= 3) {
ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2));
if (n == 0) {
ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2));
}
else {
ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target",
u, u2));
}
return;
}
else {
ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u,
u2));
ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u,
u2));
n = 1;
goblin = true;
}
}
i = MIN(u->number, i_get(u->items, rring->itype));
if (i > 0) {
n *= STEALINCOME * (u->number + i * (roqf_factor() - 1));
}
else {
n *= u->number * STEALINCOME;
}
u->wants = n;
/* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein
* guter dieb sein, schliesslich macht man immer noch sehr viel laerm */
o = (production *)calloc(1, sizeof(production));
o->unit = u;
o->qty = 1; /* Betrag steht in u->wants */
o->no = u2->no;
o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */
addlist(stealorders, o);
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
produceexp(u, SK_STEALTH, MIN(n, u->number));
}
/* ------------------------------------------------------------- */
static void expandentertainment(region * r) static void expandentertainment(region * r)
{ {
unit *u; unit *u;
int m = entertainmoney(r); int m = entertainmoney(r);
production *o; econ_request *o;
for (o = &entertainers[0]; o != nextentertainer; ++o) { for (o = &entertainers[0]; o != nextentertainer; ++o) {
double part = m / (double)entertaining; double part = m / (double)entertaining;
@ -2539,7 +2352,7 @@ void entertain_cmd(unit * u, struct order *ord)
{ {
region *r = u->region; region *r = u->region;
int max_e; int max_e;
production *o; econ_request *o;
static int entertainbase = 0; static int entertainbase = 0;
static int entertainperlevel = 0; static int entertainperlevel = 0;
keyword_t kwd; keyword_t kwd;
@ -2592,7 +2405,7 @@ void entertain_cmd(unit * u, struct order *ord)
* \return number of working spaces taken by players * \return number of working spaces taken by players
*/ */
static void static void
expandwork(region * r, production * work_begin, production * work_end, int maxwork) expandwork(region * r, econ_request * work_begin, econ_request * work_end, int maxwork)
{ {
int earnings; int earnings;
/* n: verbleibende Einnahmen */ /* n: verbleibende Einnahmen */
@ -2600,7 +2413,7 @@ expandwork(region * r, production * work_begin, production * work_end, int maxwo
int jobs = maxwork; int jobs = maxwork;
int p_wage = wage(r, NULL, NULL, turn); int p_wage = wage(r, NULL, NULL, turn);
int money = rmoney(r); int money = rmoney(r);
production *o; econ_request *o;
for (o = work_begin; o != work_end; ++o) { for (o = work_begin; o != work_end; ++o) {
unit *u = o->unit; unit *u = o->unit;
@ -2643,7 +2456,7 @@ expandwork(region * r, production * work_begin, production * work_end, int maxwo
rsetmoney(r, money + earnings); rsetmoney(r, money + earnings);
} }
static int do_work(unit * u, order * ord, production * o) static int do_work(unit * u, order * ord, econ_request * o)
{ {
if (playerrace(u_race(u))) { if (playerrace(u_race(u))) {
region *r = u->region; region *r = u->region;
@ -2678,7 +2491,7 @@ static int do_work(unit * u, order * ord, production * o)
return -1; return -1;
} }
static void expandloot(region * r, production * lootorders) static void expandloot(region * r, econ_request * lootorders)
{ {
unit *u; unit *u;
unsigned int i; unsigned int i;
@ -2715,7 +2528,7 @@ static void expandloot(region * r, production * lootorders)
} }
} }
void expandtax(region * r, production * taxorders) void expandtax(region * r, econ_request * taxorders)
{ {
unit *u; unit *u;
unsigned int i; unsigned int i;
@ -2739,13 +2552,13 @@ void expandtax(region * r, production * taxorders)
} }
} }
void tax_cmd(unit * u, struct order *ord, production ** taxorders) void tax_cmd(unit * u, struct order *ord, econ_request ** taxorders)
{ {
/* Steuern werden noch vor der Forschung eingetrieben */ /* Steuern werden noch vor der Forschung eingetrieben */
region *r = u->region; region *r = u->region;
unit *u2; unit *u2;
int n; int n;
production *o; econ_request *o;
int max; int max;
keyword_t kwd; keyword_t kwd;
static int taxperlevel = 0; static int taxperlevel = 0;
@ -2807,20 +2620,20 @@ void tax_cmd(unit * u, struct order *ord, production ** taxorders)
* fraktionen werden dann bei eintreiben unter allen eintreibenden * fraktionen werden dann bei eintreiben unter allen eintreibenden
* einheiten aufgeteilt. */ * einheiten aufgeteilt. */
o = (production *)calloc(1, sizeof(production)); o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = u->wants / TAXFRACTION; o->qty = u->wants / TAXFRACTION;
o->unit = u; o->unit = u;
addlist(taxorders, o); addlist(taxorders, o);
return; return;
} }
void loot_cmd(unit * u, struct order *ord, production ** lootorders) void loot_cmd(unit * u, struct order *ord, econ_request ** lootorders)
{ {
region *r = u->region; region *r = u->region;
unit *u2; unit *u2;
int n; int n;
int max; int max;
production *o; econ_request *o;
keyword_t kwd; keyword_t kwd;
kwd = init_order_depr(ord); kwd = init_order_depr(ord);
@ -2872,7 +2685,7 @@ void loot_cmd(unit * u, struct order *ord, production ** lootorders)
u->wants = MIN(n * skbonus * 10, max); u->wants = MIN(n * skbonus * 10, max);
} }
o = (production *)calloc(1, sizeof(production)); o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = u->wants / TAXFRACTION; o->qty = u->wants / TAXFRACTION;
o->unit = u; o->unit = u;
addlist(lootorders, o); addlist(lootorders, o);
@ -2883,8 +2696,8 @@ void loot_cmd(unit * u, struct order *ord, production ** lootorders)
#define MAX_WORKERS 2048 #define MAX_WORKERS 2048
void auto_work(region * r) void auto_work(region * r)
{ {
production workers[MAX_WORKERS]; econ_request workers[MAX_WORKERS];
production *nextworker = workers; econ_request *nextworker = workers;
unit *u; unit *u;
for (u = r->units; u; u = u->next) { for (u = r->units; u; u = u->next) {
@ -2952,11 +2765,11 @@ static bool rule_autowork(void) {
void produce(struct region *r) void produce(struct region *r)
{ {
production workers[MAX_WORKERS]; econ_request workers[MAX_WORKERS];
production *taxorders, *lootorders, *sellorders, *stealorders, *buyorders; econ_request *taxorders, *lootorders, *sellorders, *stealorders, *buyorders;
unit *u; unit *u;
bool limited = true; bool limited = true;
production *nextworker = workers; econ_request *nextworker = workers;
static int bt_cache; static int bt_cache;
static const struct building_type *caravan_bt; static const struct building_type *caravan_bt;
static int rc_cache; static int rc_cache;

View File

@ -46,8 +46,8 @@ extern "C" {
struct order; struct order;
struct message; struct message;
typedef struct production { typedef struct econ_request {
struct production *next; struct econ_request *next;
struct unit *unit; struct unit *unit;
struct order *ord; struct order *ord;
int qty; int qty;
@ -56,7 +56,7 @@ extern "C" {
bool goblin; /* stealing */ bool goblin; /* stealing */
const struct luxury_type *ltype; /* trading */ const struct luxury_type *ltype; /* trading */
} type; } type;
} production; } econ_request;
int income(const struct unit *u); int income(const struct unit *u);
int entertainmoney(const struct region *r); int entertainmoney(const struct region *r);
@ -65,17 +65,26 @@ extern "C" {
void produce(struct region *r); void produce(struct region *r);
void auto_work(struct region *r); void auto_work(struct region *r);
enum { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT }; unsigned int expand_production(struct region * r, struct econ_request * requests, struct econ_request **results);
typedef enum income_t { IC_WORK, IC_ENTERTAIN, IC_TAX, IC_TRADE, IC_TRADETAX, IC_STEAL, IC_MAGIC, IC_LOOT } income_t;
void add_income(struct unit * u, income_t type, int want, int qty);
void maintain_buildings(struct region *r); void maintain_buildings(struct region *r);
void make_item(struct unit * u, const struct item_type * itype, int want); void make_item(struct unit * u, const struct item_type * itype, int want);
int make_cmd(struct unit *u, struct order *ord); int make_cmd(struct unit *u, struct order *ord);
void split_allocations(struct region *r); void split_allocations(struct region *r);
int give_control_cmd(struct unit *u, struct order *ord); int give_control_cmd(struct unit *u, struct order *ord);
void give_control(struct unit * u, struct unit * u2); void give_control(struct unit * u, struct unit * u2);
void tax_cmd(struct unit * u, struct order *ord, struct production ** taxorders);
void expandtax(struct region * r, struct production * taxorders); void tax_cmd(struct unit * u, struct order *ord, struct econ_request ** taxorders);
void expandtax(struct region * r, struct econ_request * taxorders);
struct message * steal_message(const struct unit * u, struct order *ord);
void steal_cmd(struct unit * u, struct order *ord, struct econ_request ** stealorders);
void expandstealing(struct region * r, struct econ_request * stealorders);
void add_recruits(struct unit * u, int number, int wanted); void add_recruits(struct unit * u, int number, int wanted);
struct message * check_steal(const struct unit * u, struct order *ord);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -88,7 +88,7 @@ static void test_steal_okay(CuTest * tc) {
rc = test_create_race("human"); rc = test_create_race("human");
rc->flags = 0; rc->flags = 0;
setup_steal(&env, ter, rc); setup_steal(&env, ter, rc);
CuAssertPtrEquals(tc, 0, check_steal(env.u, 0)); CuAssertPtrEquals(tc, 0, steal_message(env.u, 0));
test_cleanup(); test_cleanup();
} }
@ -103,7 +103,7 @@ static void test_steal_nosteal(CuTest * tc) {
rc = test_create_race("human"); rc = test_create_race("human");
rc->flags = RCF_NOSTEAL; rc->flags = RCF_NOSTEAL;
setup_steal(&env, ter, rc); setup_steal(&env, ter, rc);
CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0)); CuAssertPtrNotNull(tc, msg = steal_message(env.u, 0));
msg_release(msg); msg_release(msg);
test_cleanup(); test_cleanup();
} }
@ -118,7 +118,7 @@ static void test_steal_ocean(CuTest * tc) {
ter = test_create_terrain("ocean", SEA_REGION); ter = test_create_terrain("ocean", SEA_REGION);
rc = test_create_race("human"); rc = test_create_race("human");
setup_steal(&env, ter, rc); setup_steal(&env, ter, rc);
CuAssertPtrNotNull(tc, msg = check_steal(env.u, 0)); CuAssertPtrNotNull(tc, msg = steal_message(env.u, 0));
msg_release(msg); msg_release(msg);
test_cleanup(); test_cleanup();
} }
@ -306,7 +306,7 @@ static void test_tax_cmd(CuTest *tc) {
region *r; region *r;
unit *u; unit *u;
item_type *sword, *silver; item_type *sword, *silver;
production *taxorders = 0; econ_request *taxorders = 0;
test_setup(); test_setup();
init_resources(); init_resources();

237
src/steal.c Normal file
View File

@ -0,0 +1,237 @@
/*
Copyright (c) 1998-2014,
Enno Rehling <enno@eressea.de>
Katja Zedel <katze@felidae.kn-bremen.de
Christian Schlittchen <corwin@amber.kn-bremen.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**/
#include <platform.h>
#include <kernel/config.h>
#include "economy.h"
#include "laws.h"
#include "skill.h"
#include "study.h"
#include <util/message.h>
#include <kernel/build.h>
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
#include <kernel/order.h>
#include <kernel/plane.h>
#include <kernel/pool.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/terrain.h>
#include <kernel/unit.h>
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
void expandstealing(region * r, econ_request * stealorders)
{
const resource_type *rsilver = get_resourcetype(R_SILVER);
unsigned int j;
unsigned int norders;
econ_request *requests;
assert(rsilver);
norders = expand_production(r, stealorders, &requests);
if (!norders) return;
/* F<>r jede unit in der Region wird Geld geklaut, wenn sie Opfer eines
* Beklauen-Orders ist. Jedes Opfer mu<EFBFBD> einzeln behandelt werden.
*
* u ist die beklaute unit. oa.unit ist die klauende unit.
*/
for (j = 0; j != norders && requests[j].unit->n <= requests[j].unit->wants; j++) {
unit *u = findunitg(requests[j].no, r);
int n = 0;
if (u && u->region == r) {
n = get_pooled(u, rsilver, GET_ALL, INT_MAX);
}
if (n > 10 && rplane(r) && (rplane(r)->flags & PFL_NOALLIANCES)) {
/* In Questen nur reduziertes Klauen */
n = 10;
}
if (n > 0) {
n = MIN(n, requests[j].unit->wants);
use_pooled(u, rsilver, GET_ALL, n);
requests[j].unit->n = n;
change_money(requests[j].unit, n);
ADDMSG(&u->faction->msgs, msg_message("stealeffect", "unit region amount",
u, u->region, n));
}
add_income(requests[j].unit, IC_STEAL, requests[j].unit->wants, requests[j].unit->n);
fset(requests[j].unit, UFL_LONGACTION | UFL_NOTMOVING);
}
free(requests);
}
static int max_skill(region * r, struct faction * f, skill_t sk)
{
unit *u;
int w = 0;
for (u = r->units; u; u = u->next) {
if (u->faction == f) {
int effsk = effskill(u, sk, 0);
if (effsk > w) {
w = effsk;
}
}
}
return w;
}
message * steal_message(const unit * u, struct order *ord) {
plane *pl;
if (fval(u_race(u), RCF_NOSTEAL)) {
return msg_feedback(u, ord, "race_nosteal", "race", u_race(u));
}
if (fval(u->region->terrain, SEA_REGION) && u_race(u) != get_race(RC_AQUARIAN)) {
return msg_feedback(u, ord, "error_onlandonly", "");
}
pl = rplane(u->region);
if (pl && fval(pl, PFL_NOATTACK)) {
return msg_feedback(u, ord, "error270", "");
}
return 0;
}
void steal_cmd(unit * u, struct order *ord, econ_request ** stealorders)
{
const resource_type *rring = get_resourcetype(R_RING_OF_NIMBLEFINGER);
int n, i, id, effsk;
bool goblin = false;
econ_request *o;
unit *u2 = NULL;
region *r = u->region;
faction *f = NULL;
message * msg;
keyword_t kwd;
kwd = init_order_depr(ord);
assert(kwd == K_STEAL);
assert(skill_enabled(SK_PERCEPTION) && skill_enabled(SK_STEALTH));
msg = steal_message(u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
return;
}
id = read_unitid(u->faction, r);
if (id > 0) {
u2 = findunitr(r, id);
}
if (u2 && u2->region == u->region) {
f = u2->faction;
}
else {
/* TODO: is this really necessary? it's the only time we use faction.c/deadhash
* it allows stealing from a unit in a dead faction, but why? */
f = dfindhash(id);
}
for (u2 = r->units; u2; u2 = u2->next) {
if (u2->faction == f && cansee(u->faction, r, u2, 0))
break;
}
if (!u2) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found",
""));
return;
}
if (IsImmune(u2->faction)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "newbie_immunity_error", "turns", NewbieImmunity()));
return;
}
if (u->faction->alliance && u->faction->alliance == u2->faction->alliance) {
cmistake(u, ord, 47, MSG_INCOME);
return;
}
assert(u->region == u2->region);
if (!can_contact(r, u, u2)) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error60", ""));
return;
}
effsk = effskill(u, SK_STEALTH, 0);
n = effsk - max_skill(r, f, SK_PERCEPTION);
if (n <= 0) {
/* Wahrnehmung == Tarnung */
if (u_race(u) != get_race(RC_GOBLIN) || effsk <= 3) {
ADDMSG(&u->faction->msgs, msg_message("stealfail", "unit target", u, u2));
if (n == 0) {
ADDMSG(&u2->faction->msgs, msg_message("stealdetect", "unit", u2));
}
else {
ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target",
u, u2));
}
return;
}
else {
ADDMSG(&u->faction->msgs, msg_message("stealfatal", "unit target", u,
u2));
ADDMSG(&u2->faction->msgs, msg_message("thiefdiscover", "unit target", u,
u2));
n = 1;
goblin = true;
}
}
i = MIN(u->number, i_get(u->items, rring->itype));
if (i > 0) {
n *= STEALINCOME * (u->number + i * (roqf_factor() - 1));
}
else {
n *= u->number * STEALINCOME;
}
u->wants = n;
/* wer dank unsichtbarkeitsringen klauen kann, muss nicht unbedingt ein
* guter dieb sein, schliesslich macht man immer noch sehr viel laerm */
o = (econ_request *)calloc(1, sizeof(econ_request));
o->unit = u;
o->qty = 1; /* Betrag steht in u->wants */
o->no = u2->no;
o->type.goblin = goblin; /* Merken, wenn Goblin-Spezialklau */
o->next = *stealorders;
*stealorders = o;
/* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */
produceexp(u, SK_STEALTH, MIN(n, u->number));
}