gamefic 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|