/** * \file act.offensive.c * Offensive actions for players * * This module provieds functionality for offensive activities, such as weapon * use, and archery, as well as guarding and fleeing. * * Copyright 2005, Mary C. Huston, All rights reserved. * Copyright (C) 2004, Shadows of Isildur: Traithe * * The program(s) may be used and/or copied only with written * permission or in accordance with the terms and conditions * stipulated in the license from DIKU GAMMA (0.0) and SOI. * * \author Mary Huston * \author Email: auroness@gmail.com * ****************************************************************************** */ #include <stdlib.h> #include <signal.h> #include <stdio.h> #include <string.h> #include <ctype.h> #include "structs.h" #include "protos.h" #include "utils.h" #include "decl.h" void do_throw (CHAR_DATA *ch, char *argument, int cmd) { OBJ_DATA *tobj = NULL; OBJ_DATA *armor1 = NULL; OBJ_DATA *armor2 = NULL; ROOM_DATA *troom = NULL; ROOM_DIRECTION_DATA *exit_room = NULL; CHAR_DATA *tch = NULL; bool can_lodge = FALSE; bool ranged = FALSE; int dir = 0; int result = 0; int location = 0; int wear_loc1 = 0; int wear_loc2 = 0; int wound_type = 0; float damage = 0; char buf [MAX_STRING_LENGTH] = {'\0'}; char buf2 [MAX_STRING_LENGTH] = {'\0'}; char buf3 [MAX_STRING_LENGTH] = {'\0'}; char smite_location [MAX_STRING_LENGTH] = {'\0'}; char *temp_arg = NULL; char *temp_arg1 = NULL; char *temp_arg2 = NULL; OBJ_DATA *temp_obj = NULL; if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( IS_SET (ch->room->room_flags, OOC) && IS_MORTAL(ch) ) { send_to_char ("You cannot do this in an OOC area.\n", ch); return; } argument = one_argument (argument, buf); if ( !*buf ) { send_to_char ("What did you wish to throw?\n", ch); return; } if ( !(tobj = get_obj_in_list (buf, ch->right_hand)) && !(tobj = get_obj_in_list (buf, ch->left_hand)) ) { send_to_char ("You aren't holding that in either hand.\n", ch); return; } argument = one_argument (argument, buf); if ( !*buf ) { send_to_char ("At what did you wish to throw?\n", ch); return; } if ( !(tch = get_char_room_vis (ch, buf)) ) { if ( (dir = is_direction (buf)) == -1 ) { send_to_char ("At what did you wish to throw?\n", ch); return; } } if ( ch->fighting ) { send_to_char ("You are currently engaged in melee combat and cannot throw.\n", ch); return; } if ( ch->balance <= -15 ) { send_to_char ("You're far too off-balance to attempt a throw.\n", ch); return; } if ( tobj->obj_flags.weight/100 > ch->str*2 ) { send_to_char ("That object is too heavy to throw effectively.\n", ch); return; } if ( tobj->count > 1 ) { send_to_char ("You may only throw one object at a time.\n", ch); return; } if ( !tch && dir != -1 ) { if ( (exit_room = PASSAGE (ch, dir)) ) troom = vtor (PASSAGE (ch, dir)->to_room); if ( !troom ) { send_to_char ("There is no exit in that direction.\n", ch); return; } if ( exit_room && IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } argument = one_argument (argument, buf); if ( *buf ) { tch = get_char_room_vis2 (ch, troom->virtual, buf); if ( !has_been_sighted (ch, tch) ) tch = NULL; if ( !tch ) { send_to_char ("You do not see anyone like that in this direction.\n", ch); return; } } if ( !tch ) { snprintf (buf, MAX_STRING_LENGTH, "You hurl #2%s#0 %sward.", tobj->short_description, dirs[dir]); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); snprintf (buf, MAX_STRING_LENGTH, "$n hurls #2%s#0 %sward.", tobj->short_description, dirs[dir]); act (buf, TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); obj_from_char (&tobj, 0); obj_to_room (tobj, troom->virtual); snprintf (buf, MAX_STRING_LENGTH, "#2%s#0 flies in, hurled from %s.", tobj->short_description, verbose_dirs[rev_dir[dir]]); buf[2] = toupper(buf[2]); send_to_room (buf, troom->virtual); return; } } if ( tch ) { if ( tch == ch ) { send_to_char ("That wouldn't require much of a throw...\n", ch); return; } if ( ch->room != tch->room && dir != -1 ) { if ( (exit_room = PASSAGE (ch, dir)) ) troom = vtor (PASSAGE (ch, dir)->to_room); if ( !troom ) { send_to_char ("There is no exit in that direction.\n", ch); return; } if ( exit_room && IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } } result = calculate_missile_result (ch, SKILL_THROWN, ch->balance*-10, tch, 0, NULL, tobj, NULL, &location, &damage); damage = (int)(damage); wear_loc1 = body_tab [0] [location].wear_loc1; wear_loc2 = body_tab [0] [location].wear_loc2; if ( wear_loc1 ) { armor1 = get_equip (tch, wear_loc1); if ( armor1 && GET_ITEM_TYPE (armor1) != ITEM_ARMOR ) armor1 = NULL; } if ( wear_loc2 ) { armor2 = get_equip (tch, wear_loc2); if ( armor2 && GET_ITEM_TYPE (armor2) != ITEM_ARMOR ) armor2 = NULL; } if ( damage > 3 ) criminalize (ch, tch, tch->room->zone, CRIME_KILL); if ( ch->room != tch->room ) { temp_arg1 = char_short(tch); temp_arg2 = char_short (ch); snprintf (buf, MAX_STRING_LENGTH, "You hurl #2%s#0 %sward, toward #5%s#0.", tobj->short_description, verbose_dirs[dir], temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "#5%s#0 hurls #2%s#0 %sward, toward #5%s#0.", temp_arg2, tobj->short_description, verbose_dirs[dir], temp_arg1); buf2[2] = toupper(buf2[2]); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); } else { temp_arg1 = char_short(tch); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "You hurl #2%s#0 forcefully at #5%s#0.", tobj->short_description, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "#5%s#0 hurls #2%s#0 forcefully at #5%s#0.", temp_arg2, tobj->short_description, temp_arg1); snprintf (buf3, MAX_STRING_LENGTH, "#5%s#0 hurls #2%s#0 forcefully at you.", temp_arg2, tobj->short_description); act (buf, FALSE, ch, 0, tch, TO_CHAR | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, tch, TO_NOTVICT | TO_ACT_FORMAT); act (buf3, FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); } if ( GET_ITEM_TYPE (tobj) == ITEM_WEAPON && (tobj->o.weapon.hit_type == 0 || tobj->o.weapon.hit_type == 1 || tobj->o.weapon.hit_type == 2 || tobj->o.weapon.hit_type == 4) ) { if ( result != CRITICAL_HIT && armor1 && armor1->o.armor.armor_type >= 2 ) can_lodge = FALSE; else if ( result != CRITICAL_HIT && armor2 && armor2->o.armor.armor_type >= 2 ) can_lodge = FALSE; else if ( result != CRITICAL_HIT && tch->armor && tch->armor >= 4 ) can_lodge = FALSE; else can_lodge = TRUE; } temp_arg = figure_location (tch, location); snprintf (smite_location, MAX_STRING_LENGTH, "%s", temp_arg); if ( result == MISS ) { snprintf (buf, MAX_STRING_LENGTH, "It misses completely."); snprintf (buf2, MAX_STRING_LENGTH, "It misses completely."); } else if ( result == CRITICAL_MISS ) { snprintf (buf, MAX_STRING_LENGTH, "It flies far wide of any target."); snprintf (buf2, MAX_STRING_LENGTH, "It flies far wide of any target."); } else if ( result == SHIELD_BLOCK ) { temp_obj = get_equip(tch, WEAR_SHIELD); temp_arg = obj_short_desc(temp_obj); snprintf (buf, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); } else if ( result == GLANCING_HIT ) { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It grazes %s on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It grazes you on the %s.", temp_arg); } else if ( result == HIT ) { if ( can_lodge ) { temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "It lodges in %s %s.", HSHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It lodges in your %s.", temp_arg); } else { temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "It strikes %s on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It strikes you on the %s.", temp_arg); } } else if ( result == CRITICAL_HIT ) { if ( can_lodge ) { temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "It lodges deeply in %s %s!", HSHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It lodges deeply in your %s!", temp_arg); } else { temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "It strikes %s solidly on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It strikes you solidly on the %s.", temp_arg); } } if ( ch->room != tch->room ) { send_to_room ("\n", ch->in_room); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); send_to_room ("\n", tch->in_room); act (buf2, FALSE, tch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf, FALSE, tch, 0, 0, TO_ROOM | TO_ACT_FORMAT); } else { send_to_room ("\n", ch->in_room); act (buf, TRUE, ch, 0, tch, TO_CHAR | TO_ACT_FORMAT); act (buf2, TRUE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); act (buf, TRUE, ch, 0, tch, TO_NOTVICT | TO_ACT_FORMAT); } obj_from_char (&tobj, 0); if ( (result == HIT || result == CRITICAL_HIT) && can_lodge ) { lodge_missile (tch, tobj, smite_location); } else obj_to_room (tobj, tch->in_room); if (damage > 0) { if ( !IS_NPC (tch) ) { tch->delay_ch = ch; tch->delay_info1 = tobj->virtual; } if ( ch->room != tch->room ) ranged = TRUE; if ( GET_ITEM_TYPE (tobj) == ITEM_WEAPON ) wound_type = tobj->o.weapon.hit_type; else wound_type = 3; if ( wound_to_char (tch, smite_location, (int)(damage), wound_type, 0, 0, 0) ) { if ( ranged ) send_to_char ("\nYour target collapses, dead.\n", ch); ch->ranged_enemy = NULL; return; } if ( !IS_NPC (tch) ) { tch->delay_ch = NULL; tch->delay_info1 = 0; } } if ( ch->agi <= 9 ) ch->balance += -20; else if ( ch->agi > 9 && ch->agi <= 13 ) ch->balance += -17; else if ( ch->agi > 13 && ch->agi <= 15 ) ch->balance += -15; else if ( ch->agi > 15 && ch->agi <= 18 ) ch->balance += -12; else ch->balance += -10; ch->balance = MAX (ch->balance, -50); npc_archery_retaliation (tch, ch); return; } send_to_char ("There has been an error; please report your command syntax to the staff.\n", ch); } void do_whirl (CHAR_DATA *ch, char *argument, int cmd) { OBJ_DATA *sling = NULL; if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( ch->fighting ) { send_to_char ("You're fighting for your life!\n", ch); return; } if ( !get_equip (ch, WEAR_PRIM) ) { send_to_char ("You need to be wielding a loaded sling to use this command.\n", ch); return; } sling = get_equip (ch, WEAR_PRIM); if ( sling->o.weapon.use_skill != SKILL_SLING ) { send_to_char ("This command is for use with slings only.\n", ch); return; } if ( !sling->contains ) { send_to_char ("The sling needs to be loaded, first.\n", ch); return; } act ("You begin whirling $p, gathering momentum for a shot.", FALSE, ch, sling, 0, TO_CHAR | TO_ACT_FORMAT); act ("$n begins whirling $p, gathering momentum for a shot.", TRUE, ch, sling, 0, TO_ROOM | TO_ACT_FORMAT); ch->whirling = 1; } int projectile_shield_block (CHAR_DATA *ch, int result) { OBJ_DATA *shield_obj = NULL; int roll = 0; if ( result == CRITICAL_HIT ) return 0; if ( (shield_obj = get_equip (ch, WEAR_SHIELD)) && number(1,25) <= ch->dex ) { skill_use (ch, SKILL_BLOCK, 0); roll = number(1,85); if ( roll <= ch->skills [SKILL_BLOCK] ) { return 1; } } return 0; } int calculate_missile_result (CHAR_DATA *ch, int ch_skill, int att_modifier, CHAR_DATA *target, int def_modifier, OBJ_DATA *weapon, OBJ_DATA *missile, AFFECTED_TYPE *spell, int *location, float *damage) { OBJ_DATA *armor1 = NULL; OBJ_DATA *armor2 = NULL; int roll = 0; int defense = 0; int assault = 0; int result = 0; int wear_loc1 = 0; int wear_loc2 = 0; int body_type = 0; /* Determine result of hit attempt. */ if ( !CAN_SEE (target, ch) ) def_modifier -= number (15,30); skill_use (target, SKILL_DODGE, 0); roll = number(1,85); roll += def_modifier; roll = MIN (roll, 85); if ( roll > target->skills [SKILL_DODGE] ) { if ( roll % 5 == 0 || roll == 1 ) defense = RESULT_CF; else defense = RESULT_MF; } else { if ( roll % 5 == 0 ) defense = RESULT_CS; else defense = RESULT_MS; } skill_use (ch, ch_skill, 0); if ( weather_info[ch->room->zone].fog == THIN_FOG ) att_modifier += 5; if ( weather_info[ch->room->zone].fog == THICK_FOG ) att_modifier += 10; if ( weather_info[ch->room->zone].state == STEADY_RAIN ) att_modifier += 15; if ( weather_info[ch->room->zone].state == HEAVY_RAIN ) att_modifier += 20; if ( weather_info[ch->room->zone].state == STEADY_SNOW ) att_modifier += 25; roll = number(1,85); roll += att_modifier; roll = MIN (roll, 85); ch->aim = 0; if ( ch->skills [ch_skill] ) { if ( roll > ch->skills [ch_skill] ) { if ( roll % 5 == 0 || roll == 1 ) assault = RESULT_CF; else assault = RESULT_MF; } else if ( roll <= ch->skills [ch_skill] ) { if ( roll % 5 == 0 ) assault = RESULT_CS; else assault = RESULT_MS; } } else { if ( roll > ch->skills [SKILL_OFFENSE] ) { if ( roll % 5 == 0 || roll == 1 ) assault = RESULT_CF; else assault = RESULT_MF; } else if ( roll <= ch->skills [SKILL_OFFENSE] ) { if ( roll % 5 == 0 ) assault = RESULT_CS; else assault = RESULT_MS; } } if ( assault == defense ) { if ( number(1,10) > 5 ) result = GLANCING_HIT; else result = MISS; } if ( assault == RESULT_CS ) { if ( defense == RESULT_MS ) result = HIT; else if ( defense == RESULT_MF ) result = HIT; else if ( defense == RESULT_CF ) result = CRITICAL_HIT; } else if ( assault == RESULT_MS ) { if ( defense == RESULT_CS ) result = MISS; else if ( defense == RESULT_MF ) result = HIT; else if ( defense == RESULT_CF ) result = CRITICAL_HIT; } else if ( assault == RESULT_MF ) { if ( defense == RESULT_CS ) result = CRITICAL_MISS; else if ( defense == RESULT_MS ) result = MISS; else if ( defense == RESULT_CF ) result = GLANCING_HIT; } else if ( assault == RESULT_CF ) { if ( defense == RESULT_CS ) result = CRITICAL_MISS; else if ( defense == RESULT_MS ) result = CRITICAL_MISS; else if ( defense == RESULT_MF ) result = MISS; } if ( !AWAKE (target) && assault != RESULT_CF ) result = CRITICAL_HIT; if ( (result == HIT || result == GLANCING_HIT) && projectile_shield_block (target, result) ) result = SHIELD_BLOCK; if ( result == MISS || result == CRITICAL_MISS || result == SHIELD_BLOCK ) return result; /* Determine damage of hit, if applicable. */ *damage = 0; body_type = 0; roll = number (1, 100); *location = -1; while ( roll > 0 ) roll = roll - body_tab [body_type] [++(*location)].percent; wear_loc1 = body_tab [body_type] [*location].wear_loc1; wear_loc2 = body_tab [body_type] [*location].wear_loc2; if ( wear_loc1 ) { armor1 = get_equip (target, wear_loc1); if ( armor1 && GET_ITEM_TYPE (armor1) != ITEM_ARMOR ) armor1 = NULL; } if ( wear_loc2 ) { armor2 = get_equip (target, wear_loc2); if ( armor2 && GET_ITEM_TYPE (armor2) != ITEM_ARMOR ) armor2 = NULL; } if ( missile ) { if ( GET_ITEM_TYPE (missile) == ITEM_MISSILE || GET_ITEM_TYPE (missile) == ITEM_BULLET ) *damage = (float)dice(missile->o.od.value[0], missile->o.od.value[1]); else if ( GET_ITEM_TYPE (missile) == ITEM_WEAPON ) *damage = (float)dice(missile->o.od.value[1], missile->o.od.value[2]); else *damage = (float)dice(1,3); if ( weapon ) /* Launched from a bow/sling */ *damage += weapon->o.od.value[4]; if ( weapon || IS_SET (missile->obj_flags.extra_flags, ITEM_THROWING) ) { if ( result == HIT ) { /* Multiply in critical hits to raw damage amount. */ *damage += number(3,5); *damage *= 1.75; } else if ( result == CRITICAL_HIT ) { *damage += number(4,6); *damage *= 2.75; } } if ( armor1 != NULL ) { *damage -= armor1->o.armor.armor_value; *damage += weapon_armor_table [1][armor1->o.armor.armor_type]; } if ( armor2 != NULL ) { *damage -= armor2->o.armor.armor_value; *damage += weapon_armor_table [1][armor2->o.armor.armor_type]; } if ( target->armor ) { *damage -= target->armor; } if ( weapon ) { if ( result != GLANCING_HIT) { /* Shot lodged in target, piercing the armor. */ if ( *location == 2 ) *damage *= 1.75; else if ( *location == 3 ) *damage *= 2.25; else if ( *location == 4 ) *damage *= 3.00; } } if ( missile ) { if ( GET_ITEM_TYPE (missile) != ITEM_WEAPON && GET_ITEM_TYPE (missile) != ITEM_MISSILE && GET_ITEM_TYPE (missile) != ITEM_BULLET ) *damage = 0; } } if ( weapon && weapon->o.weapon.use_skill == SKILL_SLING ) { if ( att_modifier < 0 ) att_modifier *= -1; if ( att_modifier <= 1 ) *damage *= 0.250; else if ( att_modifier > 1 && att_modifier <= 2 ) *damage *= 0.500; else if ( att_modifier > 2 && att_modifier <= 3 ) *damage *= 0.750; } return result; } void lodge_missile (CHAR_DATA *target, OBJ_DATA *ammo, char *smite_location) { LODGED_OBJECT_INFO *lodged = NULL; if ( !target->lodged ) { CREATE (target->lodged, LODGED_OBJECT_INFO, 1); target->lodged->vnum = ammo->virtual; target->lodged->location = add_hash (smite_location); } else for ( lodged = target->lodged; lodged; lodged = lodged->next ) { if ( !lodged->next ) { CREATE (lodged->next, LODGED_OBJECT_INFO, 1); lodged->next->vnum = ammo->virtual; lodged->next->location = add_hash (smite_location); break; } else continue; } } void fire_sling (CHAR_DATA *ch, OBJ_DATA *sling, char *argument) { CHAR_DATA *tch = NULL; ROOM_DATA *troom = NULL; OBJ_DATA *ammo = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; char smite_location [MAX_STRING_LENGTH] = {'\0'}; char buf2 [MAX_STRING_LENGTH] = {'\0'}; char buf3 [MAX_STRING_LENGTH] = {'\0'}; float damage = 0; int dir = 0; int location = 0; int result = 0; int attack_mod = 0; int wound_type = 0; bool ranged = FALSE; char *temp_arg = NULL; char *temp_arg1 = NULL; char *temp_arg2 = NULL; OBJ_DATA *temp_obj = NULL; if ( !ch || !sling ) return; if ( !*argument ) { send_to_char ("At what did you wish to fire your sling?\n", ch); return; } if ( !ch->whirling ) { send_to_char ("You'll need to begin whirling your sling before you can fire.\n", ch); return; } if ( !sling->contains ) { send_to_char ("You'll need to load your sling first.\n", ch); return; } argument = one_argument (argument, buf); if ( !(tch = get_char_room_vis (ch, buf)) ) { if ( (dir = is_direction (buf)) == -1 ) { send_to_char ("At what did you wish to fire?\n", ch); return; } } if ( !tch && dir != -1 ) { if ( PASSAGE (ch, dir) ) troom = vtor (PASSAGE (ch, dir)->to_room); if ( !troom ) { send_to_char ("There is no exit in that direction.\n", ch); return; } argument = one_argument (argument, buf); if ( *buf ) { tch = get_char_room_vis2 (ch, troom->virtual, buf); if ( !has_been_sighted (ch, tch) ) tch = NULL; if ( !tch ) { send_to_char ("You do not see anyone like that in this direction.\n", ch); return; } } } if ( !tch ) { send_to_char ("At whom did you wish to fire your sling?\n", ch); return; } if ( tch == ch ) { send_to_char ("Don't be silly.\n", ch); return; } attack_mod -= ch->whirling; ch->whirling = 0; result = calculate_missile_result (ch, sling->o.weapon.use_skill, attack_mod, tch, 0, sling, sling->contains, NULL, &location, &damage); damage = (int)(damage); temp_arg = figure_location (tch, location); snprintf (smite_location, MAX_STRING_LENGTH, "%s", temp_arg); if ( ch->room != tch->room ) { temp_arg1 = char_short(tch); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "You sling #2%s#0 %sward, toward #5%s#0.", sling->contains->short_description, verbose_dirs[dir], temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "#5%s#0 slings #2%s#0 %sward, toward #5%s#0.", temp_arg2, sling->contains->short_description, verbose_dirs[dir], temp_arg1); buf2[2] = toupper(buf2[2]); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); } else { temp_arg1 = char_short(tch); temp_arg2 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "You sling #2%s#0 forcefully at #5%s#0.", sling->contains->short_description, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "#5%s#0 slings #2%s#0 forcefully at #5%s#0.", temp_arg2, sling->contains->short_description, temp_arg1); snprintf (buf3, MAX_STRING_LENGTH, "#5%s#0 slings #2%s#0 forcefully at you.", temp_arg2, sling->contains->short_description); act (buf, FALSE, ch, 0, tch, TO_CHAR | TO_ACT_FORMAT); act (buf, FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, tch, TO_NOTVICT| TO_ACT_FORMAT); } if ( result == MISS ) { snprintf (buf, MAX_STRING_LENGTH, "It misses completely."); snprintf (buf2, MAX_STRING_LENGTH, "It misses completely."); } else if ( result == CRITICAL_MISS ) { snprintf (buf, MAX_STRING_LENGTH, "It flies far wide of any target."); snprintf (buf2, MAX_STRING_LENGTH, "It flies far wide of any target."); } else if ( result == SHIELD_BLOCK ) { temp_obj = get_equip(tch, WEAR_SHIELD); temp_arg = obj_short_desc(temp_obj); snprintf (buf, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); } else if ( result == GLANCING_HIT ) { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It grazes %s on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It grazes you on the %s.", temp_arg); } else if ( result == HIT ) { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It strikes %s on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It strikes you on the %s.", temp_arg); } else if ( result == CRITICAL_HIT ) { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It strikes %s solidly on the %s.", HMHR(tch), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It strikes you solidly on the %s.", temp_arg); } ammo = sling->contains; obj_from_obj (&ammo, 0); obj_to_room (ammo, tch->in_room); if ( result == CRITICAL_MISS && !number(0,1) ) { snprintf (buf + strlen(buf), MAX_STRING_LENGTH, "\n\nThe missile recedes hopelessly from sight."); snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "\n\nThe missile recedes hopelessly from sight."); snprintf (buf3 + strlen(buf3), MAX_STRING_LENGTH, "\n\nThe missile recedes hopelessly from sight."); extract_obj(ammo); } if ( ch->room != tch->room ) { send_to_room ("\n", ch->in_room); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); send_to_room ("\n", tch->in_room); act (buf2, FALSE, tch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf, FALSE, tch, 0, 0, TO_ROOM | TO_ACT_FORMAT); } else { send_to_room ("\n", ch->in_room); act (buf, FALSE, ch, 0, tch, TO_CHAR | TO_ACT_FORMAT); act (buf2, FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); act (buf, FALSE, ch, 0, tch, TO_NOTVICT | TO_ACT_FORMAT); } if (damage > 0) { if ( !IS_NPC (tch) ) { tch->delay_ch = ch; tch->delay_info1 = ammo->virtual; } if ( ch->room != tch->room ) ranged = TRUE; wound_type = 3; if ( wound_to_char (tch, smite_location, (int)damage, wound_type, 0, 0, 0) ) { if ( ranged ) send_to_char ("\nYour target collapses, dead.\n", ch); ch->ranged_enemy = NULL; return; } if ( !IS_NPC (tch) ) { tch->delay_ch = NULL; tch->delay_info1 = 0; } if ( damage > 3 ) criminalize (ch, tch, tch->room->zone, CRIME_KILL); } npc_archery_retaliation (tch, ch); } void do_fire (CHAR_DATA *ch, char *argument, int cmd) { CHAR_DATA *target = NULL; CHAR_DATA *tch = NULL; OBJ_DATA *obj = NULL; OBJ_DATA *ammo = NULL; OBJ_DATA *bow = NULL; OBJ_DATA *armor1 = NULL; OBJ_DATA *armor2 = NULL; OBJ_DATA *shield_obj = NULL; ROOM_DATA *room = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; char buf2 [MAX_STRING_LENGTH] = {'\0'}; char buf3 [MAX_STRING_LENGTH] = {'\0'}; char buffer [MAX_STRING_LENGTH] = {'\0'}; char smite_location [MAX_STRING_LENGTH] = {'\0'}; char *from_direction = NULL; char *p = NULL; char *temp_arg = NULL; char *temp_arg1 = NULL; char *temp_arg2 = NULL; int roll = 0; int ranged = 0; int result = 0; int location = 0; int attack_mod = 0; float damage = 0; int dir = 0; bool switched_target = FALSE; if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( IS_SET (ch->room->room_flags, OOC) && IS_MORTAL(ch) ) { send_to_char ("You cannot do this in an OOC area.\n", ch); return; } if ( ((bow = get_equip(ch, WEAR_PRIM)) && GET_ITEM_TYPE(bow) == ITEM_WEAPON && bow->o.weapon.use_skill == SKILL_SLING) || ((bow = get_equip (ch, WEAR_SEC)) && GET_ITEM_TYPE(bow) == ITEM_WEAPON && bow->o.weapon.use_skill == SKILL_SLING) ) { fire_sling (ch, bow, argument); return; } if ( !ch->aiming_at ) { send_to_char ("You aren't aiming at anything.\n", ch); return; } if ( !IS_NPC (ch->aiming_at) && ch->aiming_at->pc->create_state == STATE_DIED ) { send_to_char ("You aren't aiming at anything alive.\n", ch); return; } if ( !(bow = get_equip (ch, WEAR_BOTH)) ) { send_to_char ("You aren't wielding a ranged weapon!\n", ch); ch->aiming_at->targeted_by = NULL; ch->aiming_at = NULL; ch->aim = 0; return; } if ( !bow->loaded ) { send_to_char ("Your weapon isn't loaded...\n", ch); ch->aiming_at->targeted_by = NULL; ch->aiming_at = NULL; ch->aim = 0; return; } if ( IS_SET (ch->plr_flags, NEW_PLAYER_TAG) && IS_SET (ch->room->room_flags, LAWFUL) && *argument != '!' ) { snprintf (buf, MAX_STRING_LENGTH, "You are in a lawful area; you would likely be flagged wanted for assault. " "To confirm, type \'#6fire !#0\', without the quotes."); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); return; } attack_mod -= ch->aim; target = ch->aiming_at; target->targeted_by = NULL; ch->aiming_at = NULL; ch->aim = 0; if ( !IS_NPC (target) && (!str_cmp (target->tname, IMPLEMENTOR_ACCOUNT)) && !IS_NPC (ch) ){ target = ch; } if ( ch->in_room != target->in_room ){ ranged = 1; } if ( ranged ) { if ( !ch->delay_who ) { send_to_char ("You seem to have lost sight of your quarry.\n", ch); return; } if ( !cmp_strn ("north", ch->delay_who, strlen(ch->delay_who)) ) dir = 0; else if ( !cmp_strn ("east", ch->delay_who, strlen(ch->delay_who)) ) dir = 1; else if ( !cmp_strn ("south", ch->delay_who, strlen(ch->delay_who)) ) dir = 2; else if ( !cmp_strn("west", ch->delay_who, strlen(ch->delay_who)) ) dir = 3; else if ( !cmp_strn ("up", ch->delay_who, strlen(ch->delay_who)) ) dir = 4; else if ( !cmp_strn ("down", ch->delay_who, strlen(ch->delay_who)) ) dir = 5; } /* ranged_projectile_echoes (ch, target, bow, ammo); */ if ( bow->o.weapon.use_skill == SKILL_SHORTBOW || bow->o.weapon.use_skill == SKILL_LONGBOW ) { if ( ranged ) { temp_arg = char_short (target); temp_arg1 = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "You release the bowstring, launching #2%s#0 %sward through the air toward #5%s#0.", bow->loaded->short_description, ch->delay_who, temp_arg ); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 releases the bowstring, launching #2%s#0 %sward through the air toward #5%s#0.", temp_arg1, bow->loaded->short_description, ch->delay_who, temp_arg); *buf2 = toupper (*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "%s", buffer); } else { temp_arg = char_short(ch); temp_arg1 = char_short(target); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 releases the bowstring, launching #2%s#0 through the air toward #5%s#0.", temp_arg, bow->loaded->short_description, temp_arg1); *buf2 = toupper (*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "%s", buffer); snprintf (buf3, MAX_STRING_LENGTH, "%s#0 releases the bowstring, launching #2%s#0 through the air toward you!", temp_arg, bow->loaded->short_description); *buf3 = toupper (*buf3); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf3); snprintf (buf3, MAX_STRING_LENGTH, "%s", buffer); snprintf (buf, MAX_STRING_LENGTH, "You release the bowstring, launching #2%s#0 through the air toward #5%s#0!", bow->loaded->short_description, temp_arg1); } } else if ( bow->o.weapon.use_skill == SKILL_CROSSBOW ) { if ( ranged ) { temp_arg = char_short(ch); temp_arg1 = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "You squeeze the trigger, sending #2%s#0 whirring %sward through the air toward #5%s#0.", bow->loaded->short_description, ch->delay_who, temp_arg1); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 squeezes the trigger, sending #2%s#0 whirring %sward through the air toward #5%s#0.", temp_arg, bow->loaded->short_description, ch->delay_who, temp_arg1); snprintf (buffer, MAX_STRING_LENGTH, "#5%s#0", CAP(buf2)); snprintf (buf2, MAX_STRING_LENGTH, "%s", buffer); } else { temp_arg = char_short(ch); temp_arg1 = char_short(target); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 squeezes the trigger, sending #2%s#0 whirring through the air toward #5%s#0.", temp_arg, bow->loaded->short_description, temp_arg1); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", CAP(buf2)); snprintf (buf2, MAX_STRING_LENGTH, "%s", buffer); snprintf (buf3, MAX_STRING_LENGTH, "%s#0 squeezes the trigger, sending #2%s#0 whirring through the air toward you!", temp_arg, bow->loaded->short_description); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", CAP(buf3)); snprintf (buf3, MAX_STRING_LENGTH, "%s", buffer); snprintf (buf, MAX_STRING_LENGTH, "You squeeze the trigger, sending #2%s#0 whirring through the air toward #5%s#0!", bow->loaded->short_description, temp_arg1); } } if ( ranged ) { act (buf, TRUE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); act (buf2, TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); snprintf (buf3, MAX_STRING_LENGTH, "You spy #2%s#0 as it arcs high overhead, streaking %sward.", bow->loaded->short_description, ch->delay_who); reformat_string (buf3, &p); if ( PASSAGE(ch,dir) ) room = vtor (PASSAGE(ch,dir)->to_room); else room = NULL; if ( room && target->room != room ) { for ( tch = room->people; tch; tch = tch->next_in_room ){ if ( skill_use (tch, SKILL_SCAN, 0) ){ send_to_char (p, tch); } } if ( room->dir_option[dir] ){ room = vtor (room->dir_option[dir]->to_room); } else { room = NULL; } if ( room && target->room != room ) { for ( tch = room->people; tch; tch = tch->next_in_room ){ if ( skill_use (tch, SKILL_SCAN, 0) ){ send_to_char (p, tch); } } if ( room->dir_option[dir] ){ room = vtor (room->dir_option[dir]->to_room); } else{ room = NULL; } if ( room && target->room != room ) { for ( tch = room->people; tch; tch = tch->next_in_room ){ if ( skill_use (tch, SKILL_SCAN, 0) ){ send_to_char (p, tch); } } } } } mem_free (p); } else if ( !ranged ) { act (buf, TRUE, ch, 0, target, TO_CHAR | TO_ACT_FORMAT); act (buf3, TRUE, ch, 0, target, TO_VICT | TO_ACT_FORMAT); act (buf2, TRUE, ch, 0, target, TO_NOTVICT | TO_ACT_FORMAT); } ammo = load_object(bow->loaded->virtual); ammo->count = 1; ammo->in_obj = NULL; ammo->carried_by = NULL; ammo->equiped_by = NULL; if ( ranged && ch->delay_who ) { if ( !str_cmp (ch->delay_who, "north") ) from_direction = str_dup ("the south"); else if ( !str_cmp (ch->delay_who, "east") ) from_direction = str_dup ("the west"); else if ( !str_cmp (ch->delay_who, "south") ) from_direction = str_dup ("the north"); else if ( !str_cmp (ch->delay_who, "west") ) from_direction = str_dup ("the east"); else if ( !str_cmp (ch->delay_who, "up") ) from_direction = str_dup ("below"); else if ( !str_cmp (ch->delay_who, "down") ) from_direction = str_dup ("above"); if ( ch->delay_who && strlen(ch->delay_who) > 1 ) mem_free (ch->delay_who); ch->delay_who = NULL; } else{ from_direction = add_hash ("an indeterminate direction"); } attack_mod -= bow->o.od.value[2]; if ( ch->fighting ) { if ( bow->o.weapon.use_skill == SKILL_LONGBOW ) attack_mod += 30; else if ( bow->o.weapon.use_skill == SKILL_SHORTBOW ) attack_mod += 20; else if ( bow->o.weapon.use_skill == SKILL_CROSSBOW ) attack_mod += 10; } if ( !ch->delay_info1 ) { if ( bow->o.weapon.use_skill == SKILL_LONGBOW ) attack_mod += 20; else if ( bow->o.weapon.use_skill == SKILL_SHORTBOW ) attack_mod += 10; } else if ( ch->delay_info1 == 1 ) { if ( bow->o.weapon.use_skill == SKILL_LONGBOW ) attack_mod += 10; else if ( bow->o.weapon.use_skill == SKILL_CROSSBOW ) attack_mod += 10; } else if ( ch->delay_info1 == 2 ) { if ( bow->o.weapon.use_skill == SKILL_SHORTBOW ) attack_mod += 10; else if ( bow->o.weapon.use_skill == SKILL_CROSSBOW ) attack_mod += 15; } result = calculate_missile_result (ch, bow->o.weapon.use_skill, attack_mod, target, 0, bow, ammo, NULL, &location, &damage); damage = (int)(damage); if ( (result == CRITICAL_MISS || result == MISS) && target->fighting && target->fighting != ch && number(1,25) > ch->dex ) { target = target->fighting; result = calculate_missile_result (ch, bow->o.weapon.use_skill, roll, target, 0, bow, ammo, NULL, &location, &damage); switched_target = TRUE; } *buf = '\0'; *buf2 = '\0'; *buf3 = '\0'; *buffer = '\0'; if ( result == MISS ) { if ( ranged ) { temp_arg = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward you!\n\nIt misses you completely.", ammo->short_description, from_direction); *buf = toupper(*buf); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf); snprintf (buf, MAX_STRING_LENGTH, "\n%s", buffer); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward #5%s#0.\n\nIt misses %s completely.", ammo->short_description, from_direction, temp_arg, HMHR(target)); *buf2 = toupper (*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "\n%s", buffer); snprintf (buf3, MAX_STRING_LENGTH, "It misses %s completely.", HMHR(target)); } else { snprintf (buf, MAX_STRING_LENGTH, "\nIt misses %s completely.", HMHR(target)); snprintf (buf2, MAX_STRING_LENGTH, "\nIt misses you completely."); } } /* Miss. */ else if ( result == CRITICAL_MISS ) { if ( ranged ) { snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, but it flies far wide of striking any target.", ammo->short_description, from_direction); *buf = toupper (*buf); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf); snprintf (buf, MAX_STRING_LENGTH, "\n%s", buffer); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, but it flies far wide of striking any target.", ammo->short_description, from_direction); *buf2 = toupper(*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "\n%s", buffer); snprintf (buf3, MAX_STRING_LENGTH, "Your shot flies far wide of striking any target."); } else if ( !ranged ) { snprintf (buf, MAX_STRING_LENGTH, "It streaks off to one side, far wide of any desired target."); snprintf (buf2, MAX_STRING_LENGTH, "It streaks off to one side, far wide of any desired target."); } } /* Critical miss. */ else if ( result == SHIELD_BLOCK ) { shield_obj = get_equip (target, WEAR_SHIELD); temp_arg = obj_short_desc(shield_obj); temp_arg1 = char_short(target); if ( ranged ) { snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward you!\n\nIt glances harmlessly off #2%s#0.", ammo->short_description, from_direction, temp_arg ); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward #5%s#0.\n\nIt glances harmlessly off #2%s#0.", ammo->short_description, from_direction, temp_arg1, temp_arg); snprintf (buf3, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); } else if ( !ranged ) { snprintf (buf, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It glances harmlessly off #2%s#0.", temp_arg); } } else if ( result == HIT || result == GLANCING_HIT || result == CRITICAL_HIT ) { temp_arg = figure_location (target, location); snprintf (smite_location, MAX_STRING_LENGTH, "%s", temp_arg ); if ( ranged ) { if ( result != CRITICAL_HIT && result != HIT ) { temp_arg = expand_wound_loc(smite_location); temp_arg1 = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward you!\n\nIt grazes you on the %s.", ammo->short_description, from_direction, temp_arg); *buf = toupper(*buf); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf); snprintf (buf, MAX_STRING_LENGTH, "\n%s", buffer); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward #5%s#0.\n\nIt grazes %s on the %s.", ammo->short_description, from_direction, temp_arg1, HMHR(target), temp_arg); *buf2 = toupper(*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "\n%s", buffer); if ( switched_target ){ snprintf (buf3, MAX_STRING_LENGTH, "It strays off-course, instead striking #5%s#0 on the %s!", temp_arg1, temp_arg); } else{ snprintf (buf3, MAX_STRING_LENGTH, "It grazes %s on the %s.", HMHR(target), temp_arg); } } else { if ( result == CRITICAL_HIT ){ temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward you!\n\nThe missile lodges deeply in your %s!", ammo->short_description, from_direction, temp_arg); } else{ temp_arg = expand_wound_loc(smite_location); snprintf (buf, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward you!\n\nThe missile lodges in your %s!", ammo->short_description, from_direction, temp_arg); } *buf = toupper(*buf); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf); snprintf (buf, MAX_STRING_LENGTH, "\n%s", buffer); if ( result == CRITICAL_HIT ){ temp_arg = char_short(target); temp_arg1 = expand_wound_loc(smite_location); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward #5%s#0.\n\nThe missile lodges deeply in %s %s!", ammo->short_description, from_direction, temp_arg, HSHR(target), temp_arg1); } else{ temp_arg = char_short(target); temp_arg1 = expand_wound_loc(smite_location); snprintf (buf2, MAX_STRING_LENGTH, "%s#0 comes whirring through the air from %s, headed straight toward #5%s#0.\n\nThe missile lodges in %s %s!", ammo->short_description, from_direction, temp_arg, HSHR(target), temp_arg1); } *buf2 = toupper(*buf2); snprintf (buffer, MAX_STRING_LENGTH, "#2%s", buf2); snprintf (buf2, MAX_STRING_LENGTH, "\n%s", buffer); if ( switched_target ) { if ( result == CRITICAL_HIT ){ temp_arg = char_short(target); temp_arg1 = expand_wound_loc(smite_location); snprintf (buf3, MAX_STRING_LENGTH, "It strays off-course, instead lodging deeply in #5%s#0's %s!", temp_arg, temp_arg1); } else{ temp_arg = char_short(target); temp_arg1 = expand_wound_loc(smite_location); snprintf (buf3, MAX_STRING_LENGTH, "It strays off-course, instead lodging in #5%s#0's %s!", temp_arg, temp_arg1); } } else { if ( result == CRITICAL_HIT ){ temp_arg = expand_wound_loc(smite_location); snprintf (buf3, MAX_STRING_LENGTH, "The missile lodges deeply in %s %s!", HSHR(target), temp_arg); } else { temp_arg = expand_wound_loc(smite_location); snprintf (buf3, MAX_STRING_LENGTH, "The missile lodges in %s %s!", HSHR(target), temp_arg); } } } } else if ( !ranged && result != CRITICAL_HIT && result != HIT ) { if ( switched_target ) { temp_arg = char_short (target); temp_arg1 = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It strays off-course, grazing #5%s#0 on the %s.", temp_arg, temp_arg1 ); snprintf (buf2, MAX_STRING_LENGTH, "It strays off-course, grazing you on the %s.", temp_arg1); } else { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "It grazes %s on the %s.", HMHR (target), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "It grazes you on the %s.", temp_arg); } } else if ( !ranged && (result == CRITICAL_HIT || result == HIT) ) { if ( switched_target ) { temp_arg1 = expand_wound_loc (smite_location); temp_arg2 = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "The missile strays off-course, striking #5%s#0 instead, and lodging deeply in %s %s!", temp_arg2, HSHR (target), temp_arg1 ); snprintf (buf2, MAX_STRING_LENGTH, "The missile strays off-course, striking you instead, and lodging deeply in your %s!", temp_arg1); } else { if ( result == CRITICAL_HIT ) { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "The missile lodges deeply in %s %s!", HSHR (target), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "The missile lodges deeply in your %s!", temp_arg); } else { temp_arg = expand_wound_loc (smite_location); snprintf (buf, MAX_STRING_LENGTH, "The missile lodges in %s %s!", HSHR (target), temp_arg); snprintf (buf2, MAX_STRING_LENGTH, "The missile lodges in your %s!", temp_arg); } } } } if ( result == GLANCING_HIT || result == MISS || result == SHIELD_BLOCK ) { if ( !number(0,9) && ((armor1 || armor2 || target->armor) || result == MISS || result == SHIELD_BLOCK) ) { snprintf (buf + strlen(buf), MAX_STRING_LENGTH, "\n\nThe missile shatters upon impact at its destination."); snprintf (buf2 + strlen(buf2), MAX_STRING_LENGTH, "\n\nThe missile shatters upon impact at its destination."); snprintf (buf3 + strlen(buf3), MAX_STRING_LENGTH, "\n\nThe missile shatters upon impact at its destination."); } else { obj = load_object(ammo->virtual); obj->deleted = 0; obj->count = 1; obj->obj_timer = 8; /* 2 RL hours. */ obj->next_content = NULL; obj_to_room (obj, target->in_room); } extract_obj(bow->loaded); bow->loaded = NULL; } else if ( result == CRITICAL_HIT || result == HIT ) { lodge_missile (target, ammo, smite_location); bow->loaded = NULL; } if ( ranged ) { send_to_char ("\n", target); act (buf, TRUE, ch, 0, target, TO_VICT | TO_ACT_FORMAT); send_to_char ("\n", ch); act (buf3, TRUE, ch, 0, target, TO_CHAR | TO_ACT_FORMAT); for ( tch = target->room->people; tch; tch = tch->next_in_room ) { if ( tch != target && tch != ch ) { send_to_char ("\n", tch); act (buf2, TRUE, tch, 0, target, TO_CHAR | TO_ACT_FORMAT); } } } else if ( !ranged ) { act (buf2, TRUE, ch, 0, target, TO_VICT | TO_ACT_FORMAT); for ( tch = target->room->people; tch; tch = tch->next_in_room ) { if ( tch != target ) { send_to_char ("\n", tch); act (buf, TRUE, tch, 0, target, TO_CHAR | TO_ACT_FORMAT); } } } bow->loaded = NULL; criminalize (ch, target, target->room->zone, CRIME_KILL); ch->enemy_direction = NULL; if ( from_direction ) mem_free (from_direction); if ( ch->delay_who ) { mem_free (ch->delay_who); ch->delay_who = NULL; } if (damage > 0) { if ( !IS_NPC (target) ) { target->delay_ch = ch; target->delay_info1 = ammo->virtual; } if ( wound_to_char (target, smite_location, (int)(damage), 0, 0, 0, 0) ) { if ( ranged ){ send_to_char ("\nYour target collapses, dead.\n", ch); } ch->ranged_enemy = NULL; return; } if ( !IS_NPC (target) ) { target->delay_ch = NULL; target->delay_info1 = 0; } } for ( tch = target->room->people; tch; tch = tch->next_in_room ) { if ( !IS_NPC (tch) || !is_brother (target, tch) ) continue; if ( morale_broken(tch) || (!IS_SET (tch->act, ACT_ENFORCER) && !IS_SET (tch->act, ACT_AGGRESSIVE)) ) evade_attacker (tch, track (tch, ch->in_room)); } npc_archery_retaliation (target, ch); return; } int has_been_sighted (CHAR_DATA *ch, CHAR_DATA *target) { VIEWED_DATA *sighted = NULL; if ( !ch || !target ) return 0; if ( !IS_MORTAL (ch) ) return 1; if ( IS_NPC (ch) && !ch->desc ) return 1; /* We know non-animated NPCs only acquire targets via SCANning; */ /* don't need anti-twink code for them. */ for ( sighted = ch->sighted; sighted; sighted = sighted->next ) { if ( sighted->target == target ) return 1; } return 0; } void npc_archery_retaliation (CHAR_DATA *target, CHAR_DATA *ch) { if ( IS_NPC (target) && !target->desc ) { add_threat (target, ch, 7); if ( IS_SET (target->act, ACT_MOUNT) && target->mount ) add_threat (target->mount, ch, 7); if ( !target->fighting && !IS_SET (target->flags, FLAG_ENTERING) && !IS_SET (target->flags, FLAG_LEAVING) && !IS_SET (target->flags, FLAG_FLEE) ) { do_stand (target, "", 0); target->speed = 4; if ( (track (target, ch->in_room) == -1 && target->in_room != ch->in_room) || (!IS_SET (ch->act, ACT_ENFORCER) && !IS_SET (ch->act, ACT_AGGRESSIVE)) || morale_broken (target) ) evade_attacker (target, -1); else charge_archer (target, ch); } else if ( (IS_SET (target->act, ACT_MOUNT) && target->mount) && (IS_SET (target->mount->act, ACT_ENFORCER) || IS_SET (target->mount->act, ACT_AGGRESSIVE)) && !target->fighting && !IS_SET (target->flags, FLAG_ENTERING) && !IS_SET (target->flags, FLAG_LEAVING) && !IS_SET (target->flags, FLAG_FLEE) ) { do_stand (target, "", 0); target->speed = 4; if ( (track (target, ch->in_room) == -1 && target->in_room != ch->in_room) || !(IS_SET (ch->act, ACT_ENFORCER) || IS_SET (ch->act, ACT_AGGRESSIVE)) || morale_broken (target) ) evade_attacker (target, -1); else charge_archer (target, ch); } } return; } void do_aim (CHAR_DATA *ch, char *argument, int cmd) { OBJ_DATA *bow = NULL; CHAR_DATA *target = NULL; CHAR_DATA *tch = NULL; ROOM_DATA *room = NULL; ROOM_DIRECTION_DATA *exit_room = NULL; char arg1 [MAX_STRING_LENGTH] = {'\0'}; char arg2 [MAX_STRING_LENGTH] = {'\0'}; char buf [MAX_STRING_LENGTH] = {'\0'}; char buffer [MAX_STRING_LENGTH] = {'\0'}; int ranged = 0; int dir = 0; char *temp_arg = NULL; char *temp_arg1 = NULL; if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( IS_SET (ch->room->room_flags, OOC) && IS_MORTAL (ch) ) { send_to_char ("You cannot do this in an OOC area.\n", ch); return; } if ( ch->delay_type == DEL_LOAD_WEAPON ) { return; } argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); if ( !*arg1 ) { send_to_char ("Usage: aim (<direction>) <target>\n", ch); return; } if ( !(bow = get_equip (ch, WEAR_BOTH)) || (bow->o.weapon.use_skill != SKILL_SHORTBOW && bow->o.weapon.use_skill != SKILL_LONGBOW && bow->o.weapon.use_skill != SKILL_CROSSBOW) ) { send_to_char ("You aren't wielding a ranged weapon.\n", ch); return; } if ( !bow->loaded ) { send_to_char ("Your weapon isn't loaded.\n", ch); return; } if ( (!cmp_strn ("east", arg1, strlen(arg1)) || !cmp_strn ("west", arg1, strlen(arg1)) || !cmp_strn ("north", arg1, strlen(arg1)) || !cmp_strn ("south", arg1, strlen(arg1)) || !cmp_strn ("up", arg1, strlen(arg1)) || !cmp_strn ("down", arg1, strlen(arg1))) && *arg2 ) ranged = 1; if ( !ranged ) { if ( !(target = get_char_room_vis (ch, arg1)) ) { send_to_char ("Who did you want to target?\n", ch); return; } if ( target == ch ) { send_to_char ("Now, now, now... things can't be THAT bad, can they?\n", ch); return; } temp_arg = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "You begin to carefully take aim at #5%s#0.", temp_arg); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); temp_arg = char_short(ch); temp_arg1 = char_short (target); snprintf (buf, MAX_STRING_LENGTH, "%s#0 begins to carefully take aim at #5%s#0 with #2%s#0.", temp_arg, temp_arg1, bow->short_description); *buf = toupper(*buf); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf); for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( tch == ch ) continue; if ( tch == target ) continue; if ( CAN_SEE (tch, ch) ) act (buffer, FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); } temp_arg = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "%s#0 begins to carefully take aim at you with #2%s#0!", temp_arg, bow->short_description); *buf = toupper(*buf); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf); if ( CAN_SEE (target, ch) ) act (buffer, FALSE, ch, 0, target, TO_VICT | TO_ACT_FORMAT); else if ( real_skill (target, SKILL_DANGER_SENSE) ) { if ( skill_use (target, SKILL_DANGER_SENSE, 0) ) send_to_char ("The back of your neck prickles, as if you are being watched closely.\n", target); } ch->aiming_at = target; target->targeted_by = ch; return; } else if ( ranged ) { if ( !cmp_strn ("north", arg1, strlen(arg1)) ) dir = 0; else if ( !cmp_strn ("east", arg1, strlen(arg1)) ) dir = 1; else if ( !cmp_strn ("south", arg1, strlen(arg1)) ) dir = 2; else if ( !cmp_strn("west", arg1, strlen(arg1)) ) dir = 3; else if ( !cmp_strn ("up", arg1, strlen(arg1)) ) dir = 4; else if ( !cmp_strn ("down", arg1, strlen(arg1)) ) dir = 5; if ( !PASSAGE(ch, dir)) { send_to_char ("There isn't an exit in that direction.\n", ch); return; } ch->delay_who = str_dup (dirs[dir]); room = vtor(PASSAGE(ch,dir)->to_room); exit_room = PASSAGE(ch, dir); if ( exit_room && IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } if ( IS_SET (room->room_flags, STIFLING_FOG) ) { send_to_char ("The stiflingly heavy fog in that area thwarts any such attempt.\n", ch); return; } if (!(target = get_char_room_vis2 (ch, room->virtual, arg2)) || !has_been_sighted (ch, target) ) { exit_room = room->dir_option[dir]; if ( !exit_room ) { send_to_char ("You don't see them within range.\n", ch); return; } if ( exit_room && IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } if ( room->dir_option[dir] ) room = vtor(room->dir_option[dir]->to_room); else room = NULL; if ( bow->o.od.value[1] == 3 || !room ) { /* Sling, eventually. */ send_to_char ("You don't see them within range.\n", ch); return; } if ( IS_SET (room->room_flags, STIFLING_FOG) ) { send_to_char ("The stiflingly heavy fog in that area thwarts any such attempt.\n", ch); return; } if (!(target = get_char_room_vis2 (ch, room->virtual, arg2)) || !has_been_sighted (ch, target) ) { exit_room = room->dir_option[dir]; if ( !exit_room ) { send_to_char ("You don't see them within range.\n", ch); return; } if ( exit_room && IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } if ( room->dir_option[dir] ) room = vtor(room->dir_option[dir]->to_room); else room = NULL; if ( bow->o.od.value[1] == 2 || !room ) { /* Crossbows and shortbows; two-room range. */ send_to_char ("You don't see them within range.\n", ch); return; } if ( IS_SET (room->room_flags, STIFLING_FOG) ) { send_to_char ("The stiflingly heavy fog in that area thwarts any such attempt.\n", ch); return; } if (!(target = get_char_room_vis2(ch, room->virtual, arg2)) || !has_been_sighted (ch, target) ) { exit_room = room->dir_option[dir]; if ( !exit_room ) { send_to_char ("You don't see them within range.\n", ch); return; } if ( IS_SET (exit_room->exit_info, PASSAGE_CLOSED) ) { send_to_char ("Your view is blocked.\n", ch); return; } send_to_char ("You don't see them within range.\n", ch); return; } else ch->delay_info1 = 3; } else ch->delay_info1 = 2; } if ( !target || !CAN_SEE (ch, target) || !has_been_sighted (ch, target) ) { send_to_char ("You don't see them within range.\n", ch); return; } if ( target == ch ) { send_to_char ("Now, now, now... things can't be THAT bad, can they?\n", ch); return; } temp_arg = char_short(target); snprintf (buf, MAX_STRING_LENGTH, "You begin to carefully take aim at #5%s#0.", temp_arg); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); temp_arg = char_short(ch); snprintf (buf, MAX_STRING_LENGTH, "%s#0 turns %sward, taking aim at a distant target with #2%s#0.", temp_arg, dirs[dir], bow->short_description); *buf = toupper(*buf); ch->ranged_enemy = target; snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf); for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( tch == ch ) continue; if ( tch == target ) continue; if ( CAN_SEE (tch, ch) ) act (buffer, FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); } if ( real_skill (target, SKILL_DANGER_SENSE) ) { if ( skill_use (target, SKILL_DANGER_SENSE, 0) ) send_to_char ("The back of your neck prickles, as if you are being watched closely.\n", target); } ch->aiming_at = target; target->targeted_by = ch; return; } return; } void do_unload (CHAR_DATA *ch, char *argument, int cmd) { OBJ_DATA *bow = NULL; OBJ_DATA *arrow = NULL; OBJ_DATA *quiver = NULL; int i = 0; char *error = NULL; char buf[MAX_STRING_LENGTH] = {'\0'}; char buffer[MAX_STRING_LENGTH] = {'\0'}; char *temp_arg1 = NULL; char *temp_arg2 = NULL; char *temp_arg3 = NULL; bow = get_bow (ch); if ( !bow ) { send_to_char ("What did you wish to unload?\n", ch); return; } if ( !bow->loaded ) { send_to_char ("That isn't loaded.\n", ch); return; } if ( !(arrow = bow->loaded) ) { send_to_char ("That isn't loaded.\n", ch); return; } temp_arg1 = char_short (ch); snprintf (buf, MAX_STRING_LENGTH, "%s#0 unloads #2%s#0.", temp_arg1, bow->short_description); *buf = toupper (*buf); snprintf (buffer, MAX_STRING_LENGTH, "#5%s", buf); act (buffer, FALSE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); arrow = load_object(bow->loaded->virtual); arrow->in_obj = NULL; arrow->carried_by = NULL; for ( i = 0; i < MAX_WEAR; i++ ) { if ( !(quiver = get_equip (ch, i)) ) continue; if ( GET_ITEM_TYPE (quiver) == ITEM_QUIVER && get_obj_in_list_num (arrow->virtual, quiver->contains) && can_obj_to_container (arrow, quiver, &error, 1) ) break; } if ( !quiver ) { for ( i = 0; i < MAX_WEAR; i++ ) { if ( !(quiver = get_equip (ch, i)) ) continue; if ( GET_ITEM_TYPE (quiver) == ITEM_QUIVER && can_obj_to_container (arrow, quiver, &error, 1) ) break; else quiver = NULL; } } if ( quiver ) { send_to_char ("\n", ch); temp_arg1 = obj_short_desc(bow); temp_arg2 = obj_short_desc(arrow); temp_arg3 = obj_short_desc(quiver); snprintf (buf, MAX_STRING_LENGTH, "You unload #2%s#0, and slide #2%s#0 into #2%s#0.", temp_arg1, temp_arg2, temp_arg3); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); obj_to_obj (arrow, quiver); } else if ( !quiver ) { temp_arg1 = obj_short_desc(bow); snprintf (buf, MAX_STRING_LENGTH, "You unload #2%s#0.\n", temp_arg1); send_to_char (buf, ch); obj_to_char (arrow, ch); } bow->loaded = NULL; return; } void delayed_load (CHAR_DATA *ch) { OBJ_DATA *bow = NULL; OBJ_DATA *ammo = NULL; OBJ_DATA *quiver = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; int i = 0; if ( !(bow = get_equip (ch, WEAR_BOTH)) ) { ch->delay_who = NULL; ch->delay = 0; ch->delay_type = 0; ch->delay_info1 = 0; ch->delay_info2 = 0; return; } if ( bow->o.weapon.use_skill != SKILL_SHORTBOW && bow->o.weapon.use_skill != SKILL_LONGBOW && bow->o.weapon.use_skill != SKILL_CROSSBOW ) { ch->delay_who = NULL; ch->delay = 0; ch->delay_type = 0; ch->delay_info1 = 0; ch->delay_info2 = 0; return; } ammo = NULL; for ( i = 0; i < MAX_WEAR; i++ ) { if ( !(quiver = get_equip (ch, i)) ) continue; if ( quiver->virtual != ch->delay_info1 || !get_obj_in_list_num (ch->delay_info2, quiver->contains) ) continue; if ( GET_ITEM_TYPE (quiver) == ITEM_QUIVER ) { for ( ammo = quiver->contains; ammo; ammo = ammo->next_content ){ if ( GET_ITEM_TYPE (ammo) == ITEM_MISSILE && ammo->virtual == ch->delay_info2 ){ break; } if ( ammo ) break; } } } if ( !ammo ) { send_to_char ("Having lost your ammunition, you cease loading your weapon.\n", ch); return; } snprintf (buf, MAX_STRING_LENGTH, "You finish loading #2%s#0.\n", bow->short_description); send_to_char (buf, ch); snprintf (buf, MAX_STRING_LENGTH, "$n finishes loading #2%s#0.", bow->short_description); act (buf, TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); bow->loaded = load_object(ammo->virtual); if ( IS_MORTAL(ch) ) obj_from_obj (&ammo, 1); ch->delay_who = NULL; ch->delay = 0; ch->delay_info1 = 0; ch->delay_info2 = 0; ch->delay_type = 0; return; } void do_hit (CHAR_DATA *ch, char *argument, int cmd) { CHAR_DATA *victim= NULL; CHAR_DATA *tch = NULL; OBJ_DATA *obj = NULL; int i = 0; int agi_diff=0; char buf [MAX_STRING_LENGTH] = {'\0'}; char original [MAX_STRING_LENGTH] = {'\0'}; snprintf (original, MAX_STRING_LENGTH, "%s", argument); /* cmd = 0 if hit, cmd = 1 if kill */ if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( IS_SET (ch->room->room_flags, OOC) && IS_MORTAL (ch) ) { send_to_char ("You cannot do this in an OOC area.\n", ch); return; } if ( is_room_affected (ch->room->affects, MAGIC_ROOM_CALM) ) { act ("Try as you might, you simply cannot muster the will to break " "the peace that pervades the area.", FALSE, ch, 0, 0, TO_CHAR); return; } if ( IS_SET (ch->flags, FLAG_PACIFIST) ) { send_to_char ("Remove your pacifist flag, first...\n", ch); return; } argument = one_argument (argument, buf); if ( (obj = get_equip (ch, WEAR_BOTH)) ) { if ( obj->o.weapon.use_skill == SKILL_LONGBOW || obj->o.weapon.use_skill == SKILL_SHORTBOW || obj->o.weapon.use_skill == SKILL_CROSSBOW || obj->o.weapon.use_skill == SKILL_SLING || obj->o.weapon.use_skill == SKILL_THROWN ) { send_to_char ("You can't use that in melee combat!\n", ch); return; } } if ( get_affect (ch, MAGIC_AFFECT_PARALYSIS) ) { send_to_char ("You are paralyzed and unable to fight!\n\r", ch); return; } if ( get_affect (ch, MAGIC_AFFECT_FEAR) ) { send_to_char ("You are too afraid to fight!\n\r", ch); return; } if ( IS_SUBDUER (ch) ) { act ("You can't attack while you have $N subdued.", FALSE, ch, 0, ch->subdue, TO_CHAR); return; } if ( IS_SET (ch->plr_flags, NEW_PLAYER_TAG) && IS_SET (ch->room->room_flags, LAWFUL) && *argument != '!' ) { snprintf (buf, MAX_STRING_LENGTH, "You are in a lawful area; you would likely be flagged wanted for assault. " "To confirm, type \'#6hit %s !#0\', without the quotes.", original); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); return; } if ( !*buf ) { if ( IS_SET (ch->flags, FLAG_FLEE) ) { send_to_char ("You stop trying to flee.\n\r", ch); REMOVE_BIT (ch->flags, FLAG_FLEE); return; } send_to_char ("Hit whom?\n\r", ch); return; } if ( !(victim = get_char_room_vis (ch, buf)) ) { send_to_char ("They aren't here.\n\r", ch); return; } if ( victim == ch ) { send_to_char ("You affectionately pat yourself.\n\r", ch); act ("$n affectionately pats $mself.", FALSE, ch, 0, victim, TO_ROOM); return; } if ( IS_SET (victim->act, ACT_PREY) && AWAKE (victim) ) { if ( !get_affect (ch, MAGIC_HIDDEN) || !skill_use (ch, SKILL_SNEAK, 0) ) { act ("As you approach, $N spots you and darts away! Try using a ranged weapon or an ambush from hiding instead.", FALSE, ch, 0, victim, TO_CHAR | TO_ACT_FORMAT); act ("As $n approaches, $N spots $m and darts away.", FALSE, ch, 0, victim, TO_ROOM | TO_ACT_FORMAT); evade_attacker (victim, -1); add_threat (victim, ch, 7); return; } else act ("You successfully ambush $N, leaping from your cover to attack!", FALSE, ch, 0, victim, TO_CHAR | TO_ACT_FORMAT); } if ( IS_SET (victim->act, ACT_FLYING) && !IS_SET (ch->act, ACT_FLYING) && AWAKE(victim) ) { send_to_char ("They are flying out of reach!\n", ch); return; } if ( IS_SET (victim->act, ACT_VEHICLE) ) { send_to_char ("How do you propose to kill an inanimate object, hmm?\n", ch); return; } for ( tch = vtor (ch->in_room)->people; tch; tch = tch->next_in_room ){ if (tch->fighting == victim) { if (++i >= 4) { act ("You can't find an opening to attack $N.", FALSE, ch, 0, victim, TO_CHAR); return; } } } REMOVE_BIT (ch->flags, FLAG_FLEE); REMOVE_BIT (ch->act, PLR_STOP); if ( GET_POS (ch) == POSITION_STANDING && !ch->fighting && victim != ch->fighting ) { if ( ch->delay && ch->delay_type != DEL_CAST ) break_delay (ch); ch->primary_delay = 0; ch->secondary_delay = 0; if ( cmd == 0 ) REMOVE_BIT (ch->flags, FLAG_KILL); else SET_BIT (ch->flags, FLAG_KILL); set_fighting (ch, victim); if ( !victim->fighting ) set_fighting (victim, ch); hit_char (ch, victim, 0); WAIT_STATE(ch, 9); if ( victim->deleted ) return; if ( IS_SET (victim->act, ACT_MEMORY) && IS_NPC (victim) ) add_memory (ch, victim); /* Looks like a problem. If you hit/kill in one hit, then trigger isn't called. */ trigger (ch, argument, TRIG_HIT); if ( ch->fighting == victim && IS_SUBDUEE (victim) ) stop_fighting (ch); } else if ( ch->fighting == victim && !IS_SET (ch->flags, FLAG_KILL) && AWAKE (ch) && cmd == 1 ) { act ("You will try to kill $N.", FALSE, ch, 0, victim, TO_CHAR); SET_BIT (ch->flags, FLAG_KILL); } else if ( ch->fighting == victim && IS_SET (ch->flags, FLAG_KILL) && AWAKE (ch) && cmd == 0 ) { act ("You will try NOT to kill $N.", FALSE, ch, 0, victim, TO_CHAR); REMOVE_BIT (ch->flags, FLAG_KILL); } else if ( ch->fighting && (GET_POS (ch) == FIGHT || GET_POS (ch) == STAND) && victim != ch->fighting ) { if ( ch->agi <= 9 ) ch->balance += -15; else if ( ch->agi > 9 && ch->agi <= 13 ) ch->balance += -13; else if ( ch->agi > 13 && ch->agi <= 15 ) ch->balance += -11; else if ( ch->agi > 15 && ch->agi <= 18 ) ch->balance += -9; else ch->balance += -7; ch->balance = MAX (ch->balance, -50); if ( ch->balance < -15 ) { act ("You need more balance before you can try to attack $N!",FALSE,ch,0,victim,TO_CHAR | TO_ACT_FORMAT); return; } if ( ch->fighting ) { if ( ch->fighting->fighting == ch ) { agi_diff = GET_AGI (ch) - GET_AGI (ch->fighting); if ( agi_diff > number(-10,10) && ( number(0,19) != 0 ) ) { act ("You fail to shift your attention away from $N.",FALSE,ch,0,ch->fighting,TO_CHAR | TO_ACT_FORMAT | TO_ACT_COMBAT); act ("$N fails to shift their attention away from you.",FALSE,ch->fighting,0,ch,TO_CHAR | TO_ACT_FORMAT | TO_ACT_COMBAT); act ("$N fails to shift their attention away from $n.", FALSE, ch->fighting, 0, ch, TO_NOTVICT | TO_ACT_FORMAT | TO_ACT_COMBAT); return; } } act ("You stop fighting $N.", FALSE, ch, 0, ch->fighting, TO_CHAR); act ("You ready yourself for battle with $N.", FALSE, ch, 0, victim, TO_CHAR); stop_fighting (ch); } if ( (is_area_enforcer (victim) || victim->race == RACE_WOLF) && IS_NPC (victim) ) do_alert (victim, "", 0); set_fighting (ch, victim); act ("You notice $N's attention shift toward you!", FALSE, victim, 0, ch, TO_CHAR); if ( cmd == 0 ) REMOVE_BIT (ch->flags, FLAG_KILL); else SET_BIT (ch->flags, FLAG_KILL); if ( IS_SET (victim->act, ACT_MEMORY) && IS_NPC (victim) ) add_memory (ch, victim); trigger (ch, argument, TRIG_HIT); } else send_to_char ("You're doing the best you can!\n\r", ch); return; } void do_nokill (CHAR_DATA *ch, char *argument, int cmd) { send_to_char ("Please spell out all of 'kill' to avoid any mistakes.\n", ch); return; } void do_kill (CHAR_DATA *ch, char *argument, int cmd) { char arg [MAX_STRING_LENGTH] = {'\0'}; char buf [MAX_STRING_LENGTH] = {'\0'}; char verify [MAX_STRING_LENGTH] = {'\0'}; char original [MAX_STRING_LENGTH] = {'\0'}; CHAR_DATA *victim = NULL; CHAR_DATA *tch = NULL; OBJ_DATA *obj = NULL; int i = 0; snprintf (original, MAX_STRING_LENGTH, "%s", argument); if ( IS_SWIMMING (ch) ) { send_to_char ("You can't do that while swimming!\n", ch); return; } if ( IS_NPC (ch) ) { do_hit (ch, argument, 1); return; } if ( IS_SET (ch->room->room_flags, OOC) && IS_MORTAL(ch) ) { send_to_char ("You cannot do this in an OOC area.\n", ch); return; } if ( IS_SET (ch->flags, FLAG_PACIFIST) ) { send_to_char ("Remove your pacifist flag, first...\n", ch); return; } if ( (obj = get_equip (ch, WEAR_BOTH)) ) { if ( obj->o.weapon.use_skill == SKILL_LONGBOW || obj->o.weapon.use_skill == SKILL_SHORTBOW || obj->o.weapon.use_skill == SKILL_CROSSBOW || obj->o.weapon.use_skill == SKILL_SLING || obj->o.weapon.use_skill == SKILL_THROWN ) { send_to_char ("You can't use that in melee combat!\n", ch); return; } } argument = one_argument (argument, arg); argument = one_argument (argument, verify); if ( !*arg ) { send_to_char ("Kill who?\n\r", ch); return; } if ( !(victim = get_char_room_vis (ch, arg)) ) { send_to_char ("They aren't here.\n\r", ch); return; } if ( ch == victim ) { send_to_char ("You slap yourself on the wrist.\n\r", ch); return; } if ( IS_SET (victim->act, ACT_PREY) && AWAKE (victim) ) { if ( !get_affect (ch, MAGIC_HIDDEN) || !skill_use (ch, SKILL_SNEAK, 0) ) { act ("As you approach, $N spots you and darts away! Try using a ranged weapon or an ambush from hiding instead.", FALSE, ch, 0, victim, TO_CHAR | TO_ACT_FORMAT); act ("As $n approaches, $N spots $m and darts away.", FALSE, ch, 0, victim, TO_ROOM | TO_ACT_FORMAT); evade_attacker (victim, -1); add_threat (victim, ch, 7); return; } else act ("You successfully ambush $N, leaping from your cover to attack!", FALSE, ch, 0, victim, TO_CHAR | TO_ACT_FORMAT); } if ( IS_SET (victim->act, ACT_FLYING) && !IS_SET (ch->act, ACT_FLYING) && AWAKE(victim) ) { send_to_char ("They are flying out of reach!\n", ch); return; } if ( IS_SET (victim->act, ACT_VEHICLE) ) { send_to_char ("How do you propose to kill an inanimate object, hmm?\n", ch); return; } if ( IS_SET (ch->plr_flags, NEW_PLAYER_TAG) && IS_SET (ch->room->room_flags, LAWFUL) && *verify != '!' ) { snprintf (buf, MAX_STRING_LENGTH, "You are in a lawful area; you would likely be flagged wanted for assault. " "To confirm, type \'#6hit %s !#0\', without the quotes.", original); act (buf, FALSE, ch, 0, 0, TO_CHAR | TO_ACT_FORMAT); return; } i = 0; for ( tch = vtor (ch->in_room)->people; tch; tch = tch->next_in_room ){ if(tch->fighting == victim) { if(++i >= 4) { act ("You can't find an opening to attack $N.", FALSE, ch, 0, victim, TO_CHAR); return; } } } if ( (is_area_enforcer (victim) || victim->race == RACE_WOLF) && IS_NPC (victim) ) do_alert (victim, "", 0); if ( ch->fighting ) { ch->fighting = victim; act ("You will fight $N until $E is dead.", FALSE, ch, 0, victim, TO_CHAR); return; } if ( IS_NPC (ch) || !GET_TRUST (ch) ) { SET_BIT (ch->flags, FLAG_KILL); set_fighting (ch, victim); if ( !victim->fighting ) set_fighting (victim, ch); hit_char (ch, victim, 0); } else { if ( !IS_NPC (victim) && *verify != '!' ) { send_to_char ("Target is a player character. Please use " "'KILL <name> !' syntax if \n\ryou really mean it.'\n\r", ch); return; } if ( GET_TRUST (victim) > GET_TRUST (ch) ) { victim = ch; } act ("$n stares at you, narrowing $s eyes. Shortly thereafter, your heart obediently ceases to beat, and you feel death upon you...", FALSE, ch, 0, victim, TO_VICT | TO_ACT_FORMAT); act ("You narrow your eyes in concentration, and $N collapses, dead.", FALSE, ch, 0, victim, TO_CHAR | TO_ACT_FORMAT); act ("$n stares at $N, narrowing $s eyes. Suddenly, $N collapses, dead.", FALSE, ch, 0, victim, TO_NOTVICT | TO_ACT_FORMAT); die (victim); } return; } void do_order (CHAR_DATA *ch, char *argument, int cmd) { int everyone = 0; CHAR_DATA *victim = NULL; CHAR_DATA *next_in_room = NULL; CHAR_DATA *tch = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; char command [MAX_STRING_LENGTH] = {'\0'}; char *temp_arg = NULL; argument = one_argument (argument, buf); if ( !*buf ) { send_to_char ("Order whom?\n\r", ch); return; } /* We can order invis chars as well, why not :) */ if ( !str_cmp (buf, "all") || !str_cmp (buf, "follower") || !str_cmp (buf, "followers") ) everyone = 1; else if ( !(victim = get_char_room_vis (ch, buf)) && !(victim = get_char_room (buf, ch->in_room)) ) { send_to_char ("They aren't here.\n\r", ch); return; } while ( isspace (*argument) ) argument++; if ( !*argument ) { send_to_char ("What is your order?\n\r", ch); return; } strcpy (command, argument); if ( victim == ch ) { send_to_char ("You don't have to give yourself orders.\n\r", ch); return; } if ( victim ) { if ( !is_leader (ch, victim) && victim->following != ch ) { act ("You do not have the authority to order $N.", FALSE, ch, 0, victim, TO_CHAR); return; } temp_arg = char_short (ch); snprintf (buf, MAX_STRING_LENGTH, "#5%s#0 orders you to '%s'.\n", temp_arg, command); buf [2] = toupper (buf [2]); send_to_char (buf, victim); if ( victim->mob ) { send_to_char ("Ok.\n", ch); command_interpreter (victim, command); } else { temp_arg = char_short (victim); snprintf (buf, MAX_STRING_LENGTH, "You order #5%s#0 to '%s'.\n", temp_arg, command); send_to_char (buf, ch); } return; } for ( tch = ch->room->people; tch; tch = next_in_room ) { next_in_room = tch->next_in_room; if ( !is_leader (ch, tch) && (tch->following != ch) ) continue; temp_arg = char_short (ch); snprintf (buf, MAX_STRING_LENGTH, "#5%s#0 orders you to '%s'.\n", temp_arg, command); buf [2] = toupper (buf [2]); send_to_char (buf, tch); if ( tch->mob ) command_interpreter (tch, command); } send_to_char ("Ok.\n", ch); return; } void do_flee (CHAR_DATA *ch, char *argument, int cmd) { int dir; if ( !ch->fighting ) { send_to_char ("You're not fighting.\n\r", ch); return; } if ( get_affect (ch, MAGIC_AFFECT_PARALYSIS) ) { send_to_char ("You are paralyzed and unable to flee!\n\r", ch); return; } if ( IS_SET (ch->flags, FLAG_FLEE) ) { send_to_char ("You are already trying to escape!\n\r", ch); return; } for ( dir = 0; dir < 6; dir++ ) if ( CAN_GO (ch, dir) && !IsGuarded (ch->room, dir) ) break; if ( dir == 6 ) { send_to_char ("THERE IS NOWHERE TO FLEE!!\n\r", ch); return; } SET_BIT (ch->flags, FLAG_FLEE); send_to_char ("You resolve to escape combat. . .\n\r", ch); act ("$n's eyes dart about looking for an escape path!", FALSE, ch, 0, 0, TO_ROOM); return; } int flee_attempt (CHAR_DATA *ch) { int dir = 0; int enemies = 0; int mobless_count = 0; int mobbed_count = 0; int mobless_dirs [6]; int mobbed_dirs [6]; CHAR_DATA *tch = NULL; char buf [MAX_STRING_LENGTH] = {'\0'}; ROOM_DATA *troom = NULL; /* if ( IS_SET (ch->flags, FLAG_SUBDUING) ) { REMOVE_BIT (ch->flags, FLAG_FLEE); return 0; } */ if ( GET_POS (ch) < FIGHT ) return 0; for ( tch = ch->room->people; tch; tch = tch->next_in_room ) { if ( tch->fighting != ch ) continue; if ( GET_POS (tch) != FIGHT && GET_POS (tch) != STAND ) continue; if ( !CAN_SEE (tch, ch) ) continue; enemies++; } for ( dir = 0; dir < 6; dir++ ) { if ( !CAN_GO (ch, dir) ) continue; if ( vtor (PASSAGE (ch, dir)->to_room)->people ) mobbed_dirs [mobbed_count++] = dir; else mobless_dirs [mobless_count++] = dir; } if ( !mobbed_count && !mobless_count ) { send_to_char ("There is nowhere to go! You continue fighting!\n\r", ch); REMOVE_BIT (ch->flags, FLAG_FLEE); return 0; } if ( enemies && number (0, enemies) ) { switch (number (1, 3)) { case 1: send_to_char ("You attempt escape, but fail . . .\n\r", ch); break; case 2: send_to_char ("You nearly escape, but are blocked . . .\n\r", ch); break; case 3: send_to_char ("You continue seeking escape . . .\n\r", ch); break; } act ("$n nearly flees!", TRUE, ch, 0, 0, TO_ROOM); return 0; } if ( mobless_count ) dir = mobless_dirs [number (0, mobless_count - 1)]; else dir = mobbed_dirs [number (0, mobbed_count - 1)]; troom = ch->room; /* stop_fighting_sounds (ch, troom); */ if ( ch->fighting ) { stop_fighting (ch); } do_move (ch, "", dir); act ("$n #3flees!#0", FALSE, ch, 0, 0, TO_ROOM); snprintf (buf, MAX_STRING_LENGTH, "#3YOU FLEE %s!#0", dirs [dir]); act (buf, FALSE, ch, 0, 0, TO_CHAR); if ( !enemies ) snprintf (buf, MAX_STRING_LENGTH, "\nYou easily escaped to the %s.\n\r", dirs [dir]); else snprintf (buf, MAX_STRING_LENGTH, "\nYou barely escaped to the %s.\n\r", dirs [dir]); if ( ch->room != troom ) send_to_char (buf, ch); REMOVE_BIT (ch->flags, FLAG_FLEE); return 1; } /* In case victim is being guarded, make sure rescue affects are active. */ void guard_check (CHAR_DATA *victim) { CHAR_DATA *tch; AFFECTED_TYPE *af; for ( tch = victim->room->people; tch; tch = tch->next_in_room ) { if ( !(af = get_affect (tch, MAGIC_GUARD)) ) continue; if ( (CHAR_DATA *) af->a.spell.t == victim && !get_second_affect (tch, SPA_RESCUE, NULL) ) add_second_affect (SPA_RESCUE, 1, tch, (OBJ_DATA *) victim, NULL, 0); } return; } void do_guard (CHAR_DATA *ch, char *argument, int cmd) { CHAR_DATA *target = NULL; CHAR_DATA *tch = NULL; AFFECTED_TYPE *af; char buf [MAX_STRING_LENGTH] = {'\0'}; int dir; if ( IS_SET (ch->room->room_flags, OOC) ) { send_to_char ("That command cannot be used in an OOC area.\n", ch); return; } if ( (af = get_affect (ch, AFFECT_GUARD_DIR)) ) affect_remove (ch, af); argument = one_argument (argument, buf); if ( *buf && !(target = get_char_room_vis (ch, buf)) ) { if ( (dir = index_lookup (dirs, buf)) == -1 ) { send_to_char ("Who or what did you want to guard?\n", ch); return; } if ( !(af = get_affect (ch, AFFECT_GUARD_DIR)) ) magic_add_affect (ch, AFFECT_GUARD_DIR, -1, 0, 0, 0, 0); af = get_affect (ch, AFFECT_GUARD_DIR); af->a.shadow.shadow = NULL; af->a.shadow.edge = dir; snprintf (buf, MAX_STRING_LENGTH, "You will now guard the %s exit.\n", dirs[dir]); send_to_char (buf, ch); snprintf (buf, MAX_STRING_LENGTH, "$n moves to block the %s exit.", dirs[dir]); act (buf, TRUE, ch, 0, 0, TO_ROOM | TO_ACT_FORMAT); return; } if ( (!*buf || target == ch) ) { if ( !(af = get_affect (ch, MAGIC_GUARD)) && !(af = get_affect (ch, AFFECT_GUARD_DIR)) ) { send_to_char ("You are not currently guarding anything.\n", ch); return; } else if ( (af = get_affect (ch, MAGIC_GUARD)) && (tch = (CHAR_DATA *)af->a.spell.t) != NULL ) { act ("You cease guarding $N.", TRUE, ch, 0, tch, TO_CHAR | TO_ACT_FORMAT); act ("$n ceases guarding you.", FALSE, ch, 0, tch, TO_VICT | TO_ACT_FORMAT); act ("$n ceases guarding $N.", FALSE, ch, 0, tch, TO_NOTVICT | TO_ACT_FORMAT); remove_affect_type (ch, MAGIC_GUARD); return; } else if ( (af = get_affect (ch, AFFECT_GUARD_DIR)) ) { act ("You cease guarding the exit.", TRUE, ch, 0, 0, TO_CHAR); remove_affect_type (ch, AFFECT_GUARD_DIR); return; } else { send_to_char ("You cease guarding.\n", ch); remove_affect_type (ch, MAGIC_GUARD); remove_affect_type (ch, AFFECT_GUARD_DIR); return; } } if ( get_affect (target, MAGIC_GUARD) || get_affect (target, AFFECT_GUARD_DIR) ) { send_to_char ("They're already trying to guard something themselves!\n", ch); return; } if ( (af = get_affect (ch, MAGIC_GUARD)) ) affect_remove (ch, af); magic_add_affect (ch, MAGIC_GUARD, -1, 0, 0, 0, 0); if ( !(af = get_affect (ch, MAGIC_GUARD)) ) { send_to_char ("There is a bug in guard. Please let an admin " "know.\n", ch); return; } af->a.spell.t = (int) target; act ("You will now guard $N.", FALSE, ch, 0, target, TO_CHAR | TO_ACT_FORMAT); act ("$n moves into position to guard you.", FALSE, ch, 0, target, TO_VICT | TO_ACT_FORMAT); act ("$n moves into position to guard $N.", FALSE, ch, 0, target, TO_NOTVICT | TO_ACT_FORMAT); return; }