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