diff --git a/Irpg/Classes/Farmer.pm b/Irpg/Classes/Farmer.pm index 69f03f35f92ef5bbce0af7f6351285468932b01d..580e8379ef1fe8dd0b7eb079081b1721aa246128 100644 --- a/Irpg/Classes/Farmer.pm +++ b/Irpg/Classes/Farmer.pm @@ -17,9 +17,13 @@ sub new { $self->{MOD_INT} = 1; # intelligence $self->{MOD_CHA} = 1; # charisma $self->{MOD_DEX} = 1; # dexterity + $self->{MOD_WIN} = 1; # time modificator when winning a fight + $self->{MOD_DEF} = 1; # time modificator when losing a fight $self->{MOD_POS} = 1; # positive events $self->{MOD_NEG} = 1; # negative events $self->{MOD_EQP} = 1; # equipement + $self->{CRIT_SK} = 0.95; # critical strike minimum range, the lower the largest acceptance + $self->{MOD_CRT} = 1; # criticak strike modificator return $self; } @@ -53,4 +57,13 @@ sub dex { return $self->{STATS}->{dex} * $self->{MOD_DEX}; } +sub atk { + my $self = shift; + return ($self->str() + $self->int() + $self->dex())/3; +} +sub def { + my $self = shift; + return ($self->con() + $self->wis() + $self->cha())/3; +} + 1; diff --git a/Irpg/Event.pm b/Irpg/Event.pm index e1e40f354b47d6461f003de4ceda10ff0cede5ba..36ba06af1ae3b17177a096beec7a2355b75abf4c 100644 --- a/Irpg/Event.pm +++ b/Irpg/Event.pm @@ -11,7 +11,7 @@ our @EXPORT_OK = qw(hog); my $opts; my $rps; -=head1 FUNCTION init_hashes +=head1 FUNCTION init_pkg This function sets the references to options and players hashes. =over diff --git a/Irpg/Fight.pm b/Irpg/Fight.pm index 2b77b464e023d6a0471aa7d5fce5bfd158c18e48..bb66c2b7acead6e4df4e98795efb789b9a1ac6d9 100644 --- a/Irpg/Fight.pm +++ b/Irpg/Fight.pm @@ -11,7 +11,7 @@ our @EXPORT_OK = qw(itemsum); my $primnick_ref; my $opts; my $rps; -=head1 FUNCTION init_hashes +=head1 FUNCTION init_pkg This function sets the references to options and players hashes. =over @@ -47,129 +47,124 @@ sub itemsum { if (!exists($rps->{$user})) { return -1; } $sum += int($rps->{$user}{item}{$_}) for keys(%{$rps->{$user}{item}}); if ($battle) { - return $rps->{$user}{alignment} eq 'e' ? int($sum*.9) : + $sum = $rps->{$user}{alignment} eq 'e' ? int($sum*.9) : $rps->{$user}{alignment} eq 'g' ? int($sum*1.1) : $sum; + $sum *= $rps->{$user}{class}->{MOD_EQP}; + return $sum; } return $sum; } -sub challenge_opp { # pit argument player against random player - my $u = shift; - if ($rps->{$u}{level} < 25) { return unless rand(4) < 1; } - my @opps = grep { $rps->{$_}{online} && $u ne $_ } keys(%$rps); - return unless @opps; - my $opp = $opps[int(rand(@opps))]; - $opp = $$primnick_ref if rand(@opps+1) < 1; +sub fight { + my ($u, $opp, $wanted) = @_; + return unless $u && $opp; my $mysum = itemsum($u,1); my $oppsum = itemsum($opp,1); - my $myroll = int(rand($mysum)); - my $opproll = int(rand($oppsum)); + my $myroll = int(rand($mysum) * $rps->{$u}{class}->atk()); + my $opproll = int(rand($oppsum) * $rps->{$opp}{class}->def()); + my $ret = { + usum=>int($mysum/5), oppsum=>int($oppsum/5), + uroll=>int($myroll/5), opproll=>int($opproll/5), + vict=>0, gain=>0, queue=>[]}; if ($myroll >= $opproll) { - my $gain = ($opp eq $$primnick_ref)?20:int($rps->{$opp}{level}/4); + # VICTORY + my $gain = int($rps->{$opp}{level}/4); $gain = 7 if $gain < 7; + $gain *= $rps->{$u}{class}->{MOD_WIN}; + $gain *= 1.2 if ($wanted); $gain = int(($gain/100)*$rps->{$u}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u [$myroll/$mysum] has challenged $opp [$opproll/". - "$oppsum] in combat and won! ".duration($gain)." is ". - "removed from $u\'s clock.")); $rps->{$u}{next} -= $gain; - Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); - my $csfactor = $rps->{$u}{alignment} eq "g" ? 50 : - $rps->{$u}{alignment} eq "e" ? 20 : - 35; - if (rand($csfactor) < 1 && $opp ne $$primnick_ref) { - $gain = int(((5 + int(rand(20)))/100) * $rps->{$opp}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u has dealt $opp a Critical Strike! ". - duration($gain)." is added to $opp\'s clock.")); + $ret->{vict} = 1; + $ret->{gain} = $gain; + + my $align_mod = $rps->{$u}{alignment} eq "g" ? 0.05 : + $rps->{$u}{alignment} eq "e" ? -0.10 : + 1; + if ($myroll >= $mysum * $rps->{$u}{class}->atk() + * ($rps->{$u}{class}->{CRIT_SK} + $align_mod)) { + # CRITICAL STRIKE + $gain = 5 + int(rand(20)); + $gain *= $rps->{$u}{class}->{MOD_CRT}; + $gain = int(($gain/100)*$rps->{$opp}{next}); $rps->{$opp}{next} += $gain; - Irpg::Irc::chanmsg("$opp reaches next level in ".duration($rps->{$opp}{next}). - "."); + unshift($ret->{queue}, + "$u has dealt $opp a Critical Strike! ". + duration($gain)." is added to $opp\'s clock." + , + "$opp reaches next level in ".duration($rps->{$opp}{next})."."); } - elsif (rand(25) < 1 && $opp ne $$primnick_ref && $rps->{$u}{level} > 19) { + elsif (rand(25) < 1 && $rps->{$u}{level} > 19) { my @items = ("ring","amulet","charm","weapon","helm","tunic", "pair of gloves","set of leggings","shield", "pair of boots"); my $type = $items[rand(@items)]; if (int($rps->{$opp}{item}{$type}) > int($rps->{$u}{item}{$type})) { - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "In the fierce battle, $opp dropped his level ". - int($rps->{$opp}{item}{$type})." $type! $u picks ". - "it up, tossing his old level ". - int($rps->{$u}{item}{$type})." $type to $opp.")); my $tempitem = $rps->{$u}{item}{$type}; $rps->{$u}{item}{$type}=$rps->{$opp}{item}{$type}; $rps->{$opp}{item}{$type} = $tempitem; + unshift($ret->{queue}, + "In the fierce battle, $opp dropped his level ". + int($rps->{$opp}{item}{$type})." $type! $u picks it up, ". + "tossing his old level ".int($rps->{$u}{item}{$type}). + " $type to $opp."); } } } else { - my $gain = ($opp eq $$primnick_ref)?10:int($rps->{$opp}{level}/7); + # DEFEAT + my $gain = $rps->{$opp}{level}/7; $gain = 7 if $gain < 7; + $gain *= $rps->{$u}{class}->{MOD_DEF}; + $gain *= 1.2 if ($wanted); $gain = int(($gain/100)*$rps->{$u}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u [$myroll/$mysum] has challenged $opp [$opproll/". - "$oppsum] in combat and lost! ".duration($gain)." is ". - "added to $u\'s clock.")); $rps->{$u}{next} += $gain; - Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); + $ret->{gain} = $gain; + } + return $ret; +} + + +sub challenge_opp { # pit argument player against random player + my $u = shift; + if ($rps->{$u}{level} < 25) { return unless rand(4) < 1; } + my @opps = grep { $rps->{$_}{online} && $u ne $_ } keys(%$rps); + return unless @opps; + my $opp = $opps[int(rand(@opps))]; + my $res = fight($u, $opp); + my ($state, $moved); + if ($res->{vict}) { + ($state, $moved) = ('won', 'removed from'); + } + else { + ($state, $moved) = ('lost', 'added to'); } + Irpg::Irc::chanmsg(Irpg::Utils::clog( + "$u [$res->{uroll}/$res->{usum}] has challenged $opp [$res->{opproll}/". + "$res->{oppsum}] in combat and $state! ".duration($res->{gain})." is ". + "$moved $u\'s clock.")); + Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); + foreach (@{$res->{queue}}) { Irpg::Irc::chanmsg(Irpg::Utils::clog($_)); } } sub collision_fight { my($u,$opp) = @_; - my $mysum = itemsum($u,1); - my $oppsum = itemsum($opp,1); - my $myroll = int(rand($mysum)); - my $opproll = int(rand($oppsum)); - if ($myroll >= $opproll) { - my $gain = int($rps->{$opp}{level}/4); - $gain = 7 if $gain < 7; - $gain = int(($gain/100)*$rps->{$u}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u [$myroll/$mysum] has come upon $opp [$opproll/$oppsum". - "] and taken ".pronoun(3, $rps->{$opp}{gender})." in combat! ".duration($gain)." is ". - "removed from $u\'s clock.")); - $rps->{$u}{next} -= $gain; - Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); - if (rand(35) < 1 && $opp ne $$primnick_ref) { - $gain = int(((5 + int(rand(20)))/100) * $rps->{$opp}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u has dealt $opp a Critical Strike! ". - duration($gain)." is added to $opp\'s clock.")); - $rps->{$opp}{next} += $gain; - Irpg::Irc::chanmsg("$opp reaches next level in ".duration($rps->{$opp}{next}). - "."); - } - elsif (rand(25) < 1 && $opp ne $$primnick_ref && $rps->{$u}{level} > 19) { - my @items = ("ring","amulet","charm","weapon","helm","tunic", - "pair of gloves","set of leggings","shield", - "pair of boots"); - my $type = $items[rand(@items)]; - if (int($rps->{$opp}{item}{$type}) > int($rps->{$u}{item}{$type})) { - Irpg::Irc::chanmsg("In the fierce battle, $opp dropped his level ". - int($rps->{$opp}{item}{$type})." $type! $u picks it up, ". - "tossing his old level ".int($rps->{$u}{item}{$type}). - " $type to $opp."); - my $tempitem = $rps->{$u}{item}{$type}; - $rps->{$u}{item}{$type}=$rps->{$opp}{item}{$type}; - $rps->{$opp}{item}{$type} = $tempitem; - } - } - } + my $res = fight($u, $opp); + my ($state, $moved); + my @ret = (); + if ($res->{vict}) { + ($state, $moved) = ('taken '.pronoun(3, $rps->{$opp}{gender}), 'removed from'); + } else { - my $gain = ($opp eq $$primnick_ref)?10:int($rps->{$opp}{level}/7); - $gain = 7 if $gain < 7; - $gain = int(($gain/100)*$rps->{$u}{next}); - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$u [$myroll/$mysum] has come upon $opp [$opproll/$oppsum". - "] and been defeated in combat! ".duration($gain)." is ". - "added to $u\'s clock.")); - $rps->{$u}{next} += $gain; - Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); + ($state, $moved) = ('been defeated', 'added to'); } + Irpg::Irc::chanmsg(Irpg::Utils::clog( + "$u [$res->{uroll}/$res->{usum}] has come upon $opp [$res->{opproll}/". + "$res->{oppsum}] and $state in combat! ".duration($res->{gain})." is ". + "$moved $u\'s clock.")); + Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); + foreach (@{$res->{queue}}) { Irpg::Irc::chanmsg(Irpg::Utils::clog($_)); } } sub team_battle { # pit three players against three other players @@ -177,35 +172,41 @@ sub team_battle { # pit three players against three other players return if @opp < 6; splice(@opp,int(rand(@opp)),1) while @opp > 6; fisher_yates_shuffle(\@opp); - my $mysum = itemsum($opp[0],1) + itemsum($opp[1],1) + itemsum($opp[2],1); - my $oppsum = itemsum($opp[3],1) + itemsum($opp[4],1) + itemsum($opp[5],1); + my $mysum = itemsum($opp[0],1) + itemsum($opp[1],1) + itemsum($opp[2],1); + my $oppsum = itemsum($opp[3],1) + itemsum($opp[4],1) + itemsum($opp[5],1); my $gain = $rps->{$opp[0]}{next}; + my ($state, $moved); for my $p (1,2) { $gain = $rps->{$opp[$p]}{next} if $gain > $rps->{$opp[$p]}{next}; } $gain = int($gain*.20); - my $myroll = int(rand($mysum)); - my $opproll = int(rand($oppsum)); + my ($myroll, $opproll) = (0, 0); + for (my $i = 0; $i <= 6 ; $i++) { + if ($i < 3) { + $myroll += int(rand(itemsum($opp[$i],1)) * $rps->{$opp[$i]}{class}->atk()); + } + else { + $opproll += int(rand(itemsum($opp[$i],1)) * $rps->{$opp[$i]}{class}->def()); + } + } if ($myroll >= $opproll) { - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$opp[0], $opp[1], and $opp[2] [$myroll/$mysum] have ". - "team battled $opp[3], $opp[4], and $opp[5] [$opproll/". - "$oppsum] and won! ".duration($gain)." is removed from ". - "their clocks.")); + ($state, $moved) = ('won', 'removed from'); $rps->{$opp[0]}{next} -= $gain; $rps->{$opp[1]}{next} -= $gain; $rps->{$opp[2]}{next} -= $gain; } else { - Irpg::Irc::chanmsg(Irpg::Utils::clog( - "$opp[0], $opp[1], and $opp[2] [$myroll/$mysum] have ". - "team battled $opp[3], $opp[4], and $opp[5] [$opproll/". - "$oppsum] and lost! ".duration($gain)." is added to ". - "their clocks.")); + ($state, $moved) = ('lost', 'added to'); $rps->{$opp[0]}{next} += $gain; $rps->{$opp[1]}{next} += $gain; $rps->{$opp[2]}{next} += $gain; } + Irpg::Irc::chanmsg(Irpg::Utils::clog( + "$opp[0], $opp[1], and $opp[2] ". + "[".($myroll/5)."/".($mysum/5)."] have team battled ". + "$opp[3], $opp[4], and $opp[5] ". + "[".($opproll/5)."/".($oppsum/5)."] and $state! ". + duration($gain)." is $moved their clocks.")); } sub rpcheck { @@ -220,4 +221,73 @@ sub rpcheck { } } +sub do_fight { + my ($userhost, $usernick, $username, $source, @arg) = @_; + if (!defined($username)) { + Irpg::Irc::notice("You are not logged in.", $usernick); + return; + } + if (!$rps->{$username}{fight}) { + Irpg::Irc::notice("You feel too tired to handle your weapon.", $usernick); + Irpg::Irc::chanmsg("$username tries to grasp ". + pronoun(2, $rps->{$username}{gender}." weapon, but collapses". + "out of exhaustion."); + return; + } + my @opps = grep { $rps->{$_}{online} && $u ne $_ } keys(%$rps); + if (!@opps) { + Irpg::Irc::notice("Your call echoes in the ambient silence...",$usernick); + Irpg::Irc::chanmsg( + "$username is desperatly searching for an adversary, ". + "but ".pronoun(2, $rps->{$username}{gender})." call remains ". + "unheard in the silent desert of ".pronoun(2, $rps->{$username}. + " loneliness."); + return; + } + my $opp; + if (exists($arg[0]) && !(grep { $arg[0] } @opps)) { + if (exists($rps->{$arg[0]}) { + Irpg::Irc::notice( + "You searched every places you know, but $arg[0] ". + "is nowhere to be found...", $usernick); + } + else { + Irpg::Irc::notice( + "You asked everyone you met, but no one ever ". + "heard of $arg[0].", $usernick); + } + Irpg::Irc::chanmsg( + "$username calls $arg[0] for a fight, but no one can answer ". + pronoun(2, $rps->{$username}{gender}." call."); + return + } + elsif (exists($arg[0])) { + $opp = $arg[0]; + } + else { + $opp = $opps[int(rand(@opps))]; + } + my $res = fight($u, $opp, 1); + $rps->{$username}{fights} -= 1; + my ($state, $moved); + my @ret = (); + if ($res->{vict}) { + ($state, $moved) = ('won', 'removed from'); + } + else { + ($state, $moved) = ('lost', 'added to'); + } + Irpg::Irc::chanmsg(Irpg::Utils::clog( + "$u [$res->{uroll}/$res->{usum}] has provoked $opp [$res->{opproll}/". + "$res->{oppsum}] in a fight and $state! ".duration($res->{gain})." is ". + "$moved $u\'s clock.")); + Irpg::Irc::chanmsg("$u reaches next level in ".duration($rps->{$u}{next})."."); + foreach (@{$res->{queue}}) { Irpg::Irc::chanmsg(Irpg::Utils::clog($_)); } +} + +our $commands = { + fight => {ref => \&do_fight, adm => 0, prv => 1, pub => 1, + hlp => 'FIGHT [<char name>]: fight someone.'} +}; + 1; diff --git a/Irpg/Main.pm b/Irpg/Main.pm index 0a832ad94fb4636647dd074e5d7fed65d997c42e..fa1519ca168e7000fe03fc699c0b298abdbe5e2e 100644 --- a/Irpg/Main.pm +++ b/Irpg/Main.pm @@ -302,6 +302,8 @@ sub rpcheck { # check levels, update database if ($rps->{$k}{online} && exists $rps->{$k}{nick} && $rps->{$k}{nick} && exists $onchan{$rps->{$k}{nick}}) { $rps->{$k}{next} -= ($curtime - $$lasttime_ref); + $rps->{$k}{next_f} -= ($curtime - $$lasttime_ref); + $rps->{$k}{next_f} = 0 if ($rps->{$k}{next_f} < 0); $rps->{$k}{idled} += ($curtime - $$lasttime_ref); if ($rps->{$k}{next} < 1) { $rps->{$k}{level}++; @@ -320,6 +322,12 @@ sub rpcheck { # check levels, update database find_item($k); challenge_opp($k); } + if ($rps->{$k}{next_f} < 1 + && $rps->{$k}{fights} < int($rps->{$k}{level}/10)) { + $rps->{$k}{fights} += 1; + $rps->{$k}{next_f} = 3600; # 1 hour + Irpg::Irc::notice("You feel ready for new fight !", $rps->{$k}{nick}); + } } # attempt to make sure this is an actual user, and not just an # artifact of a bad PEVAL diff --git a/Irpg/Users.pm b/Irpg/Users.pm index e39921ffa1e0204cfc48d81834e1c59ebaa53a42..198e719a732410bfa25c25df9268bc61eb7ea272 100644 --- a/Irpg/Users.pm +++ b/Irpg/Users.pm @@ -93,6 +93,12 @@ sub register { $rps->{$arg[0]}{next} = $opts->{rpbase}; $rps->{$arg[0]}{title} = "@arg[6..$#arg]"; $rps->{$arg[0]}{level} = 0; + foreach (qw(str con wis int cha dex)) { + $rps{$uname}{stats}{$_} = 1; + } + $rps{$uname}{class} = Irpg::Classes::Farmer->new($rps{$uname}{stats}); + $rps{$uname}{fights} = 0; + $rps{$uname}{next_f} = 0; $rps->{$arg[0]}{online} = 1; $rps->{$arg[0]}{nick} = $usernick; $rps->{$arg[0]}{userhost} = $userhost; diff --git a/Irpg/Utils.pm b/Irpg/Utils.pm index 2c0e6118ca1eabf50c7f3032878daf279c9fb28a..edccd03a83444caf5c82d6f57b413b871805f196 100644 --- a/Irpg/Utils.pm +++ b/Irpg/Utils.pm @@ -244,8 +244,8 @@ sub loaddb { # load the players database chomp($l); next if $l =~ /^#/; # skip comments my @i = split("\t",$l); - print Dumper(@i) if @i != 41; - if (@i != 41) { + print Dumper(@i) if @i != 43; + if (@i != 43) { Irpg::Irc::sts("QUIT: Anomaly in loaddb(); line $. of $opts->{dbfile} has ". "wrong fields (".scalar(@i).")"); debug("Anomaly in loaddb(); line $. of $opts->{dbfile} has wrong ". @@ -292,6 +292,8 @@ sub loaddb { # load the players database $rps{$i[0]}{stats}{cha}, $rps{$i[0]}{stats}{dex}, $classname, + $rps{$i[0]}{fights}, + $rps{$i[0]}{next_f}, $rps{$i[0]}{alignment}, $rps{$i[0]}{gender}) = (@i[1..7],($sock?$i[8]:0),@i[9..$#i]); @@ -353,6 +355,8 @@ sub writedb { "char", "dex", "class", + "fights", + "next_f", "alignment", "gender")."\n"; my $k; @@ -398,6 +402,8 @@ sub writedb { $rps->{$k}{stats}{cha}, $rps->{$k}{stats}{dex}, $rps->{$k}{class}->{NAME}, + $rps->{$k}{fights}; + $rps->{$k}{next_f}; $rps->{$k}{alignment}, $rps->{$k}{gender})."\n"; } @@ -443,6 +449,8 @@ sub createdb { $rps{$uname}{stats}{$_} = 1; } $rps{$uname}{class} = Irpg::Classes::Farmer->new($rps{$uname}{stats}); + $rps{$uname}{fights} = 0; + $rps{$uname}{next_f} = 0; $rps{$uname}{online} = 0; $rps{$uname}{idled} = 0; $rps{$uname}{created} = time();