/* * $Id: handler.c 998 2007-01-21 21:23:49Z zsuzsu $ */ /*************************************************************************** * ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR * * ANATOLIA has been brought to you by ANATOLIA consortium * * Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr * * Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr * * Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr * * D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr * * By using this code, you have agreed to follow the terms of the * * ANATOLIA license, in the file Anatolia/anatolia.licence * ***************************************************************************/ /**************************************************************************r * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1995 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@pacinfo.com) * * Gabrielle Taylor (gtaylor@pacinfo.com) * * Brian Moore (rom@rom.efn.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include "merc.h" #include "debug.h" #include "obj_prog.h" #include "raffects.h" #include "fight.h" #include "quest.h" #include "db/db.h" #include "olc/olc.h" #include "db/lang.h" #include "waffects.h" #include "stats.h" DECLARE_DO_FUN(do_raffects); DECLARE_DO_FUN(do_return); DECLARE_DO_FUN(do_say); DECLARE_DO_FUN(do_track); DECLARE_DO_FUN(do_look); /* * Local functions. */ void affect_modify(CHAR_DATA * ch, AFFECT_DATA * paf, bool fAdd); int age_to_num(int age); int strip_from_container(CHAR_DATA * victim, OBJ_DATA * container, OBJ_INDEX_DATA * pObj); /* * Check if the character has met their tolerance for alchohol * tolerance is affected by con, race, size and the drinking skill * * returns * PC: TRUE if tolerance is exceeded * NPC: TRUE if affected by intoxication * * by Zsuzsu */ bool is_drunk(CHAR_DATA * ch) { if (IS_NPC(ch)) return is_affected(ch, gsn_intoxication); return ch->pcdata->condition[COND_DRUNK] > drunk_tolerance(ch); } int drunk_tolerance(CHAR_DATA * ch) { int tolerance = 10; if (IS_NPC(ch)) return is_affected(ch, gsn_intoxication); tolerance += UMAX(-3, ((get_curr_stat(ch, STAT_CON) - 50) / 2)); switch (ch->race) { case RACE_DWARF: case RACE_DUERGAR: tolerance += 10; break; } switch (ch->size) { case SIZE_TINY: tolerance -= 5; break; case SIZE_SMALL: tolerance -= 3; break; case SIZE_LARGE: tolerance += 5; break; case SIZE_HUGE: tolerance += 10; break; case SIZE_GIANT: tolerance += 15; break; case SIZE_GARGANTUAN: tolerance += 30; break; case SIZE_MEDIUM: default: tolerance += 0; } tolerance += get_skill(ch, gsn_drinking) / 3; tolerance = URANGE(2, tolerance, 95); return tolerance; } /* friend stuff -- for NPC's mostly */ bool is_friend(CHAR_DATA * ch, CHAR_DATA * victim) { flag64_t off; if (is_same_group(ch, victim)) return TRUE; if (!IS_NPC(ch)) return FALSE; off = ch->pIndexData->off_flags; if (!IS_NPC(victim)) { if (IS_SET(off, ASSIST_PLAYERS)) return TRUE; else return FALSE; } if (IS_AFFECTED(ch, AFF_CHARM)) return FALSE; if (IS_SET(off, ASSIST_ALL)) return TRUE; if (ch->group && ch->group == victim->group) return TRUE; if (IS_SET(off, ASSIST_VNUM) && ch->pIndexData == victim->pIndexData) return TRUE; if (IS_SET(off, ASSIST_RACE) && ch->race == victim->race) return TRUE; if (IS_SET(off, ASSIST_ALIGN) && !IS_SET(ch->pIndexData->act, ACT_NOALIGN) && !IS_SET(victim->pIndexData->act, ACT_NOALIGN) && ((IS_GOOD(ch) && IS_GOOD(victim)) || (IS_EVIL(ch) && IS_EVIL(victim)) || (IS_NEUTRAL(ch) && IS_NEUTRAL(victim)))) return TRUE; return FALSE; } /* * Room record: * For less than 5 people in room create a new record. * Else use the oldest one. */ void room_record(const char *name, ROOM_INDEX_DATA * room, int door) { ROOM_HISTORY_DATA *rec; int i; for (i = 0, rec = room->history; i < 5 && rec != NULL; i++, rec = rec->next); if (i < 5) { rec = calloc(1, sizeof(*rec)); rec->next = room->history; if (rec->next != NULL) rec->next->prev = rec; room->history = rec; rec->name = NULL; } else { rec = room->history->next->next->next->next; rec->prev->next = NULL; rec->next = room->history; rec->next->prev = rec; room->history = rec; } rec->prev = NULL; if (rec->name) { free_string(rec->name); } rec->name = str_dup(name); rec->went = door; } /* returns number of people on an object */ int count_users(OBJ_DATA * obj) { CHAR_DATA *fch; int count = 0; if (obj->in_room == NULL) return 0; for (fch = obj->in_room->people; fch != NULL; fch = fch->next_in_room) if (fch->on == obj) count++; return count; } int floating_time(OBJ_DATA * obj) { int ftime; ftime = 0; switch (obj->pIndexData->item_type) { default: break; case ITEM_KEY: ftime = 1; break; case ITEM_ARMOR: ftime = 2; break; case ITEM_TREASURE: ftime = 2; break; case ITEM_PILL: ftime = 2; break; case ITEM_POTION: ftime = 3; break; case ITEM_TRASH: ftime = 3; break; case ITEM_FOOD: ftime = 4; break; case ITEM_CONTAINER: ftime = 5; break; case ITEM_CORPSE_NPC: ftime = 10; break; case ITEM_CORPSE_PC: ftime = 10; break; } ftime = number_fuzzy(ftime); return (ftime < 0 ? 0 : ftime); } /* for immunity, vulnerabiltiy, and resistant the 'globals' (magic and weapons) may be overriden three other cases -- wood, silver, and iron -- are checked in fight.c */ int check_immune(CHAR_DATA * ch, int dam_type) { int immune, def; int bit; immune = -1; def = IS_NORMAL; if (dam_type == DAM_NONE) return immune; if (dam_type <= 3) { if (IS_SET(ch->imm_flags, IMM_WEAPON)) def = IS_IMMUNE; else if (IS_SET(ch->res_flags, RES_WEAPON)) def = IS_RESISTANT; else if (IS_SET(ch->vuln_flags, VULN_WEAPON)) def = IS_VULNERABLE; } else { /* magical attack */ if (IS_SET(ch->imm_flags, IMM_MAGIC)) def = IS_IMMUNE; else if (IS_SET(ch->res_flags, RES_MAGIC)) def = IS_RESISTANT; else if (IS_SET(ch->vuln_flags, VULN_MAGIC)) def = IS_VULNERABLE; } /* set bits to check -- VULN etc. must ALL be the same or this will fail */ switch (dam_type) { case (DAM_BASH): bit = IMM_BASH; break; case (DAM_PIERCE): bit = IMM_PIERCE; break; case (DAM_SLASH): bit = IMM_SLASH; break; case (DAM_FIRE): bit = IMM_FIRE; break; case (DAM_COLD): bit = IMM_COLD; break; case (DAM_LIGHTNING): bit = IMM_LIGHTNING; break; case (DAM_ACID): bit = IMM_ACID; break; case (DAM_POISON): bit = IMM_POISON; break; case (DAM_NEGATIVE): bit = IMM_NEGATIVE; break; case (DAM_HOLY): bit = IMM_HOLY; break; case (DAM_ENERGY): bit = IMM_ENERGY; break; case (DAM_MENTAL): if (IS_IMMORTAL(ch)) return IS_IMMUNE; bit = IMM_MENTAL; break; case (DAM_DISEASE): bit = IMM_DISEASE; break; case (DAM_DROWNING): bit = IMM_DROWNING; break; case (DAM_LIGHT): bit = IMM_LIGHT; break; case (DAM_CHARM): if (IS_IMMORTAL(ch)) return IS_IMMUNE; bit = IMM_CHARM; break; case (DAM_SOUND): bit = IMM_SOUND; break; default: return def; } if (IS_SET(ch->imm_flags, bit)) immune = IS_IMMUNE; else if (IS_SET(ch->res_flags, bit) && immune != IS_IMMUNE) immune = IS_RESISTANT; else if (IS_SET(ch->vuln_flags, bit)) { if (immune == IS_IMMUNE) immune = IS_RESISTANT; else if (immune == IS_RESISTANT) immune = IS_NORMAL; else immune = IS_VULNERABLE; } if (!IS_NPC(ch) && get_curr_stat(ch, STAT_CHA) < 45 && dam_type == DAM_CHARM) immune = IS_VULNERABLE; if (immune == -1) return def; else return immune; } void reset_obj_affects(CHAR_DATA * ch, OBJ_DATA * obj, AFFECT_DATA * af) { for (; af != NULL; af = af->next) { int mod = af->modifier; switch (af->location) { case APPLY_MANA: ch->max_mana -= mod; break; case APPLY_HIT: ch->max_hit -= mod; break; case APPLY_MOVE: ch->max_move -= mod; break; } } } /* used to de-screw characters */ void reset_char(CHAR_DATA * ch) { int loc, mod, stat; OBJ_DATA *obj; AFFECT_DATA *af; int i; if (IS_NPC(ch)) return; if (ch->pcdata->perm_hit == 0 || ch->pcdata->perm_mana == 0 || ch->pcdata->perm_move == 0 || ch->pcdata->last_level == 0) { /* do a FULL reset */ for (loc = 0; loc < MAX_WEAR; loc++) { obj = get_eq_char(ch, loc); if (obj == NULL) continue; if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) reset_obj_affects(ch, obj, obj->pIndexData->affected); reset_obj_affects(ch, obj, obj->affected); } /* now reset the permanent stats */ ch->pcdata->perm_hit = ch->max_hit; ch->pcdata->perm_mana = ch->max_mana; ch->pcdata->perm_move = ch->max_move; ch->pcdata->last_level = ch->played / 3600; if (ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2) { if (ch->sex > 0 && ch->sex < 3) ch->pcdata->true_sex = ch->sex; else ch->pcdata->true_sex = 0; } } /* now restore the character to his/her true condition */ for (stat = 0; stat < MAX_STATS; stat++) ch->mod_stat[stat] = 0; if (ch->pcdata->true_sex < 0 || ch->pcdata->true_sex > 2) ch->pcdata->true_sex = 0; ch->sex = ch->pcdata->true_sex; ch->max_hit = ch->pcdata->perm_hit; ch->max_mana = ch->pcdata->perm_mana; ch->max_move = ch->pcdata->perm_move; for (i = 0; i < 4; i++) ch->armor[i] = 100; ch->hitroll = 0; ch->damroll = 0; ch->saving_throw = 0; ch->drain_level = 0; /* now start adding back the effects */ for (loc = 0; loc < MAX_WEAR; loc++) { obj = get_eq_char(ch, loc); if (obj == NULL) continue; for (i = 0; i < 4; i++) ch->armor[i] -= apply_ac(ch, obj, loc, i); if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) for (af = obj->pIndexData->affected; af != NULL; af = af->next) { mod = af->modifier; switch (af->location) { case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break; case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break; case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break; case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break; case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break; case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break; case APPLY_LCK: ch->mod_stat[STAT_LCK] += mod; break; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_AGE: ch->played += age_to_num(mod); break; case APPLY_AC: for (i = 0; i < 4; i++) ch->armor[i] += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_SIZE: ch->size += mod; break; case APPLY_LEVEL: ch->drain_level += mod; break; case APPLY_SAVES: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; } } for (af = obj->affected; af != NULL; af = af->next) { mod = af->modifier; switch (af->location) { case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break; case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break; case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break; case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break; case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break; case APPLY_LCK: ch->mod_stat[STAT_LCK] += mod; break; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_AGE: ch->played += age_to_num(mod); break; case APPLY_AC: for (i = 0; i < 4; i++) ch->armor[i] += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_SIZE: ch->size += mod; break; case APPLY_LEVEL: ch->drain_level += mod; break; case APPLY_SAVES: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; } } } /* now add back spell effects */ for (af = ch->affected; af != NULL; af = af->next) { mod = af->modifier; switch (af->location) { case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break; case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break; case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break; case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break; case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break; case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break; case APPLY_LCK: ch->mod_stat[STAT_LCK] += mod; break; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_AC: for (i = 0; i < 4; i++) ch->armor[i] += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_SIZE: ch->size += mod; break; case APPLY_LEVEL: ch->drain_level += mod; break; case APPLY_SAVES: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; } } /* make sure sex is RIGHT! */ if (ch->sex < 0 || ch->sex > 2) ch->sex = ch->pcdata->true_sex; } /* * Retrieve a character's age. */ int get_age(CHAR_DATA * ch) { return !IS_NPC(ch) ? race_lookup(ch->race)->pcdata->age_modifier + (ch->played + (int) (current_time - ch->logon)) / 72000 : 42; } int age_to_num(int age) { return age * 72000; } /* * Retrieve a character's carry capacity. */ int can_carry_n(CHAR_DATA * ch) { if (IS_IMMORTAL(ch)) return 1000; if (IS_NPC(ch) && IS_SET(ch->pIndexData->act, ACT_PET) && !IS_SET(ch->pIndexData->attr_flags, MOB_ATTR_PET_ARMORED) && !IS_SET(ch->pIndexData->attr_flags, MOB_ATTR_PET_WEAPONED)) return 0; return MAX_WEAR + get_curr_stat(ch, STAT_DEX)/4 - 10 + ch->size; } /*--------------------------------------------------------------------------- * name list stuff * * name list is simply string of names * separated by spaces. if name contains spaces itself it is enclosed * in single quotes * */ /* * See if a string is one of the names of an object. */ bool is_name_raw(const char *str, const char *namelist, int (*cmpfun) (const char *, const char *)) { char name[MAX_INPUT_LENGTH], part[MAX_INPUT_LENGTH]; const char *list, *string; if (IS_NULLSTR(namelist) || IS_NULLSTR(str)) return FALSE; if (!str_cmp(namelist, "all")) return TRUE; string = str; /* we need ALL parts of string to match part of namelist */ for (;;) { /* start parsing string */ str = one_argument(str, part, sizeof(part)); if (part[0] == '\0') return TRUE; /* check to see if this is part of namelist */ list = namelist; for (;;) { /* start parsing namelist */ list = one_argument(list, name, sizeof(name)); if (name[0] == '\0') /* this name was not found */ return FALSE; if (!cmpfun(string, name)) return TRUE; /* full pattern match */ if (!cmpfun(part, name)) break; } } } bool is_name(const char *str, const char *namelist) { return is_name_raw(str, namelist, str_prefix); } void cat_name(char *buf, const char *name, size_t len) { bool have_spaces = strpbrk(name, " \t") != NULL; if (buf[0]) strnzcat(buf, len, " "); if (have_spaces) strnzcat(buf, len, "'"); strnzcat(buf, len, name); if (have_spaces) strnzcat(buf, len, "'"); } /* * name_edit flags */ #define NE_F_DELETE (A) /* delete name if found */ #define NE_F_ADD (B) /* add name if not found */ /* * name_edit - edit 'name' according to 'flags' in name list pointed by 'nl' * if ch == NULL name_edit will be silent * (and 'editor_name' is not used) * Return values: TRUE - name was found in namelist * FALSE - name was not found * */ bool name_edit(const char **nl, const char *name, int flags, CHAR_DATA * ch, const char *editor_name) { bool found = FALSE; const char *p = *nl; char buf[MAX_STRING_LENGTH]; if (name == NULL || name[0] == '\0') return FALSE; buf[0] = '\0'; for (;;) { char arg[MAX_STRING_LENGTH]; p = first_arg(p, arg, sizeof(arg), FALSE); if (arg[0] == '\0') break; if (!str_cmp(name, arg)) { found = TRUE; if (IS_SET(flags, NE_F_DELETE)) continue; } cat_name(buf, arg, sizeof(buf)); } if (!found) { if (!IS_SET(flags, NE_F_ADD)) return found; if (strlen(buf) + strlen(name) + 4 > MAX_STRING_LENGTH) { if (ch) char_printf(ch, "%s: name list too long\n", editor_name); return found; } cat_name(buf, name, sizeof(buf)); if (ch) char_printf(ch, "%s: %s: name added.\n", editor_name, name); } else { if (!IS_SET(flags, NE_F_DELETE)) return found; if (ch) char_printf(ch, "%s: %s: name removed.\n", editor_name, name); } free_string(*nl); *nl = str_dup(buf); return found; } bool name_add(const char **nl, const char *name, CHAR_DATA * ch, const char *editor_name) { return name_edit(nl, name, NE_F_ADD, ch, editor_name); } bool is_name_empty(const char *nl) { return nl == NULL || nl[0] == '\0'; } bool name_find(const char *nl, const char *name) { bool found = FALSE; const char *p = nl; char buf[MAX_STRING_LENGTH]; if (name == NULL || name[0] == '\0') return FALSE; buf[0] = '\0'; for (;;) { char arg[MAX_STRING_LENGTH]; p = first_arg(p, arg, sizeof(arg), FALSE); if (arg[0] == '\0') break; if (!str_cmp(name, arg)) { found = TRUE; } /* cat_name(buf, arg, sizeof(buf)); */ } return found; } bool name_transfer(const char **src, const char **dest) { char name[MAX_STRING_LENGTH]; bool found = FALSE; *src = first_arg(*src, name, sizeof(name), FALSE); for (; name[0]; *src = first_arg(*src, name, sizeof(name), FALSE)) { name_add(dest, name, NULL, NULL); name_delete(src, name, NULL, NULL); found = TRUE; } return found; } bool name_delete(const char **nl, const char *name, CHAR_DATA * ch, const char *editor_name) { return name_edit(nl, name, NE_F_DELETE, ch, editor_name); } bool name_toggle(const char **nl, const char *name, CHAR_DATA * ch, const char *editor_name) { if (!str_cmp(name, "all")) { free_string(*nl); *nl = str_dup(name); if (ch) char_printf(ch, "%s: name list set to ALL.\n", editor_name); return TRUE; } if (!str_cmp(name, "none")) { free_string(*nl); *nl = str_empty; if (ch) char_printf(ch, "%s: name list reset.\n", editor_name); return TRUE; } if (!str_cmp(*nl, "all")) { free_string(*nl); *nl = str_empty; } return name_edit(nl, name, NE_F_ADD | NE_F_DELETE, ch, editor_name); } /* enchanted stuff for eq */ void affect_enchant(OBJ_DATA * obj) { /* okay, move all the old flags into new vectors if we have to */ if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) { AFFECT_DATA *paf, *af_new; SET_BIT(obj->extra_flags, ITEM_ENCHANTED); for (paf = obj->pIndexData->affected; paf != NULL; paf = paf->next) { af_new = aff_new(); af_new->next = obj->affected; obj->affected = af_new; af_new->where = paf->where; af_new->type = UMAX(0, paf->type); af_new->level = paf->level; af_new->duration = paf->duration; af_new->location = paf->location; af_new->modifier = paf->modifier; af_new->bitvector = paf->bitvector; } } } /* * Apply or remove an affect to a character. */ void affect_modify(CHAR_DATA * ch, AFFECT_DATA * paf, bool fAdd) { OBJ_DATA *wield, *obj2; int mod, i; mod = paf->modifier; if (fAdd) { switch (paf->where) { case TO_AFFECTS: SET_BIT(ch->affected_by, paf->bitvector); break; case TO_IMMUNE: SET_BIT(ch->imm_flags, paf->bitvector); break; case TO_RESIST: SET_BIT(ch->res_flags, paf->bitvector); break; case TO_VULN: SET_BIT(ch->vuln_flags, paf->bitvector); break; } } else { switch (paf->where) { case TO_AFFECTS: REMOVE_BIT(ch->affected_by, paf->bitvector); break; case TO_IMMUNE: REMOVE_BIT(ch->imm_flags, paf->bitvector); break; case TO_RESIST: REMOVE_BIT(ch->res_flags, paf->bitvector); break; case TO_VULN: REMOVE_BIT(ch->vuln_flags, paf->bitvector); break; } mod = 0 - mod; } switch (paf->location) { case APPLY_NONE: case APPLY_CLASS: case APPLY_HEIGHT: case APPLY_WEIGHT: case APPLY_GOLD: case APPLY_EXP: case APPLY_SEX: case APPLY_SPELL_AFFECT: break; case APPLY_STR: ch->mod_stat[STAT_STR] += mod; break; case APPLY_DEX: ch->mod_stat[STAT_DEX] += mod; break; case APPLY_INT: ch->mod_stat[STAT_INT] += mod; break; case APPLY_WIS: ch->mod_stat[STAT_WIS] += mod; break; case APPLY_CON: ch->mod_stat[STAT_CON] += mod; break; case APPLY_CHA: ch->mod_stat[STAT_CHA] += mod; break; case APPLY_LCK: ch->mod_stat[STAT_LCK] += mod; break; case APPLY_MANA: ch->max_mana += mod; break; case APPLY_HIT: ch->max_hit += mod; break; case APPLY_MOVE: ch->max_move += mod; break; case APPLY_HITROLL: ch->hitroll += mod; break; case APPLY_DAMROLL: ch->damroll += mod; break; case APPLY_LEVEL: ch->drain_level += mod; break; case APPLY_SIZE: ch->size += mod; break; case APPLY_AGE: ch->played += age_to_num(mod); break; case APPLY_AC: for (i = 0; i < 4; i++) ch->armor[i] += mod; break; case APPLY_SAVES: ch->saving_throw += mod; break; case APPLY_SAVING_ROD: ch->saving_throw += mod; break; case APPLY_SAVING_PETRI: ch->saving_throw += mod; break; case APPLY_SAVING_BREATH: ch->saving_throw += mod; break; case APPLY_SAVING_SPELL: ch->saving_throw += mod; break; case APPLY_RACE:{ int from; int to; race_t *rto; race_t *rfrom; if (fAdd) { from = ORG_RACE(ch); to = ch->race = paf->modifier; } else { from = ch->race; to = ch->race = ORG_RACE(ch); } rfrom = race_lookup(from); rto = race_lookup(to); if (!rfrom || !rto || !rfrom->pcdata || !rto->pcdata) return; REMOVE_BIT(ch->affected_by, rfrom->aff); SET_BIT(ch->affected_by, rto->aff); affect_check(ch, TO_AFFECTS, rfrom->aff); REMOVE_BIT(ch->imm_flags, rfrom->imm); SET_BIT(ch->imm_flags, rto->imm); affect_check(ch, TO_IMMUNE, rfrom->imm); REMOVE_BIT(ch->res_flags, rfrom->res); SET_BIT(ch->res_flags, rto->res); affect_check(ch, TO_RESIST, rfrom->res); REMOVE_BIT(ch->vuln_flags, rfrom->vuln); SET_BIT(ch->vuln_flags, rto->vuln); affect_check(ch, TO_VULN, rfrom->vuln); ch->form = rto->form; ch->parts = rto->parts; ch->size = rto->pcdata->size; update_skills(ch); break; } default: if (IS_NPC(ch)) { log_printf("affect_modify: vnum %d: in room %d: " "unknown location %d.", ch->pIndexData->vnum, ch->in_room ? ch->in_room->vnum : -1, paf->location); } else { log_printf("affect_modify: %s: unknown location %d.", ch->name, paf->location); } return; } /* * Check for weapon wielding. * Guard against recursion (for weapons with affects). */ if (!IS_NPC(ch) && (wield = get_eq_char(ch, WEAR_WIELD)) != NULL && get_obj_weight(wield) > (get_stat_str_max_wield_weight(ch, HAND_PRIMARY))) { static int depth; if (depth == 0) { depth++; act("You drop $p.", ch, wield, NULL, TO_CHAR); act("$n drops $p.", ch, wield, NULL, TO_ROOM); obj_from_char(wield); obj_to_room(wield, ch->in_room); if ((obj2 = get_eq_char(ch, WEAR_SECOND_WIELD)) != NULL) { act("You wield his second weapon as your first!", ch, NULL, NULL, TO_CHAR); act("$n wields his second weapon as first!", ch, NULL, NULL, TO_ROOM); unequip_char(ch, obj2); equip_char(ch, obj2, WEAR_WIELD); } depth--; } } } /* find an effect in an affect list */ AFFECT_DATA *affect_find(AFFECT_DATA * paf, int sn) { AFFECT_DATA *paf_find; for (paf_find = paf; paf_find != NULL; paf_find = paf_find->next) { if (paf_find->type == sn) return paf_find; } return NULL; } AFFECT_DATA *affect_find_most_powerful(AFFECT_DATA * paf, int sn) { AFFECT_DATA *paf_find; AFFECT_DATA *paf_highest = NULL; for (paf_find = paf; paf_find != NULL; paf_find = paf_find->next) { if (paf_find->type == sn) { if (paf_highest && paf_highest->level > paf_find->level) continue; else paf_highest = paf_find; } } return paf_highest; } void affect_check_list(CHAR_DATA * ch, AFFECT_DATA * paf, int where, flag64_t vector) { for (; paf; paf = paf->next) if ((where < 0 || paf->where == where) && (paf->bitvector & vector)) switch (paf->where) { case TO_AFFECTS: SET_BIT(ch->affected_by, paf->bitvector); break; case TO_IMMUNE: SET_BIT(ch->imm_flags, paf->bitvector); break; case TO_RESIST: SET_BIT(ch->res_flags, paf->bitvector); break; case TO_VULN: SET_BIT(ch->vuln_flags, paf->bitvector); break; } } /* fix object affects when removing one */ void affect_check(CHAR_DATA * ch, int where, flag64_t vector) { OBJ_DATA *obj; if (where == TO_OBJECT || where == TO_WEAPON || vector == 0) return; affect_check_list(ch, ch->affected, where, vector); for (obj = ch->carrying; obj != NULL; obj = obj->next_content) { if (obj->wear_loc == -1 || obj->wear_loc == WEAR_STUCK_IN) continue; affect_check_list(ch, obj->affected, where, vector); if (IS_SET(obj->extra_flags, ITEM_ENCHANTED)) continue; affect_check_list(ch, obj->pIndexData->affected, where, vector); } } /* * Give an affect to a char. */ void affect_to_char(CHAR_DATA * ch, AFFECT_DATA * paf) { AFFECT_DATA *paf_new; paf_new = aff_new(); *paf_new = *paf; paf_new->next = ch->affected; ch->affected = paf_new; affect_modify(ch, paf_new, TRUE); } /* give an affect to an object */ void affect_to_obj(OBJ_DATA * obj, AFFECT_DATA * paf) { AFFECT_DATA *paf_new; paf_new = aff_new(); *paf_new = *paf; paf_new->next = obj->affected; obj->affected = paf_new; /* apply any affect vectors to the object's extra_flags */ if (paf->bitvector) switch (paf->where) { case TO_OBJECT: SET_BIT(obj->extra_flags, paf->bitvector); break; case TO_WEAPON: if (obj->pIndexData->item_type == ITEM_WEAPON) SET_BIT(obj->value[ITEM_WEAPON_FLAGS], paf->bitvector); break; } } /* * Remove an affect from a char. */ void affect_remove(CHAR_DATA * ch, AFFECT_DATA * paf) { int where; int vector; if (ch->affected == NULL) { bug("Affect_remove: no affect.", 0); return; } affect_modify(ch, paf, FALSE); where = paf->where; vector = paf->bitvector; if (paf == ch->affected) ch->affected = paf->next; else { AFFECT_DATA *prev; for (prev = ch->affected; prev; prev = prev->next) { if (prev->next == paf) { prev->next = paf->next; break; } } if (prev == NULL) { bug("Affect_remove: cannot find paf.", 0); return; } } aff_free(paf); affect_check(ch, where, vector); } void affect_remove_obj(OBJ_DATA * obj, AFFECT_DATA * paf) { int where, vector; if (obj->affected == NULL) return; if (obj->carried_by != NULL && obj->wear_loc != -1) affect_modify(obj->carried_by, paf, FALSE); where = paf->where; vector = paf->bitvector; /* remove flags from the object if needed */ if (paf->bitvector) switch (paf->where) { case TO_OBJECT: REMOVE_BIT(obj->extra_flags, paf->bitvector); break; case TO_WEAPON: if (obj->pIndexData->item_type == ITEM_WEAPON) REMOVE_BIT(obj->value[ITEM_WEAPON_FLAGS], paf->bitvector); break; } if (paf == obj->affected) obj->affected = paf->next; else { AFFECT_DATA *prev; for (prev = obj->affected; prev != NULL; prev = prev->next) { if (prev->next == paf) { prev->next = paf->next; break; } } if (prev == NULL) { bug("Affect_remove_object: cannot find paf.", 0); return; } } aff_free(paf); if (obj->carried_by != NULL && obj->wear_loc != -1) affect_check(obj->carried_by, where, vector); } /* * Strip all affects of a given sn. */ void affect_strip(CHAR_DATA * ch, int sn) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; for (paf = ch->affected; paf; paf = paf_next) { paf_next = paf->next; if (paf->type == sn) affect_remove(ch, paf); } } /* * strip all affects which affect given bitvector */ void affect_bit_strip(CHAR_DATA * ch, int where, flag64_t bits) { AFFECT_DATA *paf; AFFECT_DATA *paf_next; for (paf = ch->affected; paf; paf = paf_next) { paf_next = paf->next; if (paf->where == where && (paf->bitvector & bits)) affect_remove(ch, paf); } } /* * Return true if a char is affected by a spell. */ bool is_affected(CHAR_DATA * ch, int sn) { AFFECT_DATA *paf; for (paf = ch->affected; paf; paf = paf->next) if (paf->type == sn) return TRUE; return FALSE; } bool is_bit_affected(CHAR_DATA * ch, int where, flag64_t bits) { AFFECT_DATA *paf; for (paf = ch->affected; paf; paf = paf->next) if (paf->where == where && (paf->bitvector & bits)) return TRUE; return FALSE; } bool has_obj_affect(CHAR_DATA * ch, int vector) { OBJ_DATA *obj; for (obj = ch->carrying; obj; obj = obj->next_content) { AFFECT_DATA *paf; if (obj->wear_loc == -1 || obj->wear_loc == WEAR_STUCK_IN) continue; for (paf = obj->affected; paf; paf = paf->next) if (paf->bitvector & vector) return TRUE; if (IS_SET(obj->extra_flags, ITEM_ENCHANTED)) continue; for (paf = obj->pIndexData->affected; paf; paf = paf->next) if (paf->bitvector & vector) return TRUE; } return FALSE; } /* * Add or enhance an affect. */ void affect_join(CHAR_DATA * ch, AFFECT_DATA * paf) { AFFECT_DATA *paf_old; bool found; found = FALSE; for (paf_old = ch->affected; paf_old != NULL; paf_old = paf_old->next) { if (paf_old->type == paf->type) { paf->level = (paf->level += paf_old->level) / 2; paf->duration += paf_old->duration; paf->modifier += paf_old->modifier; affect_remove(ch, paf_old); break; } } affect_to_char(ch, paf); return; } /* * Move a char out of a room. */ void char_from_room(CHAR_DATA * ch) { OBJ_DATA *obj; ROOM_INDEX_DATA *prev_room = ch->in_room; if (ch->in_room == NULL) { bug("Char_from_room: NULL.", 0); return; } if (!IS_NPC(ch)) { --ch->in_room->area->nplayer; /* how many invaders in a clanned area */ if (!IS_IMMORTAL(ch) && ch->in_room->area->clan != CLAN_FREEMAN && ch->clan != ch->in_room->area->clan) ch->in_room->area->interlopers--; } if ((obj = get_eq_char(ch, WEAR_LIGHT)) != NULL && obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION] != 0 && ch->in_room->light > 0) --ch->in_room->light; if (ch == ch->in_room->people) ch->in_room->people = ch->next_in_room; else { CHAR_DATA *prev; for (prev = ch->in_room->people; prev; prev = prev->next_in_room) { if (prev->next_in_room == ch) { prev->next_in_room = ch->next_in_room; break; } } if (prev == NULL) bug("Char_from_room: ch not found.", 0); } ch->in_room = NULL; ch->next_in_room = NULL; ch->on = NULL; /* sanity check! */ if (MOUNTED(ch)) { ch->mount->riding = FALSE; ch->riding = FALSE; } if (RIDDEN(ch)) { ch->mount->riding = FALSE; ch->riding = FALSE; } if (prev_room && prev_room->affected_by) raffect_back_char(prev_room, ch); return; } /* * Move a char into a room. */ void char_to_room(CHAR_DATA * ch, ROOM_INDEX_DATA * pRoomIndex) { OBJ_DATA *obj; if (pRoomIndex == NULL) { ROOM_INDEX_DATA *room; bug("Char_to_room: NULL.", 0); if ((room = get_room_index(ROOM_VNUM_TEMPLE)) != NULL) char_to_room(ch, room); return; } ch->in_room = pRoomIndex; ch->next_in_room = pRoomIndex->people; pRoomIndex->people = ch; if (!IS_NPC(ch)) { if (ch->in_room->area->empty) { ch->in_room->area->empty = FALSE; ch->in_room->area->age = 0; } ++ch->in_room->area->nplayer; /* how many invaders in a clanned area */ if (!IS_IMMORTAL(ch) && ch->in_room->area->clan != CLAN_FREEMAN && ch->clan != ch->in_room->area->clan) ch->in_room->area->interlopers++; } if ((obj = get_eq_char(ch, WEAR_LIGHT)) != NULL && obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION] != 0) ++ch->in_room->light; while (IS_AFFECTED(ch, AFF_PLAGUE)) { AFFECT_DATA *af, plague; CHAR_DATA *vch; for (af = ch->affected; af != NULL; af = af->next) { if (af->type == gsn_plague) break; } if (af == NULL) { REMOVE_BIT(ch->affected_by, AFF_PLAGUE); break; } if (af->level == 1) break; plague.where = TO_AFFECTS; plague.type = gsn_plague; plague.level = af->level - 1; plague.duration = number_range(1, 2 * plague.level); plague.location = APPLY_STR; plague.modifier = -5; plague.bitvector = AFF_PLAGUE; for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room) { if (!saves_spell(plague.level - 2, vch, DAM_DISEASE) && !IS_IMMORTAL(vch) && !IS_AFFECTED(vch, AFF_PLAGUE) && number_bits(6) == 0) { char_puts("You feel hot and feverish.\n", vch); act("$n shivers and looks very ill.", vch, NULL, NULL, TO_ROOM); affect_join(vch, &plague); } } break; } if (ch->in_room->affected_by) { if (IS_IMMORTAL(ch)) do_raffects(ch, str_empty); else raffect_to_char(ch->in_room, ch); } if (ch->desc && OLCED(ch) && IS_EDIT(ch, ED_ROOM)) roomed_edit_room(ch, pRoomIndex, TRUE); } /* * Give an obj to a char. */ void obj_to_char(OBJ_DATA * obj, CHAR_DATA * ch) { obj->next_content = ch->carrying; ch->carrying = obj; obj->carried_by = ch; obj->in_room = NULL; obj->in_obj = NULL; ch->carry_number += get_obj_number(obj); ch->carry_weight += get_obj_weight(obj); } /* * medals are a different object type and use * different commands to give them to players. * This is not done in obj_to_char() because * we want a player to be able to award other * players these medals. * * by Zsuzsu */ void medal_to_char(OBJ_DATA * obj, CHAR_DATA * ch) { if (IS_NPC(ch)) { BUG("medal_to_char: tried to give to NPC [%s] %s", ch->name, obj->name); return; } obj->next_content = ch->pcdata->medals; ch->pcdata->medals = obj; obj->carried_by = ch; obj->in_room = NULL; obj->in_obj = NULL; obj->wear_loc = WEAR_MEDAL; } void award_to_char(OBJ_DATA * obj, CHAR_DATA * ch) { if (IS_NPC(ch)) { BUG("award_to_char: tried to give to NPC [%s] %s", ch->name, obj->name); return; } obj->next_content = ch->pcdata->awards; ch->pcdata->awards = obj; obj->carried_by = ch; obj->in_room = NULL; obj->in_obj = NULL; obj->wear_loc = WEAR_AWARD; } /* * Take an obj from its character. */ void obj_from_char(OBJ_DATA * obj) { CHAR_DATA *ch; bool weightless = FALSE; if ((ch = obj->carried_by) == NULL) { bug("Obj_from_char: null ch.", 0); log_printf("Name %s", obj->name); return; } if (obj->wear_loc != WEAR_NONE) unequip_char(ch, obj); if (ch->carrying == obj) ch->carrying = obj->next_content; else if (!IS_NPC(ch) && ch->pcdata->medals == obj) ch->pcdata->medals = obj->next_content; else if (!IS_NPC(ch) && ch->pcdata->awards == obj) ch->pcdata->awards = obj->next_content; else { OBJ_DATA *prev; for (prev = ch->carrying; prev; prev = prev->next_content) { if (prev->next_content == obj) { prev->next_content = obj->next_content; break; } } if (prev == NULL) { for (prev = ch->pcdata->medals; prev; prev = prev->next_content) { if (prev->next_content == obj) { prev->next_content = obj->next_content; weightless = TRUE; break; } } } if (prev == NULL) { for (prev = ch->pcdata->awards; prev; prev = prev->next_content) { if (prev->next_content == obj) { prev->next_content = obj->next_content; weightless = TRUE; break; } } } if (prev == NULL) BUG("Obj_from_char: obj not in list [%d] %s.", obj->pIndexData->vnum, obj->name); } obj->carried_by = NULL; obj->next_content = NULL; if (!weightless) { ch->carry_number -= get_obj_number(obj); ch->carry_weight -= get_obj_weight(obj); } } /* * Find the ac value of an obj, including position effect. */ int apply_ac(CHAR_DATA *ch, OBJ_DATA * obj, int iWear, int type) { int ac = 0; if (obj->pIndexData->item_type != ITEM_ARMOR) return 0; switch (iWear) { case WEAR_BODY: ac = 3 * obj->value[type]; break; case WEAR_HEAD: ac = 2 * obj->value[type]; break; case WEAR_LEGS: ac = 2 * obj->value[type]; break; case WEAR_FEET: ac = obj->value[type]; break; case WEAR_HANDS: ac = obj->value[type]; break; case WEAR_ARMS: ac = obj->value[type]; break; case WEAR_SHIELD: ac = 2 * obj->value[type]; break; case WEAR_FINGER_L: ac = 0; break; case WEAR_FINGER_R: ac = 0; break; case WEAR_NECK_1: ac = obj->value[type]; break; case WEAR_NECK_2: ac = obj->value[type]; break; case WEAR_ABOUT: ac = 2 * obj->value[type]; break; case WEAR_WAIST: ac = obj->value[type]; break; case WEAR_WRIST_L: ac = obj->value[type]; break; case WEAR_WRIST_R: ac = obj->value[type]; break; case WEAR_HOLD: ac = obj->value[type]; break; } /* modify AC for items to simulate armor types not set by builders */ if (obj->value[ITEM_ARMOR_TYPE] == 0) ac = ac * class_lookup(ch->class)->ac_rate / 100; return ac; } /* * Find a piece of eq on a character. */ OBJ_DATA *get_eq_char(CHAR_DATA * ch, int iWear) { OBJ_DATA *obj; if (ch == NULL) return NULL; for (obj = ch->carrying; obj != NULL; obj = obj->next_content) if (obj->wear_loc == iWear) return obj; return NULL; } /* * Equip a char with an obj. Return obj on success. Otherwise returns NULL. */ OBJ_DATA *equip_char(CHAR_DATA * ch, OBJ_DATA * obj, int iWear) { AFFECT_DATA *paf; int i; if (iWear == WEAR_STUCK_IN) { obj->wear_loc = iWear; return obj; } if (get_eq_char(ch, iWear)) { if (IS_NPC(ch)) { log_printf("equip_char: vnum %d: in_room %d: " "obj vnum %d: location %s: " "already equipped.", ch->pIndexData->vnum, ch->in_room ? ch->in_room->vnum : -1, obj->pIndexData->vnum, flag_string(wear_loc_flags, iWear)); } else { log_printf("equip_char: %s: location %s: " "already equipped.", ch->name, flag_string(wear_loc_flags, iWear)); } return NULL; } if ((IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch))) { /* * Thanks to Morgenes for the bug fix here! */ act("You are zapped by $p and drop it.", ch, obj, NULL, TO_CHAR); act("$n is zapped by $p and drops it.", ch, obj, NULL, TO_ROOM); obj_from_char(obj); obj_to_room(obj, ch->in_room); return NULL; } for (i = 0; i < 4; i++) ch->armor[i] -= apply_ac(ch, obj, iWear, i); obj->wear_loc = iWear; if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) for (paf = obj->pIndexData->affected; paf; paf = paf->next) if (paf->location != APPLY_SPELL_AFFECT) affect_modify(ch, paf, TRUE); for (paf = obj->affected; paf; paf = paf->next) if (paf->location == APPLY_SPELL_AFFECT) affect_to_char(ch, paf); else affect_modify(ch, paf, TRUE); if (obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION] != 0 && ch->in_room != NULL) ++ch->in_room->light; oprog_call(OPROG_WEAR, obj, ch, NULL); return obj; } void strip_obj_affects(CHAR_DATA * ch, OBJ_DATA * obj, AFFECT_DATA * paf) { AFFECT_DATA *lpaf_next = NULL; AFFECT_DATA *lpaf = NULL; for (; paf != NULL; paf = paf->next) { if (paf->location == APPLY_SPELL_AFFECT) { for (lpaf = ch->affected; lpaf != NULL; lpaf = lpaf_next) { lpaf_next = lpaf->next; if ((lpaf->type == paf->type) && (lpaf->level == paf->level) && (lpaf->location == APPLY_SPELL_AFFECT)) { affect_remove(ch, lpaf); lpaf_next = NULL; } } } else { affect_modify(ch, paf, FALSE); affect_check(ch, paf->where, paf->bitvector); } } } /* * Unequip a char with an obj. */ void unequip_char(CHAR_DATA * ch, OBJ_DATA * obj) { int i; if (obj->wear_loc == WEAR_NONE) { bug("Unequip_char: already unequipped.", 0); return; } if (obj->wear_loc == WEAR_STUCK_IN) { obj->wear_loc = WEAR_NONE; return; } for (i = 0; i < 4; i++) ch->armor[i] += apply_ac(ch, obj, obj->wear_loc, i); obj->wear_loc = -1; if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) strip_obj_affects(ch, obj, obj->pIndexData->affected); strip_obj_affects(ch, obj, obj->affected); if (obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION] != 0 && ch->in_room != NULL && ch->in_room->light > 0) --ch->in_room->light; oprog_call(OPROG_REMOVE, obj, ch, NULL); } /* * Count occurrences of an obj in a list. */ int count_obj_list(OBJ_INDEX_DATA * pObjIndex, OBJ_DATA * list) { OBJ_DATA *obj; int nMatch; nMatch = 0; for (obj = list; obj != NULL; obj = obj->next_content) { if (obj->pIndexData == pObjIndex) nMatch++; } return nMatch; } /* * Move an obj out of a room. */ void obj_from_room(OBJ_DATA * obj) { ROOM_INDEX_DATA *in_room; CHAR_DATA *ch; if ((in_room = obj->in_room) == NULL) { bug("obj_from_room: NULL.", 0); return; } for (ch = in_room->people; ch != NULL; ch = ch->next_in_room) if (ch->on == obj) ch->on = NULL; if (obj == in_room->contents) in_room->contents = obj->next_content; else { OBJ_DATA *prev; for (prev = in_room->contents; prev; prev = prev->next_content) { if (prev->next_content == obj) { prev->next_content = obj->next_content; break; } } if (prev == NULL) { bug("Obj_from_room: obj not found.", 0); return; } } obj->in_room = NULL; obj->next_content = NULL; return; } /* * Move an obj into a room. */ void obj_to_room(OBJ_DATA * obj, ROOM_INDEX_DATA * pRoomIndex) { obj->next_content = pRoomIndex->contents; pRoomIndex->contents = obj; obj->in_room = pRoomIndex; obj->carried_by = NULL; obj->in_obj = NULL; if (IS_WATER(pRoomIndex)) { if (may_float(obj)) obj->water_float = -1; else obj->water_float = floating_time(obj); } } /* * Move an object into an object. */ void obj_to_obj(OBJ_DATA * obj, OBJ_DATA * obj_to) { if (obj == obj_to) { log_printf("obj_to_obj: obj == obj_to (vnum %d)", obj->pIndexData->vnum); return; } if (!obj_to) { bug("obj_to_obj: obj(num %d) but obj_to is NULL", obj->pIndexData->vnum); return; } obj->next_content = obj_to->contains; obj_to->contains = obj; obj->in_obj = obj_to; obj->in_room = NULL; obj->carried_by = NULL; if (IS_SET(obj_to->pIndexData->extra_flags, ITEM_PIT)) obj->cost = 0; for (; obj_to != NULL; obj_to = obj_to->in_obj) { if (obj_to->carried_by != NULL) { /* obj_to->carried_by->carry_number += get_obj_number(obj); */ obj_to->carried_by->carry_weight += get_obj_weight(obj) * WEIGHT_MULT(obj_to) / 100; } } } /* * Move an object out of an object. */ void obj_from_obj(OBJ_DATA * obj) { OBJ_DATA *obj_from; if ((obj_from = obj->in_obj) == NULL) { bug("Obj_from_obj: null obj_from.", 0); return; } if (obj == obj_from->contains) obj_from->contains = obj->next_content; else { OBJ_DATA *prev; for (prev = obj_from->contains; prev; prev = prev->next_content) { if (prev->next_content == obj) { prev->next_content = obj->next_content; break; } } if (prev == NULL) { bug("Obj_from_obj: obj not found.", 0); return; } } obj->next_content = NULL; obj->in_obj = NULL; for (; obj_from != NULL; obj_from = obj_from->in_obj) { if (obj_from->carried_by != NULL) /* obj_from->carried_by->carry_number -= get_obj_number(obj); */ obj_from->carried_by->carry_weight -= get_obj_weight(obj) * WEIGHT_MULT(obj_from) / 100; } } /* * Extract an obj from the world. */ void extract_obj(OBJ_DATA * obj, int flags) { OBJ_DATA *obj_content; OBJ_DATA *obj_next; if (obj->extracted) { log_printf("extract_obj: %s, vnum %d: already extracted", obj->name, obj->pIndexData->vnum); return; } else obj->extracted = TRUE; /* if (IS_SET(obj->extra_flags, ITEM_CLAN)) return; */ for (obj_content = obj->contains; obj_content; obj_content = obj_next) { obj_next = obj_content->next_content; if (!IS_SET(flags, XO_F_NORECURSE)) { extract_obj(obj_content, flags); continue; } obj_from_obj(obj_content); if (obj->in_room) obj_to_room(obj_content, obj->in_room); else if (obj->carried_by) obj_to_char(obj_content, obj->carried_by); else if (obj->in_obj) obj_to_obj(obj_content, obj->in_obj); else extract_obj(obj_content, 0); } if (obj->in_room) obj_from_room(obj); else if (obj->carried_by) obj_from_char(obj); else if (obj->in_obj) obj_from_obj(obj); if (obj->pIndexData->vnum == OBJ_VNUM_MAGIC_JAR) { CHAR_DATA *wch; for (wch = char_list; wch && !IS_NPC(wch); wch = wch->next) { if (is_name(obj->name, wch->name)) { REMOVE_BIT(wch->state_flags, STATE_NOEXP); char_puts("Now you catch your spirit.\n", wch); break; } } } if (object_list == obj) object_list = obj->next; else { OBJ_DATA *prev; for (prev = object_list; prev != NULL; prev = prev->next) { if (prev->next == obj) { prev->next = obj->next; break; } } if (prev == NULL) { bug("Extract_obj: obj %d not found.", obj->pIndexData->vnum); return; } } if (!IS_SET(flags, XO_F_NOCOUNT)) --obj->pIndexData->count; free_obj(obj); } /* * Extract a char from the world. */ void extract_char(CHAR_DATA * ch, int flags) { CHAR_DATA *wch; OBJ_DATA *obj; OBJ_DATA *obj_next; OBJ_DATA *wield; int extract_obj_flags; if (!IS_SET(flags, XC_F_INCOMPLETE)) { /* * only for total extractions should it check */ if (ch->extracted) { /* * if it's already been extracted, * something bad is going on */ log_printf("Warning! Extraction of %s.", ch->name); return; } else { /* * if it hasn't been extracted yet, now * it's being extracted. */ ch->extracted = TRUE; } } nuke_pets(ch); if (!IS_SET(flags, XC_F_INCOMPLETE)) die_follower(ch); stop_fighting(ch, TRUE); if ((wield = get_eq_char(ch, WEAR_WIELD)) != NULL) unequip_char(ch, wield); extract_obj_flags = (IS_SET(flags, XC_F_COUNT) ? 0 : XO_F_NOCOUNT); for (obj = ch->carrying; obj != NULL; obj = obj_next) { obj_next = obj->next_content; extract_obj(obj, extract_obj_flags); } if (ch->in_room) char_from_room(ch); if (IS_SET(flags, XC_F_INCOMPLETE)) { char_to_room(ch, get_altar(ch)->room); return; } if (IS_NPC(ch)) --ch->pIndexData->count; if (ch->desc != NULL && ch->desc->original != NULL) { do_return(ch, str_empty); ch->desc = NULL; } for (wch = char_list; wch; wch = wch->next) { if (wch->reply == ch) wch->reply = NULL; if (wch->mprog_target == ch) wch->mprog_target = NULL; } if (ch == char_list) { char_list = ch->next; if (ch == char_list_lastpc) char_list_lastpc = NULL; } else { CHAR_DATA *prev; for (prev = char_list; prev; prev = prev->next) { if (prev->next == ch) break; } if (!prev) { bug("Extract_char: char not found.", 0); return; } prev->next = ch->next; if (ch == char_list_lastpc) char_list_lastpc = prev; } if (ch->desc) ch->desc->character = NULL; free_char(ch); } /* * Find a char in the room. */ CHAR_DATA *get_char_room_raw(CHAR_DATA * ch, const char *name, uint * number, ROOM_INDEX_DATA * room) { CHAR_DATA *rch; bool ugly; if (!str_cmp(name, "self")) return ch; ugly = !str_cmp(name, "ugly"); if (!room) { BUG("get_char_room_raw: got NULL room (ch:%s, name:%s)", ch->name, name); return NULL; } for (rch = room->people; rch; rch = rch->next_in_room) { CHAR_DATA *vch; if (!can_see(ch, rch)) continue; if (ugly && *number == 1 && is_affected(rch, gsn_vampire)) return rch; vch = (is_affected(rch, gsn_doppelganger) && (IS_NPC(ch) || !IS_SET(ch->conf_flags, PLR_CONF_HOLYLIGHT))) ? rch->doppel : rch; if (name[0] && !is_name(name, vch->name)) continue; if (!--(*number)) return rch; } return NULL; } /* * Find a char in the room. */ CHAR_DATA *get_char_room(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number) return NULL; return get_char_room_raw(ch, arg, &number, ch->in_room); } CHAR_DATA *get_char_area(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *ach; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number) return NULL; if ((ach = get_char_room_raw(ch, arg, &number, ch->in_room))) return ach; if (arg[0] == '\0') return NULL; for (ach = char_list; ach; ach = ach->next) { if (!ach->in_room || ach->in_room == ch->in_room) continue; if (ach->in_room->area != ch->in_room->area || !can_see(ch, ach) || !is_name(arg, ach->name)) continue; if (!--number) return ach; } return NULL; } /* * Find a char in the world. */ CHAR_DATA *get_char_world(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *wch; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number) return NULL; if ((wch = get_char_room_raw(ch, arg, &number, ch->in_room))) return wch; if (arg[0] == '\0') return NULL; for (wch = char_list; wch; wch = wch->next) { if (!wch->in_room || wch->in_room == ch->in_room || (ch != NULL && !can_see(ch, wch)) || !is_name(arg, wch->name)) continue; if (!--number) return wch; } return NULL; } /* * gets a character, but doen't check to see if the * character can been seen. Use sparingly. */ CHAR_DATA *get_char_world_unrestricted(const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *wch; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number) return NULL; if (arg[0] == '\0') return NULL; for (wch = char_list; wch; wch = wch->next) { if (!wch->in_room || !is_name(arg, wch->name)) continue; if (!--number) return wch; } return NULL; } int opposite_door(int door) { int opdoor; switch (door) { case 0: opdoor = 2; break; case 1: opdoor = 3; break; case 2: opdoor = 0; break; case 3: opdoor = 1; break; case 4: opdoor = 5; break; case 5: opdoor = 4; break; default: opdoor = -1; break; } return opdoor; } CHAR_DATA *find_char(CHAR_DATA * ch, const char *argument, int door, int range) { EXIT_DATA *pExit, *bExit; ROOM_INDEX_DATA *dest_room = ch->in_room; ROOM_INDEX_DATA *back_room; CHAR_DATA *target; uint number; int opdoor; char arg[MAX_INPUT_LENGTH]; number = number_argument(argument, arg, sizeof(arg)); if (!number) return NULL; if ((target = get_char_room_raw(ch, arg, &number, dest_room))) return target; if ((opdoor = opposite_door(door)) == -1) { bug("In find_char wrong door: %d", door); char_puts("You don't see that there.\n", ch); return NULL; } while (range > 0) { range--; /* find target room */ back_room = dest_room; if ((pExit = dest_room->exit[door]) == NULL || (dest_room = pExit->to_room.r) == NULL) break; if (IS_SET(pExit->exit_info, EX_CLOSED)) break; if (IS_SET(pExit->exit_info, EX_NORANGE)) { char_puts("You can't get a clear shot from here.\n", ch); return NULL; } /* if there isn't a bi-directional link */ if ((bExit = dest_room->exit[opdoor]) == NULL || bExit->to_room.r != back_room) { char_puts("The path you choose prevents your power " "to pass.\n", ch); return NULL; } if ((target = get_char_room_raw(ch, arg, &number, dest_room))) return target; } char_puts("You don't see that there.\n", ch); return NULL; } int check_exit(char *arg) { int door = -1; if (!str_cmp(arg, "n") || !str_cmp(arg, "north")) door = 0; else if (!str_cmp(arg, "e") || !str_cmp(arg, "east")) door = 1; else if (!str_cmp(arg, "s") || !str_cmp(arg, "south")) door = 2; else if (!str_cmp(arg, "w") || !str_cmp(arg, "west")) door = 3; else if (!str_cmp(arg, "u") || !str_cmp(arg, "up")) door = 4; else if (!str_cmp(arg, "d") || !str_cmp(arg, "down")) door = 5; return door; } /* * Find a char for range casting. * argument must specify target in form '[d.][n.]name' where * 'd' - direction * 'n' - number */ CHAR_DATA *get_char_spell(CHAR_DATA * ch, const char *argument, int *door, int range) { char buf[MAX_INPUT_LENGTH]; char *p; p = strchr(argument, '.'); if (!p) { *door = -1; return get_char_room(ch, argument); } strnzncpy(buf, sizeof(buf), argument, p - argument); if ((*door = check_exit(buf)) < 0) return get_char_room(ch, argument); return find_char(ch, p + 1, *door, range); } /* * Find some object with a given index data. * Used by area-reset 'P' command. */ OBJ_DATA *get_obj_type(OBJ_INDEX_DATA * pObjIndex) { OBJ_DATA *obj; for (obj = object_list; obj; obj = obj->next) if (obj->pIndexData == pObjIndex) return obj; return NULL; } /* * flags for get_obj_list_raw */ enum { GETOBJ_F_WEAR_ANY, /* any obj->wear_loc */ GETOBJ_F_WEAR_NONE, /* obj->wear_loc == WEAR_NONE (in inventory) */ GETOBJ_F_WEAR, /* obj->wear_loc != WEAR_NONE (worn) */ }; /* * Find an obj in a list. */ OBJ_DATA *get_obj_list_raw(CHAR_DATA * ch, const char *name, uint * number, OBJ_DATA * list, int flags) { OBJ_DATA *obj; for (obj = list; obj; obj = obj->next_content) { if (!can_see_obj(ch, obj) || !is_name(name, obj->name)) continue; switch (flags) { case GETOBJ_F_WEAR_NONE: if (obj->wear_loc != WEAR_NONE) continue; break; case GETOBJ_F_WEAR: if (obj->wear_loc == WEAR_NONE) continue; break; } if (!--(*number)) return obj; } return NULL; } /* * Find an obj in the room or in eq/inventory. */ OBJ_DATA *get_obj_here_raw(CHAR_DATA * ch, const char *name, uint * number) { OBJ_DATA *obj; /* search in player's inventory */ obj = get_obj_list_raw(ch, name, number, ch->carrying, GETOBJ_F_WEAR_NONE); if (obj) return obj; /* search in player's eq */ obj = get_obj_list_raw(ch, name, number, ch->carrying, GETOBJ_F_WEAR); if (obj) return obj; /* search in room contents */ obj = get_obj_list_raw(ch, name, number, ch->in_room->contents, GETOBJ_F_WEAR_ANY); if (obj) return obj; return NULL; } /* * Find an obj in a list. */ OBJ_DATA *get_obj_list(CHAR_DATA * ch, const char *argument, OBJ_DATA * list) { char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_list_raw(ch, arg, &number, list, GETOBJ_F_WEAR_ANY); } /* * Find an obj in player's inventory. */ OBJ_DATA *get_obj_carry(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_list_raw(ch, arg, &number, ch->carrying, GETOBJ_F_WEAR_NONE); } /* * Find an obj in player's medal list. */ OBJ_DATA *get_obj_medal(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; if (IS_NPC(ch)) return NULL; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_list_raw(ch, arg, &number, ch->pcdata->medals, GETOBJ_F_WEAR_ANY); } /* * Find an obj in player's award list. */ OBJ_DATA *get_obj_award(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; if (IS_NPC(ch)) return NULL; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_list_raw(ch, arg, &number, ch->pcdata->awards, GETOBJ_F_WEAR_ANY); } /* * Find an obj in player's equipment. */ OBJ_DATA *get_obj_wear(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_list_raw(ch, arg, &number, ch->carrying, GETOBJ_F_WEAR); } /* * Find an obj in the room or in inventory. */ OBJ_DATA *get_obj_here(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; return get_obj_here_raw(ch, arg, &number); } OBJ_DATA *get_obj_room(CHAR_DATA * ch, const char *argument) { OBJ_DATA *obj; CHAR_DATA *vch; char arg[MAX_INPUT_LENGTH]; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; if ((obj = get_obj_here_raw(ch, arg, &number))) return obj; for (vch = ch->in_room->people; vch; vch = vch->next_in_room) { /* * search in the vch's inventory */ obj = get_obj_list_raw(ch, arg, &number, vch->carrying, GETOBJ_F_WEAR_NONE); if (obj) return obj; /* * search in the vch's eq */ obj = get_obj_list_raw(ch, arg, &number, vch->carrying, GETOBJ_F_WEAR); if (obj) return obj; } return NULL; } /* * Find an obj in the world. */ OBJ_DATA *get_obj_world(CHAR_DATA * ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; OBJ_DATA *obj; uint number; number = number_argument(argument, arg, sizeof(arg)); if (!number || arg[0] == '\0') return NULL; if ((obj = get_obj_here_raw(ch, arg, &number))) return obj; for (obj = object_list; obj; obj = obj->next) if (can_see_obj(ch, obj) && obj->carried_by != ch && is_name(arg, obj->name) && !--number) return obj; return NULL; } /* * deduct cost from a character */ void deduct_cost(CHAR_DATA * ch, uint cost) { /* * price in silver. MUST BE signed for proper exchange operations */ int silver = UMIN(ch->silver, cost); int gold = 0; if (silver < cost) { gold = (cost - silver + 99) / 100; silver = cost - 100 * gold; } if (ch->gold < gold) { log_printf("deduct cost: %s: ch->gold (%d) < gold (%d)", ch->name, ch->gold, gold); ch->gold = gold; } if (ch->silver < silver) { log_printf("deduct cost: %s: ch->silver (%d) < silver (%d)", ch->name, ch->silver, silver); ch->silver = silver; } ch->gold -= gold; ch->silver -= silver; } static inline void money_form(int lang, char *buf, size_t len, int num, const char *name) { char tmp[MAX_STRING_LENGTH]; if (num < 0) return; strnzcpy(tmp, sizeof(tmp), word_form(GETMSG(name, lang), 1, lang, RULES_CASE)); strnzcpy(buf, len, word_form(tmp, num, lang, RULES_QTY)); } struct _data { int num1; const char *name1; int num2; const char *name2; }; static void money_cb(int lang, const char **p, void *arg) { char buf1[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; const char *q; struct _data *d = (struct _data *) arg; if (IS_NULLSTR(*p)) return; money_form(lang, buf1, sizeof(buf1), d->num1, d->name1); money_form(lang, buf2, sizeof(buf2), d->num2, d->name2); q = str_printf(*p, d->num1, buf1, d->num2, buf2); free_string(*p); *p = q; } static void money_descr(mlstring ** descr, int num1, const char *name1, int num2, const char *name2) { struct _data data; data.num1 = num1; data.num2 = num2; data.name1 = name1; data.name2 = name2; mlstr_for_each(descr, &data, money_cb); } /* * Create a 'money' obj. */ OBJ_DATA *create_money(int gold, int silver) { OBJ_INDEX_DATA *pObjIndex; OBJ_DATA *obj; if (gold < 0 || silver < 0 || (gold == 0 && silver == 0)) { log_printf("create_money: gold %d, silver %d", gold, silver); gold = UMAX(1, gold); silver = UMAX(1, silver); } if (gold == 0 && silver == 1) obj = create_obj(get_obj_index(OBJ_VNUM_SILVER_ONE), 0); else if (gold == 1 && silver == 0) obj = create_obj(get_obj_index(OBJ_VNUM_GOLD_ONE), 0); else if (silver == 0) { pObjIndex = get_obj_index(OBJ_VNUM_GOLD_SOME); obj = create_obj(pObjIndex, 0); money_descr(&obj->short_descr, gold, "gold coins", -1, NULL); obj->value[ITEM_MONEY_GOLD] = gold; obj->cost = 100 * gold; obj->weight = gold / 5; } else if (gold == 0) { pObjIndex = get_obj_index(OBJ_VNUM_SILVER_SOME); obj = create_obj(pObjIndex, 0); money_descr(&obj->short_descr, silver, "silver coins", -1, NULL); obj->value[ITEM_MONEY_SILVER] = silver; obj->cost = silver; obj->weight = silver / 20; } else { pObjIndex = get_obj_index(OBJ_VNUM_COINS); obj = create_obj(pObjIndex, 0); money_descr(&obj->short_descr, silver, "silver coins", gold, "gold coins"); obj->value[ITEM_MONEY_SILVER] = silver; obj->value[ITEM_MONEY_GOLD] = gold; obj->cost = 100 * gold + silver; obj->weight = gold / 5 + silver / 20; } return obj; } /* * Return # of objects which an object counts as. * Thanks to Tony Chamberlain for the correct recursive code here. */ int get_obj_number(OBJ_DATA * obj) { int number; /* if (obj->pIndexData->item_type == ITEM_CONTAINER || obj->pIndexData->item_type == ITEM_MONEY || obj->pIndexData->item_type == ITEM_GEM || obj->pIndexData->item_type == ITEM_JEWELRY) number = 0; */ if (obj->pIndexData->item_type == ITEM_MONEY) number = 0; else number = 1; /* for (obj = obj->contains; obj != NULL; obj = obj->next_content) number += get_obj_number(obj); */ return number; } int get_obj_realnumber(OBJ_DATA * obj) { int number = 1; for (obj = obj->contains; obj != NULL; obj = obj->next_content) number += get_obj_number(obj); return number; } /* * Return weight of an object, including weight of contents. */ int get_obj_weight(OBJ_DATA * obj) { int weight; OBJ_DATA *tobj; weight = obj->weight; for (tobj = obj->contains; tobj != NULL; tobj = tobj->next_content) weight += get_obj_weight(tobj) * WEIGHT_MULT(obj) / 100; return weight; } int get_true_weight(OBJ_DATA * obj) { int weight; weight = obj->weight; for (obj = obj->contains; obj != NULL; obj = obj->next_content) weight += get_obj_weight(obj); return weight; } /* * True if room is dark. */ bool room_is_dark(CHAR_DATA * ch) { ROOM_INDEX_DATA *pRoomIndex = ch->in_room; if (pRoomIndex == NULL) return FALSE; if (!IS_NPC(ch) && IS_SET(ch->conf_flags, PLR_CONF_HOLYLIGHT)) return FALSE; if (is_affected(ch, gsn_vampire)) return FALSE; if (IS_SET(ch->state_flags, STATE_GHOST)) return FALSE; if (IS_AFFECTED(ch, AFF_DARK_VISION)) return FALSE; if (pRoomIndex->light > 0) return FALSE; if (IS_SET(pRoomIndex->room_flags, ROOM_DARK)) return TRUE; if (IS_ROOM_AFFECTED(pRoomIndex, RAFF_MIDNIGHT)) return TRUE; if (pRoomIndex->sector_type == SECT_INSIDE || pRoomIndex->sector_type == SECT_CITY) return FALSE; if (weather_info.sunlight == SUN_SET || weather_info.sunlight == SUN_DARK) return TRUE; return FALSE; } bool room_dark(ROOM_INDEX_DATA * pRoomIndex) { if (pRoomIndex->light > 0) return FALSE; if (IS_SET(pRoomIndex->room_flags, ROOM_DARK)) return TRUE; if (pRoomIndex->sector_type == SECT_INSIDE || pRoomIndex->sector_type == SECT_CITY) return FALSE; if (weather_info.sunlight == SUN_SET || weather_info.sunlight == SUN_DARK) return TRUE; return FALSE; } bool is_room_owner(CHAR_DATA * ch, ROOM_INDEX_DATA * room) { if (room->owner == NULL || room->owner[0] == '\0') return FALSE; return is_name(ch->name, room->owner); } /* * True if room is private. */ bool room_is_private(ROOM_INDEX_DATA * pRoomIndex) { CHAR_DATA *rch; int count; /* if (pRoomIndex->owner != NULL && pRoomIndex->owner[0] != '\0') return TRUE; */ count = 0; for (rch = pRoomIndex->people; rch != NULL; rch = rch->next_in_room) count++; if (IS_SET(pRoomIndex->room_flags, ROOM_PRIVATE) && count >= 2) return TRUE; if (IS_SET(pRoomIndex->room_flags, ROOM_SOLITARY) && count >= 1) return TRUE; if (IS_SET(pRoomIndex->room_flags, ROOM_IMP_ONLY)) return TRUE; return FALSE; } /* visibility on a room -- for entering and exits */ bool can_see_room(CHAR_DATA * ch, ROOM_INDEX_DATA * pRoomIndex) { if (IS_SET(pRoomIndex->room_flags, ROOM_IMP_ONLY) && !IS_TRUSTED(ch, IMPLEMENTOR)) return FALSE; if (IS_SET(pRoomIndex->room_flags, ROOM_GODS_ONLY) && !IS_TRUSTED(ch, GOD)) return FALSE; if (IS_SET(pRoomIndex->room_flags, ROOM_HEROES_ONLY) && !IS_TRUSTED(ch, HERO)) return FALSE; if (IS_SET(pRoomIndex->room_flags, ROOM_NEWBIES_ONLY) && ch->level > LEVEL_NEWBIE && !IS_IMMORTAL(ch)) return FALSE; return TRUE; } /* * True if char can see victim. */ bool can_see(CHAR_DATA * ch, CHAR_DATA * victim) { /* RT changed so that WIZ_INVIS has levels */ if (ch == victim) return TRUE; if (ch == NULL || victim == NULL) { log("can_see: NULL ch or victim"); return FALSE; } /* Rulers always see their Stalkers */ if (!IS_NPC(ch) && HAS_SKILL(ch, gsn_ruler_badge) && IS_NPC(victim) && victim->pIndexData->vnum == MOB_VNUM_STALKER) return TRUE; if (!IS_NPC(victim) && !IS_TRUSTED(ch, victim->invis_level)) return FALSE; if (IS_CLAN_GUARD(ch)) return TRUE; if (!IS_TRUSTED(ch, victim->incog_level) && ch->in_room != victim->in_room) return FALSE; if (!IS_NPC(ch) && IS_SET(ch->conf_flags, PLR_CONF_HOLYLIGHT)) return TRUE; if (IS_NPC(victim) && !IS_TRUSTED(ch, victim->invis_level)) { AREA_DATA *pArea = area_vnum_lookup(victim->pIndexData->vnum); if (pArea == NULL || !IS_BUILDER(ch, pArea)) return FALSE; } if (IS_AFFECTED(ch, AFF_BLIND)) return FALSE; if (ch->in_room == NULL) return FALSE; if (IS_AFFECTED(victim, AFF_FADE) && !IS_AFFECTED(ch, AFF_DETECT_FADE) && victim->fighting == NULL) return FALSE; if (is_affected(ch, gsn_bush_sense) && victim->in_room != NULL && (victim->in_room->sector_type == SECT_FOREST || victim->in_room->sector_type == SECT_HILLS || victim->in_room->sector_type == SECT_MOUNTAIN)) return TRUE; if (room_is_dark(ch) && !IS_AFFECTED(ch, AFF_INFRARED)) return FALSE; if (IS_AFFECTED(victim, AFF_INVIS) && !IS_AFFECTED(ch, AFF_DETECT_INVIS)) return FALSE; if (get_invis_level(victim) > get_detect_invis_level(ch)) return FALSE; if (IS_AFFECTED(victim, AFF_IMP_INVIS) && !IS_AFFECTED(ch, AFF_DETECT_IMP_INVIS)) return FALSE; if (IS_AFFECTED(victim, AFF_CAMOUFLAGE) && !IS_AFFECTED(ch, AFF_ACUTE_VISION)) return FALSE; if (IS_AFFECTED(victim, AFF_HIDE) && !IS_AFFECTED(ch, AFF_DETECT_HIDDEN) && victim->fighting == NULL) return FALSE; return TRUE; } int get_invis_level(CHAR_DATA * ch) { AFFECT_DATA *paff; int level = 0, skill; bool is_mass = FALSE; if (!IS_AFFECTED(ch, AFF_INVIS)) return 0; paff = affect_find_most_powerful(ch->affected, gsn_invisibility); if (!paff) { paff = affect_find_most_powerful(ch->affected, gsn_mass_invis); is_mass = (paff != NULL); } if (!paff) { if (IS_NPC(ch)) level = ch->level - 10; else level = ch->level; } else { if (IS_NPC(ch)) level = paff->level; else { if (is_mass) skill = get_skill(ch, gsn_mass_invis); else skill = get_skill(ch, gsn_invisibility); level = paff->level + (5 * skill / 100); DEBUG(DEBUG_INVIS, "get_invis_level: mass(%s), skill:%d," " paff:%d, level:%d", (is_mass) ? "true" : "false", skill, paff->level, level); } } return UMAX(1, level); } int get_detect_invis_level(CHAR_DATA * ch) { AFFECT_DATA *paff; int level = 0, skill; if (!IS_AFFECTED(ch, AFF_DETECT_INVIS)) return 0; paff = affect_find_most_powerful(ch->affected, gsn_detect_invisibility); if (!paff) { if (IS_NPC(ch)) level = ch->level + 3 + (ch->level / 10); else level = ch->level; } else { if (IS_NPC(ch)) level = paff->level; else { skill = get_skill(ch, gsn_detect_invisibility); level = paff->level + (3 * skill / 100) + ((get_curr_stat(ch, STAT_INT) - 50) / 2); } } level = level + (LEVEL(ch) / 10); return UMAX(1, level); } /* * True if char can see obj. */ bool can_see_obj(CHAR_DATA * ch, OBJ_DATA * obj) { if (!IS_NPC(ch) && IS_SET(ch->conf_flags, PLR_CONF_HOLYLIGHT)) return TRUE; if (IS_SET(obj->extra_flags, ITEM_VIS_DEATH)) return FALSE; if (IS_AFFECTED(ch, AFF_BLIND) && !IS_OBJ_STAT(obj, ITEM_HUM)) return FALSE; if (obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION] != 0) return TRUE; if (IS_SET(obj->extra_flags, ITEM_INVIS) && !IS_AFFECTED(ch, AFF_DETECT_INVIS)) return FALSE; if (IS_OBJ_STAT(obj, ITEM_GLOW) || IS_OBJ_STAT(obj, ITEM_HUM)) return TRUE; if (room_is_dark(ch) && !IS_AFFECTED(ch, AFF_INFRARED)) return FALSE; return TRUE; } /* * True if char can drop obj. */ bool can_drop_obj(CHAR_DATA * ch, OBJ_DATA * obj) { if (!IS_SET(obj->extra_flags, ITEM_NODROP)) return TRUE; if (IS_IMMORTAL(ch)) return TRUE; return FALSE; } int isn_dark_safe(CHAR_DATA * ch) { CHAR_DATA *rch; OBJ_DATA *light; int light_exist; if (!is_affected(ch, gsn_vampire) || IS_SET(ch->in_room->room_flags, ROOM_DARK)) return 0; if (ch->in_room->sector_type != SECT_INSIDE && (weather_info.sunlight == SUN_LIGHT || weather_info.sunlight == SUN_RISE)) return 2; light_exist = 0; for (rch = ch->in_room->people; rch; rch = rch->next_in_room) { if ((light = get_eq_char(rch, WEAR_LIGHT)) && IS_OBJ_STAT(light, ITEM_MAGIC) && light->value[ITEM_LIGHT_DURATION] > 0) { light_exist = 1; break; } } return light_exist; } int count_charmed(CHAR_DATA * ch) { CHAR_DATA *gch; int count = 0; for (gch = char_list; gch != NULL; gch = gch->next) { if (IS_AFFECTED(gch, AFF_CHARM) && gch->master == ch) count++; } if (count >= MAX_CHARM(ch)) { char_puts ("You are already controlling as many charmed mobs as you can!\n", ch); return count; } return 0; } /* * add_mind - remember 'str' in mind buffer of 'ch' * remember the place to return in mind buffer */ void add_mind(CHAR_DATA * ch, const char *str) { if (!IS_NPC(ch) || ch->in_room == NULL) return; if (ch->in_mind == NULL) /* remember a place to return */ ch->in_mind = str_printf("%d", ch->in_room->vnum); if (!is_name(str, ch->in_mind)) { const char *p = ch->in_mind; ch->in_mind = str_printf("%s %s", ch->in_mind, str); free_string(p); } } /* * remove_mind - remove 'str' from mind buffer of 'ch' * if it was the last revenge - return home */ void remove_mind(CHAR_DATA * ch, const char *str) { char buf[MAX_STRING_LENGTH]; char buff[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; const char *mind = ch->in_mind; if (!IS_NPC(ch) || ch->in_room == NULL || mind == NULL || !is_name(str, mind)) return; buf[0] = '\0'; do { mind = one_argument(mind, arg, sizeof(arg)); if (!is_name(str, arg)) { if (buf[0] == '\0') strnzcpy(buf, sizeof(buf), arg); else { snprintf(buff, sizeof(buff), "%s %s", buf, arg); strnzcpy(buf, sizeof(buf), buff); } } } while (mind[0] != '\0'); free_string(ch->in_mind); if (is_number(buf)) { do_say(ch, "At last, I took my revenge!"); back_home(ch); ch->in_mind = NULL; } else ch->in_mind = str_dup(buf); } void back_home(CHAR_DATA * ch) { ROOM_INDEX_DATA *location; char arg[MAX_INPUT_LENGTH]; if (!IS_NPC(ch) || ch->in_mind == NULL) return; one_argument(ch->in_mind, arg, sizeof(arg)); if ((location = find_location(ch, arg)) == NULL) { DEBUG(DEBUG_MOB_AI, "back_home: %s[%d] in room %d can't find %s (%s) and is lost.", ch->name, ch->pIndexData->vnum, (ch->in_room) ? ch->in_room->vnum : 0, arg, ch->in_mind); return; } if (ch->fighting == NULL && location != ch->in_room) { act("$n prays for transportation.", ch, NULL, NULL, TO_ROOM); recall(ch, location); } } void path_to_track(CHAR_DATA * ch, CHAR_DATA * victim, int door) { ROOM_INDEX_DATA *temp; EXIT_DATA *pExit; int opdoor; int range = 0; SET_FIGHT_TIME(ch); if (!IS_NPC(victim)) SET_FIGHT_TIME(victim); if (IS_NPC(victim) && victim->position != POS_DEAD) { victim->last_fought = ch; if ((opdoor = opposite_door(door)) == -1) { bug("In path_to_track wrong door: %d", door); return; } temp = ch->in_room; while (1) { range++; if (victim->in_room == temp) break; if ((pExit = temp->exit[door]) == NULL || (temp = pExit->to_room.r) == NULL) { bug("In path_to_track: couldn't calculate range %d", range); return; } if (range > 100) { bug("In path_to_track: range exceeded 100", 0); return; } } temp = victim->in_room; while (--range > 0) { room_record(ch->name, temp, opdoor); if ((pExit = temp->exit[opdoor]) == NULL || (temp = pExit->to_room.r) == NULL) { log_printf ("[*****] Path to track: Range: %d Room: %d opdoor:%d", range, temp->vnum, opdoor); return; } } do_track(victim, str_empty); } } int pk_range(int level) { return UMAX(4, level / 7 + 2); } bool in_PK(CHAR_DATA * ch, CHAR_DATA * victim) { WORLD_AFFECT_DATA *waff = NULL; WORLD_AFFECT_DATA *vwaff = NULL; int mod = 0; if (IS_NPC(ch) || IS_NPC(victim)) return TRUE; if (IS_NEWBIE(ch) || IS_NEWBIE(victim)) return FALSE; if (victim->level < MIN_PK_LEVEL || ch->level < MIN_PK_LEVEL) return FALSE; if (ch_waffected(ch, WAFF_FFA) && ch_waffected(victim, WAFF_FFA)) return TRUE; if (IS_SET(ch->in_room->room_flags, ROOM_FFA) && IS_SET(victim->in_room->room_flags, ROOM_FFA)) return TRUE; /* if on the person's PK_OK list */ if ((ch->level > victim->level && name_find(ch->pcdata->pk_ok_list, victim->name)) || (victim->level > ch->level && name_find(victim->pcdata->pk_ok_list, ch->name))) return TRUE; /* modifier for the PK range */ if ((waff = ch_waffected(ch, WAFF_PK_RANGE)) && (vwaff = ch_waffected(victim, WAFF_PK_RANGE))) mod = UMIN(waff->modifier, vwaff->modifier); /* level adjustment */ if (ch != victim && !IS_IMMORTAL(ch) && (ch->level >= (victim->level + pk_range(ch->level)+ mod) || ch->level <= (victim->level - pk_range(ch->level) - mod)) && (victim->level >= (ch->level + pk_range(victim->level) + mod) || victim->level <= (ch->level - pk_range(victim->level) - mod))) return FALSE; return TRUE; } bool can_gate(CHAR_DATA * ch, CHAR_DATA * victim) { if (victim == ch || ch->fighting != NULL || victim->in_room == NULL || !can_see_room(ch, victim->in_room) || IS_SET(ch->in_room->room_flags, ROOM_SAFE | ROOM_NORECALL | ROOM_PEACE | ROOM_NOSUMMON) || IS_SET(victim->in_room->room_flags, ROOM_SAFE | ROOM_NORECALL | ROOM_PEACE | ROOM_NOSUMMON) || IS_SET(ch->in_room->area->flags, AREA_CLOSED) || IS_SET(victim->in_room->area->flags, AREA_CLOSED) || room_is_private(victim->in_room) || IS_SET(victim->imm_flags, IMM_SUMMON)) return FALSE; if (IS_NPC(victim)) return TRUE; if (((!in_PK(ch, victim) || ch->in_room->area != victim->in_room->area) && IS_SET(victim->conf_flags, PLR_CONF_NOSUMMON)) || victim->level > LEVEL_HERO || !guild_ok(ch, victim->in_room)) return FALSE; return TRUE; } void transfer_char(CHAR_DATA * ch, CHAR_DATA * vch, ROOM_INDEX_DATA * to_room, const char *msg_out, const char *msg_travel, const char *msg_in) { ROOM_INDEX_DATA *was_in = ch->in_room; if (ch != vch) act_puts(msg_travel, vch, NULL, ch, TO_VICT, POS_DEAD); char_from_room(ch); act(msg_out, was_in->people, NULL, ch, TO_ALL); act(msg_in, to_room->people, NULL, ch, TO_ALL); char_to_room(ch, to_room); if (is_affected(ch, gsn_rnet_trap)) { affect_strip(ch, gsn_rnet_trap); char_puts ("The blood rushes to your feet as you are freed of the net!\n", ch); } if (!JUST_KILLED(ch)) do_look(ch, "auto"); } void recall(CHAR_DATA * ch, ROOM_INDEX_DATA * location) { transfer_char(ch, NULL, location, "$N disappears.", NULL, "$N appears in the room."); } void look_at(CHAR_DATA * ch, ROOM_INDEX_DATA * room) { ROOM_INDEX_DATA *was_in = ch->in_room; OBJ_DATA *obj; bool adjust_light = FALSE; if ((obj = get_eq_char(ch, WEAR_LIGHT)) && obj->pIndexData->item_type == ITEM_LIGHT && obj->value[ITEM_LIGHT_DURATION]) { adjust_light = TRUE; room->light++; } ch->in_room = room; do_look(ch, str_empty); ch->in_room = was_in; if (adjust_light) room->light--; } /* random room generation procedure */ ROOM_INDEX_DATA *get_random_room(CHAR_DATA * ch, AREA_DATA * area) { int min_vnum; int max_vnum; ROOM_INDEX_DATA *room; int i = 0; if (!area) { min_vnum = 1; max_vnum = top_vnum_room; } else { min_vnum = area->min_vnum; max_vnum = area->max_vnum; } for (i = 0; i < 1000; i++) { room = get_room_index(number_range(min_vnum, max_vnum)); if (!room) continue; if (can_see_room(ch, room) && !room_is_private(room) && !IS_SET(room->room_flags, ROOM_SAFE | ROOM_PEACE) && !(IS_SET(room->area->flags, AREA_CLOSED | AREA_NOSUMMON | AREA_CLANHALL | AREA_PLAYERHOUSE) && !area) && !IS_SET(room->room_flags, ROOM_NORECALL | ROOM_NOSUMMON) && (!IS_NPC(ch) || !IS_AGGRO(ch, NULL) || !IS_SET(room->room_flags, ROOM_LAW))) break; } return room; } const char *PERS2(CHAR_DATA * ch, CHAR_DATA * looker, flag32_t flags) { if (is_affected(ch, gsn_doppelganger) && (IS_NPC(looker) || !IS_SET(looker->conf_flags, PLR_CONF_HOLYLIGHT)) && !IS_SET(flags, ACT_REALNAME)) ch = ch->doppel; if (can_see(looker, ch) || (!IS_IMMORTAL(ch) && IS_SET(flags, ACT_REALNAME))) { if (IS_NPC(ch)) { const char *descr; if (IS_SET(flags, ACT_FORMSH)) { return format_short(ch->short_descr, ch->name, looker); } descr = mlstr_cval(ch->short_descr, looker); if (IS_SET(flags, ACT_FIXSH)) return fix_short(descr); return descr; } else if (is_affected(ch, gsn_vampire) && !IS_IMMORTAL(looker) && !IS_SET(flags, ACT_REALNAME)) { return word_form(GETMSG("an ugly creature", looker->lang), ch->sex, looker->lang, RULES_GENDER); } return ch->name; } if (IS_IMMORTAL(ch)) { return word_form(GETMSG("an immortal", looker->lang), ch->sex, looker->lang, RULES_GENDER); } return "someone"; } void format_obj(BUFFER * output, OBJ_DATA * obj) { buf_printf(output, "Object '%s' is type %s, extra flags %s.\n" "Wear location: %s\n" "Weight is %d, value is %d, level is %d.\n", obj->name, flag_string(item_types, obj->pIndexData->item_type), flag_string(extra_flags, obj->extra_flags & ~ITEM_ENCHANTED), (obj->pIndexData->item_type == ITEM_LIGHT) ? "light" : flag_string(wear_flags, obj->wear_flags ^ ITEM_TAKE), obj->weight / 10, obj->cost, obj->level); if (obj->pIndexData->limit != -1) buf_printf(output, "This equipment has been LIMITED by number %d \n", obj->pIndexData->limit); switch (obj->pIndexData->item_type) { case ITEM_LIGHT: buf_printf(output, "Fuel left: %d%%\n", obj->value[ITEM_LIGHT_DURATION] == -1 ? 100 : obj->value[ITEM_LIGHT_DURATION] == 0 ? 0 : (obj->value[ITEM_LIGHT_DURATION] * 100 / obj->pIndexData->value[2])); break; case ITEM_SCROLL: case ITEM_POTION: case ITEM_PILL: buf_printf(output, "Level %d spells of:", obj->value[ITEM_POTION_LEVEL]); if (obj->value[ITEM_POTION_SPELL1] >= 0) buf_printf(output, " '%s'", skill_name(obj->value[ITEM_POTION_SPELL1])); if (obj->value[ITEM_POTION_SPELL2] >= 0) buf_printf(output, " '%s'", skill_name(obj->value[ITEM_POTION_SPELL2])); if (obj->value[ITEM_POTION_SPELL3] >= 0) buf_printf(output, " '%s'", skill_name(obj->value[ITEM_POTION_SPELL3])); if (obj->value[ITEM_POTION_SPELL4] >= 0) buf_printf(output, " '%s'", skill_name(obj->value[ITEM_POTION_SPELL4])); buf_add(output, ".\n"); break; case ITEM_WAND: case ITEM_STAFF: buf_printf(output, "Has %d charges of level %d", obj->value[ITEM_WAND_CHARGES_REMAINING], obj->value[ITEM_WAND_LEVEL]); if (obj->value[ITEM_WAND_SPELL] >= 0) buf_printf(output, " '%s'", skill_name(obj->value[ITEM_WAND_SPELL])); buf_add(output, ".\n"); break; case ITEM_DRINK_CON: buf_printf(output, "It holds %s-colored %s.\n", liq_table[obj->value[ITEM_DRINK_TYPE]].liq_color, liq_table[obj->value[ITEM_DRINK_TYPE]].liq_name); break; case ITEM_CONTAINER: buf_printf(output, "Capacity: %d# Maximum weight: %d# flags: %s\n", obj->value[ITEM_CONTAINER_WEIGHT], obj->value[ITEM_CONTAINER_PER_ITEM_WEIGHT], flag_string(cont_flags, obj->value[ITEM_CONTAINER_FLAGS])); if (obj->value[ITEM_CONTAINER_WEIGHT_MULTI] != 100) buf_printf(output, "Weight multiplier: %d%%\n", obj->value[ITEM_CONTAINER_WEIGHT_MULTI]); break; case ITEM_WEAPON: buf_printf(output, "Weapon type is %s.\n", flag_string(weapon_class, obj->value[ITEM_WEAPON_TYPE])); buf_printf(output, "Damage is %dd%d (average %d).\n", obj->value[ITEM_WEAPON_DICE_NUM], obj->value[ITEM_WEAPON_DICE_SIZE], (1 + obj->value[ITEM_WEAPON_DICE_SIZE]) * obj->value[ITEM_WEAPON_DICE_NUM] / 2); if (obj->value[ITEM_WEAPON_FLAGS]) buf_printf(output, "Weapons flags: %s\n", flag_string(weapon_type2, obj->value[ITEM_WEAPON_FLAGS])); break; case ITEM_ARMOR: buf_printf(output, "Armor class is %d pierce, " "%d bash, %d slash, and %d vs. magic.\n", obj->value[ITEM_ARMOR_AC_PIERCE], obj->value[ITEM_ARMOR_AC_BASH], obj->value[ITEM_ARMOR_AC_SLASH], obj->value[ITEM_ARMOR_AC_EXOTIC]); break; } } void format_obj_affects(BUFFER * output, AFFECT_DATA * paf, int flags) { for (; paf; paf = paf->next) { where_t *w; if (paf->location != APPLY_NONE && paf->modifier) { buf_printf(output, "Affects %s by %d", flag_string(apply_flags, paf->location), paf->modifier); if (!IS_SET(flags, FOA_F_NODURATION) && paf->duration > -1) buf_printf(output, " for %d hours", paf->duration); buf_add(output, ".\n"); } if (IS_SET(flags, FOA_F_NOAFFECTS)) continue; if ((w = where_lookup(paf->where)) && paf->bitvector) { buf_add(output, "Adds "); buf_printf(output, w->format, flag_string(w->table, paf->bitvector)); buf_add(output, ".\n"); } } } int get_wear_level(CHAR_DATA * ch, OBJ_DATA * obj) { int wear_level = ch->level + 15; /* class_t *cl; if ((cl = class_lookup(ch->class)) == NULL) return wear_level; switch (obj->pIndexData->item_type) { case ITEM_POTION: case ITEM_PILL: case ITEM_WAND: case ITEM_STAFF: case ITEM_SCROLL: return wear_level; } if (!IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST) && (obj->pIndexData->limit < 0 || obj->pIndexData->limit > 1)) wear_level += pk_range(wear_level); if (IS_SET(cl->flags, CLASS_MAGIC)) { if (obj->pIndexData->item_type == ITEM_ARMOR) wear_level += 15; } else if (obj->pIndexData->item_type == ITEM_WEAPON) wear_level += 15; */ if (IS_SET(obj->pIndexData->extra_flags, ITEM_QUEST)) { wear_level = ch->level; } return wear_level; } /* * Compute a saving throw. * Negative apply's make saving throw better. */ bool saves_spell(int level, CHAR_DATA * victim, int dam_type) { class_t *vcl; int save; if (IS_DELETED(victim)) return TRUE; save = 40 + (victim->level + victim->drain_level - level) * 4 - (victim->saving_throw * 30) / UMAX(45, victim->level); if (IS_AFFECTED(victim, AFF_BERSERK)) save += victim->level / 5; switch (check_immune(victim, dam_type)) { case IS_IMMUNE: return TRUE; case IS_RESISTANT: save += victim->level / 5; break; case IS_VULNERABLE: save -= victim->level / 5; break; } if (!IS_NPC(victim)) DEBUG(DEBUG_SAVES, "saving throw: %s[%d] against %s[%d] %d%%", victim->name, victim->level, flag_string(damage_class, dam_type), level, save); if (!IS_NPC(victim) && (vcl = class_lookup(victim->class)) && IS_SET(vcl->flags, CLASS_MAGIC)) save = 9 * save / 10; save = URANGE(5, save, 98); return number_percent() < save; } /* RT configuration smashed */ bool saves_dispel(int dis_level, int spell_level, int duration) { int save; /* impossible to dispel permanent effects */ if (duration == -2) return 1; if (duration == -1) spell_level += 5; save = 50 + (spell_level - dis_level) * 5; save = URANGE(5, save, 95); return number_percent() < save; } /* co-routine for dispel magic and cancellation */ bool check_dispel(int dis_level, CHAR_DATA * victim, int sn) { AFFECT_DATA *af; if (is_affected(victim, sn)) { for (af = victim->affected; af != NULL; af = af->next) { if (af->type == sn) { if (!saves_dispel (dis_level, af->level, af->duration)) { skill_t *sk; affect_strip(victim, sn); if ((sk = skill_lookup(sn)) && !IS_NULLSTR(sk->msg_off)) char_printf(victim, "%s\n", sk->msg_off); return TRUE; } else af->level--; } } } return FALSE; } bool check_blind_raw(CHAR_DATA * ch) { if (!IS_NPC(ch) && IS_SET(ch->conf_flags, PLR_CONF_HOLYLIGHT)) return TRUE; if (IS_AFFECTED(ch, AFF_BLIND)) return FALSE; return TRUE; } bool check_blind(CHAR_DATA * ch) { bool can_see = check_blind_raw(ch); if (!can_see) char_puts("You can't see a thing!\n", ch); return can_see; } /* * check_trust - check if victim allow ch to cast SPELL_QUESTIONABLE spell */ bool check_trust(CHAR_DATA * ch, CHAR_DATA * victim) { if (ch == victim) return TRUE; if (IS_NPC(victim)) return is_same_group(ch, victim); if (IS_SET(victim->pcdata->trust, TRUST_ALL)) return TRUE; return (IS_SET(victim->pcdata->trust, TRUST_GROUP) && is_same_group(ch, victim)) || (ch->clan && IS_SET(victim->pcdata->trust, TRUST_CLAN) && ch->clan == victim->clan) || (IS_GOOD(ch) && IS_SET(victim->pcdata->trust, TRUST_GOOD)) || (IS_NEUTRAL(ch) && IS_SET(victim->pcdata->trust, TRUST_NEUTRAL)) || (IS_EVIL(ch) && IS_SET(victim->pcdata->trust, TRUST_EVIL)); } /*---------------------------------------------------------------------------- * show affects stuff */ void show_name(CHAR_DATA * ch, BUFFER * output, AFFECT_DATA * paf, AFFECT_DATA * paf_last) { if (paf_last && paf->type == paf_last->type) if (ch && ch->level < 20) return; else buf_add(output, " "); else buf_printf(output, "Spell: {c%-15s{x", skill_name(paf->type)); } void show_duration(BUFFER * output, AFFECT_DATA * paf) { if (paf->duration < 0) buf_add(output, "permanently."); else buf_printf(output, "for {c%d{x hours.", paf->duration); buf_add(output, "\n"); } void show_loc_affect(CHAR_DATA * ch, BUFFER * output, AFFECT_DATA * paf, AFFECT_DATA ** ppaf) { if (ch->level < 20) { show_name(ch, output, paf, *ppaf); if (*ppaf && (*ppaf)->type == paf->type) return; buf_add(output, "\n"); *ppaf = paf; return; } if (paf->location > 0) { show_name(ch, output, paf, *ppaf); buf_printf(output, ": modifies {c%s{x by {c%d{x ", flag_string(apply_flags, paf->location), paf->modifier); show_duration(output, paf); *ppaf = paf; } } void show_bit_affect(BUFFER * output, AFFECT_DATA * paf, AFFECT_DATA ** ppaf, flag32_t where) { char buf[MAX_STRING_LENGTH]; where_t *w = NULL; if (IS_SET(paf->bitvector, AFF_NO_DISPLAY)) return; if (paf->where != where || (w = where_lookup(paf->where)) == NULL || (paf->modifier != 0 && paf->location != 0 && paf->bitvector == 0)) return; show_name(NULL, output, paf, *ppaf); snprintf(buf, sizeof(buf), ": adds %s ", w->format); buf_printf(output, buf, (paf->bitvector) ? flag_string(w->table, paf->bitvector) : "special"); show_duration(output, paf); *ppaf = paf; } void show_obj_affects(CHAR_DATA * ch, BUFFER * output, AFFECT_DATA * paf) { AFFECT_DATA *paf_last = NULL; for (; paf; paf = paf->next) if (paf->location != APPLY_SPELL_AFFECT) if (paf->bitvector) show_bit_affect(output, paf, &paf_last, TO_AFFECTS); } void show_affects(CHAR_DATA * ch, BUFFER * output) { OBJ_DATA *obj; AFFECT_DATA *paf, *paf_last = NULL; buf_add(output, "You are affected by the following spells:\n"); for (paf = ch->affected; paf; paf = paf->next) { show_loc_affect(ch, output, paf, &paf_last); if (ch->level < 20) continue; show_bit_affect(output, paf, &paf_last, TO_AFFECTS); show_bit_affect(output, paf, &paf_last, TO_RESIST); show_bit_affect(output, paf, &paf_last, TO_IMMUNE); } if (ch->level < 20) return; for (obj = ch->carrying; obj; obj = obj->next_content) if (obj->wear_loc != WEAR_NONE) { if (!IS_SET(obj->extra_flags, ITEM_ENCHANTED)) show_obj_affects(ch, output, obj->pIndexData->affected); show_obj_affects(ch, output, obj->affected); } } /* * Parse a name for acceptability. */ bool pc_name_ok(const char *name) { const char *pc; bool fIll, adjcaps = FALSE, cleancaps = FALSE; int total_caps = 0; int i; /* * Reserved words. */ if (is_name(name, "chronos all auto immortals self someone something" "the you demise balance circle loner honor " "none clan")) return FALSE; /* * Length restrictions. */ if (strlen(name) < 2) return FALSE; if (strlen(name) > MAX_CHAR_NAME) return FALSE; /* * Alphanumerics only. * Lock out IllIll twits. */ fIll = TRUE; for (pc = name; *pc != '\0'; pc++) { if (IS_SET(mud_options, OPT_ASCII_ONLY_NAMES) && !isascii(*pc)) return FALSE; if (!isalpha(*pc)) return FALSE; if (isupper(*pc)) { /* ugly anti-caps hack */ if (adjcaps) cleancaps = TRUE; total_caps++; adjcaps = TRUE; } else adjcaps = FALSE; if (LOWER(*pc) != 'i' && LOWER(*pc) != 'l') fIll = FALSE; } if (fIll) return FALSE; if (total_caps > strlen(name) / 2) return FALSE; /* * Prevent players from naming themselves after mobs. */ { MOB_INDEX_DATA *pMobIndex; int iHash; for (iHash = 0; iHash < MAX_KEY_HASH; iHash++) { for (pMobIndex = mob_index_hash[iHash]; pMobIndex != NULL; pMobIndex = pMobIndex->next) if (is_name(name, pMobIndex->name)) return FALSE; } } for (i = 0; i < clans.nused; i++) { class_t *clan = VARR_GET(&clans, i); if (!str_cmp(name, clan->name)) return FALSE; } return TRUE; } /* * check to see if a character has access to this * class skill * */ bool cskill_restricted_ok(CHAR_DATA * ch, cskill_t * skill) { flag32_t ch_sex = (ch->sex == SEX_MALE) ? RS_MALE : (ch->sex == SEX_FEMALE) ? RS_FEMALE : RS_NEUTER; flag32_t ch_align = RALIGN(ch); return (ch_sex & skill->restrict_sex && ch_align & skill->restrict_align && (!CHAR_CREATE_ETHOS || ch->ethos & skill->restrict_ethos)); } #define MAX_STAT_ALIASES 6 const char *stat_aliases[MAX_STATS][MAX_STAT_ALIASES] = { { /* STR */ "Weak", "Poor", "Average", "Strong", "Herculian", "Titanic" }, { /* INT */ "Hopeless", "Poor", "Average", "Good", "Clever", "Genius" }, { /* WIS */ "Fool", "Dim", "Average", "Good", "Wise", "Enlightened" }, { /* DEX */ "Slow", "Clumsy", "Average", "Dextrous", "Quick", "Fast" }, { /* CON */ "Fragile", "Poor", "Average", "Healthy", "Hearty", "Iron" }, { /* CHR */ "Mongol", "Poor", "Average", "Good", "Familier", "Charismatic" }, { /* LCK */ "Irish", "Poor", "Average", "Good", "Charmed", "Blessed" } }; const char *get_stat_alias(CHAR_DATA * ch, int stat) { int val; int delt; int interval = STAT_BASE / MAX_STAT_ALIASES; if (stat >= MAX_STATS) return "Unknown"; val = get_curr_stat(ch, stat); if (IS_NPC(ch)) { if ((val / interval) >= MAX_STAT_ALIASES) return "Godly"; else return stat_aliases[stat][val/interval]; } interval = 2*STAT_RANDOM_VARIANCE / MAX_STAT_ALIASES; delt = (val - ((RACE(ch->race)->pcdata->stats[stat]) - STAT_RANDOM_VARIANCE)) - interval/ 2; if ((delt / interval) < 0) return "Terrible"; if ((delt / interval) >= MAX_STAT_ALIASES) return "Godly"; return stat_aliases[stat][delt/interval]; } /***************************************************************************** * some formatting stuff * */ /* * smash '~' */ const char *fix_short(const char *s) { char *p; static char buf[MAX_STRING_LENGTH]; if (!strchr(s, '~')) return s; for (p = buf; *s && p - buf < sizeof(buf) - 1; s++) { if (*s == '~') continue; *p++ = *s; } *p = '\0'; return buf; } const char *format_short(mlstring * mlshort, const char *name, CHAR_DATA * looker) { static char buf[MAX_STRING_LENGTH]; const char *sshort; sshort = fix_short(mlstr_cval(mlshort, looker)); strnzcpy(buf, sizeof(buf), sshort); if (looker && !IS_SET(looker->comm, COMM_NOENG) && sshort != mlstr_mval(mlshort)) { char buf2[MAX_STRING_LENGTH]; char buf3[MAX_STRING_LENGTH]; one_argument(name, buf3, sizeof(buf3)); snprintf(buf2, sizeof(buf2), " (%s)", buf3); strnzcat(buf, sizeof(buf), buf2); } return buf; } /* * format description (long descr for mobs, description for objs) * * eng name expected to be in form " (foo)" and is stripped * if COMM_NOENG is set */ const char *format_descr(mlstring * ml, CHAR_DATA * looker) { const char *s; const char *p, *q; static char buf[MAX_STRING_LENGTH]; s = mlstr_cval(ml, looker); if (IS_NULLSTR(s) || !IS_SET(looker->comm, COMM_NOENG) || (p = strchr(s, '(')) == NULL || (q = strchr(p + 1, ')')) == NULL) return s; if (p != s && *(p - 1) == ' ') p--; strnzncpy(buf, sizeof(buf), s, p - s); strnzcat(buf, sizeof(buf), q + 1); return buf; } #if defined (WIN32) void SET_ORG_RACE(CHAR_DATA * ch, int race) { if (IS_NPC(ch)) ch->pIndexData->race = race; else ch->pcdata->race = race; } #elif defined (LINUX) void SET_ORG_RACE(CHAR_DATA * ch, int race) { if (IS_NPC(ch)) ch->pIndexData->race = race; else ch->pcdata->race = race; } #endif /* * extracts all objects of a certain type from a character, * whether in inventory or in a container. * * returns the number of objects extracted */ int strip_obj_from_char(CHAR_DATA * ch, CHAR_DATA * victim, OBJ_INDEX_DATA * pObj) { int count = 0; count += strip_from_container(victim, victim->carrying, pObj); return count; } int strip_from_container(CHAR_DATA * victim, OBJ_DATA * first_item, OBJ_INDEX_DATA * pObj) { OBJ_DATA *obj, *obj_next; int count = 0; for (obj = first_item; obj; obj = obj_next) { obj_next = obj->next_content; if (obj->pIndexData->item_type == ITEM_CONTAINER) count += strip_from_container(victim, obj->contains, pObj); if (obj->pIndexData->vnum == pObj->vnum) { DEBUG(DEBUG_OBJ_STRIP, "stripped: %s lost [%d] %s", victim->name, obj->pIndexData->vnum, obj->pIndexData->name); if (obj->wear_loc != WEAR_NONE) remove_obj(victim, obj->wear_loc, TRUE); extract_obj(obj, 0); count++; } } return count; } int world_alignment() { CHAR_DATA *wch; int align = 0; int count = 0; for (wch = char_list; wch && !IS_NPC(wch); wch = wch->next) { if (wch->desc && wch->desc->connected == CON_PLAYING && !IS_IMMORTAL(wch)) { count++; align += wch->alignment; } } if (count == 0) return 0; return align / count; } /* * sets the average damage for the item * in the way of dice and size, as is appropriate * for the particular weapon. * * percent_damage - the percent of normal damage * that this object has. * 100% is obviously default. * * returns the avg damage */ int autoweapon(OBJ_DATA * obj, int percent_damage) { int dice = 0, size = 0, avg = 0; int saved_level = obj->pIndexData->level; if (percent_damage <= 0) { DEBUG(DEBUG_BUILD_AUTO, "autoweapon: requested %d%% damage. Autoing to 100%", percent_damage); percent_damage = 100; } obj->pIndexData->level = obj->level; avg = get_autoweapon(obj->pIndexData, &dice, &size, percent_damage); obj->pIndexData->level = saved_level; obj->value[ITEM_WEAPON_DICE_NUM] = dice; obj->value[ITEM_WEAPON_DICE_SIZE] = size; return avg; } bool is_aggressive_to(CHAR_DATA * ch, CHAR_DATA * victim) { if (!IS_NPC(ch)) return FALSE; if (!IS_SET(ch->pIndexData->act, ACT_AGGRESSIVE) && !IS_SET(ch->pIndexData->act, ACT_AGGRO_RELATIVE)) return FALSE; if (!victim) return TRUE; if (IS_NPC(victim)) return FALSE; if (IS_IMMORTAL(victim)) return FALSE; if (IS_SET(ch->pIndexData->act, ACT_AGGRO_RELATIVE) && (ch->level >= (victim->level + pk_range(ch->level)) || ch->level <= (victim->level - pk_range(ch->level))) && (victim->level >= (ch->level + pk_range(victim->level)) || victim->level <= (ch->level - pk_range(victim->level)))) return TRUE; if (ch->level >= victim->level - 5) return FALSE; return TRUE; } void add_past_owner(OBJ_DATA * obj, CHAR_DATA * ch) { int i; if (!ch->desc) return; if (!str_cmp(ch->name, obj->past_owner[0])) return; if (obj->past_owner[PAST_OWNER_MAX - 1]) { free_string(obj->past_owner[PAST_OWNER_MAX - 1]); obj->past_owner[PAST_OWNER_MAX - 1] = NULL; } if (obj->past_owner_ip[PAST_OWNER_MAX - 1]) { free_string(obj->past_owner_ip[PAST_OWNER_MAX - 1]); obj->past_owner_ip[PAST_OWNER_MAX - 1] = NULL; } for (i = PAST_OWNER_MAX - 1; i > 0; i--) { obj->past_owner[i] = obj->past_owner[i - 1]; obj->past_owner_ip[i] = obj->past_owner_ip[i - 1]; } obj->past_owner[0] = str_printf("%s", ch->name); obj->past_owner_ip[0] = str_printf("%s", (ch->pcdata->fake_ip) ? ch->pcdata->fake_ip : ch->desc->host); } /* * check to see if one of the previous owners was * an alt of the player. Obviously, since IPs aren't necessarily * unique, this is just a suggestion of wrong doing. * * function reports which past owner. */ int past_owner_alt(OBJ_DATA * obj, CHAR_DATA * ch) { int i = -1; for (i = 0; i < PAST_OWNER_MAX; i++) { if (!IS_NULLSTR(obj->past_owner[i]) && !str_cmp( (ch->pcdata->fake_ip) ? ch->pcdata->fake_ip : ch->desc->host, obj->past_owner_ip[i]) && str_cmp(ch->name, obj->past_owner[i])) return i; } return -1; } int count_limiteds(CHAR_DATA * ch) { OBJ_DATA *obj; int limiteds = 0; for (obj = ch->carrying; obj != NULL; obj = obj->next_content) if (IS_OBJ_LIMITED(obj->pIndexData)) limiteds++; return limiteds; } bool align_standing_important(CHAR_DATA * ch) { if (IS_NPC(ch)) return FALSE; switch (ch->class) { case CLASS_PALADIN: case CLASS_CLERIC: return TRUE; } return FALSE; } /* * for neutrals to know if they're being too good, or evil */ int align_standing_leaning(CHAR_DATA * ch) { int good; int evil; if (IS_NPC(ch)) return 0; good = ch->pcdata->align_standing[ALIGN_INDEX_GOOD]; evil = ch->pcdata->align_standing[ALIGN_INDEX_EVIL]; if (good > (evil * 120 / 100)) return 1; if (evil > (good * 120 / 100)) return -1; return 0; } /** * return how true they are to their alignment */ int align_standing_raw(CHAR_DATA * ch) { int sum = 0; int tmp = 0; int good = 0; int neut = 0; int evil = 0; if (IS_NPC(ch)) return 0; good = ch->pcdata->align_standing[ALIGN_INDEX_GOOD]; neut = ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL]; evil = ch->pcdata->align_standing[ALIGN_INDEX_EVIL]; if (IS_GOOD(ch)) { sum = good; sum -= neut / 3; sum -= evil * 2; } else if (IS_EVIL(ch)) { sum = evil; sum += neut / 4; sum -= good * 2; } else { sum = neut; sum += (good + evil); if (good > (evil * 120 / 100) || evil > (good * 120 / 100)) tmp = (good - evil) * 2; tmp = ABS(tmp); sum -= tmp; } return sum; } int align_standing(CHAR_DATA * ch) { int index = 0; int standing = align_standing_raw(ch); if (standing > ALIGN_STANDING_UNIT * 5000) index = ALIGN_STANDING_G8; else if (standing > ALIGN_STANDING_UNIT * 2000) index = ALIGN_STANDING_G7; else if (standing > ALIGN_STANDING_UNIT * 1000) index = ALIGN_STANDING_G6; else if (standing > ALIGN_STANDING_UNIT * 500) index = ALIGN_STANDING_G5; else if (standing > ALIGN_STANDING_UNIT * 250) index = ALIGN_STANDING_G4; else if (standing > ALIGN_STANDING_UNIT * 100) index = ALIGN_STANDING_G3; else if (standing > ALIGN_STANDING_UNIT * 50) index = ALIGN_STANDING_G2; else if (standing > ALIGN_STANDING_UNIT * 10) index = ALIGN_STANDING_G1; else if (standing < ALIGN_STANDING_UNIT * -5) index = ALIGN_STANDING_B1; else if (standing < ALIGN_STANDING_UNIT * -25) index = ALIGN_STANDING_B2; else if (standing < ALIGN_STANDING_UNIT * -50) index = ALIGN_STANDING_B3; else if (standing < ALIGN_STANDING_UNIT * -100) index = ALIGN_STANDING_B4; else if (standing < ALIGN_STANDING_UNIT * -250) index = ALIGN_STANDING_B5; else if (standing < ALIGN_STANDING_UNIT * -500) index = ALIGN_STANDING_B6; else if (standing < ALIGN_STANDING_UNIT * -1000) index = ALIGN_STANDING_B7; else index = ALIGN_STANDING_0; DEBUG(DEBUG_ALIGN_STANDING, "align_standing: %s %d: %d/%d/%d = %d", ch->name, standing, ch->pcdata->align_standing[ALIGN_INDEX_GOOD], ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL], ch->pcdata->align_standing[ALIGN_INDEX_EVIL], index); return index; } /** * converts alignment standing to a bonus * or negative. */ int align_standing_bonus(CHAR_DATA * ch) { int bonus = 0; int standing = align_standing(ch); switch (standing) { case ALIGN_STANDING_G8: bonus = 6; break; case ALIGN_STANDING_G7: bonus = 5; break; case ALIGN_STANDING_G6: bonus = 4; break; case ALIGN_STANDING_G5: bonus = 3; break; case ALIGN_STANDING_G4: bonus = 2; break; case ALIGN_STANDING_G3: bonus = 1; break; case ALIGN_STANDING_G2: case ALIGN_STANDING_G1: bonus = 0; break; case ALIGN_STANDING_0: case ALIGN_STANDING_B1: bonus = -1; break; case ALIGN_STANDING_B2: bonus = -2; break; case ALIGN_STANDING_B3: bonus = -3; break; case ALIGN_STANDING_B4: bonus = -4; break; case ALIGN_STANDING_B5: bonus = -5; break; case ALIGN_STANDING_B6: bonus = -6; break; case ALIGN_STANDING_B7: bonus = -7; break; default: bonus = 0; break; } return bonus; } int standing_update(CHAR_DATA * ch) { int dec = ALIGN_STANDING_UNIT / 10; if (ch->level >= HERO) dec = dec * 50 / 100; if (IS_NPC(ch)) return 0; if (IS_GOOD(ch)) { ch->pcdata->align_standing[ALIGN_INDEX_GOOD] -= dec; ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] -= dec; ch->pcdata->align_standing[ALIGN_INDEX_EVIL] -= (dec / 5 + 1); } else if (IS_EVIL(ch)) { ch->pcdata->align_standing[ALIGN_INDEX_EVIL] -= dec; ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] -= dec; ch->pcdata->align_standing[ALIGN_INDEX_GOOD] -= (dec / 5 + 1); } else { ch->pcdata->align_standing[ALIGN_INDEX_GOOD] -= dec; ch->pcdata->align_standing[ALIGN_INDEX_EVIL] -= dec; } /* no lower than zero */ if (ch->pcdata->align_standing[ALIGN_INDEX_GOOD] < 0) ch->pcdata->align_standing[ALIGN_INDEX_GOOD] = 0; if (ch->pcdata->align_standing[ALIGN_INDEX_EVIL] < 0) ch->pcdata->align_standing[ALIGN_INDEX_EVIL] = 0; /* neuts can do anti-neut deeds */ if (IS_NEUTRAL(ch)) { /* make neut standing tend toward zero */ if (ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] > 0) ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] -= dec; else { ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] += dec / 5; if (ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] > 0) ch->pcdata-> align_standing[ALIGN_INDEX_NEUTRAL] = 0; } } else { if (ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] < 0) ch->pcdata->align_standing[ALIGN_INDEX_NEUTRAL] = 0; } return 0; } int align_standing_death_gain(CHAR_DATA * ch, CHAR_DATA * victim) { if (!IS_NPC(ch)) { if (IS_GOOD(victim) && victim->level > (ch->level - 5)) ch->pcdata->align_standing[ALIGN_INDEX_EVIL] += (IS_NPC(victim)) ? ALIGN_STANDING_UNIT : ALIGN_STANDING_UNIT * 10; if (IS_NEUTRAL(victim)) { if (IS_NEUTRAL(ch)) { ch->pcdata-> align_standing[ALIGN_INDEX_NEUTRAL] += (IS_NPC(victim)) ? ALIGN_STANDING_UNIT * -1 : ALIGN_STANDING_UNIT * -1; } else if (IS_GOOD(ch) && victim->level > (ch->level - 5)) { ch->pcdata->align_standing[ALIGN_INDEX_GOOD] += (IS_NPC(victim)) ? ALIGN_STANDING_UNIT / 5 : ALIGN_STANDING_UNIT * 3; } else if (victim->level > (ch->level - 5)) { ch->pcdata->align_standing[ALIGN_INDEX_EVIL] += (IS_NPC(victim)) ? ALIGN_STANDING_UNIT / 2 : ALIGN_STANDING_UNIT * 5; } } if (IS_EVIL(victim) && victim->level > (ch->level - 5)) { ch->pcdata->align_standing[ALIGN_INDEX_GOOD] += (IS_NPC(victim)) ? ALIGN_STANDING_UNIT : ALIGN_STANDING_UNIT * 10; } } return 1; } /* * removes all types of hide affects */ bool remove_hide_affect(CHAR_DATA * ch, flag64_t aff_hide) { AFFECT_DATA *paf = NULL; bool unhide = FALSE; if (IS_SET(aff_hide, AFF_HIDE)) { REMOVE_BIT(ch->affected_by, AFF_HIDE); if ((paf = affect_find(ch->affected, gsn_hide)) != NULL) affect_remove(ch, paf); unhide = TRUE; } if (IS_SET(aff_hide, AFF_FADE)) { REMOVE_BIT(ch->affected_by, AFF_FADE); if ((paf = affect_find(ch->affected, gsn_fade)) != NULL) affect_remove(ch, paf); unhide = TRUE; } if (IS_SET(aff_hide, AFF_CAMOUFLAGE)) { REMOVE_BIT(ch->affected_by, AFF_CAMOUFLAGE); if ((paf = affect_find(ch->affected, gsn_camouflage)) != NULL) affect_remove(ch, paf); unhide = TRUE; } return unhide; } bool add_pk_ok (CHAR_DATA *ch, CHAR_DATA *victim) { if (IS_NPC(ch) || IS_NPC(victim)) return FALSE; return name_add(&ch->pcdata->pk_ok_list, victim->name, NULL, "PKOKlist"); } bool delete_pk_ok (CHAR_DATA *ch, CHAR_DATA *victim) { if (IS_NPC(ch) || IS_NPC(victim)) return FALSE; return name_delete(&ch->pcdata->pk_ok_list, victim->name, NULL, "PKOKlist"); } /* * count the objects in a container. * if recursive, count the object in containers in the contain, etc */ int obj_in_context_count (OBJ_DATA *context, bool recursive) { int count = 0; OBJ_DATA *obj; for (obj = context; obj; obj = obj->next_content) { count++; if (recursive && obj->pIndexData->item_type == ITEM_CONTAINER) count += obj_in_context_count(obj->contains, TRUE); } return count; } CHAR_DATA *summon_shop_guard (CHAR_DATA *ch, CHAR_DATA *victim) { CHAR_DATA *guard; int i; guard = create_mob(get_mob_index(MOB_VNUM_SHOP_GUARD)); for (i = 0; i < MAX_STATS; i++) { guard->perm_stat[i] = victim->perm_stat[i] - 1; } guard->perm_stat[STAT_STR] = 80; guard->max_hit = UMIN(30000, 2 * victim->max_hit); guard->hit = victim->max_hit; guard->max_mana = victim->max_mana; guard->hitroll = victim->hitroll; guard->damroll = victim->damroll; guard->level = victim->level; guard->damage[DICE_NUMBER] = UMAX(2, number_range(guard->level / 20, guard->level / 16)); guard->damage[DICE_TYPE] = UMAX(2, number_range(guard->level / 4, guard->level / 3)); guard->damage[DICE_BONUS] = UMAX(2, number_range(guard->level / 12, guard->level / 10)); for (i = 0; i < 3; i++) guard->armor[i] = interpolate(guard->level, 100, -100); guard->armor[3] = interpolate(guard->level, 100, 0); guard->gold = number_range(0, 2); guard->target = victim; char_to_room(guard, victim->in_room); act("$n arrives, heeding the merchant's call.", guard, NULL, NULL, TO_ALL); return guard; } /* * Check if ch has a given item or item type * vnum: item vnum or -1 * item_type: item type or -1 * fWear: TRUE: item must be worn, FALSE: don't care */ OBJ_DATA * has_item(CHAR_DATA * ch, int vnum, int item_type, bool fWear) { OBJ_DATA *obj; for (obj = ch->carrying; obj; obj = obj->next_content) if ((vnum < 0 || obj->pIndexData->vnum == vnum) && (item_type < 0 || obj->pIndexData->item_type == item_type) && (!fWear || obj->wear_loc != WEAR_NONE)) return obj; return NULL; } bool extract_obj_type (CHAR_DATA *ch, int vnum, int item_type) { OBJ_DATA *obj; for (obj = ch->carrying; obj; obj = obj->next_content) if ((vnum < 0 || obj->pIndexData->vnum == vnum) && (item_type < 0 || obj->pIndexData->item_type == item_type)) { obj_from_char(obj); extract_obj(obj, 0); return TRUE; } return FALSE; } int get_ac (CHAR_DATA *ch, int type) { int ac = 0; ac = ch->armor[type]; if (!IS_AWAKE(ch)) ac = ac / 3; return ac; }