/* ************************************************************************ * File: handler.c EmpireMUD AD 1.0 * * Usage: internal funcs: moving and finding chars/objs * * * * All rights reserved. See license.doc for complete information. * * * * Code base by Paul Clarke. EmpireMUD Project, a tbgMUD Production. * * Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson. * * * * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * ************************************************************************ */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "db.h" #include "handler.h" #include "interpreter.h" #include "empire.h" #include "skills.h" /* external vars */ extern Creature combat_list; extern const char *MENU; /* external functions */ void remove_follower(Creature ch); void die_follower(Creature ch); ACMD(do_return); /* Returns the maximum an attribute may be for a given ch (or void, for normal max) */ int att_max(Creature ch) { if (ch && !IS_NPC(ch)) { /* morph accounts for werewolves */ if (GET_MORPH(ch) != MORPH_NONE) return 10; if (IS_VAMPIRE(ch)) return (GET_GENERATION(ch) < 8 ? (5 + 8 - GET_GENERATION(ch)) : 5); return 5; } return 5; } /* Returns the maximum a discipline may be */ int disc_max(Creature ch) { if (IS_NPC(ch) || IS_HUMAN(ch)) return 0; if (IS_VAMPIRE(ch)) return att_max(ch); if (IS_GHOUL(ch)) switch (GET_GENERATION(ch)) { case 7: return 2; case 6: return 3; case 5: return 4; case 4: return 5; case 3: return 6; case 2: return 7; case 1: return 8; default: return 1; } return 0; } void gain_experience(Creature ch, int amt) { if (IS_NPC(ch)) return; /* Experience may be 0 to 250 */ GET_EXPERIENCE(ch) = MAX(0, MIN(EXP_CAP, GET_EXPERIENCE(ch) + amt)); } char *fname(const char *namelist) { static char holder[30]; register char *point; for (point = holder; isalpha(*namelist); namelist++, point++) *point = *namelist; *point = '\0'; return (holder); } #define WHITESPACE " \t" int isname(char *str, char *namelist) { char *newlist; char *curtok; newlist = strdup(namelist); for (curtok = strtok(newlist, WHITESPACE); curtok; curtok = strtok(NULL, WHITESPACE)) if (curtok && is_abbrev(str, curtok)) { free(newlist); return 1; } free(newlist); return 0; } int iname(char *str, char *namelist) { char *newlist; char *curtok; newlist = strdup(namelist); for (curtok = strtok(newlist, WHITESPACE); curtok; curtok = strtok(NULL, WHITESPACE)) if (curtok && !str_cmp(str, curtok)) { free(newlist); return 1; } free(newlist); return 0; } void affect_modify(Creature ch, byte loc, sh_int mod, bitvector_t bitv, bitvector_t disc_bit, bool add) { if (add) { SET_BIT(AFF_FLAGS(ch), bitv); SET_BIT(DSC_FLAGS(ch), disc_bit); } else { REMOVE_BIT(AFF_FLAGS(ch), bitv); REMOVE_BIT(DSC_FLAGS(ch), disc_bit); mod = -mod; } switch (loc) { case APPLY_NONE: break; case APPLY_STRENGTH: GET_STRENGTH(ch) += mod; break; case APPLY_DEXTERITY: GET_DEXTERITY(ch) += mod; break; case APPLY_STAMINA: GET_STAMINA(ch) += mod; break; case APPLY_CHARISMA: GET_CHARISMA(ch) += mod; break; case APPLY_MANIPULATION: GET_MANIPULATION(ch) += mod; break; case APPLY_APPEARANCE: /* Clan Weakness: Nosferatu */ if (GET_CLAN(ch) != CLAN_NOSFERATU) GET_APPEARANCE(ch) += mod; break; case APPLY_PERCEPTION: GET_PERCEPTION(ch) += mod; break; case APPLY_INTELLIGENCE: GET_INTELLIGENCE(ch) += mod; break; case APPLY_WITS: GET_WITS(ch) += mod; break; case APPLY_AGE: ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR); break; case APPLY_MOVE: GET_MAX_MOVE(ch) += mod; GET_MOVE(ch) += mod; break; case APPLY_SOAK: GET_SOAK(ch) += mod; break; case APPLY_BLOCK: GET_BLOCK(ch) += mod; break; case APPLY_ATTACKS: ATTACK_BONUS(ch) += mod; break; case APPLY_FORTITUDE: GET_REAL_DISC(ch, DISC_FORTITUDE) += mod; break; default: log("SYSERR: Unknown apply adjust %d attempt (%s, affect_modify).", loc, __FILE__); break; } /* switch */ } /* This updates a character by subtracting everything he is affected by */ /* restoring original abilities, and then affecting all again */ void affect_total(Creature ch) { void update_morph_stats(Creature ch, bool add); struct affected_type *af; int i, j; for (i = 0; i < NUM_WEARS; i++) { if (GET_EQ(ch, i) && i != WEAR_IN_SHEATH_1 && i != WEAR_IN_SHEATH_2 && i != WEAR_IN_SHEATH_3) for (j = 0; j < MAX_OBJ_AFFECT; j++) affect_modify(ch, GET_EQ(ch, i)->affected[j].location, GET_EQ(ch, i)->affected[j].modifier, GET_EQ(ch, i)->obj_flags.bitvector, 0, FALSE); } update_morph_stats(ch, FALSE); for (af = ch->affected; af; af = af->next) affect_modify(ch, af->location, af->modifier, af->bitvector, af->disc_bit, FALSE); ch->aff_abils = ch->real_abils; GET_MAX_MOVE(ch) = 100; for (i = 0; i < NUM_WEARS; i++) { if (GET_EQ(ch, i) && i != WEAR_IN_SHEATH_1 && i != WEAR_IN_SHEATH_2 && i != WEAR_IN_SHEATH_3) for (j = 0; j < MAX_OBJ_AFFECT; j++) affect_modify(ch, GET_EQ(ch, i)->affected[j].location, GET_EQ(ch, i)->affected[j].modifier, GET_EQ(ch, i)->obj_flags.bitvector, 0, TRUE); } update_morph_stats(ch, TRUE); for (af = ch->affected; af; af = af->next) affect_modify(ch, af->location, af->modifier, af->bitvector, af->disc_bit, TRUE); /* Make sure maximums are considered */ GET_STRENGTH(ch) = MAX(0, MIN(GET_STRENGTH(ch), att_max(ch))); GET_DEXTERITY(ch) = MAX(0, MIN(GET_DEXTERITY(ch), att_max(ch))); GET_STAMINA(ch) = MAX(0, MIN(GET_STAMINA(ch), att_max(ch))); GET_CHARISMA(ch) = MAX(0, MIN(GET_CHARISMA(ch), att_max(ch))); GET_MANIPULATION(ch) = MAX(0, MIN(GET_MANIPULATION(ch), att_max(ch))); /* Clan Weakness: Nosferatu */ if (GET_CLAN(ch) == CLAN_NOSFERATU) GET_APPEARANCE(ch) = 0; else GET_APPEARANCE(ch) = MAX(0, MIN(GET_APPEARANCE(ch), att_max(ch))); GET_PERCEPTION(ch) = MAX(0, MIN(GET_PERCEPTION(ch), att_max(ch))); GET_INTELLIGENCE(ch) = MAX(0, MIN(GET_INTELLIGENCE(ch), att_max(ch))); GET_WITS(ch) = MAX(0, MIN(GET_WITS(ch), att_max(ch))); } /* * Insert an affect_type in a char_data structure * Automatically sets apropriate bits and apply's */ void affect_to_char(Creature ch, struct affected_type *af) { struct affected_type *affected_alloc; CREATE(affected_alloc, struct affected_type, 1); *affected_alloc = *af; affected_alloc->next = ch->affected; ch->affected = affected_alloc; affect_modify(ch, af->location, af->modifier, af->bitvector, af->disc_bit, TRUE); affect_total(ch); } /* Add an affect to a room */ void affect_to_room(room_rnum room, struct affected_type *af) { struct affected_type *affected_alloc; CREATE(affected_alloc, struct affected_type, 1); *affected_alloc = *af; affected_alloc->next = world[room].af; world[room].af = affected_alloc; SET_BIT(world[room].affects, af->bitvector); } /* * Remove an affected_type structure from a char (called when duration * reaches zero). Pointer *af must never be NIL! Frees mem and calls * affect_location_apply */ void affect_remove(Creature ch, struct affected_type *af) { struct affected_type *temp; if (ch->affected == NULL) return; affect_modify(ch, af->location, af->modifier, af->bitvector, af->disc_bit, FALSE); REMOVE_FROM_LIST(af, ch->affected, next); free(af); affect_total(ch); } /* * Remove an affected_type structure from a room (called when duration * reaches zero). Pointer *af must never be NIL! Frees mem and calls * affect_location_apply */ void affect_remove_room(room_rnum room, struct affected_type *af) { struct affected_type *temp; if (world[room].af == NULL) return; REMOVE_BIT(world[room].affects, af->bitvector); REMOVE_FROM_LIST(af, world[room].af, next); free(af); } /* Call affect_remove with every skill named "type" */ void affect_from_char(Creature ch, int type) { struct affected_type *hjp, *next; for (hjp = ch->affected; hjp; hjp = next) { next = hjp->next; if (hjp->type == type) affect_remove(ch, hjp); } } /* Call affect_remove_room with every skill named "type" */ void affect_from_room(room_rnum room, int type) { struct affected_type *hjp, *next; for (hjp = world[room].af; hjp; hjp = next) { next = hjp->next; if (hjp->type == type) affect_remove_room(room, hjp); } } /* * Return TRUE if a char is affected by an ability, * FALSE indicates not affected. */ bool affected_by_spell(Creature ch, int type) { struct affected_type *hjp; for (hjp = ch->affected; hjp; hjp = hjp->next) if (hjp->type == type) return (TRUE); return (FALSE); } bool room_affected_by_spell(room_rnum room, int type) { struct affected_type *hjp; for (hjp = world[room].af; hjp; hjp = hjp->next) if (hjp->type == type) return (TRUE); return (FALSE); } void affect_join(Creature ch, struct affected_type * af, bool add_dur, bool avg_dur, bool add_mod, bool avg_mod) { struct affected_type *hjp; bool found = FALSE; for (hjp = ch->affected; !found && hjp; hjp = hjp->next) { if ((hjp->type == af->type) && (hjp->location == af->location)) { if (add_dur) af->duration += hjp->duration; if (avg_dur) af->duration = (af->duration + hjp->duration) / 2; if (add_mod) af->modifier += hjp->modifier; if (avg_mod) af->modifier = (af->modifier + hjp->modifier) / 2; affect_remove(ch, hjp); affect_to_char(ch, af); found = TRUE; } } if (!found) affect_to_char(ch, af); } /* move a player out of a room */ void char_from_room(Creature ch) { extern int char_from_chair(Creature ch); Creature temp; Object obj; int pos; if (ch == NULL || ch->in_room == NOWHERE) { log("SYSERR: NULL character or NOWHERE in %s, char_from_room", __FILE__); exit(1); } if (ON_CHAIR(ch)) char_from_chair(ch); if (FIGHTING(ch) != NULL) stop_fighting(ch); for (pos = 0; pos < NUM_WEARS; pos++) if (GET_EQ(ch, pos) && OBJ_FLAGGED(GET_EQ(ch, pos), ITEM_LIGHT)) world[ch->in_room].light--; for (obj = ch->carrying; obj; obj = obj->next_content) if (OBJ_FLAGGED(obj, ITEM_LIGHT)) world[ch->in_room].light--; REMOVE_FROM_LIST(ch, world[ch->in_room].people, next_in_room); ch->in_room = NOWHERE; ch->next_in_room = NULL; } /* place a character in a room */ void char_to_room(Creature ch, room_rnum room) { int pos; Object obj; if (ch == NULL || room < 0 || room > top_of_world) log("SYSERR: Illegal value(s) passed to char_to_room. (Room: %d/%d Ch: %p", room, top_of_world, ch); else { if (ch->in_room != NOWHERE) char_from_room(ch); ch->next_in_room = world[room].people; world[room].people = ch; ch->in_room = room; for (pos = 0; pos < NUM_WEARS; pos++) if (GET_EQ(ch, pos) && OBJ_FLAGGED(GET_EQ(ch, pos), ITEM_LIGHT)) world[room].light++; for (obj = ch->carrying; obj; obj = obj->next_content) if (OBJ_FLAGGED(obj, ITEM_LIGHT)) world[room].light++; /* Stop fighting now, if we left. */ if (FIGHTING(ch) && IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) { stop_fighting(FIGHTING(ch)); stop_fighting(ch); } } if (GET_RIDING(ch)) char_to_room(GET_RIDING(ch), ch->in_room); } /* Make sure an object is NOWHERE! */ void check_obj_in_void(Object obj) { if (!obj) return; if (obj->in_room != NOWHERE) obj_from_room(obj); if (obj->in_obj) obj_from_obj(obj); if (obj->carried_by) obj_from_char(obj); if (obj->worn_by) if (unequip_char(obj->worn_by, obj->worn_on) != obj) log("SYSERR: Inconsistent worn_by and worn_on pointers!!"); } /* give an object to a char */ void obj_to_char(Object object, Creature ch) { check_obj_in_void(object); if (object && ch) { object->next_content = ch->carrying; ch->carrying = object; object->carried_by = ch; object->in_room = NOWHERE; IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object); IS_CARRYING_N(ch)++; if (ch->in_room != NOWHERE && OBJ_FLAGGED(object, ITEM_LIGHT)) world[ch->in_room].light++; } else log("SYSERR: NULL obj (%p) or char (%p) passed to obj_to_char.", object, ch); } /* take an object from a char */ void obj_from_char(Object object) { Object temp; if (object == NULL) { log("SYSERR: NULL object passed to obj_from_char."); return; } REMOVE_FROM_LIST(object, object->carried_by->carrying, next_content); IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object); IS_CARRYING_N(object->carried_by)--; if (object->carried_by->in_room != NOWHERE && OBJ_FLAGGED(object, ITEM_LIGHT)) world[object->carried_by->in_room].light++; object->carried_by = NULL; object->next_content = NULL; } void equip_char(Creature ch, Object obj, int pos) { int j; if (pos < 0 || pos >= NUM_WEARS) return; if (GET_EQ(ch, pos)) { log("SYSERR: Char is already equipped: %s, %s", GET_NAME(ch), obj->short_description); return; } check_obj_in_void(obj); if (obj->carried_by) { log("SYSERR: EQUIP: Obj is carried_by when equip."); return; } if (obj->in_room != NOWHERE) { log("SYSERR: EQUIP: Obj is in_room when equip."); return; } GET_EQ(ch, pos) = obj; obj->worn_by = ch; obj->worn_on = pos; if (ch->in_room != NOWHERE && OBJ_FLAGGED(obj, ITEM_LIGHT)) world[ch->in_room].light++; if (pos != WEAR_IN_SHEATH_1 && pos != WEAR_IN_SHEATH_2 && pos != WEAR_IN_SHEATH_3) for (j = 0; j < MAX_OBJ_AFFECT; j++) affect_modify(ch, obj->affected[j].location, obj->affected[j].modifier, obj->obj_flags.bitvector, 0, TRUE); affect_total(ch); } Object unequip_char(Creature ch, int pos) { int j; Object obj; if ((pos < 0 || pos >= NUM_WEARS) || GET_EQ(ch, pos) == NULL) return (NULL); obj = GET_EQ(ch, pos); obj->worn_by = NULL; obj->worn_on = -1; if (ch->in_room != NOWHERE && OBJ_FLAGGED(obj, ITEM_LIGHT)) world[ch->in_room].light--; GET_EQ(ch, pos) = NULL; if (pos != WEAR_IN_SHEATH_1 && pos != WEAR_IN_SHEATH_2 && pos != WEAR_IN_SHEATH_3) for (j = 0; j < MAX_OBJ_AFFECT; j++) affect_modify(ch, obj->affected[j].location, obj->affected[j].modifier, obj->obj_flags.bitvector, 0, FALSE); affect_total(ch); return (obj); } int get_number(char **name) { int i; char *ppos; char number[MAX_INPUT_LENGTH]; *number = '\0'; if ((ppos = strchr(*name, '.')) != NULL) { *ppos++ = '\0'; strcpy(number, *name); strcpy(*name, ppos); for (i = 0; *(number + i); i++) if (!isdigit(*(number + i))) return (0); return (atoi(number)); } return (1); } /* Search a given list for an object number, and return a ptr to that obj */ Object get_obj_in_list_num(int num, Object list) { Object i; for (i = list; i; i = i->next_content) if (GET_OBJ_RNUM(i) == num) return (i); return (NULL); } /* search the entire world for an object number, and return a pointer */ Object get_obj_num(obj_rnum nr) { Object i; for (i = object_list; i; i = i->next) if (GET_OBJ_RNUM(i) == nr) return (i); return (NULL); } /* search a room for a char, and return a pointer if found.. */ Creature get_char_room(char *name, room_rnum room) { Creature i; int j = 0, number; char tmpname[MAX_INPUT_LENGTH]; char *tmp = tmpname; strcpy(tmp, name); if (!(number = get_number(&tmp))) return (NULL); for (i = world[room].people; i && (j <= number); i = i->next_in_room) if (isname(tmp, i->player.name) || isname(tmp, PERS(i, i, 0)) || isname(tmp, PERS(i, i, 1)) || (GET_LASTNAME(i) && isname(name, GET_LASTNAME(i)))) if (++j == number) return (i); return (NULL); } /* search all over the world for a char num, and return a pointer if found */ Creature get_char_num(mob_rnum nr) { Creature i; for (i = character_list; i; i = i->next) if (GET_MOB_RNUM(i) == nr) return (i); return (NULL); } /* put an object in a room */ void obj_to_room(Object object, room_rnum room) { check_obj_in_void(object); if (!object || room < 0 || room > top_of_world) log("SYSERR: Illegal value(s) passed to obj_to_room. (Room #%d/%d, obj %p)", room, top_of_world, object); else { object->next_content = world[room].contents; world[room].contents = object; object->in_room = room; object->carried_by = NULL; if (OBJ_FLAGGED(object, ITEM_LIGHT)) world[object->in_room].light++; ROOM_WEIGHT(room) += GET_OBJ_WEIGHT(object); } } /* Take an object from a room */ void obj_from_room(Object object) { extern int char_from_chair(Creature ch); Object temp; if (!object || object->in_room == NOWHERE) { log("SYSERR: NULL object (%p) or obj not in a room (%d) passed to obj_from_room", object, object->in_room); return; } if (IN_CHAIR(object)) char_from_chair(IN_CHAIR(object)); if (OBJ_FLAGGED(object, ITEM_LIGHT)) world[object->in_room].light--; ROOM_WEIGHT(object->in_room) -= GET_OBJ_WEIGHT(object); REMOVE_FROM_LIST(object, world[object->in_room].contents, next_content); object->in_room = NOWHERE; object->next_content = NULL; } /* put an object in an object (quaint) */ void obj_to_obj(Object obj, Object obj_to) { Object tmp_obj; if (!obj || !obj_to || obj == obj_to) { log("SYSERR: NULL object (%p) or same source (%p) and target (%p) obj passed to obj_to_obj.", obj, obj, obj_to); return; } check_obj_in_void(obj); obj->next_content = obj_to->contains; obj_to->contains = obj; obj->in_obj = obj_to; for (tmp_obj = obj->in_obj; tmp_obj->in_obj; tmp_obj = tmp_obj->in_obj) GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj); /* top level object. Subtract weight from inventory if necessary. */ GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj); if (tmp_obj->carried_by) IS_CARRYING_W(tmp_obj->carried_by) += GET_OBJ_WEIGHT(obj); } /* remove an object from an object */ void obj_from_obj(Object obj) { Object temp, obj_from; if (obj->in_obj == NULL) { log("SYSERR: (%s): trying to illegally extract obj from obj.", __FILE__); return; } obj_from = obj->in_obj; REMOVE_FROM_LIST(obj, obj_from->contains, next_content); /* Subtract weight from containers container */ for (temp = obj->in_obj; temp->in_obj; temp = temp->in_obj) GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj); /* Subtract weight from char that carries the object */ GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj); if (temp->carried_by) IS_CARRYING_W(temp->carried_by) -= GET_OBJ_WEIGHT(obj); obj->in_obj = NULL; obj->next_content = NULL; } /* Set all carried_by to point to new owner */ void object_list_new_owner(Object list, Creature ch) { if (list) { object_list_new_owner(list->contains, ch); object_list_new_owner(list->next_content, ch); list->carried_by = ch; } } /* Extract an object from the world */ void extract_obj(Object obj) { Object temp; check_obj_in_void(obj); /* Get rid of the contents of the object, as well. */ while (obj->contains) extract_obj(obj->contains); REMOVE_FROM_LIST(obj, object_list, next); if (GET_OBJ_RNUM(obj) >= 0) (obj_index[GET_OBJ_RNUM(obj)].number)--; free_obj(obj); } /* Extract a ch completely from the world, and leave his stuff behind */ void extract_char(Creature ch) { void display_statistics_to_char(Creature ch); Creature k, temp; Descr t_desc; Object obj; int i, freed = 0; perform_dismount(ch); if (GET_FED_ON_BY(ch)) { GET_FEEDING_FROM(GET_FED_ON_BY(ch)) = NULL; GET_FED_ON_BY(ch) = NULL; } if (GET_FEEDING_FROM(ch)) { GET_FED_ON_BY(GET_FEEDING_FROM(ch)) = NULL; GET_FEEDING_FROM(ch) = NULL; } if (GET_LEADING(ch)) { GET_LED_BY(GET_LEADING(ch)) = NULL; GET_LEADING(ch) = NULL; } if (GET_LED_BY(ch)) { GET_LEADING(GET_LED_BY(ch)) = NULL; GET_LED_BY(ch) = NULL; } if (GET_PULLING(ch)) { if (GET_PULLED_BY(GET_PULLING(ch), 0) == ch) GET_PULLED_BY(GET_PULLING(ch), 0) = NULL; if (GET_PULLED_BY(GET_PULLING(ch), 1) == ch) GET_PULLED_BY(GET_PULLING(ch), 1) = NULL; GET_PULLING(ch) = NULL; } if (!IS_NPC(ch) && !ch->desc) { for (t_desc = descriptor_list; t_desc; t_desc = t_desc->next) if (t_desc->original == ch) do_return(t_desc->character, NULL, 0, 0); } if (ch->in_room == NOWHERE) { log("SYSERR: NOWHERE extracting char %s. (%s, extract_char)", GET_NAME(ch), __FILE__); exit(1); } if (ch->followers || ch->master) die_follower(ch); /* Forget snooping, if applicable */ if (ch->desc) { if (ch->desc->snooping) { ch->desc->snooping->snoop_by = NULL; ch->desc->snooping = NULL; } if (ch->desc->snoop_by) { SEND_TO_Q("Your victim is no longer among us.\r\n", ch->desc->snoop_by); ch->desc->snoop_by->snooping = NULL; ch->desc->snoop_by = NULL; } } /* transfer objects to room, if any */ while (ch->carrying) { obj = ch->carrying; obj_from_char(obj); obj_to_room(obj, ch->in_room); } /* transfer equipment to room, if any */ for (i = 0; i < NUM_WEARS; i++) if (GET_EQ(ch, i)) obj_to_room(unequip_char(ch, i), ch->in_room); if (FIGHTING(ch)) stop_fighting(ch); for (k = combat_list; k; k = temp) { temp = k->next_fighting; if (FIGHTING(k) == ch) stop_fighting(k); } char_from_room(ch); /* pull the char from the list */ REMOVE_FROM_LIST(ch, character_list, next); if (ch->desc && ch->desc->original) do_return(ch, NULL, 0, 0); if (!IS_NPC(ch)) Crash_delete_crashfile(ch); else { if (GET_MOB_RNUM(ch) > -1) /* if mobile */ mob_index[GET_MOB_RNUM(ch)].number--; free_char(ch); freed = 1; } if (!freed && ch->desc != NULL) { STATE(ch->desc) = CON_MENU; display_statistics_to_char(ch); SEND_TO_Q(MENU, ch->desc); } else { /* if a player gets purged from within the game */ if (!freed) free_char(ch); } } /* *********************************************************************** * Here follows high-level versions of some earlier routines, ie functions* * which incorporate the actual player-data *. *********************************************************************** */ Creature get_player_vis(Creature ch, char *name, int inroom) { Creature i; for (i = character_list; i; i = i->next) { if (IS_NPC(i)) continue; if (IS_SET(inroom, FIND_CHAR_ROOM) && i->in_room != ch->in_room) continue; if (IS_SET(inroom, FIND_CHAR_ROOM) && AFF_FLAGGED(i, AFF_NO_TARGET_IN_ROOM)) continue; if (!isname(name, i->player.name) && (!GET_LASTNAME(i) || !isname(name, GET_LASTNAME(i))) && !isname(name, PERS(i, ch, 0)) && !isname(name, PERS(i, ch, 1))) continue; if (!CAN_SEE(ch, i) && (!IS_SET(inroom, FIND_NO_DARK) || !CAN_SEE_NO_DARK(ch, i))) continue; return (i); } return (NULL); } Creature get_char_room_vis(Creature ch, char *name) { Creature i; int j = 0, number; char tmpname[MAX_INPUT_LENGTH]; char *tmp = tmpname; /* JE 7/18/94 :-) :-) */ if (!str_cmp(name, "self") || !str_cmp(name, "me")) return (ch); /* 0.<name> means PC with name */ strcpy(tmp, name); if (!(number = get_number(&tmp))) return (get_player_vis(ch, tmp, FIND_CHAR_ROOM)); for (i = world[ch->in_room].people; i && j <= number; i = i->next_in_room) if (isname(tmp, i->player.name) || isname(tmp, PERS(i, ch, 0)) || isname(tmp, PERS(i, ch, 1)) || (GET_LASTNAME(i) && isname(name, GET_LASTNAME(i)))) if (CAN_SEE(ch, i) && !AFF_FLAGGED(i, AFF_NO_TARGET_IN_ROOM)) if (++j == number) return (i); return (NULL); } Creature get_char_vis(Creature ch, char *name, int where) { Creature i; int j = 0, number; char tmpname[MAX_INPUT_LENGTH]; char *tmp = tmpname; /* check the room first */ if (IS_SET(where, FIND_CHAR_ROOM)) return get_char_room_vis(ch, name); else if (IS_SET(where, FIND_CHAR_WORLD)) { if ((i = get_char_room_vis(ch, name)) != NULL) return (i); strcpy(tmp, name); if (!(number = get_number(&tmp))) return get_player_vis(ch, tmp, where); for (i = character_list; i && (j <= number); i = i->next) if ((isname(tmp, i->player.name) || isname(tmp, PERS(i, ch, 0)) || isname(tmp, PERS(i, ch, 1)) || (GET_LASTNAME(i) && isname(name, GET_LASTNAME(i)))) && (CAN_SEE(ch, i) || (IS_SET(where, FIND_NO_DARK) && CAN_SEE_NO_DARK(ch, i)))) if (++j == number) return (i); } return (NULL); } Object get_obj_in_list_vis(Creature ch, char *name, Object list) { Object i; int j = 0, number; char tmpname[MAX_INPUT_LENGTH]; char *tmp = tmpname; strcpy(tmp, name); if (!(number = get_number(&tmp))) return (NULL); for (i = list; i && (j <= number); i = i->next_content) if (isname(tmp, i->name)) if (CAN_SEE_OBJ(ch, i)) if (++j == number) return (i); return (NULL); } /* search the entire world for an object, and return a pointer */ Object get_obj_vis(Creature ch, char *name) { Object i; int j = 0, number; char tmpname[MAX_INPUT_LENGTH]; char *tmp = tmpname; /* scan items carried */ if ((i = get_obj_in_list_vis(ch, name, ch->carrying)) != NULL) return (i); /* scan room */ if ((i = get_obj_in_list_vis(ch, name, world[ch->in_room].contents)) != NULL) return (i); strcpy(tmp, name); if ((number = get_number(&tmp)) == 0) return (NULL); /* ok.. no luck yet. scan the entire obj list */ for (i = object_list; i && (j <= number); i = i->next) if (isname(tmp, i->name)) if (CAN_SEE_OBJ(ch, i)) if (++j == number) return (i); return (NULL); } Object get_object_in_equip_vis(Creature ch, char *arg, Object equipment[], int *j) { for ((*j) = 0; (*j) < NUM_WEARS; (*j)++) if (equipment[(*j)]) if (CAN_SEE_OBJ(ch, equipment[(*j)])) if (isname(arg, equipment[(*j)]->name)) return (equipment[(*j)]); return (NULL); } /* Generic Find, designed to find any object/character * * Calling: * *arg is the pointer containing the string to be searched for. * This string doesn't have to be a single word, the routine * extracts the next word itself. * bitv.. All those bits that you want to "search through". * Bit found will be result of the function * *ch This is the person that is trying to "find" * **tar_ch Will be NULL if no character was found, otherwise points * **tar_obj Will be NULL if no object was found, otherwise points * * The routine used to return a pointer to the next word in *arg (just * like the one_argument routine), but now it returns an integer that * describes what it filled in. */ int generic_find(char *arg, bitvector_t bitvector, Creature ch, Creature *tar_ch, Object *tar_obj) { int i, found; char name[256]; *tar_ch = NULL; *tar_obj = NULL; one_argument(arg, name); if (!*name) return (0); if (IS_SET(bitvector, FIND_CHAR_ROOM)) { /* Find person in room */ if ((*tar_ch = get_char_vis(ch, name, FIND_CHAR_ROOM)) != NULL) return (FIND_CHAR_ROOM); } if (IS_SET(bitvector, FIND_CHAR_WORLD)) { if ((*tar_ch = get_char_vis(ch, name, FIND_CHAR_WORLD)) != NULL) return (FIND_CHAR_WORLD); } if (IS_SET(bitvector, FIND_OBJ_EQUIP)) { for (found = FALSE, i = 0; i < NUM_WEARS && !found; i++) if (GET_EQ(ch, i) && isname(name, GET_EQ(ch, i)->name)) { *tar_obj = GET_EQ(ch, i); found = TRUE; } if (found) return (FIND_OBJ_EQUIP); } if (IS_SET(bitvector, FIND_OBJ_INV)) { if ((*tar_obj = get_obj_in_list_vis(ch, name, ch->carrying)) != NULL) return (FIND_OBJ_INV); } if (IS_SET(bitvector, FIND_OBJ_ROOM)) { if ((*tar_obj = get_obj_in_list_vis(ch, name, world[ch->in_room].contents)) != NULL) return (FIND_OBJ_ROOM); } if (IS_SET(bitvector, FIND_OBJ_WORLD)) { if ((*tar_obj = get_obj_vis(ch, name))) return (FIND_OBJ_WORLD); } return (0); } /* a function to scan for "all" or "all.x" */ int find_all_dots(char *arg) { if (!strcmp(arg, "all")) return (FIND_ALL); else if (!strncmp(arg, "all.", 4)) { strcpy(arg, arg + 4); return (FIND_ALLDOT); } else return (FIND_INDIV); } int char_from_chair(Creature ch) { Object chair; if (!ON_CHAIR(ch)) return 0; if (!(chair = ON_CHAIR(ch))) { log("SYSERR: No chair for char in char_from_chair"); ON_CHAIR(ch) = NULL; return 0; } ON_CHAIR(ch) = NULL; IN_CHAIR(chair) = NULL; return 1; } int char_to_chair(Creature ch, Object chair) { if (!ch || !chair) return 0; if (IN_CHAIR(chair) || ON_CHAIR(ch)) return 0; IN_CHAIR(chair) = ch; ON_CHAIR(ch) = chair; return 1; } /* affect_update: called from comm.c (causes spells to wear off) */ void affect_update(void) { extern const char *affect_wear_off_msgs[]; struct affected_type *af, *next; Creature i; for (i = character_list; i; i = i->next) for (af = i->affected; af; af = next) { next = af->next; if (af->duration >= 1) af->duration--; else if (af->duration == -1) /* No action */ af->duration = -1; /* GODs only! unlimited */ else { if ((af->type > 0)) if (!af->next || (af->next->type != af->type) || (af->next->duration > 0)) { if (*affect_wear_off_msgs[af->type]) msg_to_char(i, "%s\r\n", affect_wear_off_msgs[af->type]); } affect_remove(i, af); } } } /* affect_update_room: called from comm.c (causes spells to wear off) */ void affect_update_room(void) { extern const char *affect_wear_off_msgs[]; struct affected_type *af, *next; room_rnum room; for (room = 0; room <= top_of_world; room++) { for (af = world[room].af; af; af = next) { next = af->next; if (af->duration >= 1) af->duration--; else if (af->duration == -1) /* No action */ af->duration = -1; /* GODs only! unlimited */ else { if ((af->type > 0)) if (!af->next || (af->next->type != af->type) || (af->next->duration > 0)) { if (*affect_wear_off_msgs[af->type] && world[room].people) act(affect_wear_off_msgs[af->type], FALSE, world[room].people, 0, 0, TO_CHAR | TO_ROOM); } affect_remove_room(room, af); } } SET_BIT(ROOM_AFF_FLAGS(room), world[room].base_affects); } } void perform_dismount(Creature ch) { if (GET_RIDING(ch)) { GET_RIDDEN_BY(GET_RIDING(ch)) = NULL; GET_RIDING(ch) = NULL; } else if (GET_RIDDEN_BY(ch)) { GET_RIDING(GET_RIDDEN_BY(ch)) = NULL; GET_RIDDEN_BY(ch) = NULL; } } void perform_mount(Creature ch, Creature mount) { perform_dismount(ch); /* Just in case */ if (GET_RIDDEN_BY(mount)) return; GET_RIDING(ch) = mount; GET_RIDDEN_BY(mount) = ch; } /* Find an optimal place to start */ room_rnum find_load_room(Creature ch) { extern int num_of_start_locs; extern int *start_locs; if (num_of_start_locs < 0) return 0; return (real_room(start_locs[number(0, num_of_start_locs)])); } /* Remove specific lore */ void remove_lore_record(Creature ch, struct lore_data *lore) { struct lore_data *temp; if (!ch || IS_NPC(ch) || !lore) return; REMOVE_FROM_LIST(lore, GET_LORE(ch), next); free(lore); } /* Remove all lore of a given type */ void remove_lore(Creature ch, int type, long value) { struct lore_data *lore, *next_lore; if (IS_NPC(ch)) return; for (lore = GET_LORE(ch); lore; lore = next_lore) { next_lore = lore->next; if (lore->type == type) if (value == -1 || value == lore->value) remove_lore_record(ch, lore); } } /* Clean up old kill/death lore */ void clean_lore(Creature ch) { extern struct time_info_data *mud_time_passed(time_t t2, time_t t1); extern long load_time(); extern struct time_info_data time_info; struct lore_data *lore, *next_lore; struct time_info_data t; long beginning_of_time = load_time(); if (IS_NPC(ch)) return; for (lore = GET_LORE(ch); lore; lore = next_lore) { next_lore = lore->next; if (lore->type == LORE_PLAYER_KILL || lore->type == LORE_PLAYER_DEATH || lore->type == LORE_TOWER_DEATH) { t = *mud_time_passed((time_t) beginning_of_time, (time_t) lore->date); if (time_info.year - (-t.year + YEAR_ADD * 2) >= 1) remove_lore_record(ch, lore); } } } /* Add lore to a character's list */ void add_lore(Creature ch, int type, long value) { void write_lore(Creature ch); struct lore_data *new, *lore; if (IS_NPC(ch)) return; /* Clean old records */ switch (type) { case LORE_START_VAMPIRE: case LORE_EMBRACE_VAMPIRE: case LORE_MAKE_GHOUL: remove_lore(ch, LORE_START_VAMPIRE, -1); remove_lore(ch, LORE_EMBRACE_VAMPIRE, -1); remove_lore(ch, LORE_MAKE_GHOUL, -1); break; case LORE_JOIN_EMPIRE: remove_lore(ch, LORE_DEFECT_EMPIRE, -1); remove_lore(ch, LORE_KICKED_EMPIRE, -1); remove_lore(ch, LORE_FOUND_EMPIRE, -1); break; case LORE_DEFECT_EMPIRE: case LORE_KICKED_EMPIRE: remove_lore(ch, LORE_JOIN_EMPIRE, -1); remove_lore(ch, LORE_FOUND_EMPIRE, -1); break; case LORE_FOUND_EMPIRE: remove_lore(ch, LORE_FOUND_EMPIRE, -1); remove_lore(ch, LORE_JOIN_EMPIRE, -1); remove_lore(ch, LORE_KICKED_EMPIRE, -1); remove_lore(ch, LORE_DEFECT_EMPIRE, -1); break; } /* Find the last entry in ch's lore */ for (lore = GET_LORE(ch); lore && lore->next; lore = lore->next); CREATE(new, struct lore_data, 1); new->type = type; new->value = value; new->date = (long) time(0); new->next = NULL; /* If they have lore, append this to the end. Elsewise it becomes their lore */ if (lore) lore->next = new; else GET_LORE(ch) = new; /* And last but not least, save it */ write_lore(ch); }