diff --git a/scripts/fix1984.lua b/scripts/fix1984.lua new file mode 100644 index 000000000..2404d9a6a --- /dev/null +++ b/scripts/fix1984.lua @@ -0,0 +1,33 @@ +function recover(turn) + eressea.free_game() + eressea.read_game(turn .. ".dat") + ships = {} + bldgs = {} + for r in regions() do + for b in r.buildings do + if b.info~=nil and (string.len(b.info)>120) then + bldgs[b.id] = b.info + end + end + for b in r.ships do + if b.info~=nil and (string.len(b.info)>120) then + ships[b.id] = b.info + end + end + end + eressea.free_game() + eressea.read_game((turn+1) .. ".dat") + for k, v in pairs(bldgs) do + b = get_building(k) + if b~=nil then + b.info = v + end + end + for k, v in pairs(ships) do + b = get_ship(k) + if b~=nil then + b.info = v + end + end + eressea.write_game((turn+1) .. ".fixed") +end diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 635427916..402e4dc58 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -166,6 +166,7 @@ set(TESTS_SRC economy.test.c json.test.c keyword.test.c + give.test.c laws.test.c magic.test.c market.test.c diff --git a/src/economy.c b/src/economy.c index 295d78ce5..d5cc4eca5 100644 --- a/src/economy.c +++ b/src/economy.c @@ -388,36 +388,6 @@ static int do_recruiting(recruitment * recruits, int available) return recruited; } -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 (u->faction != u2->faction) { - 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; -} - void free_recruitments(recruitment * recruits) { while (recruits) { @@ -708,275 +678,6 @@ int give_control_cmd(unit * u, order * ord) return 0; } -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; -} - -void give_cmd(unit * u, order * ord) -{ - region *r = u->region; - unit *u2; - const char *s; - int n; - const item_type *itype; - param_t p; - plane *pl; - message *msg; - keyword_t kwd; - - kwd = init_order(ord); - assert(kwd == K_GIVE); - u2 = getunit(r, u->faction); - s = getstrtoken(); - 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 (!u2 && !getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - - msg = check_give(u, u2, ord); - if (msg) { - ADDMSG(&u->faction->msgs, msg); - return; - } - - /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ - if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) - && !cansee(u->faction, r, u2, 0) && !ucontact(u2, u) - && !fval(u2, UFL_TAKEALL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - if (u == u2) { - cmistake(u, ord, 8, MSG_COMMERCE); - 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; - } - - if (u2 && u_race(u2) == get_race(RC_SPELL)) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", - "")); - return; - } - - else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { - cmistake(u, ord, 40, MSG_COMMERCE); - return; - } - - else if (p == P_HERBS) { - bool given = false; - if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u_race(u))); - return; - } - if (!can_give(u, u2, NULL, GIVE_HERBS)) { - feedback_give_not_allowed(u, ord); - return; - } - if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u_race(u2))); - return; - } - if (!u2) { - if (!getunitpeasants) { - ADDMSG(&u->faction->msgs, msg_feedback(u, ord, - "feedback_unit_not_found", "")); - return; - } - } - if (u->items) { - item **itmp = &u->items; - while (*itmp) { - item *itm = *itmp; - const item_type *itype = itm->type; - if (fval(itype, ITF_HERB) && itm->number > 0) { - /* give_item ändert im fall,das man alles übergibt, die - * item-liste der unit, darum continue vor pointerumsetzten */ - if (give_item(itm->number, itm->type, u, u2, ord) == 0) { - given = true; - if (*itmp != itm) - continue; - continue; - } - } - itmp = &itm->next; - } - } - if (!given) - cmistake(u, ord, 38, MSG_COMMERCE); - 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 & GIVEUNIT)) { - cmistake(u, ord, 167, MSG_COMMERCE); - return; - } - - give_unit(u, u2, ord); - return; - } - - else if (p == P_ANY) { - const char *s; - - if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) { - feedback_give_not_allowed(u, ord); - return; - } - s = getstrtoken(); - if (!s || *s == 0) { /* GIVE ALL items that you have */ - - /* do these checks once, not for each item we have: */ - if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u_race(u))); - return; - } - if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u_race(u2))); - return; - } - - /* für alle items einmal prüfen, ob wir mehr als von diesem Typ - * reserviert ist besitzen und diesen Teil dann übergeben */ - 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->rtype) > 0) { - n = itm->number - get_reservation(u, itype->rtype); - if (give_item(n, itype, u, u2, ord) == 0) { - if (*itmp != itm) - continue; - } - } - itmp = &itm->next; - } - } - } - else { - if (isparam(s, u->faction->locale, P_PERSON)) { - if (!(u_race(u)->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); - } - else { - n = u->number; - give_men(n, u, u2, ord); - } - } - else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u_race(u))); - } - else if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_notake", "race", u_race(u2))); - } - else { - 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)) { - n = i->number - get_reservation(u, itype->rtype); - give_item(n, itype, u, u2, ord); - } - else { - feedback_give_not_allowed(u, ord); - } - } - } - } - } - return; - } - else if (p == P_EACH) { - if (u2 == NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "peasants_give_invalid", "")); - return; - } - s = getstrtoken(); /* skip one ahead to get the amount. */ - n = atoip(s); /* n: Anzahl */ - n *= u2->number; - } - s = getstrtoken(); - - if (s == NULL) { - cmistake(u, ord, 113, MSG_COMMERCE); - return; - } - - if (isparam(s, u->faction->locale, P_PERSON)) { - if (!(u_race(u)->ec_flags & GIVEPERSON)) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); - return; - } - give_men(n, u, u2, ord); - return; - } - - if (u2 != NULL) { - if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { - ADDMSG(&u->faction->msgs, - msg_feedback(u, ord, "race_nogive", "race", u_race(u))); - return; - } - if (!(u_race(u2)->ec_flags & GETITEM)) { - 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); -} - static int forget_cmd(unit * u, order * ord) { skill_t sk; diff --git a/src/economy.h b/src/economy.h index da5e8e299..b06ed21c3 100644 --- a/src/economy.h +++ b/src/economy.h @@ -54,10 +54,8 @@ extern "C" { extern int recruit_archetypes(void); extern int give_control_cmd(struct unit *u, struct order *ord); extern void give_control(struct unit * u, struct unit * u2); - void give_cmd(struct unit * u, struct order * ord); struct message * check_steal(const struct unit * u, struct order *ord); - struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord); #ifdef __cplusplus } diff --git a/src/give.c b/src/give.c index 2b3d0ab91..ac928ab9b 100644 --- a/src/give.c +++ b/src/give.c @@ -15,6 +15,7 @@ #include "give.h" #include "economy.h" +#include "laws.h" /* kernel includes */ #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +40,7 @@ #include #include #include +#include /* libc includes */ #include @@ -59,6 +62,36 @@ static int GiveRestriction(void) return value; } +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 (u->faction != u2->faction) { + 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; +} + static void add_give(unit * u, unit * u2, int given, int received, const resource_type * rtype, struct order *ord, int error) @@ -456,3 +489,273 @@ void give_unit(unit * u, unit * u2, order * ord) u_setfaction(u, u2->faction); u2->faction->newbies += n; } + +void give_cmd(unit * u, order * ord) +{ + region *r = u->region; + unit *u2; + const char *s; + int n; + const item_type *itype; + param_t p; + plane *pl; + message *msg; + keyword_t kwd; + + kwd = init_order(ord); + assert(kwd == K_GIVE); + u2 = getunit(r, u->faction); + s = getstrtoken(); + 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 (!u2 && !getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + + msg = check_give(u, u2, ord); + if (msg) { + ADDMSG(&u->faction->msgs, msg); + return; + } + + /* Damit Tarner nicht durch die Fehlermeldung enttarnt werden können */ + if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) + && !cansee(u->faction, r, u2, 0) && !ucontact(u2, u) + && !fval(u2, UFL_TAKEALL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + if (u == u2) { + cmistake(u, ord, 8, MSG_COMMERCE); + 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; + } + + if (u2 && u_race(u2) == get_race(RC_SPELL)) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", + "")); + return; + } + + else if (u2 && !alliedunit(u2, u->faction, HELP_GIVE) && !ucontact(u2, u)) { + cmistake(u, ord, 40, MSG_COMMERCE); + return; + } + + else if (p == P_HERBS) { + bool given = false; + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); + return; + } + if (!can_give(u, u2, NULL, GIVE_HERBS)) { + feedback_give_not_allowed(u, ord); + return; + } + if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); + return; + } + if (!u2) { + if (!getunitpeasants) { + ADDMSG(&u->faction->msgs, msg_feedback(u, ord, + "feedback_unit_not_found", "")); + return; + } + } + if (u->items) { + item **itmp = &u->items; + while (*itmp) { + item *itm = *itmp; + const item_type *itype = itm->type; + if (fval(itype, ITF_HERB) && itm->number > 0) { + /* give_item ändert im fall,das man alles übergibt, die + * item-liste der unit, darum continue vor pointerumsetzten */ + if (give_item(itm->number, itm->type, u, u2, ord) == 0) { + given = true; + if (*itmp != itm) + continue; + continue; + } + } + itmp = &itm->next; + } + } + if (!given) + cmistake(u, ord, 38, MSG_COMMERCE); + 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 & GIVEUNIT)) { + cmistake(u, ord, 167, MSG_COMMERCE); + return; + } + + give_unit(u, u2, ord); + return; + } + + else if (p == P_ANY) { + const char *s; + + if (!can_give(u, u2, NULL, GIVE_ALLITEMS)) { + feedback_give_not_allowed(u, ord); + return; + } + s = getstrtoken(); + if (!s || *s == 0) { /* GIVE ALL items that you have */ + + /* do these checks once, not for each item we have: */ + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); + return; + } + if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); + return; + } + + /* für alle items einmal prüfen, ob wir mehr als von diesem Typ + * reserviert ist besitzen und diesen Teil dann übergeben */ + 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->rtype) > 0) { + n = itm->number - get_reservation(u, itype->rtype); + if (give_item(n, itype, u, u2, ord) == 0) { + if (*itmp != itm) + continue; + } + } + itmp = &itm->next; + } + } + } + else { + if (isparam(s, u->faction->locale, P_PERSON)) { + if (!(u_race(u)->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); + } + else { + n = u->number; + give_men(n, u, u2, ord); + } + } + else if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); + } + else if (u2 && !(u_race(u2)->ec_flags & GETITEM)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_notake", "race", u_race(u2))); + } + else { + 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)) { + n = i->number - get_reservation(u, itype->rtype); + give_item(n, itype, u, u2, ord); + } + else { + feedback_give_not_allowed(u, ord); + } + } + } + } + } + return; + } + else if (p == P_EACH) { + if (u2 == NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "peasants_give_invalid", "")); + return; + } + s = getstrtoken(); /* skip one ahead to get the amount. */ + n = atoip(s); /* n: Anzahl */ + n *= u2->number; + } + s = getstrtoken(); + + if (s == NULL) { + cmistake(u, ord, 113, MSG_COMMERCE); + return; + } + + if (isparam(s, u->faction->locale, P_PERSON)) { + if (!(u_race(u)->ec_flags & GIVEPERSON)) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_noregroup", "race", u_race(u))); + return; + } + give_men(n, u, u2, ord); + return; + } + + if (u2 != NULL) { + if (!(u_race(u)->ec_flags & GIVEITEM) && u2 != NULL) { + ADDMSG(&u->faction->msgs, + msg_feedback(u, ord, "race_nogive", "race", u_race(u))); + return; + } + if (!(u_race(u2)->ec_flags & GETITEM)) { + 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; +} + diff --git a/src/give.h b/src/give.h index 1fec3af81..c392ecde8 100644 --- a/src/give.h +++ b/src/give.h @@ -20,11 +20,13 @@ extern "C" { struct order; struct unit; - extern int give_item(int want, const struct item_type *itype, + int give_item(int want, const struct item_type *itype, struct unit *src, struct unit *dest, struct order *ord); - extern void give_men(int n, struct unit *u, struct unit *u2, + void give_men(int n, struct unit *u, struct unit *u2, struct order *ord); - extern void give_unit(struct unit *u, struct unit *u2, struct order *ord); + void give_unit(struct unit *u, struct unit *u2, struct order *ord); + void give_cmd(struct unit * u, struct order * ord); + struct message * check_give(const struct unit * u, const struct unit * u2, struct order *ord); #ifdef __cplusplus }