/*
* Combat
* =======
* 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 birth.c */
void ghost(CHAR_DATA *ch);
/* From interp.c */
bool check_social(CHAR_DATA *ch, char *command, char *argument);
/* from handler.c */
extern bool is_bane(OBJ_DATA *weapon, CHAR_DATA *victim);
/* from save.c */
extern void save_world(CHAR_DATA *ch);
/* from talent.c */
extern void player_echo( CHAR_DATA *ch, sh_int AT_COLOR, char *argument, sh_int tar);
void die(CHAR_DATA *ch) {
char log_buf[MAX_STRING_LENGTH];
if (char_died(ch)) return;
if (!IS_NPC(ch) && ch->last_hit && !IS_NPC(ch->last_hit)
&& ch->last_hit != ch
&& (IS_SET(ch->last_hit->pcdata->flags, PCFLAG_SPAR)
|| !ch->desc)) {
act(AT_ACTION, "$N has defeated you in a spar.", ch, NULL, ch->last_hit, TO_CHAR);
act(AT_ACTION, "You have defeated $n in a spar.", ch, NULL, ch->last_hit, TO_VICT);
xSET_BIT(ch->act, PLR_DEFENSE);
xSET_BIT(ch->last_hit->act, PLR_DEFENSE);
ch->last_hit->pcdata->pkills++;
ch->pcdata->pdeaths++;
ch->hit = 10;
return;
}
switch (number_range(1,5)) {
default:
act(AT_DEAD, "$n dies.", ch, NULL, NULL, TO_ROOM);
break;
case 1:
act(AT_DEAD, "$n collapses motionless to the ground.", ch, NULL, NULL, TO_ROOM);
break;
case 2:
act(AT_DEAD, "$n is DEAD!!", ch, NULL, NULL, TO_ROOM);
break;
case 3:
act(AT_DEAD, "$n jerks limply, then is still.", ch, NULL, NULL, TO_ROOM);
break;
case 4:
act(AT_DEAD, "$n slumps over lifelessly.", ch, NULL, NULL, TO_ROOM);
break;
}
if (ch->last_hit) {
mprog_death_trigger( ch->last_hit, ch);
if ( char_died(ch) )
return;
rprog_death_trigger( ch->last_hit, ch );
if ( char_died(ch) )
return;
}
if (!IS_NEWBIE(ch))
make_corpse(ch);
if (ch->last_hit && !IS_NPC(ch->last_hit)
&& ch->in_room == ch->last_hit->in_room) {
act(AT_DEAD, "You have slain $N.", ch->last_hit, NULL, ch, TO_CHAR);
if (xIS_SET(ch->last_hit->act, PLR_AUTOGOLD))
do_get(ch->last_hit, "coins corpse");
if (xIS_SET(ch->last_hit->act, PLR_AUTOLOOT))
do_get(ch->last_hit, "all corpse");
if (!IS_AFFECTED(ch, AFF_NONLIVING)
&& IS_SET(ch->last_hit->pcdata->flags, PCFLAG_VAMPIRE)) {
act(AT_BLOOD, "You drain the last blood from $N.", ch->last_hit, NULL, ch, TO_CHAR);
ch->last_hit->hit += get_curr_con(ch);
}
}
save_world(ch);
if (IS_NPC(ch)) {
if (ch->last_hit) {
if (!IS_NPC(ch->last_hit)) {
ch->last_hit->pcdata->mkills++;
} else {
int i;
for (i = get_exp_worth(ch);i > 10000;i -= 10000) {
if (i > 100000) {
switch(number_range(1,7)) {
case 1:
ch->last_hit->perm_str++;
break;
case 2:
ch->last_hit->perm_int++;
break;
case 3:
ch->last_hit->perm_wis++;
break;
case 4:
ch->last_hit->perm_con++;
break;
case 5:
ch->last_hit->perm_dex++;
break;
case 6:
ch->last_hit->perm_cha++;
break;
case 7:
ch->last_hit->perm_lck++;
break;
}
i -= 90000;
continue;
}
ch->last_hit->max_hit++;
}
}
}
ch->pIndexData->killed++;
extract_char(ch, TRUE);
ch = NULL;
return;
}
if (ch->last_hit) {
sprintf( log_buf, "%s Pkill: %s killed by %s in %s (%d)",
!IS_NPC(ch->last_hit) ?
(IS_SET(ch->in_room->area->flags, AFLAG_FREEKILL) ?
"Legal" : "&RILLEGAL") : "Mob",
ch->name,
(IS_NPC(ch->last_hit)
? ch->last_hit->short_descr : ch->last_hit->name),
ch->in_room->name,
ch->in_room->vnum );
log_string( log_buf );
if (IS_NPC(ch->last_hit)) {
stop_hating(ch->last_hit);
ch->pcdata->mdeaths++;
} else {
if (xIS_SET(ch->act, PLR_BOUNTY) && ch->pcdata->bounty > 0) {
char buf[MAX_STRING_LENGTH];
sprintf(buf, "&YYou receive %d coins from the bounty!&w\r\n", ch->pcdata->bounty);
send_to_char(buf, ch->last_hit);
ch->last_hit->gold += ch->pcdata->bounty;
ch->pcdata->bounty = 0;
xREMOVE_BIT(ch->act, PLR_BOUNTY);
}
ch->last_hit->pcdata->rkills++;
ch->pcdata->rdeaths++;
}
} else {
sprintf( log_buf, "%s (%d) died in %s (%d)",
ch->name,
get_char_worth(ch),
ch->in_room->name,
ch->in_room->vnum );
log_string( log_buf );
}
/* must be called AFTER triggers */
stop_fighting(ch, TRUE);
ghost(ch);
}
void uncon(CHAR_DATA *ch) {
act(AT_HURT, "$n loses consciousness!", ch, NULL, NULL, TO_ROOM);
act(AT_DANGER, "You lose consciousness!", ch, NULL, NULL, TO_CHAR);
ch->position = POS_STUNNED;
}
void pain(CHAR_DATA *ch, int dam) {
char msg1[MAX_STRING_LENGTH];
char msg2[MAX_STRING_LENGTH];
ROOM_INDEX_DATA *was_in_room;
EXIT_DATA *pexit;
int pain;
if (!ch->in_room
|| IS_SILENT(ch)
|| IS_AFFECTED(ch, AFF_NONLIVING)) return;
pain = (ch->hit) / dam;
msg1[0] = '\0';
msg2[0] = '\0';
switch (pain) {
case 8:
sprintf(msg1, "$n grunts in pain.");
sprintf(msg2, "Something grunts in pain.");
break;
case 7:
sprintf(msg1, "$n winces in pain.");
break;
case 6:
sprintf(msg1, "$n cries out in pain!");
sprintf(msg2, "Something cries out in pain!");
break;
case 5:
sprintf(msg1, "$n screams loudly!");
sprintf(msg2, "Something screams loudly!");
break;
case 4:
sprintf(msg1, "$n groans loudly.");
sprintf(msg2, "Something groans somewhere.");
break;
case 3:
sprintf(msg1, "$n moans pitifully.");
case 2:
sprintf(msg1, "$n whimpers feebly.");
break;
}
if (msg1[0] != '\0')
act(AT_BLOOD, msg1, ch, NULL, NULL, TO_ROOM);
if (msg2[0] == '\0') return;
was_in_room = ch->in_room;
for ( pexit = was_in_room->first_exit; pexit; pexit = pexit->next )
{
if ( pexit->to_room
&& pexit->to_room != was_in_room )
{
ch->in_room = pexit->to_room;
act( AT_ACTION, msg2, ch, NULL, NULL, TO_ROOM );
}
}
ch->in_room = was_in_room;
}
bool can_hit( CHAR_DATA *ch, CHAR_DATA *victim, OBJ_DATA *obj) {
if (!obj || !IS_OBJ_STAT(obj, ITEM_MAGIC))
if ( (IS_AFFECTED(victim, AFF_ETHEREAL)
&& !IS_AFFECTED(ch, AFF_ETHEREAL))
|| (IS_AFFECTED(ch, AFF_ETHEREAL)
&& !IS_AFFECTED(victim, AFF_ETHEREAL))
|| !IS_SAME_PLANE(ch, victim)) {
act(AT_ACTION, "Your attack passes through $N!",
ch, NULL, victim, TO_CHAR);
act(AT_ACTION, "$n's attack passes through you!",
ch, NULL, victim, TO_VICT);
act(AT_ACTION, "$n's attack passes through $N!",
ch, NULL, victim, TO_NOTVICT);
if (IS_NPC(ch) && number_range(1,40) < get_curr_int(ch)) {
if (IS_SET(ch->xflags, PART_HANDS))
act(AT_SOCIAL, "$n gasps in surprise.", ch, NULL, NULL, TO_ROOM);
else
act(AT_SOCIAL, "$n roars in anger.", ch, NULL, NULL, TO_ROOM);
xSET_BIT(ch->act, ACT_PHYS_FAIL);
}
return FALSE;
}
return TRUE;
}
bool can_gain_exp( CHAR_DATA *ch, CHAR_DATA *victim) {
if (!ch) return FALSE;
if (!victim) return FALSE;
if (ch == victim) return FALSE;
if (IS_AFFECTED(victim, AFF_SLEEP)) return FALSE;
if (victim->spec_fun) return TRUE;
if (IS_AFFECTED(victim, AFF_ETHEREAL)) {
if (!IS_AFFECTED(ch, AFF_ETHEREAL)) return FALSE;
return TRUE;
} else {
if (IS_AFFECTED(ch, AFF_ETHEREAL)) return FALSE;
return TRUE;
}
return TRUE;
}
void gain_exp( CHAR_DATA *ch, int gain ) {
if ( IS_NPC(ch) )
return;
/* xp cap just in case someone decides to cheat or something -- Scion */
gain = URANGE(0, gain, 100000);
ch->exp = UMAX( 0, ch->exp + gain );
}
/* Take some hp. Return true if it killed them */
bool lose_hp(CHAR_DATA *ch, int amt) {
if (!IS_NPC(ch) && ch->last_hit && !IS_NPC(ch->last_hit)
&& IS_SET(ch->last_hit->pcdata->flags, PCFLAG_CHEAT)) return FALSE;
ch->hit -= amt;
if (ch->last_hit && can_gain_exp(ch->last_hit, ch))
gain_exp(ch->last_hit, get_exp_worth(ch) / 10);
if (ch->hit < 1) {
die(ch);
return TRUE;
}
return FALSE;
}
/* Take some ep. Return true if they went unconscious */
bool lose_ep(CHAR_DATA *ch, int amt) {
ch->move -= amt;
if (ch->move < 1) {
uncon(ch);
return TRUE;
}
return FALSE;
}
/* Do damage, but allow security to reduce it */
bool direct_damage(CHAR_DATA *ch, int amt) {
amt = (100 - number_range(1, TALENT(ch, TAL_SECURITY))) * amt / 100;
if (amt < 0) amt = 0;
learn_talent(ch, TAL_SECURITY);
return lose_hp(ch, amt);
}
void do_auto(CHAR_DATA *ch, char *argument) {
if (IS_NPC(ch)) {
huh(ch);
return;
}
if (!argument || argument[0] == '\0') {
if (ch->pcdata->auto_attack)
ch_printf(ch, "You will %s every chance in combat.\n\r", ch->pcdata->auto_attack);
else
send_to_char("You won't try to fight in combat automatically.\n\r", ch);
return;
}
if (ch->pcdata->auto_attack) STRFREE(ch->pcdata->auto_attack);
if (str_cmp(argument, "none")) {
ch->pcdata->auto_attack = STRALLOC(argument);
ch_printf(ch, "You will now %s every opportunity in monster combat.\n\r", ch->pcdata->auto_attack);
return;
}
send_to_char("You will not automatically do anything in combat.\n\r", ch);
}
bool check_shield(CHAR_DATA *ch, CHAR_DATA *victim) {
if (!IS_AWAKE(ch) || !IS_SET(ch->mood, MOOD_READY)) return FALSE;
if (ch->main_hand && IS_OBJ_STAT(ch->main_hand, ITEM_SHIELD)) {
if (number_percent() >= 25) {
act(AT_YELLOW, "$n blocks your attack with $p.",
ch, ch->main_hand, victim, TO_VICT);
act(AT_YELLOW, "$n blocks $N's attack with $p.",
ch, ch->main_hand, victim, TO_NOTVICT);
act(AT_YELLOW, "You block $N's attack with $p.",
ch, ch->main_hand, victim, TO_CHAR);
learn_weapon(ch, SK_COMBAT);
return TRUE;
}
}
if (ch->off_hand && IS_OBJ_STAT(ch->off_hand, ITEM_SHIELD)) {
if (number_percent() >= 25) {
act(AT_SKILL, "$n blocks your attack with $p.",
ch, ch->off_hand, victim, TO_VICT);
act(AT_SKILL, "$n blocks $N's attack with $p.",
ch, ch->off_hand, victim, TO_NOTVICT);
act(AT_SKILL, "You block $N's attack with $p.",
ch, ch->off_hand, victim, TO_CHAR);
learn_weapon(ch, SK_COMBAT);
return TRUE;
}
}
return FALSE;
}
/* Hit someone somewhere. All physical attacks call this */
void check_hit(CHAR_DATA *ch, CHAR_DATA *victim, int loc, int dam, int type) {
PART_DATA *part;
char buf[MAX_STRING_LENGTH];
int chance = 0;
int i;
if (!IS_SAME_PLANE(ch, victim)) return;
if (IS_NPC(victim) && xIS_SET(victim->act, ACT_PACIFIST)) return;
if (IS_NPC(ch) && xIS_SET(victim->act, ACT_PACIFIST)) return;
learn_weapon(ch, SK_COMBAT);
ch->last_hit = victim;
if (!IS_NPC(ch)) chance += ch->pcdata->noncombat[0];
/* Sneak attack */
if (IS_AFFECTED(ch, AFF_HIDE)) {
dam *= 2;
chance += 100;
act(AT_DGREY, "You step out of your hiding spot.", ch, NULL, NULL, TO_CHAR);
act(AT_DGREY, "$n steps out of $s hiding spot.", ch, NULL, NULL, TO_ROOM);
if (IS_NPC(ch))
xREMOVE_BIT(ch->affected_by, AFF_HIDE);
else
xREMOVE_BIT(ch->pcdata->perm_aff, AFF_HIDE);
}
if (loc == -1) { /* none specificed, pick one at random */
chance += 100;
i = 0;
part = victim->first_part;
while (part) {
i++;
part = part->next;
}
loc = number_range(1, i);
}
/* Make sure they have the part it would have hit */
if ((part = find_bodypart(victim, loc)) == NULL
|| part->flags == PART_SEVERED) {
act(AT_ACTION, "You miss $N by an inch.",
ch, NULL, victim, TO_CHAR);
act(AT_ACTION, "$n misses $N by an inch.",
ch, NULL, victim, TO_NOTVICT);
act(AT_ACTION, "$n misses you by an inch.",
ch, NULL, victim, TO_VICT);
return;
}
/* Add in anymore bonuses */
if (IS_SET(ch->mood, MOOD_READY)) chance += 250;
if (IS_SET(victim->mood, MOOD_READY)) chance -= 250;
if (IS_SET(ch->mood, MOOD_DEFENSE)) chance -= 300;
if (IS_SET(victim->mood, MOOD_DEFENSE)) chance -= 300;
chance += IS_NPC(ch) ? 100 : ch->pcdata->weapon[SK_COMBAT];
chance += GET_HITROLL(ch);
chance += get_curr_dex(ch);
chance -= get_curr_dex(victim);
chance -= ch->encumberance*3;
chance += victim->encumberance*3;
if (chance < 75) chance = 75;
/* Roll to see if it hit */
chance = number_range(1, chance);
/* Chance to dodge. Can't miss if they're not awake */
if (chance < 50 && IS_AWAKE(victim)) {
if (check_dodge(ch, victim)) return;
if (check_tumble(ch, victim)) return;
}
if (check_blur(ch, victim)) return;
if (check_displacement(ch, victim)) return;
if (check_shield(victim, ch)) return;
/* Everything went through, hurt them */
dam -= number_range(part->armor, part->armor*3);
sprintf(buf, part_locs[part->loc]);
if (dam == 0)
strcat(buf, ", but fails to do any damage");
else if (dam < 20)
strcat(buf, " lightly.");
else if (dam < 50)
strcat(buf, ".");
else if (dam < 100)
strcat(buf, "!");
else if (dam < 200)
strcat(buf, " hard!");
else if (dam < 300)
strcat(buf, " very hard!");
else if (dam < 400)
strcat(buf, " extremely hard!");
else if (dam < 600)
strcat(buf, " incredibly hard!");
else if (dam < 800)
strcat(buf, " amazingly hard!");
else
strcat(buf, " unbelievably hard!");
act(AT_ACTION, "$n hits $N in the $t",
ch, buf, victim, TO_NOTVICT);
act(AT_SKILL, "You hit $N in the $t",
ch, buf, victim, TO_CHAR);
act(AT_HURT, "$n hits you in the $t",
ch, buf, victim, TO_VICT);
victim->last_hit = ch;
if (dam <= 0) return;
if (ch->last_hit && can_gain_exp(ch->last_hit, ch))
gain_exp(ch, get_exp_worth(victim) * dam / 100);
/* Blunt weapons tend to cause more internal (direct) damage */
if (type == MAG_BLUNT) {
if (dam > 500) break_part(victim, part);
if (direct_damage(victim, dam)) return;
hurt_part(victim, part, dam / 3);
} else {
if (direct_damage(victim, dam / 10)) return;
hurt_part(victim, part, dam);
}
pain(victim, dam);
}
/* This function processes all melee physical attacks */
void process_attack(CHAR_DATA *ch, char *argument, int dam, int type,
OBJ_DATA *obj, int sk) {
int part;
CHAR_DATA *victim;
char arg1[MAX_INPUT_LENGTH];
int lag;
learn_weapon(ch, sk);
argument = one_argument(argument, arg1);
if ((victim = find_target(ch, arg1, TRUE)) == NULL) return;
if (victim == ch) {
send_to_char("You're a masochist, aren't you.\n\r", ch);
return;
}
if (!can_hit(ch, victim, obj)) return;
if (!argument || argument[0] == '\0')
part = -1;
else {
part = find_part_name(argument);
}
/* wait first so bonuses/rolling doesnt alter it */
/* lighter weapons are faster */
lag = (dam + (obj ? obj->weight*10 : 0))/40;
if (ch->speed > 100) lag /= ch->speed / 100;
else lag += (100 - ch->speed) / 20;
lag = UMAX(4, lag); /* so we don't have lagless attacks */
if (lose_ep(ch, lag*3)) return;
/* add in any bonuses */
dam += GET_DAMROLL(ch);
if (!IS_NPC(ch))
dam += ch->pcdata->noncombat[sk];
if (obj && obj->item_type == ITEM_WEAPON) {
dam += obj->weight*10;
dam += obj->value[2];
if (obj->gem && IS_OBJ_STAT(obj->gem, ITEM_MAGIC)) dam += 100;
if (obj->value[4]) dam *= 2;
if (is_bane(obj, victim)) {
if (number_range(1, obj->value[6]) < dam)
obj->value[6]++;
dam += number_range(1, obj->value[6] / 10);
}
} else {
if (ch->nation)
dam += ch->nation->unarmed;
}
/* now roll for damage */
dam = number_range(dam/5, dam);
check_hit(ch, victim, part, dam, type);
}
/* Process a ranged attack. Obj is the projectile being sent */
void ranged_attack( CHAR_DATA *ch, OBJ_DATA *obj, char *argument ) {
CHAR_DATA *victim = NULL;
char arg[MAX_INPUT_LENGTH];
char arg1[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
int dir = -1, dist = 0, part = -1;
EXIT_DATA *pexit;
ROOM_INDEX_DATA *was_in_room;
CHAR_DATA *vch;
char *dtxt = "somewhere";
if (!argument || argument[0] == '\0')
{
send_to_char( "Where? At who?\n\r", ch );
return;
}
argument = one_argument(argument, arg);
argument = one_argument(argument, arg1);
if ((pexit = find_door(ch, arg, TRUE)) == NULL ) {
if ( ((victim=get_char_room(ch, arg)) == NULL) ) {
send_to_char( "Aim in what direction?\n\r", ch );
return;
}
} else
dir = pexit->vdir;
if (IS_SET(ch->in_room->room_flags, ROOM_PRIVATE)) {
send_to_char("There isn't enough room here.\n\r", ch);
return;
}
if (victim == ch) {
send_to_char("Suicidal, are we?\n\r", ch);
return;
}
if ( pexit && !pexit->to_room )
{
send_to_char( "Are you expecting to fire through a wall!?\n\r", ch );
return;
}
/* Check for obstruction */
if ( pexit && IS_SET(pexit->exit_info, EX_CLOSED) )
{
if ( IS_SET(pexit->exit_info, EX_SECRET)
|| IS_SET(pexit->exit_info, EX_DIG) )
send_to_char( "Are you expecting to fire through a wall!?\n\r", ch );
else
send_to_char( "Are you expecting to fire through a door!?\n\r", ch );
return;
}
vch = NULL;
if ( pexit && arg1[0] != '\0' )
{
if ( (vch=scan_for_victim(ch, pexit, arg1)) == NULL )
{
send_to_char( "You cannot see your target.\n\r", ch );
return;
}
/*don't allow attacks on mobs that are in a no-missile room --Shaddai */
if ( IS_SET(vch->in_room->room_flags, ROOM_NOMISSILE) )
{
send_to_char( "You can't get a clean shot off.\n\r", ch );
return;
}
}
victim = vch;
was_in_room = ch->in_room;
sprintf(buf, "firing the %s", myobj(obj));
STRFREE(ch->last_taken);
ch->last_taken = STRALLOC(arg);
WAIT_STATE(ch, PULSE_VIOLENCE);
/* if pexit is NULL at this point, it must be a point blank shot */
if (!pexit) {
victim = find_target(ch, arg, TRUE);
if (!victim) return;
if (!can_hit(ch, victim, obj)) return;
if (!arg1 || arg1[0] == '\0')
part = -1;
else {
part = find_part_name(arg1);
}
check_hit(ch, victim, part, 200 + obj->value[2], MAG_PIERCE);
if ( obj->in_obj )
obj_from_obj(obj);
if ( obj->carried_by )
obj_from_char(obj);
/* bullets and blasts aren't reusable */
if (obj->value[5] == SK_FIREARMS
|| obj->value[5] == SK_WAND)
extract_obj(obj);
else
obj_to_room(obj,ch->in_room);
return;
} /* end point blank shot */
while (dist <= 5) {
char_from_room(ch);
char_to_room(ch, pexit->to_room);
if ( IS_SET(pexit->exit_info, EX_CLOSED) ) {
/* whadoyahknow, the door's closed */
sprintf(buf,"You see your %s pierce a door in the distance to the %s.",
myobj(obj), dir_name[dir] );
act( AT_ACTION, buf, ch, NULL, NULL, TO_CHAR );
if (dir==4)
sprintf(buf, "$p flies in from %s and implants itself solidly in the ceiling.", dtxt);
else if (dir==5)
sprintf(buf, "$p flies in from %s and implants itself solidly in the floor.", dtxt);
else
sprintf(buf,"$p flies in from %s and implants itself solidly in the %sern door.",
dtxt, dir_name[dir] );
act( AT_ACTION, buf, ch, obj, NULL, TO_ROOM );
if ( obj->in_obj )
obj_from_obj(obj);
if (obj->carried_by )
obj_from_char(obj);
if (obj->value[5] == SK_WAND)
extract_obj(obj);
else if (IS_OBJ_STAT(obj, ITEM_RETURNING)) {
act(AT_SKILL, "$p returns to your hand.",
ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$p whirls around and flies back.",
ch, obj, NULL, TO_ROOM);
obj_to_char(obj, ch);
} else
obj_to_room(obj, ch->in_room);
break;
}
/* no victim? pick a random one */
if ( !victim ) {
for ( vch = ch->in_room->first_person; vch; vch = vch->next_in_room ) {
if ( number_bits(1) == 0 && ch!=vch ) {
victim = vch;
break;
}
}
}
dtxt = rev_exit(pexit->vdir);
/* In the same room as our victim? */
if ( victim && ch->in_room == victim->in_room ) {
act( AT_PLAIN, "$p flies in from $T.", ch, obj, dtxt, TO_ROOM );
if (!can_hit(ch, victim, obj)) return;
check_hit(ch, victim, -1, 100 + obj->value[2], MAG_PIERCE);
if ( obj->in_obj )
obj_from_obj(obj);
if ( obj->carried_by )
obj_from_char(obj);
/* bullets and blasts aren't reusable */
if (obj->value[5] == SK_FIREARMS
|| obj->value[5] == SK_WAND)
extract_obj(obj);
else if (IS_OBJ_STAT(obj, ITEM_RETURNING)) {
act(AT_SKILL, "$p returns to your hand.",
ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$p whirls around and flies back.",
ch, obj, NULL, TO_ROOM);
obj_to_char(obj, ch);
} else
obj_to_room(obj,ch->in_room);
char_from_room(ch);
char_to_room(ch, was_in_room);
return;
}
if ( ( pexit = get_exit( ch->in_room, dir ) ) == NULL )
{
act( AT_PLAIN, "Your $t hits a wall and bounces harmlessly to the ground to the $T.",
ch, myobj(obj), dir_name[dir], TO_CHAR );
act( AT_PLAIN, "$p strikes the $Tern wall and falls harmlessly to the ground.",
ch, obj, dir_name[dir], TO_ROOM );
if ( obj->in_obj )
obj_from_obj(obj);
if (obj->carried_by )
obj_from_char(obj);
if (obj->value[5] == SK_WAND)
extract_obj(obj);
else if (IS_OBJ_STAT(obj, ITEM_RETURNING)) {
act(AT_SKILL, "$p returns to your hand.",
ch, obj, NULL, TO_CHAR);
act(AT_SKILL, "$p whirls around and flies back.",
ch, obj, NULL, TO_ROOM);
obj_to_char(obj, ch);
} else
obj_to_room(obj, ch->in_room);
break;
}
act( AT_ACTION, "$p whizzes past you from $T.", ch, obj, dtxt, TO_ROOM );
dist++;
} /* end while loop */
char_from_room( ch );
char_to_room( ch, was_in_room );
if (obj && IS_OBJ_STAT(obj, ITEM_RETURNING))
act(AT_SKILL, "$p flies back into the room and $n deftly catches it again.", ch, obj, NULL, TO_ROOM);
}
/* Stop a fight */
void stop_fighting( CHAR_DATA *ch, bool fBoth )
{
CHAR_DATA *fch;
ch->last_hit = NULL;
if ( !fBoth ) /* major short cut here by Thoric */
return;
for ( fch = first_char; fch; fch = fch->next )
{
if ( fch->last_hit == ch )
{
fch->last_hit = NULL;
}
}
}
/* Mob attack function
* Mob picks a random attack based on its bodyparts
*/
void mob_attack(CHAR_DATA *ch, CHAR_DATA *victim) {
int i = number_range(1,3);
if (!ch) return;
if (!ch->in_room) return;
if (!victim) return;
if (victim == ch) return;
if (!IS_AWAKE(ch)) return;
if (!IS_NPC(ch) && xIS_SET(ch->act, PLR_DEFENSE)) return;
if (xIS_SET(ch->act, ACT_PHYS_FAIL) && IS_NPC(ch)) {
do_flee(ch, "");
return;
}
if (ch->main_hand) {
switch (ch->main_hand->value[5]) {
case SK_SWORD:
switch (i) {
case 1: do_slash(ch, victim->name); break;
case 2: do_stab(ch, victim->name); break;
case 3: do_lunge(ch, victim->name); break;
}
break;
case SK_DAGGER:
switch (i) {
case 1: do_slash(ch, victim->name); break;
default: do_stab(ch, victim->name); break;
}
break;
case SK_AXE:
switch(i) {
case 1: do_slash(ch, victim->name); break;
default: do_chop(ch, victim->name); break;
}
case SK_HALBERD:
case SK_POLEARM:
do_slash(ch, victim->name); break;
case SK_MACE:
case SK_STAFF:
do_pound(ch, victim->name); break;
case SK_SPEAR:
do_lunge(ch, victim->name); break;
case SK_CLAW:
do_claw(ch, victim->name); break;
case SK_WHIP:
do_whip(ch, victim->name); break;
case SK_FIREARMS:
case SK_BOW:
case SK_CROSSBOW:
case SK_WAND:
if (ch->main_hand->value[0] > 0) {
do_shoot(ch, victim->name); break;
}
}
}
if (ch->off_hand && ch->off_hand != ch->main_hand) {
switch (ch->off_hand->value[5]) {
case SK_SWORD:
switch (i) {
case 1: do_slash(ch, victim->name); break;
case 2: do_stab(ch, victim->name); break;
case 3: do_lunge(ch, victim->name); break;
}
break;
case SK_DAGGER:
switch (i) {
case 1: do_slash(ch, victim->name); break;
default: do_stab(ch, victim->name); break;
}
break;
case SK_AXE:
switch(i) {
case 1: do_slash(ch, victim->name); break;
default: do_chop(ch, victim->name); break;
}
case SK_HALBERD:
case SK_POLEARM:
do_slash(ch, victim->name); break;
case SK_MACE:
case SK_STAFF:
do_pound(ch, victim->name); break;
case SK_SPEAR:
do_lunge(ch, victim->name); break;
case SK_CLAW:
do_claw(ch, victim->name); break;
}
}
if (IS_SET(ch->xflags, 1 << PART_CLAWS) && i == 1) {
do_claw(ch, victim->name);
return;
}
if (IS_SET(ch->xflags, 1 << PART_TAIL) && i == 2) {
do_tail(ch, victim->name);
return;
}
if (IS_SET(ch->xflags, 1 << PART_HORNS) && i == 3) {
do_headbutt(ch, victim->name);
return;
}
if (IS_SET(ch->xflags, 1 << PART_FEET) && i == 1) {
do_kick(ch, victim->name);
return;
}
if (IS_SET(ch->xflags, 1 << PART_HANDS) && i == 2) {
do_punch(ch, victim->name);
return;
}
if (IS_SET(ch->xflags, 1 << PART_LEGS) && i == 3) {
do_knee(ch, victim->name);
return;
}
do_hit(ch, victim->name);
}
/* Mood functions */
void do_ready(CHAR_DATA *ch, char *argument) {
if (IS_SET(ch->mood, MOOD_READY)) {
send_to_char("You are already in a ready position!\n\r", ch);
return;
}
act(AT_ACTION, "You spring to readiness.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n springs to readiness.", ch, NULL, NULL, TO_ROOM);
REMOVE_BIT(ch->mood, MOOD_RELAXED);
SET_BIT(ch->mood, MOOD_READY);
}
void do_relax(CHAR_DATA *ch, char *argument) {
if (IS_SET(ch->mood, MOOD_RELAXED)) {
send_to_char("You are already relaxed!\n\r",ch);
return;
}
act(AT_ACTION, "You relax from your readiness.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n seems to relax.", ch, NULL, NULL, TO_ROOM);
REMOVE_BIT(ch->mood, MOOD_READY);
SET_BIT(ch->mood, MOOD_RELAXED);
}
/* Generic hit function. Swing whatever you're wielding at them */
void do_hit(CHAR_DATA *ch, char *argument) {
if (ch->main_hand) {
act(AT_ACTION, "You swing $p.", ch, ch->main_hand, NULL, TO_CHAR);
act(AT_ACTION, "$n swings $p.", ch, ch->main_hand, NULL, TO_ROOM);
process_attack(ch, argument, ch->main_hand->weight*5, MAG_BLUNT, ch->main_hand, SK_COMBAT);
} else
process_attack(ch, argument, 50, MAG_BLUNT, NULL, SK_COMBAT);
}
/* Physical attacks */
void do_punch( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj = NULL;
if (!can_use_bodypart(ch, BP_RHAND)
&& !can_use_bodypart(ch, BP_LHAND)
&& (obj = get_weapon(ch, SK_HAND)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You swing your fist.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n swings $s fist.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument, 150, MAG_BLUNT, obj, SK_HAND);
}
void do_kick( CHAR_DATA *ch, char *argument) {
if (!can_use_bodypart(ch, BP_RFOOT)
&& !can_use_bodypart(ch, BP_LFOOT)
&& !can_use_bodypart(ch, BP_RHOOF)
&& !can_use_bodypart(ch, BP_LHOOF)) {
huh(ch);
return;
}
act(AT_ACTION, "You kick with your $t.",
ch, IS_SET(ch->xflags, 1 << PART_HOOVES) ? "hooves" : "foot", NULL, TO_CHAR);
act(AT_ACTION, "$n kicks with $s $t.",
ch, IS_SET(ch->xflags, 1 << PART_HOOVES) ? "hooves" : "foot", NULL, TO_ROOM);
process_attack(ch, argument, 400 * (IS_SET(ch->xflags, 1 << PART_HOOVES)
? 2 : 1), MAG_BLUNT, NULL, SK_KICK);
}
void do_knee( CHAR_DATA *ch, char *argument) {
if (!can_use_bodypart(ch, BP_RLEG)
&& !can_use_bodypart(ch, BP_LLEG)) {
huh(ch);
return;
}
act(AT_ACTION, "You thrust your knee.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n thrusts $s knee.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument, 250, MAG_BLUNT, NULL, SK_KICK);
}
void do_elbow( CHAR_DATA *ch, char *argument) {
if (!can_use_bodypart(ch, BP_RARM)
&& !can_use_bodypart(ch, BP_LARM)) {
huh(ch);
return;
}
act(AT_ACTION, "You thrust your elbow.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n thrusts $s elbow.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument, 350, MAG_BLUNT, NULL, SK_HAND);
}
void do_headbutt( CHAR_DATA *ch, char *argument) {
act(AT_ACTION, "You butt your head.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n butts $s head.", ch, NULL, NULL, TO_ROOM);
if (can_use_bodypart(ch, BP_RHORN)
|| can_use_bodypart(ch, BP_LHORN)
|| can_use_bodypart(ch, BP_HORN))
process_attack(ch, argument, 500, MAG_PIERCE, NULL, SK_HEAD);
else
process_attack(ch, argument, 100, MAG_BLUNT, NULL, SK_HEAD);
}
void do_bite( CHAR_DATA *ch, char *argument) {
act(AT_ACTION, "You snap your teeth.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n snaps $s teeth.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument,
(can_use_bodypart(ch, BP_FANGS) ? 100 : 600),
MAG_PIERCE, NULL, SK_FANG);
}
void do_claw( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj = NULL;
if ((obj = get_weapon(ch, SK_CLAW)) == NULL
&& !can_use_bodypart(ch, BP_CLAWS)) {
huh(ch);
return;
}
act(AT_ACTION, "You swipe your claws.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n swipes $s claws.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument, 300, MAG_PIERCE, obj, SK_CLAW);
}
void do_tail( CHAR_DATA *ch, char *argument) {
if (!can_use_bodypart(ch, BP_TAIL)) {
huh(ch);
return;
}
act(AT_ACTION, "You swing your tail.", ch, NULL, NULL, TO_CHAR);
act(AT_ACTION, "$n swings $s tail.", ch, NULL, NULL, TO_ROOM);
process_attack(ch, argument, 400, MAG_BLUNT, NULL, SK_TAIL);
}
void do_slap( CHAR_DATA *ch, char *argument) {
if (!can_use_bodypart(ch, BP_RHAND)
&& !can_use_bodypart(ch, BP_LHAND)) {
huh(ch);
return;
}
check_social(ch, "slap", argument);
process_attack(ch, argument, 20, MAG_BLUNT, NULL, SK_HAND);
}
/* If you don't want these commands, comment out this section */
void do_piss( CHAR_DATA *ch, char *argument) {
char buf[MAX_STRING_LENGTH];
OBJ_DATA *obj;
PART_DATA *part;
CHAR_DATA *victim;
if (IS_NPC(ch) || ch->pcdata->condition[COND_THIRST] < 10) {
send_to_char("Nothing comes out.\n\r", ch);
return;
}
if ((part = find_bodypart(ch, BP_PENIS)) != NULL) {
if (part->obj) {
act(AT_YELLOW, "You piss your pants.",
ch, NULL, NULL, TO_CHAR);
act(AT_YELLOW, "$n pisses $s pants.",
ch, NULL, NULL, TO_ROOM);
return;
}
} else if ((part = find_bodypart(ch, BP_VAGINA)) != NULL) {
if (part->obj) {
act(AT_YELLOW, "You piss your pants.",
ch, NULL, NULL, TO_CHAR);
act(AT_YELLOW, "$n pisses $s pants.",
ch, NULL, NULL, TO_ROOM);
return;
}
}
victim = find_target(ch, argument, TRUE);
if (victim && (can_use_bodypart(ch, BP_PENIS)
|| IS_AFFECTED(ch, AFF_FLYING)
|| victim->position < POS_SQUATTING)) {
act(AT_YELLOW, "You piss on $N!",
ch, NULL, victim, TO_CHAR);
act(AT_YELLOW, "$n pisses on you!",
ch, NULL, victim, TO_VICT);
act(AT_YELLOW, "$n pisses on $N!",
ch, NULL, victim, TO_NOTVICT);
} else {
act(AT_YELLOW, "You take a piss on the floor.",
ch, NULL, NULL, TO_CHAR);
act(AT_YELLOW, "$n takes a piss on the floor.",
ch, NULL, NULL, TO_ROOM);
}
obj = obj_to_room(create_object(get_obj_index(OBJ_VNUM_PUDDLE),0), ch->in_room);
obj->value[1] = 10;
obj->value[0] = 10;
obj->value[2] = 8;
obj->timer = 5;
gain_condition(ch, COND_THIRST, -10);
sprintf(buf, obj->name, liq_table[obj->value[2]]);
STRFREE(obj->name);
obj->name = STRALLOC(buf);
sprintf(buf, obj->short_descr, liq_table[obj->value[2]]);
STRFREE(obj->short_descr);
obj->short_descr = STRALLOC(buf);
STRFREE(ch->last_taken);
ch->last_taken = STRALLOC("relieving yourself");
WAIT_STATE(ch, 10);
return;
}
/* end gross section */
/* START WEAPONS SECTION */
/* Weapon handling functions */
int free_hands(CHAR_DATA *ch) {
int i = 0;
if (can_use_bodypart(ch, BP_RHAND)
&& !ch->main_hand)
i++;
if (can_use_bodypart(ch, BP_LHAND)
&& !ch->off_hand)
i++;
return i;
}
OBJ_DATA *get_weapon(CHAR_DATA *ch, int skill) {
bool main_good;
bool off_good;
main_good = FALSE;
off_good = FALSE;
if (ch->main_hand
&& (ch->main_hand->item_type == ITEM_WEAPON
|| ch->main_hand->item_type == ITEM_MISSILE_WEAPON)
&& ch->main_hand->value[5] == skill)
main_good = TRUE;
if (ch->off_hand
&& (ch->off_hand->item_type == ITEM_WEAPON
|| ch->off_hand->item_type == ITEM_MISSILE_WEAPON)
&& ch->off_hand->value[5] == skill)
off_good = TRUE;
if (main_good && off_good) {
switch (number_range(1,2)) {
default:
return ch->main_hand; break;
case 2:
return ch->off_hand; break;
}
}
if (main_good) return ch->main_hand;
if (off_good) return ch->off_hand;
return NULL;
}
/* Weapon attack functions */
void do_whip( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_WHIP)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You crack your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n cracks $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 200, MAG_BLUNT,
obj, obj->value[5]);
}
void do_slash( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_SWORD)) == NULL
&& (obj = get_weapon(ch, SK_DAGGER)) == NULL
&& (obj = get_weapon(ch, SK_AXE)) == NULL
&& (obj = get_weapon(ch, SK_POLEARM)) == NULL
&& (obj = get_weapon(ch, SK_HALBERD)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You slash with your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n slashes with $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 400, MAG_SLASH, obj,
obj->value[5]);
}
void do_lunge( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_SWORD)) == NULL
&& (obj = get_weapon(ch, SK_SPEAR)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You lunge with your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n lunges with $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 750, MAG_PIERCE, obj,
obj->value[5]);
}
void do_chop( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_AXE)) == NULL
&& (obj = get_weapon(ch, SK_FANG)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You chop with your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n chops with $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 700, MAG_SLASH, obj,
obj->value[5]);
}
void do_stab( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_SWORD)) == NULL
&& (obj = get_weapon(ch, SK_DAGGER)) == NULL
&& (obj = get_weapon(ch, SK_SPEAR)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You stab with your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n stabs with $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 250, MAG_PIERCE, obj,
obj->value[5]);
}
void do_pound( CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
if ((obj = get_weapon(ch, SK_MACE)) == NULL
&& (obj = get_weapon(ch, SK_STAFF)) == NULL) {
huh(ch);
return;
}
act(AT_ACTION, "You swing your $t.",
ch, myobj(obj), NULL, TO_CHAR);
act(AT_ACTION, "$n swings $s $t.",
ch, myobj(obj), NULL, TO_ROOM);
process_attack(ch, argument, 400, MAG_BLUNT, obj,
obj->value[5]);
}
/* Ranged weapon attacks */
void do_throw(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
char arg[MAX_INPUT_LENGTH];
argument = one_argument(argument, arg);
if ((obj = get_obj_carry(ch, arg)) == NULL) {
send_to_char("You don't have that.\n\r", ch);
return;
}
if (obj->item_type == ITEM_WEAPON)
learn_weapon(ch, obj->value[5]);
act(AT_ACTION, "You throw $p.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n throws $p.", ch, obj, NULL, TO_ROOM);
ranged_attack(ch, obj, argument);
}
void do_shoot(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
OBJ_DATA *bullet;
if ((obj = get_weapon(ch, SK_FIREARMS)) == NULL
&& (obj = get_weapon(ch, SK_BOW)) == NULL
&& (obj = get_weapon(ch, SK_CROSSBOW)) == NULL
&& (obj = get_weapon(ch, SK_WAND)) == NULL) {
huh(ch);
return;
}
if (obj->value[0] == 0 && obj->value[5] != SK_WAND) {
ch_printf(ch, "Your %s is empty.\n\r", myobj(obj));
return;
} else if (obj->value[5] == SK_WAND && obj->raw_mana <= 0
&& !IS_OBJ_STAT(obj, ITEM_ARTIFACT)) {
ch_printf(ch, "Your %s is out of energy.\n\r", myobj(obj));
return;
}
act(AT_ACTION, "You fire $p.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n fires $p.", ch, obj, NULL, TO_ROOM);
if (obj->value[5] == SK_WAND)
obj->raw_mana -= 50;
else if (!IS_OBJ_STAT(obj, ITEM_RETURNING))
obj->value[0]--;
if (obj->value[5] == SK_FIREARMS) {
WAIT_STATE(ch, 8);
player_echo( ch, AT_ACTION,
"You hear a gunshot.", ECHOTAR_AREA );
bullet = create_object( get_obj_index( 29050 ), 0 ); /* bullet */
STRFREE(bullet->short_descr);
bullet->short_descr = STRALLOC("bullet");
} else if (obj->value[5] == SK_BOW) {
WAIT_STATE(ch, 10);
bullet = create_object( get_obj_index( 29048 ), 0 ); /* arrow */
STRFREE(bullet->short_descr);
bullet->short_descr = STRALLOC("arrow");
} else if (obj->value[5] == SK_CROSSBOW) {
WAIT_STATE(ch, 12);
bullet = create_object( get_obj_index( 29046 ), 0 ); /* bolt */
STRFREE(bullet->short_descr);
bullet->short_descr = STRALLOC("bolt");
} else if (obj->value[5] == SK_WAND) {
WAIT_STATE(ch, 14);
bullet = create_object( get_obj_index( 50 ), 0 ); /* blast */
}
if (!bullet) {
send_to_char("Your weapon jams mysteriously.\n\r", ch);
bug("Do_shoot: Cannot find type for projectile.", 0);
return;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
xSET_BIT(bullet->extra_flags, ITEM_MAGIC);
if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD))
xSET_BIT(bullet->extra_flags, ITEM_DREAMWORLD);
bullet->value[2] += obj->value[2];
if (obj->value[4]) bullet->value[2] *= 2;
if (obj->gem && IS_OBJ_STAT(obj->gem, ITEM_MAGIC))
bullet->value[2] += 100;
bullet->value[2] = number_range(bullet->value[2]/5, bullet->value[2]);
ranged_attack(ch, bullet, argument);
learn_weapon(ch, obj->value[5]);
/* Check for a second gun */
if (ch->main_hand && ch->main_hand->item_type == ITEM_MISSILE_WEAPON
&& (ch->main_hand->value[5] == SK_FIREARMS
|| ch->main_hand->value[5] == SK_WAND)
&& ch->off_hand && ch->off_hand->item_type == ITEM_MISSILE_WEAPON
&& (ch->off_hand->value[5] == SK_FIREARMS
|| ch->off_hand->value[5] == SK_WAND)) {
obj = ch->off_hand;
if (obj->value[0] == 0 && obj->value[5] != SK_WAND) {
ch_printf(ch, "Your %s is empty.\n\r", myobj(obj));
return;
} else if (obj->value[5] == SK_WAND && obj->raw_mana <= 0) {
ch_printf(ch, "Your %s is out of energy.\n\r", myobj(obj));
return;
}
act(AT_ACTION, "You fire $p.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n fires $p.", ch, obj, NULL, TO_ROOM);
if (obj->value[5] == SK_WAND)
obj->raw_mana -= 50;
else if (!IS_OBJ_STAT(obj, ITEM_RETURNING))
obj->value[0]--;
if (obj->value[5] == SK_FIREARMS) {
player_echo( ch, AT_ACTION,
"You hear another gunshot.", ECHOTAR_AREA );
bullet = create_object( get_obj_index( 29050 ), 0 ); /* bullet */
STRFREE(bullet->short_descr);
bullet->short_descr = STRALLOC("bullet");
} else if (obj->value[5] == SK_WAND) {
WAIT_STATE(ch, 14);
bullet = create_object( get_obj_index( 50 ), 0 ); /* blast */
}
if (!bullet) {
send_to_char("Your weapon jams mysteriously.\n\r", ch);
bug("Do_shoot: Cannot find type for projectile.", 0);
return;
}
if (IS_OBJ_STAT(obj, ITEM_MAGIC))
xSET_BIT(bullet->extra_flags, ITEM_MAGIC);
if (IS_OBJ_STAT(obj, ITEM_DREAMWORLD))
xSET_BIT(bullet->extra_flags, ITEM_DREAMWORLD);
bullet->value[2] += obj->value[2];
if (obj->value[4]) bullet->value[2] *= 2;
if (obj->gem && IS_OBJ_STAT(obj->gem, ITEM_MAGIC))
bullet->value[2] += 100;
bullet->value[2] = number_range(bullet->value[2]/5, bullet->value[2]);
ranged_attack(ch, bullet, argument);
learn_weapon(ch, obj->value[5]);
} /* end second gun */
}
/* Weapon manipulation commands */
void do_wield(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
obj = get_obj_carry(ch, argument);
if (!obj) {
send_to_char("Hold what?\n\r", ch);
return;
}
if (obj == ch->main_hand || obj == ch->off_hand) {
send_to_char("You are already wielding that.\n\r", ch);
return;
}
if (!free_hands(ch)) {
send_to_char("You have no free hands.\n\r", ch);
return;
}
obj_from_char(obj);
obj_to_char(obj, ch);
separate_obj(obj);
if (obj->weight > ch->weight / 2) {
send_to_char("That is too heavy for you to wield.\n\r", ch);
return;
} else if (obj->weight > ch->weight / 4
|| IS_OBJ_STAT(obj, ITEM_TWO_HANDED)) {
if (free_hands(ch) < 2) {
send_to_char("You need two hands to wield that.\n\r", ch);
return;
}
ch->off_hand = obj;
ch->main_hand = obj;
act(AT_ACTION, "You hold $p in both hands.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n holds $p in both hands.", ch, obj, NULL, TO_ROOM);
} else {
if (!ch->main_hand && can_use_bodypart(ch, BP_RHAND)) {
ch->main_hand = obj;
act(AT_ACTION, "You hold $p in your right hand.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n holds $p in $s right hand.", ch, obj, NULL, TO_ROOM);
} else if (!ch->off_hand && can_use_bodypart(ch, BP_LHAND)) {
ch->off_hand = obj;
act(AT_ACTION, "You hold $p in your left hand.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n holds $p in $s left hand.", ch, obj, NULL, TO_ROOM);
} else {
send_to_char("Both of your hands are full.\n\r", ch);
return;
}
}
obj_affect_ch(ch, obj);
}
void do_sheathe(CHAR_DATA *ch, char *argument) {
OBJ_DATA *obj;
obj = get_obj_carry(ch, argument);
if (!obj) {
send_to_char("You are not carrying that.\n\r", ch);
return;
}
if (obj != ch->main_hand && obj != ch->off_hand) {
send_to_char("You are not holding that.\n\r", ch);
return;
}
obj_from_char(obj);
obj_to_char(obj, ch);
act(AT_ACTION, "You put down $p.", ch, obj, NULL, TO_CHAR);
act(AT_ACTION, "$n puts down $p.", ch, obj, NULL, TO_ROOM);
}
void do_load(CHAR_DATA *ch, char *argument) {
OBJ_DATA *gun;
OBJ_DATA *bullet;
OBJ_DATA *bullet_next;
char arg[MAX_INPUT_LENGTH];
bool found;
argument = one_argument(argument, arg);
gun = get_obj_carry(ch, argument);
if (!gun) {
send_to_char("You don't have that.\n\r", ch);
return;
}
if (gun->item_type != ITEM_MISSILE_WEAPON) {
send_to_char("You can't load that!\n\r", ch);
return;
}
if (!str_cmp(arg, "all")) {
found = FALSE;
for (bullet = ch->first_carrying;bullet;bullet = bullet_next) {
bullet_next = bullet->next;
if (bullet->item_type != ITEM_PROJECTILE) continue;
if (gun->value[5] != bullet->value[5]) continue;
found = TRUE;
gun->value[0] += bullet->count;
extract_obj(bullet);
}
if (found) {
act(AT_ACTION, "You load $p.", ch, gun, NULL, TO_CHAR);
act(AT_ACTION, "$n loads $p.", ch, gun, NULL, TO_ROOM);
sprintf(arg, "loading the %s", myobj(gun));
STRFREE(ch->last_taken);
ch->last_taken = STRALLOC(arg);
WAIT_STATE(ch, PULSE_VIOLENCE);
} else {
send_to_char("You have nothing you can load that with.\n\r", ch);
}
return;
}
bullet = get_obj_carry(ch, arg);
if (!bullet) {
send_to_char("You don't have that.\n\r", ch);
return;
}
if (bullet->item_type != ITEM_PROJECTILE) {
send_to_char("That is not a projectile!\n\r", ch);
return;
}
if (gun->value[5] != bullet->value[5]) {
send_to_char("That is the wrong type of projectile for that weapon.\n\r", ch);
return;
}
if (!IS_OBJ_STAT(gun, ITEM_DREAMWORLD)
&& IS_OBJ_STAT(bullet, ITEM_DREAMWORLD)) {
send_to_char("In your dreams.\n\r", ch);
return;
}
gun->value[0] += bullet->count;
extract_obj(bullet);
sprintf(arg, "loading the %s", myobj(gun));
STRFREE(ch->last_taken);
ch->last_taken = STRALLOC(arg);
WAIT_STATE(ch, PULSE_VIOLENCE/2);
act(AT_ACTION, "You load $p.", ch, gun, NULL, TO_CHAR);
act(AT_ACTION, "$n loads $p.", ch, gun, NULL, TO_ROOM);
}