Class: NWN::Tlk::Tlk

Inherits:
Object
  • Object
show all
Defined in:
lib/nwn/tlk.rb

Overview

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

Constant Summary collapse

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io) ⇒ Tlk

Cereate

Raises:

  • (IOError)


32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 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

Instance Attribute Details

#cacheObject (readonly)

Returns the value of attribute cache.



29
30
31
# File 'lib/nwn/tlk.rb', line 29

def cache
  @cache
end

#languageObject (readonly)

The language_id of this Tlk.



27
28
29
# File 'lib/nwn/tlk.rb', line 27

def language
  @language
end

Instance Method Details

#[](id) ⇒ Object

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.

Raises:

  • (ArgumentError)


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
# 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) ⇒ Object

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



86
87
88
89
90
91
# 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_idObject

Return the highest ID in this Tlk table.



94
95
96
97
# 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) ⇒ Object

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



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
# 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