#combat routines, I haven't had a chance to clean these up yet, edit at your own #peril. Working now! wahoo.

sub attack {
	my $attacktype=(shift or return);
	my $enemy=(shift or $enemy);
	my $client=(shift or $client);
	unless (local $weapon=weaponfind()){
		$outbuffer{$client}.="You don't have a weapon!\r\n$prompt";
		return 1;
	}
	if (&roundcheck){
		return;
	}
	my $a;
	#run combatcheck to verify engaged and in range
	unless ($a=&combatcheck){
		$outbuffer{$client}.="You must be engaged to something\r\n$prompt";
		return;
	}
	unless (defined($attack{$attacktype}{$a})){
		$outbuffer{$client}.="Can't attack from this range.";
		my @a=keys %{$attack{$attacktype}};
		if (@a==1){
			$outbuffer{$client}.=" You must be at $a[0] range";
		}
		else {
			$outbuffer{$client}.="You must be at ";
			while (@a){
				if (@a==1){
					$outbuffer{$client}.="or $a[0]";
				}else {
				
					$outbuffer{$client}.="$a[0], ";
				}
				shift @a;
			}
			$outbuffer{$client}.="\r\n$prompt";
		}
	return;
	}
	#engaged to a valid living target. 
	local $attack=\%{$attack{$attacktype}{$a}};
	#first check we have everything needed to use this attack.
	foreach $b (keys %{$attack{$attacktype}{$a}{cost}}){
		if ($user{$client}{$b}<$attack{$attacktype}{$a}{cost}{$b}){
			$outbuffer{$client}.="You don't have the $b. $user{$client}{$b}";
			return;
		}
	}
	#then we actually do the subtraction here
	foreach $b (keys %{$attack{$attacktype}{$a}{cost}}){
		$user{$client}{$b}-=$attack{$attacktype}{$a}{cost}{$b};
	}
	my $round=${$attack}{round};
	my $tohitscript=(${$attack}{tohitscript} or \&tohit_normal);
	my $tohit=&{$tohitscript};
	my $tohitbonus=${$attack}{tohit};
	if (defined($user{$client}{tohitbonus})){
		$tohitbonus +=${$attack}{tohit};
	}
	$tohit+=int(($user{$client}{balance}-$user{$enemy}{balance})/10);
	
my $line.="$desc{${$attack}{desctype}}[int($tohit)] ${$attack}{line}";
	my $defensescript=(${$attack}{defensescript} or \&defense_normal);
	my %list=&{$defensescript};
	my $last;
	my $total=0;
	#this is not really a good way to do this but i don't know a better way
	#need to go through defenses in a more or less random order.
	foreach $a (sort { rand(1) <=> rand(1)} keys %list){
		$total+=$list{$a};
		$last=$a;
		#need a better way to do this...
		my %keys=("evasion" => "Survival", "parry" => "weapons", "shield" => "Armor");
		my $rand=rand(1); 
		if ($rand+($tohitbonus/100)<$list{$a}/($list{$a}+$tohit)){
			$line.=" but ".($desc{$a}[int($tohit-$list{$a})] or $desc{$a}[-1]);
			my $exp=$tohit-($list{$a}-$tohit);
			$exp*=5;
			if ($exp<5){
				$exp=5;
			}
			addexp("$a","$keys{$a}", (($list{$a}+($tohit-$list{$a}))*20), $enemy);
			addexp("$item{$weapon}{primary}","weapons",$exp);
			addexp("$item{$weapon}{secondary}","weapons",$exp/2);
			addexp("$item{$weapon}{third}","weapons",$exp/5);
			foreach $b (keys %{$attack{$attacktype}{$a}{faileffects}}){
				$user{$client}{$b} -= $attack{$attacktype}{$a}{faileffects}{$b};
			}
			foreach $b (keys %{$attack{$attacktype}{$a}{efaileffects}}){
				$user{$enemy}{$b} -= $attack{$attacktype}{$a}{efaileffects}{$b};
			}
			endcombatdisplay($line, $round+${$attack}{missround}+int (rand 3));
			return;
		}else {
			if ($list{$a}){
				my $exp = $list{$a} - ($tohit-$list{$a});
				addexp("$a","$keys{$a}", $exp, $enemy);
			}
		}
	}
	my $weight=weight(\%{$user{$enemy}{health}});
	my $hit=rand_dist($weight);
	my $damage=&calcdamage($weapon);
	$line.=". [name] ".($desc{hits}[int($damage/10)] or $desc{hits}[-1]) ." [enameown] $hit";
$line.=dodamage($enemy, "$hit", $damage, "${$attack}{damagetype}");
endcombatdisplay($line, $round+${$attack}{hitround}+int(rand(3)));
my $exp=$tohit+($total-$tohit);
$exp*=20;
if ($exp<5){
	$exp=5;
}
foreach $b (keys %{$attack{$attacktype}{$a}{sucesseffects}}){
	$user{$client}{$b}-=$attack{$attacktype}{$a}{successeffects}{$b};
}
foreach $b (keys %{$attack{$attacktype}{$a}{esuccesseffects}}){
	$user{$enemy}{$b}-=$attack{$attacktype}{$a}{esuccesseffects}{$b};
}
addexp("$item{$weapon}{primary}","weapons",$exp);
addexp("$item{$weapon}{secondary}","weapons",$exp/2);
addexp("$item{$weapon}{third}","weapons",$exp/5);
if ($user{$enemy}{vitality}<0){
	died($enemy, "$user{$enemy}{deathline}", "$user{$enemy}{deathdesc}");
	$exp*=4;
	addexp("$item{$weapon}{primary}","weapons",$exp);
	addexp("$item{$weapon}{secondary}","weapons",$exp/2);
	addexp("$item{$weapon}{third}","weapons",$exp/5);
	&endcombat;
	}
if ($user{$enemy}{counterscript}){
	&{$user{$enemy}{counterscript}}($enemy, $client);
}
	
		

}
sub defense_normal {
#returns list of valid defenses for the attacked. ie parry, dodge, block with
#shield etc and a power value. this should be improved...
my $modifier;
my %list;
my $tododge;
foreach $a (keys %{$user{$enemy}{defense}}) {
	if (defined(${$attack}{defenses}{$a})){
		#if the given attack is strong/weak against a particular defence
		#adjust values.
		$modifier=${$attack}{defenses}{$a};
	}else {
		$modifier=1;
	}
	if ($modifier==0) {
		next;
	}
	$list{$a}=&{$a}($enemy);
}
return %list;	
	
}	
sub tohit_normal {
#returns the hit chance. 
	my $tohit;
	my $total;
	my $totalcount;
	foreach $a (keys %{${$attack}{tohitstats}}){
		#stats which determine hit/miss. multiple stats can be listed
		
		unless (defined($user{$client}{$a})){
			print "Error missing stat $a\n";
		}
		$total=$user{$client}{$a}*${$attack}{tohitstats}{$a};
		$totalcount++;
	}
	$total=$total/$totalcount;
	#now add in skill. weapon being used determines the actual skills used
	#attack determines how effective they are.
	my $type=($item{weapon}{basetype} or "weapons");
	my $secondtotal=$user{$client}{exp}{$type}{$item{$weapon}{primary}}{ranks}*${$attack}{primaryskillfactor};
$secondtotal+=$user{$client}{exp}{$type}{$item{$weapon}{secondary}}{ranks}*${$attack}{secondaryskillfactor};
$secondtotal+=$user{$client}{exp}{$type}{$item{$weapon}{third}}{ranks}*${$attack}{thirdskillfactor};
	$total+=$secondtotal;
	$total*=($user{$client}{balance}/100);
	return $total;
}

sub combat {
my $attack=shift;
if (&roundcheck){
	return;
	}
local $enemy=$user{$client}{eng}{to};
my $weapon=weaponfind();
my $attack=($item{$weapon}{$attack} or $attack);
if ($attack){
	attack("$attack", $enemy, $client);
}else {
	$outbuffer{$client}.="You can't $attack with that";
}
}
sub swing {
combat ("swing");
}
sub endcombat {
#actually end combat and remove the eng data. someone died/quit/retreated.
	my $enemy=(shift or $enemy);
	delete $user{$client}{eng}{to};
	delete $user{$client}{eng}{distance};

}
sub calcdamage {
#put here for easy modification. just add skills and str and random +/- factor
my $weapon=shift;
my $dam=$user{$client}{${$attack}{damagestat}};
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{primary}}{ranks}/${$attack}{skilltodamage};
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{secondary}}{ranks}/${$attack}{skilltodamage2};
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{third}}{ranks}/${$attack}{skilltodamage3};
$dam=$dam*${$attack}{damagefactor};
my $rand=$damage*${$attack}{damagerandom};
$dam+=rand($rand)-($rand/2);
$damage =($damage * 10);
return $dam;

}

sub dodamage {
#do damage here. This should also check if a limb has been severed but doesn't yet
my $client=shift;
my $location=shift;
my $damage=shift;
my $type=shift;
my $line;
my $startingdamage=int($user{$client}{health}{$location}{hp}/$user{$client}{health}{$location}{maxhp}*10);
if ($startingdamage==10){
	$startingdamage=9;
}
$startingintdamage=int($user{$client}{health}{$location}{inthp}/$user{$client}{health}{$location}{maxinthp}*10);
if ($startingintdamage==10){
	$startingintdamage=9;
}

if ($type eq "pierce"){
	$damage-=($user{$client}{armorabsorb}/2);
	$damage*=(1-($user{$client}{armordeflect}/2));
	$user{$client}{vitality}-=$damage*0.5;
}elsif ($type eq "blunt") {
	$damage-=($user{$client}{armorabsorb}*1.5);
	$damage*=1-($user{$client}{armordeflect}*1.5);
	$user{$client}{vitality}-=$damage*1.5;

}else {
	$damage-=$user{$client}{armorabsorb};
	$damage*=1-$user{$client}{armordeflect};
	$user{$client}{vitality}-=$damage;
}
if (($type eq "pierce") or ($type eq "slice")){
$user{$client}{health}{$location}{hp}-=$damage;
	$endingdamage = int( $user{$client}{health}{$location}{hp} / $user{$client}{health}{$location}{maxhp} * 10 );
	if ($endingdamage<=6) {
		$user{$client}{health}{$location}{bleeding}+=5;
	}
}
elsif (($type eq "blunt") or $type eq "pierce") {
	$user{$client}{health}{$location}{inthp}-=$damage;
	
	if (int(($user{$client}{health}{$location}{inthp}/$user{$client}{health}{$location}{maxinthp})*10)<=6) {
		$user{$client}{health}{$location}{intbleeding}+=int ($damage/10);
		}
	}
if ($endingdamage<$startingdamage){
	$line=($desc{damage}[$endingdamage] or $desc{damage}[-1]);
}
	if ($user{$client}{health}{$location}{inthp}<=0 or $user{$client}{health}{$location}{hp}<=0){
	#limb has been severed or destroyed should drop what it's holding
		if ($user{$client}{health}{$location}{vital}){
		#vital limb, victim dies!
			$user{$client}{vitality}=0;
			died($client);
		}
	}
return $line;
}

sub endcombatdisplay {
my $line=shift;
my $round=(shift or 1);
my $line2=$line;
my $line3=$line2;
#nasty parsing stuff. 
my %keys=
	(
	name=>"you", 
	ename=>$user{$enemy}{name},
	"1s"=>"",
	"2s"=>"s",
	nameown=>"your",
	enameown=>"it's",
	weapon => "$item{$weapon}{name}",
	);
while ($line=~s/\[(.*?)\]/$keys{$1}/is){

	}
%keys=
	(
	name=>"$user{$client}{name}", 
	ename=>"you",
	"1s"=>"s",
	"2s"=>"",
	nameown=>"it's",
	enameown=>"your",
	weapon => "$item{$weapon}{name}",
	);
$line2=~s/\[(.*?)\]/$keys{$1}/isg;
%keys=
	(
	name=>"$user{$client}{name}", 
	ename=>"$user{$enemy}{name}",
	"1s"=>"s",
	"2s"=>"s",
	nameown=>"it's",
	enameown=>"it's",
	weapon => "$item{$weapon}{name}",
	);
$line3=~s/\[(.*?)\]/$keys{$1}/isg;
say3("$line3",$client,$enemy,"$line","$line2");
$outbuffer{$client}.="\r\n[Balance: ".$desc{balance}[int($user{$client}{balance}/10)]." Relative Position: ".$desc{pos}[int(($user{$client}{balance}-$user{$enemy}{balance})/10)+10]."]";
$outbuffer{$client}.="\r\nRoundtime: $round";
$user{$client}{round}+=$round;
}

sub parse {
my $string=shift;
my %hash={shift};
$string=~s/\[(.*?)\]/$keys{$1}/isg;
return $string;
}

sub shield {
#This is used by normal_defence
$enemy=shift;
my $shield;
#first check if we have a shield in a hand/tail/etc
foreach $hold (@{$user{$enemy}{hold}}){
	if ($user{$enemy}{health}{$hold}{hold}){
		if ($item{$user{$enemy}{health}{$hold}{hold}}{shield}) {
			$shield=$user{$enemy}{health}{$hold}{hold};
			last;
			}
		}
	}
#if yes calc how good we are with it
if ($shield){
	my $skill=($user{$enemy}{exp}{Armor}{shield}{ranks} or 1);
	my $tododge=$skill+$user{$enemy}{reflex};
	return $tododge;
	}
return 0;
}


sub parry {
#' '
my $enemy=shift;
my $weapon=weaponfind($enemy);
my $weapon2=weaponfind($client);
if (defined $item{$weapon}{parry}){
	$skill=(($user{$enemy}{exp}{weapons}{parry}{ranks} + $user{$enemy}{exp}{weapons}{$item{$weapon}{primary}}{ranks} + $user{exp}{weapons}{$item{$weapon2}{primary}}{ranks})/3 or 1);
	$skill*=$item{$weapon}{parry};
	$tododge=$skill+$user{$enemy}{reflex};
	return $tododge
	}
return 0;
}


sub dodge {
#''
my $enemy=shift;
my $skill=($user{$enemy}{exp}{Survival}{evasion}{ranks} or 1);
my $tododge=$skill+$user{$enemy}{agi};
return $tododge;
}
sub evasion {
#''
my $enemy=shift;
my $skill=($user{$enemy}{exp}{Survival}{evasion}{ranks} or 1);
my $tododge=$skill+$user{$enemy}{agi};
return $tododge;
}

sub combatcheck{
my $client=(shift or $client);
unless (defined($user{$client}{eng}{to})){
	return 0;
	&endcombat
	}
my $enemy=$user{$client}{eng}{to};
unless (defined($user{$enemy})){
	&endcombat;
	return 0;
	}
unless ($user{$enemy}{room} == $user{$client}{room}){
	&endcombat;
	return 0;
	}
if ($user{$enemy}{dead}){
	&endcombat;
	return 0;
	}
return $user{$client}{eng}{distance};

if ($user{$client}{eng}{distance} eq "missile"){
	return 1;
	}
if ($user{$client}{eng}{distance} eq "pole"){
	return 2;
	}
if ($user{$client}{eng}{distance} eq "melee"){
	return 3;}

}


sub weaponfind {
#find out what were attacking with
my $client=(shift or $client);
unless (defined($user{$client}{weapon})){
	$user{$client}{weapon}="right hand";
	}
my $weapon=$user{$client}{health}{$user{$client}{weapon}}{weapon};
unless ($weapon){
$weapon=$user{$client}{health}{$user{$client}{weapon}}{hold};
}

unless ($weapon){
	return 0;
	}
return $weapon;
}

sub rand_dist {
#choose a weighted random body part to hit... might use this elsewhere as well.
	my $dist=shift;
	my $key;
	my $rand=rand;
	foreach $key (keys %{$dist}) {
		return $key if (($rand -= $dist->{$key})<0);
	}
}
sub weight {
#calculate weighting for random choices. ie which body part to hit.
my $weights=shift;
my ($total_weight, %dist)=0;
foreach (values %$weights){ $total_weight+=$_->{hitchance};}
while (my ($key, $values)= each %$weights){
	$dist{$key}= $values->{hitchance}/$total_weight;
	}
return \%dist;
}

return 1;