Class NWN::Tlk::Tlk

  1. lib/nwn/tlk.rb
Parent: Object

Tlk wraps a File object that points to a .tlk file.

Methods

public class

  1. new

public instance

  1. []
  2. add
  3. highest_id
  4. write_to

Constants

HEADER_SIZE = 20
DATA_ELEMENT_SIZE = 4 + 16 + 4 + 4 + 4 + 4 + 4

Attributes

cache [R]
language [R] The language_id of this Tlk.

Public class methods

new (io)

Cereate

[show source]
# File lib/nwn/tlk.rb, line 32
      def initialize io
        @io = io

        # Read the header
        @file_type, @file_version, language_id,
          string_count, string_entries_offset =
            @io.e_read(HEADER_SIZE, "header").unpack("A4 A4 I I I")

        raise IOError, "The given IO does not describe a valid tlk table" unless
          @file_type == "TLK" && @file_version == "V3.0"

        @size = string_count
        @language = language_id
        @entries_offset = string_entries_offset

        @cache = {}
      end

Public instance methods

[] (id)

Returns a TLK entry as a hash with the following keys:

:text          string: The text
:sound         string: A sound resref, or "" if no sound is specified.
:sound_length  float: Length of the given resref (or 0.0 if no sound is given).

id is the numeric offset within the Tlk, starting at 0. The maximum is Tlk#size - 1.

[show source]
# File lib/nwn/tlk.rb, line 57
      def [](id)
        return { :text => "", :sound => "", :sound_length => 0.0, :volume_variance => 0, :pitch_variance => 0} if id == 0xffffffff

        return @cache[id] if @cache[id]

        raise ArgumentError, "No such string ID: #{id.inspect}" if id > self.highest_id || id < 0
        seek_to = HEADER_SIZE + (id) * DATA_ELEMENT_SIZE
        @io.seek(seek_to)
        data = @io.e_read(DATA_ELEMENT_SIZE, "tlk entry = #{id}")

        flags, sound_resref, v_variance, p_variance, offset,
          size, sound_length = data.unpack("I A16 I I I I f")
        flags = flags.to_i

        @io.seek(@entries_offset + offset)
        text = @io.e_read(size, "tlk entry = #{id}, offset = #{@entries_offset + offset}")

        text = flags & 0x1 > 0 ? text : ""
        sound = flags & 0x2 > 0 ? sound_resref : ""
        sound_length = flags & 0x4 > 0 ? sound_length.to_f : 0.0

        @cache[id] = {
          :text => text, :sound => sound, :sound_length => sound_length,
          :volume_variance => v_variance, :pitch_variance => p_variance
        }
      end
add (text, sound = "", sound_length = 0.0, v_variance = 0, p_variance = 0)

Add a new entry to this Tlk and return the strref given to it. To override existing entries, use tlk[][:text] = “..“

[show source]
# File lib/nwn/tlk.rb, line 86
      def add text, sound = "", sound_length = 0.0, v_variance = 0, p_variance = 0
        next_id = self.highest_id + 1
        $stderr.puts "put in cache: #{next_id}"
        @cache[next_id] = {:text => text, :sound => sound, :sound_length => 0.0, :volume_variance => v_variance, :pitch_variance => p_variance}
        next_id
      end
highest_id ()

Return the highest ID in this Tlk table.

[show source]
# File lib/nwn/tlk.rb, line 94
      def highest_id
        highest_cached = @cache.keys.sort[-1] || 0
        @size - 1 > highest_cached ? @size - 1 : highest_cached
      end
write_to (io)

Write this Tlk to io. Take care not to write it to the same IO object you are reading from.

[show source]
# File lib/nwn/tlk.rb, line 101
      def write_to io
        text_block = []
        offsets = []
        offset = 0
        for i in 0..self.highest_id do
          entry = self[i]
          offsets[i] = offset
          text_block << entry[:text]
          offset += entry[:text].size
        end
        text_block = text_block.join("")

        header = [
          @file_type, @file_version,
          @language,
          self.highest_id + 1, HEADER_SIZE + (self.highest_id + 1) * DATA_ELEMENT_SIZE
        ].pack("A4 A4 I I I")

        entries = []
        for i in 0..self.highest_id do
          entry = self[i]
          text, sound, sound_length = entry[:text], entry[:sound], entry[:sound_length]
          flags = 0
          flags |= 0x01 if text.size > 0
          flags |= 0x02 if sound.size > 0
          flags |= 0x04 if sound_length > 0.0
          entries << [
            flags, sound, entry[:volume_variance], entry[:pitch_variance], offsets[i], text.size, sound_length
          ].pack("I a16 I I I I f")
        end
        entries = entries.join("")

        io.write(header)
        io.write(entries)
        io.write(text_block)
      end