RPGでMoose、その4:クラスとレベルと経験値

RPGMoose、その4:クラスとレベルと経験値

 RPGと言ったらこれがなくっちゃ! ――であるところの経験値とレベルとクラスもそろそろ追加します。

package TG::PC;
use utf8;
use Any::Moose;

use Try::Tiny;

# 経験値、レベル、クラス
has 'expoint' => (
  is => 'rw',
  isa => 'Int',
  writer => "_set_expoint",
);
has 'level' => (
  is => 'rw',
  isa => 'Int',
  writer => "_set_level",
);

has 'class' => (
  is => 'rw',
  isa => 'TG::Class',
  writer => "_set_class",
);

sub add_expoint {
  my $self = shift;
  my($score) = @_;
  die "★経験値は減らせないよ!\n" if $score <= 0;

  $self->_set_expoint($self->expoint + $score);
  $self->append_message('add_expoint', $score);

  while ($self->expoint >= $self->next_expoint) {
    $self->_up_level() or last;
  }
}

sub next_expoint {
  my $self = shift;
  $self->class->next_expoint($self->level);
}

sub _up_level {
  my $self = shift;
  return if $self->level >= 50;

  $self->_set_expoint($self->expoint - $self->next_expoint);
  $self->_set_level($self->level + 1);
  # レベルが上がりました!
  $self->append_message("up_level");

  ## 能力値などの上昇
  my $race = $self->race;

  my $seed = $self->level;
  foreach my $ability ($self->ABILITIES) {
    my $attr = "${ability}_up";
    my $up_score = $race->$attr;
    my $min = int($up_score / 2);
    my $max = $up_score + ($up_score - $min);
    my $score = $self->random($min, $max, $seed++);
    $self->_up_ability($ability, $score);
  }

  ## 種別ランクの上昇
  #if (exists $KIND_UP_LEVEL{$self->level}) {
  #  $self->up_kind();
  #}

}

sub change_class {
  my $self = shift;
  my $class = shift;
  try {
    die "not_enough" unless $class->can_change($self);
    my $cost = $class->cost;
    die "no_money" if $cost > $self->bit;
    $self->_set_bit($self->bit - $cost);
    $self->append_message('pay_bit', $cost);
    $self->_to_class($class);
  }
  catch {
    if ($_ eq "not_enough") {
      # $classnameになるための条件を満たしていません。
      $self->append_message("not_class_cond", $class->bcode, $class->pcode);
    }
    elsif ($_ eq "no_money") {
      # 所持金が足りないため、クラスチェンジできませんでした。
      $self->append_message("not_change_class_money");
    }
    else {
      die $_;
    }
  };
}

sub _to_class {
  my $self = shift;
  my($class) = @_;

  #$self->save_class; # 現在のクラス・レベルを保存

  # 過去にこのクラスになったことがあるか?
  my $level = $self->has_class($class);
  if ($level) {
    $self->_set_level($level);
  }
  else {
    $self->_set_level( 1 );
  }

  $self->_set_class($class);
  $self->_set_expoint( 0 );

  my $race = $self->race;
  foreach my $ability ($self->ABILITIES) {
    my $set = "_set_$ability";
    $self->$set( int(($self->$ability + $race->$ability) / 2) );
  }

  # $classname($classcode)になりました。
  $self->append_message("to_class", $class->bcode, $class->pcode);

  $self;
}

 経験値は増加しかしないルールなので、メソッドとしては「add_expoint」のみ用意しています。

 add_expointの中ではレベルアップするかどうかもチェックしています。次のレベルに必要な経験値は現在のクラスによって異なるので、クラスに計算させています。

 次のレベルに必要な経験値に達していたら「_up_level」でレベルアップさせます(レベルは複数上がる事もあります)。

 レベルが上がると能力値も上がります。どれくらい上昇するかは種族毎に決まっています。

 クラスチェンジも「change_class」でできます。

 まずはクラスチェンジ条件を調べ、それを満たしていたら必要に応じて料金を払ってクラスチェンジします。

 もし以前にそのクラスになっていたら、レベルは以前のレベルになります。なったことななければレベルは1になります。

 また、クラスチェンジをすると能力値が現在値と初期値との中間になります。

 ……いろいろ面倒くさいことしてましたな。

 説明してないメソッドとか平気で出てきてるけど、まあ気にしない。