/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

warrior.c				Skills and commands which are
					'usually' unique to the warrior
					class.

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "magic.h"
#include "mudlimits.h"
#include "fight.h"
#include "affect.h"
#include "lists.h"

/* extern variables */
extern int rev_dir[];
extern struct str_app_type str_app[];
extern int check_room_affects(chdata *ch, int room);
extern char *dirs[];
extern char *comm_dirs[];

// allow a warrior to open door without key :)
// also opens jammed doors...  4/26/98 -jtrhone
ACMD(do_doorbash)
{
  char *argu = argument;
  int dir, other_room;
  rmdirdata *d, *back;

  if (IS_NPC(ch))
    return;

  if (!GET_SKILL(ch, SKILL_DOORBASH))
  {
    act("You do not posess that ability.", FALSE, ch, 0,0,TO_CHAR);
    return;
  }

  skip_spaces(&argu);
  if (!*argu)
  {
    act("Doorbash what?", FALSE, ch, 0, 0, TO_CHAR);
    return;
  }

  dir = search_block(argu, comm_dirs, FALSE);

  if (dir < 0 || dir > NUM_OF_DIRS)
  {
    send_to_char("Usage: doorbash <[direction]>.\n\r",ch);
    return;
  }

  if (!(d = EXIT(ch, dir)))
  {
    act("It would be fairly difficult to do that there.",FALSE,ch,0,0,TO_CHAR);
    return;
  }

  if (!EXIT_ISDOOR(d))
    act("It would be fairly difficult to do that there.",FALSE,ch,0,0,TO_CHAR);
  else if (EXIT_OPEN(d))
    send_to_char("It's open!\n\r", ch);
  else if (!EXIT_LOCKED(d) && !EXIT_JAMMED(d))
    send_to_char("It's not locked or jammed!\n\r", ch);
  else if (EXIT_FLAGGED(d, EX_NOBASH) || EXIT_FLAGGED(d, EX_PICKPROOF))
  {
    send_to_char("OUCH! You only hurt your shoulder.\n\r", ch);
    GET_HIT(ch) -= number(1, 10);
    GET_HIT(ch) = MAX(GET_HIT(ch), 1);
  }
  else
  {
    // skill check :)
    if (GET_SKILL(ch, SKILL_DOORBASH) < number(1, 101))
    {
      act("OUCH! You only hurt your shoulder.", FALSE, ch, 0,0,TO_CHAR);
      GET_HIT(ch) -= number(1, 10);
      GET_HIT(ch) = MAX(GET_HIT(ch), 1);
      return;
    }

    UNFLAG_EXIT(d, EX_LOCKED | EX_JAMMED);
    if (d->keyword)
    {
      act("You bash the $F open!", FALSE, ch, 0, d->keyword, TO_CHAR);
      act("$n bashes the $F open!", TRUE, ch, 0, d->keyword, TO_ROOM);
    }
    else
    {
      act("You bash it open!", FALSE, ch, 0, 0, TO_CHAR);
      act("$n bashes something open!", TRUE, ch, 0, 0, TO_ROOM);
    }

    /* now for jamming the other side, too */
    if ((other_room = d->to_room) != NOWHERE)
      if ((back = DIR(other_room, rev_dir[dir])))
        if (back->to_room == ch->in_room)
          UNFLAG_EXIT(back, EX_LOCKED | EX_JAMMED);
  }
}

ACMD(do_bash)
{
   chdata *victim;

  if (IS_PC(ch) && 
      (GET_LEVEL(ch) == LEV_IMM || GET_LEVEL(ch) == LEV_GOD))
  {
     send_to_char("You, being an Immortal, are forbidden to kill.\n\r",ch);
     return;
  }

  if (GET_LEVEL(ch) < LEV_AIMP && ROOM_FLAGGED(ch->in_room, PEACEFUL))
  {
    send_to_char("Your offensive actions lead to naught in this peaceful area.\n\r",ch);
    return;
  }

   one_argument(argument, arg);

   if (!IS_WARRIOR(ch)) 
   {
      send_to_char("You'd better leave all the martial arts to fighters.\n\r", ch);
      return;
   }

   if (!(victim = get_char_room_vis(ch, arg)) && !(victim = FIGHTING(ch)))
   {
     send_to_char("Bash who?\n\r", ch);
     return;
   }

   if (victim == ch) {
      send_to_char("You bash yourself on the head...\n\r", ch);
      return;
   }

   if (!check_mortal_combat(ch, victim))
     return;

   if (!EQ(ch, W_HOLD) || !IS_ARMOR(EQ(ch, W_HOLD)))
   {
      send_to_char("You need to hold a shield to make it a success.\n\r", ch);
      return;
   }

   if (!check_truce(ch, victim))
     return;

   if (GET_SKILL(ch, SKILL_BASH) < number(1, 101))
   {  // they failed
      damage(ch, victim, 0, SKILL_BASH, TRUE);
      if (GET_POS(ch) > POS_SITTING)
        GET_POS(ch) = POS_SITTING;
   } 
   else   // they succeeded
   {
      if (damage(ch, victim, 1, SKILL_BASH, TRUE) == CHAR_OK)
      {
        VWAIT(victim) = 1;
        WAIT_STATE(victim, PULSE_VIOLENCE * 2);
        if (GET_POS(victim) > POS_SITTING)
          GET_POS(victim) = POS_SITTING;
      }
      damage_object(EQ(ch, W_HOLD), ch);
   }

   WAIT_STATE(ch, PULSE_VIOLENCE * 2);
}

ACMD(do_rescue)
{
   chdata *victim, *tmp_ch;

   if (IN_NOWHERE(ch)) return;

   if (!GET_SKILL(ch, SKILL_RESCUE))
   {
     send_to_char("You know not how to rescue!\n\r",ch);
     return;
   }

   one_argument(argument, arg);

   if (!(victim = get_char_room_vis(ch, arg))) {
      send_to_char("Who do you want to rescue?\n\r", ch);
      return;
   }

   if (victim == ch) {
      send_to_char("What about fleeing instead?\n\r", ch);
      return;
   }

   if (FIGHTING(ch) == victim) {
      send_to_char("How can you rescue someone you are trying to kill?\n\r", ch);
      return;
   }

   for (tmp_ch = world[ch->in_room].people; tmp_ch && 
       (FIGHTING(tmp_ch) != victim); tmp_ch = tmp_ch->next_in_room)
      ;

   if (!tmp_ch) {
      act("But nobody is fighting $M!", FALSE, ch, 0, victim, TO_CHAR);
      return;
   }

   if (GET_SKILL(ch, SKILL_RESCUE) < number(1, 101)) {
     send_to_char("You fail the rescue!\n\r", ch);
     return;
   }
   send_to_char("Banzai!  To the rescue...\n\r", ch);
   act("You are rescued by $N, you are confused!", FALSE, victim, 0, ch, TO_CHAR);
   act("$n heroically rescues $N!", FALSE, ch, 0, victim, TO_NOTVICT);

   if (FIGHTING(victim) == tmp_ch)
	 stop_fighting(victim);
   if (FIGHTING(tmp_ch))
	 stop_fighting(tmp_ch);
   if (FIGHTING(ch))
	 stop_fighting(ch);
   set_fighting(ch, tmp_ch);
   set_fighting(tmp_ch, ch);
   WAIT_STATE(victim, 2 * PULSE_VIOLENCE);
}

ACMD(do_kick)
{
   chdata *victim;
   byte percent, prob;

  if (IS_PC(ch) && 
      (GET_LEVEL(ch) == LEV_IMM || GET_LEVEL(ch) == LEV_GOD))
  {
     send_to_char("You, being an Immortal, are forbidden to kill.\n\r",ch);
     return;
  }

  if (GET_LEVEL(ch) < LEV_AIMP && ROOM_FLAGGED(ch->in_room, PEACEFUL))
  {
    send_to_char("Your offensive actions lead to naught in this peaceful area.\n\r",ch);
    return;
  }

   if (!IS_WARRIOR(ch) && !IS_WARLOCK(ch) && !IS_MONK(ch) && !IS_RANGER(ch)) {
      send_to_char("You'd better leave all the martial arts to fighters.\n\r", ch);
      return;
   }

   one_argument(argument, arg);

   if (!(victim = get_char_room_vis(ch, arg))) {
      if (ch->specials.fighting) {
	 victim = ch->specials.fighting;
      } else {
	 send_to_char("Kick who?\n\r", ch);
	 return;
      }
   }

   if (victim == ch) {
      send_to_char("Aren't we funny today...\n\r", ch);
      return;
   }

   if (!check_mortal_combat(ch, victim))
     return;
  
   if (!check_truce(ch, victim))
     return;

   percent = ((10 - (GET_AC(victim) / 10)) << 1) + number(1, 101);  
   prob = GET_SKILL(ch, SKILL_KICK);

   if (percent > prob) 
      damage(ch, victim, 0, SKILL_KICK, TRUE);
   else
   {
      damage(ch, victim, GET_LEVEL(ch) >> 1, SKILL_KICK, FALSE);
      if (!EQ(ch, W_FEET) && GET_HIT(ch) > 1)
      {
        send_to_char("You're kicking with bare feet!\n\r",ch);
        GET_HIT(ch)--;
      }
      else
        damage_object(EQ(ch, W_FEET), ch);
   }
   WAIT_STATE(ch, PULSE_VIOLENCE * 3);
}

int find_exit(chdata *ch)
{ 
  int deflt = -1, attempt; 
  int i;

  for(attempt = 0; attempt < NUM_OF_DIRS; attempt++) 
    if(CAN_GO(ch, attempt)) 
    {
      deflt = attempt;
      break;
    }

  if (deflt == -1) 
    return -1;
  else 
    for(i = 0; i < 6; i++) 
    {
      attempt = number(0, NUM_OF_DIRS - 1);
      if (CAN_GO(ch, attempt)) 
        return attempt;
    }

  return deflt;
}

ACMD(do_hurl)
{
  chdata *vict, *k;
  int prob = GET_SKILL(ch, SKILL_HURL); 
  int chweight, victweight;
  int door;
  BOOL bodyslam = FALSE;
  int was_in;

  if (IN_NOWHERE(ch)) return;

  if(!prob) 
  {
    send_to_char("But you don't yet know how to hurl your opponents.\r\n", ch);
    return;
  }

  if(!(vict = FIGHTING(ch))) 
  {
    send_to_char("You need to be fighting in order to hurl!\r\n", ch);
    return;
  }

  chweight = (int) GET_WEIGHT(ch);
  victweight = (int) GET_WEIGHT(vict);

  if( (prob < number(1, 101)) || (2 * chweight < victweight) ) 
  {
    damage(ch, vict, 0, SKILL_HURL, TRUE);
    WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
    return;
  }

  was_in = vict->in_room;  
  door = find_exit(ch);

  if ((door == -1) || 
      (was_in == (world[ch->in_room].dir_option[door])->to_room)) 
    bodyslam = TRUE;

  /* In 1/2 of the cases, throw the vict out of the room, in 1/2 of the 
     cases, bodyslam them to the ground */
  if(number(0,1) || bodyslam) 
  {
    GET_POS(vict) = POS_SITTING;
    WAIT_STATE(vict, PULSE_VIOLENCE);
    WAIT_STATE(ch, 3 * PULSE_VIOLENCE);
    damage(ch, vict, (GET_LEVEL(ch) + GET_DAMROLL(ch))/3, SKILL_HURL, FALSE);
    return;
  }
  /* Now, do the actual throw thing */
  else 
  {
    if (damage(ch, vict, (GET_LEVEL(ch) + GET_DAMROLL(ch))/3, 250, FALSE) == CHAR_DIED)
    {
      WAIT_STATE(ch, 3 * PULSE_VIOLENCE);
      return;
    }     

    for(k = world[vict->in_room].people;k;k=k->next_in_room) 
      if(vict == FIGHTING(k)) 
        stop_fighting(k);

    if (FIGHTING(vict))
      stop_fighting(vict);

    char_from_room(vict);
    char_to_room(vict, DIR(was_in, door)->to_room);
    act("$n arrives hurling into the room!", FALSE, vict, 0, 0, TO_ROOM);
    GET_POS(vict) = POS_SITTING;
    WAIT_STATE(vict, 2 * PULSE_VIOLENCE);
    WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
    do_look_at_room(vict, 0, 0);

    // remove all songs from character being thrown
    if (SINGING(vict))
      do_finish(vict, "song", 0, 0);
    if (PLAYING(vict))
      do_finish(vict, "tune", 0, 0);

    if (check_room_affects(vict, vict->in_room) == CHAR_DIED)
	return;
    if (check_death_trap(vict, NULL))
	return;
  }
}

/* Disarm - warrior/thief skill - 6/3/95 */
ACMD(do_disarm)
{
  int prob = GET_SKILL(ch, SKILL_DISARM);
  int lvldiff;
  chdata *vict;
  obdata *ob;

  if(!prob) {
    send_to_char("But you don't yet know how to disarm your opponents!\r\n", ch);
    return;
  }

  if(!FIGHTING(ch)) {
    send_to_char("You need to be fighting in order to disarm!\r\n", ch);
    return;
  }

  vict = FIGHTING(ch);

  /* check if victim is wielding anything */
  if (!EQ(vict, W_WIELD)) {
    send_to_char("Your opponent is already bare-handed.\r\n", ch);
    return;
  }

  lvldiff = GET_LEVEL(vict) - GET_LEVEL(ch);
  lvldiff = (lvldiff > 0 ? lvldiff : 0);
  
  if(prob > number(1, 250) + lvldiff) {
    /* Send the messages */ 
    ob = unequip_char(vict, W_WIELD, TRUE);
    act("You skillfully force $p out of $N's hands.", TRUE, ch, ob, vict, TO_CHAR);
    act("$N disarms you!", TRUE, vict, NULL, ch, TO_CHAR);
    act("With a quick draw, $n forces $N to lose control of $S weapon!", TRUE, ch, ob, vict, TO_NOTVICT);
    obj_to_char(ob, vict);
  }
  else {
    /* Failed disarm */
    ob = EQ(vict, W_WIELD);
    act("You fail to disarm $N.", TRUE, ch, NULL, vict, TO_CHAR);
    act("$N tries to disarm you, but fails.", TRUE, vict, NULL, ch, TO_CHAR);
    act("$n's puny attempt to knock $p out of $N's hands fails.", TRUE, ch, ob, vict, TO_NOTVICT);
  }

  /* Wait state and return */
  WAIT_STATE(ch, 3 * PULSE_VIOLENCE);
} 
 
ACMD(do_shieldblock)
{
   chdata *vict = 0;

   if (!(vict = FIGHTING(ch))) return;  /* not fighting anybody */

   act("You %5block%0 $N's attack with your shield!", TRUE, ch, NULL, vict, TO_CHAR);
   act("$n %5blocks%0 your attack!.", TRUE, ch, NULL, vict, TO_VICT);
   act("$n %5blocks%0 $N's attack!.", TRUE, ch, NULL, vict, TO_NOTVICT);
}

ACMD(do_grapple)
{
   int percent, prob, cycles;
   
   if (!IS_WARRIOR(ch)) {
      send_to_char("You know not how to hold your opponent.\n\r",ch);
      return;
   }
   
   if (!FIGHTING(ch)) {
      send_to_char("You must be fighting in order to grapple.\n\r",ch);
      return;
   }

   percent = number (1,101);
   prob    = GET_SKILL(ch, SKILL_GRAPPLE);
   prob   += (GET_DEX(ch) - GET_DEX(FIGHTING(ch))) * 5;
   prob   += (GET_LEVEL(ch) - GET_LEVEL(FIGHTING(ch))) * 5;
   prob    = MIN(prob, 100);
   
   if (percent <= prob && !MOB_FLAGGED(FIGHTING(ch), MOB_NO_HOLD)) 
   {
      if (GET_LEVEL(ch) <= 20) 
        cycles = 1;
      else
	cycles = 2;

      if (affected_by_spell(FIGHTING(ch), SPELL_MIRRORIMAGE))
      {
	act("You hold $N's image!", TRUE, ch, 0, FIGHTING(ch), TO_CHAR);
	act("$n holds $N's image!", TRUE, ch, 0, FIGHTING(ch), TO_ROOM);
        VWAIT(ch) = cycles - 1;
	WAIT_STATE(ch, PULSE_VIOLENCE * 5);
	return;
      }

      act("You hold $N, rendering $M motionless.", TRUE, ch, 0, FIGHTING(ch), TO_CHAR);
      act("$n holds $N, rendering $M motionless.", TRUE, ch, 0, FIGHTING(ch), TO_ROOM);
      VWAIT(ch) = cycles - 1;
      WAIT_STATE(ch, PULSE_VIOLENCE * 5);
      VWAIT(FIGHTING(ch)) = cycles;
      WAIT_STATE(FIGHTING(ch), PULSE_VIOLENCE * 5);
   } 
   else 
   {
      act("You fail to hold $N.", TRUE, ch, 0, FIGHTING(ch), TO_CHAR);
      act("$n fails to hold $N.", TRUE, ch, 0, FIGHTING(ch), TO_ROOM);
      WAIT_STATE(ch, PULSE_VIOLENCE * 2);
   }
}
   
// add a certain amount to hit regeneration, warriors
ACMD(do_fortify)
{
  struct affected_type af;

  if (IN_NOWHERE(ch)) return;
  if (IS_NPC(ch)) return;

  if (!GET_SKILL(ch, SKILL_FORTIFY))
  {
    send_to_char("You know not of that skill.\n\r",ch);
    return;
  }

  if (GET_MOVE(ch) < 30)
  {
    send_to_char("You feel too weak to fortify yourself.\n\r",ch);
    return;
  }

  if (affected_by_spell(ch, SKILL_FORTIFY))
  {
    send_to_char("You are already fortified.\n\r",ch);
    return;
  }

  GET_MOVE(ch) -= 30;

  if (GET_SKILL(ch, SKILL_FORTIFY) < number(1, 101))
  {
    send_to_char("You fail to fortify yourself.\n\r",ch);
    return;
  }

  af.type      = SKILL_FORTIFY;
  af.duration  = GET_LEVEL(ch) / 4;
  af.modifier  = GET_LEVEL(ch) / 3;
  af.location  = APPLY_HIT_REGEN;
  af.bitvector = 0;
  af.bitvector2 = 0;
  affect_to_char(ch, &af);

  act("$n fortifies $mself.", TRUE, ch, 0, 0, TO_ROOM);
  act("You feel fortified!", TRUE, ch, 0, 0, TO_CHAR);
}

// cripple an opponent, reduce # of attacks and dex on opponent 
ACMD(do_cripple)
{
  struct affected_type af;
  chdata *vict;

  if (IN_NOWHERE(ch)) return;
  if (IS_NPC(ch)) return;

  if (!GET_SKILL(ch, SKILL_CRIPPLE))
  {
    send_to_char("You know not of that skill.\n\r",ch);
    return;
  }

  if (!(vict = FIGHTING(ch)))
  {
    send_to_char("You must be fighting to use this skill.\n\r",ch);
    return;
  }

  if (GET_MOVE(ch) < 30)
  {
    send_to_char("You feel too weak to cripple your opponent.\n\r",ch);
    return;
  }

  if (affected_by_spell(vict, SKILL_CRIPPLE))
  {
    send_to_char("Your opponent is already crippled.\n\r",ch);
    return;
  }

  GET_MOVE(ch) -= 30;

  if (GET_SKILL(ch, SKILL_CRIPPLE) < number(1, 101) || GET_DEX(vict) > number(1, 18))
  {
    send_to_char("You fail to cripple your opponent.\n\r",ch);
    WAIT_STATE(ch, 2 * PULSE_VIOLENCE);
    return;
  }

  af.type      = SKILL_CRIPPLE;
  af.duration  = 1;
  af.modifier  = -3;
  af.location  = APPLY_DEX;
  af.bitvector = 0;
  af.bitvector2 = 0;
  affect_to_char(vict, &af);
  WAIT_STATE(ch, 3 * PULSE_VIOLENCE);

  act("You cripple $N!", TRUE, ch, 0, vict, TO_CHAR);
  act("%BAHHHHH!!%0  $n hits you with a crippling force!", FALSE, ch, 0, vict, TO_VICT); 
  act("$n flings $mself towards $N and cripples $M!", TRUE, ch, 0, vict, TO_NOTVICT);
}