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
creport.c
report.c
steal.c
economy.c
give.c
items.c

View File

@ -83,12 +83,12 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
static int working;
static production entertainers[1024];
static production *nextentertainer;
static econ_request entertainers[1024];
static econ_request *nextentertainer;
static int entertaining;
static unsigned int norders;
static production *g_requests;
static econ_request *g_requests;
#define RECRUIT_MERGE 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;
production *o;
econ_request *o;
unsigned int norders = 0;
/* Alle Units ohne production haben ein -1, alle units mit orders haben ein
* 0 hier stehen */
@ -152,8 +153,6 @@ static void expandorders(region * r, production * requests)
for (u = r->units; u; u = u->next)
u->n = -1;
norders = 0;
for (o = requests; o; o = o->next) {
if (o->qty > 0) {
norders += o->qty;
@ -162,28 +161,35 @@ static void expandorders(region * r, production * requests)
if (norders > 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) {
if (o->qty > 0) {
unsigned int j;
for (j = o->qty; j; j--) {
g_requests[i] = *o;
g_requests[i].unit->n = 0;
split[i] = *o;
split[i].unit->n = 0;
i++;
}
}
}
scramble(g_requests, norders, sizeof(production));
scramble(split, norders, sizeof(econ_request));
*results = split;
}
else {
g_requests = NULL;
*results = NULL;
}
while (requests) {
production *o = requests->next;
econ_request *o = requests->next;
free_order(requests->ord);
free(requests);
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 {
struct recruitment *next;
faction *f;
production *requests;
econ_request *requests;
int total, assigned;
} recruitment;
/** Creates a list of recruitment structs, one for each faction. Adds every quantifyable production
* 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)
{
recruitment *recruits = NULL;
while (*rop) {
recruitment *rec = recruits;
production *ro = *rop;
econ_request *ro = *rop;
unit *u = ro->unit;
const race *rc = u_race(u);
int qty = quantify(rc, ro->qty);
@ -318,7 +324,7 @@ static int do_recruiting(recruitment * recruits, int available)
/* do actual recruiting */
for (rec = recruits; rec != NULL; rec = rec->next) {
production *req;
econ_request *req;
int get = rec->assigned;
for (req = rec->requests; req; req = req->next) {
@ -367,7 +373,7 @@ void free_recruitments(recruitment * recruits)
recruitment *rec = recruits;
recruits = rec->next;
while (rec->requests) {
production *req = rec->requests;
econ_request *req = rec->requests;
rec->requests = req->next;
free_order(req->ord);
free(req);
@ -377,7 +383,7 @@ void free_recruitments(recruitment * recruits)
}
/* Rekrutierung */
static void expandrecruit(region * r, production * recruitorders)
static void expandrecruit(region * r, econ_request * recruitorders)
{
recruitment *recruits = NULL;
@ -418,11 +424,11 @@ static int recruit_cost(const faction * f, const race * rc)
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;
plane *pl;
production *o;
econ_request *o;
int recruitcost = -1;
const faction *f = u->faction;
const struct race *rc = u_race(u);
@ -543,7 +549,7 @@ static void recruit(unit * u, struct order *ord, production ** recruitorders)
return;
}
o = (production *)calloc(1, sizeof(production));
o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = n;
o->unit = u;
o->ord = copy_order(ord);
@ -739,7 +745,7 @@ void maintain_buildings(region * r)
void economics(region * r)
{
unit *u;
production *recruitorders = NULL;
econ_request *recruitorders = NULL;
/* Geben vor Selbstmord (doquit)! Hier alle unmittelbaren Befehle.
* Rekrutieren vor allen Einnahmequellen. Bewachen JA vor Steuern
@ -1429,7 +1435,7 @@ const attrib_type at_luxuries = {
"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);
int max_products;
@ -1542,12 +1548,12 @@ attrib_type at_trades = {
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];
region *r = u->region;
int n, k;
production *o;
econ_request *o;
attrib *a;
const item_type *itype = 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", ""));
return;
}
o = (production *)calloc(1, sizeof(production));
o = (econ_request *)calloc(1, sizeof(econ_request));
o->type.ltype = ltype; /* sollte immer gleich sein */
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)
want = qty;
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 */
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;
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];
bool unlimited = true;
@ -1940,7 +1946,7 @@ static bool sell(unit * u, production ** sellorders, struct order *ord)
}
else {
attrib *a;
production *o;
econ_request *o;
int k, available;
if (!r_demand(r, ltype)) {
@ -1988,7 +1994,7 @@ static bool sell(unit * u, production ** sellorders, struct order *ord)
assert(n >= 0);
/* die Menge der verkauften G<>ter merken */
a->data.i += n;
o = (production *)calloc(1, sizeof(production));
o = (econ_request *)calloc(1, sizeof(econ_request));
o->unit = u;
o->qty = n;
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)
{
@ -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)
{
unit *u;
int m = entertainmoney(r);
production *o;
econ_request *o;
for (o = &entertainers[0]; o != nextentertainer; ++o) {
double part = m / (double)entertaining;
@ -2539,7 +2352,7 @@ void entertain_cmd(unit * u, struct order *ord)
{
region *r = u->region;
int max_e;
production *o;
econ_request *o;
static int entertainbase = 0;
static int entertainperlevel = 0;
keyword_t kwd;
@ -2592,7 +2405,7 @@ void entertain_cmd(unit * u, struct order *ord)
* \return number of working spaces taken by players
*/
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;
/* n: verbleibende Einnahmen */
@ -2600,7 +2413,7 @@ expandwork(region * r, production * work_begin, production * work_end, int maxwo
int jobs = maxwork;
int p_wage = wage(r, NULL, NULL, turn);
int money = rmoney(r);
production *o;
econ_request *o;
for (o = work_begin; o != work_end; ++o) {
unit *u = o->unit;
@ -2643,7 +2456,7 @@ expandwork(region * r, production * work_begin, production * work_end, int maxwo
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))) {
region *r = u->region;
@ -2678,7 +2491,7 @@ static int do_work(unit * u, order * ord, production * o)
return -1;
}
static void expandloot(region * r, production * lootorders)
static void expandloot(region * r, econ_request * lootorders)
{
unit *u;
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;
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 */
region *r = u->region;
unit *u2;
int n;
production *o;
econ_request *o;
int max;
keyword_t kwd;
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
* einheiten aufgeteilt. */
o = (production *)calloc(1, sizeof(production));
o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = u->wants / TAXFRACTION;
o->unit = u;
addlist(taxorders, o);
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;
unit *u2;
int n;
int max;
production *o;
econ_request *o;
keyword_t kwd;
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);
}
o = (production *)calloc(1, sizeof(production));
o = (econ_request *)calloc(1, sizeof(econ_request));
o->qty = u->wants / TAXFRACTION;
o->unit = u;
addlist(lootorders, o);
@ -2883,8 +2696,8 @@ void loot_cmd(unit * u, struct order *ord, production ** lootorders)
#define MAX_WORKERS 2048
void auto_work(region * r)
{
production workers[MAX_WORKERS];
production *nextworker = workers;
econ_request workers[MAX_WORKERS];
econ_request *nextworker = workers;
unit *u;
for (u = r->units; u; u = u->next) {
@ -2952,11 +2765,11 @@ static bool rule_autowork(void) {
void produce(struct region *r)
{
production workers[MAX_WORKERS];
production *taxorders, *lootorders, *sellorders, *stealorders, *buyorders;
econ_request workers[MAX_WORKERS];
econ_request *taxorders, *lootorders, *sellorders, *stealorders, *buyorders;
unit *u;
bool limited = true;
production *nextworker = workers;
econ_request *nextworker = workers;
static int bt_cache;
static const struct building_type *caravan_bt;
static int rc_cache;

View File

@ -46,8 +46,8 @@ extern "C" {
struct order;
struct message;
typedef struct production {
struct production *next;
typedef struct econ_request {
struct econ_request *next;
struct unit *unit;
struct order *ord;
int qty;
@ -56,7 +56,7 @@ extern "C" {
bool goblin; /* stealing */
const struct luxury_type *ltype; /* trading */
} type;
} production;
} econ_request;
int income(const struct unit *u);
int entertainmoney(const struct region *r);
@ -65,17 +65,26 @@ extern "C" {
void produce(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 make_item(struct unit * u, const struct item_type * itype, int want);
int make_cmd(struct unit *u, struct order *ord);
void split_allocations(struct region *r);
int give_control_cmd(struct unit *u, struct order *ord);
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);
struct message * check_steal(const struct unit * u, struct order *ord);
#ifdef __cplusplus
}

View File

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