--- deliantra/Deliantra/Deliantra.pm 2007/02/27 23:29:59 1.89 +++ deliantra/Deliantra/Deliantra.pm 2007/03/03 18:58:25 1.90 @@ -141,8 +141,94 @@ sub MOVE_SWIM (){ 0x08 } sub MOVE_BOAT (){ 0x10 } sub MOVE_KNOWN (){ 0x1f } # all of above -sub MOVE_ALLBIT (){ 0x10000 } -sub MOVE_ALL (){ 0x1001f } # very special value, more PITA +sub MOVE_ALL (){ 0x10000 } # very special value + +our %MOVE_TYPE = ( + walk => MOVE_WALK, + fly_low => MOVE_FLY_LOW, + fly_high => MOVE_FLY_HIGH, + flying => MOVE_FLYING, + swim => MOVE_SWIM, + boat => MOVE_BOAT, + all => MOVE_ALL, +); + +our @MOVE_TYPE = qw(all walk flying fly_low fly_high swim boat); + +{ + package Crossfire::MoveType; + + use overload + '""' => \&as_string, + '>=' => sub { $_[0][0] & $MOVE_TYPE{$_[1]} ? $_[0][1] & $MOVE_TYPE{$_[1]} : undef }, + '+=' => sub { $_[0][0] |= $MOVE_TYPE{$_[1]}; $_[0][1] |= $MOVE_TYPE{$_[1]}; &normalise }, + '-=' => sub { $_[0][0] |= $MOVE_TYPE{$_[1]}; $_[0][1] &= ~$MOVE_TYPE{$_[1]}; &normalise }, + '/=' => sub { $_[0][0] &= ~$MOVE_TYPE{$_[1]}; &normalise }, + 'x=' => sub { + my $cur = $_[0] >= $_[1]; + if (!defined $cur) { + $_[0] += $_[1]; + } elsif ($cur) { + $_[0] -= $_[1]; + } else { + $_[0] /= $_[1]; + } + + $_[0] + }, + ; +} + +sub Crossfire::MoveType::new { + my ($class, $string) = @_; + + my $mask; + my $value; + + for (split /\s+/, lc $string) { + if (s/^-//) { + $mask |= $MOVE_TYPE{$_}; + $value &= ~$MOVE_TYPE{$_}; + } else { + $mask |= $MOVE_TYPE{$_}; + $value |= $MOVE_TYPE{$_}; + } + } + + (bless [$mask, $value], $class)->normalise +} + +sub Crossfire::MoveType::normalise { + my ($self) = @_; + + if ($self->[0] & MOVE_ALL) { + my $mask = ~(($self->[1] & MOVE_ALL ? $self->[1] : ~$self->[1]) & $self->[0] & ~MOVE_ALL); + $self->[0] &= $mask; + $self->[1] &= $mask; + } + + $self->[1] &= $self->[0]; + + $self +} + +sub Crossfire::MoveType::as_string { + my ($self) = @_; + + my @res; + + my ($mask, $value) = @$self; + + for (@Crossfire::MOVE_TYPE) { + my $bit = $Crossfire::MOVE_TYPE{$_}; + if (($mask & $bit) == $bit && (($value & $bit) == $bit || ($value & $bit) == 0)) { + $mask &= ~$bit; + push @res, $value & $bit ? $_ : "-$_"; + } + } + + join " ", @res +} sub load_ref($) { my ($path) = @_; @@ -270,66 +356,31 @@ for my $attr (keys %FIELD_MOVEMENT) { next unless exists $ob->{$attr}; - $ob->{$attr} = MOVE_ALL if $ob->{$attr} == 255; #d# compatibility - - next if $ob->{$attr} =~ /^\d+$/; - - my $flags = 0; - - # assume list - for my $flag (map lc, split /\s+/, $ob->{$attr}) { - $flags |= MOVE_WALK if $flag eq "walk"; - $flags |= MOVE_FLY_LOW if $flag eq "fly_low"; - $flags |= MOVE_FLY_HIGH if $flag eq "fly_high"; - $flags |= MOVE_FLYING if $flag eq "flying"; - $flags |= MOVE_SWIM if $flag eq "swim"; - $flags |= MOVE_BOAT if $flag eq "boat"; - $flags |= MOVE_ALL if $flag eq "all"; - - $flags &= ~MOVE_WALK if $flag eq "-walk"; - $flags &= ~MOVE_FLY_LOW if $flag eq "-fly_low"; - $flags &= ~MOVE_FLY_HIGH if $flag eq "-fly_high"; - $flags &= ~MOVE_FLYING if $flag eq "-flying"; - $flags &= ~MOVE_SWIM if $flag eq "-swim"; - $flags &= ~MOVE_BOAT if $flag eq "-boat"; - $flags &= ~MOVE_ALL if $flag eq "-all"; - } - - $ob->{$attr} = $flags; + $ob->{$attr} = new Crossfire::MoveType $ob->{$attr}; } # convert outdated movement flags to new movement sets if (defined (my $v = delete $ob->{no_pass})) { - $ob->{move_block} = $v ? MOVE_ALL : 0; + $ob->{move_block} = new Crossfire::MoveType $v ? "all" : ""; } if (defined (my $v = delete $ob->{slow_move})) { - $ob->{move_slow} |= MOVE_WALK; + $ob->{move_slow} += "walk"; $ob->{move_slow_penalty} = $v; } if (defined (my $v = delete $ob->{walk_on})) { - $ob->{move_on} = 0 unless exists $ob->{move_on}; - $ob->{move_on} = $v ? $ob->{move_on} | MOVE_WALK - : $ob->{move_on} & ~MOVE_WALK; + $ob->{move_on} ||= new Crossfire::MoveType; if ($v) { $ob->{move_on} += "walk" } else { $ob->{move_on} -= "walk" } } if (defined (my $v = delete $ob->{walk_off})) { - $ob->{move_off} = 0 unless exists $ob->{move_off}; - $ob->{move_off} = $v ? $ob->{move_off} | MOVE_WALK - : $ob->{move_off} & ~MOVE_WALK; + $ob->{move_off} ||= new Crossfire::MoveType; if ($v) { $ob->{move_off} += "walk" } else { $ob->{move_off} -= "walk" } } if (defined (my $v = delete $ob->{fly_on})) { - $ob->{move_on} = 0 unless exists $ob->{move_on}; - $ob->{move_on} = $v ? $ob->{move_on} | MOVE_FLY_LOW - : $ob->{move_on} & ~MOVE_FLY_LOW; + $ob->{move_on} ||= new Crossfire::MoveType; if ($v) { $ob->{move_on} += "fly_low" } else { $ob->{move_on} -= "fly_low" } } if (defined (my $v = delete $ob->{fly_off})) { - $ob->{move_off} = 0 unless exists $ob->{move_off}; - $ob->{move_off} = $v ? $ob->{move_off} | MOVE_FLY_LOW - : $ob->{move_off} & ~MOVE_FLY_LOW; + $ob->{move_off} ||= new Crossfire::MoveType; if ($v) { $ob->{move_off} += "fly_low" } else { $ob->{move_off} -= "fly_low" } } if (defined (my $v = delete $ob->{flying})) { - $ob->{move_type} = 0 unless exists $ob->{move_type}; - $ob->{move_type} = $v ? $ob->{move_type} | MOVE_FLY_LOW - : $ob->{move_type} & ~MOVE_FLY_LOW; + $ob->{move_type} ||= new Crossfire::MoveType; if ($v) { $ob->{move_type} += "fly_low" } else { $ob->{move_type} -= "fly_low" } } # convert idiotic event_xxx things into objects @@ -595,32 +646,6 @@ if (my $end = $Crossfire::FIELD_MULTILINE{$k}) { $v =~ s/\n$//; $str .= "$k\n$v\n$end\n"; - } elsif (exists $Crossfire::FIELD_MOVEMENT{$k}) { - if ($v & ~Crossfire::MOVE_ALL or !$v) { - $str .= "$k $v\n"; - - } elsif ($v & Crossfire::MOVE_ALLBIT) { - $str .= "$k all"; - - $str .= " -walk" unless $v & Crossfire::MOVE_WALK; - $str .= " -fly_low" unless $v & Crossfire::MOVE_FLY_LOW; - $str .= " -fly_high" unless $v & Crossfire::MOVE_FLY_HIGH; - $str .= " -swim" unless $v & Crossfire::MOVE_SWIM; - $str .= " -boat" unless $v & Crossfire::MOVE_BOAT; - - $str .= "\n"; - - } else { - $str .= $k; - - $str .= " walk" if $v & Crossfire::MOVE_WALK; - $str .= " fly_low" if $v & Crossfire::MOVE_FLY_LOW; - $str .= " fly_high" if $v & Crossfire::MOVE_FLY_HIGH; - $str .= " swim" if $v & Crossfire::MOVE_SWIM; - $str .= " boat" if $v & Crossfire::MOVE_BOAT; - - $str .= "\n"; - } } else { $str .= "$k $v\n"; }