/*************************************************************************
* File: fight.c Part of CircleMUD *
* Usage: Combat system *
* *
* All rights reserved. See license.doc for complete information. *
* *
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. *
************************************************************************ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "structs.h"
#include "awake.h"
#include "utils.h"
#include "comm.h"
#include "handler.h"
#include "interpreter.h"
#include "db.h"
#include "spells.h"
#include "screen.h"
#include "newmagic.h"
/* Structures */
struct char_data *combat_list = NULL; /* head of l-list of fighting chars */
struct char_data *next_combat_list = NULL;
/* External structures */
extern struct char_data *character_list;
extern struct obj_data *obj_proto;
extern struct room_data *world;
extern struct message_list fight_messages[MAX_MESSAGES];
extern int pk_allowed; /* see config.c */
extern int auto_save; /* see config.c */
extern int max_exp_gain; /* see config.c */
extern int top_of_world;
extern int material_ratings[];
extern char *dirs[];
extern int rev_dir[];
int find_sight(struct char_data *ch);
void damage_door(struct char_data *ch, int room, int dir, int power, int type);
void damage_obj(struct char_data *ch, struct obj_data *obj, int power, int type);
/* External procedures */
char *fread_action(FILE * fl, int nr);
char *fread_string(FILE * fl, char *error);
void stop_follower(struct char_data * ch);
ACMD(do_flee);
void hit(struct char_data * ch, struct char_data * victim, int type);
void docwagon(struct char_data *ch);
void range_combat(struct char_data *ch, char target[MAX_INPUT_LENGTH],
struct obj_data *weapon, int range, int dir);
void roll_individual_initiative(struct char_data *ch);
void ranged_response(struct char_data *ch, struct char_data *vict);
int find_weapon_range(struct char_data *ch, struct obj_data *weapon);
void weapon_scatter(struct char_data *ch, struct char_data *victim,
struct obj_data *weapon);
void explode(struct char_data *ch, struct obj_data *weapon, int room);
void target_explode(struct char_data *ch, struct obj_data *weapon,
int room, int mode);
void forget(struct char_data * ch, struct char_data * victim);
void remember(struct char_data * ch, struct char_data * victim);
int ok_damage_shopkeeper(struct char_data * ch, struct char_data * victim);
extern int success_test(int number, int target);
extern int resisted_test(int num_for_ch, int tar_for_ch, int num_for_vict,
int tar_for_vict);
extern int modify_target(struct char_data *ch);
extern int is_allergic(struct char_data *ch, int type);
extern int skill_web (struct char_data *ch, int skillnumber);
extern bool mob_magic(struct char_data * mob);
extern int reverse_web(struct char_data *, int &, int &);
extern bool attempt_reload(struct char_data *mob, int pos);
extern void Crash_rentsave(struct char_data *ch, int cost);
extern void switch_weapons(struct char_data *mob, int pos);
extern void hunt_victim(struct char_data * ch);
extern void matrix_fight(struct char_data *ch, struct char_data *victim);
extern void check_quest_kill(struct char_data *ch, struct char_data *victim);
extern void check_quest_destroy(struct char_data *ch, struct obj_data *obj);
extern void purge_spell_q(struct char_data *ch);
extern bool cycle_spell_q(struct char_data *ch);
extern int return_general(int);
extern struct index_data *obj_index;
extern struct index_data *mob_index;
extern struct zone_data *zone_table;
/* Weapon attack texts */
struct attack_hit_type attack_hit_text[] =
{
{"hit", "hits", "hit"}, /* 0 */
{"sting", "stings", "sting"},
{"whip", "whips", "whip"},
{"slash", "slashes", "slash"},
{"bite", "bites", "bite"},
{"bludgeon", "bludgeons", "bludgeon"}, /* 5 */
{"crush", "crushes", "crush"},
{"pound", "pounds", "pound"},
{"claw", "claws", "claw"},
{"maul", "mauls", "maul"},
{"thrash", "thrashes", "thrash"}, /* 10 */
{"pierce", "pierces", "pierce"},
{"punch", "punches", "punch"},
{"stab", "stabs", "stab"},
{"shock", "shocks", "shock"},
{"shuriken", "shurikens", "shuriken"}, /* 15 */
{"pierce", "pierces", "pierce"},
{"pierce", "pierces", "pierce"},
{"grenade", "grenades", "grenade"},
{"grenade", "grenades", "grenade"},
{"rocket", "rockets", "rocket"}, /* 20 */
{"shoot", "shoots", "shot"},
{"blast", "blasts", "blast"},
{"shoot", "shoots", "shot"},
{"blast", "blasts", "blast"},
{"blast", "blasts", "burst fire"}, /* 25 */
{"blast", "blasts", "blast"},
{"bifurcate", "bifurcates", "BIFURCATION"}
};
void set_attacking(struct char_data *ch, struct char_data *vict, const char *file, int line)
{
//ch->char_specials.fightList.ADD(vict);
//vict->char_specials.defendList.ADD(ch);
}
/* The Fight related routines */
void appear(struct char_data * ch)
{
if (affected_by_spell(ch, SPELL_INVISIBILITY) == 1)
affect_from_char(ch, SPELL_INVISIBILITY);
if (affected_by_spell(ch, SPELL_IMPROVED_INVIS) == 1)
affect_from_char(ch, SPELL_IMPROVED_INVIS);
REMOVE_BIT(AFF_FLAGS(ch), AFF_IMP_INVIS | AFF_INVISIBLE | AFF_HIDE);
if (GET_LEVEL(ch) < LVL_LEGEND)
act("$n slowly fades into existence.", FALSE, ch, 0, 0, TO_ROOM);
else act("You feel a strange presence as $n appears, seemingly from nowhere.",
FALSE, ch, 0, 0, TO_ROOM);
}
void load_messages(void)
{
FILE *fl;
int i, type;
struct message_type *messages;
char chk[128];
if (!(fl = fopen(MESS_FILE, "r"))) {
sprintf(buf2, "Error reading combat message file %s", MESS_FILE);
perror(buf2);
exit(1);
}
for (i = 0; i < MAX_MESSAGES; i++) {
fight_messages[i].a_type = 0;
fight_messages[i].number_of_attacks = 0;
fight_messages[i].msg = 0;
}
fgets(chk, 128, fl);
while (!feof(fl) && (*chk == '\n' || *chk == '*'))
fgets(chk, 128, fl);
while (*chk == 'M') {
fgets(chk, 128, fl);
sscanf(chk, " %d\n", &type);
for (i = 0; (i < MAX_MESSAGES) && (fight_messages[i].a_type != type) &&
(fight_messages[i].a_type); i++);
if (i >= MAX_MESSAGES) {
fprintf(stderr, "Too many combat messages. Increase MAX_MESSAGES and recompile.");
exit(1);
}
messages = new message_type;
fight_messages[i].number_of_attacks++;
fight_messages[i].a_type = type;
messages->next = fight_messages[i].msg;
fight_messages[i].msg = messages;
messages->die_msg.attacker_msg = fread_action(fl, i);
messages->die_msg.victim_msg = fread_action(fl, i);
messages->die_msg.room_msg = fread_action(fl, i);
messages->miss_msg.attacker_msg = fread_action(fl, i);
messages->miss_msg.victim_msg = fread_action(fl, i);
messages->miss_msg.room_msg = fread_action(fl, i);
messages->hit_msg.attacker_msg = fread_action(fl, i);
messages->hit_msg.victim_msg = fread_action(fl, i);
messages->hit_msg.room_msg = fread_action(fl, i);
messages->god_msg.attacker_msg = fread_action(fl, i);
messages->god_msg.victim_msg = fread_action(fl, i);
messages->god_msg.room_msg = fread_action(fl, i);
fgets(chk, 128, fl);
while (!feof(fl) && (*chk == '\n' || *chk == '*'))
fgets(chk, 128, fl);
}
fclose(fl);
}
void update_pos(struct char_data * victim)
{
if (IS_IC(victim) && GET_MENTAL(victim) < -100) {
GET_MENTAL(victim) = GET_MAX_MENTAL(victim);
GET_POS(victim) = POS_STANDING;
return;
}
if ((GET_MENTAL(victim) < 100) && (GET_PHYSICAL(victim) >= 100)) {
GET_POS(victim) = POS_STUNNED;
GET_INIT_ROLL(victim) = 0;
return;
}
if ((GET_PHYSICAL(victim) >= 100) && (GET_POS(victim) > POS_STUNNED))
return;
else if (GET_PHYSICAL(victim) >= 100) {
GET_POS(victim) = POS_STANDING;
return;
} else if ((int)(GET_PHYSICAL(victim) / 100) <= -GET_BOD(victim))
GET_POS(victim) = POS_DEAD;
else
GET_POS(victim) = POS_MORTALLYW;
GET_INIT_ROLL(victim) = 0;
}
void check_killer(struct char_data * ch, struct char_data * vict)
{
if (!IS_NPC(ch) && !IS_NPC(vict) && !PLR_FLAGGED(vict, PLR_KILLER) &&
!PLR_FLAGGED(vict, PLR_THIEF) && (!PRF_FLAGGED(ch, PRF_PKER) ||
!PRF_FLAGGED(vict, PRF_PKER)) && !PLR_FLAGGED(ch, PLR_KILLER) && (ch != vict)) {
char buf[256];
SET_BIT(PLR_FLAGS(ch), PLR_KILLER);
sprintf(buf, "PC Killer bit set on %s for initiating attack on %s at %s.",
GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name);
mudlog(buf, ch, LOG_MISCLOG, TRUE);
send_to_char("If you want to be a PLAYER KILLER, so be it...\r\n", ch);
}
else if ( (IS_NPC(ch) && ch->desc != NULL && ch->desc->original != NULL) )
{
if (!PLR_FLAGGED(vict, PLR_KILLER) &&
!PLR_FLAGGED(vict, PLR_THIEF) && (!PRF_FLAGGED(ch->desc->original, PRF_PKER) ||
!PRF_FLAGGED(vict, PRF_PKER)) && !PLR_FLAGGED(ch->desc->original, PLR_KILLER)
&& (ch->desc->original != vict))
{
if ( IS_NPC(vict) && vict->desc == NULL )
return;
else if ( IS_NPC(vict) && vict->desc != NULL && vict->desc->original != NULL )
{
if (!PLR_FLAGGED(vict->desc->original, PLR_KILLER) &&
!PLR_FLAGGED(vict->desc->original, PLR_THIEF) && (!PRF_FLAGGED(ch->desc->original, PRF_PKER) ||
!PRF_FLAGGED(vict->desc->original, PRF_PKER)) && !PLR_FLAGGED(ch->desc->original, PLR_KILLER)
&& (ch->desc->original != vict->desc->original))
;
else
return;
}
char buf[256];
SET_BIT(PLR_FLAGS(ch->desc->original), PLR_KILLER);
sprintf(buf, "PC Killer bit set on %s (while in %s) for initiating attack on %s at %s.",
GET_NAME(ch->desc->original), ch->player.short_descr, GET_NAME(vict), world[vict->in_room].name);
mudlog(buf, ch, LOG_MISCLOG, TRUE);
send_to_char("If you want to be a PLAYER KILLER, so be it...\r\n", ch);
}
}
}
/* start one char fighting another (yes, it is horrible, I know... ) */
void set_fighting(struct char_data * ch, struct char_data * vict)
{
if (ch == vict)
return;
assert(!FIGHTING(ch));
ch->next_fighting = combat_list;
combat_list = ch;
if (IS_AFFECTED(ch, AFF_SLEEP))
REMOVE_BIT(AFF_FLAGS(ch), AFF_SLEEP);
roll_individual_initiative(ch);
FIGHTING(ch) = vict;
GET_POS(ch) = POS_FIGHTING;
if (!pk_allowed)
check_killer(ch, vict);
}
/* remove a char from the list of fighting chars */
void stop_fighting(struct char_data * ch)
{
struct char_data *temp;
if (ch == next_combat_list)
next_combat_list = ch->next_fighting;
REMOVE_FROM_LIST(ch, combat_list, next_fighting);
ch->next_fighting = NULL;
FIGHTING(ch) = NULL;
GET_POS(ch) = POS_STANDING;
update_pos(ch);
purge_spell_q(ch);
GET_INIT_ROLL(ch) = 0;
}
void make_corpse(struct char_data * ch)
{
extern int max_npc_corpse_time, max_pc_corpse_time;
struct obj_data *create_nuyen(int amount);
struct obj_data *create_credstick(struct char_data *ch, int amount);
struct obj_data *corpse, *o, *obj;
struct obj_data *money;
int i, nuyen, credits, counter;
corpse = create_obj();
corpse->item_number = NOTHING;
corpse->in_room = NOWHERE;
sprintf(buf2, "corpse %s", ch->player.name);
corpse->name = str_dup(buf2);
sprintf(buf2, "^rThe corpse of %s is lying here.^n", GET_NAME(ch));
corpse->description = str_dup(buf2);
sprintf(buf2, "^rthe corpse of %s^n", GET_NAME(ch));
corpse->short_description = str_dup(buf2);
GET_OBJ_TYPE(corpse) = ITEM_CONTAINER;
GET_OBJ_WEAR(corpse) = ITEM_WEAR_TAKE;
GET_OBJ_EXTRA(corpse) = (ITEM_NODONATE | ITEM_CORPSE);
GET_OBJ_VAL(corpse, 0) = 0; /* You can't store stuff in a corpse */
GET_OBJ_VAL(corpse, 4) = 1; /* corpse identifier */
GET_OBJ_WEIGHT(corpse) = MAX(100, GET_WEIGHT(ch)) + IS_CARRYING_W(ch);
if (IS_NPC(ch)) {
GET_OBJ_TIMER(corpse) = max_npc_corpse_time;
GET_OBJ_VAL(corpse, 4) = 0;
GET_OBJ_VAL(corpse, 5) = ch->nr;
} else {
GET_OBJ_TIMER(corpse) = max_pc_corpse_time;
GET_OBJ_VAL(corpse, 4) = 1;
GET_OBJ_VAL(corpse, 5) = GET_IDNUM(ch);
/* make 'em bullet proof...(anti-twink measure) */
GET_OBJ_BARRIER(corpse) = 75;
}
/* transfer character's inventory to the corpse */
for (o = ch->carrying; o; o = obj) {
obj = o->next_content;
obj_from_char(o);
obj_to_obj(o, corpse);
}
/* transfer character's equipment to the corpse */
for (i = 0; i < NUM_WEARS; i++)
if (ch->equipment[i])
obj_to_obj(unequip_char(ch, i), corpse);
/* transfer nuyen & credstick */
if (IS_NPC(ch)) {
nuyen = (int)(GET_NUYEN(ch) / 10);
nuyen = number(GET_NUYEN(ch) - nuyen, GET_NUYEN(ch) + nuyen);
credits = (int)(GET_BANK(ch) / 10);
credits = number(GET_BANK(ch) - credits, GET_BANK(ch) + credits);
} else {
nuyen = GET_NUYEN(ch);
credits = 0;
}
if (IS_NPC(ch) && (nuyen > 0 || credits > 0))
if (from_ip_zone(GET_MOB_VNUM(ch))) {
nuyen = 0;
credits = 0;
}
if (nuyen > 0) {
/* following 'if' clause added to fix gold duplication loophole */
if (IS_NPC(ch) || (!IS_NPC(ch) && ch->desc)) {
money = create_nuyen(nuyen);
obj_to_obj(money, corpse);
}
GET_NUYEN(ch) = 0;
}
if (credits > 0) {
money = create_credstick(ch, credits);
obj_to_obj(money, corpse);
}
ch->carrying = NULL;
IS_CARRYING_N(ch) = 0;
IS_CARRYING_W(ch) = 0;
obj_to_room(corpse, ch->in_room);
}
/* When ch kills victim */
void change_alignment(struct char_data * ch, struct char_data * victim)
{
/*
* new alignment change algorithm: if you kill a monster with alignment A,
* you move 1/16th of the way to having alignment -A. Simple and fast.
*/
GET_ALIGNMENT(ch) += (-GET_ALIGNMENT(victim) - GET_ALIGNMENT(ch)) >> 4;
}
void death_cry(struct char_data * ch)
{
int door, was_in;
act("$n cries out $s last breath as $e dies!", FALSE, ch, 0, 0, TO_ROOM);
was_in = ch->in_room;
for (door = 0; door < NUM_OF_DIRS; door++) {
if (CAN_GO(ch, door)) {
ch->in_room = world[was_in].dir_option[door]->to_room;
act("Somewhere close, you hear someone's death cry!", FALSE, ch, 0, 0, TO_ROOM);
ch->in_room = was_in;
}
}
}
void raw_kill(struct char_data * ch)
{
struct obj_data *bio, *obj, *o;
int i;
if (FIGHTING(ch))
stop_fighting(ch);
while (ch->affected)
affect_remove(ch, ch->affected, 0);
if (IS_ASTRAL(ch)) {
act("$n vanishes.", FALSE, ch, 0, 0, TO_ROOM);
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i))
extract_obj(GET_EQ(ch, i));
for (obj = ch->carrying; obj; obj = o) {
o = obj->next_content;
extract_obj(obj);
}
} else {
death_cry(ch);
if (!(IS_SPIRIT(ch) && GET_MOB_VNUM(ch) >= 25 && GET_MOB_VNUM(ch) <= 42))
make_corpse(ch);
if (!IS_NPC(ch)) {
for (bio = ch->bioware; bio; bio = bio->next_content)
if (!GET_OBJ_VAL(bio, 2)) {
GET_OBJ_VAL(bio, 5) = 12;
GET_OBJ_VAL(bio, 6) = 0;
} else if (GET_OBJ_VAL(bio, 2) == 4) {
if (GET_OBJ_VAL(bio, 5) > 0)
for (i = 0; i < MAX_OBJ_AFFECT; i++)
affect_modify(ch, bio->affected[i].location, bio->affected[i].modifier,
bio->obj_flags.bitvector, FALSE);
GET_OBJ_VAL(bio, 5) = 0;
}
Crash_rentsave(ch, 0);
SET_BIT(PLR_FLAGS(ch), PLR_JUST_DIED);
}
}
extract_char(ch);
}
void death_penalty(struct char_data *ch, int is_death_trap)
{
if (!IS_NPC(ch)
&& ch->real_abils.bod > 1
&& !PLR_FLAGGED(ch, PLR_NEWBIE)
&& !success_test(MAX((int)(ch->real_abils.ess / 100), 1),
7 - (int)(GET_ESS(ch) / 100))) {
GET_REP(ch) -= ch->real_abils.bod;
ch->real_abils.bod--;
GET_INDEX(ch) -= 100;
} else gain_exp(ch, -(ch->real_abils.bod * 100));
}
void die(struct char_data * ch)
{
if (!IS_NPC(ch)) {
death_penalty(ch, 0);
/* REMOVE_BIT(PLR_FLAGS(ch), PLR_KILLER | PLR_THIEF); */
}
raw_kill(ch);
}
int calc_karma(struct char_data *ch, struct char_data *vict)
{
int base = 0, i, counter;
struct spell_data *spell;
char rbuf[MAX_STRING_LENGTH];
if (!vict)
return 0;
base = (int)((1.5 * (vict->real_abils.bod + GET_BALLISTIC(vict) + GET_IMPACT(vict))) +
(vict->real_abils.qui + (int)(vict->real_abils.mag / 100) +
vict->real_abils.str + vict->real_abils.wil + vict->real_abils.rea));
for (i = MAX_SPELLS + 1; i <= MAX_SKILLS; i++)
if (GET_SKILL(vict, i) > 0) {
if (i == SKILL_SORCERY && GET_MAG(vict) > 0)
base += (int)(1.15 * GET_SKILL(vict, i));
else if (return_general(i) == SKILL_FIREARMS ||
return_general(i) == SKILL_UNARMED_COMBAT ||
return_general(i) == SKILL_ARMED_COMBAT ||
i == SKILL_KILL_HANDS)
base += (int)(1.4 * GET_SKILL(vict, i));
else if (i > SKILL_PERCEPTION)
base += (int)(1.10 * GET_SKILL(vict, i));
}
if (MOB_FLAGGED(vict, MOB_GUARD))
base = (int)(base * 1.1);
if (MOB_FLAGGED(vict, MOB_NOBLIND))
base = (int)(base * 1.05);
if (MOB_FLAGGED(vict, MOB_IMMEXPLODE))
base = (int)(base * 1.05);
if (IS_NPC(vict) && GET_RACE(vict) == CLASS_SPIRIT)
base = (int)(base * 1.15);
if (ch && !IS_NPC(ch)) {
if (PLR_FLAGGED(ch, PLR_NEWBIE))
base -= (int)(GET_REP(ch) / 5);
else
base -= (int)(GET_REP(ch) / 2);
}
if (IS_NPC(vict))
base += GET_KARMA(vict);
else if (ch)
base += (int)(GET_REP(ch) / 4);
//now to randomize it a bit
base += (!ch ? 0 : (!number(0,2) ? number(0,5) :
0 - number(0,5)));
base = (ch ? MIN(max_exp_gain, base) : base);
base = MAX(base, 1);
if (ch && !IS_NPC(ch) && GET_LEVEL(ch) < LVL_LEGEND && IS_NPC(vict))
if (from_ip_zone(GET_MOB_VNUM(vict)))
base = 0;
return base;
}
void perform_group_gain(struct char_data * ch, int base, struct char_data * victim)
{
int share;
share = MIN(max_exp_gain, MAX(1, base));
if (!IS_NPC(ch))
share = MIN(base, (PLR_FLAGGED(ch, PLR_NEWBIE) ? 20 : GET_REP(ch) * 2));
/* psuedo-fix of the group with a newbie to get more exp exploit */
if ( !PLR_FLAGGED(ch, PLR_NEWBIE) )
share /= 2;
share = gain_exp(ch, share);
send_to_char(ch, "You receive your share of %0.2f karma.\r\n", ((float)share / 100));
change_alignment(ch, victim);
}
void group_gain(struct char_data * ch, struct char_data * victim)
{
int tot_members, base;
struct char_data *k;
struct follow_type *f;
if (!(k = ch->master))
k = ch;
if (IS_AFFECTED(k, AFF_GROUP) && (k->in_room == ch->in_room))
tot_members = 1;
else
tot_members = 0;
for (f = k->followers; f; f = f->next)
if (IS_AFFECTED(f->follower, AFF_GROUP)
&& f->follower->in_room == ch->in_room)
tot_members++;
base = calc_karma(k, victim);
if (tot_members >= 1)
base = MAX(1, (base / tot_members));
else base = 0;
if (IS_AFFECTED(k, AFF_GROUP) && k->in_room == ch->in_room)
perform_group_gain(k, base, victim);
for (f = k->followers; f; f = f->next)
if (IS_AFFECTED(f->follower, AFF_GROUP) && f->follower->in_room == ch->in_room)
perform_group_gain(f->follower, base, victim);
}
char *replace_string(char *str, char *weapon_singular, char *weapon_plural,
char *weapon_different)
{
static char buf[256];
char *cp;
cp = buf;
for (; *str; str++) {
if (*str == '#') {
switch (*(++str)) {
case 'W':
for (; *weapon_plural; *(cp++) = *(weapon_plural++));
break;
case 'w':
for (; *weapon_singular; *(cp++) = *(weapon_singular++));
break;
case 'd':
for (; *weapon_different; *(cp++) = *(weapon_different++));
break;
default:
*(cp++) = '#';
break;
}
} else
*(cp++) = *str;
*cp = 0;
} /* For */
return (buf);
}
#define SENDOK(ch) ((ch)->desc && AWAKE(ch) && !(PLR_FLAGGED((ch), PLR_WRITING) || PLR_FLAGGED((ch), PLR_EDITING) || PLR_FLAGGED((ch), PLR_MAILING) || PLR_FLAGGED((ch), PLR_CUSTOMIZE)) && (STATE(ch->desc) != CON_SPELL_CREATE))
/* message for doing damage with a weapon */
void dam_message(int dam, struct char_data * ch, struct char_data * victim, int w_type)
{
char *buf;
int msgnum;
struct char_data *vict, *witness;
static struct dam_weapon_type {
char *to_room;
char *to_char;
char *to_victim;
}
dam_weapons[] = {
{
"$n tries to #w $N, but misses.", /* 0: 0 */
"You try to #w $N, but miss.",
"$n tries to #w you, but misses."
},
{
"$n grazes $N as $e #W $M.", /* 1: 1..2 */
"You graze $N as you #w $M.",
"$n grazes you as $e #W you."
},
{
"$n barely #W $N.", /* 2: 3..4 */
"You barely #w $N.",
"$n barely #W you."
},
{
"$n #W $N.", /* 3: 5..6 */
"You #w $N.",
"$n #W you."
},
{
"$n #W $N hard.", /* 4: 7..10 */
"You #w $N hard.",
"$n #W you hard."
},
{
"$n #W $N very hard.", /* 5: 11..14 */
"You #w $N very hard.",
"$n #W you very hard."
},
{
"$n #W $N extremely hard.", /* 6: 15..19 */
"You #w $N extremely hard.",
"$n #W you extremely hard."
},
{
"$n massacres $N to small fragments with $s #d.", /* 7: 19..23 */
"You massacre $N to small fragments with your #d.",
"$n massacres you to small fragments with $s #d."
},
{
"$n demolishes $N with $s deadly #d!", /* 8: > 23 */
"You demolish $N with your deadly #d!",
"$n demolishes you with $s deadly #d!"
},
{
"$n pulverizes $N with $s incredibly powerful #d!!",
"You pulverize $N with your incredibly powerful #d!!",
"$n pulverizes you with $s incredibly powerful #d!!",
},
{
"$n sublimates $N with an ultimate #d!!!",
"You sublimate $N with an ultimate #d!!!",
"$n sublimates you with an ultimate #d!!!",
}
};
w_type -= TYPE_HIT; /* Change to base of table with text */
if (dam < 0)
msgnum = 0;
else if (dam == 0) {
switch(number(0,1)) {
case 0: msgnum = 1; break;
case 1: msgnum = 2; break;
default: msgnum = 0; break;
}
} else if (dam <= 1)
msgnum = 3;
else if (dam <= 3)
msgnum = 5;
else if (dam <= 6)
msgnum = 7;
else if (dam <= 10)
msgnum = 8;
else if (dam <= 13)
msgnum = 9;
else msgnum = 10;
/* damage message to onlookers */
buf = replace_string(dam_weapons[msgnum].to_room,
attack_hit_text[w_type].singular, attack_hit_text[w_type].plural,
attack_hit_text[w_type].different);
for (witness = world[victim->in_room].people; witness; witness = witness->next_in_room)
if (witness != ch && witness != victim && !PRF_FLAGGED(witness, PRF_FIGHTGAG) && SENDOK(witness))
perform_act(buf, ch, NULL, victim, witness);
if (ch->in_room != victim->in_room)
for (witness = world[ch->in_room].people; witness; witness = witness->next_in_room)
if (witness != ch && witness != victim && !PRF_FLAGGED(witness, PRF_FIGHTGAG) && SENDOK(witness))
perform_act(buf, ch, NULL, victim, witness);
/* damage message to damager */
strcpy(buf1, "^y");
buf = replace_string(dam_weapons[msgnum].to_char,
attack_hit_text[w_type].singular, attack_hit_text[w_type].plural,
attack_hit_text[w_type].different);
strcat(buf1, buf);
act(buf1, FALSE, ch, NULL, victim, TO_CHAR);
/* damage message to damagee */
strcpy(buf1, "^r");
buf = replace_string(dam_weapons[msgnum].to_victim,
attack_hit_text[w_type].singular, attack_hit_text[w_type].plural,
attack_hit_text[w_type].different);
strcat(buf1, buf);
act(buf1, FALSE, ch, NULL, victim, TO_VICT | TO_SLEEP);
}
#undef SENDOK
/*
* message for doing damage with a spell or skill
* C3.0: Also used for weapon damage on miss and death blows
*/
int skill_message(int dam, struct char_data * ch, struct char_data * vict, int attacktype)
{
int i, j, nr;
struct message_type *msg;
struct obj_data *weap = ch->equipment[WEAR_WIELD];
for (i = 0; i < MAX_MESSAGES; i++) {
if (fight_messages[i].a_type == attacktype) {
nr = dice(1, fight_messages[i].number_of_attacks);
for (j = 1, msg = fight_messages[i].msg; (j < nr) && msg; j++)
msg = msg->next;
if (!IS_NPC(vict) && (GET_LEVEL(vict) >= LVL_LEGEND) && dam < 1) {
act(msg->god_msg.attacker_msg, FALSE, ch, weap, vict, TO_CHAR);
act(msg->god_msg.victim_msg, FALSE, ch, weap, vict, TO_VICT);
act(msg->god_msg.room_msg, FALSE, ch, weap, vict, TO_NOTVICT);
} else if (dam > 0) {
if (GET_POS(vict) == POS_DEAD) {
send_to_char(CCYEL(ch, C_CMP), ch);
act(msg->die_msg.attacker_msg, FALSE, ch, weap, vict, TO_CHAR);
send_to_char(CCNRM(ch, C_CMP), ch);
send_to_char(CCRED(vict, C_CMP), vict);
act(msg->die_msg.victim_msg, FALSE, ch, weap, vict, TO_VICT | TO_SLEEP);
send_to_char(CCNRM(vict, C_CMP), vict);
act(msg->die_msg.room_msg, FALSE, ch, weap, vict, TO_NOTVICT);
} else {
send_to_char(CCYEL(ch, C_CMP), ch);
act(msg->hit_msg.attacker_msg, FALSE, ch, weap, vict, TO_CHAR);
send_to_char(CCNRM(ch, C_CMP), ch);
send_to_char(CCRED(vict, C_CMP), vict);
act(msg->hit_msg.victim_msg, FALSE, ch, weap, vict, TO_VICT | TO_SLEEP);
send_to_char(CCNRM(vict, C_CMP), vict);
act(msg->hit_msg.room_msg, FALSE, ch, weap, vict, TO_NOTVICT);
}
} else if ((ch != vict) && (dam <= 0)) { /* Dam == 0 */
send_to_char(CCYEL(ch, C_CMP), ch);
act(msg->miss_msg.attacker_msg, FALSE, ch, weap, vict, TO_CHAR);
send_to_char(CCNRM(ch, C_CMP), ch);
send_to_char(CCRED(vict, C_CMP), vict);
act(msg->miss_msg.victim_msg, FALSE, ch, weap, vict, TO_VICT | TO_SLEEP);
send_to_char(CCNRM(vict, C_CMP), vict);
act(msg->miss_msg.room_msg, FALSE, ch, weap, vict, TO_NOTVICT);
}
return 1;
}
}
return 0;
}
int find_orig_dir(struct char_data *ch, struct char_data *victim)
{
struct char_data *vict;
int nextroom, dir, dist, room;
for (dir = 0; dir < (NUM_OF_DIRS - 1); dir++) {
room = victim->in_room;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
for (dist = 1; nextroom != NOWHERE && dist <= 4; dist++) {
for (vict = world[nextroom].people; vict; vict = vict->next_in_room)
if (vict == ch)
return (rev_dir[dir]);
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
}
return -1;
}
void weapon_scatter(struct char_data *ch, struct char_data *victim, struct obj_data *weapon)
{
struct char_data *vict;
char ammo_type[20];
int damage_total, power, total = 0, door = 0, dir[3], i;
if (!ch || !victim || !weapon || ch->in_room == victim->in_room)
return;
dir[1] = find_orig_dir(ch, victim);
if (dir[1] >= NORTH && dir[1] <= NORTHWEST) {
if (dir[1] == NORTH)
dir[0] = NORTHWEST;
else dir[0] = dir[1] - 1;
if (dir[1] == NORTHWEST)
dir[2] = NORTH;
else dir[2] = dir[1] + 1;
} else dir[0] = dir[2] = -1;
for (vict = world[victim->in_room].people; vict; vict = vict->next_in_room)
if (vict != victim && !IS_ASTRAL(vict) && GET_POS(vict) > POS_SLEEPING)
total++;
for (i = 0; i < 3; i++)
if (dir[i] != -1 && EXIT(victim, dir[i]) &&
IS_SET(EXIT(victim, dir[i])->exit_info, EX_CLOSED))
door += 2;
switch(GET_OBJ_VAL(weapon, 3)) {
case TYPE_SHOTGUN:
sprintf(ammo_type, "horde of pellets");
break;
case TYPE_MACHINE_GUN:
sprintf(ammo_type, "stream of bullets");
break;
case TYPE_CANNON:
sprintf(ammo_type, "shell");
break;
case TYPE_ROCKET:
sprintf(ammo_type, "rocket");
break;
default:
sprintf(ammo_type, "bullet");
break;
}
i = number(1, MAX(20, total + door + 2));
if (i <= total) { // hits a victim
for (vict = world[victim->in_room].people; vict; vict = vict->next_in_room)
if (vict != victim && !IS_ASTRAL(vict) && GET_POS(vict) > POS_SLEEPING &&
!number(0, total - 1))
break;
if (vict && (IS_NPC(vict) || (!IS_NPC(vict) && vict->desc))) {
sprintf(buf, "A %s flies in from nowhere, hitting you!", ammo_type);
act(buf, FALSE, vict, 0, 0, TO_CHAR);
sprintf(buf, "A %s hums into the room and hits $n!", ammo_type);
act(buf, FALSE, vict, 0, 0, TO_ROOM);
power = MAX(GET_OBJ_VAL(weapon, 0) - GET_BALLISTIC(vict) - 3, 2);
damage_total = MAX(1, GET_OBJ_VAL(weapon, 1));
damage_total = convert_damage(stage((2 - success_test(GET_BOD(vict), power +
modify_target(vict))), damage_total));
damage(ch, vict, damage_total, TYPE_SCATTERING, PHYSICAL);
return;
}
} else if (i > (MAX(20, total + door + 2) - door)) { // hits a door
for (i = 0; i < 3; i++)
if (dir[i] != -1 && EXIT(victim, dir[i]) && !number(0, door - 1) &&
IS_SET(EXIT(victim, dir[i])->exit_info, EX_CLOSED))
break;
if (i < 3) {
sprintf(buf, "A %s hums into the room and hits the %s!", ammo_type,
fname(EXIT(victim, dir[i])->keyword));
act(buf, FALSE, victim, 0, 0, TO_ROOM);
act(buf, FALSE, victim, 0, 0, TO_CHAR);
damage_door(NULL, victim->in_room, dir[i], GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_PROJECTILE);
return;
}
}
// if it's reached this point, it's harmless
sprintf(buf, "A %s hums harmlessly through the room.", ammo_type);
act(buf, FALSE, victim, 0, 0, TO_ROOM);
act(buf, FALSE, victim, 0, 0, TO_CHAR);
}
void damage_equip(struct char_data *ch, struct char_data *victim, int power,
int attacktype)
{
int i = number(0, 39);
if (i >= WEAR_PATCH || !GET_EQ(victim, i))
return;
if (attacktype >= TYPE_PISTOL && attacktype <= TYPE_BIFURCATE) {
if (i >= WEAR_EYES)
return;
damage_obj(ch, GET_EQ(victim, i), power, DAMOBJ_PROJECTILE);
} switch (attacktype) {
case TYPE_PIERCE: case TYPE_STAB: case TYPE_SHURIKEN:
if (i >= WEAR_EYES)
return;
damage_obj(ch, GET_EQ(victim, i), power, DAMOBJ_PIERCE);
break;
case TYPE_STING: case TYPE_SLASH: case TYPE_CLAW:
case TYPE_THRASH: case TYPE_ARROW: case TYPE_THROWING_KNIFE:
if (i >= WEAR_EYES)
return;
damage_obj(ch, GET_EQ(victim, i), power, DAMOBJ_SLASH);
break;
case TYPE_HIT: case TYPE_BLUDGEON: case TYPE_POUND:
case TYPE_MAUL: case TYPE_PUNCH:
damage_obj(ch, GET_EQ(victim, i), power, DAMOBJ_CRUSH);
break;
}
}
float power_multiplier(int type, int material)
{
switch (type) {
case DAMOBJ_ACID:
switch (material) {
case 6: case 7: case 10: case 11: return 1.2;
case 13: return 2.0;
}
break;
case DAMOBJ_AIR:
switch (material) {
case 2: return 2.0;
case 5: case 8: case 14: case 15: case 16: return 0.4;
default: return 0.8;
}
break;
case DAMOBJ_EARTH:
switch (material) {
case 2: return 2.0;
default: return 0.9;
}
break;
case DAMOBJ_FIRE:
switch (material) {
case 0: case 1: case 3: return 1.5;
case 4: case 6: case 7: return 1.1;
default: return 0.8;
}
break;
case DAMOBJ_ICE:
switch (material) {
case 3: case 4: return 1.2;
default: return 0.9;
}
break;
case DAMOBJ_LIGHTNING:
switch (material) {
case 8: return 2.0;
case 10: case 11: return 5.0;
default: return 0.7;
}
break;
case DAMOBJ_WATER:
switch (material) {
case 10: case 11: return 3.0;
default: return 0.5;
}
break;
case DAMOBJ_EXPLODE:
switch (material) {
case 0: case 1: case 3: case 4: case 13: return 1.3;
case 2: return 3.0;
default: return 1.1;
}
break;
case DAMOBJ_PROJECTILE:
switch (material) {
case 2: return 3.0;
case 10: case 11: return 1.1;
default: return 0.8;
}
break;
case DAMOBJ_CRUSH:
switch (material) {
case 1: case 6: case 7: return 1.4;
case 2: return 4.0;
case 5: case 14: case 15: case 16: return 1.0;
default: return 0.7;
}
break;
case DAMOBJ_SLASH:
switch (material) {
case 0: case 3: case 4: case 13: return 1.4;
case 5: case 14: case 15: case 16: return 0.3;
default: return 0.6;
}
break;
case DAMOBJ_PIERCE:
switch (material) {
case 0: case 3: case 4: case 13: return 1.0;
case 5: case 8: case 14: case 15: case 16: return 0.1;
default: return 0.3;
}
break;
}
return 1.0;
}
void damage_door(struct char_data *ch, int room, int dir, int power, int type)
{
if (room < 0 || room > top_of_world || dir < NORTH || dir > UP ||
!world[room].dir_option[dir] || !world[room].dir_option[dir]->keyword ||
!IS_SET(world[room].dir_option[dir]->exit_info, EX_CLOSED))
return;
int modifier, dam, target, rating, half, opposite, rev, ok = 0;
opposite = world[room].dir_option[dir]->to_room;
rev = rev_dir[dir];
if (opposite > -1 && world[opposite].dir_option[rev] &&
world[opposite].dir_option[rev]->to_room == room)
ok = TRUE;
if (IS_SET(type, DAMOBJ_MANIPULATION)) {
rating = world[room].dir_option[dir]->barrier;
modifier = 2;
REMOVE_BIT(type, DAMOBJ_MANIPULATION);
} else {
rating = world[room].dir_option[dir]->barrier << 1;
modifier = 4;
}
half = MAX(1, rating >> 1);
modifier -= power >> 2;
if (success_test(2, MAX(2, material_ratings[world[room].dir_option[dir]->material] + modifier)))
power = (int)(power * power_multiplier(type, world[room].dir_option[dir]->material));
if (power < half) {
sprintf(buf, "The %s remains undamaged.\r\n", fname(world[room].dir_option[dir]->keyword));
send_to_room(buf, room);
if (ch && ch->in_room != room)
send_to_char(buf, ch);
return;
} else if (power < rating) {
sprintf(buf, "The %s has been slightly damaged.\r\n",
fname(world[room].dir_option[dir]->keyword));
send_to_room(buf, room);
if (ch && ch->in_room != room)
send_to_char(buf, ch);
world[room].dir_option[dir]->condition--;
} else {
sprintf(buf, "The %s has been damaged!\r\n", fname(world[room].dir_option[dir]->keyword));
send_to_room(buf, room);
if (ch && ch->in_room != room)
send_to_char(buf, ch);
world[room].dir_option[dir]->condition -= 1 + (power - rating) / half;
}
if (ok)
world[opposite].dir_option[rev]->condition = world[room].dir_option[dir]->condition;
if (world[room].dir_option[dir]->condition <= 0) {
sprintf(buf, "The %s has been destroyed!\r\n", fname(world[room].dir_option[dir]->keyword));
send_to_room(buf, room);
if (ch && ch->in_room != room)
send_to_char(buf, ch);
REMOVE_BIT(world[room].dir_option[dir]->exit_info, EX_CLOSED);
REMOVE_BIT(world[room].dir_option[dir]->exit_info, EX_LOCKED);
SET_BIT(world[room].dir_option[dir]->exit_info, EX_DESTROYED);
if (ok) {
sprintf(buf, "The %s is destroyed from the other side!\r\n",
fname(world[room].dir_option[dir]->keyword));
send_to_room(buf, opposite);
REMOVE_BIT(world[opposite].dir_option[rev]->exit_info, EX_CLOSED);
REMOVE_BIT(world[opposite].dir_option[rev]->exit_info, EX_LOCKED);
SET_BIT(world[opposite].dir_option[rev]->exit_info, EX_DESTROYED);
}
}
}
// damage_obj does what its name says, it figures out effects of successes
// damage, applies that damage to that object, and sends messages to the player
void damage_obj(struct char_data *ch, struct obj_data *obj, int power, int type)
{
if (!obj)
return;
if (power <= 0)
return;
int success, modifier, dam, target, rating, half;
struct char_data *vict = (obj->worn_by ? obj->worn_by : obj->carried_by);
struct obj_data *temp, *next;
// PC corpses are indestructable by normal means
if ( IS_OBJ_STAT(obj, ITEM_CORPSE) && GET_OBJ_VAL(obj, 4) == 1 )
{
if ( ch != NULL )
send_to_char("Nuh uh fuck nut.\n\r",ch);
return;
}
if (IS_SET(type, DAMOBJ_MANIPULATION)) {
rating = GET_OBJ_BARRIER(obj);
modifier = 2;
REMOVE_BIT(type, DAMOBJ_MANIPULATION);
} else {
rating = GET_OBJ_BARRIER(obj) << 1;
modifier = 4;
}
half = MAX(1, rating >> 1);
modifier -= power >> 2;
success = success_test(2, MAX(2, material_ratings[GET_OBJ_MATERIAL(obj)] + modifier));
if (success > 0) {
switch (type) {
case DAMOBJ_ACID:
if (GET_OBJ_TYPE(obj) == ITEM_ARMOR && success == 2)
switch (number(0, 4)) {
case 0:
GET_OBJ_VAL(obj, 0) = MAX(GET_OBJ_VAL(obj, 0) - 1, 0);
GET_OBJ_VAL(obj, 1) = MAX(GET_OBJ_VAL(obj, 1) - 1, 0);
break;
case 1: case 2:
GET_OBJ_VAL(obj, 0) = MAX(GET_OBJ_VAL(obj, 0) - 1, 0);
break;
case 3: case 4:
GET_OBJ_VAL(obj, 1) = MAX(GET_OBJ_VAL(obj, 1) - 1, 0);
break;
}
break;
case DAMOBJ_FIRE: case DAMOBJ_EXPLODE:
if (GET_OBJ_TYPE(obj) == ITEM_GUN_CLIP && success == 2 && vict) {
act("$p ignites, spraying bullets about!", FALSE, vict, obj, 0, TO_CHAR);
act("One of $n's clips ignites, spraying bullets about!",
FALSE, vict, obj, 0, TO_ROOM);
target = (int)(GET_OBJ_VAL(obj, 0) / 4);
switch (GET_OBJ_VAL(obj, 1) + 300) {
case TYPE_ROCKET:
dam = DEADLY; break;
case TYPE_GRENADE_LAUNCHER: case TYPE_CANNON:
dam = SERIOUS; break;
case TYPE_SHOTGUN: case TYPE_MACHINE_GUN: case TYPE_RIFLE:
dam = MODERATE; break;
default:
dam = LIGHT;
}
dam = convert_damage(stage(-success_test(GET_BOD(vict) + GET_DEFENSE(vict),
target + modify_target(vict)), dam));
damage(vict, vict, dam, TYPE_SCATTERING, TRUE);
extract_obj(obj);
return;
}
if (GET_OBJ_TYPE(obj) == ITEM_WEAPON && success == 2 &&
GET_OBJ_VAL(obj, 3) == TYPE_HAND_GRENADE) {
if (vict) {
act("$p is set off by the fire!", FALSE, vict, obj, 0, TO_CHAR);
act("A $p carried by $n is set off by the fire!", FALSE, vict, obj, 0, TO_ROOM);
explode(NULL, obj, obj->in_room);
} else if (obj->in_room != NOWHERE) {
sprintf(buf, "%s is set off by the flames!", CAP(obj->short_description));
send_to_room(buf, obj->in_room);
explode(NULL, obj, obj->in_room);
}
return;
}
break;
}
power = (int)(power * power_multiplier(type, GET_OBJ_MATERIAL(obj)));
}
if (power < half) {
if (ch)
send_to_char(ch, "%s remains undamaged.\r\n", CAP(obj->short_description));
return;
} else if (power < rating) {
if (ch)
send_to_char(ch, "%s has been slightly damaged.\r\n", CAP(obj->short_description));
if (vict && vict != ch)
send_to_char(vict, "%s has been slightly damaged.\r\n", CAP(obj->short_description));
GET_OBJ_CONDITION(obj)--;
} else {
if (ch)
send_to_char(ch, "%s has been damaged!\r\n", CAP(obj->short_description));
if (vict && vict != ch)
send_to_char(vict, "%s has been damaged!\r\n", CAP(obj->short_description));
GET_OBJ_CONDITION(obj) -= 1 + (power - rating) / half;
}
// if the end result is that the object's condition rating is 0 or less
// it's destroyed -- a good reason to keep objects in good repair
if (GET_OBJ_CONDITION(obj) <= 0) {
if (ch)
send_to_char(ch, "%s has been destroyed!\r\n", CAP(obj->short_description));
if (vict && vict != ch)
send_to_char(vict, "%s has been destroyed!\r\n", CAP(obj->short_description));
if (ch && !IS_NPC(ch) && GET_QUEST(ch))
check_quest_destroy(ch, obj);
else if (ch && AFF_FLAGGED(ch, AFF_GROUP) && ch->master &&
!IS_NPC(ch->master) && GET_QUEST(ch->master))
check_quest_destroy(ch->master, obj);
for (temp = obj->contains; temp; temp = next) {
next = temp->next_content;
obj_from_obj(temp);
if (IS_OBJ_STAT(obj, ITEM_CORPSE) && !GET_OBJ_VAL(obj, 4) &&
GET_OBJ_TYPE(temp) != ITEM_MONEY)
extract_obj(temp);
else if (vict)
obj_to_char(temp, vict);
else if (obj->in_room != NOWHERE)
obj_to_room(temp, obj->in_room);
else extract_obj(temp);
}
extract_obj(obj);
}
}
#define DOCWAGON_ROOM 2127
void docwagon_message(struct char_data *ch)
{
char buf[MAX_STRING_LENGTH];
switch (SECT(ch->in_room)) {
case SECT_INSIDE:
sprintf(buf,"A DocWagon employee suddenly appears, teleports %s's body to\r\nsafety, and dissolves into thin air.", GET_NAME(ch));
act(buf,FALSE, ch, 0, 0, TO_ROOM);
break;
case SECT_WATER_SWIM: case SECT_WATER_NOSWIM:
sprintf(buf,"A DocWagon armored speedboat arrives, loading %s's body on\r\nboard before leaving.", GET_NAME(ch));
act(buf, FALSE, ch, 0, 0, TO_ROOM);
break;
case SECT_UNDERWATER:
sprintf(buf,"A DocWagon submarine silently arrives and loads %s's body into the\r\ndecompression chamber.", GET_NAME(ch));
act(buf, FALSE, ch, 0, 0, TO_ROOM);
break;
default:
sprintf(buf,"A DocWagon helicopter flies in, taking %s's body to safety.", GET_NAME(ch));
act(buf, FALSE, ch, 0, 0, TO_ROOM);
break;
}
mudlog(buf, ch, LOG_DEATHLOG, TRUE);
}
void docwagon(struct char_data *ch)
{
int i, creds;
struct obj_data *docwagon = NULL, *obj, *temp;
if (IS_NPC(ch))
return;
for (obj = ch->carrying; obj && !docwagon; obj = obj->next_content) {
if (GET_OBJ_TYPE(obj) == ITEM_DOCWAGON && GET_OBJ_VAL(obj, 1) == GET_IDNUM(ch))
docwagon = obj;
else for (temp = obj->contains; temp && !docwagon; temp = temp->next_content)
if (GET_OBJ_TYPE(temp) == ITEM_DOCWAGON && GET_OBJ_VAL(temp, 1) == GET_IDNUM(ch))
docwagon = temp;
}
for (i = 0; (i < NUM_WEARS && !docwagon); i++)
if ((obj = GET_EQ(ch, i))) {
if (GET_OBJ_TYPE(obj) == ITEM_DOCWAGON && GET_OBJ_VAL(obj, 1) == GET_IDNUM(ch))
docwagon = obj;
else for (temp = obj->contains; temp && !docwagon; temp = temp->next_content)
if (GET_OBJ_TYPE(temp) == ITEM_DOCWAGON && GET_OBJ_VAL(temp, 1) == GET_IDNUM(ch))
docwagon = temp;
}
if (!docwagon)
return;
if (success_test(GET_OBJ_VAL(docwagon, 0),
MAX(zone_table[world[ch->in_room].zone].security, 4))) {
if (FIGHTING(ch) && FIGHTING(FIGHTING(ch)) == ch)
stop_fighting(FIGHTING(ch));
if (FIGHTING(ch))
stop_fighting(ch);
docwagon_message(ch);
GET_PHYSICAL(ch) = GET_MAX_PHYSICAL(ch);
GET_MENTAL(ch) = 0;
SET_BIT(AFF_FLAGS(ch), AFF_SLEEP);
update_pos(ch);
send_to_char("\r\n\r\nYour last conscious memory is the arrival of a DocWagon.\r\n", ch);
char_from_room(ch);
char_to_room(ch, real_room(DOCWAGON_ROOM));
creds = MAX((number(8, 12) * 500 / GET_OBJ_VAL(docwagon, 0)), (int)(GET_NUYEN(ch) / 10));
if ((GET_NUYEN(ch) + GET_BANK(ch)) < creds) {
send_to_char("Not finding sufficient payment, your DocWagon contract was retracted.\r\n", ch);
extract_obj(docwagon);
} else if (GET_BANK(ch) < creds) {
GET_NUYEN(ch) -= (creds - GET_BANK(ch));
GET_BANK(ch) = 0;
} else GET_BANK(ch) -= creds;
}
return;
}
#undef DOCWAGON_ROOM
void check_adrenaline(struct char_data *ch, int mode)
{
int i, dam;
struct obj_data *bio, *pump = NULL;
for (bio = ch->bioware; bio && !pump; bio = bio->next_content)
if (GET_OBJ_VAL(bio, 2) == 4)
pump = bio;
if (!pump)
return;
if (GET_OBJ_VAL(pump, 5) == 0 && mode == 1) {
GET_OBJ_VAL(pump, 5) = dice(GET_OBJ_VAL(pump, 0), 6);
GET_OBJ_VAL(pump, 6) = GET_OBJ_VAL(pump, 5);
send_to_char("Your body is wracked with renewed vitality as adrenaline "
"pumps into your\r\nbloodstream.\r\n", ch);
for (i = 0; i < MAX_OBJ_AFFECT; i++)
affect_modify(ch, pump->affected[i].location, pump->affected[i].modifier,
pump->obj_flags.bitvector, TRUE);
} else if (GET_OBJ_VAL(pump, 5) > 0 && !mode) {
GET_OBJ_VAL(pump, 5)--;
if (GET_OBJ_VAL(pump, 5) == 0) {
for (i = 0; i < MAX_OBJ_AFFECT; i++)
affect_modify(ch, pump->affected[i].location, pump->affected[i].modifier,
pump->obj_flags.bitvector, FALSE);
GET_OBJ_VAL(pump, 5) = -number(168, 180);
send_to_char("Your body softens and relaxes as the adrenaline wears off.\r\n", ch);
dam = convert_damage(stage(-success_test(GET_BOD(ch),
(int)(GET_OBJ_VAL(pump, 6) / 2) + modify_target(ch)), DEADLY));
GET_OBJ_VAL(pump, 6) = 0;
damage(ch, ch, dam, TYPE_BIOWARE, FALSE);
}
} else if (GET_OBJ_VAL(pump, 5) < 0 && !mode)
GET_OBJ_VAL(pump, 5)++;
}
void gen_death_msg(struct char_data *ch, struct char_data *vict, int attacktype)
{
switch (attacktype) {
case TYPE_SUFFERING:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s died (no blood, it seems). {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s's brain ran out of oxygen {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s simply ran out of blood. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "%s unwittingly committed suicide. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "Bloodlack stole %s's life. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
}
break;
case TYPE_EXPLOSION:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s blew %s to pieces. {%s (%d)}", ch == vict ? "???"
: GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s was blown to bits. [%s] {%s (%d)}",
GET_NAME(vict), ch == vict ? "???" : GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s got vaporized by %s. {%s (%d)}",
GET_NAME(vict), ch == vict ? "???" : GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "%s was incinerated by an explosion. [%s] {%s (%d)}",
GET_NAME(vict), ch == vict ? "???" : GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "%s got blown to hell by %s. {%s (%d)}",
GET_NAME(vict), ch == vict ? "???" : GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
}
break;
case TYPE_SCATTERING:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s accidentally (?) killed by %s. {%s (%d)}",
GET_NAME(vict), GET_NAME(ch), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "Shouldn't have been standing there, should you %s? "
"[%s] {%s (%d)}", GET_NAME(vict), GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "Oops....%s just blew %s's head off. {%s (%d)}",
GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "%s's stray bullet caught %s in the heart. "
"What a shame. {%s (%d)}", GET_NAME(ch), GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "A random bullet killed a random person -- poor %s. "
"[%s] {%s (%d)}", GET_NAME(vict), GET_NAME(ch),
world[vict->in_room].name, world[vict->in_room].number);
break;
}
break;
case TYPE_FALL:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s died on impact. {%s (%d)}", GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s failed to miss the ground. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "Life's a bitch, %s. So's concrete. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "What %s wouldn't have given for a safety net... "
"{%s (%d)}", GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "The ground can be such an unforgiving thing. "
"Right, %s? {%s (%d)}", GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
}
break;
case TYPE_DROWN:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s drank way, way, WAY too much. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s swims with the fishes. Involuntarily. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "The water had a fight with %s's lungs. "
"The water won. {%s (%d)}", GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "Water doesn't seem so harmless now, does it %s? "
"{%s (%d)}", GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "%s didn't float. {%s (%d)}", GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
}
break;
case TYPE_ALLERGY:
switch (number(0, 2)) {
case 0:
sprintf(buf2, "%s died from an allergy, of all things. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s, didn't the doctor say NOT to go near that "
"stuff? {%s (%d)}", GET_NAME(vict),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s died a warrior's death...from an allergy. "
"{%s (%d)}", GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
}
break;
case TYPE_BIOWARE:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "%s just hasn't been taking %s medication. Oops. "
"{%s (%d)}", GET_NAME(vict), GET_SEX(vict) == SEX_MALE ?
"his" : (GET_SEX(vict) == SEX_FEMALE ? "her" : "its"),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s was killed in a bioware rebellion. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s has a fatal heart attack. Wuss. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "Still think the bioware was worth it, %s?. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "Maybe %s got a defective piece of bioware... {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
}
break;
case TYPE_RECOIL:
switch (number(0, 4)) {
case 0:
sprintf(buf2, "You're meant to hit *other* people with that whip, "
"%s. {%s (%d)}", GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s lopped off %s own head. Oops. {%s (%d)}",
GET_NAME(vict), GET_SEX(vict) == SEX_MALE ? "his" :
(GET_SEX(vict) == SEX_FEMALE ? "her" : "its"),
world[vict->in_room].name, world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s, watch out for your whi....nevermind. {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "THWAP! Wait.....was that *your* whip, %s?!? "
"{%s (%d)}", GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "%s's whip didn't agree with %s. {%s (%d)}",
GET_NAME(vict), GET_SEX(vict) == SEX_MALE ? "his" :
(GET_SEX(vict) == SEX_FEMALE ? "her" : "its"),
world[vict->in_room].name, world[vict->in_room].number);
break;
}
break;
default:
if (ch == vict)
sprintf(buf2, "%s died (cause uncertain). {%s (%d)}",
GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
else switch (number(0, 5)) {
case 0:
sprintf(buf2, "%s killed by %s. {%s (%d)}", GET_NAME(vict),
GET_NAME(ch), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 1:
sprintf(buf2, "%s wiped %s out of existence. {%s (%d)}",
GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 2:
sprintf(buf2, "%s's life terminated by %s. {%s (%d)}",
GET_NAME(vict), GET_NAME(ch), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 3:
sprintf(buf2, "%s flatlined %s. {%s (%d)}",
GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 4:
sprintf(buf2, "%s transformed %s into a corpse. {%s (%d)}",
GET_NAME(ch), GET_NAME(vict), world[vict->in_room].name,
world[vict->in_room].number);
break;
case 5:
sprintf(buf2, "%s got geeked by %s. {%s (%d)}",
GET_NAME(vict), GET_NAME(ch), world[vict->in_room].name,
world[vict->in_room].number);
break;
}
break;
}
mudlog(buf2, vict, LOG_DEATHLOG, TRUE);
}
#define IS_RANGED(eq) (GET_OBJ_TYPE(eq) == ITEM_FIREWEAPON || \
(GET_OBJ_TYPE(eq) == ITEM_WEAPON && \
(GET_OBJ_VAL(eq, 3) == TYPE_SHURIKEN || \
GET_OBJ_VAL(eq, 3) == TYPE_THROWING_KNIFE || \
GET_OBJ_VAL(eq, 3) >= TYPE_PISTOL)))
#define RANGE_OK(ch) ((GET_WIELDED(ch, 0) && GET_EQ(ch, WEAR_WIELD) && \
IS_RANGED(GET_EQ(ch, WEAR_WIELD))) || (GET_WIELDED(ch, 1) && \
GET_EQ(ch, WEAR_HOLD) && IS_RANGED(GET_EQ(ch, WEAR_HOLD))))
#define IS_BURST(eq) (GET_OBJ_TYPE(eq) == ITEM_WEAPON && \
(GET_OBJ_VAL(eq, 3) == TYPE_MACHINE_GUN || \
(GET_OBJ_VAL(eq, 3) == TYPE_RIFLE && \
GET_OBJ_VAL(eq, 4) == SKILL_ASSAULT_RIFLES)))
// return 1 if victim died, 0 otherwise
int damage(struct char_data *ch, struct char_data *victim, int dam, int attacktype,
bool is_physical)
{
char rbuf[MAX_STRING_LENGTH];
int exp, damage_total;
bool total_miss = FALSE;
struct obj_data *bio;
int counter;
ACMD(do_disconnect);
ACMD(do_return);
if (GET_POS(victim) <= POS_DEAD) {
log("SYSERR: Attempt to damage a corpse.");
return 0; /* -je, 7/7/92 */
}
sprintf(rbuf,"Damage: ");
if (((!IS_NPC(ch) && GET_LEVEL(ch) >= LVL_LEGEND &&
!access_level(ch, LVL_PRESIDENT)) || (IS_NPC(ch) && ch->master &&
AFF_FLAGGED(ch, AFF_CHARM) && !IS_NPC(ch->master) &&
GET_LEVEL(ch->master) >= LVL_LEGEND &&
!access_level(ch->master, LVL_PRESIDENT))) &&
IS_NPC(victim) && dam > 0 && !from_ip_zone(GET_MOB_VNUM(victim)))
{
dam = -1;
buf_mod(rbuf,"Invalid",dam);
}
/* shopkeeper protection */
if (!ok_damage_shopkeeper(ch, victim))
{
dam = -1;
buf_mod(rbuf,"Keeper",dam);
}
if (victim != ch) {
if (GET_POS(ch) > POS_STUNNED && attacktype < TYPE_SUFFERING) {
if (!FIGHTING(ch))
set_fighting(ch, victim);
if (!IS_NPC(ch) && IS_NPC(victim) && victim->master && !number(0, 10) &&
IS_AFFECTED(victim, AFF_CHARM) && (victim->master->in_room == ch->in_room) &&
!(ch->master && ch->master == victim->master)) {
if (FIGHTING(ch))
stop_fighting(ch);
set_fighting(ch, victim->master);
if (!FIGHTING(victim->master))
set_fighting(victim->master, ch);
return 0;
}
}
if (GET_POS(victim) > POS_STUNNED && !FIGHTING(victim)) {
if (victim->in_room == ch->in_room)
set_fighting(victim, ch);
if (MOB_FLAGGED(victim, MOB_MEMORY) && !IS_NPC(ch) &&
(GET_LEVEL(ch) < LVL_LEGEND))
remember(victim, ch);
}
}
if (victim->master && victim->master == ch)
stop_follower(victim);
if (IS_AFFECTED(ch, AFF_HIDE))
appear(ch);
/* stop sneaking if it's the case */
if (IS_AFFECTED(ch, AFF_SNEAK))
REMOVE_BIT(AFF_FLAGS(ch), AFF_SNEAK);
if (PLR_FLAGGED(victim, PLR_MATRIX)) {
do_disconnect(victim, "", 0, SCMD_MORTED);
WAIT_STATE(victim, PULSE_VIOLENCE);
}
if (PLR_FLAGGED(victim, PLR_PROJECT) && ch != victim) {
do_return(victim, "", 0, 0);
WAIT_STATE(victim, PULSE_VIOLENCE);
}
if (!pk_allowed && ch != victim) {
check_killer(ch, victim);
if (PLR_FLAGGED(ch, PLR_KILLER) && !IS_NPC(victim))
{
dam = -1;
buf_mod(rbuf,"No-PK",dam);
}
}
if (attacktype == TYPE_EXPLOSION && (IS_ASTRAL(victim) ||
MOB_FLAGGED(victim, MOB_IMMEXPLODE)))
{
dam = -1;
buf_mod(rbuf,"ImmExplode",dam);
}
if (dam == -1)
{
total_miss = TRUE;
}
if (ch != victim && !IS_NPC(victim) && !(victim->desc)) {
if (!FIGHTING(victim)) {
act("$n is rescued by divine forces.", FALSE, victim, 0, 0, TO_ROOM);
GET_WAS_IN(victim) = victim->in_room;
GET_PHYSICAL(victim) = MAX(100, GET_PHYSICAL(victim) -
(int)(GET_MAX_PHYSICAL(victim) / 2));
GET_MENTAL(victim) = MAX(100, GET_MENTAL(victim) -
(int)(GET_MAX_MENTAL(victim) / 2));
char_from_room(victim);
char_to_room(victim, 0);
}
return 0;
}
if (is_physical && dam >= 3)
for (bio = ch->bioware; bio; bio = bio->next_content)
if (GET_OBJ_VAL(bio, 2) == 0) {
dam--;
break;
}
if (is_physical)
GET_PHYSICAL(victim) -= MAX(dam * 100, 0);
else if (((int)(GET_MENTAL(victim) / 100) - dam) < 0) {
int physdam = dam - (int)(GET_MENTAL(victim) / 100);
GET_MENTAL(victim) = 0;
GET_PHYSICAL(victim) -= MAX(physdam * 100, 0);
} else GET_MENTAL(victim) -= MAX(dam * 100, 0);
update_pos(victim);
/*
* skill_message sends a message from the messages file in lib/misc.
* dam_message just sends a generic "You hit $n extremely hard.".
* skill_message is preferable to dam_message because it is more
* descriptive.
*
* If we are _not_ attacking with a weapon (i.e. a spell), always use
* skill_message. If we are attacking with a weapon: If this is a miss or a
* death blow, send a skill_message if one exists; if not, default to a
* dam_message. Otherwise, always send a dam_message.
*/
if (attacktype > 0 && ch != victim && attacktype < TYPE_SUFFERING) {
if (!IS_WEAPON(attacktype)) {
skill_message(dam, ch, victim, attacktype);
} else {
if (GET_POS(victim) == POS_DEAD || total_miss) {
if (!skill_message(dam, ch, victim, attacktype))
dam_message(dam, ch, victim, attacktype);
} else
dam_message(dam, ch, victim, attacktype);
}
}
if ((ch->in_room != victim->in_room) && total_miss && attacktype < TYPE_SUFFERING &&
GET_EQ(ch, WEAR_WIELD) && GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 3) >= TYPE_PISTOL)
weapon_scatter(ch, victim, GET_EQ(ch, WEAR_WIELD));
if (victim->bioware && GET_POS(victim) > POS_STUNNED && dam > 0 && ch != victim)
check_adrenaline(victim, 1);
if (ch != victim && dam > 0 && attacktype >= TYPE_HIT)
damage_equip(ch, victim, dam, attacktype);
/* Use send_to_char -- act() doesn't send message if you are DEAD. */
switch (GET_POS(victim)) {
case POS_MORTALLYW:
act("$n is mortally wounded, and will die soon, if not aided.",
TRUE, victim, 0, 0, TO_ROOM);
send_to_char("You are mortally wounded, and will die soon, if not "
"aided.\r\n", victim);
if (!IS_NPC(victim))
docwagon(victim);
break;
case POS_INCAP:
act("$n is incapacitated and will slowly die, if not aided.",
TRUE, victim, 0, 0, TO_ROOM);
send_to_char("You are incapacitated and will slowly die, if not "
"aided.\r\n", victim);
if (!IS_NPC(victim))
docwagon(victim);
break;
case POS_STUNNED:
act("$n is stunned, but will probably regain consciousness again.",
TRUE, victim, 0, 0, TO_ROOM);
send_to_char("You're stunned, but will probably regain consciousness "
"again.\r\n", victim);
break;
case POS_DEAD:
act("$n is dead! R.I.P.", FALSE, victim, 0, 0, TO_ROOM);
send_to_char("You are dead! Sorry...\r\n", victim);
break;
default: /* >= POSITION SLEEPING */
if (dam > ((int)(GET_MAX_PHYSICAL(victim) / 100) >> 2))
act("^RThat really did HURT!^n", FALSE, victim, 0, 0, TO_CHAR);
if (GET_PHYSICAL(victim) < (GET_MAX_PHYSICAL(victim) >> 2))
send_to_char(victim, "%sYou wish that your wounds would stop "
"^RBLEEDING^n so much!%s\r\n", CCRED(victim, C_SPR),
CCNRM(victim, C_SPR));
if (MOB_FLAGGED(victim, MOB_WIMPY) && ch != victim &&
GET_PHYSICAL(victim) < (GET_MAX_PHYSICAL(victim) >> 2))
do_flee(victim, "", 0, 0);
else if (IS_NPC(victim) && ch->in_room != victim->in_room && !RANGE_OK(victim)) {
do_flee(victim, "", 0, 0);
stop_fighting(victim);
}
if (!IS_NPC(victim) && GET_WIMP_LEV(victim) && victim != ch &&
(int)(GET_PHYSICAL(victim) / 100) < GET_WIMP_LEV(victim)) {
send_to_char("You ^Ywimp^n out, and attempt to flee!\r\n", victim);
do_flee(victim, "", 0, 0);
}
break;
}
if (GET_MENTAL(victim) < 100)
if (FIGHTING(ch) == victim)
stop_fighting(ch);
if (!AWAKE(victim))
if (FIGHTING(victim))
stop_fighting(victim);
if (GET_POS(victim) == POS_DEAD) {
if (ch != victim && !IS_NPC(ch) && GET_QUEST(ch) && IS_NPC(victim))
check_quest_kill(ch, victim);
else if (ch != victim && AFF_FLAGGED(ch, AFF_GROUP) && ch->master &&
!IS_NPC(ch->master) && GET_QUEST(ch->master) && IS_NPC(victim))
check_quest_kill(ch->master, victim);
if ((IS_NPC(victim) || victim->desc) && ch != victim &&
attacktype != TYPE_EXPLOSION) {
if (IS_AFFECTED(ch, AFF_GROUP))
group_gain(ch, victim);
else {
exp = calc_karma(ch, victim);
exp = gain_exp(ch, exp);
send_to_char(ch, "You receive %0.2f karma.\r\n", ((float)exp / 100));
change_alignment(ch, victim);
}
}
if (!IS_NPC(victim)) {
gen_death_msg(ch, victim, attacktype);
if (MOB_FLAGGED(ch, MOB_MEMORY) && !IS_NPC(victim))
forget(ch, victim);
}
die(victim);
return 1;
}
return 0;
}
bool has_ammo(struct char_data *ch, int pos)
{
int i;
bool found = FALSE;
struct obj_data *obj;
if (pos != WEAR_WIELD && pos != WEAR_HOLD)
return FALSE;
struct obj_data *wielded = GET_EQ(ch, pos);
if (wielded && GET_OBJ_TYPE(wielded) == ITEM_FIREWEAPON) {
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i) && GET_OBJ_TYPE(GET_EQ(ch, i)) == ITEM_QUIVER)
for (obj = GET_EQ(ch, i)->contains; obj; obj = GET_EQ(ch, i)->next_content)
if (GET_OBJ_TYPE(obj) == ITEM_MISSILE && GET_OBJ_VAL(obj, 0) == GET_OBJ_VAL(wielded, 5)) {
GET_OBJ_VAL(GET_EQ(ch, i), 2)--;
extract_obj(obj);
found = TRUE;
}
if (found)
return TRUE;
else {
if (IS_NPC(ch)) {
switch_weapons(ch, pos);
return TRUE;
} else {
send_to_char("You're out of arrows!\r\n", ch);
stop_fighting(ch);
return FALSE;
}
}
}
if (wielded && (GET_OBJ_VAL(wielded, 5) > 0)) {
if (GET_OBJ_VAL(wielded, 6) > 0) {
GET_OBJ_VAL(wielded, 6)--;
#if 0
if (GET_OBJ_VAL(wielded, 6) == GET_OBJ_VAL(wielded, 5)) // just reloaded
return FALSE;
GET_INIT_ROLL(ch)--;
#endif
return TRUE;
} else
// make the mob do something (intelligent hopefully)
if (IS_NPC(ch)) {
if (!attempt_reload(ch, pos))
switch_weapons(ch, pos);
return TRUE;
} else {
send_to_char("*Click*\r\n", ch);
return FALSE;
}
} else return TRUE;
}
int check_smartlink(struct char_data *ch, struct obj_data *weapon)
{
struct obj_data *obj, *access = NULL;
int i, mod = 0;
// are they wielding two weapons?
if (GET_EQ(ch, WEAR_WIELD) && GET_EQ(ch, WEAR_HOLD) &&
CAN_WEAR(GET_EQ(ch, WEAR_HOLD), ITEM_WEAR_WIELD))
return 0;
for (i = 7; !mod && i < 10; i++)
{
if (GET_OBJ_VAL(weapon, i) > 0
&& real_object(GET_OBJ_VAL(weapon, i)) > 0
&& (access = &obj_proto[real_object(GET_OBJ_VAL(weapon, i))])
&& GET_OBJ_VAL(access, 1) == 1)
{
for (obj = ch->cyberware; !mod && obj; obj = obj->next_content)
if (GET_OBJ_VAL(obj, 2) == 22)
mod = 2;
access = NULL;
}
}
if (mod < 1 && AFF_FLAGGED(ch, AFF_LASER_SIGHT))
mod = 1;
return mod;
}
int check_recoil(struct char_data *ch, struct obj_data *gun)
{
struct obj_data *obj;
int i, rnum, comp = 0;
if (!gun || GET_OBJ_TYPE(gun) != ITEM_WEAPON)
return 0;
for (i = 7; i < 10; i++) {
obj = NULL;
if (GET_OBJ_VAL(gun, i) > 0 &&
(rnum = real_object(GET_OBJ_VAL(gun, i))) > -1 &&
(obj = &obj_proto[rnum]) && GET_OBJ_TYPE(obj) == ITEM_GUN_ACCESSORY) {
if (GET_OBJ_VAL(obj, 1) == 3)
comp += 0 - GET_OBJ_VAL(obj, 2);
else if (GET_OBJ_VAL(obj, 1) == 4)
comp++;
}
}
return comp;
}
void astral_fight(struct char_data *ch, struct char_data *vict)
{
int w_type, dam, power, attack_success, newskill, skill_total, base_target, i;
struct obj_data *wielded, *obj, *o = NULL;
struct char_data *temp;
bool focus = FALSE, is_physical;
wielded = ch->equipment[WEAR_WIELD];
if (ch->in_room != vict->in_room) {
stop_fighting(ch);
if (FIGHTING(vict) == ch)
stop_fighting(vict);
return;
}
if ((IS_PROJECT(ch) || PLR_FLAGGED(ch, PLR_PERCEIVE))
&& wielded
&& GET_OBJ_TYPE(wielded) == ITEM_WEAPON
&& GET_OBJ_VAL(wielded, 3) < TYPE_TASER
&& GET_OBJ_VAL(wielded, 7)
&& GET_OBJ_VAL(wielded, 8)
&& GET_OBJ_VAL(wielded, 9) == GET_IDNUM(ch))
focus = TRUE;
else if (wielded) {
stop_fighting(ch);
return;
}
if (IS_PROJECT(ch) && (ch != vict) && PLR_FLAGGED(vict, PLR_PERCEIVE) &&
!PLR_FLAGGED(vict, PLR_KILLER) && !PLR_FLAGGED(vict, PLR_THIEF) &&
(!PRF_FLAGGED(ch, PRF_PKER) || !PRF_FLAGGED(vict, PRF_PKER)) &&
!PLR_FLAGGED(ch->desc->original, PLR_KILLER)) {
SET_BIT(PLR_FLAGS(ch->desc->original), PLR_KILLER);
sprintf(buf, "PC Killer bit set on %s (astral) for initiating attack on %s at %s.",
GET_NAME(ch->desc->original), GET_NAME(vict), world[vict->in_room].name);
mudlog(buf, ch, LOG_MISCLOG, TRUE);
send_to_char("If you want to be a PLAYER KILLER, so be it...\r\n", ch);
}
if (GET_POS(vict) <= POS_DEAD) {
log("SYSERR: Attempt to damage a corpse.");
return; /* -je, 7/7/92 */
}
if (wielded)
w_type = GET_OBJ_VAL(wielded, 3);
else {
if (ch->mob_specials.attack_type != 0)
w_type = ch->mob_specials.attack_type;
else w_type = TYPE_HIT;
}
if (((w_type == TYPE_HIT) || (w_type == TYPE_BLUDGEON) || (w_type == TYPE_PUNCH) ||
(w_type == TYPE_TASER) || (w_type == TYPE_CRUSH) || (w_type == TYPE_POUND)) &&
(GET_MENTAL(vict) >= 100))
is_physical = FALSE;
else is_physical = TRUE;
base_target = 4 + modify_target(ch);
if (!AWAKE(vict))
base_target -= 2;
if ((w_type != TYPE_HIT) && wielded) {
power = (GET_OBJ_VAL(wielded, 0) ? GET_OBJ_VAL(wielded, 0) : GET_STR(ch)) +
GET_OBJ_VAL(wielded, 2);
if (focus)
power += GET_OBJ_VAL(wielded, 8);
power -= GET_IMPACT(vict);
dam = MODERATE;
if (IS_SPIRIT(vict))
skill_total = GET_WIL(ch);
else if (GET_SKILL(ch, GET_OBJ_VAL(wielded, 4)) < 1) {
newskill = return_general(GET_OBJ_VAL(wielded, 4));
if (GET_SKILL(ch, newskill) < 1)
skill_total = reverse_web(ch, newskill, base_target);
else skill_total = GET_SKILL(ch, newskill);
} else skill_total = GET_SKILL(ch, GET_OBJ_VAL(wielded, 4));
} else {
power = GET_STR(ch) - GET_IMPACT(vict);
if (IS_PROJECT(ch) || PLR_FLAGGED(ch, PLR_PERCEIVE))
dam = LIGHT;
else dam = MODERATE;
if (IS_SPIRIT(vict))
skill_total = GET_WIL(ch);
else if (GET_SKILL(ch, SKILL_UNARMED_COMBAT) < 1) {
if (GET_SKILL(ch, SKILL_SORCERY) < 1) {
newskill = SKILL_UNARMED_COMBAT;
skill_total = reverse_web(ch, newskill, base_target);
} else skill_total = GET_SKILL(ch, SKILL_SORCERY);
} else skill_total = MAX(GET_SKILL(ch, SKILL_UNARMED_COMBAT),
GET_SKILL(ch, SKILL_SORCERY));
}
skill_total += (int)(GET_ASTRAL(ch) / 2);
if (power < 2) {
skill_total = MAX(0, skill_total - (2 - power));
power = 2;
}
if (AWAKE(vict))
attack_success = resisted_test(skill_total, base_target,
(int)(GET_ASTRAL(vict) / 2), power + modify_target(vict));
else attack_success = success_test(skill_total, base_target);
if (attack_success < 1) {
if (!AFF_FLAGGED(ch, AFF_COUNTER_ATT)) {
if ((GET_ASTRAL(vict) > 0) && (attack_success < 0)
&& FIGHTING(vict) == ch && GET_POS(vict) <= POS_SLEEPING) {
send_to_char(ch, "%s counters your attack!\r\n", GET_NAME(vict));
send_to_char(vict, "You counter %s's attack!\r\n", GET_NAME(ch));
SET_BIT(AFF_FLAGS(vict), AFF_COUNTER_ATT);
astral_fight(vict, ch);
}
return;
} else {
REMOVE_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
return;
}
} else if (AFF_FLAGGED(ch, AFF_COUNTER_ATT))
REMOVE_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
attack_success -= success_test(GET_BOD(vict), power);
dam = convert_damage(stage(attack_success, dam));
if (IS_PROJECT(ch) && (PLR_FLAGGED(ch->desc->original, PLR_KILLER) ||
PLR_FLAGGED(ch->desc->original, PLR_THIEF)))
dam = 0;
damage(ch, vict, dam, w_type, is_physical);
if (IS_PROJECT(vict) && dam > 0)
damage(vict->desc->original, vict->desc->original, dam, 0, is_physical);
}
void remove_throwing(struct char_data *ch)
{
struct obj_data *obj = NULL;
int i, pos, type;
for (pos = WEAR_WIELD; pos <= WEAR_HOLD; pos++)
if (GET_EQ(ch, pos)) {
type = GET_OBJ_VAL(GET_EQ(ch, pos), 3);
if (type == TYPE_SHURIKEN || type == TYPE_THROWING_KNIFE) {
extract_obj(unequip_char(ch, pos));
for (i = 0; i < NUM_WEARS; i++)
if (GET_EQ(ch, i) && GET_OBJ_TYPE(GET_EQ(ch, i)) == ITEM_QUIVER)
for (obj = GET_EQ(ch, i)->contains; obj; obj = obj->next_content)
if (GET_OBJ_TYPE(obj) == ITEM_WEAPON && GET_OBJ_VAL(obj, 3) == type) {
obj_from_obj(obj);
equip_char(ch, obj, pos);
return;
}
return;
}
}
}
void hit(struct char_data * ch, struct char_data * victim, int type)
{
char rbuf[MAX_STRING_LENGTH];
static struct obj_data *wielded;
static bool is_physical;
static bool melee;
static int base_target, power, w_type, damage_total;
struct obj_data *obj;
struct char_data *vict;
int attack_success = 0, attack_resist=0, skill_total = 1;
int newskill, successes = 0;
int room, nextroom, dir, distance, pos, range, dead = 0, hits = 0;
int vict_found, recoil=0, burst=0, recoil_comp=0;
int tsleep=0, tcansee=0, toffhand=0, ttwoweap=0, tsmartlink=0;
int tdistance=0, modtarget=0, tallergic=0, tsight=0;
if (IS_AFFECTED(ch, AFF_PETRIFY))
return;
// determine if attack is in Matrix
if (IS_SET(world[ch->in_room].room_flags, ROOM_MATRIX)) {
matrix_fight(ch, victim);
return;
}
if ((IS_ASTRAL(victim) && !IS_ASTRAL(ch) && !IS_DUAL(ch) &&
!PLR_FLAGGED(ch, PLR_PERCEIVE)) || (IS_ASTRAL(ch) &&
!IS_ASTRAL(victim) && !IS_DUAL(victim) && !PLR_FLAGGED(victim, PLR_PERCEIVE)))
return;
if ((IS_ASTRAL(victim) && CAN_SEE(ch, victim)) || (IS_ASTRAL(ch) &&
(IS_DUAL(victim) || PLR_FLAGGED(victim, PLR_PERCEIVE)))) {
astral_fight(ch, victim);
return;
}
for (pos = WEAR_WIELD; !dead && pos <= WEAR_HOLD; pos++)
{
if (GET_WIELDED(ch, pos - WEAR_WIELD))
{
if (!(wielded = GET_EQ(ch, pos)))
GET_WIELDED(ch, pos - WEAR_WIELD) = 0;
}
else
wielded = NULL;
if (pos == WEAR_HOLD && (type == TYPE_MELEE || !wielded))
continue;
else if (pos == WEAR_WIELD && !wielded && GET_WIELDED(ch, 1) &&
GET_EQ(ch, WEAR_HOLD))
continue;
// before you do anything, check to see if they have ammo
if (wielded && !has_ammo(ch, pos))
{
if (!FIGHTING(victim)
&& ch->in_room == victim->in_room
&& GET_POS(victim) > POS_STUNNED)
set_fighting(victim, ch);
hits++;
continue;
}
if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON &&
GET_OBJ_VAL(wielded, 3) >= TYPE_HAND_GRENADE &&
GET_OBJ_VAL(wielded, 3) <= TYPE_ROCKET && ch->in_room == victim->in_room)
continue;
if (ch->in_room != victim->in_room && !RANGE_OK(ch))
{
stop_fighting(ch);
return;
}
// determine attack type
if (wielded && (GET_OBJ_TYPE(wielded) == ITEM_WEAPON ||
GET_OBJ_TYPE(wielded) == ITEM_FIREWEAPON))
w_type = GET_OBJ_VAL(wielded, 3);
else if (IS_NPC(ch) && ch->mob_specials.attack_type != 0)
w_type = ch->mob_specials.attack_type;
else
w_type = TYPE_HIT;
/* determine if this attack does mental or physical damage */
if ((w_type == TYPE_HIT || w_type == TYPE_BLUDGEON || w_type == TYPE_PUNCH ||
w_type == TYPE_TASER || w_type == TYPE_CRUSH || w_type == TYPE_POUND) &&
GET_MENTAL(victim) >= 100)
is_physical = FALSE;
else
is_physical = TRUE;
/* determine if attacker is using melee or fire combat */
if (!IS_GUN(w_type))
melee = TRUE;
else
melee = FALSE;
if (type == TYPE_MELEE)
{
if (!melee)
{
wielded = GET_EQ(victim, WEAR_WIELD);
if (wielded && (GET_OBJ_TYPE(wielded) == ITEM_WEAPON ||
GET_OBJ_TYPE(wielded) == ITEM_FIREWEAPON))
w_type = GET_OBJ_VAL(wielded, 3);
else
{
if (IS_NPC(victim) && (victim->mob_specials.attack_type != 0))
w_type = victim->mob_specials.attack_type;
else w_type = TYPE_HIT;
}
damage(victim, ch, -1, w_type, TRUE);
return;
}
if ( GET_POS(victim) <= POS_SLEEPING )
{
send_to_char(victim, "%s counters your attack!\r\n", GET_NAME(ch));
send_to_char(ch, "You counter %s's attack!\r\n", GET_NAME(victim));
SET_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
}
}
if (wielded && IS_BURST(wielded))
{
if (GET_OBJ_VAL(wielded, 6) >= 2)
{
burst = 3;
GET_OBJ_VAL(wielded, 6) -= 2;
}
else if (GET_OBJ_VAL(wielded, 6) == 1)
{
burst = 2;
GET_OBJ_VAL(wielded, 6)--;
}
else
burst = 0;
}
recoil_comp = check_recoil(ch, wielded);
recoil = MAX(0, burst - recoil_comp);
/* lower target number for victim being asleep */
if (!AWAKE(victim))
tsleep = -2;
if (!CAN_SEE(ch, victim))
tcansee = 4;
if (pos == WEAR_HOLD)
toffhand = 1;
// wielding two weapons
if (GET_WIELDED(ch, 0) && GET_WIELDED(ch, 1))
ttwoweap = 1;
else if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON &&
GET_OBJ_VAL(wielded, 3) >= TYPE_PISTOL)
tsmartlink = 0 - check_smartlink(ch, wielded);
if (ch->in_room != victim->in_room)
{
vict_found = FALSE;
if (wielded && IS_RANGED(wielded))
{
range = MIN(find_sight(ch), find_weapon_range(ch, GET_EQ(ch, pos)));
for (dir = 0; dir < (NUM_OF_DIRS - 1) && !vict_found; dir++)
{
room = ch->in_room;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else
nextroom = NOWHERE;
for (distance = 1; (nextroom != NOWHERE) && (distance <= range) &&
!vict_found; distance++)
{
for (vict = world[nextroom].people; vict;
vict = vict->next_in_room)
if (vict == victim)
{
tdistance += 2 * distance;
// Too powerful with these.
#if 0
if (AFF_FLAGGED(ch, AFF_VISION_MAG_3))
tsight = 0 - MIN(6, tdistance);
else if (AFF_FLAGGED(ch, AFF_VISION_MAG_2))
tsight = 0 - MIN(4, tdistance);
else if (AFF_FLAGGED(ch, AFF_VISION_MAG_1))
tsight = 0 - MIN(2, tdistance);
#endif
vict_found = TRUE;
break;
}
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else
nextroom = NOWHERE;
}
}
}
if (!vict_found)
continue;
}
if (wielded && GET_OBJ_VAL(wielded, 3) < TYPE_HAND_GRENADE && !IS_NPC(ch) &&
!GET_EQ(ch, WEAR_HANDS) && is_allergic(ch, GET_OBJ_RENT(wielded)) == 2)
tallergic = 2;
if (1)
{
sprintf( rbuf,
"Targ: (b/r %d-%d) ",
burst, recoil_comp );
modtarget = modify_target_rbuf(ch, rbuf);
#if 0
buf_mod( rbuf, "MT", modtarget );
#endif
buf_mod( rbuf, "Recoil", recoil);
buf_mod( rbuf, "Sleep", tsleep);
buf_mod( rbuf, "Cansee", tcansee);
buf_mod( rbuf, "Offhand", toffhand);
buf_mod( rbuf, "2Weap", ttwoweap);
buf_mod( rbuf, "Smart", tsmartlink);
buf_mod( rbuf, "Distance", tdistance);
buf_mod( rbuf, "Sight", tsight);
buf_mod( rbuf, "Allergic", tallergic);
// set the base target number and modify
base_target = 4 + modtarget + recoil + tsleep + tcansee
+ toffhand + ttwoweap + tsmartlink + tdistance + tsight
+ tallergic;
buf_roll( rbuf, "Total", base_target);
act( rbuf, 1, ch, NULL, NULL, TO_ROLLS );
}
damage_total = 0;
hits++;
/* find power, staging, and initial damage */
if (w_type != TYPE_HIT && w_type != TYPE_PUNCH && wielded)
{
power = (GET_OBJ_VAL(wielded, 0) ? GET_OBJ_VAL(wielded, 0) :
GET_STR(ch)) + GET_OBJ_VAL(wielded, 2) + burst;
// this is how armor now works
if (w_type >= TYPE_PISTOL)
power -= GET_BALLISTIC(victim);
else
power -= GET_IMPACT(victim);
damage_total = GET_OBJ_VAL(wielded, 1) + (burst == 3 ? 1 : 0);
if (IS_SPIRIT(victim))
{
skill_total = GET_WIL(ch);
}
else if (GET_SKILL(ch, GET_OBJ_VAL(wielded, 4)) < 1)
{
newskill = return_general(GET_OBJ_VAL(wielded, 4));
if (GET_SKILL(ch, newskill) < 1)
skill_total = reverse_web(ch, newskill, base_target);
else
skill_total = GET_SKILL(ch, newskill);
}
else
{
skill_total = GET_SKILL(ch, GET_OBJ_VAL(wielded, 4));
}
if (w_type < TYPE_TASER
&& GET_OBJ_VAL(wielded, 7)
&& GET_OBJ_VAL(wielded, 8)
&& return_general(GET_OBJ_VAL(wielded, 4)) == SKILL_ARMED_COMBAT
&& GET_OBJ_VAL(wielded, 9) == (IS_NPC(ch) ? -1 : GET_IDNUM(ch)))
skill_total += GET_OBJ_VAL(wielded, 8);
}
else
{ // fists
power = GET_STR(ch) - GET_IMPACT(victim);
if ((IS_NPC(ch) || GET_TRADITION(ch) == TRAD_ADEPT) &&
GET_SKILL(ch, SKILL_KILL_HANDS) > 0)
{
damage_total = GET_SKILL(ch, SKILL_KILL_HANDS);
is_physical = TRUE;
}
else
{
for (obj = ch->cyberware;
obj && !damage_total;
obj = obj->next_content)
{
switch (GET_OBJ_VAL(obj, 2))
{
case 19:
damage_total = LIGHT;
is_physical = TRUE;
w_type = TYPE_SLASH;
break;
case 21:
is_physical = TRUE;
w_type = TYPE_SLASH;
damage_total = MODERATE;
break;
case 29:
power += GET_OBJ_VAL(obj, 0);
damage_total = MODERATE;
is_physical = TRUE;
break;
}
}
}
if (!damage_total)
damage_total = MODERATE;
if (IS_SPIRIT(victim))
{
skill_total = GET_WIL(ch);
}
else if (GET_SKILL(ch, SKILL_UNARMED_COMBAT) < 1)
{
newskill = SKILL_UNARMED_COMBAT;
skill_total = reverse_web(ch, newskill, base_target);
}
else
{
skill_total = GET_SKILL(ch, SKILL_UNARMED_COMBAT);
}
}
if (IS_SPIRIT(victim)
&& wielded
&& ((GET_OBJ_TYPE(wielded) == ITEM_WEAPON
&& w_type >= TYPE_PISTOL)
|| (GET_OBJ_TYPE(wielded) == ITEM_FIREWEAPON
&& GET_OBJ_VAL(wielded, 5) == 1)))
power -= (2 * GET_LEVEL(victim)) - MAX(GET_BALLISTIC(victim),
GET_IMPACT(victim));
if (wielded
&& GET_OBJ_VAL(wielded, 3) < TYPE_HAND_GRENADE
&& !IS_NPC(victim)
&& is_allergic(victim, GET_OBJ_RENT(wielded)) == 2)
power += 2;
// add offense (from combat pool) to dice pool for attacking--divided
// by the number of folks you are attacking
if (!IS_SPIRIT(victim))
skill_total += MAX(0,GET_OFFENSE(ch)); // GET_NUM_FIGHTING(ch);
#if 0
// I do this because it's silly that if you have enough armor to reduce
// the power of a weapon below 2, that the armor no longer counts...
// seems to me it still should, so I'm making it count at least a little
if (power < 2)
{
skill_total = MAX(0, skill_total - (2 - power));
power = 2;
}
#endif
// find # of attack successes, allow defense if victim is awake
attack_success = success_test(skill_total, base_target);
modtarget = modify_target(victim);
if (AWAKE(victim))
{
attack_resist = success_test(GET_DEFENSE(victim), power + modtarget);
}
else
{
// Always hit !awake victims
attack_success = MAX( attack_success, 1 );
}
sprintf(rbuf,"Fight: I %2d, Ski %d, Targ %d, Succ %d. %sDef %d, Targ %d+%d, Succ %d. L:%d",
GET_INIT_ROLL(ch),
skill_total, base_target, attack_success,
AWAKE(victim) ? "" : "!A ",
GET_DEFENSE(victim), power, modtarget, attack_resist,
damage_total);
act(rbuf, FALSE, ch, NULL, NULL, TO_ROLLS);
attack_success -= attack_resist;
/* if there were no successes, fighter missed from lack of skill or dodge */
/* send a -1 damage to indicate complete miss */
if (ch->in_room != victim->in_room && attack_success < 1)
{
if (wielded && GET_WSPEC(wielded) != NULL)
{
if (!(GET_WSPEC(wielded) (ch, victim, wielded, -1)))
dead = damage(ch, victim, -1, w_type, is_physical);
else if (GET_POS(victim) == POS_DEAD || GET_POS(ch) == POS_DEAD)
dead = TRUE;
}
else
dead = damage(ch, victim, -1, w_type, is_physical);
remove_throwing(ch);
continue;
}
else if (attack_success < 1)
{
if (!AFF_FLAGGED(ch, AFF_COUNTER_ATT))
{
if ((GET_DEFENSE(victim) > 0)
&& melee
&& FIGHTING(victim) == ch
&& GET_POS(victim) == POS_FIGHTING )
{
if ( type == TYPE_MELEE )
hit(victim, ch, TYPE_HIT);
/*hit(victim, ch, TYPE_MELEE);*/
}
else if (wielded && GET_WSPEC(wielded) != NULL)
{
if (!(GET_WSPEC(wielded) (ch, victim, wielded, -1)))
dead = damage(ch, victim, -1, w_type, is_physical);
else if (GET_POS(victim) == POS_DEAD || GET_POS(ch) == POS_DEAD)
dead = TRUE;
}
else
{
dead = damage(ch, victim, -1, w_type, is_physical);
}
remove_throwing(ch);
continue;
}
else
{
if (wielded && GET_WSPEC(wielded) != NULL)
{
if (!(GET_WSPEC(wielded) (ch, victim, wielded, -1)))
dead = damage(ch, victim, -1, w_type, is_physical);
else if (GET_POS(victim) == POS_DEAD || GET_POS(ch) == POS_DEAD)
dead = TRUE;
}
else
dead = damage(ch, victim, -1, w_type, is_physical);
REMOVE_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
remove_throwing(ch);
continue;
}
}
else if (AFF_FLAGGED(ch, AFF_COUNTER_ATT))
REMOVE_BIT(AFF_FLAGS(ch), AFF_COUNTER_ATT);
int bod_success=0;
// then subtract successes from body test of victim if they didn't dodge
if (IS_SPIRIT(ch) && !IS_NPC(victim) && (GET_TRADITION(victim) == TRAD_HERMETIC ||
GET_TRADITION(victim) == TRAD_SHAMANIC))
bod_success = success_test(MAX(GET_BOD(victim), GET_SKILL(victim, SKILL_CONJURING)),
power);
else
bod_success = success_test(GET_BOD(victim), power);
attack_success -= bod_success;
int old_damage_total = damage_total;
int staged_damage = stage(attack_success, damage_total);
damage_total = convert_damage(staged_damage);
sprintf(rbuf, "Fight: Bod %d, Pow %d, Suc %d. %d(%d)->%d. %d%c.",
GET_BOD(victim), power, bod_success,
old_damage_total, attack_success, staged_damage,
damage_total,
is_physical ? 'P' : 'M');
act(rbuf, FALSE, ch, NULL, NULL, TO_ROLLS);
if (wielded && GET_WSPEC(wielded) != NULL)
{
if (!(GET_WSPEC(wielded) (ch, victim, wielded, -1)))
dead = damage(ch, victim, damage_total, w_type, is_physical);
else if (GET_POS(victim) == POS_DEAD || GET_POS(ch) == POS_DEAD)
dead = TRUE;
}
else
dead = damage(ch, victim, damage_total, w_type, is_physical);
remove_throwing(ch);
}
if (!hits)
stop_fighting(ch);
}
int find_sight(struct char_data *ch)
{
int sight;
if (IS_PERSONA(ch))
return 1;
if ((!IS_NPC(ch) && access_level(ch, LVL_OWNER)) || AFF_FLAGGED(ch, AFF_VISION_MAG_3))
sight = 4;
else if (AFF_FLAGGED(ch, AFF_VISION_MAG_2))
sight = 3;
else if (AFF_FLAGGED(ch, AFF_VISION_MAG_1))
sight = 2;
else sight = 1;
/* add more weather conditions here to affect scan */
if (SECT(ch->in_room) != SECT_INSIDE && (IS_NPC(ch) || !access_level(ch, LVL_OWNER)))
switch (weather_info.sky) {
case SKY_RAINING:
sight -= 1;
break;
case SKY_LIGHTNING:
sight -= 2;
break;
}
sight = MIN(4, MAX(1, sight));
return sight;
}
int find_weapon_range(struct char_data *ch, struct obj_data *weapon)
{
int temp;
if ( weapon == NULL )
return 0;
if (GET_OBJ_TYPE(weapon) == ITEM_FIREWEAPON) {
temp = MIN(MAX(1, ((int)(GET_STR(ch)/3))), 4);
return temp;
}
switch(GET_OBJ_VAL(weapon, 3)) {
case TYPE_SHURIKEN: case TYPE_THROWING_KNIFE: case TYPE_HAND_GRENADE:
case TYPE_PISTOL: case TYPE_SHOTGUN: case TYPE_BLAST:
return 1;
case TYPE_GRENADE_LAUNCHER: case TYPE_BIFURCATE:
return 2;
case TYPE_RIFLE: case TYPE_MACHINE_GUN:
return 3;
case TYPE_CANNON: case TYPE_ROCKET:
return 4;
default:
return 0;
}
}
void ranged_response(struct char_data *ch, struct char_data *vict)
{
int range, sight, distance, dir, room, nextroom = NOWHERE, found = 0;
struct char_data *temp;
if (!vict || !IS_NPC(vict) || ch->in_room == vict->in_room ||
GET_POS(vict) <= POS_STUNNED)
return;
if (GET_POS(vict) < POS_FIGHTING)
GET_POS(vict) = POS_STANDING;
if (IS_SET(MOB_FLAGS(vict), MOB_WIMPY))
do_flee(vict, "", 0, 0);
else if (RANGE_OK(vict) && !FIGHTING(vict)) {
sight = find_sight(vict);
range = find_weapon_range(vict, GET_EQ(vict, WEAR_WIELD));
for (dir = 0; dir < (NUM_OF_DIRS - 1) && !found; dir++) {
room = vict->in_room;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
for (distance = 1; !found && ((nextroom != NOWHERE) && (distance <= 4)); distance++) {
for (temp = world[nextroom].people; !found && temp; temp = temp->next_in_room)
if (temp == ch && (distance > range || distance > sight)) {
act("$n runs after $s distant attacker.", TRUE, vict, 0, 0, TO_ROOM);
act("You charge after $N.", FALSE, vict, 0, ch, TO_CHAR);
char_from_room(vict);
char_to_room(vict, ch->in_room);
set_fighting(vict, ch);
found = 1;
act("$n arrives in a rush of fury, immediately attacking $N!",
TRUE, vict, 0, ch, TO_NOTVICT);
act("$n arrives in a rush of fury, rushing straight towards you!",
FALSE, vict, 0, ch, TO_VICT);
}
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
}
if (!found)
set_fighting(vict, ch);
} else if (!FIGHTING(vict)) {
act("$n runs after $s distant attacker.", TRUE, vict, 0, 0, TO_ROOM);
act("You charge after $N.", FALSE, vict, 0, ch, TO_CHAR);
char_from_room(vict);
char_to_room(vict, ch->in_room);
set_fighting(vict, ch);
act("$n arrives in a rush of fury, immediately attacking $N!", TRUE, vict, 0, ch, TO_NOTVICT);
act("$n arrives in a rush of fury, rushing straight towards you!", FALSE, vict, 0, ch, TO_VICT);
}
return;
}
void explode(struct char_data *ch, struct obj_data *weapon, int room)
{
int damage_total, exp, i, power, level;
struct char_data *victim, *next_vict;
struct obj_data *obj, *next;
power = GET_OBJ_VAL(weapon, 0);
level = GET_OBJ_VAL(weapon, 1);
extract_obj(weapon);
if (world[room].people) {
act("The room is lit by an explosion!", FALSE, world[room].people, 0, 0, TO_ROOM);
act("The room is lit by an explosion!", FALSE, world[room].people, 0, 0, TO_CHAR);
}
for (obj = world[room].contents; obj; obj = next) {
next = obj->next_content;
damage_obj(NULL, obj, level * 2 + (int)(power / 6), DAMOBJ_EXPLODE);
}
for (victim = world[room].people; victim; victim = next_vict) {
next_vict = victim->next_in_room;
if (IS_ASTRAL(victim))
continue;
act("You are hit by the flames!", FALSE, victim, 0, 0, TO_CHAR);
for (obj = victim->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < 50)
damage_obj(NULL, obj, level * 2 + (int)(power / 6), DAMOBJ_EXPLODE);
}
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(victim, i) && number(1, 100) < 100)
damage_obj(NULL, GET_EQ(victim, i), level * 2 + (int)(power / 6),
DAMOBJ_EXPLODE);
if (IS_NPC(victim) && !FIGHTING(victim)) {
GET_DEFENSE(victim) = GET_COMBAT(victim);
GET_OFFENSE(victim) = 0;
}
damage_total =
convert_damage(stage((number(1, 3) - success_test(GET_BOD(victim) +
GET_DEFENSE(victim), MAX(2, (power -
(int)(GET_IMPACT(victim) / 2))) + modify_target(victim))),
level));
if (!ch)
damage(victim, victim, damage_total, TYPE_EXPLOSION, PHYSICAL);
else damage(ch, victim, damage_total, TYPE_EXPLOSION, PHYSICAL);
}
for (i = 0; i < (NUM_OF_DIRS - 1); i++)
if (world[room].dir_option[i] && IS_SET(world[room].dir_option[i]->exit_info, EX_CLOSED))
damage_door(NULL, room, i, level * 2 + (int)(power / 6), DAMOBJ_EXPLODE);
}
void target_explode(struct char_data *ch, struct obj_data *weapon, int room, int mode)
{
int damage_total, exp = 0, i;
struct char_data *victim, *next_vict;
struct obj_data *obj, *next;
sprintf(buf, "The room is lit by a%s explosion!",
(GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET ? " massive" : "n"));
if (world[room].people) {
act(buf, FALSE, world[room].people, 0, 0, TO_ROOM);
act(buf, FALSE, world[room].people, 0, 0, TO_CHAR);
}
for (obj = world[room].contents; obj; obj = next) {
next = obj->next_content;
damage_obj(NULL, obj, GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_EXPLODE);
}
for (victim = world[room].people; victim; victim = next_vict) {
next_vict = victim->next_in_room;
if (IS_ASTRAL(victim))
continue;
act("You are hit by the flames!", FALSE, victim, 0, 0, TO_CHAR);
for (obj = victim->carrying; obj; obj = next) {
next = obj->next_content;
if (number(1, 100) < 50)
damage_obj(NULL, obj, GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_EXPLODE);
}
for (i = 0; i < (NUM_WEARS - 1); i++)
if (GET_EQ(victim, i) && number(1, 100) < 100)
damage_obj(NULL, GET_EQ(victim, i), GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_EXPLODE);
if (IS_NPC(victim) && !FIGHTING(victim)) {
GET_DEFENSE(victim) = GET_COMBAT(victim);
GET_OFFENSE(victim) = 0;
}
if (!mode) {
if (GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET)
damage_total = convert_damage(stage((number(3,6) - success_test(GET_BOD(victim) + GET_DEFENSE(victim),
MAX(2, (GET_OBJ_VAL(weapon, 0) - (int)(GET_IMPACT(victim) / 2))) +
modify_target(victim))), GET_OBJ_VAL(weapon, 1)));
else damage_total = convert_damage(stage((number(2,5) - success_test(GET_BOD(victim) + GET_DEFENSE(victim),
MAX(2, (GET_OBJ_VAL(weapon, 0) - (int)(GET_IMPACT(victim) / 2))) +
modify_target(victim))), GET_OBJ_VAL(weapon, 1)));
} else damage_total = convert_damage(stage((number(2,5) - success_test(GET_BOD(victim) + GET_DEFENSE(victim),
MAX(2, (GET_OBJ_VAL(weapon, 0) - 4 - (int)(GET_IMPACT(victim) / 2))) +
modify_target(victim))), GET_OBJ_VAL(weapon, 1) - 1));
damage(ch, victim, damage_total, TYPE_EXPLOSION, PHYSICAL);
}
if (!mode)
for (i = 0; i < (NUM_OF_DIRS - 1); i++)
if (world[room].dir_option[i] &&
IS_SET(world[room].dir_option[i]->exit_info, EX_CLOSED))
damage_door(NULL, room, i, GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_EXPLODE);
}
void range_combat(struct char_data *ch, char *target, struct obj_data *weapon,
int range, int dir)
{
int room, nextroom, distance, sight, temp, temp2, left, right, scatter[4];
int power, level;
struct char_data *vict = NULL;
if (ROOM_FLAGGED(ch->in_room, ROOM_PEACEFUL)) {
send_to_char("This room just has a peaceful, easy feeling...\r\n", ch);
return;
}
sight = find_sight(ch);
if (CAN_GO2(ch->in_room, dir))
nextroom = EXIT2(ch->in_room, dir)->to_room;
else nextroom = NOWHERE;
if (GET_OBJ_TYPE(weapon) == ITEM_WEAPON && GET_OBJ_VAL(weapon, 3) == TYPE_HAND_GRENADE) {
if (nextroom == NOWHERE) {
send_to_char("There seems to be something in the way...\r\n", ch);
return;
}
if (IS_SET(ROOM_FLAGS(nextroom), ROOM_PEACEFUL)) {
send_to_char("Nah - leave them in peace.\r\n", ch);
return;
}
power = GET_OBJ_VAL(weapon, 0);
level = GET_OBJ_VAL(weapon, 1);
if (FIGHTING(ch))
stop_fighting(ch);
act("You pull the pin and throw $p!", FALSE, ch, weapon, 0, TO_CHAR);
act("$n pulls the pin and throws $p!", FALSE, ch, weapon, 0, TO_ROOM);
WAIT_STATE(ch, PULSE_VIOLENCE);
if (!GET_SKILL(ch, SKILL_NONAERODYNAMIC))
temp = MAX(1, GET_SKILL(ch, SKILL_THROWING_WEAPONS));
else temp = GET_SKILL(ch, SKILL_NONAERODYNAMIC);
if (!number(0, 19)) {
sprintf(buf, "A defective grenade lands on the floor.\r\n");
if (world[nextroom].people) {
act(buf, FALSE, world[nextroom].people, 0, 0, TO_ROOM);
act(buf, FALSE, world[nextroom].people, 0, 0, TO_CHAR);
}
return;
} else if (!success_test(temp+GET_OFFENSE(ch), 5)) {
left = -1;
right = -1;
if (dir < UP) {
if ((dir - 1) < NORTH)
left = NORTHWEST;
else left = dir - 1;
if ((dir + 1) > NORTHWEST)
right = NORTH;
else right = dir + 1;
}
scatter[0] = ch->in_room;
if (left > 0 && CAN_GO(ch, left))
scatter[1] = EXIT(ch, left)->to_room;
else scatter[1] = NOWHERE;
if (right > 0 && CAN_GO(ch, right))
scatter[2] = EXIT(ch, right)->to_room;
else scatter[2] = NOWHERE;
if (CAN_GO2(nextroom, dir))
scatter[3] = EXIT2(nextroom, dir)->to_room;
else scatter[3] = NOWHERE;
for (temp = 0, temp2 = 0; temp2 < 4; temp2++)
if (scatter[temp2] != NOWHERE)
temp++;
for (temp2 = 0; temp2 < 4; temp2++)
if (scatter[temp2] != NOWHERE && !number(0, temp-1)) {
if (temp2 == 0) {
act("$p deflects due to $n's poor accuracy, landing at $s feet.",
FALSE, ch, weapon, 0, TO_ROOM);
sprintf(buf, "Your realize your aim must've been off-target as "
"$p lands at your feet.");
} else if (temp2 == 3)
sprintf(buf, "Your aim is slightly off, going past its target.");
else sprintf(buf, "Your aim is slightly off, and $p veers to the %s.",
dirs[temp2 == 1 ? left : right]);
act(buf, FALSE, ch, weapon, 0, TO_CHAR);
explode(ch, weapon, scatter[temp2]);
return;
}
}
explode(ch, weapon, nextroom);
return;
}
for (distance = 1; ((nextroom != NOWHERE) && (distance <= sight)); distance++) {
if ((vict = get_char_room(target, nextroom)) && vict != ch &&
CAN_SEE(ch, vict))
break;
vict = NULL;
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
if (vict) {
if (vict == FIGHTING(ch)) {
send_to_char("You're doing the best you can!\r\n", ch);
return;
} else if (IS_SET(ROOM_FLAGS(vict->in_room), ROOM_PEACEFUL)) {
send_to_char("Nah - leave them in peace.\r\n", ch);
return;
} else if (distance > range) {
act("$N seems to be out of $p's range.", FALSE, ch, weapon, vict, TO_CHAR);
return;
} else if (!ok_damage_shopkeeper(ch, vict)) {
send_to_char("Maybe that's not such a good idea.\r\n", ch);
return;
}
if (GET_OBJ_TYPE(weapon) == ITEM_FIREWEAPON) {
act("$n draws $p and fires into the distance!", TRUE, ch, weapon, 0, TO_ROOM);
act("You draw $p, aim it at $N and fire!", FALSE, ch, weapon, vict, TO_CHAR);
check_killer(ch, vict);
if (IS_NPC(vict) && !IS_PROJECT(vict) && !FIGHTING(vict)) {
GET_DEFENSE(vict) = GET_COMBAT(vict);
GET_OFFENSE(vict) = 0;
}
if (FIGHTING(ch))
stop_fighting(ch);
hit(ch, vict, TYPE_UNDEFINED);
WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
return;
}
switch(GET_OBJ_VAL(weapon, 3)) {
case TYPE_SHURIKEN: case TYPE_THROWING_KNIFE:
act("$n throws $p at something in the distance!", TRUE, ch, weapon, 0, TO_ROOM);
act("You throw $p at $N!", FALSE, ch, weapon, vict, TO_CHAR);
break;
default:
act("$n aims $p and fires into the distance!", TRUE, ch, weapon, 0, TO_ROOM);
act("You aim $p at $N and fire!", FALSE, ch, weapon, vict, TO_CHAR);
break;
}
if (GET_OBJ_VAL(weapon, 3) >= TYPE_PISTOL
|| GET_OBJ_VAL(weapon, 3) == TYPE_SHURIKEN
|| GET_OBJ_VAL(weapon, 3) == TYPE_THROWING_KNIFE)
{
check_killer(ch, vict);
if (GET_OBJ_VAL(weapon, 3) < TYPE_PISTOL
|| GET_OBJ_VAL(weapon, 6) > 0)
{
if (IS_NPC(vict) && !IS_PROJECT(vict) && !FIGHTING(vict))
{
GET_DEFENSE(vict) = GET_COMBAT(vict);
GET_OFFENSE(vict) = 0;
}
if (FIGHTING(ch))
stop_fighting(ch);
hit(ch, vict, TYPE_UNDEFINED);
ranged_response(ch, vict);
}
else
send_to_char("*Click*\r\n", ch);
WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
}
else
{
if (!has_ammo(ch, weapon->worn_on))
return;
stop_fighting(ch);
if (GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET)
{
if (!GET_SKILL(ch, SKILL_MISSILE_LAUNCHERS))
temp = MAX(1, GET_SKILL(ch, SKILL_GUNNERY));
else
temp = GET_SKILL(ch, SKILL_MISSILE_LAUNCHERS);
}
else
{
if (!GET_SKILL(ch, SKILL_GRENADE_LAUNCHERS))
temp = MAX(1, GET_SKILL(ch, SKILL_FIREARMS));
else
temp = GET_SKILL(ch, SKILL_GRENADE_LAUNCHERS);
}
WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
if (!number(0,49)) {
sprintf(buf, "A defective %s lands on the floor.",
(GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET ? "rocket" : "grenade"));
act(buf, TRUE, vict, 0, 0, TO_ROOM);
act(buf, TRUE, vict, 0, 0, TO_CHAR);
return;
}
else if (!success_test(temp + GET_OFFENSE(ch), 6)) {
left = -1;
right = -1;
if (dir < UP) {
if ((dir - 1) < NORTH)
left = NORTHWEST;
else left = dir - 1;
if ((dir + 1) > NORTHWEST)
right = NORTH;
else right = dir + 1;
}
scatter[0] = ch->in_room;
if (left > 0 && CAN_GO(ch, left))
scatter[1] = EXIT(ch, left)->to_room;
else scatter[1] = NOWHERE;
if (right > 0 && CAN_GO(ch, right))
scatter[2] = EXIT(ch, right)->to_room;
else scatter[2] = NOWHERE;
if (CAN_GO2(nextroom, dir))
scatter[3] = EXIT2(nextroom, dir)->to_room;
else scatter[3] = NOWHERE;
for (temp = 0, temp2 = 0; temp2 < 4; temp2++)
if (scatter[temp2] != NOWHERE)
temp++;
for (temp2 = 0; temp2 < 4; temp2++)
if (scatter[temp2] != NOWHERE && !number(0, temp-1)) {
if (temp2 == 0) {
act("$p's trajectory is slightly off...", FALSE, ch, weapon, 0, TO_ROOM);
sprintf(buf, "Your arm jerks just before you fire...");
} else if (temp2 == 3)
sprintf(buf, "Your aim is slightly off, going past $N.");
else sprintf(buf, "Your aim is slightly off, the %s veering to the %s.",
(GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET ? "rocket" : "grenade"),
dirs[temp2 == 1 ? left : right]);
act(buf, FALSE, ch, weapon, vict, TO_CHAR);
target_explode(ch, weapon, scatter[temp2], 0);
if (GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET)
for (temp = 0; temp < (NUM_OF_DIRS - 1); temp++)
if (CAN_GO2(scatter[temp2], temp))
target_explode(ch, weapon, EXIT2(scatter[temp2], temp)->to_room, 1);
return;
}
}
temp2 = vict->in_room;
target_explode(ch, weapon, vict->in_room, 0);
if (GET_OBJ_VAL(weapon, 3) == TYPE_ROCKET)
for (temp = 0; temp < (NUM_OF_DIRS - 1); temp++)
if (CAN_GO2(temp2, temp))
target_explode(ch, weapon, EXIT2(temp2, temp)->to_room, 1);
return;
}
return;
}
bool found = FALSE;
if (CAN_GO2(ch->in_room, dir))
nextroom = EXIT2(ch->in_room, dir)->to_room;
else nextroom = NOWHERE;
// now we search for a door by the given name
for (distance = 1; nextroom != NOWHERE && distance <= sight; distance++) {
if (EXIT2(nextroom, dir) && EXIT2(nextroom, dir)->keyword &&
isname(target, EXIT2(nextroom, dir)->keyword) &&
!IS_SET(EXIT2(nextroom, dir)->exit_info, EX_DESTROYED) &&
(PRF_FLAGGED(ch, PRF_HOLYLIGHT) || IS_AFFECTED(ch, AFF_INFRAVISION) ||
(IS_LIGHT(nextroom) || (IS_LOW(nextroom) &&
IS_AFFECTED(ch, AFF_LOW_LIGHT))))) {
found = TRUE;
break;
}
room = nextroom;
if (CAN_GO2(room, dir))
nextroom = EXIT2(room, dir)->to_room;
else nextroom = NOWHERE;
}
if (found) {
if (FIGHTING(ch)) {
send_to_char("Maybe you'd better wait...\r\n", ch);
return;
} else if (!IS_SET(EXIT2(nextroom, dir)->exit_info, EX_CLOSED) && isname(target, EXIT2(nextroom, dir)->keyword) ) {
send_to_char("You can only damage closed doors!\r\n", ch);
return;
} else if (IS_SET(ROOM_FLAGS(nextroom), ROOM_PEACEFUL)) {
send_to_char("Nah - leave it in peace.\r\n", ch);
return;
} else if (distance > range) {
send_to_char(ch, "The %s seems to be out of %s's range.\r\n",
CAP(fname(EXIT2(nextroom, dir)->keyword)),
weapon->short_description);
return;
}
if (GET_OBJ_TYPE(weapon) == ITEM_FIREWEAPON) {
act("$n draws $p and fires into the distance!", TRUE, ch, weapon, 0, TO_ROOM);
sprintf(buf, "You draw $p, aim it at the %s and fire!",
fname(EXIT2(nextroom, dir)->keyword));
act(buf, FALSE, ch, weapon, vict, TO_CHAR);
} else {
switch(GET_OBJ_VAL(weapon, 3)) {
case TYPE_SHURIKEN: case TYPE_THROWING_KNIFE:
act("$n throws $p at something in the distance!", TRUE, ch, weapon, 0, TO_ROOM);
sprintf(buf, "You throw $p at the %s!", fname(EXIT2(nextroom, dir)->keyword));
act(buf, FALSE, ch, weapon, vict, TO_CHAR);
break;
default:
act("$n aims $p and fires into the distance!", TRUE, ch, weapon, 0, TO_ROOM);
sprintf(buf, "You aim $p at the %s and fire!",
fname(EXIT2(nextroom, dir)->keyword));
act(buf, FALSE, ch, weapon, vict, TO_CHAR);
break;
}
if (GET_OBJ_VAL(weapon, 3) >= TYPE_PISTOL)
if (!has_ammo(ch, weapon->worn_on))
return;
}
switch (GET_OBJ_VAL(weapon, 3)) {
case TYPE_SHURIKEN: case TYPE_THROWING_KNIFE: case TYPE_ARROW:
damage_door(ch, nextroom, dir, GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_PIERCE);
break;
case TYPE_GRENADE_LAUNCHER:
target_explode(ch, weapon, nextroom, 0);
break;
case TYPE_ROCKET:
target_explode(ch, weapon, nextroom, 0);
for (temp = 0; temp < (NUM_OF_DIRS - 1); temp++)
if (CAN_GO2(nextroom, temp))
target_explode(ch, weapon, EXIT2(nextroom, temp)->to_room, 1);
break;
default:
damage_door(ch, nextroom, dir, GET_OBJ_VAL(weapon, 1) * 2 +
(int)(GET_OBJ_VAL(weapon, 0) / 6), DAMOBJ_PROJECTILE);
break;
}
WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
return;
}
sprintf(buf, "You can't see any %s there.\r\n", target);
send_to_char(buf, ch);
return;
}
void roll_individual_initiative(struct char_data *ch)
{
if (AWAKE(ch)) {
if (IS_PERSONA(ch))
GET_INIT_ROLL(ch) = MIN(39, (dice(1 + GET_INIT_DICE(ch), 6) + GET_REA(ch)));
else if (IS_IC(ch)) {
switch(world[ch->in_room].sector_type) {
case SECT_GREEN:
GET_INIT_ROLL(ch) = 5 + GET_LEVEL(ch);
break;
case SECT_ORANGE:
GET_INIT_ROLL(ch) = 7 + GET_LEVEL(ch);
break;
case SECT_RED:
GET_INIT_ROLL(ch) = 9 + GET_LEVEL(ch);
break;
case SECT_BLACK:
GET_INIT_ROLL(ch) = 10 + GET_LEVEL(ch);
break;
default:
GET_INIT_ROLL(ch) = 0;
break;
}
}
else
GET_INIT_ROLL(ch) = MIN(39, (dice(1 + GET_INIT_DICE(ch), 6) + GET_REA(ch)));
if (AFF_FLAGGED(ch, AFF_ACTION)) {
GET_INIT_ROLL(ch) -= 10;
REMOVE_BIT(AFF_FLAGS(ch), AFF_ACTION);
}
}
if (1)
{
char rbuf[MAX_STRING_LENGTH];
sprintf(rbuf,"Init: %2d %s",
GET_INIT_ROLL(ch), GET_NAME(ch));
act(rbuf,TRUE,ch,NULL,NULL,TO_ROLLS);
}
}
void decide_combat_pool(void)
{
struct char_data *ch;
for (ch = combat_list; ch; ch = ch->next_fighting) {
if (ch->bioware)
check_adrenaline(ch, 0);
if (IS_NPC(ch) && !IS_PROJECT(ch) && !IS_PERSONA(ch) && FIGHTING(ch)) {
if (GET_INIT_ROLL(ch) == GET_INIT_ROLL(FIGHTING(ch)))
GET_OFFENSE(ch) = GET_COMBAT(ch) >> 1;
else if (GET_INIT_ROLL(ch) > GET_INIT_ROLL(FIGHTING(ch)))
GET_OFFENSE(ch) = (int)(GET_COMBAT(ch) * .75);
else GET_OFFENSE(ch) = (int)(GET_COMBAT(ch) / 4);
GET_DEFENSE(ch) = GET_COMBAT(ch) - GET_OFFENSE(ch);
}
}
}
void roll_initiative(void)
{
struct char_data *ch;
for (ch = combat_list; ch; ch = next_combat_list) {
next_combat_list = ch->next_fighting;
roll_individual_initiative(ch);
}
return;
}
/* control the fights going on. Called every 2 seconds from comm.c. */
void perform_violence(void)
{
struct char_data *ch;
extern struct index_data *mob_index;
for (ch = combat_list; ch; ch = next_combat_list) {
next_combat_list = ch->next_fighting;
if (FIGHTING(ch) == NULL || GET_POS(ch) <= POS_STUNNED)
stop_fighting(ch);
else if (GET_INIT_ROLL(ch) >= 0) {
if (IS_PERSONA(ch)) {
if (ch->in_room != FIGHTING(ch)->in_room)
stop_fighting(ch);
else {
hit(ch, FIGHTING(ch), TYPE_UNDEFINED);
GET_INIT_ROLL(ch) -= 10;
}
} else {
if ((!IS_NPC(ch) || (IS_NPC(ch) && !mob_magic(ch))) && !cycle_spell_q(ch))
hit(ch, FIGHTING(ch), TYPE_UNDEFINED);
GET_INIT_ROLL(ch) -= 10;
if (MOB_FLAGGED(ch, MOB_SPEC) && mob_index[GET_MOB_RNUM(ch)].func != NULL)
(mob_index[GET_MOB_RNUM(ch)].func) (ch, ch, 0, "");
}
}
}
}
void order_list(void)
{
register struct char_data *one, *two, *next, *previous = NULL, *temp;
if (combat_list == NULL)
return;
for (one = combat_list; one; previous = NULL, one = next) {
next = one->next_fighting;
for (two = combat_list; two && two->next_fighting; previous = two,
two = two->next_fighting) {
if (GET_INIT_ROLL(two->next_fighting) > GET_INIT_ROLL(two)) {
if (previous)
previous->next_fighting = two->next_fighting;
else combat_list = two->next_fighting;
temp = two->next_fighting->next_fighting;
two->next_fighting->next_fighting = two;
two->next_fighting = temp;
}
}
}
}