gamefic-commodities 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '08a734e8585509d12f97f384bcd5e7ff9081ee6500ea4f3eaaae6337bbaf0d98'
4
+ data.tar.gz: 7c83ac167edba79d950397f919faeffe7c12ef76c0f0e82e4b4fbe8cda3d288a
5
+ SHA512:
6
+ metadata.gz: ff83060ddb98824b01c98a229697834e5d3448d4ceb8c22f8de11939439c48fae7cdda371c79dd5cc94f2347edc51dc98fca623d1f42ca7a14152e136756f440
7
+ data.tar.gz: ada7030b38061a939c7ee47b010f67dbd039645f8bf2464a9a71658568fd9144a7c4f9072806d3fc377398aaa28e07c36eb4c3a12e9f770cfbafd42024da69ec
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,2 @@
1
+ ## 0.1.0 - October 5, 2024
2
+ - First release
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Gamefic::Commodities
2
+
3
+ A groupable Gamefic entity.
4
+
5
+ Commodities are grouped by default. When a commodity gets added to a parent
6
+ that already contains a commodity with the same class and name, they get
7
+ combined, i.e., the existing commodity's quantity is increased by the new
8
+ commodity's quantity, and the other commodity is destroyed.
9
+
10
+ Players can specify quantities in commands, e.g., `take 1 coin`.
11
+
12
+ ## Installation
13
+
14
+ Add the library to your Gamefic project's Gemfile:
15
+
16
+ ```
17
+ gem 'gamefic-commodities'
18
+ ```
19
+
20
+ Run `bundle install`.
21
+
22
+ Add the requirement to your project's code (typically in `main.rb`):
23
+
24
+ ```
25
+ require 'gamefic-commodities'
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ The `Commodity` entity and related actions are automatically imported into `Gamefic::Standard`.
31
+
32
+ Example of adding a commodity:
33
+
34
+ ```ruby
35
+ class Example::Plot < Gamefic::Plot
36
+ include Gamefic::Standard
37
+
38
+ attr_seed :room, Room,
39
+ name: 'room'
40
+
41
+ make_seed Commodity,
42
+ name: 'coin',
43
+ quantity: 2,
44
+ parent: _attr(:room)
45
+
46
+ introduction do |actor|
47
+ actor.parent = room
48
+ end
49
+ end
50
+ ```
51
+
52
+ Example gameplay:
53
+
54
+ > look
55
+ You see 2 coins.
56
+ > take coin
57
+ You take 2 coins.
58
+ > drop 1 coin
59
+ You drop a coin.
60
+ > look
61
+ You see a coin.
62
+ > inventory
63
+ You're carrying a coin.
64
+
65
+ ## Development
66
+
67
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
68
+
69
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/castwide/gamefic-commodity.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require 'opal/rspec/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task default: :spec
10
+
11
+ Opal::RSpec::RakeTask.new(:opal) do |_, config|
12
+ Opal.append_path File.join(__dir__, 'lib')
13
+ Opal.use_gem 'gamefic'
14
+ Opal.use_gem 'gamefic-standard'
15
+ config.default_path = 'spec'
16
+ config.pattern = 'spec/**/*_spec.rb'
17
+ config.requires = ['opal_helper']
18
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/gamefic/commodities/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'gamefic-commodities'
7
+ spec.version = Gamefic::Commodities::VERSION
8
+ spec.authors = ['Fred Snyder']
9
+ spec.email = ['fsnyder@castwide.com']
10
+
11
+ spec.summary = 'A Commodity entity for Gamefic.'
12
+ # spec.description = "TODO: Write a longer description or delete this line."
13
+ # spec.homepage = "TODO: Put your gem's website or public repo URL here."
14
+ spec.required_ruby_version = '>= 2.7.0'
15
+
16
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
17
+
18
+ # spec.metadata["homepage_uri"] = spec.homepage
19
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
20
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(__dir__) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (File.expand_path(f) == __FILE__) ||
27
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
28
+ end
29
+ end
30
+ spec.bindir = 'exe'
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ['lib']
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ # spec.add_dependency "example-gem", "~> 1.0"
36
+ spec.add_dependency 'gamefic', '~> 3.5'
37
+ spec.add_dependency 'gamefic-standard', '~> 3.0'
38
+
39
+ spec.add_development_dependency 'opal', '~> 1.7'
40
+ spec.add_development_dependency 'opal-rspec', '~> 1.0'
41
+ spec.add_development_dependency 'opal-sprockets', '~> 1.0'
42
+ spec.add_development_dependency 'rspec', '~> 3.0'
43
+ spec.add_development_dependency 'simplecov', '~> 0.14'
44
+
45
+ # For more information and examples about making a new gem, check out our
46
+ # guide at: https://bundler.io/guides/creating_gem.html
47
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Commodities
5
+ module Actions
6
+ extend Gamefic::Scriptable
7
+
8
+ respond :look, ::Commodity do |actor, thing|
9
+ actor.proceed
10
+ next unless thing.plural?
11
+
12
+ if thing.parent == actor
13
+ actor.tell "You have #{thing.quantity} of them."
14
+ else
15
+ actor.tell "There are #{thing.quantity} of them in #{the thing.parent}."
16
+ end
17
+ end
18
+
19
+ respond :take, siblings(::Commodity) do |actor, _|
20
+ actor.proceed
21
+ end
22
+
23
+ respond :place, siblings(::Commodity), available do |actor, _|
24
+ actor.proceed
25
+ end
26
+
27
+ respond :place, children(::Commodity), available do |actor, _|
28
+ actor.proceed
29
+ end
30
+
31
+ respond :insert, siblings(::Commodity), available do |actor, _|
32
+ actor.proceed
33
+ end
34
+
35
+ respond :insert, children(::Commodity), available do |actor, _|
36
+ actor.proceed
37
+ end
38
+
39
+ respond :take, available(::Commodity, ambiguous: true) do |actor, comms|
40
+ comms = comms.reject { |com| com.parent == actor }
41
+ if comms.one?
42
+ actor.execute :take, comms.first
43
+ else
44
+ filtered = comms.reject { |ent| actor.flatten.include?(ent) }
45
+ if filtered.one?
46
+ actor.execute :take, filtered.first
47
+ else
48
+ places = filtered.map { |object| object.parent.definitely }
49
+ actor.tell "Where do you want to take one from, #{places.join_or}?"
50
+ actor.ask_for_what "take #{filtered.first.name} from __what__"
51
+ end
52
+ end
53
+ end
54
+
55
+ respond :collect, available(::Commodity, ambiguous: true) do |actor, comms|
56
+ comms.reject { |com| com.parent == actor }
57
+ .each { |com| actor.perform "take #{com.plural_name} from #{com.parent}" }
58
+ end
59
+ interpret 'collect all', 'take all'
60
+ interpret 'collect :thing', 'take :thing'
61
+ interpret 'collect all :commodity', 'collect :commodity'
62
+ interpret 'collect all of :commodity', 'collect :commodity'
63
+ interpret 'collect every :commodity', 'collect :commodity'
64
+ interpret 'collect each :commodity', 'collect :commodity'
65
+ interpret 'take all :commodity', 'collect :commodity'
66
+ interpret 'take all of :commodity', 'collect :commodity'
67
+ interpret 'take every :commodity', 'collect :commodity'
68
+ interpret 'take each :commodity', 'collect :commodity'
69
+
70
+ meta nil, plaintext do |actor, text|
71
+ words = text.keywords
72
+ verb = words.shift
73
+ next actor.proceed if words.empty? || words.first =~ /[^\d]+/
74
+
75
+ number = words.shift.to_i
76
+ Utils.try_quantity(actor, number, "#{verb} #{words.join(' ')}")
77
+ end
78
+
79
+ on_update do
80
+ entities.that_are(::Commodity)
81
+ .reject(&:parent)
82
+ .each { |entity| destroy entity }
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Commodities
5
+ # A groupable Gamefic entity.
6
+ #
7
+ # Commodities are grouped by default. When a commodity gets added to a parent
8
+ # that already contains a commodity with the same class and name, they get
9
+ # combined, i.e., the existing commodity's quantity is increased by the new
10
+ # commodity's quantity, and the other commodity is destroyed.
11
+ #
12
+ class Commodity < Item
13
+ class CommodityError < ArgumentError; end
14
+
15
+ # @return [Integer]
16
+ attr_writer :quantity
17
+
18
+ # @return [String]
19
+ attr_writer :plural_name
20
+
21
+ def quantity
22
+ @quantity ||= 1
23
+ end
24
+
25
+ def name
26
+ plural? ? plural_name : super
27
+ end
28
+
29
+ def indefinite_article
30
+ plural? ? quantity : super
31
+ end
32
+
33
+ def plural?
34
+ quantity > 1
35
+ end
36
+
37
+ # @return [String]
38
+ def plural_name
39
+ @plural_name ||= "#{@name}s"
40
+ end
41
+
42
+ # @param amount [Integer]
43
+ # @return [Commodity]
44
+ def except(amount)
45
+ validate_split(amount)
46
+ split(quantity - amount)
47
+ end
48
+
49
+ # @param amount [Integer]
50
+ # @return [Commodity]
51
+ def split(amount)
52
+ validate_split(amount)
53
+ return nil if amount.zero?
54
+
55
+ dup.tap do |other|
56
+ self.quantity -= amount
57
+ other.quantity = amount
58
+ other.parent = nil
59
+ end
60
+ end
61
+
62
+ def parent=(other)
63
+ extant = other&.children&.that_are&.find { |ent| same?(ent) }
64
+ if extant
65
+ extant.quantity += quantity
66
+ super(nil)
67
+ else
68
+ super
69
+ end
70
+ end
71
+
72
+ def same?(other)
73
+ other.class == self.class && other.plural_name == plural_name
74
+ end
75
+
76
+ def keywords
77
+ super + plural_name.keywords
78
+ end
79
+
80
+ def counted?
81
+ @counted ||= false
82
+ end
83
+
84
+ def count(number)
85
+ raise CommodityError, "You need to specify 1 or more #{plural_name}" if number.zero?
86
+ return unless block_given?
87
+
88
+ @counted = true
89
+ rest = except(number)
90
+ from = parent
91
+ yield
92
+ rest&.parent = from if rest&.quantity&.positive?
93
+ @counted = false
94
+ end
95
+
96
+ def validate_split(amount)
97
+ raise CommodityError, "There #{maybe_plural('is', 'are')} only #{quantity} #{name}." unless amount <= quantity
98
+
99
+ raise CommodityError, "You can't specify a negative number of #{plural_name}." unless amount >= 0
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ Commodity = Gamefic::Commodities::Commodity
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Commodities
5
+ module Utils
6
+ module_function
7
+
8
+ # @param actor [Gamefic::Actor]
9
+ # @param number [Integer]
10
+ # @param input [String]
11
+ def try_quantity(actor, number, input)
12
+ command = Gamefic::Command.compose(actor, input)
13
+ return actor.proceed unless command.arguments.first.is_a?(Commodity)
14
+
15
+ command.arguments.first.count(number) do
16
+ actor.execute command.verb, *command.arguments
17
+ end
18
+ rescue Commodity::CommodityError => e
19
+ actor.tell e.message
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gamefic
4
+ module Commodities
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic'
4
+ require 'gamefic-standard'
5
+
6
+ module Gamefic
7
+ module Commodities
8
+ require 'gamefic/commodities/version'
9
+ require 'gamefic/commodities/commodity'
10
+ require 'gamefic/commodities/utils'
11
+ require 'gamefic/commodities/actions'
12
+ end
13
+ end
14
+
15
+ Gamefic::Standard.include Gamefic::Commodities::Actions
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic/commodities'
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gamefic-commodities
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Fred Snyder
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-10-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gamefic
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: gamefic-standard
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: opal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: opal-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: opal-sprockets
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.14'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.14'
111
+ description:
112
+ email:
113
+ - fsnyder@castwide.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".rspec"
119
+ - CHANGELOG.md
120
+ - README.md
121
+ - Rakefile
122
+ - gamefic-commodities.gemspec
123
+ - lib/gamefic-commodities.rb
124
+ - lib/gamefic/commodities.rb
125
+ - lib/gamefic/commodities/actions.rb
126
+ - lib/gamefic/commodities/commodity.rb
127
+ - lib/gamefic/commodities/utils.rb
128
+ - lib/gamefic/commodities/version.rb
129
+ homepage:
130
+ licenses: []
131
+ metadata: {}
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: 2.7.0
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubygems_version: 3.3.7
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: A Commodity entity for Gamefic.
151
+ test_files: []