Class: Lich::Common::Inventory::Item

Inherits:
Object
  • Object
show all
Defined in:
documented/common/inventory.rb

Overview

A single item from an inventoryManager response: one exist id, its identity, physical data, container facets, and links into the tree.

Weight is intrinsic (location-independent -- a nodachi weighs the same in a pocket or in a weight-nullifying eddy). Container load is read from the wire via #in_encum when present, else summed from direct children.

Constant Summary collapse

LEADING_ARTICLE =

Leading article dropped from the GameObj bridge name (per the GameObj author's guidance, before_name stays nil so it does not collide with the DR get-command context stored there).

/\A(an?|some|the)\s+/i
NAME_MARKER =

Simu highlight markers that wrap the core noun phrase inside long (e.g. a $_gnarled rowan crook$_ wound with knotted yarn): the text between the markers is the name, the text after them is the descriptor.

/\$_(.*?)\$_/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fields) ⇒ Item

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Item.

Parameters:

  • fields (Hash) —

    pre-parsed, coerced attribute values



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'documented/common/inventory.rb', line 201

def initialize(fields)
  @id           = freeze_str(fields[:id])
  @article      = freeze_str(fields[:article])
  @adjective    = freeze_str(fields[:adjective])
  @noun         = freeze_str(fields[:noun])
  @name         = freeze_str(fields[:name])
  @long         = freeze_str(fields[:long])
  @relation     = freeze_str(fields[:relation])
  @parent_id    = freeze_str(fields[:parent_id])
  @weight       = fields[:weight]
  @capacity_lbs = fields[:capacity_lbs]
  @in_encum     = fields[:in_encum]
  @in_selector  = freeze_str(fields[:in_selector])
  # Frozen (deeply) so a consumer cannot mutate shared snapshot state via
  # e.g. +item.flags << "locked"+; the flag tokens are frozen too.
  @flags        = fields[:flags].map(&:freeze).freeze
  @has_max      = fields[:has_max]
  @children     = []
end

Instance Attribute Details

#adjective ⇒ String (readonly)

Returns the adjective segment (may be empty).

Returns:

  • (String) —

    the adjective segment (may be empty)



150
151
152
# File 'documented/common/inventory.rb', line 150

def adjective
  @adjective
end

#article ⇒ String (readonly)

Returns leading article/pre-noun words (e.g. "a scuffed").

Returns:

  • (String) —

    leading article/pre-noun words (e.g. "a scuffed")



147
148
149
# File 'documented/common/inventory.rb', line 147

def article
  @article
end

#capacity_lbs ⇒ Integer? (readonly)

Returns weight capacity in pounds, or nil when unknown (no in_max/on_max, or the NO_WEIGHT_LIMIT_SENTINEL).

Returns:



181
182
183
# File 'documented/common/inventory.rb', line 181

def capacity_lbs
  @capacity_lbs
end

#children ⇒ Array<Item> (readonly)

Returns direct children (both "in" and "on").

Returns:

  • (Array<Item>) —

    direct children (both "in" and "on")



194
195
196
# File 'documented/common/inventory.rb', line 194

def children
  @children
end

#flags ⇒ Array<String> (readonly)

Returns flag tokens, e.g. ["closed", "locked"].

Returns:

  • (Array<String>) —

    flag tokens, e.g. ["closed", "locked"]



191
192
193
# File 'documented/common/inventory.rb', line 191

def flags
  @flags
end

#id ⇒ String (readonly)

Returns the exist id (game object id) as a string.

Returns:

  • (String) —

    the exist id (game object id) as a string



144
145
146
# File 'documented/common/inventory.rb', line 144

def id
  @id
end

#in_encum ⇒ Integer? (readonly)

Returns raw container load from the wire (0 for a weight-nullifying container), or nil when the wire omits it.

Returns:

  • (Integer, nil) —

    raw container load from the wire (0 for a weight-nullifying container), or nil when the wire omits it



185
186
187
# File 'documented/common/inventory.rb', line 185

def in_encum
  @in_encum
end

#in_selector ⇒ String? (readonly)

Returns the container's in_selector verb hint, or nil.

Returns:

  • (String, nil) —

    the container's in_selector verb hint, or nil



188
189
190
# File 'documented/common/inventory.rb', line 188

def in_selector
  @in_selector
end

#name ⇒ String (readonly)

Returns assembled short display name (e.g. "a scuffed pack").

Returns:

  • (String) —

    assembled short display name (e.g. "a scuffed pack")



156
157
158
# File 'documented/common/inventory.rb', line 156

def name
  @name
end

#noun ⇒ String (readonly)

Returns the noun (e.g. "pack"); used for classification.

Returns:

  • (String) —

    the noun (e.g. "pack"); used for classification



153
154
155
# File 'documented/common/inventory.rb', line 153

def noun
  @noun
end

#parent_id ⇒ String? (readonly)

Returns parent exist id, "player", "room", or nil.

Returns:

  • (String, nil) —

    parent exist id, "player", "room", or nil



174
175
176
# File 'documented/common/inventory.rb', line 174

def parent_id
  @parent_id
end

#parent_item ⇒ Item? (readonly)

Returns the parent Lich::Common::Inventory::Item, or nil for a top-level item.

Returns:



197
198
199
# File 'documented/common/inventory.rb', line 197

def parent_item
  @parent_item
end

#relation ⇒ String? (readonly)

Returns the loc relation: "worn", "in", "on", "room".

Returns:

  • (String, nil) —

    the loc relation: "worn", "in", "on", "room"



171
172
173
# File 'documented/common/inventory.rb', line 171

def relation
  @relation
end

#weight ⇒ Integer (readonly)

Returns intrinsic weight in pounds (0 when absent).

Returns:

  • (Integer) —

    intrinsic weight in pounds (0 when absent)



177
178
179
# File 'documented/common/inventory.rb', line 177

def weight
  @weight
end

Instance Method Details

#add_child(child) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Attaches a child during tree construction.

Parameters:



367
368
369
# File 'documented/common/inventory.rb', line 367

def add_child(child)
  @children << child
end

#at_feet? ⇒ Boolean

Returns whether the item is on the ground at the player's feet.

Returns:

  • (Boolean) —

    whether the item is on the ground at the player's feet



273
274
275
# File 'documented/common/inventory.rb', line 273

def at_feet?
  @relation == 'atfeet'
end

#closed? ⇒ Boolean

Returns whether the container is closed (still enumerated).

Returns:

  • (Boolean) —

    whether the container is closed (still enumerated)



233
234
235
# File 'documented/common/inventory.rb', line 233

def closed?
  @flags.include?('closed')
end

#container? ⇒ Boolean

Whether this item can hold other items: it either has children or advertises a weight cap. (A max-less holder -- e.g. a ring-holder with rings ON it -- is still a container.)

Examples:

Inventory['40236126'].container? #=> true

Returns:

  • (Boolean)


228
229
230
# File 'documented/common/inventory.rb', line 228

def container?
  !@children.empty? || @has_max
end

#contents(relation = nil) ⇒ Array<Item>

Direct children, optionally filtered by relation. An opaque (locked) container returns [] (contents unknown), never a false "empty".

Examples:

List only what is worn ON a ring-holder

Inventory['40235982'].contents(:on)

Parameters:

  • relation (Symbol, String, nil) (defaults to: nil) —

    :in, :on, or nil for all

Returns:



290
291
292
293
294
295
# File 'documented/common/inventory.rb', line 290

def contents(relation = nil)
  return [] if opaque?
  return @children.dup if relation.nil?

  @children.select { |child| child.relation == relation.to_s }
end

#effective_weight(visited, depth) ⇒ Integer (protected)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Recursive weight traversal backing #total_weight. Kept internal so the public query takes no arguments; protected so a parent Lich::Common::Inventory::Item can pass the shared +visited+/+depth+ accumulators down to its children (a cycle guard + depth cap) without exposing them as public API.

Parameters:

  • visited (Set<String>) —

    exist ids already counted on this walk

  • depth (Integer) —

    current recursion depth

Returns:

  • (Integer)


435
436
437
438
439
440
441
442
443
444
445
# File 'documented/common/inventory.rb', line 435

def effective_weight(visited, depth)
  return 0 if depth > MAX_TREE_DEPTH || visited.include?(@id)

  visited.add(@id)
  own = @weight
  return own unless container?
  return own if opaque?
  return own + @in_encum unless @in_encum.nil?

  own + @children.sum { |child| child.effective_weight(visited, depth + 1) }
end

#finalize! ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Freezes the child list once the tree is fully wired.



384
385
386
# File 'documented/common/inventory.rb', line 384

def finalize!
  @children.freeze
end

#held? ⇒ Boolean

Returns whether the item is held in either hand.

Returns:

  • (Boolean) —

    whether the item is held in either hand



268
269
270
# File 'documented/common/inventory.rb', line 268

def held?
  in_right_hand? || in_left_hand?
end

#in_left_hand? ⇒ Boolean

Returns whether the item is in the player's left hand.

Returns:

  • (Boolean) —

    whether the item is in the player's left hand



263
264
265
# File 'documented/common/inventory.rb', line 263

def in_left_hand?
  @relation == 'lefthand'
end

#in_right_hand? ⇒ Boolean

Returns whether the item is in the player's right hand.

Returns:

  • (Boolean) —

    whether the item is in the player's right hand



258
259
260
# File 'documented/common/inventory.rb', line 258

def in_right_hand?
  @relation == 'righthand'
end

#in_room? ⇒ Boolean

Returns whether the item is on the ground in the room (shared; the feed lists the whole room's ground loot, not only the player's).

Returns:

  • (Boolean) —

    whether the item is on the ground in the room (shared; the feed lists the whole room's ground loot, not only the player's)



279
280
281
# File 'documented/common/inventory.rb', line 279

def in_room?
  @relation == 'room'
end

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Records the parent item during tree construction.

Parameters:



376
377
378
# File 'documented/common/inventory.rb', line 376

def link_parent(parent)
  @parent_item = parent
end

#locked? ⇒ Boolean

Returns whether the container is locked.

Returns:

  • (Boolean) —

    whether the container is locked



238
239
240
# File 'documented/common/inventory.rb', line 238

def locked?
  @flags.include?('locked')
end

#long ⇒ String?

The long description, entity-decoded and with Simu's $_ highlight markers removed (they wrap the core name on the wire; see NAME_MARKER).

Examples:

Inventory['165666521'].long #=> "a gnarled rowan crook wound with knotted yarn"

Returns:



164
165
166
167
168
# File 'documented/common/inventory.rb', line 164

def long
  return @long if @long.nil?

  @long.gsub('$_', '')
end

#opaque? ⇒ Boolean

Whether the interior is unknown. A LOCKED container emits zero children by game design (treasure boxes populate only on open; gem pouches aggregate), so it is opaque -- never conclude it is empty.

Returns:

  • (Boolean)


247
248
249
# File 'documented/common/inventory.rb', line 247

def opaque?
  locked?
end

#register_gameobj(place_worn:, open_container_ids:) ⇒ GameObj

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Mirrors this item into GameObj for a committed snapshot. Only the two registries the extended feed authoritatively owns are written: worn -> @@inv and +in+/+on+ -> @@contents[parent] (both via the staging-aware GameObj.new_inv, so the caller's +begin_inv+/+begin_container+ cycle publishes them atomically). Hands and room loot are left to the classic ++/++/room-objs streams, which are live and authoritative for those slots. Every other item (hands, room, atfeet, unknown relations, or a target the caller skipped this cycle) is pooled identity-only via GameObj.index_or_create so #type/#sellable still classify, without a registry placement.

Parameters:

  • place_worn (Boolean) —

    whether to route worn items into @@inv this cycle (false when a classic inv refresh is already open)

  • open_container_ids (Set<String>) —

    container ids whose staging the caller opened this cycle; an in/on item lands in @@contents only if its parent is among them

Returns:



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'documented/common/inventory.rb', line 406

def register_gameobj(place_worn:, open_container_ids:)
  before, name, after = descriptive_parts
  @gameobj =
    case @relation
    when 'worn'
      place_worn ? GameObj.new_inv(@id, @noun, name, nil, before, after) : GameObj.index_or_create(@id, @noun, name, before, after)
    when 'in', 'on'
      if open_container_ids.include?(@parent_id)
        GameObj.new_inv(@id, @noun, name, @parent_id, before, after)
      else
        GameObj.index_or_create(@id, @noun, name, before, after)
      end
    else
      GameObj.index_or_create(@id, @noun, name, before, after)
    end
  backfill_names(@gameobj, before, after)
end

#sellable ⇒ String?

Sellable classification, derived like #type from the item's own noun/name via #bridge_gameobj.

Examples:

Inventory.refresh.find('diamond')&.sellable #=> "gem"

Returns:

  • (String, nil) —

    comma-joined sellable tags, or nil if none match



358
359
360
# File 'documented/common/inventory.rb', line 358

def sellable
  bridge_gameobj.sellable
end

#space_left ⇒ Integer?

Remaining weight capacity in pounds, or nil when either capacity or used weight is unknown (never raises on a nil operand). Not clamped -- may be negative if a container is overfull.

Examples:

Inventory['40236126'].space_left #=> 86

Returns:

  • (Integer, nil)


322
323
324
325
326
# File 'documented/common/inventory.rb', line 322

def space_left
  return nil if @capacity_lbs.nil? || used_lbs.nil?

  @capacity_lbs - used_lbs
end

#total_weight ⇒ Integer

Total effective weight of this item and everything it carries, in pounds. A container subtree contributes the container's own #weight plus (#in_encum when present, else the recursive contribution of its children) -- so a weight-nullifying eddy adds only its own weight, not the heavy contents inside it. Cycle-safe (visited set + depth cap; see the internal #effective_weight traversal).

Examples:

The eddy weighs 10 lb regardless of its contents

Inventory['40235966'].total_weight #=> 10

Returns:

  • (Integer)


338
339
340
# File 'documented/common/inventory.rb', line 338

def total_weight
  effective_weight(Set.new, 0)
end

#type ⇒ String?

Type classification (e.g. "weapon,edged"), derived from this item's own noun/name via its backing GameObj (see #bridge_gameobj).

Examples:

Inventory.refresh.find('sword')&.type #=> "weapon"

Returns:

  • (String, nil) —

    comma-joined type tags, or nil if none match



348
349
350
# File 'documented/common/inventory.rb', line 348

def type
  bridge_gameobj.type
end

#used_lbs ⇒ Integer?

Weight currently used by this container, in pounds: #in_encum when the wire provides it (authoritative for magical containers), else the sum of each direct child's effective #total_weight -- so items nested inside child containers are counted too (a plain child contributes just its own #weight; a child eddy contributes only its own). nil for a non-container or an opaque (locked) container, where it is not meaningful.

Examples:

Inventory['40236126'].used_lbs #=> 84

Returns:

  • (Integer, nil)


307
308
309
310
311
312
313
# File 'documented/common/inventory.rb', line 307

def used_lbs
  return nil unless container?
  return nil if opaque?
  return @in_encum unless @in_encum.nil?

  @children.sum(&:total_weight)
end

#worn? ⇒ Boolean

Returns whether the item is worn on the player (relation worn -- NOT merely parent player, which also covers hands/feet).

Returns:

  • (Boolean) —

    whether the item is worn on the player (relation worn -- NOT merely parent player, which also covers hands/feet)



253
254
255
# File 'documented/common/inventory.rb', line 253

def worn?
  @relation == 'worn'
end