public
Description: A set of utilities for creating and manipulating tilesets for NetHack, Slash'EM and other variants
Homepage: http://clivecrous.lighthouseapp.com/projects/11276/home
Clone URL: git://github.com/clivecrous/nethack-tiles.git
nethack-tiles / nhtiles.rb
100644 186 lines (156 sloc) 5.072 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
require 'RMagick'
 
class TilesTask
  def task_instance
    Rake::Task[ task_name ]
  end
end
 
class Tile
  attr_reader :name
 
  def initialize name
    @name = name
  end
end
 
class Tileset < TilesTask
  attr_reader :name, :path, :format, :variant, :width, :height, :fullpath, :fullpath
 
  def initialize name, path, format, variant, width, height
    @name = name
    @path = path
    @format = format
    @variant = variant
    @width = width
    @height = height
 
    @fullname = "#{@name}.#{@format}"
    @fullpath = "#{@path}/#{@fullname}"
 
    if not File.exists? @fullpath # Is this an output tileset?
      @fullname = "#{@name}_#{@width}x#{height}.#{@format}"
      @injectpath = "#{@path}/.injected/#{variant.name}/#{@fullname}" # This must be before redefining @path
      @path="#{path}/#{variant.name}"
      @fullpath = "#{@path}/#{@fullname}"
    else
      @injectpath = "#{@path}/.injected/#{@fullname}"
    end
 
    @image = nil
 
    @tileswritten = 0
 
    @injected = []
 
    @variant.task_instance.prerequisites << task_name
    directory @path
    directory @injectpath
    file task_name => [@path] do
      if @tileswritten > 0 then
        puts "Creating/Writing (Injected #{@tileswritten} tiles) in Tileset: #{@fullpath}"
        @image.write @fullpath
        @injected.each do |injecttile|
          File::new injecttile, "w"
        end
      end
    end
  end
 
  def image
    if !@image
      if File.exists? @fullpath
        puts "Loading #{@fullpath}"
        @image = Magick::Image.read( @fullpath )[0]
      else
        total = @variant.tilenames.size
        columns = 40
        width = columns*@width
        height = ((total+(columns-1))/columns)*@height
        puts "Creating #{@fullpath} at #{width}x#{height} with #{columns} columns"
        @image = Magick::Image.new( width, height ) do
          self.background_color = Magick::Pixel.new 0, 0, 0, Magick::MaxRGB
        end
      end
    end
    @image
  end
 
  def add_source_tilegroup tilegroup
    Rake::Task[ @variant.task_name ].prerequisites << task_name
    total = @variant.tilenames.size
    @variant.tilenames.each_with_index do |tilename,index|
      tilepath = "#{tilegroup.fullpath}/#{tilename}.#{tilegroup.format}"
      tiletask = "Inject tile: #{fullpath} #{tilepath}"
      injecttile = "#{@injectpath}/#{tilename}"
      if task_instance.prerequisites.index( injecttile ) == nil then
        task_instance.prerequisites << injecttile
        file injecttile => [ tilepath, @injectpath ] do
          columns = image.columns/@width
          #puts "#{tilename} [#{index+1} of #{total}] => #{@fullpath}"
          tile = Magick::Image.read( tilepath ) do
            self.size = Magick::Geometry.new( tilegroup.width, tilegroup.height )
          end[0]
          if tile then
            @image.composite! tile.resize( @width, @height ),
              (index%columns)*@width, (index/columns)*@height,
              Magick::OverCompositeOp
            @tileswritten += 1
          end
          @injected << injecttile
        end
      end
    end
  end
 
  def task_name
    "tileset: #{@fullpath}"
  end
 
end
 
class TileGroup < TilesTask
  attr_reader :name, :path, :format, :fullpath, :width, :height
 
  def initialize name, path, format, width, height
    @name = name
    @path = path
    @format = format
    @width = width
    @height = height
    @fullpath = "#{@path}/#{@name}/#{format}"
    @tileswritten = 0
 
    directory @fullpath
    task task_name => [@fullpath] do
      puts "Created/Updated #{@tileswritten} tiles in TileGroup: #{@fullpath}" if @tileswritten > 1
    end
  end
 
  def add_source_tileset tileset
    Rake::Task[ tileset.variant.task_name ].prerequisites << task_name
    total = tileset.variant.tilenames.size
    columns = nil
    tileset.variant.tilenames.each_with_index do |tilename,index|
      tilepath = "#{@fullpath}/#{tilename}.#{format}"
      if task_instance.prerequisites.index( tilepath ) == nil then
        task_instance.prerequisites << tilepath
        file tilepath => [tileset.fullpath,@fullpath] do
          columns = tileset.image.columns/tileset.width if !columns
          #puts "#{tileset.name} [#{index+1} of #{total}] => #{tilepath}"
          tileset.image.crop((index%columns)*tileset.width,(index/columns)*tileset.height,tileset.width,tileset.height).resize(@width,@height).write tilepath
          @tileswritten += 1
        end
      end
    end
  end
 
  def task_name
    "tilegroup: #{@fullpath}"
  end
 
end
 
class Variant < TilesTask
  attr_reader :name
  attr_reader :tilenames
 
  def initialize name, filename
    @name = name
    @tilenames = []
 
    File.readlines( filename ).each do |line|
      @tilenames << line.chomp
    end
 
    task task_name => []
  end
 
  def task_name
    "variant: #{@name}"
  end
 
end
 
class Variants < Hash
  def initialize directory
    super()
    @directory = directory
    FileList[ "#{directory}/*" ].each do |path|
      variant_name = File::basename( path ).to_sym
      self[ variant_name ] = Variant.new( variant_name, path )
    end
  end
end