gamefic-sdk 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/html/core/engine.js +16 -61
- data/html/sinatra/engine.js +51 -0
- data/html/skins/standard/index.html.erb +1 -1
- data/html/skins/standard/play.js +20 -4
- data/html/skins/standard/style.css +3 -0
- data/lib/gamefic-sdk.rb +2 -2
- data/lib/gamefic-sdk/debug/plot.rb +1 -1
- data/lib/gamefic-sdk/platform.rb +1 -0
- data/lib/gamefic-sdk/platform/sinatra.rb +100 -0
- data/lib/gamefic-sdk/platform/web.rb +19 -12
- data/lib/gamefic-sdk/platform/web/app_config.rb +5 -6
- data/lib/gamefic-sdk/platform/web/engine.rb +41 -0
- data/lib/gamefic-sdk/platform/web/user.rb +19 -0
- data/lib/gamefic-sdk/server.rb +67 -0
- data/lib/gamefic-sdk/shell.rb +50 -10
- data/lib/gamefic-sdk/shell/init.rb +7 -2
- data/lib/gamefic-sdk/version.rb +1 -1
- data/scripts/autosuggest.plot.rb +5 -11
- data/scripts/clothing/actions/wear.plot.rb +1 -1
- data/scripts/clothing/entities/clothing.plot.rb +1 -1
- data/scripts/clothing/entities/coat.plot.rb +1 -1
- data/scripts/clothing/entities/gloves.plot.rb +1 -1
- data/scripts/clothing/entities/hat.plot.rb +1 -1
- data/scripts/clothing/entities/pants.plot.rb +1 -1
- data/scripts/clothing/entities/shirt.plot.rb +1 -1
- data/scripts/clothing/entities/shoes.plot.rb +1 -1
- data/scripts/save-restore.plot.rb +1 -0
- data/scripts/snapshots.plot.rb +1 -1
- data/scripts/standard.plot.rb +1 -1
- data/scripts/standard/actions/close.plot.rb +2 -2
- data/scripts/standard/actions/drop.plot.rb +6 -2
- data/scripts/standard/actions/give.plot.rb +12 -17
- data/scripts/standard/actions/go.plot.rb +7 -6
- data/scripts/standard/actions/lock.plot.rb +3 -3
- data/scripts/standard/actions/look-under.plot.rb +1 -1
- data/scripts/standard/actions/look.plot.rb +13 -8
- data/scripts/standard/actions/nil.plot.rb +1 -1
- data/scripts/standard/actions/place.plot.rb +2 -1
- data/scripts/standard/actions/read.plot.rb +1 -1
- data/scripts/standard/actions/search.plot.rb +1 -0
- data/scripts/standard/actions/take.plot.rb +1 -1
- data/scripts/standard/actions/talk.plot.rb +4 -4
- data/scripts/standard/actions/unlock.plot.rb +6 -6
- data/scripts/standard/actions/use.plot.rb +4 -4
- data/scripts/standard/entities/character.plot.rb +0 -2
- data/scripts/standard/entities/container.plot.rb +1 -4
- data/scripts/standard/entities/door.plot.rb +1 -3
- data/scripts/standard/entities/entity.plot.rb +0 -1
- data/scripts/standard/entities/exterior.plot.rb +1 -1
- data/scripts/standard/entities/fixture.plot.rb +1 -1
- data/scripts/standard/entities/item.plot.rb +1 -1
- data/scripts/standard/entities/portal.plot.rb +2 -3
- data/scripts/standard/entities/receptacle.plot.rb +1 -2
- data/scripts/standard/entities/room.plot.rb +4 -6
- data/scripts/standard/entities/rubble.plot.rb +1 -1
- data/scripts/standard/entities/scenery.plot.rb +1 -1
- data/scripts/standard/entities/supporter.plot.rb +2 -2
- data/scripts/standard/modules/attachable.plot.rb +1 -1
- data/scripts/standard/modules/auto_takes.plot.rb +1 -1
- data/scripts/standard/modules/darkenable.plot.rb +1 -1
- data/scripts/standard/modules/enterable.plot.rb +1 -1
- data/scripts/standard/modules/explicit_exits.plot.rb +1 -1
- data/scripts/standard/modules/itemizable.plot.rb +1 -1
- data/scripts/standard/modules/lockable.plot.rb +1 -1
- data/scripts/standard/modules/openable.plot.rb +4 -1
- data/scripts/standard/modules/parent-room.plot.rb +1 -1
- data/scripts/standard/modules/portable.plot.rb +1 -1
- data/scripts/standard/modules/transparent.plot.rb +1 -1
- data/scripts/standard/plural/actions/place.plot.rb +2 -2
- data/scripts/standard/queries.plot.rb +21 -4
- data/scripts/standard/use.plot.rb +26 -8
- data/scripts/suggestible.plot.rb +17 -17
- metadata +58 -10
- data/lib/gamefic-sdk/platform/web/gamefic_opal.rb +0 -45
- data/scripts/standard/queries/from_expression.plot.rb +0 -16
- data/scripts/standard/queries/reachable.plot.rb +0 -48
- data/scripts/standard/queries/room.plot.rb +0 -17
- data/scripts/standard/queries/visible.plot.rb +0 -45
@@ -0,0 +1,41 @@
|
|
1
|
+
# @hack Explicit requires for Opal
|
2
|
+
require 'gamefic/plot/playbook'
|
3
|
+
require 'gamefic/grammar'
|
4
|
+
require 'gamefic/query'
|
5
|
+
require 'gamefic/grammar/verb_set'
|
6
|
+
require 'gamefic/grammar/conjugator'
|
7
|
+
|
8
|
+
module Gamefic
|
9
|
+
module Engine
|
10
|
+
class Web < Gamefic::Engine::Base
|
11
|
+
def post_initialize
|
12
|
+
self.user_class = Gamefic::User::Web
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
connect
|
17
|
+
@plot.introduce @character
|
18
|
+
@plot.ready
|
19
|
+
@user.update @character.state
|
20
|
+
end
|
21
|
+
|
22
|
+
def turn
|
23
|
+
@plot.ready
|
24
|
+
@user.update @character.state
|
25
|
+
update unless @character.queue.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def receive input
|
29
|
+
@character.queue.push input unless input.nil?
|
30
|
+
update
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def update
|
36
|
+
@plot.update
|
37
|
+
turn
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Gamefic
|
2
|
+
module User
|
3
|
+
class Web < Gamefic::User::Base
|
4
|
+
def update state
|
5
|
+
`Gamefic.update(#{state.to_json});`
|
6
|
+
end
|
7
|
+
|
8
|
+
def save filename, data
|
9
|
+
data[:metadata] = GameficOpal.static_plot.metadata
|
10
|
+
`Gamefic.save(filename, data);`
|
11
|
+
end
|
12
|
+
|
13
|
+
def restore filename
|
14
|
+
data = `Gamefic.restore(filename);`
|
15
|
+
return data
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module Gamefic
|
5
|
+
module Sdk
|
6
|
+
|
7
|
+
class Server < Sinatra::Base
|
8
|
+
set :port, 4342
|
9
|
+
|
10
|
+
get '/' do
|
11
|
+
paths = config_path(settings.source_dir).script_paths + [Gamefic::Sdk::GLOBAL_SCRIPT_PATH]
|
12
|
+
config = YAML.load(File.read(File.join(settings.source_dir, 'config.yaml')))
|
13
|
+
config['name'] = 'sinatra'
|
14
|
+
@@plot = Gamefic::Sdk::Debug::Plot.new Source::File.new(*paths)
|
15
|
+
@@plot.script 'main'
|
16
|
+
@@plot.script 'debug'
|
17
|
+
sinatra = Gamefic::Sdk::Platform::Sinatra.new(settings.source_dir, config)
|
18
|
+
sinatra.build
|
19
|
+
File.read File.join(sinatra.config['target_dir'], 'index.html')
|
20
|
+
end
|
21
|
+
|
22
|
+
post '/start' do
|
23
|
+
content_type :json
|
24
|
+
@@character = Character.new(name: 'player', synonyms: 'me myself self you yourself', description: 'As good-looking as ever.')
|
25
|
+
@@character.connect User::Base.new
|
26
|
+
@@plot.introduce @@character
|
27
|
+
@@plot.ready
|
28
|
+
@@character.state.to_json
|
29
|
+
end
|
30
|
+
|
31
|
+
post '/update' do
|
32
|
+
content_type :json
|
33
|
+
@@character.queue.push params['command']
|
34
|
+
@@plot.update
|
35
|
+
@@plot.ready
|
36
|
+
@@character.state.merge(input: params['command']).to_json
|
37
|
+
end
|
38
|
+
|
39
|
+
class << self
|
40
|
+
|
41
|
+
def run!
|
42
|
+
start_browser if settings.browser
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def start_browser
|
47
|
+
Thread.new {
|
48
|
+
sleep 1 until Server.running?
|
49
|
+
`start http://localhost:#{settings.port}`
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def config_path dir
|
58
|
+
if File.directory?(dir)
|
59
|
+
PlotConfig.new File.join(dir, 'config.yaml')
|
60
|
+
else
|
61
|
+
PlotConfig.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
data/lib/gamefic-sdk/shell.rb
CHANGED
@@ -21,30 +21,70 @@ module Gamefic
|
|
21
21
|
option :standard, type: :boolean, default: true, desc: 'Include the standard script'
|
22
22
|
option :scripts, type: :array, aliases: [:s, :script], desc: 'Additional scripts'
|
23
23
|
option :webskin, default: 'standard', aliases: [:w], desc: 'Skin to use for the Web platform'
|
24
|
+
option :webdir, aliases: [:d], desc: 'HTML directory to copy. This option overrides the webskin.'
|
24
25
|
option :title, type: :string, aliases: [:t], desc: "The game's title"
|
25
26
|
option :author, type: :string, aliases: [:a], desc: "The game's author"
|
26
27
|
def init(directory_name)
|
27
|
-
Gamefic::Sdk::Shell::Init.new(
|
28
|
-
quiet: options[:quiet], scripts: options[:scripts],
|
29
|
-
title: options[:title], author: options[:author]
|
28
|
+
Gamefic::Sdk::Shell::Init.new(
|
29
|
+
directory: directory_name, quiet: options[:quiet], scripts: options[:scripts],
|
30
|
+
webskin: options[:webskin], title: options[:title], author: options[:author],
|
31
|
+
webdir: options[:webdir]
|
32
|
+
).run
|
30
33
|
end
|
31
34
|
|
32
|
-
desc 'test DIRECTORY_NAME', 'Play the game in DIRECTORY_NAME'
|
33
|
-
def test(directory_name)
|
35
|
+
desc 'test [DIRECTORY_NAME]', 'Play the game in DIRECTORY_NAME'
|
36
|
+
def test(directory_name = '.')
|
34
37
|
Gamefic::Sdk::Shell::Test.new(directory: directory_name).run
|
35
38
|
end
|
36
39
|
|
37
|
-
desc '
|
40
|
+
desc 'server [DIRECTORY_NAME]', 'Run the game in DIRECTORY_NAME in a web server'
|
41
|
+
option :browser, type: :boolean, aliases: :b, desc: 'Open a browser when the server starts'
|
42
|
+
def server(directory_name = '.')
|
43
|
+
Gamefic::Sdk::Server.set :source_dir, directory_name
|
44
|
+
Gamefic::Sdk::Server.set :browser, options[:browser]
|
45
|
+
pub = File.join(directory_name, 'release', 'sinatra').gsub(/\\/, '/')
|
46
|
+
Gamefic::Sdk::Server.set :public_folder, pub
|
47
|
+
Gamefic::Sdk::Server.run!
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'build [DIRECTORY_NAME]', 'Build the game for specified platforms in DIRECTORY_NAME'
|
38
51
|
option :quiet, type: :boolean, aliases: :q, desc: 'Suppress output'
|
39
|
-
def build(directory_name)
|
52
|
+
def build(directory_name = '.')
|
40
53
|
Gamefic::Sdk::Build.release(directory_name, options[:quiet])
|
41
54
|
end
|
42
55
|
|
43
|
-
desc 'clean DIRECTORY_NAME', 'Perform cleanup of DIRECTORY_NAME'
|
44
|
-
def clean(directory_name)
|
56
|
+
desc 'clean [DIRECTORY_NAME]', 'Perform cleanup of DIRECTORY_NAME'
|
57
|
+
def clean(directory_name = '.')
|
45
58
|
Gamefic::Sdk::Build.clean(directory_name)
|
46
59
|
end
|
47
|
-
|
60
|
+
|
61
|
+
desc 'import-scripts [DIRECTORY_NAME]', 'Copy external scripts to the local scripts directory'
|
62
|
+
def import_scripts(directory_name = '.')
|
63
|
+
config_yaml = File.join(directory_name, 'config.yaml')
|
64
|
+
if File.exist?(config_yaml)
|
65
|
+
config_path = PlotConfig.new config_yaml
|
66
|
+
else
|
67
|
+
config_path = PlotConfig.new
|
68
|
+
end
|
69
|
+
FileUtils.mkdir_p(File.join(directory_name, 'scripts'))
|
70
|
+
paths = config_path.script_paths + [Gamefic::Sdk::GLOBAL_SCRIPT_PATH]
|
71
|
+
plot = Gamefic::Sdk::Debug::Plot.new Source::File.new(*paths)
|
72
|
+
plot.script 'main'
|
73
|
+
plot.imported_scripts.each { |s|
|
74
|
+
src = File.absolute_path(s.absolute_path)
|
75
|
+
dst = File.absolute_path(File.join(directory_name, 'scripts', "#{s.path}.plot.rb"))
|
76
|
+
next if src == dst
|
77
|
+
puts "Importing #{s.path}"
|
78
|
+
FileUtils.mkdir_p(File.dirname(dst))
|
79
|
+
FileUtils.cp_r(src, dst)
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
desc 'reset-package [DIRECTORY_NAME]', 'Reset package.yaml to the default values'
|
84
|
+
def reset_config(directory_name = '.')
|
85
|
+
|
86
|
+
end
|
87
|
+
|
48
88
|
desc 'webskins', 'List the available skins for the Web platform'
|
49
89
|
def webskins
|
50
90
|
Dir[File.join(Gamefic::Sdk::HTML_TEMPLATE_PATH, 'skins', '*')].sort.each { |d|
|
@@ -5,10 +5,11 @@ module Gamefic
|
|
5
5
|
module Sdk
|
6
6
|
class Shell
|
7
7
|
class Init
|
8
|
-
def initialize(directory:, standard: true, quiet: false, scripts: [], webskin: 'standard', title: nil, author: nil)
|
8
|
+
def initialize(directory:, standard: true, quiet: false, scripts: [], webskin: 'standard', webdir: nil, title: nil, author: nil)
|
9
9
|
@quiet = quiet
|
10
10
|
@directory = directory
|
11
11
|
@html = webskin
|
12
|
+
@webdir = webdir
|
12
13
|
@scripts = []
|
13
14
|
@scripts.push('standard') if standard
|
14
15
|
@scripts += scripts if scripts
|
@@ -86,7 +87,11 @@ module Gamefic
|
|
86
87
|
|
87
88
|
def copy_html_skin
|
88
89
|
Dir.mkdir("#{@directory}/html")
|
89
|
-
|
90
|
+
if @webdir.nil?
|
91
|
+
FileUtils.cp_r(Dir[Gamefic::Sdk::HTML_TEMPLATE_PATH + '/skins/' + @html + '/*'], "#{@directory}/html")
|
92
|
+
else
|
93
|
+
FileUtils.cp_r(Dir[File.join(File.realpath(@webdir), '*')], "#{@directory}/html")
|
94
|
+
end
|
90
95
|
end
|
91
96
|
end
|
92
97
|
end
|
data/lib/gamefic-sdk/version.rb
CHANGED
data/scripts/autosuggest.plot.rb
CHANGED
@@ -22,8 +22,11 @@ class Gamefic::Character
|
|
22
22
|
include Autosuggest
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
# Suggestions get updated (future suggestions become current) in
|
26
|
+
# on_player_ready. Autosuggest gathers suggestions in on_ready so it gets
|
27
|
+
# done first.
|
28
|
+
on_player_ready do |actor|
|
29
|
+
if (actor.scene == default_scene and actor.next_scene.nil?) or actor.next_scene == default_scene
|
27
30
|
actor.suggest "look around"
|
28
31
|
actor.suggest "inventory"
|
29
32
|
actor.room.children.that_are(Portal).each { |entity|
|
@@ -55,15 +58,6 @@ on_player_update do |actor|
|
|
55
58
|
if (actor.parent != actor.room)
|
56
59
|
actor.suggest "#{actor.parent.leave_verb} #{the actor.parent}"
|
57
60
|
end
|
58
|
-
actor.children.that_are_not(:attached?).each { |entity|
|
59
|
-
actor.suggest "drop #{the entity}"
|
60
|
-
Use.siblings.context_from(actor).that_are(Supporter).each { |supporter|
|
61
|
-
actor.suggest "put #{the entity} on #{the supporter}"
|
62
|
-
}
|
63
|
-
Use.siblings.context_from(actor).that_are(Receptacle).each { |receptacle|
|
64
|
-
actor.suggest "put #{the entity} in #{the receptacle}"
|
65
|
-
}
|
66
|
-
}
|
67
61
|
vicinity = actor.parent.children.that_are_not(Portal)
|
68
62
|
if actor.parent != actor.room
|
69
63
|
vicinity.concat actor.room.children.that_are_not(Portal)
|
data/scripts/snapshots.plot.rb
CHANGED
@@ -7,7 +7,7 @@ end
|
|
7
7
|
last_snapshot = nil
|
8
8
|
|
9
9
|
on_player_ready do |actor|
|
10
|
-
if (actor.
|
10
|
+
if (actor.last_action.nil? or !actor.last_action.meta?) and !last_snapshot.nil?
|
11
11
|
Snapshots.history.push last_snapshot
|
12
12
|
end
|
13
13
|
last_snapshot = save
|
data/scripts/standard.plot.rb
CHANGED
@@ -3,10 +3,10 @@
|
|
3
3
|
# interactive fiction. Designed to be suitable for parser-based text
|
4
4
|
# adventures, but easily extensible for other formats.
|
5
5
|
|
6
|
+
script 'standard/queries'
|
6
7
|
script 'standard/use'
|
7
8
|
script 'standard/modules'
|
8
9
|
script 'standard/direction'
|
9
10
|
script 'standard/entities'
|
10
|
-
script 'standard/queries'
|
11
11
|
script 'standard/actions'
|
12
12
|
script 'standard/pathfinder'
|
@@ -2,11 +2,11 @@ respond :close, Query::Text.new() do |actor, string|
|
|
2
2
|
actor.tell "#{you.pronoun.Subj} #{you.contract you.verb.do + ' not'} see any \"#{string}\" here."
|
3
3
|
end
|
4
4
|
|
5
|
-
respond :close,
|
5
|
+
respond :close, Use.reachable() do |actor, thing|
|
6
6
|
actor.tell "#{you.pronoun.Subj} #{you.contract you.verb.can + ' not'} close #{the thing}."
|
7
7
|
end
|
8
8
|
|
9
|
-
respond :close,
|
9
|
+
respond :close, Use.reachable(Openable) do |actor, container|
|
10
10
|
if !container.open?
|
11
11
|
actor.tell "It's already closed."
|
12
12
|
else
|
@@ -1,5 +1,9 @@
|
|
1
|
-
respond :drop,
|
2
|
-
|
1
|
+
respond :drop, Use.family() do |actor, thing|
|
2
|
+
if thing.parent != actor
|
3
|
+
actor.tell "#{you.contract you.pronoun.Subj + ' ' + you.verb.be} not carrying #{the thing}."
|
4
|
+
else
|
5
|
+
actor.proceed
|
6
|
+
end
|
3
7
|
end
|
4
8
|
|
5
9
|
respond :drop, Query::Children.new() do |actor, thing|
|
@@ -1,21 +1,8 @@
|
|
1
|
-
respond :give,
|
2
|
-
if gift.parent != actor
|
3
|
-
actor.perform :take, gift
|
4
|
-
end
|
5
|
-
if gift.parent == actor
|
6
|
-
actor.perform :give, character, gift
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
respond :give, Query::Reachable.new, Query::Children.new do |actor, character, gift|
|
1
|
+
respond :give, Use.available, Query::Children.new do |actor, character, gift|
|
11
2
|
actor.tell "Nothing happens."
|
12
3
|
end
|
13
4
|
|
14
|
-
respond :give,
|
15
|
-
actor.tell "#{you.pronoun.Subj} #{you.contract(you.verb.do + ' not')} have #{the gift}."
|
16
|
-
end
|
17
|
-
|
18
|
-
respond :give, Query::Reachable.new(Character), Query::Children.new do |actor, character, gift|
|
5
|
+
respond :give, Use.available(Character), Use.available do |actor, character, gift|
|
19
6
|
if gift.sticky?
|
20
7
|
actor.tell gift.sticky_message || "#{you.pronoun.Subj} #{you.verb.need} to keep #{the gift} for now."
|
21
8
|
else
|
@@ -23,8 +10,16 @@ respond :give, Query::Reachable.new(Character), Query::Children.new do |actor, c
|
|
23
10
|
end
|
24
11
|
end
|
25
12
|
|
26
|
-
respond :give,
|
13
|
+
respond :give, Use.available(Character), Use.available do |actor, character, gift|
|
14
|
+
if gift.parent == actor
|
15
|
+
actor.proceed
|
16
|
+
else
|
17
|
+
actor.tell "#{you.pronoun.Subj} #{you.contract(you.verb.do + ' not')} have #{the gift}."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
respond :give, Use.text, Use.available do |actor, character, gift|
|
27
22
|
actor.tell "#{you.pronoun.Subj} #{you.contract(you.verb.do + ' not')} see any \"#{character}\" here."
|
28
23
|
end
|
29
24
|
|
30
|
-
|
25
|
+
interpret "give :gift to :character", "give :character :gift"
|