Olib 2.0.0.pre.rc.1 → 2.0.0.pre.rc.6
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.
- checksums.yaml +4 -4
- data/Olib.gemspec +1 -1
- data/lib/Olib/bounty.rb +16 -23
- data/lib/Olib/character/group.rb +238 -225
- data/lib/Olib/combat/attack.rb +60 -0
- data/lib/Olib/combat/creature.rb +77 -59
- data/lib/Olib/combat/creatures.json +1770 -0
- data/lib/Olib/combat/creatures.rb +8 -22
- data/lib/Olib/combat/metadata.rb +13 -0
- data/lib/Olib/core/action.rb +6 -0
- data/lib/Olib/core/container.rb +5 -1
- data/lib/Olib/core/containers.rb +37 -18
- data/lib/Olib/core/exist.rb +14 -15
- data/lib/Olib/core/item.rb +11 -0
- data/lib/Olib/core/scroll.rb +37 -0
- data/lib/Olib/core/transaction.rb +15 -3
- data/lib/Olib/ext/matchdata.rb +1 -1
- data/lib/Olib/go2.rb +1 -2
- data/lib/Olib/log.rb +42 -0
- data/lib/Olib/loot.rb +2 -1
- data/lib/Olib/opts.rb +42 -0
- data/lib/Olib/pattern_matching/any.rb +0 -11
- data/lib/Olib/pattern_matching/result.rb +16 -1
- data/lib/Olib/pattern_matching/rill.rb +13 -5
- data/lib/Olib/version.rb +1 -1
- data/lib/Olib/xml.rb +6 -2
- metadata +8 -4
- data/lib/Olib/objects/scroll.rb +0 -42
@@ -1,11 +1,8 @@
|
|
1
|
-
require 'net/http'
|
2
1
|
require 'json'
|
3
2
|
# a collection for managing all of the creatures in a room
|
4
3
|
|
5
4
|
class Creatures
|
6
5
|
include Enumerable
|
7
|
-
|
8
|
-
METADATA_URL = "https://cdn.rawgit.com/ondreian/gemstone_data_project/c40a5dfb/creatures.json"
|
9
6
|
|
10
7
|
ARCHETYPES = %i[
|
11
8
|
undead living weak
|
@@ -15,7 +12,6 @@ class Creatures
|
|
15
12
|
|
16
13
|
STATES = %i[
|
17
14
|
prone sitting kneeling
|
18
|
-
dead
|
19
15
|
sleeping webbed immobile
|
20
16
|
stunned
|
21
17
|
flying
|
@@ -23,22 +19,6 @@ class Creatures
|
|
23
19
|
|
24
20
|
KINDS = ARCHETYPES + STATES
|
25
21
|
|
26
|
-
def self.fetch_metadata()
|
27
|
-
begin
|
28
|
-
JSON.parse Net::HTTP.get URI METADATA_URL
|
29
|
-
rescue
|
30
|
-
puts $!
|
31
|
-
puts $!.backtrace[0..1]
|
32
|
-
[]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
METADATA = fetch_metadata()
|
37
|
-
BY_NAME = METADATA.reduce(Hash.new) do |by_name, record|
|
38
|
-
by_name[record["name"]] = record
|
39
|
-
by_name
|
40
|
-
end
|
41
|
-
|
42
22
|
ALL = -> creature { true }
|
43
23
|
|
44
24
|
attr_reader :predicate
|
@@ -48,9 +28,9 @@ class Creatures
|
|
48
28
|
end
|
49
29
|
|
50
30
|
def each()
|
51
|
-
GameObj.
|
31
|
+
GameObj.targets.to_a.map do |obj| Creature.new(obj) end
|
52
32
|
.select(&@predicate)
|
53
|
-
.each do |creature| yield(creature) if GameObj[creature.id]
|
33
|
+
.each do |creature| yield(creature) if GameObj[creature.id] end
|
54
34
|
end
|
55
35
|
|
56
36
|
def respond_to_missing?(method, include_private = false)
|
@@ -75,6 +55,12 @@ class Creatures
|
|
75
55
|
Creatures.new do |creature| creature.name.include?(Bounty.creature) end
|
76
56
|
end
|
77
57
|
|
58
|
+
def dead
|
59
|
+
GameObj.npcs.to_a
|
60
|
+
.select do |c| c.status.include?("dead") end
|
61
|
+
.map do |obj| Creature.new(obj) end
|
62
|
+
end
|
63
|
+
|
78
64
|
def self.method_missing(method, *args, &block)
|
79
65
|
if respond_to?(method)
|
80
66
|
Creatures.new.send(method, *args, &block)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Creatures
|
2
|
+
module Metadata
|
3
|
+
@repo = JSON.parse File.read File.join(__dir__, "creatures.json")
|
4
|
+
|
5
|
+
def self.put(name:, level:, tags: [])
|
6
|
+
@repo[name.downcase] = {name: name, level: level, tags: tags}
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.get(name)
|
10
|
+
@repo.fetch(name.downcase) do {name: name, level: Char.level, tags: []} end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/Olib/core/action.rb
CHANGED
data/lib/Olib/core/container.rb
CHANGED
@@ -23,7 +23,11 @@ class Container < Exist
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def contents
|
26
|
-
GameObj.containers.fetch(id, []).map do |item| Item.
|
26
|
+
GameObj.containers.fetch(id, []).map do |item| Item.of(item, self) end
|
27
|
+
end
|
28
|
+
|
29
|
+
def closed?
|
30
|
+
not GameObj.containers[id]
|
27
31
|
end
|
28
32
|
|
29
33
|
def each(&block)
|
data/lib/Olib/core/containers.rb
CHANGED
@@ -1,31 +1,45 @@
|
|
1
1
|
require "Olib/pattern_matching/pattern_matching"
|
2
2
|
|
3
3
|
module Containers
|
4
|
-
@@containers
|
5
|
-
|
6
|
-
def self.find_game_obj!(
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
@@containers ||= {}
|
5
|
+
|
6
|
+
def self.find_game_obj!(pattern)
|
7
|
+
candidates = GameObj.inv.select do |item|
|
8
|
+
if pattern.class.is_a?(String)
|
9
|
+
item.name.include?(pattern)
|
10
|
+
else
|
11
|
+
item.name.match(pattern)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
case candidates.size
|
15
|
+
when 1
|
16
|
+
return Container.new(candidates.first)
|
17
|
+
when 0
|
18
|
+
fail Exception, <<~ERROR
|
19
|
+
Source(GameObj.inv)
|
20
|
+
|
21
|
+
reason: no matches for Pattern(#{pattern}) found in GameObj.inv
|
22
|
+
ERROR
|
23
|
+
else
|
24
|
+
fail Exception, <<~ERROR
|
25
|
+
Source(GameObj.inv)
|
26
|
+
|
27
|
+
reason: aspecific Container[#{pattern.to_s}] found
|
28
|
+
matches: #{candidates.map(&:name)}
|
29
|
+
ERROR
|
30
|
+
end
|
10
31
|
end
|
11
32
|
|
12
33
|
def self.define(name)
|
13
|
-
|
14
|
-
|
34
|
+
var = Vars[name.to_s] or fail Exception, "Var[#{name}] is not set\n\t;vars set #{name}=<whatever>"
|
35
|
+
pattern = %r[#{var}]
|
36
|
+
@@containers[name] = Containers.find_game_obj!(pattern)
|
15
37
|
@@containers[name]
|
16
38
|
end
|
17
39
|
|
18
|
-
def self.method_missing(name, *args)
|
19
|
-
return @@containers[name] if @@containers[name]
|
20
|
-
return self.define(name)
|
21
|
-
end
|
22
|
-
|
23
40
|
def self.[](name)
|
24
|
-
|
25
|
-
|
26
|
-
rescue Exception => err
|
27
|
-
Err(why: err.message, error: err)
|
28
|
-
end
|
41
|
+
return define(name) if name.is_a?(Symbol)
|
42
|
+
find_game_obj!(name)
|
29
43
|
end
|
30
44
|
|
31
45
|
def self.right_hand
|
@@ -39,4 +53,9 @@ module Containers
|
|
39
53
|
def self.registry
|
40
54
|
@@containers
|
41
55
|
end
|
56
|
+
|
57
|
+
def self.method_missing(name, *args)
|
58
|
+
return @@containers[name] if @@containers[name]
|
59
|
+
return self.define(name)
|
60
|
+
end
|
42
61
|
end
|
data/lib/Olib/core/exist.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
require "Olib/core/action"
|
3
3
|
|
4
4
|
class Exist
|
5
|
-
GETTER
|
5
|
+
GETTER = %r[\w$]
|
6
|
+
PATTERN = %r(<a exist=(?:'|")(?<id>.*?)(?:'|") noun=(?:'|")(?<noun>.*?)(?:'|")>(?<name>.*?)</a>)
|
6
7
|
|
7
8
|
def self.fetch(id)
|
8
9
|
[ GameObj.inv, GameObj.containers.values,
|
@@ -12,8 +13,12 @@ class Exist
|
|
12
13
|
.find do |item| item.id.to_s.eql?(id.to_s) end
|
13
14
|
end
|
14
15
|
|
16
|
+
def self.scan(str)
|
17
|
+
str.scan(PATTERN).map do |matches| Item.new(GameObj.new(*matches)) end
|
18
|
+
end
|
19
|
+
|
15
20
|
def self.normalize_type_data(type)
|
16
|
-
(type or "").gsub(",", " ").split(" ")
|
21
|
+
(type or "").gsub(",", " ").split(" ").compact
|
17
22
|
end
|
18
23
|
|
19
24
|
attr_reader :id, :gameobj
|
@@ -35,6 +40,8 @@ class Exist
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def method_missing(method, *args)
|
43
|
+
return nil if fetch.nil?
|
44
|
+
|
38
45
|
if respond_to_missing?(method)
|
39
46
|
fetch.send(method, *args)
|
40
47
|
else
|
@@ -51,7 +58,7 @@ class Exist
|
|
51
58
|
end
|
52
59
|
|
53
60
|
def tags
|
54
|
-
Exist.normalize_type_data(type).map(&:to_sym)
|
61
|
+
Exist.normalize_type_data("#{type},#{sellable}").map(&:to_sym)
|
55
62
|
end
|
56
63
|
|
57
64
|
def effects
|
@@ -72,17 +79,9 @@ class Exist
|
|
72
79
|
inspect()
|
73
80
|
end
|
74
81
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
val = send(prop)
|
80
|
-
acc = "#{acc} #{prop}=#{val.inspect}" unless val.nil? or val.empty?
|
81
|
-
acc
|
82
|
-
end.strip
|
83
|
-
|
84
|
-
body = "#{body} contents=[#{contents.map {|i| i.inspect(depth + 1)}.join}]" unless contents.to_a.empty?
|
85
|
-
|
86
|
-
%[#{indent}#{self.class.name}(#{body})]
|
82
|
+
def deconstruct_keys(keys)
|
83
|
+
keys.each_with_object({}) do |key, acc|
|
84
|
+
acc[key] = self.send(key)
|
85
|
+
end
|
87
86
|
end
|
88
87
|
end
|
data/lib/Olib/core/item.rb
CHANGED
@@ -2,6 +2,7 @@ require "ostruct"
|
|
2
2
|
require "Olib/core/exist"
|
3
3
|
require "Olib/core/use"
|
4
4
|
require "Olib/core/transaction"
|
5
|
+
require "Olib/core/scroll"
|
5
6
|
|
6
7
|
class GameObj
|
7
8
|
def to_item
|
@@ -12,6 +13,12 @@ end
|
|
12
13
|
# this is the structure for a base Object
|
13
14
|
# wraps an instance of GameObj and adds the ability for tags, queries
|
14
15
|
class Item < Exist
|
16
|
+
def self.of(item, container = nil)
|
17
|
+
return Scroll.new(item, container) if item.type.include?("scroll")
|
18
|
+
return Item.new(item, container)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
15
22
|
def self.fetch(id)
|
16
23
|
new Exist.fetch(id)
|
17
24
|
end
|
@@ -53,6 +60,10 @@ class Item < Exist
|
|
53
60
|
Transaction.new(take, **args)
|
54
61
|
end
|
55
62
|
|
63
|
+
def appraise(**args)
|
64
|
+
transaction(**args).appraise()
|
65
|
+
end
|
66
|
+
|
56
67
|
def sell(**args)
|
57
68
|
transaction(**args).sell()
|
58
69
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Scroll < Exist
|
2
|
+
SPELL = %r[\((?<num>\d+)\)\s(?<name>(\w|\s)+)$]
|
3
|
+
|
4
|
+
def initialize(obj, container = nil)
|
5
|
+
super(obj.id)
|
6
|
+
@knowledge = nil
|
7
|
+
@container = container
|
8
|
+
end
|
9
|
+
|
10
|
+
def spells()
|
11
|
+
@_spells ||= _read()
|
12
|
+
end
|
13
|
+
|
14
|
+
def knowledge?
|
15
|
+
spells
|
16
|
+
@knowledge.eql?(true)
|
17
|
+
end
|
18
|
+
|
19
|
+
def _read()
|
20
|
+
Script.current.want_downstream_xml = true
|
21
|
+
dothistimeout("read ##{id}", 5, /It takes you a moment to focus on the/)
|
22
|
+
spells = []
|
23
|
+
@knowledge = false
|
24
|
+
while line = get
|
25
|
+
@knowledge = true if line.include?(%[in vibrant ink])
|
26
|
+
break if line =~ %r[<prompt]
|
27
|
+
_parse_spell(spells, line.strip)
|
28
|
+
end
|
29
|
+
Script.current.want_downstream_xml = false
|
30
|
+
return spells
|
31
|
+
end
|
32
|
+
|
33
|
+
def _parse_spell(spells, line)
|
34
|
+
return unless line =~ SPELL
|
35
|
+
spells << OpenStruct.new(line.match(SPELL).to_h)
|
36
|
+
end
|
37
|
+
end
|
@@ -5,6 +5,7 @@ class Transaction < Exist
|
|
5
5
|
start: %[to appraise (?:a |an |)<a exist="{{id}}"],
|
6
6
|
close: Regexp.union(
|
7
7
|
%r[I already appraised that],
|
8
|
+
%r[Sorry, #{Char.name}, I'm not buying anything this valuable today\.],
|
8
9
|
%r[(I'll give you|How's|I'll offer you|worth at least) (?<value>\d+)],
|
9
10
|
%r[(?<value>\d+) silvers])
|
10
11
|
)
|
@@ -14,6 +15,9 @@ class Transaction < Exist
|
|
14
15
|
close: Regexp.union(
|
15
16
|
%r[(hands you|for) (?<value>\d+)],
|
16
17
|
%r[No #{Char.name}, I won't buy that],
|
18
|
+
%r[I'm sorry, #{Char.name}, but I have no use for that\.],
|
19
|
+
%r[He hands it back to you],
|
20
|
+
%r[Nope #{Char.name}, I ain't buying that\.],
|
17
21
|
%r[basically worthless here, #{Char.name}])
|
18
22
|
)
|
19
23
|
|
@@ -33,9 +37,13 @@ class Transaction < Exist
|
|
33
37
|
def appraise()
|
34
38
|
return self unless @value.nil?
|
35
39
|
take
|
36
|
-
(match,
|
40
|
+
(_, match, lines) = Appraise.capture(self.to_h,
|
37
41
|
"appraise \#{{id}}")
|
38
|
-
|
42
|
+
if lines.any? {|line| line.include?(%[Sorry, Pixelia, I'm not buying anything this valuable today.])}
|
43
|
+
@value = Float::INFINITY
|
44
|
+
else
|
45
|
+
@value = match[:value].to_i
|
46
|
+
end
|
39
47
|
self
|
40
48
|
end
|
41
49
|
|
@@ -46,8 +54,12 @@ class Transaction < Exist
|
|
46
54
|
transaction: self,
|
47
55
|
reason: "Value[#{@value}] is over Threshold[#{@threshold}]"]
|
48
56
|
end
|
49
|
-
|
57
|
+
|
58
|
+
(_, match, _lines) = Sell.capture(self.to_h,
|
50
59
|
"sell \#{{id}}")
|
60
|
+
|
61
|
+
|
62
|
+
match[:value] = 0 unless match[:value].is_a?(Integer)
|
51
63
|
Ok[**match]
|
52
64
|
end
|
53
65
|
end
|
data/lib/Olib/ext/matchdata.rb
CHANGED
data/lib/Olib/go2.rb
CHANGED
@@ -32,8 +32,7 @@ class Go2
|
|
32
32
|
def Go2.room(roomid)
|
33
33
|
unless Room.current.id == roomid || Room.current.tags.include?(roomid)
|
34
34
|
Char.unhide if hidden
|
35
|
-
|
36
|
-
wait_while { running? "go2" };
|
35
|
+
Script.run("go2", "#{roomid} _disable_confirm_")
|
37
36
|
end
|
38
37
|
Go2
|
39
38
|
end
|
data/lib/Olib/log.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Preset
|
2
|
+
def self.as(kind, body)
|
3
|
+
%[<preset id="#{kind}">#{body}</preset>\r\n]
|
4
|
+
end
|
5
|
+
end
|
6
|
+
##
|
7
|
+
## contextual logging
|
8
|
+
##
|
9
|
+
module Log
|
10
|
+
require "cgi"
|
11
|
+
def self.out(msg, label: :debug)
|
12
|
+
return _write _view(msg, label) unless msg.is_a?(Exception)
|
13
|
+
## pretty-print exception
|
14
|
+
_write _view(msg.message, label)
|
15
|
+
msg.backtrace.to_a.slice(0..5).each do |frame| _write _view(frame, label) end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self._write(line)
|
19
|
+
if Script.current.vars.include?("--headless") or not defined?(:_respond)
|
20
|
+
$stdout.write(line + "\n")
|
21
|
+
elsif line.include?("<") and line.include?(">")
|
22
|
+
respond(line)
|
23
|
+
else
|
24
|
+
_respond Preset.as(:debug, CGI.escapeHTML(line))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self._view(msg, label)
|
29
|
+
label = [Script.current.name, label].flatten.compact.join(".")
|
30
|
+
safe = msg.inspect
|
31
|
+
#safe = safe.gsub("<", "<").gsub(">", ">") if safe.include?("<") and safe.include?(">")
|
32
|
+
"[#{label}] #{safe}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.pp(msg, label = :debug)
|
36
|
+
respond _view(msg, label)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.dump(*args)
|
40
|
+
pp(*args)
|
41
|
+
end
|
42
|
+
end
|
data/lib/Olib/loot.rb
CHANGED
data/lib/Olib/opts.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
##
|
2
|
+
## minimal options parser
|
3
|
+
##
|
4
|
+
module Opts
|
5
|
+
FLAG_PREFIX = "--"
|
6
|
+
|
7
|
+
def self.parse_command(h, c)
|
8
|
+
h[c.to_sym] = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.parse_flag(h, f)
|
12
|
+
(name, val) = f[2..-1].split("=")
|
13
|
+
if val.nil?
|
14
|
+
h[name.to_sym] = true
|
15
|
+
else
|
16
|
+
val = val.split(",")
|
17
|
+
|
18
|
+
h[name.to_sym] = val.size == 1 ? val.first : val
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse(args = Script.current.vars[1..-1])
|
23
|
+
OpenStruct.new(**args.to_a.reduce(Hash.new) do |opts, v|
|
24
|
+
if v.start_with?(FLAG_PREFIX)
|
25
|
+
Opts.parse_flag(opts, v)
|
26
|
+
else
|
27
|
+
Opts.parse_command(opts, v)
|
28
|
+
end
|
29
|
+
opts
|
30
|
+
end)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.as_list(key)
|
34
|
+
val = to_h.fetch(key.to_sym, [])
|
35
|
+
val = [val] if val.is_a?(String)
|
36
|
+
return val
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.method_missing(method, *args)
|
40
|
+
parse.send(method, *args)
|
41
|
+
end
|
42
|
+
end
|