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