gamefic-standard 3.2.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Rakefile +11 -5
  4. data/gamefic-standard.gemspec +15 -13
  5. data/lib/gamefic/standard/actions/attack.rb +32 -0
  6. data/lib/gamefic/standard/actions/close.rb +24 -0
  7. data/lib/gamefic/standard/actions/drop.rb +39 -0
  8. data/lib/gamefic/standard/actions/enter.rb +34 -0
  9. data/lib/gamefic/standard/actions/give.rb +38 -0
  10. data/lib/gamefic/standard/actions/go.rb +63 -0
  11. data/lib/gamefic/standard/actions/insert.rb +53 -0
  12. data/lib/gamefic/standard/actions/inventory.rb +20 -0
  13. data/lib/gamefic/standard/actions/leave.rb +57 -0
  14. data/lib/gamefic/standard/actions/lock.rb +31 -0
  15. data/lib/gamefic/standard/actions/look.rb +149 -0
  16. data/lib/gamefic/standard/actions/mount.rb +29 -0
  17. data/lib/gamefic/standard/actions/move.rb +28 -0
  18. data/lib/gamefic/standard/actions/nil.rb +37 -0
  19. data/lib/gamefic/standard/actions/open.rb +39 -0
  20. data/lib/gamefic/standard/actions/place.rb +39 -0
  21. data/lib/gamefic/standard/actions/pronouns.rb +34 -0
  22. data/lib/gamefic/standard/actions/quit.rb +24 -0
  23. data/lib/gamefic/standard/actions/repeat.rb +28 -0
  24. data/lib/gamefic/standard/actions/save-restore-undo.rb +26 -0
  25. data/lib/gamefic/standard/actions/search.rb +36 -0
  26. data/lib/gamefic/standard/actions/take.rb +54 -0
  27. data/lib/gamefic/standard/actions/talk.rb +51 -0
  28. data/lib/gamefic/standard/actions/unlock.rb +35 -0
  29. data/lib/gamefic/standard/actions/wait.rb +17 -0
  30. data/lib/gamefic/standard/actions.rb +57 -0
  31. data/lib/gamefic/standard/articles.rb +52 -0
  32. data/lib/gamefic/standard/enterable.rb +13 -0
  33. data/lib/gamefic/standard/entities/character.rb +14 -0
  34. data/lib/gamefic/standard/entities/container.rb +16 -0
  35. data/lib/gamefic/standard/entities/door.rb +46 -0
  36. data/lib/gamefic/standard/entities/fixture.rb +8 -0
  37. data/lib/gamefic/standard/entities/item.rb +11 -0
  38. data/lib/gamefic/standard/entities/portal.rb +50 -0
  39. data/lib/gamefic/standard/entities/receptacle.rb +9 -0
  40. data/lib/gamefic/standard/entities/room.rb +55 -0
  41. data/lib/gamefic/standard/entities/rubble.rb +16 -0
  42. data/lib/gamefic/standard/entities/scenery.rb +13 -0
  43. data/lib/gamefic/standard/entities/supporter.rb +9 -0
  44. data/lib/gamefic/standard/entities/thing.rb +9 -0
  45. data/lib/gamefic/standard/entities.rb +18 -0
  46. data/lib/gamefic/standard/introduction.rb +18 -0
  47. data/lib/gamefic/standard/lockable.rb +44 -0
  48. data/lib/gamefic/standard/openable.rb +33 -0
  49. data/lib/gamefic/standard/pathfinder.rb +82 -0
  50. data/lib/gamefic/standard/queries.rb +24 -0
  51. data/lib/gamefic/standard/standardized.rb +65 -0
  52. data/lib/{gamefic-standard → gamefic/standard}/version.rb +1 -1
  53. data/lib/gamefic/standard.rb +32 -0
  54. data/lib/gamefic-standard.rb +1 -27
  55. metadata +83 -58
  56. data/lib/gamefic-standard/actions/attack.rb +0 -28
  57. data/lib/gamefic-standard/actions/close.rb +0 -18
  58. data/lib/gamefic-standard/actions/drop.rb +0 -24
  59. data/lib/gamefic-standard/actions/enter.rb +0 -36
  60. data/lib/gamefic-standard/actions/go.rb +0 -59
  61. data/lib/gamefic-standard/actions/insert.rb +0 -39
  62. data/lib/gamefic-standard/actions/inventory.rb +0 -15
  63. data/lib/gamefic-standard/actions/leave.rb +0 -50
  64. data/lib/gamefic-standard/actions/lock.rb +0 -25
  65. data/lib/gamefic-standard/actions/look.rb +0 -133
  66. data/lib/gamefic-standard/actions/move.rb +0 -24
  67. data/lib/gamefic-standard/actions/nil.rb +0 -60
  68. data/lib/gamefic-standard/actions/open.rb +0 -29
  69. data/lib/gamefic-standard/actions/place.rb +0 -24
  70. data/lib/gamefic-standard/actions/pronouns.rb +0 -28
  71. data/lib/gamefic-standard/actions/quit.rb +0 -10
  72. data/lib/gamefic-standard/actions/repeat.rb +0 -14
  73. data/lib/gamefic-standard/actions/save-restore-undo.rb +0 -18
  74. data/lib/gamefic-standard/actions/search.rb +0 -26
  75. data/lib/gamefic-standard/actions/take.rb +0 -40
  76. data/lib/gamefic-standard/actions/talk.rb +0 -37
  77. data/lib/gamefic-standard/actions/unlock.rb +0 -25
  78. data/lib/gamefic-standard/actions/wait.rb +0 -7
  79. data/lib/gamefic-standard/actions.rb +0 -23
  80. data/lib/gamefic-standard/articles.rb +0 -42
  81. data/lib/gamefic-standard/entities/character.rb +0 -2
  82. data/lib/gamefic-standard/entities/container.rb +0 -8
  83. data/lib/gamefic-standard/entities/door.rb +0 -42
  84. data/lib/gamefic-standard/entities/fixture.rb +0 -4
  85. data/lib/gamefic-standard/entities/item.rb +0 -7
  86. data/lib/gamefic-standard/entities/portal.rb +0 -46
  87. data/lib/gamefic-standard/entities/receptacle.rb +0 -5
  88. data/lib/gamefic-standard/entities/room.rb +0 -46
  89. data/lib/gamefic-standard/entities/rubble.rb +0 -12
  90. data/lib/gamefic-standard/entities/scenery.rb +0 -9
  91. data/lib/gamefic-standard/entities/supporter.rb +0 -5
  92. data/lib/gamefic-standard/entities/thing.rb +0 -9
  93. data/lib/gamefic-standard/entities.rb +0 -12
  94. data/lib/gamefic-standard/give.rb +0 -21
  95. data/lib/gamefic-standard/grammar/attributes.rb +0 -37
  96. data/lib/gamefic-standard/grammar/pronoun.rb +0 -101
  97. data/lib/gamefic-standard/grammar.rb +0 -2
  98. data/lib/gamefic-standard/introduction.rb +0 -8
  99. data/lib/gamefic-standard/modules/enterable.rb +0 -9
  100. data/lib/gamefic-standard/modules/lockable.rb +0 -34
  101. data/lib/gamefic-standard/modules/openable.rb +0 -19
  102. data/lib/gamefic-standard/modules/standardized.rb +0 -57
  103. data/lib/gamefic-standard/modules.rb +0 -6
  104. data/lib/gamefic-standard/pathfinder.rb +0 -62
  105. data/lib/gamefic-standard/queries.rb +0 -12
  106. data/spec-opal/spec_helper.rb +0 -32
  107. /data/lib/{gamefic-standard → gamefic/standard}/direction.rb +0 -0
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # An openable and lockable portal.
6
+ #
7
+ class Door < Portal
8
+ include Gamefic::Standard::Openable
9
+ include Gamefic::Standard::Lockable
10
+
11
+ def post_initialize
12
+ update_reverse_open
13
+ update_reverse_lock
14
+ end
15
+
16
+ def open=(bool)
17
+ super
18
+ reverse&.lock_key = lock_key
19
+ update_reverse_open
20
+ update_reverse_lock
21
+ end
22
+
23
+ def locked=(bool)
24
+ super
25
+ update_reverse_lock
26
+ end
27
+
28
+ def two_way_lock_key=(key)
29
+ self.lock_key = key
30
+ reverse&.lock_key = key
31
+ end
32
+
33
+ private
34
+
35
+ def update_reverse_open
36
+ rev = find_reverse
37
+ rev&.open = open? unless rev&.open? == open?
38
+ end
39
+
40
+ def update_reverse_lock
41
+ rev = find_reverse
42
+ rev&.locked = locked? unless rev&.locked? == locked?
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ class Fixture < Thing
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # An entity that is portable by default.
6
+ #
7
+ class Item < Thing
8
+ set_default portable: true
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # An entity that provides access from one room to another.
6
+ #
7
+ class Portal < Thing
8
+ # @return [Gamefic::Entity]
9
+ attr_accessor :destination
10
+
11
+ # Get the ordinal direction of this Portal
12
+ # Portals have distinct direction and name properties so games can display a
13
+ # bare compass direction for exits, e.g., "south" vs. "the southern door."
14
+ #
15
+ # A portal's destination can also be nil, in which case it can be referenced
16
+ # in commands by its destination, e.g., "go to the house."
17
+ #
18
+ # @return [Direction, nil]
19
+ attr_reader :direction
20
+
21
+ # Find the portal in the destination that returns to this portal's parent
22
+ #
23
+ # @return [Room, nil]
24
+ def reverse
25
+ return nil if destination.nil?
26
+
27
+ destination.children.that_are(Portal).find do |portal|
28
+ portal.destination == parent
29
+ end
30
+ end
31
+ alias find_reverse reverse
32
+
33
+ def direction=(dir)
34
+ @direction = Direction.find(dir)
35
+ end
36
+
37
+ def name
38
+ @name || direction&.name || destination.name
39
+ end
40
+
41
+ def instruction
42
+ direction || (destination ? "to #{destination.definitely}" : name)
43
+ end
44
+
45
+ def synonyms
46
+ "#{super} #{@destination} #{@direction} #{!direction.nil? ? direction.synonyms : ''}"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ class Receptacle < Thing
6
+ include Gamefic::Standard::Enterable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ class Room < Thing
6
+ attr_writer :explicit_exits
7
+
8
+ set_default explicit_exits: true
9
+
10
+ def explicit_exits?
11
+ @explicit_exits
12
+ end
13
+
14
+ def tell(message)
15
+ children.each { |c| c.tell message }
16
+ end
17
+
18
+ # @return [Array<Portal>]
19
+ def portals
20
+ children.that_are(Portal)
21
+ end
22
+
23
+ # @param destination [Room]
24
+ # @param direction [Direction, String, nil]
25
+ # @param type [Class<Portal>]
26
+ # @param two_way [Boolean]
27
+ # @return [Portal, Array<Portal>]
28
+ def connect(destination, direction: nil, type: Portal, two_way: true, **opts)
29
+ direction = Direction.find(direction)
30
+ here = type.new parent: self, destination: destination, direction: Direction.find(direction), **opts
31
+ return here unless two_way
32
+
33
+ there = type.new parent: destination, destination: self, direction: direction&.reverse, **opts
34
+ [here, there]
35
+ end
36
+
37
+ protected
38
+
39
+ %w[north south west east northeast southeast southwest northwest up down].each do |direction|
40
+ define_method "#{direction}=" do |destination|
41
+ connect destination, direction: direction
42
+ end
43
+ end
44
+
45
+ def connect=(destinations)
46
+ all = [destinations].flatten
47
+ until all.empty?
48
+ destination = all.shift
49
+ direction = (all.first.is_a?(String) ? all.shift : nil)
50
+ connect destination, direction: direction
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic/standard/entities/scenery'
4
+
5
+ module Gamefic
6
+ module Standard
7
+ # Rubble is Scenery with slightly modified action responses.
8
+ # Intended for things that might be portable but are useless.
9
+ # Rule of thumb: Scenery is something that can't be carried,
10
+ # like a table or the sky; and Rubble is something that might
11
+ # be portable but is otherwise useless, like trash or debris.
12
+ #
13
+ class Rubble < Scenery
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # Scenery is an entity that is not itemized by default. They're typically used
6
+ # to provide a description for objects that can be observed but do not respond
7
+ # to any other interactions.
8
+ #
9
+ class Scenery < Thing
10
+ set_default itemized: false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ class Supporter < Thing
6
+ include Enterable
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ Thing = Gamefic::Entity
6
+ Thing.set_default itemized: true, portable: false
7
+ Thing.include Gamefic::Standard::Standardized
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ require 'gamefic/standard/entities/thing'
6
+ require 'gamefic/standard/entities/character'
7
+ require 'gamefic/standard/entities/fixture'
8
+ require 'gamefic/standard/entities/item'
9
+ require 'gamefic/standard/entities/portal'
10
+ require 'gamefic/standard/entities/door'
11
+ require 'gamefic/standard/entities/receptacle'
12
+ require 'gamefic/standard/entities/container'
13
+ require 'gamefic/standard/entities/room'
14
+ require 'gamefic/standard/entities/scenery'
15
+ require 'gamefic/standard/entities/rubble'
16
+ require 'gamefic/standard/entities/supporter'
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # Add a simple introduction that sets an appropriate name and synonyms for
6
+ # the player character.
7
+ #
8
+ module Introduction
9
+ extend Gamefic::Scriptable
10
+
11
+ introduction do |actor|
12
+ actor.name = 'you'
13
+ actor.synonyms = 'self me yourself myself'
14
+ actor.proper_named = true
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # A module for entities that are both openable and lockable.
6
+ #
7
+ module Lockable
8
+ include Openable
9
+
10
+ attr_accessor :lock_key
11
+
12
+ def lock
13
+ self.locked = true
14
+ end
15
+
16
+ def unlock
17
+ self.locked = false
18
+ end
19
+
20
+ def locked=(bool)
21
+ @locked = bool
22
+ @open = false if @locked
23
+ end
24
+
25
+ def open=(bool)
26
+ @open = bool
27
+ @locked = false if @open
28
+ end
29
+
30
+ def locked?
31
+ @locked ||= false
32
+ end
33
+
34
+ def unlocked?
35
+ !locked?
36
+ end
37
+
38
+ def lock_key?
39
+ !@lock_key.nil?
40
+ end
41
+ alias has_lock_key? lock_key?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # A module for entities that are openable.
6
+ #
7
+ module Openable
8
+ def open
9
+ self.open = true
10
+ end
11
+
12
+ def close
13
+ self.open = false
14
+ end
15
+
16
+ def open=(bool)
17
+ @open = bool
18
+ end
19
+
20
+ def open?
21
+ @open ||= false
22
+ end
23
+
24
+ def closed?
25
+ !open?
26
+ end
27
+
28
+ def accessible
29
+ open? ? children : []
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # Pathfinders provide the shortest route between two rooms. The destination
6
+ # needs to be accessible from the origin through portals. Note that
7
+ # Pathfinder does not take into account portals that characters should not
8
+ # be able to traverse, such as locked doors.
9
+ #
10
+ class Pathfinder
11
+ # @return [Room]
12
+ attr_reader :origin
13
+
14
+ # @return [Room]
15
+ attr_reader :destination
16
+
17
+ # @param origin [Room]
18
+ # @param destination [Room]
19
+ def initialize(origin, destination)
20
+ @origin = origin
21
+ @destination = destination
22
+ @visited = []
23
+ if origin == destination
24
+ @path = []
25
+ else
26
+ embark [[origin]]
27
+ end
28
+ end
29
+
30
+ # An array of rooms starting with the first room after the origin and
31
+ # ending with the destination.
32
+ #
33
+ # The path will be empty if a path could not be found or the origin and
34
+ # destination are the same room.
35
+ #
36
+ # @return [Array<Room>]
37
+ def path
38
+ @path || []
39
+ end
40
+
41
+ # True if there is a valid path from the origin to the destination (or
42
+ # the origin and destination are the same room).
43
+ #
44
+ def valid?
45
+ !!@path
46
+ end
47
+
48
+ private
49
+
50
+ def embark(paths)
51
+ return if paths.empty?
52
+
53
+ new_paths = paths.each_with_object([]) do |path, acc|
54
+ updates = traverse(path)
55
+ acc.concat updates
56
+ end
57
+
58
+ if new_paths.last&.last == destination
59
+ @path = new_paths.last
60
+ else
61
+ embark new_paths
62
+ end
63
+ end
64
+
65
+ def traverse(path)
66
+ portals_with_destination(path).map do |portal|
67
+ next if @visited.include?(portal.destination)
68
+
69
+ return [path[1..] + [portal.destination]] if portal.destination == destination
70
+
71
+ @visited.push portal.destination
72
+ path + [portal.destination]
73
+ end
74
+ .compact
75
+ end
76
+
77
+ def portals_with_destination(path)
78
+ path.last.children.that_are(Portal).select(&:destination)
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,24 @@
1
+ module Gamefic
2
+ module Standard
3
+ module Queries
4
+ class RoomQuery < Gamefic::Query::Base
5
+ def span(subject)
6
+ [subject.room].compact
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ # @todo Monkey patch
14
+ module Gamefic
15
+ module Scriptable
16
+ module Queries
17
+ include Gamefic::Standard::Queries
18
+
19
+ def room *args
20
+ RoomQuery.new(Gamefic::Standard::Room, *args, name: 'room')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Standard
5
+ # Common features of standard entities.
6
+ #
7
+ module Standardized
8
+ # @return [Boolean]
9
+ attr_writer :itemized
10
+
11
+ # @return [Boolean]
12
+ attr_writer :portable
13
+
14
+ # An optional description to use when itemizing entities in room
15
+ # descriptions. The locale_description will be used instead of adding
16
+ # the entity's name to a list.
17
+ #
18
+ # @return [String, nil]
19
+ attr_accessor :locale_description
20
+
21
+ # Itemized entities are automatically listed in room descriptions.
22
+ #
23
+ # @return [Boolean]
24
+ def itemized?
25
+ @itemized
26
+ end
27
+
28
+ # Portable entities can be taken with TAKE actions.
29
+ #
30
+ # @return [Boolean]
31
+ def portable?
32
+ @portable
33
+ end
34
+
35
+ # @return [Boolean]
36
+ def attached?
37
+ @attached ||= false
38
+ end
39
+
40
+ # @param bool [Boolean]
41
+ def attached=(bool)
42
+ @attached = if parent.nil?
43
+ # @todo Log attachment failure
44
+ false
45
+ else
46
+ bool
47
+ end
48
+ end
49
+
50
+ def parent=(new_parent)
51
+ self.attached = false unless new_parent == parent
52
+ super
53
+ end
54
+
55
+ # The entity's parent room (i.e., the closest ascendant that is a Room).
56
+ #
57
+ # @return [Room]
58
+ def room
59
+ ascendant = parent
60
+ ascendant = ascendant.parent until ascendant.is_a?(Room) || ascendant.nil?
61
+ ascendant
62
+ end
63
+ end
64
+ end
65
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gamefic
4
4
  module Standard
5
- VERSION = '3.2.4'
5
+ VERSION = '4.0.0'
6
6
  end
7
7
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic'
4
+ require 'gamefic-grammar'
5
+ require 'gamefic-what'
6
+
7
+ module Gamefic
8
+ # The Gamefic standard library provides a base collection of entities and
9
+ # rules for interactive fiction.
10
+ #
11
+ module Standard
12
+ extend Gamefic::Scriptable
13
+
14
+ require 'gamefic/standard/version'
15
+ require 'gamefic/standard/articles'
16
+ require 'gamefic/standard/queries'
17
+ require 'gamefic/standard/standardized'
18
+ require 'gamefic/standard/enterable'
19
+ require 'gamefic/standard/openable'
20
+ require 'gamefic/standard/lockable'
21
+ require 'gamefic/standard/direction'
22
+ require 'gamefic/standard/entities'
23
+ require 'gamefic/standard/actions'
24
+ require 'gamefic/standard/introduction'
25
+ require 'gamefic/standard/pathfinder'
26
+
27
+ include Articles
28
+ include Grammar::Pronoun
29
+ include Actions
30
+ include Introduction
31
+ end
32
+ end
@@ -1,29 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'gamefic'
4
-
5
- module Gamefic
6
- # The Gamefic standard library provides a base collection of entities and
7
- # rules for interactive fiction.
8
- #
9
- module Standard
10
- extend Gamefic::Scriptable
11
-
12
- require 'gamefic-standard/version'
13
- require 'gamefic-standard/grammar'
14
- require 'gamefic-standard/articles'
15
- require 'gamefic-standard/queries'
16
- require 'gamefic-standard/modules'
17
- require 'gamefic-standard/direction'
18
- require 'gamefic-standard/entities'
19
- require 'gamefic-standard/actions'
20
- require 'gamefic-standard/introduction'
21
- require 'gamefic-standard/give'
22
-
23
- include Articles
24
-
25
- def connect(origin, destination, direction = nil, type: Portal, two_way: true)
26
- origin.connect destination, direction: direction, type: type, two_way: two_way
27
- end
28
- end
29
- end
3
+ require 'gamefic/standard'