/* Hack of one_hit so we can use the checks again elsewhere. 
 * The goal of this is to be able to be used in skills such as bash,
 * to detect chance of hit.
 * also, if use_weapon is false, it takes dt as a skill, and gets the skill's %
 * learned and uses that as its skill-value.
 * so for backstab, we do a.
 * is_hit(ch, victim, gsn_backstab, true, false);
 * this makes it use the weapons data, and influence later by the skill check
 * but if we do a.....
 * is_hit(ch, victim, gsn_trip, false, false);
 * we purely base the chance to hit off of the AC value's and the
 * skill value of gsn_trip on the user.
 *
 * This effectively gives skills a better skill check, then the average
 * system that was used, which was just based purely on the skill level
 * and the player/victim level.  And Misc other stats.
 *
 * With this I put a modified do_bash to showcase the simple system
 *
 * Note: This works well, changing all the skills to this method
 * is fast, and easy, and returns a much faster method of
 * registering a hit, so all you need todo is create your damage modifiers.
 *
 *
 * This can be used within one_hit, to replace the existing hit code,
 * why duplicate when you don't need to
 *
 *
 * Credit:  I require no credit, but if you want to mention me, please feel
 * free to.  Questions, comments, concerns, I can be reached on mudbytes
 * or on my mud, CombatMud.  sandstorm.arthmoor.com port 9696
 * Cheers.
 */


/* did we hit?  -- Darien*/
bool is_hit(CHAR_DATA *ch, CHAR_DATA *victim, int dt, bool use_weapon, bool secondary) {
	OBJ_DATA *wield;    
	int victim_ac;    
	int thac0;    
	int thac0_00;    
	int thac0_32;
	int diceroll;    
	int sn = 0,skill;
	int dam_type;

	if(use_weapon) {
		if (!secondary)        
			wield = get_eq_char( ch, WEAR_WIELD );    
		else        
			wield = get_eq_char( ch, WEAR_SECONDARY );

		/* get the weapon skill */    
		sn = get_weapon_sn(ch);    
		skill = 20 + get_weapon_skill(ch,sn);     
	} else {
		// we're a skill!
		skill = get_skill(ch, dt);
	}

        if ( dt == TYPE_UNDEFINED )    {	
		dt = TYPE_HIT;
		if ( wield != NULL && wield->item_type == ITEM_WEAPON )	    
			dt += wield->value[3];	else 	    dt += ch->dam_type;    
	}     
	if (dt < TYPE_HIT) {
		if (wield != NULL)    	    
			dam_type = attack_table[wield->value[3]].damage;    	
		else    	    
			dam_type = attack_table[ch->dam_type].damage;    
	}
	else    	
		dam_type = attack_table[dt - TYPE_HIT].damage;     

	if (dam_type == -1)	
		dam_type = DAM_BASH;

	/*     
	 * Calculate to-hit-armor-class-0 versus armor.     
	 */    
	if ( IS_NPC(ch) )    {	
		thac0_00 = 20;	
		thac0_32 = -4;   
		/* as good as a thief */ 	
		if (IS_SET(ch->act,ACT_WARRIOR))	    
			thac0_32 = -10;	
		else if (IS_SET(ch->act,ACT_THIEF))	    
			thac0_32 = -4;	
		else if (IS_SET(ch->act,ACT_CLERIC))	    
			thac0_32 = 2;	
		else if (IS_SET(ch->act,ACT_MAGE))	    
			thac0_32 = 6;    
	} else {	
		thac0_00 = class_table[ch->iclass].thac0_00;	
		thac0_32 = class_table[ch->iclass].thac0_32;  
	}    

	thac0  = interpolate( ch->level, thac0_00, thac0_32 );     
	if (thac0 < 0)        
		thac0 = thac0/2;     
	if (thac0 < -5)        
		thac0 = -5 + (thac0 + 5) / 2;     
	thac0 -= GET_HITROLL(ch) * skill/100;    
	thac0 += 5 * (100 - skill) / 100;     

	
	/* special skill checks here 
	 * If we use a weapon, then we modify here if it is a special skill
	 * if no weapon is used, then the skill-value is already set.
	 * and that doesn't affect thaco unless you specify otherwise.
	 * an example of this would be trip.
	 */
	if(use_weapon) {
		// weapon-skills
		if (dt == skill_lookup("backstab"))	
			thac0 -= 10 * (100 - get_skill(ch,skill_lookup("backstab")));     
		// bash is a slow but powerful hit, so thac0 goes up slightly,
		// making it a harder hit, this is optional
		if (dt == skill_lookup("bash"))	
			thac0 += 2 * (100 - get_skill(ch,skill_lookup("bash")));     
	} else {
		// affect thac0 with non-weapon-skills.
		// so for trip, we lower the thac0 (which = good)
		if(dt == gsn_trip)
			thac0 -= 10 * (100 - skill);    
	}

	switch(dam_type)    {	
		case(DAM_PIERCE):	victim_ac = GET_AC(victim,AC_PIERCE)/10;	break;	
		case(DAM_BASH):	 	victim_ac = GET_AC(victim,AC_BASH)/10;		break;	
		case(DAM_SLASH): 	victim_ac = GET_AC(victim,AC_SLASH)/10;		break;	
		default:	 	victim_ac = GET_AC(victim,AC_EXOTIC)/10;	break;    
	};      

	if (victim_ac < -15)	
		victim_ac = (victim_ac + 15) / 5 - 15;     
	if ( !can_see( ch, victim ) )	
		victim_ac -= 4;     
	if ( victim->position < POS_FIGHTING)	
		victim_ac += 4;     
	if (victim->position < POS_RESTING)	
		victim_ac += 6;     

	/*     
	 * The moment of excitement!     
	 * hit or miss!
	 */    

	while ( ( diceroll = number_bits( 5 ) ) >= 20 )	
		;     
	if ( diceroll == 0    || ( diceroll != 19 && diceroll < thac0 - victim_ac ) )    {	
		/* Miss. */	
		return FALSE;    
	}
	// we hit the enemy, lets return true and do this
	return true;
}



/**************************************************************************************************/
/*
	bash revamped as an example of what can be done with this minor change
 */
void do_bash( CHAR_DATA *ch, char *argument ) {    
	char arg[MAX_INPUT_LENGTH];    
	CHAR_DATA *victim;    
	int chance;     

	one_argument(argument,arg);     

	if ( (chance = get_skill(ch,gsn_bash)) == 0 
	|| (IS_NPC(ch) && !IS_SET(ch->off_flags,OFF_BASH))    
	|| (!IS_NPC(ch)    
	&&	  ch->level < skill_table[gsn_bash].skill_level[ch->class]))    {
		send_to_char("Bashing? What's that?\n\r",ch);	
		return;    
	}     

	if (arg[0] == '\0')    {
		victim = ch->fighting;	
		if (victim == NULL)	
		{	    
			send_to_char("But you aren't fighting anyone!\n\r",ch);	    
			return;	
		}
        }     
	else if ((victim = get_char_room(ch,arg)) == NULL)    {	
		send_to_char("They aren't here.\n\r",ch);	
		return;    
	}     

	if (victim->position < POS_FIGHTING)    {
		act("You'll have to let $M get back up first.",ch,NULL,victim,TO_CHAR);	
		return;    
	}      
	if (victim == ch)    {	
		send_to_char("You try to bash your brains out, but fail.\n\r",ch);	
		return;    
	}     

	if (is_safe(ch,victim))	 return;     

	if ( IS_NPC(victim) && 	victim->fighting != NULL 
	&& 	!is_same_group(ch,victim->fighting))    {        
		send_to_char("Kill stealing is not permitted.\n\r",ch);        
		return;    
	}     

	if (IS_AFFECTED(ch,AFF_CHARM) && ch->master == victim)    {	
		act("But $N is your friend!",ch,NULL,victim,TO_CHAR);	
		return;    
	}     

	// okay, here we go.
	// chance is just used as a damage modifier
	// thats it, thats all.
	chance = 0;

	/* modifiers */     
	/* size  and weight */    

	chance += ch->carry_weight / 250;    
	chance -= victim->carry_weight / 200;     
	if (ch->size < victim->size)	
		chance += (ch->size - victim->size) * 15;    
	else	
		chance += (ch->size - victim->size) * 10;       

	/* stats */    
	chance += get_curr_stat(ch,STAT_STR);    
	chance -= (get_curr_stat(victim,STAT_DEX) * 4)/3;    
	chance -= GET_AC(victim,AC_BASH) /25;    

	/* speed */    
	if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))        
		chance += 10;    
	if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))        
		chance -= 30;     

	/* level */    
	chance += (ch->level - victim->level);     
	if (!IS_NPC(victim) && chance < get_skill(victim,gsn_dodge) )    {	
		chance -= 3 * (get_skill(victim,gsn_dodge) - chance);    
	}     

	/* now the attack, very simple,  */    
	if(is_hit(ch, victim, gsn_bash, true, false)) { 	
		act("$n sends you sprawling with a powerful bash!",ch,NULL,victim,TO_VICT);	
		act("You slam into $N, and send $M flying!",ch,NULL,victim,TO_CHAR);	
		act("$n sends $N sprawling with a powerful bash.",ch,NULL,victim,TO_NOTVICT);	
		check_improve(ch,gsn_bash,TRUE,1); 	
		DAZE_STATE(victim, 3 * PULSE_VIOLENCE);	
		WAIT_STATE(ch,skill_table[gsn_bash].beats);	
		victim->position = POS_RESTING;	
		damage(ch, victim, number_range(2, 2 + 2 * ch->size + chance/20), gsn_bash, DAM_BASH,FALSE);
	}    
	else    // moment of sadness
	{	
		damage(ch,victim,0,gsn_bash,DAM_BASH,FALSE);	
		act("You fall flat on your face!",	    ch,NULL,victim,TO_CHAR);	
		act("$n falls flat on $s face.",	    ch,NULL,victim,TO_NOTVICT);	
		act("You evade $n's bash, causing $m to fall flat on $s face.",	    ch,NULL,victim,TO_VICT);	
		check_improve(ch,gsn_bash,FALSE,1);	
		ch->position = POS_RESTING;	
		WAIT_STATE(ch,skill_table[gsn_bash].beats * 3/2);     
	}
	check_killer(ch,victim);
}