# File ../lib/roller/CWRP.rb, line 688
  def replace_forests(replacements)
    objects_to_add = Array.new # All new objects, that aren't direct replacements.
    num_forests_replaced = 0 # Number of forest objects replaced

    # Add new objects after the last one we already have.
    last_object_id = if @objects.empty?
      0
    else
      @objects.last.id
    end

    reset_progress 'Replacing forests', @objects.size / OBJECTS_PER_PROGRESS

    @objects.each_with_index do |object, index|
      # If replacement has been defined, replace it.
      replacement = replacements[object.name]
      unless replacement.nil?
        forest_id = object.id # ID of the object we are replacing.

        block_dir = object.dir

        total_proportion = replacement[:models].values.inject(0) do |total, value|
          total + value
        end

        # Work out how many to place within the block.
        min = replacement[:min].to_f
        max = replacement[:max].to_f
        to_place = (rand(max - min + 1) + min).floor

        sectors = replacement[:sectors]

        # Place a number of replacement objects.
        to_place.times do

          # Pick a random replacement object from the options.
          pick_proportion = rand() * total_proportion

          replacement[:models].each_pair do |model, proportion|
            pick_proportion -= proportion

            if pick_proportion <= 0
              # Use a copy of the original orientation, so you have the same
              # scale, but then rotate it randomly.
              orientation = object.orientation.deep_copy
              orientation.dir = rand() * 360

              # Work out an appropriate position within the available sectors.
              h_offset, v_offset = random_sector_position(sectors)

              # Rotate the position based on the orientation of the block.
              h_offset, v_offset = rotate(h_offset, v_offset, block_dir)

              # Rotate the position around the block position,
              # based on the block dir.
              # TODO: The height will ALWAYS be wrong, unless on a flat plane.
              position = object.position.deep_copy
              position.x += h_offset
              position.y += v_offset
              position.z = height_at(position.x, position.y)

              # The height (position.z) will be wrong, since object is not in same place!
              if forest_id.nil?
                # Not the first replacement, add object as a new object (not replacing an old ID).
                last_object_id += 1
                objects_to_add.push WrpObject.new(model, last_object_id, position, orientation)
              else
                # The first replacement for this block, so replace the block ID.
                num_forests_replaced += 1
                @objects[index] = WrpObject.new(model, forest_id, position, orientation)
                forest_id = nil
              end

              break
            end
          end
        end
      end

      increment_progress if index.modulo(OBJECTS_PER_PROGRESS) == 0
    end

    @objects += objects_to_add
    
    [num_forests_replaced, objects_to_add.size]
  end