/* * Bodyparts * ======= * Abilities and handling * Written by Keolah for Rogue Winds 2.0 * * You may not use or distribute any of this code without the * explicit permission of the code maintainer, Heather Dunn (Keolah) */ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <string.h> #ifdef sun #include <strings.h> #endif #include <time.h> #include "mud.h" /* from handler.c */ extern NATION_DATA *find_nation( char *name); PART_DATA *find_bodypart(CHAR_DATA *ch, int loc) { PART_DATA *part; part = ch->first_part; while (part) { if (part->loc == loc) return part; part = part->next; } return NULL; } int find_part_name(char *argument) { int loc; for (loc = 0;loc <= BP_CLAWS; loc++) { if (!str_cmp(argument, part_locs[loc]) || is_name(argument, part_locs[loc])) return loc; } return -1; } bool has_bodypart(CHAR_DATA *ch, int loc) { if (find_bodypart(ch, loc)) return TRUE; return FALSE; } bool can_use_bodypart(CHAR_DATA *ch, int loc) { PART_DATA *part; part = find_bodypart(ch, loc); if (!part) return FALSE; if (part->flags != PART_WELL) return FALSE; return TRUE; } void add_part(CHAR_DATA *ch, int loc, int to_loc) { PART_DATA *new_part; PART_DATA *part; if ((part = find_bodypart(ch, loc)) != NULL) { if (ch->nation) { part->armor = ch->nation->ac_plus; } else { part->armor = 0; } return; } CREATE(new_part, PART_DATA, 1); if (!ch->first_part) { ch->first_part=new_part; ch->last_part=new_part; } else { ch->last_part->next=new_part; new_part->prev=ch->last_part; ch->last_part=new_part; } new_part->loc = loc; new_part->cond = PART_WELL; new_part->flags = PART_WELL; new_part->obj = NULL; new_part->obj2 = NULL; if (ch->nation) new_part->armor = ch->nation->ac_plus; else if (IS_NPC(ch)) new_part->armor = ch->pIndexData->ac; else new_part->armor = 0; if ((part = find_bodypart(ch, to_loc)) == NULL) return; new_part->connect_to = part; } void remove_part(CHAR_DATA *ch, int loc) { PART_DATA *part; part = find_bodypart(ch, loc); if (!part) return; if (part->obj) unequip_char(ch, part->obj); if (part->obj2) unequip_char(ch, part->obj2); UNLINK(part, ch->first_part, ch->last_part, next, prev); DISPOSE(part); } void check_bodyparts(CHAR_DATA *ch) { int i=0; if (!IS_NPC(ch)) { if (!ch->species) return; if (!ch->nation) ch->nation = find_nation(ch->species); if (!ch->nation) { bug("check_bodyparts: could not find nation!"); bug("setting char to first_nation..."); ch->nation = first_nation; set_char_color(AT_DANGER, ch); send_to_char("Your species has been reset to avoid a possible crash.\n\r", ch); send_to_char("Please ask an immortal to fix your species as soon as possible.\n\r", ch); } ch->xflags = ch->nation->parts; if (IS_VAMPIRE(ch)) SET_BIT(ch->xflags, 1 << PART_FANGS); if (IS_AFFECTED(ch, AFF_ANTHRO)) { SET_BIT(ch->xflags, 1 << PART_HANDS); SET_BIT(ch->xflags, 1 << PART_ARMS); SET_BIT(ch->xflags, 1 << PART_LEGS); REMOVE_BIT(ch->xflags, 1 << PART_FORELEGS); REMOVE_BIT(ch->xflags, 1 << PART_HAUNCH); } } for (i=0; i<MAX_PARTS; i++) { if (ch == supermob) return; /* give them parts they should have */ if (IS_SET(ch->xflags, 1 << i)) { switch (i) { case PART_HEAD: add_part(ch, BP_HEAD, BP_NECK); add_part(ch, BP_FACE, BP_HEAD); add_part(ch, BP_NOSE, BP_HEAD); add_part(ch, BP_TONGUE, BP_HEAD); break; case PART_BRAINS: add_part(ch, BP_NECK, BP_CHEST); break; case PART_HEART: add_part(ch, BP_CHEST, -1); add_part(ch, BP_BACK, -1); break; case PART_GUTS: add_part(ch, BP_STOMACH, -1); add_part(ch, BP_ASS, -1); break; case PART_ARMS: add_part(ch, BP_RARM, BP_CHEST); add_part(ch, BP_LARM, BP_CHEST); add_part(ch, BP_RWRIST, BP_RARM); add_part(ch, BP_LWRIST, BP_LARM); break; case PART_HANDS: add_part(ch, BP_RHAND, BP_RWRIST); add_part(ch, BP_LHAND, BP_LWRIST); break; case PART_LEGS: add_part(ch, BP_RLEG, BP_ASS); add_part(ch, BP_LLEG, BP_ASS); add_part(ch, BP_RANKLE, BP_RLEG); add_part(ch, BP_LANKLE, BP_LLEG); break; case PART_WINGS: add_part(ch, BP_RWING, BP_BACK); add_part(ch, BP_LWING, BP_BACK); break; case PART_FEET: add_part(ch, BP_RFOOT, BP_RANKLE); add_part(ch, BP_LFOOT, BP_LANKLE); break; case PART_PAWS: add_part(ch, BP_RPAW, BP_RANKLE); add_part(ch, BP_LPAW, BP_LANKLE); break; case PART_HOOVES: add_part(ch, BP_RHOOF, BP_RANKLE); add_part(ch, BP_LHOOF, BP_LANKLE); break; case PART_FANGS: add_part(ch, BP_FANGS, BP_HEAD); break; case PART_TAIL: add_part(ch, BP_TAIL, BP_ASS); break; case PART_HORNS: add_part(ch, BP_RHORN, BP_HEAD); add_part(ch, BP_LHORN, BP_HEAD); break; case PART_FORELEGS: add_part(ch, BP_RFLEG, BP_CHEST); add_part(ch, BP_LFLEG, BP_CHEST); break; case PART_HAUNCH: add_part(ch, BP_RRLEG, BP_ASS); add_part(ch, BP_LRLEG, BP_ASS); break; case PART_EYE: add_part(ch, BP_REYE, BP_HEAD); add_part(ch, BP_LEYE, BP_HEAD); break; case PART_FINS: add_part(ch, BP_RFIN, BP_CHEST); add_part(ch, BP_LFIN, BP_CHEST); add_part(ch, BP_DFIN, BP_BACK); break; case PART_CLAWS: add_part(ch, BP_CLAWS, BP_RPAW); break; case PART_EAR: add_part(ch, BP_REAR, BP_HEAD); add_part(ch, BP_LEAR, BP_HEAD); break; } /* switch */ } else { /* otherwise remove parts they shouldnt have */ switch (i) { case PART_HEAD: remove_part(ch, BP_HEAD); remove_part(ch, BP_FACE); remove_part(ch, BP_NOSE); remove_part(ch, BP_TONGUE); break; case PART_BRAINS: remove_part(ch, BP_NECK); break; case PART_HEART: remove_part(ch, BP_CHEST); remove_part(ch, BP_BACK); break; case PART_GUTS: remove_part(ch, BP_STOMACH); remove_part(ch, BP_ASS); break; case PART_ARMS: remove_part(ch, BP_RARM); remove_part(ch, BP_LARM); remove_part(ch, BP_RWRIST); remove_part(ch, BP_LWRIST); break; case PART_HANDS: remove_part(ch, BP_RHAND); remove_part(ch, BP_LHAND); break; case PART_LEGS: remove_part(ch, BP_RLEG); remove_part(ch, BP_LLEG); remove_part(ch, BP_RANKLE); remove_part(ch, BP_LANKLE); break; case PART_WINGS: remove_part(ch, BP_RWING); remove_part(ch, BP_LWING); break; case PART_FEET: remove_part(ch, BP_RFOOT); remove_part(ch, BP_LFOOT); break; case PART_PAWS: remove_part(ch, BP_RPAW); remove_part(ch, BP_LPAW); break; case PART_HOOVES: remove_part(ch, BP_RHOOF); remove_part(ch, BP_LHOOF); break; case PART_FANGS: remove_part(ch, BP_FANGS); break; case PART_TAIL: remove_part(ch, BP_TAIL); break; case PART_HORNS: remove_part(ch, BP_RHORN); remove_part(ch, BP_LHORN); break; case PART_FORELEGS: remove_part(ch, BP_RFLEG); remove_part(ch, BP_LFLEG); break; case PART_HAUNCH: remove_part(ch, BP_RRLEG); remove_part(ch, BP_LRLEG); break; case PART_EYE: remove_part(ch, BP_REYE); remove_part(ch, BP_LEYE); break; case PART_FINS: remove_part(ch, BP_RFIN); remove_part(ch, BP_LFIN); remove_part(ch, BP_DFIN); break; case PART_CLAWS: remove_part(ch, BP_CLAWS); break; case PART_EAR: remove_part(ch, BP_REAR); remove_part(ch, BP_LEAR); break; } /* switch */ } /* if */ } /* for */ /* comment out if you dont want anatomically correct chars */ if (ch->sex == SEX_MALE || ch->sex == SEX_HERMAPH) add_part(ch, BP_PENIS, BP_ASS); else remove_part(ch, BP_PENIS); if (ch->sex == SEX_FEMALE || ch->sex == SEX_HERMAPH) add_part(ch, BP_VAGINA, BP_ASS); else remove_part(ch, BP_VAGINA); } /* Returns the object on the top layer of the part */ OBJ_DATA *outer_layer(PART_DATA *part) { if (part->obj2) return part->obj2; return part->obj; } /* For fancy messages for magic */ char *hands(CHAR_DATA *ch) { if (IS_SET(ch->xflags, 1 << PART_HANDS)) return "hands"; if (IS_AFFECTED(ch, AFF_COLDBLOOD)) return "mouth"; return "eyes"; } void do_body(CHAR_DATA *ch, char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *victim; OBJ_DATA *obj; argument = one_argument(argument, arg); if (arg[0] == '\0') victim = ch; else if (IS_SET(ch->pcdata->permissions, PERMIT_MISC)) { if ((victim = get_char_world(ch, arg)) == NULL) { send_to_char("They aren't here.\r\n", ch); return; } } else { if ((victim = get_char_room(ch, arg)) == NULL) { send_to_char("They aren't here.\r\n", ch); return; } else { act(AT_PLAIN, "$n looks you over.", ch, NULL, victim, TO_VICT); act(AT_PLAIN, "$n looks $N over.", ch, NULL, victim, TO_NOTVICT); } } if (victim == ch) send_to_char("Your body:\r\n", ch); else ch_printf(ch, "%s's body:\r\n", PERS(victim, ch)); if (victim->first_part) { PART_DATA *part; part = victim->first_part; while (part) { pager_printf_color(ch, "&W%16s: &Y%dac &C%dhp", part_locs[part->loc], part->armor, part->cond); switch(part->flags) { case PART_BROKEN: pager_printf_color(ch, " &Obroken&w "); break; case PART_SEVERED: pager_printf_color(ch, " &rsevered&w "); break; case PART_BOUND: pager_printf_color(ch, " &Cbound&w "); break; case PART_WELL: switch (part->cond) { case PART_WELL: pager_printf_color(ch, " &Gfine "); break; default: pager_printf_color(ch, " &Yinjured "); } break; } /* See if any object is attached that shouldn't be */ /* if (part->obj && part->obj->carried_by != ch) { part->obj = part->obj2; part->obj2 = NULL; } if (part->obj2 && part->obj2->carried_by != ch) part->obj2 = NULL; */ if ((obj = outer_layer(part)) != NULL) pager_printf(ch, obj->short_descr ? obj->short_descr : "???"); pager_printf(ch, "\n\r"); part = part->next; } } } void show_equip(CHAR_DATA *ch, CHAR_DATA *to) { OBJ_DATA *obj; PART_DATA *part; bool found; found = FALSE; /* first tell them what they're wielding, if anything */ if ((obj = ch->main_hand)) { ch_printf(to, " %s, held in right hand\n\r", format_obj_to_char( obj, ch, TRUE )); found = TRUE; } if ((obj = ch->off_hand)) { ch_printf(to, " %s, held in left hand\n\r", format_obj_to_char( obj, ch, TRUE )); found = TRUE; } /* now run through their parts and find any armor */ if (ch == to) { for (part = ch->first_part;part;part = part->next) { if (part->obj && can_see_obj(to, part->obj)) { ch_printf(to, " %s, worn on %s\n\r", format_obj_to_char( part->obj, ch, TRUE ), part_locs[part->loc]); found = TRUE; } if (part->obj2 && can_see_obj(to, part->obj2)) { ch_printf(to, " %s, worn on %s\n\r", format_obj_to_char( part->obj2, ch, TRUE ), part_locs[part->loc]); found = TRUE; } } } else { for (part = ch->first_part;part;part = part->next) { if ((obj = outer_layer(part)) != NULL) { ch_printf(to, " %s, worn on %s\n\r", format_obj_to_char( obj, ch, TRUE ), part_locs[part->loc]); found = TRUE; } } } if (!found) send_to_char(" &GNothing.&w\n\r", to); } /* Display wielded items and worn armor */ void do_equipment(CHAR_DATA *ch, char *argument) { send_to_char("You are using:\n\r", ch); show_equip(ch, ch); } void obj_affect_ch(CHAR_DATA *ch, OBJ_DATA *obj) { AFFECT_DATA *paf; for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); for ( paf = obj->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); if (obj->gem) { for ( paf = obj->gem->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, TRUE ); } } /* Equip a char with an object */ bool equip_char(CHAR_DATA *ch, OBJ_DATA *obj) { PART_DATA *part; bool found = FALSE; if (obj->size > ch->height * 1.5) return FALSE; if (obj->size < ch->height / 2) return FALSE; for (part = ch->first_part;part;part = part->next) { if (xIS_SET(obj->parts, part->loc) && part->flags == PART_WELL) { if (part->obj) { if (part->obj2) continue; if (part->obj->pIndexData->layers < obj->pIndexData->layers) { part->obj2 = obj; } else { continue; } } else { part->obj = obj; } if (obj->item_type == ITEM_ARMOR) part->armor += obj->value[0]; obj->wear_loc = part->loc; found = TRUE; } } if (found) { ch->carry_number -= get_obj_number( obj ); ch->encumberance += obj->weight; obj_affect_ch(ch, obj); return TRUE; } return FALSE; } void obj_unaffect_ch(CHAR_DATA *ch, OBJ_DATA *obj) { AFFECT_DATA *paf; for ( paf = obj->pIndexData->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); for ( paf = obj->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); if (obj->gem) { for ( paf = obj->gem->first_affect; paf; paf = paf->next ) affect_modify( ch, paf, FALSE ); } } /* Unequip a char with an object */ void unequip_char(CHAR_DATA *ch, OBJ_DATA *obj) { PART_DATA *part; if (!ch || !ch->name) return; for (part = ch->first_part;part;part = part->next) { if (part->obj == obj) { if (obj->item_type == ITEM_ARMOR) part->armor -= obj->value[0]; part->obj = NULL; if (part->obj2) { part->obj = part->obj2; part->obj2 = NULL; } } if (part->obj2 == obj) { if (obj->item_type == ITEM_ARMOR) part->armor -= obj->value[0]; part->obj2 = NULL; } } obj->wear_loc = -1; ch->carry_number += get_obj_number( obj ); ch->encumberance -= obj->weight; obj_unaffect_ch(ch, obj); update_aris(ch); } void do_wear(CHAR_DATA *ch, char *argument) { OBJ_DATA *obj; bool found; found = FALSE; if (!str_cmp("all", argument)) { for (obj=ch->first_carrying;obj;obj=obj->next_content) { if (obj->wear_loc == -1) if (equip_char(ch, obj)) found = TRUE; } if (found) { act(AT_ACTION, "You get dressed.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n gets dressed.", ch, obj, NULL, TO_ROOM); } return; } if ((obj = get_obj_carry(ch, argument)) == NULL) { send_to_char("You have nothing like that.\n\r", ch); return; } if (obj->wear_loc != -1) { send_to_char("You are already wearing that!\n\r", ch); return; } separate_obj(obj); obj_from_char(obj); /* To make sure layering is */ obj_to_char(obj, ch); /* in the correct order */ if (equip_char(ch, obj) == FALSE) { send_to_char("You can't wear that.\n\r", ch); return; } if (!obj->action_desc || obj->action_desc[0]=='\0' ) { act(AT_ACTION, "You wear $p on your $T.", ch, obj, part_locs[obj->wear_loc], TO_CHAR); act(AT_ACTION, "$n wears $p on $s $T.", ch, obj, part_locs[obj->wear_loc], TO_ROOM); } else { actiondesc(ch, obj, NULL); } } void do_remove(CHAR_DATA *ch, char *argument) { OBJ_DATA *obj; if (!str_cmp(argument, "all")) { for (obj=ch->first_carrying;obj;obj=obj->next_content) { if (obj->wear_loc != -1) unequip_char(ch, obj); } act(AT_ACTION, "You strip naked.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n strips naked.", ch, obj, NULL, TO_ROOM); return; } if ((obj = get_obj_wear(ch, argument)) == NULL) { send_to_char("You have nothing like that.\n\r", ch); return; } if (obj->wear_loc == -1) { send_to_char("You aren't wearing that.\n\r", ch); return; } unequip_char(ch, obj); act(AT_ACTION, "You take off $p.", ch, obj, NULL, TO_CHAR); act(AT_ACTION, "$n takes off $p.", ch, obj, NULL, TO_ROOM); } bool sever_part(CHAR_DATA *ch, PART_DATA *part) { OBJ_DATA *obj; char buf[MAX_STRING_LENGTH]; PART_DATA *connected_part; bool was_neck; if (part->flags == PART_SEVERED) return FALSE; /* parts that can't be severed */ if (part->loc == BP_CHEST || part->loc == BP_ASS || part->loc == BP_VAGINA || part->loc == BP_STOMACH || part->loc == BP_BACK || part->loc == BP_FACE) { return FALSE; } /* cutting off the neck will remove the head * if you make a hit hard enough to sever the neck * survivable, this will need to be changed * better, get in that 'attached' code. */ if (part->loc == BP_NECK) { was_neck = TRUE; part->loc = BP_HEAD; } act(AT_ACTION, "$n's $t is severed!", ch, part_locs[part->loc], NULL, TO_ROOM); act(AT_DANGER, "Your severed $t flies off!", ch, part_locs[part->loc], NULL, TO_CHAR); part->flags = PART_SEVERED; part->cond /= 2; /* there's less of it to bleed */ if (part->obj) unequip_char(ch, part->obj); if (part->obj2) unequip_char(ch, part->obj2); /* make a severed limb */ if (!IS_AFFECTED(ch, AFF_NO_CORPSE)) { obj = create_object(get_obj_index(OBJ_VNUM_SEVERED_PART), 0); STRFREE(obj->short_descr); STRFREE(obj->name); sprintf(buf, "%s of %s", part_locs[part->loc], IS_NPC(ch) ? ch->short_descr : ch->name); obj->short_descr = STRALLOC(buf); obj->name = STRALLOC(part_locs[part->loc]); obj->timer = 5; obj->value[1] = part->loc; if (IS_AFFECTED(ch, AFF_CONSTRUCT)) { obj->item_type = ITEM_WEAPON; obj->value[5] = SK_MACE; obj->value[2] = 20; obj->value[3] = 7; obj->weight = 15; obj->value[0] = 0; } /* end construct check */ obj_to_room(obj, ch->in_room); } /* end ethereal check */ /* find anything that was attached to it and remove it too */ connected_part = ch->first_part; while (connected_part) { if (connected_part->connect_to && connected_part->connect_to->flags == PART_SEVERED) { connected_part->flags = PART_SEVERED; if (connected_part->obj) unequip_char(ch, connected_part->obj); if (connected_part->obj2) unequip_char(ch, connected_part->obj2); } if (connected_part == ch->last_part) break; connected_part = connected_part->next; } if (part->loc == BP_HEAD) { if (was_neck) part->loc = BP_NECK; switch (number_range(1,10)) { default: act(AT_DEAD, "$n's headless corpse falls to the ground.", ch, NULL, NULL, TO_ROOM); break; case 1: act(AT_DEAD, "$n runs around like a chicken with its head cut off for a moment before laying still.", ch, NULL, NULL, TO_ROOM); break; case 2: act(AT_DEAD, "$n's face becomes forever frozen in a look of shock.", ch, NULL, NULL, TO_ROOM); break; } die(ch); return TRUE; } return direct_damage(ch, 100); } void break_part(CHAR_DATA *ch, PART_DATA *part) { if (part->flags != PART_WELL) return; /* parts that can't be broken */ if (part->loc == BP_STOMACH || part->loc == BP_REAR || part->loc == BP_LEAR || part->loc == BP_PENIS || part->loc == BP_REYE || part->loc == BP_LEYE) { return; } act(AT_ACTION, "You hear a sickening crunch.", ch, NULL, NULL, TO_ROOM); act(AT_DANGER, "You hear a sickening crunch from your $t.", ch, part_locs[part->loc], NULL, TO_CHAR); part->flags = PART_BROKEN; } void unbreak_part(CHAR_DATA *ch, PART_DATA *part) { if (part->flags != PART_BROKEN) return; act(AT_ACTION, "$n's $t snaps back into place.", ch, part_locs[part->loc], NULL, TO_ROOM); act(AT_ACTION, "Your $t snaps back into place.", ch, part_locs[part->loc], NULL, TO_CHAR); part->flags = PART_WELL; } void hurt_part(CHAR_DATA *ch, PART_DATA *part, int dam) { if (part->cond == PART_SEVERED) return; if (!IS_NPC(ch) && ch->last_hit && !IS_NPC(ch->last_hit) && IS_SET(ch->last_hit->pcdata->flags, PCFLAG_CHEAT)) return; dam = (100 - number_range(1, TALENT(ch, TAL_SECURITY))) * dam / 100; if (dam < 0) dam = 0; learn_talent(ch, TAL_SECURITY); if (dam > 50) { if (outer_layer(part)) damage_obj(outer_layer(part)); } /* see if the hit severed or broke it */ if ((dam > 500 && part->cond < -2000) && part->armor < number_range(1, 100)) { if ( sever_part(ch, part)) return; } else if (dam > 300 && number_range(1,2) == 1) break_part(ch, part); part->cond -= dam; /* now make sure they can still use their weapons */ if (ch->main_hand && !can_use_bodypart(ch, BP_RHAND)) { act(AT_HURT, "You are unable to wield your $t anymore and drop it.", ch, myobj(ch->main_hand), NULL, TO_CHAR); act(AT_HURT, "$n winces as $s $t drops to the ground.", ch, myobj(ch->main_hand), NULL, TO_ROOM); obj_unaffect_ch(ch, ch->main_hand); ch->main_hand = NULL; } if (ch->off_hand && !can_use_bodypart(ch, BP_LHAND)) { act(AT_HURT, "You are unable to wield your $t anymore and drop it.", ch, myobj(ch->off_hand), NULL, TO_CHAR); act(AT_HURT, "$n winces as $s $t drops to the ground.", ch, myobj(ch->off_hand), NULL, TO_ROOM); obj_unaffect_ch(ch, ch->off_hand); ch->off_hand = NULL; } /* check to see if they could survive the blow */ if (dam - part->armor*5 > 500 && part->cond < -3000 && (part->loc == BP_HEAD || part->loc == BP_CHEST || part->loc == BP_BACK || part->loc == BP_NECK)) { act(AT_DANGER, "You have taken a fatal injury and die instantly.", ch, NULL, NULL, TO_CHAR); act(AT_HURT, "$n has taken a fatal injury and dies instantly.", ch, NULL, NULL, TO_ROOM); die(ch); } } /* A skill to set a broken bone */ void do_boneset(CHAR_DATA *ch, char *argument) { CHAR_DATA *victim; PART_DATA *part; char arg2[MAX_INPUT_LENGTH]; int loc; argument = one_argument(argument, arg2); victim = find_target(ch, argument, FALSE); if (!victim) return; loc = find_part_name(arg2); if (loc == -1) { send_to_char("Set what bone?\n\r", ch); return; } part = find_bodypart(victim, loc); if (!part) { send_to_char("You don\'t see any such part.\n\r", ch); return; } if (part->flags != PART_BROKEN) { send_to_char("That bone is not broken.\n\r", ch); return; } unbreak_part(victim, part); act(AT_SKILL, "You carefully set the bone.", ch, NULL, NULL, TO_CHAR); act(AT_SKILL, "$n carefully sets a bone.", ch, NULL, NULL, TO_ROOM); learn_noncombat(ch, SK_MEDICINE); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("setting the bone"); WAIT_STATE(ch, PULSE_VIOLENCE*2); } /* Bandage up a bleeding part */ void do_bandage(CHAR_DATA *ch, char *argument) { CHAR_DATA *victim; PART_DATA *part; char arg2[MAX_INPUT_LENGTH]; int loc; argument = one_argument(argument, arg2); victim = find_target(ch, argument, FALSE); if (!victim) return; loc = find_part_name(arg2); if (loc == -1) { send_to_char("Bandage what part?\n\r", ch); return; } part = find_bodypart(victim, loc); if (!part) { send_to_char("You don\'t see any such part.\n\r", ch); return; } if (part->cond > 0) { send_to_char("That part is not bleeding.\n\r", ch); return; } part->cond += number_range(SK_MEDICINE, SK_MEDICINE*10); act(AT_SKILL, "You carefully bandage the wound.", ch, NULL, NULL, TO_CHAR); act(AT_SKILL, "$n carefully bandages a wound.", ch, NULL, NULL, TO_ROOM); learn_noncombat(ch, SK_MEDICINE); STRFREE(ch->last_taken); ch->last_taken = STRALLOC("bandaging the wound"); WAIT_STATE(ch, PULSE_VIOLENCE); }