mud/help/
mud/map/
mud/monsters/
mud/players/
#combat routines, I haven't had a chance to clean these up yet, edit at your own peril.
sub attack {
	my $attacktype=(shift or "swing");
	my $enemy=(shift or $enemy);
	my $client=(shift or $client);
	my $weapon=weaponfind();
	if (&roundcheck){
		return;
	}
	my $a;
	unless ($a=&combatcheck){
		$outbuffer{$client}.="You must be engaged to something\r\n$prompt";
		return;
	}
	print "$attacktype\n$a\n";
	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;
	}
	local $attack=\%{$attack{$attacktype}{$a}};
	$user{$client}{balance}+=${$attack}{startbal};
	$user{$client}{eng}{pos}+=${$attack}{startpos};
	my $tohitscript=(${$weapon}{tohitscript} or \&tohit_normal);
	my $tohit=&{$tohitscript};
	$tohit=$tohit*${$attack}{tohit};
	
my 	$line.="$desc{$attacktype}[int($tohit)]";
	my $defensescript=(${$weapon}{defensescript} or \&defense_normal);
	my %list=&{$defensescript};
	my $last;
	foreach $a (keys %list){
		$last=$a;
		if ($list{$a}>$tohit){
			print "$a successful.$tohit - $list{$a}\r\n";
			$outbuffer{$client}.="$a successful.\r\n$prompt";
			return;
			}
		}
	print "$last failed $list{$last}\r\n";
	$outbuffer{$client}.="$last failed\r\n";
	
	endcombatdisplay($line);
}
sub defense_normal {
my $modifier;
my %list;
my $tododge;
foreach $a (keys %{$user{$enemy}{defense}}) {
	if (defined(${$attack}{defenses}{$a})){
		$modifier=${$attack}{defenses}{$a};
	}else {
		$modifier=1;
	}
	if ($modifier==0) {
		next;
	}
	$tododge=$user{$enemy}{dex}+$user{$enemy}{agi};
	$tododge+=int(rand(10));
	$tododge=$tododge*$modifier;
	$list{$a}=$tododge;
}
return %list;	
	
}	
sub tohit_normal {
	my $tohit;
	my $total;
	my $totalcount;
	foreach $a (keys %{${$attack}{tohitstats}}){
		unless (defined($user{$client}{$a})){
			print "Error missing stat $a\n";
		}
		$total=$user{$client}{$a}*${$attack}{tohitstats}{$a};
		$totalcount++;
	}
	print "$total\n$totalcount\n\n\n";
	$total=$total/$totalcount;
	$total=int ($total+rand(${$attack}{tohitrand}));
	return $total;
	print "$total\n";

}


sub swing {
if (&roundcheck){
	print "failed roundcheck\n";
	return;
	}
local $enemy=$user{$client}{eng}{to};
attack("swing",$enemy, $client);
return;
my $weapon=weaponfind();
unless ($weapon){
	$outbuffer{$client}.="You don't have a weapon\r\n$prompt";
	return;
	}

print "myweapon=$weapon";
my $skill;
addexp("$item{$weapon}{primary}","weapons", "1",$client);
if (defined($user{$client}{exp}{weapons}{$item{$weapon}{primary}}{ranks})){
$skill=$user{$client}{exp}{weapons}{$item{$weapon}{primary}}{ranks};
	print "skill=$skill\n";
	}
else {
	$skill=1;
	}
$tohit=$skill+$user{$client}{agi}+int(rand(10))+$user{$client}{eng}{pos};
my $line;
if (defined($desc{swing}[$tohit])){
	$line.=$desc{swing}[$tohit];
	}
else {
	$line.="$desc{swing}[-1]";
	}
$line.=" [name] swing[1s] at [ename] with $item{$weapon}{name}. ";


($tododge, $skill)=dodge($enemy);
unless ($tohit>$tododge){
	addexp("evasion","survival",$tohit-$skill*3,$enemy);
	$line.="[ename] dodge[2s] [nameown] blow.";
	&endcombatdisplay($line);
	return;
	}
addexp("evasion","survival", 1,$enemy);
$tododge=0;

($tododge, $skill)= parry($enemy);
unless  ($tohit>$tododge){
	addexp("parry","weapons",$tohit,$enemy);
	$line.="[ename] parry[1s].";
	&endcombatdisplay($line);
	return;
	}
if ($tododge){
	addexp("parry","weapons",1,$enemy);
	}
$tododge=0;

($tododge,$skill)=shield($enemy);
	unless  ($tohit>$tododge){
		addexp("shield","armor",$tohit,$enemy);
		$line.="[ename] block[1s].";
		&endcombatdisplay($line);
		return;
		}
if ($tododge){
	addexp("shield","armor",1,$enemy);
	}
my $exp=10;
#add exp now.
addexp("$item{$weapon}{primary}","weapons",$exp);
addexp("$item{$weapon}{secondary}","weapons",$exp/2);
addexp("$item{$weapon}{third}","weapons",$exp/5);
print "\nadded exp to $item{$weapon}{primary},$item{$weapon}{secondary},$item{$weapon}{third}\n";

#Weighted random. choose which body part we wish to hit.
my $weight=weight(\%{$user{$enemy}{health}});
my $hit=rand_dist($weight);
$line.="[name] hit[1s] [enameown] $hit";
print "hit $hit\n";
#will add a sub to calc damage later... opps did that :) calc damage here
my $damage=&calcdamage($weapon);
print "Doing $damage damage\n";
dodamage($enemy, "$hit", $damage*$item{$weapon}{piercestr}, "pierce");
dodamage($enemy, "$hit", $damage*$item{$weapon}{impactstr}, "blunt");
dodamage($enemy, "$hit", $damage*$item{$weapon}{slicestr}, "slice");
endcombatdisplay($line);
if ($user{$enemy}{vitality}<0){
	died($enemy, "$user{$enemy}{deathline}", "$user{$enemy}{deathdesc}");
	&endcombat;
	}
if ($user{$enemy}{counterscript}){
	unless(defined($user{$enemy}{counterscript})){
		print "error!!\r\n";
		}
	else {
		&{$user{$enemy}{counterscript}}($enemy, $client);
		}
	}
}
sub endcombat {
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}{str};
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{primary}}{ranks}/5;
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{secondary}}{ranks}/10;
$dam+=$user{$client}{exp}{weapons}{$item{$weapon}{third}}{ranks}/20;
$dam=$dam*3;
$dam+=int(rand(($dam/3)*2)-($dam/3));
return $dam;

}

sub dodamage {
#do damage here, bit nasty right now.
my $client=shift;
my $location=shift;
my $damage=shift;
my $type=shift;
if ($type eq "pierce"){
	$user{$client}{vitality}-=$damage*0.7;
}elsif ($type eq "blunt") {
	$user{$client}{vitality}-=$damage*1.3;
}else {
	$user{$client}{vitality}-=$damage;
}

if (($type eq "pierce") or ($type eq "slice")){
	$user{$client}{health}{$location}{hp}-=$damage;
}
elsif (($type eq "blunt") or $type eq "pierce") {
	$user{$client}{health}{$location}{inthp}-=$damage;
}

}

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=>"$user{$enemy}{name}'s",
	);
while ($line=~s/\[(.*?)\]/$keys{$1}/is){
	print "$1\n";
	}
%keys=
	(
	name=>"$user{$client}{name}", 
	ename=>"you",
	"1s"=>"s",
	"2s"=>"",
	nameown=>"$user{$client}{name}'s",
	enameown=>"your",
	);
$line2=~s/\[(.*?)\]/$keys{$1}/isg;
%keys=
	(
	name=>"$user{$client}{name}", 
	ename=>"$user{$enemy}{name}",
	"1s"=>"s",
	"2s"=>"s",
	nameown=>"$user{$client}{name}'s",
	enameown=>"$user{$enemy}{name}'s",
	);
$line3=~s/\[(.*?)\]/$keys{$1}/isg;
say3("$line3",$client,$enemy,"$line","$line2");
$outbuffer{$client}.="\r\nRoundtime: $round";
$user{$client}{round}+=$round;
$outbuffer{$client}.="\r\n$prompt";
print "$line3\n";
}

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

sub shield {
$enemy=shift;
my $shield;
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};
			print "shield=$shield";
			last;
			}
		}
	}
if ($shield){
	my $skill=($user{$enemy}{exp}{armor}{shield}{ranks} or 1);
	my $tododge=$skill+$user{$enemy}{reflex}+int(rand(10));
	return ($tododge, $skill);
	}
return 0;
}


sub parry {
my $enemy=shift;
my $weapon=weaponfind($enemy);
if ($item{$weapon}{parry}){
	$skill=($user{$enemy}{exp}{weapons}{parry}{ranks} or 1);
	$tododge=$skill+$user{$enemy}{reflex}+int(rand(12));
	return $tododge, $skill
	}
return 0;
}


sub dodge {
my $enemy=shift;
my $skill=($user{$enemy}{exp}{survival}{evasion}{ranks} or 1);
my $tododge=$skill+$user{$enemy}{agi}+int(rand(10));
return ($tododge,$skill);
}


sub combatcheck{
my $client=(shift or $client);
print "starting check\n";
unless (defined($user{$client}{eng}{to})){
	print "no eng\n";
	return 0;
	}
my $enemy=$user{$client}{eng}{to};
unless (defined($user{$enemy})){
	print "no enemy\n";
	&endcombat;
	return 0;
	}
unless ($user{$enemy}{room} == $user{$client}{room}){
	print "wrong rooms\n";
	&endcombat;
	return 0;
	}
if ($user{$enemy}{dead}){
	print "is dead\n";
	&endcombat;
	return 0;
	}
print "distance is $user{$client}{eng}{distance}\n";
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 {
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 {
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;