15 #define _GNU_SOURCE // strcasestr() is a GNU extension in string.h 44 if (!op || !victim || !roll)
50 if (op->type == PLAYER
51 && op->body_used[BODY_ARMS] <= 0
52 && op->body_info[BODY_ARMS]) {
54 "But you have no free hands to steal with!");
68 else if (op->invisible)
76 roll -= equip->weight/10000;
79 roll -= equip->weight/5000;
81 roll -= equip->weight/2000;
84 roll -= equip->weight/5000;
86 roll -= equip->weight/100;
112 object *success = NULL, *tmp = NULL;
113 int roll = 0, chance = 0, stats_value;
117 stats_value = ((who->stats.Dex+who->stats.Int)*3)/2;
128 "Your attempt is prevented!");
137 op->stats.Wis += (op->stats.Int/5)+1;
143 "You can't steal from the dungeon master!");
148 "You can't steal from other players!");
168 || inv->type == SPELL
180 chance =
adj_stealchance(who, op, stats_value+skill->level*10-op->level*3);
184 tag_t inv_count = inv->count;
192 if (object_was_destroyed(inv, inv_count) || inv->env != op) {
205 "%s%s has nothing you can steal!",
206 op->type == PLAYER ?
"" :
"The ", name);
215 if (roll >= skill->level
222 if (op->type != PLAYER) {
224 if (who->type == PLAYER) {
228 "%s notices your attempted pilfering!",
242 snprintf(buf,
sizeof(buf),
"Your %s is missing!", name);
244 snprintf(buf,
sizeof(buf),
"Your pack feels strangely lighter.");
249 if (who->invisible) {
250 snprintf(buf,
sizeof(buf),
"you feel itchy fingers getting at your pack.");
253 snprintf(buf,
sizeof(buf),
"%s looks very shifty.", name);
261 return success ? 1 : 0;
277 int steal(
object *op,
int dir,
object *skill) {
306 if (tmp->above == NULL)
323 if (tmp->type == PLAYER)
329 if (owner != NULL && owner->type == PLAYER)
354 int difficulty = pl->map->difficulty ? pl->map->difficulty : 0;
355 int success = 0, number;
363 if (door->inv && (door->inv->type == RUNE || door->inv->type == TRAP)) {
366 if (number < pl->stats.Dex + skill->level*2 - difficulty ) {
368 success = difficulty;
401 "There is no lock there.");
405 for (tmp =
GET_MAP_OB(pl->map, x, y); tmp; tmp = tmp->above)
406 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
411 "There is no lock there.");
418 if (tmp->type == LOCKED_DOOR) {
420 "You can't pick that lock!");
424 if (!tmp->move_block) {
426 "The door has no lock!");
434 "You fail to pick the lock.");
439 "You pick the lock.");
464 int number, difficulty = op->map->difficulty;
475 if (!
stand_near_hostile(op) && number < op->stats.Dex+skill->level+terrain-difficulty) {
476 op->invisible += 100;
477 if (op->type == PLAYER)
478 op->contr->tmp_invis = 1;
494 int hide(
object *op,
object *skill) {
500 "You don't need to hide while invisible!");
504 if (!op->hide && op->invisible > 0 && op->type == PLAYER) {
506 "Your attempt to hide breaks the invisibility spell!");
510 if (op->invisible > 50*skill->level) {
512 "You are as hidden as you can get.");
518 "You hide in the shadows.");
523 "You fail to conceal yourself.");
560 if (pl->contr && pl->contr->transport){
564 "Your bounce off the walls of %s.", trans_name);
589 for (i = 0; i <= spaces; i++) {
602 "Your jump is blocked.");
613 "You jump into %s%s.",
614 tmp->type == PLAYER ?
"" :
"the ", tmp->name);
617 if (tmp->type != PLAYER
618 || (pl->type == PLAYER && pl->contr->party == NULL)
619 || (pl->type == PLAYER && tmp->type == PLAYER && pl->contr->party != tmp->contr->party))
664 int jump(
object *
pl,
int dir,
object *skill) {
665 int spaces = 0, stats;
666 int str = pl->stats.Str;
667 int dex = pl->stats.Dex;
669 dex = dex ? dex : 15;
670 str = str ? str : 10;
672 stats = str*str*str*dex*skill->level;
674 if (pl->carrying != 0)
675 spaces = (int)(stats/pl->carrying);
681 else if (spaces == 0) {
683 "You are carrying too much weight to jump.");
704 && tmp->item_power < skill->level) {
752 && (
is_magical(tmp)) && tmp->item_power < skill->level) {
809 int success = 0, chance, ip;
810 int skill_value = (skill->level && pl->stats.Int) ? pl->stats.Int : 10;
814 if (tmp->item_power > ip)
815 ip = tmp->item_power;
818 for (
uint32_t i = 0; i < NROF(tmp); i++) {
820 if (skill_value >= chance) {
825 if (identified == 0) {
831 if (identified < NROF(tmp)) {
847 if (pl->type == PLAYER && print_on_success) {
855 "The item has a story:\n%s",
877 int success = 0, area, i;
881 if (tmp->type == obj_class)
890 if (skill->level > 64) {
892 }
else if (skill->level > 16) {
894 }
else if (skill->level > 4) {
900 for (i = 0; i < area; i++) {
912 if (tmp->type == obj_class)
931 int i, identifiable_types=0;
934 if (pl->type != PLAYER)
938 "You look at the objects nearby with your %s skill...", skill->name);
940 switch (skill->subtype) {
945 "...and discover cursed items!");
952 "...and discover items imbued with mystic forces!");
957 for (i=0; i<=OBJECT_TYPE_MAX; i++) {
962 identifiable_types++;
966 if (identifiable_types == 0) {
967 LOG(
llevError,
"Error: skill_ident() called with skill %d which can't identify any items\n", skill->subtype);
975 "...and learn nothing more.");
1006 if (pl->type != PLAYER)
1017 "There is nothing to orate to.");
1027 if (tmp2->type == PLAYER)
1032 if (value && strcmp(value,
"1") == 0)
1042 "There is nothing to orate to.");
1048 "You orate to the %s.",
1057 "Too bad the %s isn't listening!",
1066 "Your follower loves your speech.");
1070 if (skill->level > tmp->level) {
1077 "You convince the %s to follow you instead!",
1092 chance = skill->level*2+(pl->stats.Cha-2*tmp->stats.Int)/2;
1099 "You convince the %s to become your follower.",
1104 tmp->stats.exp /= 5;
1109 tmp->attack_movement =
PETMOVE;
1119 "Your speech angers the %s!",
1125 tmp->attack_movement = 0;
1154 int i, exp = 0, chance, mflags;
1161 if (pl->type != PLAYER)
1166 for (i = dir; i < (dir+
MIN(skill->level,
SIZEOFFREE)); i++) {
1185 if (tmp2->type == PLAYER) {
1199 && (tmp->level <= skill->level)
1207 chance = skill->level*2+(pl->stats.Cha-5-tmp->stats.Int)/2;
1210 if (value && strcmp(value,
"1") == 0)
1217 "You calm down the %s",
1227 "Too bad the %s isn't listening!",
1247 int i, expsum = 0, mflags;
1255 for (i = 0; i < 9; i++) {
1273 if (tmp2->type == RUNE || tmp2->type == TRAP)
1276 if (tmp2->stats.Cha > 1) {
1280 if (owner == NULL || owner->type != PLAYER)
1283 tmp2->stats.Cha = 1;
1288 if ((tmp->type == RUNE || tmp->type == TRAP) &&
trap_see(pl, tmp)) {
1290 if (tmp->stats.Cha > 1) {
1294 if (owner == NULL || owner->type != PLAYER)
1302 "You search the area.");
1318 int i, success = 0, mflags;
1322 for (i = 0; i < 9; i++) {
1340 if ((tmp2->type == RUNE || tmp2->type == TRAP) && tmp2->stats.Cha <= 1) {
1345 tmp2->stats.exp = tmp2->stats.Cha*tmp2->level;
1354 if ((tmp->type == RUNE || tmp->type == TRAP) && tmp->stats.Cha <= 1) {
1359 tmp->stats.exp = tmp->stats.Cha*tmp->level;
1393 if (pl->type != PLAYER)
1396 snprintf(buf,
sizeof(buf),
"You pray.");
1405 if (tmp->type == HOLY_ALTAR && tmp->other_arch) {
1406 snprintf(buf,
sizeof(buf),
"You pray over the %s.", tmp->name);
1415 if (pl->stats.grace < pl->stats.maxgrace) {
1417 pl->last_grace = -1;
1439 if (pl->type != PLAYER)
1445 "You can't concentrate while wielding a weapon!");
1450 if (((tmp->type == ARMOUR && skill->level < 12)
1451 || (tmp->type == HELMET && skill->level < 10)
1452 || (tmp->type == SHIELD && skill->level < 6)
1453 || (tmp->type == BOOTS && skill->level < 4)
1454 || (tmp->type == GLOVES && skill->level < 2))
1457 "You can't concentrate while wearing so much armour!");
1473 if (pl->stats.sp < pl->stats.maxsp) {
1476 }
else if (pl->stats.hp < pl->stats.maxhp) {
1497 object *newBook = NULL;
1500 if (!item || item->type != BOOK) {
1502 "That was interesting...");
1510 "Hmm... what was I going to write?");
1518 "Trying to cheat now are we?");
1533 snprintf(buf,
sizeof(buf),
"%s%s\n", item->msg, msg);
1535 snprintf(buf,
sizeof(buf),
"%s\n", msg);
1539 if (item->nrof > 1) {
1557 "You write in the %s.", buf);
1565 "Your message won't fit in the %s!", buf);
1585 int success = 0, confused = 0, grace_cost = 0;
1586 object *newscroll, *chosen_spell, *tmp;
1589 if (!scroll || scroll->type != SCROLL) {
1591 "A spell must be written on a magic scroll!");
1598 if (!chosen_spell) {
1600 "You should ready the spell you wish to inscribe.");
1606 if (grace_cost > 0 && grace_cost > pl->stats.grace) {
1609 "You don't have enough grace to write a scroll of %s.",
1610 chosen_spell->name);
1617 "You don't have enough mana to write a scroll of %s.",
1618 chosen_spell->name);
1623 if (chosen_spell->path_attuned & pl->path_denied
1630 "Just the idea of writing a scroll of %s makes you sick!",
1638 if ((scroll->stats.sp || scroll->inv) &&
1641 "Oops! You accidently read it while trying to write on it.");
1662 if (scroll->nrof > 1) {
1666 newscroll->nrof = 1;
1672 newscroll->level =
MAX(skill->level, chosen_spell->level);
1677 "You succeed in writing a new scroll.");
1680 if (!chosen_spell) {
1686 "In your confused state, you write down some odd spell.");
1689 if (newscroll->inv) {
1691 ninv = newscroll->inv;
1702 newscroll->path_attuned = tmp->path_repelled;
1706 newscroll->value = newscroll->arch->clone.value *
1707 newscroll->inv->value * (newscroll->level + 50 ) /
1708 (newscroll->inv->level + 50);
1709 newscroll->stats.exp = newscroll->value / 5;
1712 if (newscroll == scroll) {
1724 success = success * skill->level;
1729 if (chosen_spell->level > skill->level || confused) {
1732 "Ouch! Your attempt to write a new scroll strains your mind!");
1739 return -30 * chosen_spell->level;
1744 "Your attempt to write a new scroll rattles your mind!");
1749 "You fail to write a new scroll.");
1770 const char *
string = params;
1775 if (pl->type != PLAYER) {
1790 "You must learn to read before you can write!");
1797 "You are unable to write while blind.");
1802 if (
string[0] !=
'\0') {
1812 "You haven't marked any items to write on yet.");
1819 "You had better pay for that before you write on it!");
1824 if (msgtype != item->type) {
1827 "You must mark a %s to write %s.",
1828 msgtype == BOOK ?
"book" :
"magic scroll",
1829 msgtype == BOOK ?
"your message on" :
"your spell down");
1833 if (msgtype == BOOK) {
1835 }
else if (msgtype == SCROLL) {
1860 LOG(
llevError,
"find_throw_ob(): confused! have a NULL thrower!\n");
1861 return (
object *)NULL;
1877 if (tmp2->invisible)
1891 if (tmp2->race == race) {
1907 if (tmp->type != WEAPON) {
1910 "You can't throw %s.",
1917 "The %s sticks to your hand!",
1922 LOG(
llevError,
"BUG: find_throw_ob(): couldn't unapply\n");
1929 "You should pay for the %s first.",
1935 LOG(
llevError,
"BUG: find_throw_ob(): object is locked\n");
1960 LOG(
llevError,
"BUG: make_throw_ob(): ob is applied\n");
1965 toss_item->type = THROWN_OBJ;
1967 toss_item->stats.dam = 0;
1993 static int do_throw(
object *op,
object *part,
object *toss_item,
int dir,
object *skill) {
1994 object *throw_ob = toss_item, *left = NULL;
1995 int eff_str = 0, str = op->stats.Str, dam = 0;
1996 int pause_f, weight_f = 0, mflags;
1997 float str_factor = 1.0, load_factor = 1.0, item_factor = 1.0;
2003 if (throw_ob == NULL) {
2004 if (op->type == PLAYER) {
2006 "You have nothing to throw.");
2011 if (op->type == PLAYER) {
2013 "The gods won't let you throw that.");
2018 tag = throw_ob->count;
2020 if (object_was_destroyed(throw_ob, tag)) {
2036 if (op->type == PLAYER
2055 load_factor =
MIN(load_factor, 1.0f);
2059 if (throw_ob->weight > 0)
2064 "You can't throw %s.",
2069 eff_str = str*load_factor;
2070 eff_str = (float)eff_str*item_factor*str_factor;
2078 LOG(
llevDebug,
"%s carries %d, eff_str=%d\n", op->name, op->carrying, eff_str);
2081 LOG(
llevDebug,
" item %s weight= %d\n", throw_ob->name, throw_ob->weight);
2097 if (op->type == PLAYER) {
2101 "Your load is so heavy you drop %s to the ground.",
2106 "You throw %s at the ground.",
2110 "Something is in the way.");
2121 if (throw_ob == NULL) {
2127 if (throw_ob->type == POTION && throw_ob->subtype ==
POT_DUST) {
2138 throw_ob = toss_item;
2139 if (throw_ob->skill)
2153 throw_ob->direction = dir;
2161 throw_ob->last_sp = (eff_str*3)/5;
2165 throw_ob->speed =
MIN(1.0, throw_ob->speed);
2169 throw_ob->stats.dam += (dam/3)+
get_dam_bonus(weight_f)+(throw_ob->weight/15000)-2;
2172 throw_ob->stats.food = (dam/2)+(throw_ob->weight/60000);
2184 throw_ob->last_sp += eff_str/3;
2185 throw_ob->stats.dam += throw_ob->inv->stats.dam+throw_ob->magic+2;
2186 throw_ob->stats.wc -= throw_ob->magic+throw_ob->inv->stats.wc;
2193 throw_ob->stats.dam -= 1;
2194 throw_ob->stats.food -= 10;
2196 if (throw_ob->material&
M_GLASS)
2197 throw_ob->stats.food += 60;
2200 throw_ob->stats.dam -= 3;
2201 throw_ob->stats.food += 55;
2204 throw_ob->stats.dam -= 5;
2205 throw_ob->speed *= 0.8;
2206 throw_ob->stats.wc += 3;
2207 throw_ob->stats.food -= 30;
2210 if (throw_ob->weight > 500)
2211 throw_ob->speed *= 0.8;
2212 if (throw_ob->weight > 50)
2213 throw_ob->speed *= 0.5;
2217 if (throw_ob->stats.dam < 0)
2218 throw_ob->stats.dam = 0;
2219 if (throw_ob->last_sp > eff_str)
2220 throw_ob->last_sp = eff_str;
2221 if (throw_ob->stats.food < 0)
2222 throw_ob->stats.food = 0;
2223 if (throw_ob->stats.food > 100)
2224 throw_ob->stats.food = 100;
2225 if (throw_ob->stats.wc > 30)
2226 throw_ob->stats.wc = 30;
2229 pause_f = ((2*eff_str)/3)+20+skill->level;
2241 op->speed_left -= 50.0/pause_f;
2244 throw_ob->speed_left = 0;
2247 throw_ob->move_on = MOVE_FLY_LOW|
MOVE_WALK;
2251 LOG(
llevDebug,
" %s stats: wc=%d dam=%d dist=%d spd=%f break=%d\n", throw_ob->name, throw_ob->stats.wc, throw_ob->stats.dam, throw_ob->last_sp, throw_ob->speed, throw_ob->stats.food);
2252 LOG(
llevDebug,
"inserting tossitem (%d) into map\n", throw_ob->count);
2254 tag = throw_ob->count;
2256 if (!object_was_destroyed(throw_ob, tag))
2279 if (op->type == PLAYER)
2284 return do_throw(op, part, throw_ob, dir, skill);
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
void spring_trap(object *trap, object *victim)
int apply_special(object *who, object *op, int aflags)
static object * make_throw_ob(object *orig)
int apply_manual(object *op, object *tmp, int aflag)
void object_free(object *ob, int flags)
int64_t calc_skill_exp(const object *who, const object *op, const object *skill)
static int adj_stealchance(object *op, object *victim, int roll)
int is_magical(const object *op)
void remove_door(object *op)
#define FOR_OB_AND_ABOVE_PREPARE(op_)
static int attempt_jump(object *pl, int dir, int spaces, object *skill)
static int do_skill_ident(object *pl, int obj_class, object *skill)
int get_dam_bonus(int stat)
#define MSG_TYPE_ITEM_INFO
void cast_dust(object *op, object *throw_ob, int dir)
static int attempt_hide(object *op, object *skill)
static int do_skill_detect_magic(object *pl, object *skill)
void free_string(sstring str)
void esrv_update_item(int flags, object *pl, object *op)
const char * object_get_value(const object *op, const char *const key)
void pick_up(object *op, object *alt)
int check_pick(object *op)
short freearr_x[SIZEOFFREE]
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
#define MSG_TYPE_SKILL_MISSING
void meditate(object *pl, object *skill)
int pray(object *pl, object *skill)
#define MSG_TYPE_VICTIM_STEAL
int stand_near_hostile(object *who)
int singing(object *pl, int dir, object *skill)
method_ret ob_process(object *op)
#define MSG_TYPE_SKILL_ERROR
#define OUT_OF_REAL_MAP(M, X, Y)
int trap_disarm(object *disarmer, object *trap, int risk, object *skill)
void remove_friendly_object(object *op)
void object_update(object *op, int action)
#define MSG_TYPE_ITEM_REMOVE
uint32_t get_weight_limit(int stat)
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
#define FOR_OB_AND_BELOW_FINISH()
int pick_lock(object *pl, int dir, object *skill)
short freearr_y[SIZEOFFREE]
#define FLAG_KNOWN_MAGICAL
const typedata * get_typedata(int itemtype)
int rndm(int min, int max)
#define FREE_PLAYER_LOAD_PERCENT
void object_set_owner(object *op, object *owner)
int trap_show(object *trap, object *where)
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
sstring find_string(const char *str)
void object_update_turn_face(object *op)
void confuse_living(object *op, object *hitter, int dam)
static int do_throw(object *op, object *part, object *toss_item, int dir, object *skill)
int is_identified(const object *op)
object * object_new(void)
#define FOR_OB_AND_ABOVE_FINISH()
int object_can_pick(const object *who, const object *item)
object * object_insert_in_ob(object *op, object *where)
static object * find_throw_ob(object *op, sstring race)
int hide(object *op, object *skill)
#define FLAG_UNAGGRESSIVE
void monster_npc_call_help(object *op)
int remove_trap(object *op, object *skill)
void drain_specific_stat(object *op, int deplete_stats)
#define MSG_TYPE_ATTRIBUTE
int detect_curse_on_item(object *pl, object *tmp, object *skill)
static int write_note(object *pl, object *item, const char *msg)
int write_on_item(object *pl, const char *params, object *skill)
int die_roll(int num, int size, const object *op, int goodbad)
void add_friendly_object(object *op)
int steal(object *op, int dir, object *skill)
int detect_magic_on_item(object *pl, object *tmp, object *skill)
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
#define OB_TYPE_MOVE_BLOCK(ob1, type)
#define GET_MAP_MOVE_BLOCK(M, X, Y)
int trap_see(object *op, object *trap)
#define MSG_TYPE_SKILL_FAILURE
object * find_marked_object(object *op)
#define QUERY_FLAG(xyz, p)
#define CLEAR_FLAG(xyz, p)
static void stop_jump(object *pl)
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
int find_traps(object *pl, object *skill)
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
archetype * get_archetype_by_type_subtype(int type, int subtype)
static int attempt_pick_lock(object *door, object *pl, object *skill)
#define FLAG_READY_WEAPON
#define FLAG_KNOWN_CURSED
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
#define object_decrease_nrof_by_one(xyz)
void pray_at_altar(object *pl, object *altar, object *skill)
#define FREE_AND_COPY(sv, nv)
object * find_random_spell_in_ob(object *ob, const char *skill)
#define NUM_ANIMATIONS(ob)
static int write_scroll(object *pl, object *scroll, object *skill)
object * monster_find_throw_ob(object *op)
uint8_t no_player_stealing
static int do_skill_detect_curse(object *pl, object *skill)
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
object * object_merge(object *op, object *top)
void query_short_name(const object *op, char *buf, size_t size)
int hideability(object *ob)
#define FOR_OB_AND_BELOW_PREPARE(op_)
sstring add_string(const char *str)
object * identify(object *op)
#define GET_MAP_OB(M, X, Y)
void object_copy(const object *src_ob, object *dest_ob)
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
int use_oratory(object *pl, int dir, object *skill)
int skill_throw(object *op, object *part, int dir, object *skill)
void LOG(LogLevel logLevel, const char *format,...)
#define SCRIPT_FIX_ACTIVATOR
void make_visible(object *op)
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
static int attempt_steal(object *op, object *who, object *skill)
void object_set_msg(object *op, const char *msg)
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
#define MSG_TYPE_SKILL_SUCCESS
int jump(object *pl, int dir, object *skill)
void query_name(const object *op, char *buf, size_t size)
#define FOR_BELOW_PREPARE(op_, it_)
int allow_denied_spells_writing
int random_roll(int min, int max, const object *op, int goodbad)
#define MSG_TYPE_ATTRIBUTE_GOOD_EFFECT_END
#define FLAG_NO_SKILL_IDENT
int get_dex_bonus(int stat)
int skill_ident(object *pl, object *skill)
void fix_object(object *op)
object * find_skill_by_name(object *who, const char *name)
float get_speed_bonus(int stat)
void object_update_speed(object *op)
object * object_get_owner(object *op)
#define FOR_BELOW_FINISH()
#define FOR_INV_PREPARE(op_, it_)
void object_remove(object *op)
int get_thaco_bonus(int stat)