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();