/*
* 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);
}