2010-08-08 10:06:34 +02:00
|
|
|
/*
|
2015-01-30 22:10:29 +01:00
|
|
|
Copyright (c) 1998-2015, Enno Rehling <enno@eressea.de>
|
2015-01-30 20:37:14 +01:00
|
|
|
Katja Zedel <katze@felidae.kn-bremen.de
|
|
|
|
Christian Schlittchen <corwin@amber.kn-bremen.de>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
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 "alchemy.h"
|
2016-10-26 11:35:20 +02:00
|
|
|
#include "guard.h"
|
2014-08-27 06:40:18 +02:00
|
|
|
#include "skill.h"
|
2016-03-08 14:09:22 +01:00
|
|
|
#include "study.h"
|
2014-08-27 06:40:18 +02:00
|
|
|
|
|
|
|
#include <kernel/item.h>
|
|
|
|
#include <kernel/faction.h>
|
|
|
|
#include <kernel/messages.h>
|
|
|
|
#include <kernel/build.h>
|
|
|
|
#include <kernel/region.h>
|
|
|
|
#include <kernel/pool.h>
|
|
|
|
#include <kernel/race.h>
|
|
|
|
#include <kernel/unit.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* util includes */
|
|
|
|
#include <util/attrib.h>
|
2016-02-13 13:42:02 +01:00
|
|
|
#include <util/gamedata.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <util/base36.h>
|
|
|
|
#include <util/log.h>
|
2017-12-29 06:13:28 +01:00
|
|
|
#include <util/macros.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
#include <util/rand.h>
|
2013-12-31 10:06:28 +01:00
|
|
|
|
|
|
|
#include <storage.h>
|
2010-08-08 10:06:34 +02:00
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
typedef struct potion_type {
|
|
|
|
struct potion_type *next;
|
|
|
|
const struct item_type *itype;
|
|
|
|
int level;
|
|
|
|
} potion_type;
|
|
|
|
|
|
|
|
static potion_type *potiontypes;
|
|
|
|
|
|
|
|
static void pt_register(potion_type * ptype)
|
|
|
|
{
|
|
|
|
ptype->next = potiontypes;
|
|
|
|
potiontypes = ptype;
|
|
|
|
}
|
|
|
|
|
|
|
|
void new_potiontype(item_type * itype, int level)
|
|
|
|
{
|
|
|
|
potion_type *ptype;
|
|
|
|
|
|
|
|
ptype = (potion_type *)calloc(sizeof(potion_type), 1);
|
|
|
|
itype->flags |= ITF_POTION;
|
|
|
|
ptype->itype = itype;
|
|
|
|
ptype->level = level;
|
|
|
|
pt_register(ptype);
|
|
|
|
}
|
|
|
|
|
|
|
|
int potion_level(const item_type *itype)
|
|
|
|
{
|
|
|
|
potion_type *ptype;
|
|
|
|
for (ptype = potiontypes; ptype; ptype = ptype->next) {
|
|
|
|
if (ptype->itype == itype) {
|
|
|
|
return ptype->level;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
|
2017-12-29 17:00:16 +01:00
|
|
|
void herbsearch(unit * u, int max_take)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-08-27 14:46:08 +02:00
|
|
|
region * r = u->region;
|
2015-01-30 20:37:14 +01:00
|
|
|
int herbsfound;
|
|
|
|
const item_type *whichherb;
|
2015-08-27 16:16:55 +02:00
|
|
|
int effsk = effskill(u, SK_HERBALISM, 0);
|
2017-12-29 17:00:16 +01:00
|
|
|
int herbs = rherbs(r);
|
2015-01-30 20:37:14 +01:00
|
|
|
|
2015-08-27 14:46:08 +02:00
|
|
|
if (effsk == 0) {
|
2015-01-30 20:37:14 +01:00
|
|
|
cmistake(u, u->thisorder, 59, MSG_PRODUCE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-31 07:45:06 +01:00
|
|
|
if (is_guarded(r, u)) {
|
2015-01-30 20:37:14 +01:00
|
|
|
cmistake(u, u->thisorder, 70, MSG_EVENT);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
whichherb = rherbtype(r);
|
|
|
|
if (whichherb == NULL) {
|
|
|
|
cmistake(u, u->thisorder, 108, MSG_PRODUCE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-12-29 17:00:16 +01:00
|
|
|
if (max_take < herbs) {
|
|
|
|
herbs = max_take;
|
|
|
|
}
|
2015-08-27 14:46:08 +02:00
|
|
|
herbsfound = ntimespprob(effsk * u->number,
|
2015-01-30 20:37:14 +01:00
|
|
|
(double)rherbs(r) / 100.0F, -0.01F);
|
2017-12-28 18:55:45 +01:00
|
|
|
|
2017-12-29 17:00:16 +01:00
|
|
|
if (herbsfound > herbs) herbsfound = herbs;
|
2018-01-21 11:14:55 +01:00
|
|
|
rsetherbs(r, rherbs(r) - herbsfound);
|
2015-01-30 20:37:14 +01:00
|
|
|
|
|
|
|
if (herbsfound) {
|
|
|
|
produceexp(u, SK_HERBALISM, u->number);
|
|
|
|
i_change(&u->items, whichherb, herbsfound);
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("herbfound",
|
|
|
|
"unit region amount herb", u, r, herbsfound, whichherb->rtype));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("researchherb_none",
|
2015-08-27 14:46:08 +02:00
|
|
|
"unit region", u, r));
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
static int begin_potion(unit * u, const item_type * itype, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-01-12 09:17:01 +01:00
|
|
|
static int config;
|
|
|
|
static bool rule_multipotion;
|
|
|
|
|
|
|
|
assert(itype);
|
|
|
|
if (config_changed(&config)) {
|
|
|
|
/* should we allow multiple different potions to be used the same turn? */
|
|
|
|
rule_multipotion = config_get_int("rules.magic.multipotion", 0) != 0;
|
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
|
|
|
|
if (!rule_multipotion) {
|
2018-01-12 09:17:01 +01:00
|
|
|
const item_type *use = ugetpotionuse(u);
|
|
|
|
if (use != NULL && use != itype) {
|
2015-01-30 20:37:14 +01:00
|
|
|
ADDMSG(&u->faction->msgs,
|
|
|
|
msg_message("errusingpotion", "unit using command",
|
2018-01-12 09:17:01 +01:00
|
|
|
u, use->rtype, ord));
|
2015-01-30 20:37:14 +01:00
|
|
|
return ECUSTOM;
|
|
|
|
}
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2015-01-30 20:37:14 +01:00
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
static void end_potion(unit * u, const item_type * itype, int amount)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-01-12 09:17:01 +01:00
|
|
|
usetpotionuse(u, itype);
|
2011-03-07 08:02:35 +01:00
|
|
|
|
2015-01-30 20:37:14 +01:00
|
|
|
ADDMSG(&u->faction->msgs, msg_message("usepotion",
|
2018-01-12 09:17:01 +01:00
|
|
|
"unit potion", u, itype->rtype));
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2015-11-22 14:36:05 +01:00
|
|
|
static int potion_water_of_life(unit * u, region *r, int amount) {
|
2016-09-11 12:48:00 +02:00
|
|
|
static int config;
|
|
|
|
static int tree_type, tree_count;
|
2015-11-22 14:28:15 +01:00
|
|
|
int wood = 0;
|
2016-09-11 12:48:00 +02:00
|
|
|
|
|
|
|
if (config_changed(&config)) {
|
|
|
|
tree_type = config_get_int("rules.magic.wol_type", 1);
|
|
|
|
tree_count = config_get_int("rules.magic.wol_effect", 10);
|
|
|
|
}
|
2015-11-22 14:28:15 +01:00
|
|
|
/* mallorn is required to make mallorn forests, wood for regular ones */
|
|
|
|
if (fval(r, RF_MALLORN)) {
|
2018-02-15 20:35:38 +01:00
|
|
|
wood = use_pooled(u, rt_find("mallorn"), GET_DEFAULT, tree_count * amount);
|
2015-11-22 14:28:15 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-02-15 20:35:38 +01:00
|
|
|
wood = use_pooled(u, rt_find("log"), GET_DEFAULT, tree_count * amount);
|
2015-11-22 14:28:15 +01:00
|
|
|
}
|
|
|
|
if (r->land == 0)
|
|
|
|
wood = 0;
|
|
|
|
if (wood < tree_count * amount) {
|
|
|
|
int x = wood / tree_count;
|
|
|
|
if (wood % tree_count)
|
|
|
|
++x;
|
|
|
|
if (x < amount)
|
|
|
|
amount = x;
|
|
|
|
}
|
|
|
|
rsettrees(r, tree_type, rtrees(r, tree_type) + wood);
|
|
|
|
ADDMSG(&u->faction->msgs, msg_message("growtree_effect",
|
|
|
|
"mage amount", u, wood));
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
void show_potions(faction *f, int sklevel)
|
|
|
|
{
|
|
|
|
const potion_type *ptype;
|
|
|
|
for (ptype = potiontypes; ptype; ptype = ptype->next) {
|
|
|
|
if (ptype->level > 0 && sklevel == ptype->level * 2) {
|
|
|
|
attrib *a = a_find(f->attribs, &at_showitem);
|
|
|
|
while (a && a->type == &at_showitem && a->data.v != ptype)
|
|
|
|
a = a->next;
|
|
|
|
if (a == NULL || a->type != &at_showitem) {
|
|
|
|
a = a_add(&f->attribs, a_new(&at_showitem));
|
|
|
|
a->data.v = (void *)ptype->itype;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-22 14:36:05 +01:00
|
|
|
static int potion_luck(unit *u, region *r, attrib_type *atype, int amount) {
|
2015-11-22 14:28:15 +01:00
|
|
|
attrib *a = (attrib *)a_find(r->attribs, atype);
|
2017-01-10 18:07:36 +01:00
|
|
|
UNUSED_ARG(u);
|
2015-11-22 14:28:15 +01:00
|
|
|
if (!a) {
|
|
|
|
a = a_add(&r->attribs, a_new(atype));
|
|
|
|
}
|
|
|
|
a->data.i += amount;
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int potion_power(unit *u, int amount) {
|
2017-12-29 17:00:16 +01:00
|
|
|
int hp = 10 * amount;
|
|
|
|
|
|
|
|
if (hp > u->number) {
|
|
|
|
hp = u->number;
|
|
|
|
amount = (hp + 9) % 10;
|
2015-11-22 14:28:15 +01:00
|
|
|
}
|
2017-12-29 17:00:16 +01:00
|
|
|
u->hp += hp * unit_max_hp(u) * 4;
|
2015-11-22 14:28:15 +01:00
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
2018-02-15 20:35:38 +01:00
|
|
|
static int heal(unit * user, int effect)
|
|
|
|
{
|
|
|
|
int req = unit_max_hp(user) * user->number - user->hp;
|
|
|
|
if (req > 0) {
|
|
|
|
if (req > effect) req = effect;
|
|
|
|
effect -= req;
|
|
|
|
user->hp += req;
|
|
|
|
}
|
|
|
|
return effect;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int potion_ointment(unit * u, int amount) {
|
|
|
|
int effect = amount * 400;
|
|
|
|
effect = heal(u, effect);
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int potion_healing(struct unit *user, int amount)
|
|
|
|
{
|
|
|
|
int effect = amount * 400;
|
|
|
|
unit *u = user->region->units;
|
|
|
|
effect = heal(user, effect);
|
|
|
|
while (effect > 0 && u != NULL) {
|
|
|
|
if (u->faction == user->faction) {
|
|
|
|
effect = heal(u, effect);
|
|
|
|
}
|
|
|
|
u = u->next;
|
|
|
|
}
|
|
|
|
return amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
static int do_potion(unit * u, region *r, const item_type * itype, int amount)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-15 20:35:38 +01:00
|
|
|
/* TODO: why do some of these take a region argument? */
|
2018-01-12 09:17:01 +01:00
|
|
|
if (itype == oldpotiontype[P_LIFE]) {
|
2015-11-22 14:36:05 +01:00
|
|
|
return potion_water_of_life(u, r, amount);
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
2018-01-12 09:17:01 +01:00
|
|
|
else if (itype == oldpotiontype[P_PEOPLE]) {
|
2015-11-22 14:36:05 +01:00
|
|
|
return potion_luck(u, r, &at_peasantluck, amount);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2018-01-12 09:17:01 +01:00
|
|
|
else if (itype == oldpotiontype[P_HORSE]) {
|
2015-11-22 14:36:05 +01:00
|
|
|
return potion_luck(u, r, &at_horseluck, amount);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2018-02-15 20:35:38 +01:00
|
|
|
else if (itype == oldpotiontype[P_HEAL]) {
|
|
|
|
return potion_healing(u, amount);
|
|
|
|
}
|
|
|
|
else if (itype == oldpotiontype[P_OINTMENT]) {
|
|
|
|
return potion_ointment(u, amount);
|
|
|
|
}
|
2018-01-12 09:17:01 +01:00
|
|
|
else if (itype == oldpotiontype[P_MACHT]) {
|
2015-11-22 14:28:15 +01:00
|
|
|
return potion_power(u, amount);
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
|
|
|
else {
|
2018-01-12 09:17:01 +01:00
|
|
|
change_effect(u, itype, 10 * amount);
|
2015-01-30 20:37:14 +01:00
|
|
|
}
|
|
|
|
return amount;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2011-03-07 08:02:35 +01:00
|
|
|
int use_potion(unit * u, const item_type * itype, int amount, struct order *ord)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-15 20:35:38 +01:00
|
|
|
int result = begin_potion(u, itype, ord);
|
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
amount = do_potion(u, u->region, itype, amount);
|
|
|
|
end_potion(u, itype, amount);
|
|
|
|
return amount;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************/
|
|
|
|
/* at_effect */
|
|
|
|
/*****************/
|
|
|
|
|
2018-02-09 21:20:43 +01:00
|
|
|
static void a_initeffect(variant *var)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-09 21:20:43 +01:00
|
|
|
var->v = calloc(sizeof(effect_data), 1);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-02-09 21:20:43 +01:00
|
|
|
a_writeeffect(const variant *var, const void *owner, struct storage *store)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2018-02-09 21:20:43 +01:00
|
|
|
effect_data *edata = (effect_data *)var->v;
|
2017-01-10 18:07:36 +01:00
|
|
|
UNUSED_ARG(owner);
|
2018-01-12 09:17:01 +01:00
|
|
|
WRITE_TOK(store, resourcename(edata->type->rtype, 0));
|
2015-01-30 20:37:14 +01:00
|
|
|
WRITE_INT(store, edata->value);
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2018-02-09 21:20:43 +01:00
|
|
|
static int a_readeffect(variant *var, void *owner, struct gamedata *data)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2016-02-13 13:42:02 +01:00
|
|
|
struct storage *store = data->store;
|
2015-01-30 20:37:14 +01:00
|
|
|
int power;
|
|
|
|
const resource_type *rtype;
|
2018-02-09 21:20:43 +01:00
|
|
|
effect_data *edata = (effect_data *)var->v;
|
2015-01-30 20:37:14 +01:00
|
|
|
char zText[32];
|
|
|
|
|
2017-01-10 18:07:36 +01:00
|
|
|
UNUSED_ARG(owner);
|
2015-01-30 20:37:14 +01:00
|
|
|
READ_TOK(store, zText, sizeof(zText));
|
|
|
|
rtype = rt_find(zText);
|
|
|
|
|
|
|
|
READ_INT(store, &power);
|
2018-01-12 09:17:01 +01:00
|
|
|
if (rtype == NULL || rtype->itype == NULL || power <= 0) {
|
2015-01-30 20:37:14 +01:00
|
|
|
return AT_READ_FAIL;
|
|
|
|
}
|
2018-01-12 09:17:01 +01:00
|
|
|
if (data->version < NOLANDITEM_VERSION) {
|
|
|
|
if (rtype->itype == oldpotiontype[P_HEAL]) {
|
|
|
|
/* healing potions used to have long-term effects */
|
|
|
|
return AT_READ_FAIL;
|
|
|
|
}
|
2016-06-17 21:49:31 +02:00
|
|
|
}
|
2018-01-12 09:17:01 +01:00
|
|
|
edata->type = rtype->itype;
|
2015-01-30 20:37:14 +01:00
|
|
|
edata->value = power;
|
|
|
|
return AT_READ_OK;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
attrib_type at_effect = {
|
2015-01-30 20:37:14 +01:00
|
|
|
"effect",
|
|
|
|
a_initeffect,
|
2018-02-09 21:20:43 +01:00
|
|
|
a_free_voidptr,
|
2015-01-30 20:37:14 +01:00
|
|
|
DEFAULT_AGE,
|
|
|
|
a_writeeffect,
|
|
|
|
a_readeffect,
|
2010-08-08 10:06:34 +02:00
|
|
|
};
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
int get_effect(const unit * u, const item_type * effect)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
const attrib *a;
|
|
|
|
for (a = a_find(u->attribs, &at_effect); a != NULL && a->type == &at_effect;
|
|
|
|
a = a->next) {
|
|
|
|
const effect_data *data = (const effect_data *)a->data.v;
|
|
|
|
if (data->type == effect)
|
|
|
|
return data->value;
|
|
|
|
}
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
|
|
|
|
2018-01-12 09:17:01 +01:00
|
|
|
int change_effect(unit * u, const item_type * effect, int delta)
|
2010-08-08 10:06:34 +02:00
|
|
|
{
|
2015-01-30 20:37:14 +01:00
|
|
|
if (delta != 0) {
|
|
|
|
attrib *a = a_find(u->attribs, &at_effect);
|
|
|
|
effect_data *data = NULL;
|
|
|
|
|
|
|
|
while (a && a->type == &at_effect) {
|
|
|
|
data = (effect_data *)a->data.v;
|
|
|
|
if (data->type == effect) {
|
|
|
|
if (data->value + delta == 0) {
|
|
|
|
a_remove(&u->attribs, a);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data->value += delta;
|
|
|
|
return data->value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a = a->next;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2011-03-07 08:02:35 +01:00
|
|
|
|
2015-01-30 20:37:14 +01:00
|
|
|
a = a_add(&u->attribs, a_new(&at_effect));
|
|
|
|
data = (effect_data *)a->data.v;
|
|
|
|
data->type = effect;
|
|
|
|
data->value = delta;
|
|
|
|
return data->value;
|
|
|
|
}
|
|
|
|
log_error("change effect with delta==0 for unit %s\n", itoa36(u->no));
|
|
|
|
return 0;
|
2010-08-08 10:06:34 +02:00
|
|
|
}
|
2018-01-12 10:01:06 +01:00
|
|
|
|
|
|
|
bool display_potions(struct unit *u)
|
|
|
|
{
|
|
|
|
int skill = effskill(u, SK_ALCHEMY, 0);
|
|
|
|
int c = 0;
|
|
|
|
const potion_type *ptype;
|
|
|
|
for (ptype = potiontypes; ptype != NULL; ptype = ptype->next) {
|
|
|
|
if (ptype->level * 2 <= skill) {
|
|
|
|
show_item(u, ptype->itype);
|
|
|
|
++c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (c > 0);
|
|
|
|
}
|