Deliantra

 view release on metacpan or  search on metacpan

Deliantra.pm  view on Meta::CPAN

our %FACE; # face32
our %FACEDATA;
our $TILE;

our %FIELD_MULTILINE = (
   msg     => "endmsg",
   lore    => "endlore",
   maplore => "endmaplore",
);

# movement bit type, PITA
our %FIELD_MOVEMENT = map +($_ => undef),
   qw(move_type move_block move_allow move_on move_off move_slow);

# same as in server save routine, to (hopefully) be compatible
# to the other editors.
our @FIELD_ORDER_MAP = (qw(
   file_format_version
   name attach swap_time reset_timeout fixed_resettime difficulty
   region music
   shopitems shopgreed shopmin shopmax shoprace
   darkness width height enter_x enter_y msg maplore
   unique template
   outdoor temp pressure humid windspeed winddir sky nosmooth
   tile_path_1 tile_path_2 tile_path_3 tile_path_4
));

our @FIELD_ORDER = (qw(
   inherit

   elevation

   name name_pl custom_name attach title race
   slaying skill msg lore other_arch
   sound sound_destroy face animation is_animated
   magicmap glyph smoothlevel smoothface
   str dex con wis pow cha int
   hp maxhp sp maxsp grace maxgrace
   exp perm_exp expmul
   food dam luck wc ac x y speed speed_left move_state attack_movement
   nrof level direction type subtype attacktype

   resist_physical resist_magic resist_fire resist_electricity 
   resist_cold resist_confusion resist_acid resist_drain 
   resist_weaponmagic resist_ghosthit resist_poison resist_slow 
   resist_paralyze resist_turn_undead resist_fear resist_cancellation 
   resist_deplete resist_death resist_chaos resist_counterspell 
   resist_godpower resist_holyword resist_blind resist_internal 
   resist_life_stealing resist_disease

   path_attuned path_repelled path_denied material materialname
   value carrying weight invisible state magic
   last_heal last_sp last_grace last_eat
   connected glow_radius randomitems tresure_env npx_status npc_program
   run_away pick_up container will_apply smoothlevel
   current_weapon_script weapontype tooltype elevation client_type
   item_power duration range
   range_modifier duration_modifier dam_modifier gen_sp_armour
   move_type move_block move_allow move_on move_off move_on move_slow move_slow_penalty

   alive wiz was_wiz applied unpaid can_use_shield no_pick is_animated monster
   friendly generator is_thrown auto_apply treasure player sold see_invisible
   can_roll overlay_floor is_turnable is_used_up identified reflecting changing
   splitting hitback startequip blocksview undead scared unaggressive
   reflect_missile reflect_spell no_magic no_fix_player is_lightable tear_down
   run_away pick_up unique no_drop can_cast_spell can_use_scroll can_use_range
   can_use_bow can_use_armour can_use_weapon can_use_ring has_ready_range
   has_ready_bow xrays is_floor lifesave no_strength sleep stand_still
   random_move only_attack confused stealth cursed damned see_anywhere
   known_magical known_cursed can_use_skill been_applied has_ready_scroll
   can_use_rod can_use_horn make_invisible inv_locked is_wooded is_hilly
   has_ready_skill has_ready_weapon no_skill_ident is_blind can_see_in_dark
   is_cauldron is_dust no_steal one_hit berserk neutral no_attack no_damage
   activate_on_push activate_on_release is_water use_content_on_gen is_buildable
   precious

   body_range body_arm body_torso body_head body_neck body_skill
   body_finger body_shoulder body_foot body_hand body_wrist body_waist
));

our %EVENT_TYPE = (
   apply   =>  1,
   attack  =>  2,
   death   =>  3,
   drop    =>  4,
   pickup  =>  5,
   say     =>  6,
   stop    =>  7,
   time    =>  8,
   throw   =>  9,
   trigger => 10,
   close   => 11,
   timer   => 12,
);

# 1 up 2 right 4 down 8 left
our %WALLDIR = (
  0     =>  0,
  1_2   =>  1,
  1_4   =>  2,
  2_2_1 =>  3,
  1_1   =>  4,
  2_1_1 =>  5,
  2_2_2 =>  6,
  3_2   =>  7,
  1_3   =>  8,
  2_2_4 =>  9,
  2_1_2 => 10,
  3_1   => 11,
  2_2_3 => 12,
  3_4   => 13,
  3_3   => 14,
  4     => 15,
);

sub MOVE_WALK      (){ 0x01 }
sub MOVE_FLY_LOW   (){ 0x02 }
sub MOVE_FLY_HIGH  (){ 0x04 }
sub MOVE_FLYING    (){ 0x06 }
sub MOVE_SWIM      (){ 0x08 }
sub MOVE_BOAT      (){ 0x10 }

Deliantra.pm  view on Meta::CPAN

   my $face = $FACE{$a->{face} || $o->{face} || "blank.111"};
   unless ($face) {
      $face = $FACE{"blank.x11"}
         or (warn "no face data found for arch '$a->{_name}'"), return;
   }

   if ($face->{w} > 1 || $face->{h} > 1) { 
      # bigface
      return (0, 0, $face->{w} - 1, $face->{h} - 1);

   } elsif ($o->{more}) {
      # linked face
      my ($minx, $miny, $maxx, $maxy) = ($o->{x}, $o->{y}) x 2;

      for (; $o; $o = $o->{more}) {
         $minx = min $minx, $o->{x};
         $miny = min $miny, $o->{y};
         $maxx = max $maxx, $o->{x};
         $maxy = max $maxy, $o->{y};
      }

      return ($minx, $miny, $maxx, $maxy);

   } else {
      # single face
      return (0, 0, 0, 0);
   }
}

=item $type = arch_attr $arch

Returns a hashref describing the object and its attributes. It can contain
the following keys:

   name   the name, suitable for display purposes
   ignore
   attr
   desc
   use
   section => [name => \%attr, name => \%attr]
   import

=cut

sub arch_attr($) {
   my ($obj) = @_;

   require Deliantra::Data;

   my $root;
   my $attr = { };
   
   my $arch = $ARCH{ $obj->{_name} };
   my $type = $obj->{type} || $arch->{type};

   if ($type > 0) {
      $root = $Deliantra::Data::ATTR{$type};
   } else {
      my %a = (%$arch, %$obj);

      if ($a{is_floor} && !$a{alive}) {
         $root = $Deliantra::Data::TYPE{Floor};
      } elsif (!$a{is_floor} && $a{alive} && !$a{tear_down}) {
         $root = $Deliantra::Data::TYPE{"Monster & NPC"};
      } elsif (!$a{is_floor} && !$a{alive} && $a{move_block}) {
         $root = $Deliantra::Data::TYPE{Wall};
      } elsif (!$a{is_floor} && $a{alive} && $a{tear_down}) {
         $root = $Deliantra::Data::TYPE{"Weak Wall"};
      } else {
         $root = $Deliantra::Data::TYPE{Misc};
      }
   }

   my (%ignore);
   my @import = ($root);

   my @new_import;
   while (my $type = shift @import) {
      # first import everything we will need:
      push @import,
         grep $_,
            map $Deliantra::Data::TYPE{$_},
               @{$type->{import} || []};

      # and compute the ignored attributes
      for (@{$type->{ignore} || []}) {
         $ignore{$_}++ for ref $_ ? @$_ : $_;
      }

      push @new_import, $type;
   }
   (@import) = @new_import;

   # then add defaults to the back of the list, so they are added
   # as last resort.
   push @import, \%Deliantra::Data::DEFAULT_ATTR
      unless $type == 116;

   my (@section_order, %section, @attr_order);

   # @import = root, imported, default
   while (my $type = pop @import) {
      $attr->{$_} ||= $type->{$_}
         for qw(name desc use);

      for ([general => ($type->{attr} || [])], @{$type->{section} || []}) {
         my ($name, $attr) = @$_;
         push @section_order, $name;
         for (@$attr) {
            my ($k, $v) = @$_;
            push @attr_order, $k;
            $section{$name}{$k} = $v; # overwrite, so that the root decides
         }
      }
   }

   # remove ignores for "root" type
   for (
      map @{$_->[1]}, # section attributes
        [general => ($root->{attr} || [])],
        @{$root->{section} || []}
   ) {
      my ($k, $v) = @$_;
      # skip fixed attributes, if they are ignored thats fine
      next if $v->{type} eq 'fixed';

      delete $ignore{$k}; # if the attributes are defined explicitly they



( run in 1.633 second using v1.01-cache-2.11-cpan-df04353d9ac )