server/src/give.c

948 lines
27 KiB
C
Raw Normal View History

#ifdef _MSC_VER
2010-08-08 10:06:34 +02:00
#include <platform.h>
#endif
2010-08-08 10:06:34 +02:00
#include <kernel/config.h>
#include "give.h"
#include "contact.h"
2010-08-08 10:06:34 +02:00
#include "economy.h"
2014-11-03 08:40:58 +01:00
#include "laws.h"
2010-08-08 10:06:34 +02:00
#include <spells/unitcurse.h>
/* attributes includes */
#include <attributes/racename.h>
/* kernel includes */
2018-09-29 19:32:39 +02:00
#include <kernel/attrib.h>
#include <kernel/event.h>
#include <kernel/ally.h>
#include <kernel/build.h>
2012-06-03 22:39:42 +02:00
#include <kernel/curse.h>
2010-08-08 10:06:34 +02:00
#include <kernel/faction.h>
#include <kernel/item.h>
#include <kernel/messages.h>
2010-08-08 10:06:34 +02:00
#include <kernel/order.h>
2014-11-03 08:40:58 +01:00
#include <kernel/plane.h>
2010-08-08 10:06:34 +02:00
#include <kernel/pool.h>
#include <kernel/race.h>
#include <kernel/region.h>
#include <kernel/ship.h>
#include <kernel/terrain.h>
#include <kernel/unit.h>
/* util includes */
#include <util/base36.h>
#include <util/log.h>
#include <util/macros.h>
2018-09-29 19:32:39 +02:00
#include <util/param.h>
2014-11-03 08:40:58 +01:00
#include <util/parser.h>
2010-08-08 10:06:34 +02:00
/* libc includes */
#include <assert.h>
#include <limits.h>
#include <stdlib.h>
/* Wieviel Fremde eine Partei pro Woche aufnehmen kangiven */
2011-03-07 08:02:35 +01:00
#define RESERVE_DONATIONS /* shall we reserve objects given to us by other factions? */
#define RESERVE_GIVE /* reserve anything that's given from one unit to another? */
2010-08-08 10:06:34 +02:00
2015-03-13 21:56:18 +01:00
static int max_transfers(void) {
return config_get_int("rules.give.max_men", 5);
}
2011-03-07 08:02:35 +01:00
static int GiveRestriction(void)
{
return config_get_int("GiveRestriction", 0);
2010-08-08 10:06:34 +02:00
}
2014-11-03 08:40:58 +01:00
static void feedback_give_not_allowed(unit * u, order * ord)
{
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_give_forbidden",
""));
}
static bool can_give(const unit * u, const unit * u2, const item_type * itype, int mask)
{
if (u2) {
if (u2->number==0 && !fval(u2, UFL_ISNEW)) {
/* https://bugs.eressea.de/view.php?id=2230
* cannot give anything to dead units */
return false;
} else if (u->faction != u2->faction) {
2014-11-03 08:40:58 +01:00
int rule = rule_give();
if (itype) {
assert(mask == 0);
if (itype->rtype->ltype)
mask |= GIVE_LUXURIES;
else if (fval(itype, ITF_HERB))
mask |= GIVE_HERBS;
else
mask |= GIVE_GOODS;
}
return (rule & mask) != 0;
}
}
else {
int rule = rule_give();
return (rule & GIVE_PEASANTS) != 0;
}
return true;
}
2010-08-08 10:06:34 +02:00
static void
2011-03-07 08:02:35 +01:00
add_give(unit * u, unit * u2, int given, int received,
2014-08-08 01:03:46 +02:00
const resource_type * rtype, struct order *ord, int error)
2010-08-08 10:06:34 +02:00
{
2014-08-08 01:03:46 +02:00
if (error) {
cmistake(u, ord, error, MSG_COMMERCE);
}
else if (u2 == NULL) {
ADDMSG(&u->faction->msgs,
msg_message("give_peasants", "unit resource amount", u, rtype, given));
}
else if (u2->faction != u->faction) {
message *msg;
msg =
msg_message("give", "unit target resource amount", u, u2, rtype, given);
add_message(&u->faction->msgs, msg);
msg_release(msg);
msg =
msg_message("receive", "unit target resource amount", u, u2, rtype,
received);
add_message(&u2->faction->msgs, msg);
msg_release(msg);
}
2010-08-08 10:06:34 +02:00
}
2017-03-05 11:25:17 +01:00
static void add_give_person(unit * u, unit * u2, int given,
struct order *ord, int error)
{
assert(u2);
if (error) {
cmistake(u, ord, error, MSG_COMMERCE);
}
else if (u2->faction != u->faction) {
message *msg;
msg = msg_message("give_person", "unit target amount",
2017-03-05 11:25:17 +01:00
u, u2, given);
add_message(&u->faction->msgs, msg);
msg_release(msg);
msg = msg_message("receive_person", "unit target amount",
2017-03-05 11:25:17 +01:00
u, u2, given);
add_message(&u2->faction->msgs, msg);
msg_release(msg);
}
}
static bool limited_give(const item_type * type)
2010-08-08 10:06:34 +02:00
{
2014-08-08 01:03:46 +02:00
/* trade only money 2:1, if at all */
return (type->rtype == get_resourcetype(R_SILVER));
2010-08-08 10:06:34 +02:00
}
2011-03-07 08:02:35 +01:00
int give_quota(const unit * src, const unit * dst, const item_type * type,
2014-08-08 01:03:46 +02:00
int n)
2010-08-08 10:06:34 +02:00
{
2014-08-08 01:03:46 +02:00
if (!limited_give(type)) {
return n;
}
if (dst && src && src->faction != dst->faction) {
static int config;
2018-02-25 20:49:33 +01:00
static int divisor = 1;
if (config_changed(&config)) {
2018-02-25 20:49:33 +01:00
divisor = config_get_int("rules.items.give_divisor", divisor);
}
2014-08-08 01:03:46 +02:00
if (divisor >= 1) {
/* predictable > correct: */
2018-02-11 15:57:31 +01:00
return n / divisor;
2014-08-08 01:03:46 +02:00
}
}
2010-08-08 10:06:34 +02:00
return n;
}
static void
give_horses(unit * s, const item_type * itype, int n)
{
region *r = s->region;
UNUSED_ARG(itype);
if (r->land) {
rsethorses(r, rhorses(r) + n);
}
}
static void
give_money(unit * s, const item_type * itype, int n)
{
region *r = s->region;
UNUSED_ARG(itype);
if (r->land) {
rsetmoney(r, rmoney(r) + n);
}
}
2010-08-08 10:06:34 +02:00
int
2011-03-07 08:02:35 +01:00
give_item(int want, const item_type * itype, unit * src, unit * dest,
struct order *ord)
2010-08-08 10:06:34 +02:00
{
2014-08-08 01:03:46 +02:00
short error = 0;
int n, delta;
2014-08-08 01:03:46 +02:00
assert(itype != NULL);
n = get_pooled(src, item2resource(itype), GET_SLACK | GET_POOLED_SLACK, want);
if (n > want) n = want;
delta = n;
2014-08-08 01:03:46 +02:00
if (dest && src->faction != dest->faction
&& src->faction->age < GiveRestriction()) {
if (ord != NULL) {
ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "giverestriction",
"turns", GiveRestriction()));
}
return -1;
}
else if (n == 0) {
int reserve = get_reservation(src, itype);
2014-08-08 01:03:46 +02:00
if (reserve) {
ADDMSG(&src->faction->msgs, msg_feedback(src, ord, "nogive_reserved", "resource reservation",
itype->rtype, reserve));
2014-08-08 01:03:46 +02:00
return -1;
}
error = 36;
}
else if (itype->flags & ITF_CURSED) {
error = 25;
}
else {
2014-08-08 01:03:46 +02:00
int use = use_pooled(src, item2resource(itype), GET_SLACK, n);
2014-08-08 01:03:46 +02:00
if (use < n)
use +=
use_pooled(src, item2resource(itype), GET_POOLED_SLACK,
n - use);
if (dest) {
delta = give_quota(src, dest, itype, n);
i_change(&dest->items, itype, delta);
2010-08-08 10:06:34 +02:00
#ifdef RESERVE_GIVE
#ifdef RESERVE_DONATIONS
change_reservation(dest, itype, delta);
2010-08-08 10:06:34 +02:00
#else
2014-08-08 01:03:46 +02:00
if (src->faction == dest->faction) {
change_reservation(dest, item2resource(itype), r);
}
2010-08-08 10:06:34 +02:00
#endif
#endif
2014-08-08 01:03:46 +02:00
}
else {
/* return horses to the region */
if (itype->construction && itype->flags & ITF_ANIMAL) {
if (itype->construction->skill == SK_HORSE_TRAINING) {
give_horses(src, itype, n);
}
}
else if (itype->rtype == get_resourcetype(R_SILVER)) {
give_money(src, itype, n);
}
}
2014-08-08 01:03:46 +02:00
}
add_give(src, dest, n, delta, item2resource(itype), ord, error);
2014-08-08 01:03:46 +02:00
if (error)
return -1;
return 0;
2010-08-08 10:06:34 +02:00
}
static bool unit_has_cursed_item(const unit * u)
{
item *itm = u->items;
while (itm) {
if (fval(itm->type, ITF_CURSED) && itm->number > 0)
return true;
itm = itm->next;
}
return false;
}
static bool can_give_men(const unit *u, const unit *dst, order *ord, message **msg) {
UNUSED_ARG(dst);
if (unit_has_cursed_item(u)) {
if (msg) *msg = msg_error(u, ord, 78);
}
else if (has_skill(u, SK_MAGIC)) {
/* cannot give units to and from magicians */
if (msg) *msg = msg_error(u, ord, 158);
}
else if (fval(u, UFL_HUNGER)) {
/* hungry people cannot be given away */
if (msg) *msg = msg_error(u, ord, 73);
}
else if (fval(u, UFL_LOCKED) || is_cursed(u->attribs, &ct_slavery)) {
if (msg) *msg = msg_error(u, ord, 74);
}
else {
return true;
}
return false;
}
bool rule_transfermen(void)
{
int rule = config_get_int("rules.transfermen", 1);
return rule != 0;
}
2019-10-07 21:45:49 +02:00
static void transfer_ships(ship *s1, ship *s2, int n)
{
2019-10-08 04:52:41 +02:00
assert(n <= s1->number);
2019-10-07 21:45:49 +02:00
s2->damage += s1->damage * n / s1->number;
s2->size += s1->size * n / s1->number;
s2->number += n;
scale_ship(s1, s1->number - n);
}
2019-10-08 04:52:41 +02:00
static void transfer_units(ship *s1, ship *s2)
2019-10-07 21:45:49 +02:00
{
2019-10-08 04:52:41 +02:00
region * r = s1->region;
unit *u;
for (u = r->units; u; u = u->next) {
if (u->ship == s1) {
leave_ship(u);
u_set_ship(u, s2);
}
2019-10-07 21:45:49 +02:00
}
2019-10-08 04:52:41 +02:00
}
static bool ship_cursed(const ship *sh) {
return a_find(sh->attribs, &at_curse) != NULL;
}
2019-10-08 04:52:41 +02:00
message * give_ship(unit *u1, unit *u2, int n, order *ord)
{
assert(u1->ship);
assert(n > 0 && n <= u1->ship->number);
if (u1->faction != u2->faction) {
return msg_error(u1, ord, 324);
}
if (ship_cursed(u1->ship)) {
return msg_error(u1, ord, 323);
2019-10-08 04:52:41 +02:00
}
2019-10-07 21:45:49 +02:00
if (u2->ship) {
if (ship_cursed(u2->ship)) {
return msg_error(u1, ord, 323);
}
2019-10-08 04:52:41 +02:00
if (n < u1->ship->number) {
if (u2->ship->type != u1->ship->type) {
return msg_error(u1, ord, 322);
}
transfer_ships(u1->ship, u2->ship, n);
}
else {
transfer_ships(u1->ship, u2->ship, n);
transfer_units(u1->ship, u2->ship);
2019-10-07 21:45:49 +02:00
}
}
2019-10-08 04:52:41 +02:00
else {
2019-10-07 21:45:49 +02:00
if (fval(u_race(u2), RCF_CANSAIL)) {
2019-10-08 04:52:41 +02:00
if (n < u1->ship->number) {
ship * sh = new_ship(u1->ship->type, u1->region, u1->faction->locale);
scale_ship(sh, 0);
u_set_ship(u2, sh);
transfer_ships(u1->ship, sh, n);
}
else {
u_set_ship(u2, u1->ship);
ship_set_owner(u2);
}
2019-10-07 21:45:49 +02:00
}
else {
2019-10-08 04:52:41 +02:00
return msg_error(u1, ord, 233);
2019-10-07 21:45:49 +02:00
}
2019-10-06 20:42:47 +02:00
}
return NULL;
}
message * give_men(int n, unit * u, unit * u2, struct order *ord)
2010-08-08 10:06:34 +02:00
{
2014-08-08 01:03:46 +02:00
int error = 0;
message * msg;
int maxt = max_transfers();
assert(u2); /* use disband_men for GIVE 0 */
if (!can_give_men(u, u2, ord, &msg)) {
return msg;
}
2014-08-08 01:03:46 +02:00
if (u->faction != u2->faction && u->faction->age < GiveRestriction()) {
return msg_feedback(u, ord, "giverestriction",
"turns", GiveRestriction());
2014-08-08 01:03:46 +02:00
}
else if (u == u2) {
error = 10;
}
else if (u2->number && (fval(u, UFL_HERO) != fval(u2, UFL_HERO))) {
2014-08-08 01:03:46 +02:00
/* heroes may not be given to non-heroes and vice versa */
error = 75;
}
else if (unit_has_cursed_item(u2)) {
2014-08-08 01:03:46 +02:00
error = 78;
}
else if (fval(u2, UFL_LOCKED) || is_cursed(u2->attribs, &ct_slavery)) {
2014-08-08 01:03:46 +02:00
error = 75;
}
else if (!ucontact(u2, u)) {
return msg_feedback(u, ord, "feedback_no_contact",
"target", u2);
2014-08-08 01:03:46 +02:00
}
else if (has_skill(u2, SK_MAGIC)) {
2014-08-08 01:03:46 +02:00
/* cannot give units to and from magicians */
error = 158;
}
else if (fval(u, UFL_WERE) != fval(u2, UFL_WERE)) {
2014-08-08 01:03:46 +02:00
/* werewolves can't be given to non-werewolves and vice-versa */
error = 312;
}
else if (u2->number != 0 && u_race(u2) != u_race(u)) {
log_debug("faction %s attempts to give %s to %s.\n", itoa36(u->faction->no), u_race(u)->_name, u_race(u2)->_name);
2014-08-08 01:03:46 +02:00
error = 139;
}
else if (get_racename(u2->attribs) || get_racename(u->attribs)) {
2014-08-08 01:03:46 +02:00
error = 139;
}
else if (u2->faction != u->faction && !rule_transfermen()) {
2014-08-08 01:03:46 +02:00
error = 74;
}
else {
if (n > u->number)
n = u->number;
if (n + u2->number > UNIT_MAXSIZE) {
2014-08-08 01:03:46 +02:00
n = UNIT_MAXSIZE - u2->number;
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "error_unit_size",
"maxsize", UNIT_MAXSIZE));
assert(n >= 0);
2010-08-08 10:06:34 +02:00
}
2014-08-08 01:03:46 +02:00
if (n == 0) {
error = 96;
}
else if (u->faction != u2->faction) {
if (maxt >= 0 && u2->faction->newbies + n > maxt) {
2014-08-08 01:03:46 +02:00
error = 129;
}
else if (u_race(u) != u2->faction->race) {
if (u2->faction->race != get_race(RC_HUMAN)) {
error = 120;
}
else if (count_migrants(u2->faction) + n >
count_maxmigrants(u2->faction)) {
error = 128;
}
else if (has_limited_skills(u) || has_limited_skills(u2)) {
error = 154;
}
else if (u2->number != 0) {
error = 139;
}
}
}
}
if (has_skill(u, SK_ALCHEMY) || has_skill(u2, SK_ALCHEMY)) {
int k = faction_count_skill(u2->faction, SK_ALCHEMY);
2014-08-08 01:03:46 +02:00
/* Falls die Zieleinheit keine Alchemisten sind, werden sie nun
* welche. */
if (!has_skill(u2, SK_ALCHEMY) && has_skill(u, SK_ALCHEMY))
k += u2->number;
/* Wenn in eine Alchemisteneinheit Personen verschoben werden */
if (has_skill(u2, SK_ALCHEMY) && !has_skill(u, SK_ALCHEMY))
k += n;
2019-02-09 12:50:12 +01:00
/* Wenn Parteigrenzen ueberschritten werden */
2014-08-08 01:03:46 +02:00
if (u2->faction != u->faction)
k += n;
/* wird das Alchemistenmaximum ueberschritten ? */
if (k > faction_skill_limit(u2->faction, SK_ALCHEMY)) {
2014-08-08 01:03:46 +02:00
error = 156;
}
}
if (error == 0) {
ship *sh = leftship(u);
2019-02-09 12:50:12 +01:00
/* Einheiten von Schiffen koennen nicht NACH in von
* Nicht-alliierten bewachten Regionen ausfuehren */
if (sh) {
set_leftship(u2, sh);
}
if (u2->number == 0) {
2014-08-08 01:03:46 +02:00
set_racename(&u2->attribs, get_racename(u->attribs));
u_setrace(u2, u_race(u));
u2->irace = u->irace;
2017-09-16 07:37:33 +02:00
if (fval(u, UFL_HERO)) {
2014-08-08 01:03:46 +02:00
fset(u2, UFL_HERO);
2017-09-16 07:37:33 +02:00
}
else {
2014-08-08 01:03:46 +02:00
freset(u2, UFL_HERO);
2017-09-16 07:37:33 +02:00
}
2010-08-08 10:06:34 +02:00
}
2014-08-08 01:03:46 +02:00
transfermen(u, u2, n);
if (maxt >= 0 && u->faction != u2->faction) {
u2->faction->newbies += n;
2014-08-08 01:03:46 +02:00
}
}
if (error > 0) {
return msg_error(u, ord, error);
2014-08-08 01:03:46 +02:00
}
else if (u2->faction != u->faction) {
return add_message(&u2->faction->msgs,
msg_message("give_person", "unit target amount", u, u2, n));
2014-08-08 01:03:46 +02:00
}
return NULL;
2010-08-08 10:06:34 +02:00
}
message * disband_men(int n, unit * u, struct order *ord) {
message * msg;
2016-11-13 17:06:28 +01:00
static const race *rc_snotling;
static int rccache;
2016-11-13 17:06:28 +01:00
if (rc_changed(&rccache)) {
rc_snotling = get_race(RC_SNOTLING);
}
if (u_race(u) == rc_snotling) {
/* snotlings may not be given to the peasants. */
return msg_error(u, ord, 307);
}
if (!can_give_men(u, NULL, ord, &msg)) {
return msg;
}
transfermen(u, NULL, n);
2014-12-11 08:35:05 +01:00
if (fval(u->region->terrain, SEA_REGION)) {
return msg_message("give_person_ocean", "unit amount", u, n);
}
return msg_message("give_person_peasants", "unit amount", u, n);
}
int give_unit_allowed(const unit * u)
{
if (unit_has_cursed_item(u)) {
return 78;
}
if (fval(u, UFL_HERO)) {
return 75;
}
if (fval(u, UFL_LOCKED) || fval(u, UFL_HUNGER)) {
return 74;
}
return 0;
}
2011-03-07 08:02:35 +01:00
void give_unit(unit * u, unit * u2, order * ord)
2010-08-08 10:06:34 +02:00
{
int err, maxt = max_transfers();
2014-08-08 01:03:46 +02:00
assert(u);
2015-11-04 14:27:38 +01:00
if (!rule_transfermen() && u2 && u->faction != u2->faction) {
2014-08-08 01:03:46 +02:00
cmistake(u, ord, 74, MSG_COMMERCE);
return;
}
err = give_unit_allowed(u);
if (err != 0) {
cmistake(u, ord, err, MSG_COMMERCE);
2014-08-08 01:03:46 +02:00
return;
}
if (u2 == NULL) {
region *r = u->region;
2014-12-11 08:35:05 +01:00
message *msg;
2014-08-08 01:03:46 +02:00
if (fval(r->terrain, SEA_REGION)) {
2014-12-11 08:35:05 +01:00
msg = disband_men(u->number, u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
else {
cmistake(u, ord, 152, MSG_COMMERCE);
}
2014-08-08 01:03:46 +02:00
}
else {
2014-08-08 01:03:46 +02:00
unit *u3;
for (u3 = r->units; u3; u3 = u3->next)
if (u3->faction == u->faction && u != u3)
break;
if (u3) {
while (u->items) {
item *iold = i_remove(&u->items, u->items);
item *inew = *i_find(&u3->items, iold->type);
if (inew == NULL)
i_add(&u3->items, iold);
else {
inew->number += iold->number;
i_free(iold);
}
}
}
msg = disband_men(u->number, u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
else {
cmistake(u, ord, 153, MSG_COMMERCE);
}
2014-08-08 01:03:46 +02:00
}
return;
} else {
int err = checkunitnumber(u2->faction, 1);
if (err) {
if (err == 1) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord,
"too_many_units_in_alliance",
"allowed", rule_alliance_limit()));
}
else {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord,
"too_many_units_in_faction",
"allowed", rule_faction_limit()));
}
return;
}
2014-08-08 01:03:46 +02:00
}
if (!alliedunit(u2, u->faction, HELP_GIVE) && ucontact(u2, u) == 0) {
ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_no_contact",
"target", u2));
return;
}
if (u->number == 0) {
cmistake(u, ord, 105, MSG_COMMERCE);
return;
}
if (maxt >= 0 && u->faction != u2->faction) {
if (u2->faction->newbies + u->number > maxt) {
cmistake(u, ord, 129, MSG_COMMERCE);
return;
}
2014-08-08 01:03:46 +02:00
}
if (u_race(u) != u2->faction->race) {
if (u2->faction->race != get_race(RC_HUMAN)) {
cmistake(u, ord, 120, MSG_COMMERCE);
return;
}
if (count_migrants(u2->faction) + u->number >
count_maxmigrants(u2->faction)) {
cmistake(u, ord, 128, MSG_COMMERCE);
return;
2010-08-08 10:06:34 +02:00
}
2014-08-08 01:03:46 +02:00
if (has_limited_skills(u)) {
cmistake(u, ord, 154, MSG_COMMERCE);
return;
}
}
if (has_skill(u, SK_MAGIC)) {
if (faction_count_skill(u2->faction, SK_MAGIC) + u->number >
faction_skill_limit(u2->faction, SK_MAGIC)) {
2014-08-08 01:03:46 +02:00
cmistake(u, ord, 155, MSG_COMMERCE);
return;
}
if (u2->faction->magiegebiet != unit_get_magic(u)) {
2014-08-08 01:03:46 +02:00
cmistake(u, ord, 157, MSG_COMMERCE);
return;
}
}
if (has_skill(u, SK_ALCHEMY)
&& faction_count_skill(u2->faction, SK_ALCHEMY) + u->number >
faction_skill_limit(u2->faction, SK_ALCHEMY)) {
2014-08-08 01:03:46 +02:00
cmistake(u, ord, 156, MSG_COMMERCE);
return;
}
2017-03-05 11:25:17 +01:00
add_give_person(u, u2, u->number, ord, 0);
2014-08-08 01:03:46 +02:00
u_setfaction(u, u2->faction);
u2->faction->newbies += u->number;
2010-08-08 10:06:34 +02:00
}
2014-11-03 08:40:58 +01:00
bool can_give_to(unit *u, unit *u2) {
2019-02-09 12:50:12 +01:00
/* Damit Tarner nicht durch die Fehlermeldung enttarnt werden koennen */
if (!u2) {
return false;
}
if (u2 && !alliedunit(u2, u->faction, HELP_GIVE)
&& !cansee(u->faction, u->region, u2, 0) && !ucontact(u2, u)
&& !fval(u2, UFL_TAKEALL)) {
return false;
}
return true;
}
static void give_all_items(unit *u, unit *u2, order *ord) {
char token[128];
const char *s;
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
feedback_give_not_allowed(u, ord);
return;
}
s = gettoken(token, sizeof(token));
if (!s || *s == 0) { /* GIVE ALL items that you have */
/* do these checks once, not for each item we have: */
if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
return;
}
2019-02-09 12:50:12 +01:00
/* fuer alle items einmal pruefen, ob wir mehr als von diesem Typ
* reserviert ist besitzen und diesen Teil dann uebergeben */
if (u->items) {
item **itmp = &u->items;
while (*itmp) {
item *itm = *itmp;
const item_type *itype = itm->type;
if (itm->number > 0
&& itm->number - get_reservation(u, itype) > 0) {
int n = itm->number - get_reservation(u, itype);
if (give_item(n, itype, u, u2, ord) == 0) {
if (*itmp != itm)
continue;
}
}
itmp = &itm->next;
}
}
}
else {
2019-10-06 20:42:47 +02:00
param_t p = findparam(s, u->faction->locale);
2019-10-07 21:45:49 +02:00
if (p == P_PERSON) {
if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
}
else {
message * msg;
msg = u2 ? give_men(u->number, u, u2, ord) : disband_men(u->number, u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
}
}
else if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
}
else {
const item_type *itype = finditemtype(s, u->faction->locale);
if (itype != NULL) {
item *i = *i_find(&u->items, itype);
if (i != NULL) {
if (can_give(u, u2, itype, 0)) {
int n = i->number - get_reservation(u, itype);
give_item(n, itype, u, u2, ord);
}
else {
feedback_give_not_allowed(u, ord);
}
}
}
}
}
}
2014-11-03 08:40:58 +01:00
void give_cmd(unit * u, order * ord)
{
char token[128];
2014-11-03 08:40:58 +01:00
region *r = u->region;
unit *u2;
const char *s;
int err, n;
2014-11-03 08:40:58 +01:00
const item_type *itype;
param_t p;
plane *pl;
message *msg;
keyword_t kwd;
2017-10-09 20:33:47 +02:00
kwd = init_order_depr(ord);
2014-11-03 08:40:58 +01:00
assert(kwd == K_GIVE);
err = getunit(r, u->faction, &u2);
s = gettoken(token, sizeof(token));
2014-11-03 08:40:58 +01:00
n = s ? atoip(s) : 0;
p = (n > 0) ? NOPARAM : findparam(s, u->faction->locale);
/* first, do all the ones that do not require HELP_GIVE or CONTACT */
if (p == P_CONTROL) {
/* handled in give_control_cmd */
return;
}
if (err == GET_NOTFOUND || (err != GET_PEASANTS && !can_give_to(u, u2))) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "feedback_unit_not_found", ""));
return;
}
if (u == u2) {
cmistake(u, ord, 8, MSG_COMMERCE);
2014-11-03 08:40:58 +01:00
return;
}
msg = check_give(u, u2, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
return;
}
/* UFL_TAKEALL ist ein grober Hack. Generalisierung tut not, ist aber nicht
* wirklich einfach. */
pl = rplane(r);
if (pl && fval(pl, PFL_NOGIVE) && (!u2 || !fval(u2, UFL_TAKEALL))) {
cmistake(u, ord, 268, MSG_COMMERCE);
return;
}
2017-05-24 08:52:19 +02:00
if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) {
2014-11-03 08:40:58 +01:00
cmistake(u, ord, 40, MSG_COMMERCE);
return;
}
2016-11-14 20:33:26 +01:00
else if (p == NOPARAM) {
/* the most likely case: giving items to someone.
* let's catch this and save ourselves the rest of the param_t checks.
*/
}
2014-11-03 08:40:58 +01:00
else if (p == P_HERBS) {
bool given = false;
if (!can_give(u, u2, NULL, GIVE_HERBS)) {
feedback_give_not_allowed(u, ord);
return;
}
if (u2 && !(u_race(u2)->ec_flags & ECF_GETITEM)) {
2014-11-03 08:40:58 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
return;
}
if (u->items) {
item **itmp = &u->items;
while (*itmp) {
item *itm = *itmp;
if (fval(itm->type, ITF_HERB) && itm->number > 0) {
2019-02-09 12:50:12 +01:00
/* give_item aendert im fall,das man alles uebergibt, die
2014-11-03 08:40:58 +01:00
* item-liste der unit, darum continue vor pointerumsetzten */
if (give_item(itm->number, itm->type, u, u2, ord) == 0) {
given = true;
continue;
}
}
itmp = &itm->next;
}
}
if (!given) {
2014-11-03 08:40:58 +01:00
cmistake(u, ord, 38, MSG_COMMERCE);
}
2014-11-03 08:40:58 +01:00
return;
}
else if (p == P_ZAUBER) {
cmistake(u, ord, 7, MSG_COMMERCE);
/* geht nimmer */
return;
}
else if (p == P_UNIT) { /* Einheiten uebergeben */
if (!(u_race(u)->ec_flags & ECF_GIVEUNIT)) {
2014-11-03 08:40:58 +01:00
cmistake(u, ord, 167, MSG_COMMERCE);
return;
}
give_unit(u, u2, ord);
return;
}
else if (p == P_ANY) {
give_all_items(u, u2, ord);
2014-11-03 08:40:58 +01:00
return;
}
else if (p == P_EACH) {
if (u2 == NULL) {
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "peasants_give_invalid", ""));
return;
}
s = gettoken(token, sizeof(token)); /* skip one ahead to get the amount. */
n = s ? atoip(s) : 0; /* n: Anzahl */
2014-11-03 08:40:58 +01:00
n *= u2->number;
}
s = gettoken(token, sizeof(token));
2014-11-03 08:40:58 +01:00
if (s == NULL) {
cmistake(u, ord, 113, MSG_COMMERCE);
return;
}
2019-10-06 20:42:47 +02:00
p = findparam(s, u->faction->locale);
if (p == P_SHIP) {
if (u->ship) {
2019-10-07 21:45:49 +02:00
message * msg;
2019-10-08 04:52:41 +02:00
if (n > u->ship->number) {
n = u->ship->number;
2019-10-07 21:45:49 +02:00
}
msg = give_ship(u, u2, n, ord);
2019-10-06 20:42:47 +02:00
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
}
else {
cmistake(u, ord, 144, MSG_COMMERCE);
}
return;
2019-10-06 20:42:47 +02:00
}
else if (p == P_PERSON) {
if (!(u_race(u)->ec_flags & ECF_GIVEPERSON)) {
2014-11-03 08:40:58 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_noregroup", "race", u_race(u)));
return;
}
if (n > u->number) n = u->number;
msg = u2 ? give_men(n, u, u2, ord) : disband_men(n, u, ord);
if (msg) {
ADDMSG(&u->faction->msgs, msg);
}
2014-11-03 08:40:58 +01:00
return;
}
if (u2 != NULL) {
if (!(u_race(u2)->ec_flags & ECF_GETITEM)) {
2014-11-03 08:40:58 +01:00
ADDMSG(&u->faction->msgs,
msg_feedback(u, ord, "race_notake", "race", u_race(u2)));
return;
}
}
itype = finditemtype(s, u->faction->locale);
if (itype != NULL) {
if (can_give(u, u2, itype, 0)) {
give_item(n, itype, u, u2, ord);
}
else {
feedback_give_not_allowed(u, ord);
}
return;
}
cmistake(u, ord, 123, MSG_COMMERCE);
}
message *check_give(const unit *u, const unit *u2, order * ord) {
if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) {
return msg_feedback(u, ord, "feedback_give_forbidden", "");
}
return 0;
}