<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -11,5 +11,14 @@ module Apocalypse
     include Skills
     include Perks
     include Dumper
+
+    attr_accessor :name, :age
+
+    def initialize(*args)
+      options = args.last.is_a?(Hash) ? args.last : {}
+      @name = options[:name]
+      @age = options[:age]
+      super
+    end
   end
 end</diff>
      <filename>lib/apocalypse/character.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,24 +1,32 @@
 module Apocalypse
-  module Perk
-    def self.extended(base)
-      base.extend ClassMethods
+  class Perk
+    attr_reader :owner
+    attr_reader :rank
+    attr_reader :name, :description, :requirements, :max_rank
+
+    def initialize(owner)
+      @owner = owner
+      @requirements = {}
+      @max_rank = 1
+      @rank = 1
     end
 
-    module ClassMethods
-      def description
-        @description
-      end
+    def name
+      @name ||= self.class.to_s.demodulize.titleize
+    end
 
-      def name
-        @name ||= self.to_s.demodulize.titleize
-      end
+    def allows_rank_increase?
+      rank &lt; max_rank
+    end
 
-      def requirements
-        @requirements ||= {}
-      end
+    def increase_rank!
+      @rank += 1 if allows_rank_increase?
+      @rank
+    end
 
-      def ranks
-        @ranks ||= 1
+    class &lt;&lt; self
+      def for(owner)
+        new(owner)
       end
     end
   end</diff>
      <filename>lib/apocalypse/perk.rb</filename>
    </modified>
    <modified>
      <diff>@@ -17,13 +17,14 @@ module Apocalypse
       end
     end
 
-    def initialize(*params)
-      super(*params)
+    def initialize(*args)
       @perks = {}
     end
 
-    def add_perk(perk)
-      if perk.is_a?(Perk) &amp;&amp; meets_requirements_for?(perk) &amp;&amp; rank_limit_allows?(perk)
+    def add_perk(perk_class)
+      return(false) unless perk_class.superclass == Perk
+      perk = perk_class.for(self)
+      if meets_requirements_for?(perk)
         apply_perk(perk)
         return true
       else
@@ -31,15 +32,14 @@ module Apocalypse
       end
     end
 
-    def perk_rank(perk)
-      @perks[perk].to_i
-    end
-
     private
     def apply_perk(perk)
-      @perks[perk] ||= 0
-      @perks[perk] += 1
-      self.class.send(:include, perk)
+      if @perks[perk.class]
+        @perks[perk.class].increase_rank!
+      else
+        @perks[perk.class] = perk
+      end
+      @perks[perk.class]
     end
 
     def meets_requirements_for?(perk)
@@ -48,9 +48,5 @@ module Apocalypse
       end
       true
     end
-
-    def rank_limit_allows?(perk)
-      perk_rank(perk) &lt; perk.ranks
-    end
   end
 end</diff>
      <filename>lib/apocalypse/perks.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,12 +2,13 @@ require 'perk'
 
 module Apocalypse
   module Perks
-    module GunNut
-      extend Perk
-
-      @requirements = { :level =&gt; 2, :agility =&gt; 4, :inteligence =&gt; 4 }
-      @description = &quot;You are obsessed with using and maintaining a wide variety of conventional firearms. With each rank of the Gun Nut perk, you gain an additional 5 points to the Small Guns and Repair skills.&quot;
-      @ranks = 3
+    class GunNut &lt; Perk
+      def initialize(*args)
+        super
+        @requirements = { :level =&gt; 2, :agility =&gt; 4, :inteligence =&gt; 4 }
+        @description = &quot;You are obsessed with using and maintaining a wide variety of conventional firearms. With each rank of the Gun Nut perk, you gain an additional 5 points to the Small Guns and Repair skills.&quot;
+        @max_rank = 3
+      end
 
       def small_guns
         super + (perk_rank(GunNut) * 5)</diff>
      <filename>lib/apocalypse/perks/gun_nut.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,12 +2,12 @@ require 'perk'
 
 module Apocalypse
   module Perks
-    module StrongBack
-      extend Perk
-
-      @requirements = { :level =&gt; 8, :endurance =&gt; 5, :strength =&gt; 5 }
-      @description = &quot;You can carry an additional 50 lbs. of equipment with each level of this perk.&quot;
-      @ranks = 1
+    class StrongBack &lt; Perk
+      def initialize(*args)
+        super
+        @requirements = { :level =&gt; 8, :endurance =&gt; 5, :strength =&gt; 5 }
+        @description  = &quot;You can carry an additional 50 lbs. of equipment with each level of this perk.&quot;
+      end
 
       def carry_weight
         super + (perk_rank(StrongBack) * 50)</diff>
      <filename>lib/apocalypse/perks/strong_back.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,12 +2,12 @@ require 'perk'
 
 module Apocalypse
   module Perks
-    module Thief
-      extend Perk
-
-      @description = &quot;With each rank of Thief perk, you gain an immediate bonus of 5 points to both the Sneak and Lockpick skills.&quot;
-      @requirements = { :level =&gt; 2, :agility =&gt; 4, :perception =&gt; 4 }
-      @ranks = 1
+    class Thief &lt; Perk
+      def initialize(*args)
+        super
+        @description = &quot;With each rank of Thief perk, you gain an immediate bonus of 5 points to both the Sneak and Lockpick skills.&quot;
+        @requirements = { :level =&gt; 2, :agility =&gt; 4, :perception =&gt; 4 }
+      end
 
       def sneak
         super + 5</diff>
      <filename>lib/apocalypse/perks/thief.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,15 @@ require 'spec/spec_helper'
 describe Apocalypse::Character do
   describe &quot;new character&quot; do
     before(:each) do
-      @character = Apocalypse::Character.new
+      @character = Apocalypse::Character.new(character_attrs(:name =&gt; 'Peter', :age =&gt; 25))
+    end
+
+    it &quot;has a name&quot; do
+      @character.name.should == 'Peter'
+    end
+
+    it &quot;has age&quot; do
+      @character.age.should == 25
     end
 
     all_stats.each do |stat|</diff>
      <filename>spec/apocalypse/character_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,21 +1,34 @@
 require 'spec/spec_helper'
 
-module TestPerk
-  extend Apocalypse::Perk
-  @description = &quot;What a nice description&quot;
-  @requirements = { :level =&gt; 2 }
+class TestPerk &lt; Apocalypse::Perk
+  def initialize(*args)
+    super
+    @description = &quot;What a nice description&quot;
+    @requirements = { :level =&gt; 2 }
+  end
 end
 
-module TestADifferentPerk
-  extend Apocalypse::Perk
-  @name = &quot;This is a nice perk!&quot;
-  @ranks = 2
+class TestADifferentPerk &lt; Apocalypse::Perk
+  def initialize(*args)
+    super
+    @name = &quot;This is a nice perk!&quot;
+    @max_rank = 2
+  end
 end
 
 describe Apocalypse::Perk do
   before(:each) do
-    @perk = TestPerk
-    @other_perk = TestADifferentPerk
+    @character = new_character
+    @perk = TestPerk.new(@character)
+    @other_perk = TestADifferentPerk.new(@character)
+  end
+
+  it &quot;should be a perk&quot; do
+    @perk.class.superclass.should == Apocalypse::Perk
+  end
+
+  it &quot;has an owner&quot; do
+    @perk.owner.should == @character
   end
 
   it &quot;includes description method&quot; do
@@ -31,15 +44,29 @@ describe Apocalypse::Perk do
     @other_perk.requirements.should == {}
   end
 
-  it &quot;uses a custom name if available&quot; do
+  it &quot;uses specified name if available&quot; do
     @other_perk.name.should == 'This is a nice perk!'
   end
 
-  it &quot;includes ranks method&quot; do
-    @perk.ranks.should == 1
+  it &quot;includes current rank method&quot; do
+    @perk.rank.should == 1
+  end
+
+  it &quot;uses defined max_rank if available&quot; do
+    @other_perk.max_rank.should == 2
+  end
+
+  it &quot;allows rank increase if current rank is less than max&quot; do
+    @other_perk.allows_rank_increase?.should be_true
+    @other_perk.stub!(:rank).and_return @other_perk.max_rank
+    @other_perk.allows_rank_increase?.should be_false
   end
 
-  it &quot;uses custom ranks iv available&quot; do
-    @other_perk.ranks.should == 2
+  it &quot;increases rank if allowed&quot; do
+    @other_perk.rank.should == 1
+    @other_perk.increase_rank!
+    @other_perk.rank.should == 2
+    @other_perk.increase_rank!
+    @other_perk.rank.should == 2
   end
 end</diff>
      <filename>spec/apocalypse/perk_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,16 +1,20 @@
 require 'spec/spec_helper'
 
-module RequiredPerk
-  extend Apocalypse::Perk
-  @requirements = { :level =&gt; 3, :agility =&gt; 7, :perception =&gt; 8 }
+class RequiredPerk &lt; Apocalypse::Perk
+  def initialize(*args)
+    super
+    @requirements = { :level =&gt; 3, :agility =&gt; 7, :perception =&gt; 8 }
+  end
 end
 
-module NotAPerk
+class NotAPerk
 end
 
-module YesAPerk
-  extend Apocalypse::Perk
-  @ranks = 2
+class YesAPerk &lt; Apocalypse::Perk
+  def initialize(*args)
+    super
+    @max_rank = 2
+  end
 end
 
 describe Apocalypse::Perks do
@@ -25,13 +29,14 @@ describe Apocalypse::Perks do
   it &quot;lists all available perks&quot; do
     @perks.all.should == [
       Apocalypse::Perks::GunNut,
+      Apocalypse::Perks::StrongBack,
       Apocalypse::Perks::Thief
     ]
   end
 
   describe &quot;#apply_perks&quot; do
     before(:each) do
-      @character = Apocalypse::Character.new
+      @character = new_character
       @required_perk = RequiredPerk
     end
 
@@ -45,44 +50,46 @@ describe Apocalypse::Perks do
 
     it &quot;does not apply a perk if requirements are not met&quot; do
       @character.add_perk(RequiredPerk).should be_false
-      @character.perks.should_not include(RequiredPerk)
+      @character.perks.keys.should_not include(RequiredPerk)
 
       @character.stub!(:level).and_return(3)
       @character.add_perk(RequiredPerk).should be_false
-      @character.perks.should_not include(RequiredPerk)
-
+      @character.perks.keys.should_not include(RequiredPerk)
 
       @character.stub!(:agility).and_return(7)
       @character.add_perk(RequiredPerk).should be_false
-      @character.perks.should_not include(RequiredPerk)
+      @character.perks.keys.should_not include(RequiredPerk)
 
       @character.stub!(:perception).and_return(8)
       @character.add_perk(RequiredPerk).should be_true
-      @character.perks.should include(RequiredPerk)
+      @character.perks.keys.should include(RequiredPerk)
     end
 
     it &quot;does not apply a perk if rank limit is matched&quot; do
-      @character.add_perk(YesAPerk).should be_true
-      @character.perk_rank(YesAPerk).should == 1
+      @character.add_perk(YesAPerk)
+      @character.perks[YesAPerk].rank.should == 1
 
-      @character.add_perk(YesAPerk).should be_true
-      @character.perk_rank(YesAPerk).should == 2
+      @character.add_perk(YesAPerk)
+      @character.perks[YesAPerk].rank.should == 2
 
-      @character.add_perk(YesAPerk).should be_false
-      @character.perk_rank(YesAPerk).should == 2
+      @character.add_perk(YesAPerk)
+      @character.perks[YesAPerk].rank.should == 2
     end
   end
 end
 
 describe &quot;Perks&quot; do
+  before(:each) do
+    @character = new_character
+  end
   Apocalypse::Perks.all.each do |perk|
     describe perk.to_s.split('::').last do
       it &quot;has a description&quot; do
-        perk.description.should_not be_empty
+        perk.new(@character).description.should_not be_empty
       end
 
       it &quot;has a name&quot; do
-        perk.name.should_not be_empty
+        perk.new(@character).name.should_not be_empty
       end
     end
   end</diff>
      <filename>spec/apocalypse/perks_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,3 +6,4 @@
 --format failing_examples:previous_failures.txt
 --example previous_failures.txt
 --timeout 20
+--debugger</diff>
      <filename>spec/spec.opts</filename>
    </modified>
    <modified>
      <diff>@@ -8,3 +8,14 @@ end
 def all_skills
   %w(barter big_guns energy_weapons explosives lockpick medicine melee_weapons repair science small_guns sneak unarmed)
 end
+
+def character_attrs(attrs = {})
+  {
+    :name =&gt; 'John',
+    :age =&gt; 20
+  }.merge(attrs)
+end
+
+def new_character
+  Apocalypse::Character.new(character_attrs)
+end</diff>
      <filename>spec/spec_helper.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>b6b3147079802e02eb025a3dc4181bd468e703fc</id>
    </parent>
  </parents>
  <author>
    <name>Piotr Usewicz</name>
    <email>piotr@layer22.com</email>
  </author>
  <url>http://github.com/pusewicz/apocalypse/commit/90894e0643740b3359d77587ef4e340fd2322536</url>
  <id>90894e0643740b3359d77587ef4e340fd2322536</id>
  <committed-date>2009-10-12T13:39:16-07:00</committed-date>
  <authored-date>2009-10-12T13:39:16-07:00</authored-date>
  <message>Changed perk system to use objects</message>
  <tree>bc4ac2474188e77118bd1a81f99978bef3fb6382</tree>
  <committer>
    <name>Piotr Usewicz</name>
    <email>piotr@layer22.com</email>
  </committer>
</commit>
