gamefic 0.0.1
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 +7 -0
- data/lib/gamefic/action.rb +61 -0
- data/lib/gamefic/action_ext/container.rb +36 -0
- data/lib/gamefic/action_ext/inventory.rb +37 -0
- data/lib/gamefic/action_ext/look.rb +52 -0
- data/lib/gamefic/action_ext/meta.rb +10 -0
- data/lib/gamefic/action_ext/traversal.rb +39 -0
- data/lib/gamefic/base.rb +10 -0
- data/lib/gamefic/character.rb +72 -0
- data/lib/gamefic/core_ext/array.rb +40 -0
- data/lib/gamefic/core_ext/string.rb +42 -0
- data/lib/gamefic/describable.rb +27 -0
- data/lib/gamefic/director.rb +133 -0
- data/lib/gamefic/engine.rb +18 -0
- data/lib/gamefic/entity.rb +76 -0
- data/lib/gamefic/entity_ext/container.rb +9 -0
- data/lib/gamefic/entity_ext/fixture.rb +9 -0
- data/lib/gamefic/entity_ext/item.rb +11 -0
- data/lib/gamefic/entity_ext/itemized.rb +7 -0
- data/lib/gamefic/entity_ext/portable.rb +33 -0
- data/lib/gamefic/entity_ext/portal.rb +47 -0
- data/lib/gamefic/entity_ext/room.rb +31 -0
- data/lib/gamefic/entity_ext/scenery.rb +7 -0
- data/lib/gamefic/entity_ext/zone.rb +8 -0
- data/lib/gamefic/keywords.rb +39 -0
- data/lib/gamefic/node.rb +62 -0
- data/lib/gamefic/plot.rb +188 -0
- data/lib/gamefic/query.rb +187 -0
- data/lib/gamefic/syntax.rb +117 -0
- data/lib/gamefic/user.rb +64 -0
- data/lib/gamefic.rb +12 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d39e0e4c0bdd08258174c87bfe75b1a44ab60643
|
4
|
+
data.tar.gz: 201eb4941dc0d59a784992c35068a379287d9e0e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4939cd6592c098ce8d407b654c38c1ba75583b95b0581c8c834c3d973e9e415d36095317f837888b937e0ceb2231cfc80e003b3c59e9ff0c75b8547af4c8eb98
|
7
|
+
data.tar.gz: eece7938f58fdbf2746061eb85c2eb932fe0773afd966f544c3cb9c7ac87131da403b339cedd46bdc2ffb07fc4dda5a7626c675ed7b2dc569aa05698ea2a30f0
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
class Action
|
4
|
+
attr_reader :command
|
5
|
+
@@defaults = Array.new
|
6
|
+
def initialize(story, command, *queries, &proc)
|
7
|
+
if (command.kind_of?(Symbol) == false)
|
8
|
+
raise "Action commands must be symbols"
|
9
|
+
end
|
10
|
+
if (queries.length + 1 != proc.arity) and (queries.length == 0 and proc.arity != -1)
|
11
|
+
raise "Number of contexts is not compatible with proc arguments"
|
12
|
+
end
|
13
|
+
@command = command
|
14
|
+
@queries = queries
|
15
|
+
@proc = proc
|
16
|
+
if story == nil
|
17
|
+
@@defaults.push self
|
18
|
+
else
|
19
|
+
story.send :add_action, self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
def self.defaults
|
23
|
+
@@defaults.clone
|
24
|
+
end
|
25
|
+
def specificity
|
26
|
+
spec = 0
|
27
|
+
magnitude = 1
|
28
|
+
@queries.each { |q|
|
29
|
+
if q.kind_of?(Query)
|
30
|
+
spec += (q.specificity * magnitude)
|
31
|
+
else
|
32
|
+
spec += magnitude
|
33
|
+
end
|
34
|
+
magnitude = magnitude * 10
|
35
|
+
}
|
36
|
+
return spec
|
37
|
+
end
|
38
|
+
def key
|
39
|
+
@key
|
40
|
+
end
|
41
|
+
def queries
|
42
|
+
@queries
|
43
|
+
end
|
44
|
+
def proc
|
45
|
+
@proc
|
46
|
+
end
|
47
|
+
private
|
48
|
+
def self.explode(entity)
|
49
|
+
arr = Array.new
|
50
|
+
arr.push entity
|
51
|
+
cls = entity.class
|
52
|
+
while cls != Object
|
53
|
+
arr.push cls
|
54
|
+
cls = cls.superclass
|
55
|
+
end
|
56
|
+
arr.push String
|
57
|
+
arr.push nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
Action.new nil, :look_inside, Query.new(:family, Container) do |actor, container|
|
4
|
+
if container.children.length == 0
|
5
|
+
actor.tell "You don't find anything."
|
6
|
+
else
|
7
|
+
actor.tell "#{container.longname} contains: #{container.children.join(', ')}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
Syntax.new nil, "look inside :container", :look_inside, :container
|
11
|
+
Syntax.new nil, "search :container", :look_inside, :container
|
12
|
+
Syntax.new nil, "look in :container", :look_inside, :container
|
13
|
+
|
14
|
+
Action.new nil, :look_in_at, Query.new(:family, Container), Subquery.new(:children, Entity) do |actor, container, item|
|
15
|
+
actor.tell item.description
|
16
|
+
end
|
17
|
+
Syntax.new nil, "look at :item in :container", :look_in_at, :container, :item
|
18
|
+
Syntax.new nil, "look :item in :container", :look_in_at, :container, :item
|
19
|
+
|
20
|
+
Action.new nil, :take_from, Query.new(:family, Container), Subquery.new(:children, Item) do |actor, container, item|
|
21
|
+
item.parent = actor
|
22
|
+
actor.tell "You take #{item.longname} from #{container.longname}."
|
23
|
+
end
|
24
|
+
Syntax.new nil, "take :item from :container", :take_from, :container, :item
|
25
|
+
Syntax.new nil, "get :item from :container", :take_from, :container, :item
|
26
|
+
Syntax.new nil, "remove :item from :container", :take_from, :container, :item
|
27
|
+
|
28
|
+
Action.new nil, :drop_in, Query.new(:family, Container), Query.new(:children) do |actor, container, item|
|
29
|
+
item.parent = container
|
30
|
+
actor.tell "You put #{item.longname} in #{container.longname}."
|
31
|
+
end
|
32
|
+
Syntax.new nil, "drop :item in :container", :drop_in, :container, :item
|
33
|
+
Syntax.new nil, "put :item in :container", :drop_in, :container, :item
|
34
|
+
Syntax.new nil, "place :item in :container", :drop_in, :container, :item
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
Action.new nil, :inventory do |actor|
|
4
|
+
if actor.children.length > 0
|
5
|
+
actor.tell actor.children.join(', ')
|
6
|
+
else
|
7
|
+
actor.tell "You aren't carrying anything."
|
8
|
+
end
|
9
|
+
end
|
10
|
+
Syntax.new nil, "i", :inventory
|
11
|
+
|
12
|
+
Action.new nil, :take, Query.new(:siblings, Portable) do |actor, thing|
|
13
|
+
thing.parent = actor
|
14
|
+
actor.tell "You take #{thing.longname}.", true
|
15
|
+
end
|
16
|
+
|
17
|
+
Action.new nil, :take, Query.new(:siblings) do |actor, thing|
|
18
|
+
actor.tell "You can't carry #{thing.longname}."
|
19
|
+
end
|
20
|
+
|
21
|
+
Action.new nil, :take, String do |actor, thing|
|
22
|
+
actor.tell "You don't see anything called \"#{thing}\" here."
|
23
|
+
end
|
24
|
+
|
25
|
+
Action.new nil, :drop, Query.new(:children) do |actor, thing|
|
26
|
+
thing.parent = actor.parent
|
27
|
+
actor.tell "You drop #{thing.longname}.", true
|
28
|
+
end
|
29
|
+
|
30
|
+
Syntax.new nil, "get :thing", :take, :thing
|
31
|
+
Syntax.new nil, "pick :thing up", :take, :thing
|
32
|
+
Syntax.new nil, "pick up :thing", :take, :thing
|
33
|
+
|
34
|
+
Syntax.new nil, "put down :thing", :drop, :thing
|
35
|
+
Syntax.new nil, "put :thing down", :drop, :thing
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
Action.new nil, :look do |actor|
|
4
|
+
actor.perform "itemize room full"
|
5
|
+
end
|
6
|
+
|
7
|
+
Action.new nil, :look_around do |actor|
|
8
|
+
actor.perform "look"
|
9
|
+
end
|
10
|
+
|
11
|
+
Action.new nil, :itemize_room, Query.new(:string) do |actor, option|
|
12
|
+
actor.tell "#{actor.parent.longname.cap_first}"
|
13
|
+
if option == "full"
|
14
|
+
actor.tell actor.parent.description
|
15
|
+
end
|
16
|
+
chars = actor.parent.children.that_are(Character) - [actor]
|
17
|
+
if chars.length > 0
|
18
|
+
actor.tell "Others here: #{chars.join(", ")}"
|
19
|
+
end
|
20
|
+
#items = actor.parent.children.that_are(Itemized) - [chars] - [actor] - actor.parent.children.that_are(Portal)
|
21
|
+
items = actor.parent.children.that_are(Itemized)
|
22
|
+
if items.length > 0
|
23
|
+
actor.tell "Visible items: #{items.join(", ")}"
|
24
|
+
end
|
25
|
+
portals = actor.parent.children.that_are(Portal)
|
26
|
+
if portals.length > 0
|
27
|
+
actor.tell "Obvious exits: #{portals.join(', ')}"
|
28
|
+
else
|
29
|
+
actor.tell "Obvious exits: none"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
Syntax.new nil, "itemize room", :itemize_room, "short"
|
33
|
+
Syntax.new nil, "itemize room :option", :itemize_room, :option
|
34
|
+
|
35
|
+
Action.new nil, :look, Query.new(:family) do |actor, thing|
|
36
|
+
actor.tell thing.description
|
37
|
+
end
|
38
|
+
|
39
|
+
Action.new nil, :look, Query.new(:parent) do |actor, thing|
|
40
|
+
actor.perform "look"
|
41
|
+
end
|
42
|
+
|
43
|
+
Action.new nil, :look, String do |actor, string|
|
44
|
+
actor.tell "You don't see any \"#{string}\" here."
|
45
|
+
end
|
46
|
+
|
47
|
+
Syntax.new nil, "look at :thing", :look, :thing
|
48
|
+
Syntax.new nil, "examine :thing", :look, :thing
|
49
|
+
Syntax.new nil, "exam :thing", :look, :thing
|
50
|
+
Syntax.new nil, "x :thing", :look, :thing
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
Action.new nil, :go, Query.new(:siblings, Portal) do |actor, portal|
|
4
|
+
actor.parent = portal.destination
|
5
|
+
actor.tell "You go #{portal.name}."
|
6
|
+
actor.perform "itemize room"
|
7
|
+
end
|
8
|
+
|
9
|
+
Action.new nil, :go, String do |actor, string|
|
10
|
+
actor.tell "You don't see any exit \"#{string}\" from here."
|
11
|
+
end
|
12
|
+
|
13
|
+
Action.new nil, :go do |actor|
|
14
|
+
actor.tell "Where do you want to go?"
|
15
|
+
end
|
16
|
+
|
17
|
+
Syntax.new nil, "north", :go, "north"
|
18
|
+
Syntax.new nil, "south", :go, "south"
|
19
|
+
Syntax.new nil, "west", :go, "west"
|
20
|
+
Syntax.new nil, "east", :go, "east"
|
21
|
+
Syntax.new nil, "up", :go, "up"
|
22
|
+
Syntax.new nil, "down", :go, "down"
|
23
|
+
Syntax.new nil, "northwest", :go, "northwest"
|
24
|
+
Syntax.new nil, "northeast", :go, "northeast"
|
25
|
+
Syntax.new nil, "southwest", :go, "southwest"
|
26
|
+
Syntax.new nil, "southeast", :go, "southeast"
|
27
|
+
|
28
|
+
Syntax.new nil, "n", :go, "north"
|
29
|
+
Syntax.new nil, "s", :go, "south"
|
30
|
+
Syntax.new nil, "w", :go, "west"
|
31
|
+
Syntax.new nil, "e", :go, "east"
|
32
|
+
Syntax.new nil, "u", :go, "up"
|
33
|
+
Syntax.new nil, "d", :go, "down"
|
34
|
+
Syntax.new nil, "nw", :go, "northwest"
|
35
|
+
Syntax.new nil, "ne", :go, "northeast"
|
36
|
+
Syntax.new nil, "sw", :go, "southwest"
|
37
|
+
Syntax.new nil, "se", :go, "southeast"
|
38
|
+
|
39
|
+
end
|
data/lib/gamefic/base.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
class Character < Entity
|
4
|
+
attr_reader :state, :queue, :user
|
5
|
+
def post_initialize
|
6
|
+
@state = CharacterState.new(self)
|
7
|
+
@queue = Array.new
|
8
|
+
end
|
9
|
+
def connect(user)
|
10
|
+
@user = user
|
11
|
+
end
|
12
|
+
def disconnect
|
13
|
+
# TODO: We might need some cleanup here. Like, move the character out of the game, or set a timeout to allow dropped users to reconnect... figure it out.
|
14
|
+
@user = nil
|
15
|
+
end
|
16
|
+
def perform(command)
|
17
|
+
#if command != nil
|
18
|
+
# @queue.push command
|
19
|
+
#end
|
20
|
+
if state.busy? == false
|
21
|
+
Director.dispatch(self, command)
|
22
|
+
else
|
23
|
+
@queue.push command
|
24
|
+
end
|
25
|
+
end
|
26
|
+
#def inject(command)
|
27
|
+
# Director.dispatch(self, command)
|
28
|
+
#end
|
29
|
+
def tell(message, refresh = false)
|
30
|
+
if user != nil and message.to_s != ''
|
31
|
+
user.stream.send "#{message}\n"
|
32
|
+
if (refresh == true)
|
33
|
+
user.refresh
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
def state=(new_state)
|
38
|
+
@state = new_state
|
39
|
+
end
|
40
|
+
def destroy
|
41
|
+
if @user != nil
|
42
|
+
@user.quit
|
43
|
+
end
|
44
|
+
super
|
45
|
+
end
|
46
|
+
def update
|
47
|
+
super
|
48
|
+
@state.update
|
49
|
+
end
|
50
|
+
end
|
51
|
+
class CharacterState
|
52
|
+
def initialize(character)
|
53
|
+
@character = character
|
54
|
+
post_initialize
|
55
|
+
end
|
56
|
+
def post_initialize
|
57
|
+
# TODO: Required by subclasses?
|
58
|
+
end
|
59
|
+
def busy?
|
60
|
+
false
|
61
|
+
end
|
62
|
+
def update
|
63
|
+
while (line = @character.queue.shift)
|
64
|
+
@character.perform line
|
65
|
+
if @character.state != self
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Array
|
2
|
+
def that_are(cls)
|
3
|
+
if (cls.kind_of?(Class) or cls.kind_of?(Module))
|
4
|
+
return self.clone.delete_if { |i| i.kind_of?(cls) == false }
|
5
|
+
else
|
6
|
+
if self.include?(cls)
|
7
|
+
return [cls]
|
8
|
+
end
|
9
|
+
return Array.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def that_are_not(cls)
|
13
|
+
if (cls.kind_of?(Class) or cls.kind_of?(Module))
|
14
|
+
return self.clone.delete_if { |i| i.kind_of?(cls) == true }
|
15
|
+
else
|
16
|
+
return self.clone - [cls]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def random
|
20
|
+
return self[rand(self.length)]
|
21
|
+
end
|
22
|
+
def shuffle
|
23
|
+
self.sort { |a, b|
|
24
|
+
rand(3) <=> rand(3)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
def shuffle!
|
28
|
+
self.sort! { |a, b|
|
29
|
+
rand(3) <=> rand(3)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
def join_and(sep = ', ', andSep = ' and ', serial = true)
|
33
|
+
if self.length < 3
|
34
|
+
self.join(andSep)
|
35
|
+
else
|
36
|
+
start = self - [self.last]
|
37
|
+
start.join(sep) + "#{serial ? sep.strip : ''}#{andSep}#{self.last}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class String
|
2
|
+
def capitalize_first
|
3
|
+
"#{self[0,1].upcase}#{self[1,self.length]}"
|
4
|
+
end
|
5
|
+
def cap_first
|
6
|
+
self.capitalize_first
|
7
|
+
end
|
8
|
+
def specify
|
9
|
+
if self[0,2] == 'a ' or self[0,3] == 'an '
|
10
|
+
"the #{self.split(' ').shift.join(' ')}"
|
11
|
+
end
|
12
|
+
if self[0,2] == 'A ' or self[0,3] == 'An '
|
13
|
+
"The #{self.split(' ').shift.join(' ')}"
|
14
|
+
end
|
15
|
+
"#{self}"
|
16
|
+
end
|
17
|
+
def terminalize
|
18
|
+
output = ''
|
19
|
+
lines = self.split("\n")
|
20
|
+
lines.each { |line|
|
21
|
+
if line.size > 79
|
22
|
+
while (line.size > 79)
|
23
|
+
offset = line.rindex(/[\s\W]/, 79)
|
24
|
+
if (offset == 0 or offset == nil)
|
25
|
+
output = output + line + "\n"
|
26
|
+
line = ''
|
27
|
+
else
|
28
|
+
output = output + line[0,offset + 1] + "\n"
|
29
|
+
line = line[offset + 1, line.size - offset]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
output = output + line + "\n"
|
33
|
+
else
|
34
|
+
output = output + line + "\n"
|
35
|
+
end
|
36
|
+
}
|
37
|
+
return output.strip
|
38
|
+
end
|
39
|
+
def split_words
|
40
|
+
self.gsub(/ +/, ' ').strip.split
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "gamefic/keywords"
|
2
|
+
|
3
|
+
module Gamefic
|
4
|
+
|
5
|
+
module Describable
|
6
|
+
attr_accessor :name, :longname, :synonyms
|
7
|
+
def keywords
|
8
|
+
Keywords.new "#{name} #{longname} #{synonyms}"
|
9
|
+
end
|
10
|
+
def keywords=(value)
|
11
|
+
@keywords = value
|
12
|
+
end
|
13
|
+
def longname
|
14
|
+
@longname.to_s != '' ? @longname : name
|
15
|
+
end
|
16
|
+
def longname=(value)
|
17
|
+
@longname = value
|
18
|
+
end
|
19
|
+
def description
|
20
|
+
@description.to_s != '' ? @description : "Nothing special."
|
21
|
+
end
|
22
|
+
def description=(value)
|
23
|
+
@description = value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
class Director
|
4
|
+
def self.dispatch(actor, command)
|
5
|
+
command.strip!
|
6
|
+
handlers = Syntax.match(command, actor.plot.syntaxes)
|
7
|
+
options = Array.new
|
8
|
+
handlers.each { |handler|
|
9
|
+
actions = actor.plot.commands[handler.command]
|
10
|
+
if actions != nil
|
11
|
+
actions.each { |action|
|
12
|
+
orders = bind_contexts_in_result(actor, handler, action)
|
13
|
+
orders.each { |order|
|
14
|
+
args = Array.new
|
15
|
+
args.push actor
|
16
|
+
order.arguments.each { |a|
|
17
|
+
if a.length > 1
|
18
|
+
longnames = Array.new
|
19
|
+
a.each { |b|
|
20
|
+
longnames.push b.longname
|
21
|
+
}
|
22
|
+
actor.tell "I don't know which you mean: #{longnames.join(', ')}"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
args.push a[0]
|
26
|
+
}
|
27
|
+
options.push [order.action.proc, args]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
}
|
32
|
+
options.push([
|
33
|
+
Proc.new { |actor|
|
34
|
+
actor.tell "I don't know what you mean by '#{command}.'"
|
35
|
+
}, [actor], -1
|
36
|
+
])
|
37
|
+
del = Delegate.new(options)
|
38
|
+
del.execute
|
39
|
+
end
|
40
|
+
private
|
41
|
+
def self.bind_contexts_in_result(actor, handler, action)
|
42
|
+
objects = Array.new
|
43
|
+
valid = true
|
44
|
+
prepared = Array.new
|
45
|
+
arguments = handler.arguments.clone
|
46
|
+
action.queries.each { |context|
|
47
|
+
arg = arguments.shift
|
48
|
+
if arg == nil or arg == ''
|
49
|
+
valid = false
|
50
|
+
next
|
51
|
+
end
|
52
|
+
if context == String
|
53
|
+
prepared.push [arg]
|
54
|
+
elsif context.kind_of?(Query)
|
55
|
+
if context.kind_of?(Subquery)
|
56
|
+
last = prepared.last
|
57
|
+
if last == nil or last.length > 1
|
58
|
+
valid = false
|
59
|
+
next
|
60
|
+
end
|
61
|
+
result = context.execute(last[0], arg)
|
62
|
+
else
|
63
|
+
result = context.execute(actor, arg)
|
64
|
+
end
|
65
|
+
if result.objects.length == 0
|
66
|
+
valid = false
|
67
|
+
next
|
68
|
+
else
|
69
|
+
prepared.push result.objects
|
70
|
+
if result.remainder
|
71
|
+
arguments.push result.remainder
|
72
|
+
end
|
73
|
+
end
|
74
|
+
else
|
75
|
+
# TODO: Better message
|
76
|
+
raise "Invalid object"
|
77
|
+
end
|
78
|
+
}
|
79
|
+
if valid == true
|
80
|
+
prepared.each { |p|
|
81
|
+
p.uniq!
|
82
|
+
}
|
83
|
+
objects.push Order.new(action, prepared)
|
84
|
+
end
|
85
|
+
return objects
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Director
|
90
|
+
class Delegate
|
91
|
+
@@delegation_stack = Array.new
|
92
|
+
def initialize(options)
|
93
|
+
@options = options
|
94
|
+
end
|
95
|
+
def execute
|
96
|
+
@@delegation_stack.push @options
|
97
|
+
if @options.length > 0
|
98
|
+
opt = @options.shift
|
99
|
+
if opt[1].length == 1
|
100
|
+
opt[0].call(opt[1][0])
|
101
|
+
else
|
102
|
+
opt[0].call(opt[1])
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@@delegation_stack.pop
|
106
|
+
end
|
107
|
+
def self.passthru
|
108
|
+
if @@delegation_stack.last != nil
|
109
|
+
if @@delegation_stack.last.length > 0
|
110
|
+
opt = @@delegation_stack.last.shift
|
111
|
+
if opt[1].length == 1
|
112
|
+
opt[0].call(opt[1][0])
|
113
|
+
else
|
114
|
+
opt[0].call(opt[1])
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
class Order
|
121
|
+
attr_reader :action, :arguments
|
122
|
+
def initialize(action, arguments)
|
123
|
+
@action = action
|
124
|
+
@arguments = arguments
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.passthru
|
130
|
+
Director::Delegate.passthru
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gamefic
|
2
|
+
|
3
|
+
class Engine
|
4
|
+
def initialize(plot)
|
5
|
+
@plot = plot
|
6
|
+
end
|
7
|
+
def run
|
8
|
+
user = User.new @plot
|
9
|
+
@plot.introduce user.character
|
10
|
+
while true
|
11
|
+
user.stream.select
|
12
|
+
user.state.update
|
13
|
+
@plot.update
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "digest/md5"
|
2
|
+
require "gamefic/node"
|
3
|
+
require "gamefic/describable"
|
4
|
+
require "gamefic/plot"
|
5
|
+
|
6
|
+
module Gamefic
|
7
|
+
|
8
|
+
class Entity
|
9
|
+
include Branch
|
10
|
+
include Describable
|
11
|
+
attr_reader :session, :plot
|
12
|
+
def initialize(plot, args = {})
|
13
|
+
if (plot.kind_of?(Plot) == false)
|
14
|
+
raise "First argument must be a Plot"
|
15
|
+
end
|
16
|
+
pre_initialize
|
17
|
+
#self.state = State
|
18
|
+
#@story = Subplot.current
|
19
|
+
@plot = plot
|
20
|
+
@plot.send :add_entity, self
|
21
|
+
#@story.add_entity self
|
22
|
+
args.each { |key, value|
|
23
|
+
send "#{key}=", value
|
24
|
+
}
|
25
|
+
@update_procs = Array.new
|
26
|
+
@session = Hash.new
|
27
|
+
post_initialize
|
28
|
+
end
|
29
|
+
#def self.present(args = {})
|
30
|
+
# story = Plot.Loading
|
31
|
+
# if story == nil
|
32
|
+
# raise "No plot loading"
|
33
|
+
# end
|
34
|
+
# return self.new(story, args)
|
35
|
+
#end
|
36
|
+
def uid
|
37
|
+
if @uid == nil
|
38
|
+
@uid = Digest::MD5.hexdigest(self.object_id.to_s)[0,8]
|
39
|
+
end
|
40
|
+
@uid
|
41
|
+
end
|
42
|
+
def pre_initialize
|
43
|
+
# raise NotImplementedError, "#{self.class} must implement post_initialize"
|
44
|
+
end
|
45
|
+
def post_initialize
|
46
|
+
# raise NotImplementedError, "#{self.class} must implement post_initialize"
|
47
|
+
end
|
48
|
+
def tell(message, refresh = false)
|
49
|
+
#TODO: Should this even be here? In all likelihood, only Characters receive tells, right?
|
50
|
+
#TODO: On second thought, it might be interesting to see logs from an npc point of view.
|
51
|
+
end
|
52
|
+
def to_s
|
53
|
+
name
|
54
|
+
end
|
55
|
+
def update
|
56
|
+
@update_procs.each { |p|
|
57
|
+
p.call self
|
58
|
+
}
|
59
|
+
end
|
60
|
+
def on_update(&block)
|
61
|
+
@update_procs.push block
|
62
|
+
end
|
63
|
+
def parent=(node)
|
64
|
+
if node != nil and node.kind_of?(Entity) == false and node.kind_of?(Zone) == false
|
65
|
+
raise "Entity's parent must be an Entity or a Zone"
|
66
|
+
end
|
67
|
+
super
|
68
|
+
end
|
69
|
+
def destroy
|
70
|
+
self.parent = nil
|
71
|
+
# TODO: Need to call this private method here?
|
72
|
+
@plot.send(:rem_entity, self)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|