#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;