Class: Lich::Common::GameObj

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

Overview

Represents a game object in the world.

Direct Known Subclasses

RoomObj

Constant Summary collapse

@@loot =

Class-level registries

[]
@@npcs =
[]
@@npc_status =
{}
@@pcs =
[]
@@pc_status =
{}
@@inv =
[]
@@reserve =
nil
@@contents =
{}
@@right_hand =
nil
@@left_hand =
nil
@@room_desc =
[]
@@fam_loot =
[]
@@fam_npcs =
[]
@@fam_pcs =
[]
@@fam_room_desc =
[]
@@type_data =
{}
@@type_cache =
{}
@@sellable_data =
{}
@@index =

Shared identity index — single persistent O(1) lookup pool with TTL.

Maps composite key String "id|noun|name" to a two-element array [GameObj, last_seen_at] where last_seen_at is a Float timestamp (from Process.clock_gettime(Process::CLOCK_MONOTONIC)) recording when the entry was last accessed by find_or_create.

All registries share this one index because a GameObj with the same id, noun, and name is the same logical game entity regardless of which registry it belongs to.

The index is intentionally not flushed when a registry is cleared. Room transitions call multiple clear_* methods in quick succession; flushing on every clear would cause every re-encountered object to be needlessly reallocated. Instead, stale index entries self-heal: when find_or_create finds an entry for an object that was cleared from its registry, it simply re-adds that same instance to the target registry and refreshes its last_seen_at timestamp.

Garbage collection is handled by prune_index!, which removes entries whose last_seen_at is older than a given TTL (default 15 minutes). Call it at natural session breakpoints (e.g. after a room transition or from a script's idle loop). It is safe to call frequently — entries that were just accessed will never be pruned regardless of how often it runs.

Use index_stats to inspect the current state of the index at any time.

For very long automated sessions an alternative LruIndex drop-in is also available — see Lich::Common::LruIndex below.

{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, noun, name, before = nil, after = nil) ⇒ GameObj

Initializes a new game object.

Parameters:

  • id (String)

    unique object ID

  • noun (String)

    object noun (e.g., "sword", "backpack")

  • name (String)

    object name

  • before (String, nil) (defaults to: nil)

    optional prefix for the name

  • after (String, nil) (defaults to: nil)

    optional suffix for the name



86
87
88
89
90
91
92
# File 'documented/common/gameobj.rb', line 86

def initialize(id, noun, name, before = nil, after = nil)
  @id          = id.is_a?(Integer) ? id.to_s : id
  @noun        = normalize_noun(noun, name)
  @name        = name
  @before_name = before
  @after_name  = after
end

Instance Attribute Details

#after_nameObject

Returns the value of attribute after_name.



77
78
79
# File 'documented/common/gameobj.rb', line 77

def after_name
  @after_name
end

#before_nameObject

Returns the value of attribute before_name.



75
76
77
# File 'documented/common/gameobj.rb', line 75

def before_name
  @before_name
end

#idObject (readonly)

Returns the value of attribute id.



69
70
71
# File 'documented/common/gameobj.rb', line 69

def id
  @id
end

#nameObject

Returns the value of attribute name.



73
74
75
# File 'documented/common/gameobj.rb', line 73

def name
  @name
end

#nounObject

Returns the value of attribute noun.



71
72
73
# File 'documented/common/gameobj.rb', line 71

def noun
  @noun
end

Class Method Details

.[](val) ⇒ Object



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
# File 'documented/common/gameobj.rb', line 313

def self.[](val)
  unless val.is_a?(String) || val.is_a?(Regexp)
    respond "--- Lich: error: GameObj[] passed with #{val.class} #{val} via caller: #{caller[0]}"
    respond "--- Lich: error: GameObj[] supports String or Regexp only"
    Lich.log "--- Lich: error: GameObj[] passed with #{val.class} #{val} via caller: #{caller[0]}\n\t"
    Lich.log "--- Lich: error: GameObj[] supports String or Regexp only\n\t"

    if val.is_a?(Integer)
      respond "--- Lich: error: GameObj[] converted Integer #{val} to String to continue"
      val = val.to_s
    else
      return nil
    end
  end

  if val.is_a?(Regexp)
    return search_registries { |o| o.name =~ val }
  end

  if val =~ /^\-?[0-9]+$/
    # Numeric ID lookup (room_desc excluded from primary, appended last for completeness)
    search_registries { |o| o.id == val }
  elsif val.split(' ').length == 1
    # Single-word noun lookup
    search_registries { |o| o.noun == val }
  else
    # Name lookup — exact first, then suffix, then fuzzy suffix
    escaped     = Regexp.escape(val.strip)
    fuzzy       = Regexp.escape(val).sub(' ', ' .*')
    search_registries { |o| o.name == val } ||
      search_registries { |o| o.name =~ /\b#{escaped}$/i } ||
      search_registries { |o| o.name =~ /\b#{fuzzy}$/i }
  end
end

.clear_all_containersObject



302
# File 'documented/common/gameobj.rb', line 302

def self.clear_all_containers = @@contents.clear

.clear_container(container_id) ⇒ Object



304
305
306
# File 'documented/common/gameobj.rb', line 304

def self.clear_container(container_id)
  @@contents[container_id] = []
end

.clear_fam_lootObject



296
# File 'documented/common/gameobj.rb', line 296

def self.clear_fam_loot      = @@fam_loot.clear

.clear_fam_npcsObject



298
# File 'documented/common/gameobj.rb', line 298

def self.clear_fam_npcs      = @@fam_npcs.clear

.clear_fam_pcsObject



300
# File 'documented/common/gameobj.rb', line 300

def self.clear_fam_pcs       = @@fam_pcs.clear

.clear_fam_room_descObject



294
# File 'documented/common/gameobj.rb', line 294

def self.clear_fam_room_desc = @@fam_room_desc.clear

.clear_invObject



288
# File 'documented/common/gameobj.rb', line 288

def self.clear_inv           = @@inv.clear

.clear_lootObject



282
# File 'documented/common/gameobj.rb', line 282

def self.clear_loot          = @@loot.clear

.clear_npcsObject



284
# File 'documented/common/gameobj.rb', line 284

def self.clear_npcs          = (@@npcs.clear; @@npc_status.clear)

.clear_pcsObject



286
# File 'documented/common/gameobj.rb', line 286

def self.clear_pcs           = (@@pcs.clear; @@pc_status.clear)

.clear_reserveObject



290
# File 'documented/common/gameobj.rb', line 290

def self.clear_reserve       = (@@reserve = [])

.clear_room_descObject



292
# File 'documented/common/gameobj.rb', line 292

def self.clear_room_desc     = @@room_desc.clear

.containersObject



279
# File 'documented/common/gameobj.rb', line 279

def self.containers  = @@contents.dup

.deadObject



369
370
371
372
# File 'documented/common/gameobj.rb', line 369

def self.dead
  dead_list = @@npcs.select { |obj| obj.status == 'dead' }
  dead_list.empty? ? nil : dead_list
end

.delete_container(container_id) ⇒ Object



308
309
310
# File 'documented/common/gameobj.rb', line 308

def self.delete_container(container_id)
  @@contents.delete(container_id)
end

.fam_lootObject



273
# File 'documented/common/gameobj.rb', line 273

def self.fam_loot    = registry_or_nil(@@fam_loot)

.fam_npcsObject



275
# File 'documented/common/gameobj.rb', line 275

def self.fam_npcs    = registry_or_nil(@@fam_npcs)

.fam_pcsObject



277
# File 'documented/common/gameobj.rb', line 277

def self.fam_pcs     = registry_or_nil(@@fam_pcs)

.fam_room_descObject



271
# File 'documented/common/gameobj.rb', line 271

def self.fam_room_desc = registry_or_nil(@@fam_room_desc)

.hidden_targetsObject



361
362
363
# File 'documented/common/gameobj.rb', line 361

def self.hidden_targets
  XMLData.current_target_ids.reject { |id| @@npcs.any? { |n| n.id == id } }
end

.index_or_create(id, noun, name, before = nil, after = nil) ⇒ GameObj

Looks up an existing GameObj in the shared identity index by composite key (+id+, noun, name), or creates and indexes a new one.

Unlike find_or_create, this method does not push the object into any Looks up an existing game object in the shared identity index by composite key (id, noun, name), or creates and indexes a new one.

Parameters:

  • id (String)

    unique object ID

  • noun (String)

    object noun

  • name (String)

    object name

  • before (String, nil) (defaults to: nil)

    optional prefix for the name

  • after (String, nil) (defaults to: nil)

    optional suffix for the name

Returns:

  • (GameObj)

    the found or newly created game object.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'documented/common/gameobj.rb', line 236

def self.index_or_create(id, noun, name, before = nil, after = nil)
  str_id = id.is_a?(Integer) ? id.to_s : id
  key    = "#{str_id}|#{noun}|#{name}"
  now    = Process.clock_gettime(Process::CLOCK_MONOTONIC)

  if (entry = @@index[key])
    existing, _ts        = entry
    @@index[key]         = [existing, now]
    existing.before_name = before if existing.before_name.nil? && !before.nil?
    existing.after_name  = after  if existing.after_name.nil?  && !after.nil?
    return existing
  end

  obj          = GameObj.new(id, noun, name, before, after)
  @@index[key] = [obj, now]
  obj
end

.index_stats(verbose: false) ⇒ Hash

Provides statistics about the current state of the index.

Parameters:

  • verbose (Boolean) (defaults to: false)

    whether to print detailed output

Returns:

  • (Hash)

    a summary of index statistics.



476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'documented/common/gameobj.rb', line 476

def self.index_stats(verbose: false)
  require 'objspace'
  return empty_index_stats if @@index.empty?

  now        = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  live_ids   = live_registry_ids
  buckets    = { 'under5m' => 0, '5-15m' => 0,
                 '15-30m' => 0, '30-60m' => 0, 'over60m' => 0 }
  stale      = 0
  oldest_age = 0.0

  @@index.each_value do |obj, last_seen|
    age        = now - last_seen
    oldest_age = age if age > oldest_age
    stale     += 1 unless live_ids.include?(obj.id)

    buckets[case age
            when 0...300    then 'under5m'
            when 300...900  then '5-15m'
            when 900...1800 then '15-30m'
            when 1800...3600 then '30-60m'
            else 'over60m'
            end] += 1
  end

  obj_mem  = gameobj_memory_bytes
  heap_mem = ruby_heap_bytes

  result = {
    total_entries: @@index.size,
    live_in_registries: @@index.size - stale,
    stale_entries: stale,
    oldest_entry_seconds: oldest_age.round(1),
    age_buckets: buckets,
    gameobj_bytes: obj_mem,
    heap_bytes: heap_mem
  }

  if verbose
    oldest_fmt = if oldest_age < 60
                   "#{oldest_age.round(1)}s"
                 elsif oldest_age < 3600
                   "#{(oldest_age / 60).round(1)}m"
                 else
                   "#{(oldest_age / 3600).round(2)}h"
                 end

    w = 28
    puts "=" * 52
    puts "  GameObj.index_stats"
    puts "=" * 52
    puts format("  %-#{w}s %d", "Total index entries:",  @@index.size)
    puts format("  %-#{w}s %d", "Live in registries:",   result[:live_in_registries])
    puts format("  %-#{w}s %d", "Stale (index-only):",   stale)
    puts format("  %-#{w}s %s", "Oldest entry:",         oldest_fmt)
    puts "-" * 52
    puts "  Age distribution:"
    buckets.each do |label, count|
      bar = "#" * [count, 30].min
      puts format("  %-10s %4d  %s", label, count, bar)
    end
    puts "-" * 52
    puts format("  %-#{w}s %s", "GameObj object memory:", format_bytes(obj_mem))
    puts format("  %-#{w}s %s", "Ruby heap size:", format_bytes(heap_mem))
    puts "=" * 52
  end

  result
end

.invObject



265
# File 'documented/common/gameobj.rb', line 265

def self.inv         = registry_or_nil(@@inv)

.left_handObject



257
# File 'documented/common/gameobj.rb', line 257

def self.left_hand   = @@left_hand&.dup

.load_data(filename = nil) ⇒ Object



558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'documented/common/gameobj.rb', line 558

def self.load_data(filename = nil)
  primary = filename || File.join(DATA_DIR, 'gameobj-data.xml')

  unless File.exist?(primary)
    @@type_data = @@sellable_data = nil
    echo "error: GameObj.load_data: file does not exist: #{primary}"
    return false
  end

  begin
    @@type_data     = {}
    @@sellable_data = {}
    @@type_cache    = {}
    parse_data_file(primary)
  rescue => e
    @@type_data = @@sellable_data = nil
    echo "error: GameObj.load_data: #{e}"
    respond e.backtrace[0..1]
    return false
  end

  custom = File.join(DATA_DIR, 'gameobj-custom', 'gameobj-data.xml')
  if File.exist?(custom)
    begin
      parse_data_file(custom, merge: true)
    rescue => e
      echo "error: Custom GameObj.load_data: #{e}"
      respond e.backtrace[0..1]
      return false
    end
  end

  true
end

.lootObject



261
# File 'documented/common/gameobj.rb', line 261

def self.loot        = registry_or_nil(@@loot)

.merge_data(existing, new_value) ⇒ Object



554
555
556
# File 'documented/common/gameobj.rb', line 554

def self.merge_data(existing, new_value)
  existing.is_a?(Regexp) ? Regexp.union(existing, new_value) : new_value
end

.new_fam_loot(id, noun, name) ⇒ Object



205
206
207
# File 'documented/common/gameobj.rb', line 205

def self.new_fam_loot(id, noun, name)
  find_or_create(@@fam_loot, id, noun, name)
end

.new_fam_npc(id, noun, name) ⇒ Object



209
210
211
# File 'documented/common/gameobj.rb', line 209

def self.new_fam_npc(id, noun, name)
  find_or_create(@@fam_npcs, id, noun, name)
end

.new_fam_pc(id, noun, name) ⇒ Object



213
214
215
# File 'documented/common/gameobj.rb', line 213

def self.new_fam_pc(id, noun, name)
  find_or_create(@@fam_pcs, id, noun, name)
end

.new_fam_room_desc(id, noun, name) ⇒ Object



201
202
203
# File 'documented/common/gameobj.rb', line 201

def self.new_fam_room_desc(id, noun, name)
  find_or_create(@@fam_room_desc, id, noun, name)
end

.new_inv(id, noun, name, container = nil, before = nil, after = nil) ⇒ Object



183
184
185
186
187
188
189
190
# File 'documented/common/gameobj.rb', line 183

def self.new_inv(id, noun, name, container = nil, before = nil, after = nil)
  if container
    @@contents[container] ||= []
    find_or_create(@@contents[container], id, noun, name, before, after)
  else
    find_or_create(@@inv, id, noun, name, before, after)
  end
end

.new_left_hand(id, noun, name) ⇒ Object



221
222
223
# File 'documented/common/gameobj.rb', line 221

def self.new_left_hand(id, noun, name)
  @@left_hand = index_or_create(id, noun, name)
end

.new_loot(id, noun, name) ⇒ Object



167
168
169
# File 'documented/common/gameobj.rb', line 167

def self.new_loot(id, noun, name)
  find_or_create(@@loot, id, noun, name)
end

.new_npc(id, noun, name, status = nil) ⇒ GameObj

Creates a new NPC game object and registers it.

Parameters:

  • id (String)

    unique NPC ID

  • noun (String)

    NPC noun

  • name (String)

    NPC name

  • status (String, nil) (defaults to: nil)

    optional status of the NPC

Returns:

  • (GameObj)

    the created NPC object.



161
162
163
164
165
# File 'documented/common/gameobj.rb', line 161

def self.new_npc(id, noun, name, status = nil)
  obj = find_or_create(@@npcs, id, noun, name)
  @@npc_status[obj.id] = status
  obj
end

.new_pc(id, noun, name, status = nil) ⇒ GameObj

Creates a new player character game object and registers it.

Parameters:

  • id (String)

    unique PC ID

  • noun (String)

    PC noun

  • name (String)

    PC name

  • status (String, nil) (defaults to: nil)

    optional status of the PC

Returns:

  • (GameObj)

    the created PC object.



177
178
179
180
181
# File 'documented/common/gameobj.rb', line 177

def self.new_pc(id, noun, name, status = nil)
  obj = find_or_create(@@pcs, id, noun, name)
  @@pc_status[obj.id] = status
  obj
end

.new_reserve(id, noun, name) ⇒ Object



192
193
194
195
# File 'documented/common/gameobj.rb', line 192

def self.new_reserve(id, noun, name)
  @@reserve ||= []
  find_or_create(@@reserve, id, noun, name)
end

.new_right_hand(id, noun, name) ⇒ Object



217
218
219
# File 'documented/common/gameobj.rb', line 217

def self.new_right_hand(id, noun, name)
  @@right_hand = index_or_create(id, noun, name)
end

.new_room_desc(id, noun, name) ⇒ Object



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

def self.new_room_desc(id, noun, name)
  find_or_create(@@room_desc, id, noun, name)
end

.npcsObject



259
# File 'documented/common/gameobj.rb', line 259

def self.npcs        = registry_or_nil(@@npcs)

.pcsObject



263
# File 'documented/common/gameobj.rb', line 263

def self.pcs         = registry_or_nil(@@pcs)

.prune_index!(ttl: 900, verbose: false) ⇒ Hash

Removes entries from the shared identity index whose last_seen_at timestamp is older than ttl seconds ago and whose object is not currently present in any active registry, then GC-hints Ruby.

The live-registry check is the critical guard: an object that is still held in @@npcs, @@loot, @@inv, or any other registry must never be pruned regardless of how long ago it was last re-registered. Pruning a live entry would cause the next find_or_create call for that object to allocate a brand-new instance, silently breaking the identity guarantee.

An entry is only eligible for pruning when both conditions are true:

1. +last_seen_at+ is older than +ttl+ seconds ago
2. The object's ID is not present in any active registry

Safe to call at any time and as frequently as desired. Entries that are live in registries are always skipped. Entries accessed within the TTL window are always skipped. Removes entries from the shared identity index whose last_seen_at timestamp is older than ttl seconds ago and whose object is not currently present in any active registry.

Parameters:

  • ttl (Integer) (defaults to: 900)

    the time-to-live in seconds for entries in the index

  • verbose (Boolean) (defaults to: false)

    whether to print detailed output

Returns:

  • (Hash)

    a summary of the pruning operation.



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'documented/common/gameobj.rb', line 399

def self.prune_index!(ttl: 900, verbose: false)
  require 'objspace'
  t_start   = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  cutoff    = t_start - ttl

  # Build the live-ID set once before the sweep so we do not repeatedly
  # iterate all registries inside the delete_if block.
  live_ids = live_registry_ids

  obj_before  = gameobj_memory_bytes
  heap_before = ruby_heap_bytes

  pruned       = 0
  skipped_live = 0

  @@index.delete_if do |_key, (obj, last_seen)|
    if live_ids.include?(obj.id)
      # Object is currently held in a registry — never prune regardless of age.
      skipped_live += 1
      false
    elsif last_seen < cutoff
      pruned += 1
      true
    else
      false
    end
  end

  GC.start(full_mark: false, immediate_sweep: false) if pruned.positive?

  obj_after  = gameobj_memory_bytes
  heap_after = ruby_heap_bytes
  elapsed    = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t_start) * 1000

  result = {
    pruned: pruned,
    skipped_live: skipped_live,
    remaining: @@index.size,
    gameobj_bytes_before: obj_before,
    gameobj_bytes_after: obj_after,
    gameobj_bytes_freed: obj_before - obj_after,
    heap_bytes_before: heap_before,
    heap_bytes_after: heap_after,
    heap_bytes_freed: heap_before - heap_after,
    elapsed_ms: elapsed.round(3)
  }

  if verbose
    w = 28
    puts "=" * 52
    puts "  GameObj.prune_index! - TTL: #{ttl}s"
    puts "=" * 52
    puts format("  %-#{w}s %s -> %s  (%s)",
                "GameObj object memory:",
                format_bytes(obj_before),
                format_bytes(obj_after),
                format_delta(result[:gameobj_bytes_freed]))
    puts format("  %-#{w}s %s -> %s  (%s)",
                "Ruby heap size:",
                format_bytes(heap_before),
                format_bytes(heap_after),
                format_delta(result[:heap_bytes_freed]))
    puts format("  %-#{w}s %d removed, %d skipped (live), %d remaining",
                "Index entries:",
                pruned,
                skipped_live,
                @@index.size)
    puts format("  %-#{w}s %.3f ms", "Elapsed:", elapsed)
    puts "=" * 52
  end

  result
end

.reload(filename = nil) ⇒ Boolean

Reloads the game object data from the specified file.

Parameters:

  • filename (String, nil) (defaults to: nil)

    optional path to the data file

Returns:

  • (Boolean)

    true if the reload was successful, false otherwise.



550
551
552
# File 'documented/common/gameobj.rb', line 550

def self.reload(filename = nil)
  load_data(filename)
end

.reserveObject



267
# File 'documented/common/gameobj.rb', line 267

def self.reserve     = @@reserve&.dup

.right_handObject



255
# File 'documented/common/gameobj.rb', line 255

def self.right_hand  = @@right_hand&.dup

.room_descObject



269
# File 'documented/common/gameobj.rb', line 269

def self.room_desc   = registry_or_nil(@@room_desc)

.sellable_dataObject



597
# File 'documented/common/gameobj.rb', line 597

def self.sellable_data = @@sellable_data

.targetObject



365
366
367
# File 'documented/common/gameobj.rb', line 365

def self.target
  (@@npcs + @@pcs).find { |n| n.id == XMLData.current_target_id }
end

.targetsObject



349
350
351
352
353
354
355
356
357
358
359
# File 'documented/common/gameobj.rb', line 349

def self.targets
  XMLData.current_target_ids.filter_map do |id|
    npc = @@npcs.find { |n| n.id == id }
    next unless npc
    next if npc.status.to_s =~ /dead|gone/i
    next if npc.name  =~ /^animated\b/i && npc.name !~ /^animated slush/i
    next if npc.noun  =~ /^(?:arm|appendage|claw|limb|pincer|tentacle)s?$|^(?:palpus|palpi)$/i &&
            npc.name !~ /(?:amaranthine|ghostly|grizzled|ancient) kraken tentacle/i
    npc
  end
end

.type_cacheObject



595
# File 'documented/common/gameobj.rb', line 595

def self.type_cache    = @@type_cache

.type_dataObject



593
# File 'documented/common/gameobj.rb', line 593

def self.type_data     = @@type_data

Instance Method Details

#contentsObject



106
107
108
# File 'documented/common/gameobj.rb', line 106

def contents
  @@contents[@id]&.dup
end

#empty?Boolean

Returns:

  • (Boolean)


102
103
104
# File 'documented/common/gameobj.rb', line 102

def empty?
  false
end

#full_nameObject



110
111
112
113
# File 'documented/common/gameobj.rb', line 110

def full_name
  parts = [@before_name, @name, @after_name]
  parts.compact.reject(&:empty?).join(' ')
end

#GameObjObject



98
99
100
# File 'documented/common/gameobj.rb', line 98

def GameObj
  @noun
end

#sellableString?

Retrieves the sellable types of the game object.

Returns:

  • (String, nil)

    a comma-separated list of sellable types or nil if none found.



132
133
134
135
136
# File 'documented/common/gameobj.rb', line 132

def sellable
  GameObj.load_data if @@sellable_data.empty?
  matches = matching_data_keys(@@sellable_data)
  matches.empty? ? nil : matches.join(',')
end

#statusObject



139
140
141
142
143
144
# File 'documented/common/gameobj.rb', line 139

def status
  return @@npc_status[@id] if @@npc_status.key?(@id)
  return @@pc_status[@id]  if @@pc_status.key?(@id)

  present_in_any_registry? ? nil : 'gone'
end

#status=(val) ⇒ Object



146
147
148
149
150
151
152
# File 'documented/common/gameobj.rb', line 146

def status=(val)
  if @@npcs.any? { |npc| npc.id == @id }
    @@npc_status[@id] = val
  elsif @@pcs.any? { |pc| pc.id == @id }
    @@pc_status[@id] = val
  end
end

#to_sObject



94
95
96
# File 'documented/common/gameobj.rb', line 94

def to_s
  @noun
end

#typeString?

Retrieves the type of the game object based on its name.

Returns:

  • (String, nil)

    a comma-separated list of types or nil if none found.



118
119
120
121
122
123
124
# File 'documented/common/gameobj.rb', line 118

def type
  GameObj.load_data if @@type_data.empty?
  return @@type_cache[@name] if @@type_cache.key?(@name)

  matches = matching_data_keys(@@type_data)
  @@type_cache[@name] = matches.empty? ? nil : matches.join(',')
end

#type?(type_to_check) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
# File 'documented/common/gameobj.rb', line 126

def type?(type_to_check)
  type.to_s.split(',').include?(type_to_check)
end