1
0
Fork 0
mirror of https://gitlab.com/Oreolek/salet.git synced 2024-07-04 07:45:03 +03:00

Documentation and API

Made enter() a redefinable function.
Updated Gulpfile to watch the libs.
Fixed a couple of bugs in Raconteur CoffeeScript port.
This commit is contained in:
Alexander Yakovlev 2016-01-15 15:10:12 +07:00
parent b0c0804b43
commit 828962b1ff
8 changed files with 142 additions and 41 deletions

View file

@ -86,6 +86,7 @@ gulp.task('serve', ['build'], () ->
gulp.watch(['./sass/*.scss'], ['sass']);
gulp.watch(['./img/*.png', './img/*.jpeg', './img/*.jpg'], ['img']);
gulp.watch(['./game/*.coffee'], ['coffee']);
gulp.watch(['./lib/*.coffee','./lib/*.js'], ['coffee']);
gulp.watch(['./build/css/main.css'], sassListener);
gulp.watch(

View file

@ -23,6 +23,15 @@ actlink = (content, ref) ->
textcycle = (content, ref) ->
return "<a href='./_replacer_#{ref}' class='cycle' id='#{ref}'>#{content}</a>"
###
This function clears the screen.
The full backlog makes sense in dialogues but it's clunky when you exploring.
So this is manual cls
###
cls = () ->
document.getElementById("intro").innerHTML = ""
document.getElementById("content").innerHTML = ""
# usage: writemd( system, "Text to write")
writemd = (system, text) ->
text = markdown(text)

View file

@ -1,19 +1,79 @@
# Your game goes here
dialogue "Option 1", "start", "secretary", """
No spoilers!
"""
dialogue "Yes", "start", "question2", """
Good, because you'll have to read the sources. A lot.
Salet is *not* a library or a framework you can slap something on.
It's more a game you can hack into your game.
(Like Undum, yeah.)
dialogue "Option 2", "start", "secretary", """
No spoilers!
"""
I hope to change that in the future but for now it's a weird mix of CoffeeScript classes and Undum core Javascript functions.
And Undum is notorious for making some hardcoded calls to how your game should *look and feel*.
The point of Salet is to have some freedom to change the user interface however you like.
But you'll have to code it first.
room "university-start",
tags: ["secretary"]
ways: ["supermarket"]
optionText: "Leave the University"
For example, notice the lack of "Character" section?
The qualities and tools?
The functionality is still there but you'll have to style it yourself if you want it.
So, that's the bad news. The good news are just a click ahead of you.
"""
dialogue "No", "start", "question2", """
Okay, this is going to be tough but you'll have to pick up *something* to use this.
Salet is *not* a library or a framework you can slap something on.
It's more a game you can hack into your game. (Like Undum, yeah.)
There is no cool editor or clear instructions.
You'll have to copy the source code and edit the CoffeeScript files in the `game` folder.
Then *compile* them.
So, that's the bad news. The good news are just a click ahead of you.
"""
dialogue "Dialogue functions", "question2", "world", """
Let's start with a relatively small feature: dialogues.
Undum's arguably not the best thing for menu-style dialogues because while it gives the author a great dialogue engine,
he has to write a lot of code for a single reply.
So I did a shortcut function.
This is Undum's implicit choice, which you can use in you dialogues or floating modules:
dialogue "Title", "start_tag", "end_tag", "content", "code"
where:
* `title` is a text the player clicks on,
* `start_tag` is a tag for *this* room (no `#` or arrays),
* `end_tag` is a tag for the choices in this room (no `#` or arrays)
* `code` is a piece of Javascript that gets executed once the player clicks on a choice.
You still need to write a Situation for each reply, sorry.
But now you can do it faster!
Okay, with this aside, let me show you... The World.
"""
room "world",
tags: ["world"],
optionText: "Enter the world",
before: () ->
cls()
ways: ["university"]
content: """
### Rhinestone Room
You're in a large room carved inside a giant milky rock mountain.
The floor and walls are littered with signs and signatures of the previous visitors.
A steep narrow #{textlink("well", "well")} proceeds upward.
"""
writers:
well: "There is only one passage out. See the „Other rooms“ block popped up? Click it."
room "university",
before: () ->
document.getElementById("intro").innerHTML = ""
document.getElementById("content").innerHTML = ""
undum.game.situations["supermarket"].destination()
"""
You leave the University.

View file

@ -23,7 +23,11 @@
<div id="content_wrapper" class="row">
<div id="intro" class="content">
<section>
<p>Intro here.</p>
<p><em>Salet</em> is an offspring of Undum and Raconteur.</p>
<p>The project is still a work-in-progress. This "game" will show you some of the new features.</p>
<p>It's supposed to be relatively painless for the author without sacrificing the reader's experience.
For example, the game still loads while you're reading this.</p>
<p>First of all, are you familiar with HTML and Coffeescript? As in, reading the real source code.</p>
<noscript>You need to turn on Javascript to play this game.</noscript>
</section>

View file

@ -19,6 +19,7 @@ dialogue = (title, startTag, endTag, text, effect) ->
retval = room(randomid(), {
optionText: title
content: text
clear: false # backlog is useful in dialogues
choices: "#"+endTag
})
if typeof(startTag) == "string"

View file

@ -36,6 +36,7 @@ update_ways = (ways) ->
content = ""
distances = []
if ways
document.querySelector(".ways h2").style.display = "block"
for way in ways
if undum.game.situations[way]?
title = undum.game.situations[way].name
@ -44,6 +45,8 @@ update_ways = (ways) ->
key: way
distance: undum.game.situations[way].distance
})
else
document.querySelector(".ways h2").style.display = "none"
document.getElementById("ways").innerHTML = content
min = Infinity
min_key = []
@ -64,16 +67,38 @@ class SaletRoom extends RaconteurSituation
@objects = spec.objects
if spec.exit?
@exit = spec.exit
if spec.enter?
@enter = spec.enter
if spec.clear?
@clear = spec.clear
if spec.writers?
@writers = spec.writers
return this
objects: []
distance: Infinity # distance to the destination
clear: true # clear the screen on entering the room?
###
I call SaletRoom.exit every time the player exits to another room.
Unlike @after this gets called after the section is closed.
It's a styling difference.
###
exit: (character, system, to) ->
return true
###
Undum calls Situation.enter every time a situation is entered, and
I call SaletRoom.enter every time the player enters this room but before the section is opened.
Unlike @before this gets called before the current section is opened.
It's a styling difference.
The upstream Undum version does not allow you to redefine @enter function easily but allows custom @exit one.
It was renamed as @entering to achieve API consistency.
###
enter: (character, system, from) ->
return true
###
Salet's Undum version calls Situation.entering every time a situation is entered, and
passes it three arguments; The character object, the system object,
and a string referencing the previous situation, or null if there is
none (ie, for the starting situation).
@ -81,11 +106,17 @@ class SaletRoom extends RaconteurSituation
My version of `enter` splits the location description from the effects.
Also if f == this.name (we're in the same location) the `before` and `after` callbacks are ignored.
###
enter: (character, system, f) ->
#system.clearContent()
entering: (character, system, f) ->
if @clear
system.clearContent()
if f != @name and f?
@visited++
undum.game.situations[f].exit(character, system, @name)
if undum.game.situations[f].exit?
undum.game.situations[f].exit(character, system, @name)
if @enter
@enter character, system, f
if not @extendSection
classes = if @classes then ' ' + @classes.join(' ') else ''
@ -95,13 +126,17 @@ class SaletRoom extends RaconteurSituation
system.write("<section id='current-situation' data-situation='#{@name}' class='situation-#{@name}#{classes}'>")
if f != @name and @before?
print(@before.fcall(this, character, system, f))
content = @before.fcall(this, character, system, f)
if content
print(content)
if @look
@look character, system, f
if f != @name and @after?
print(@after.fcall(this, character, system, f))
content = @after.fcall(this, character, system, f)
if content
print(content)
if not @extendSection
system.write("</section>")
@ -124,10 +159,6 @@ class SaletRoom extends RaconteurSituation
You could interpret this as an EXAMINE verb or USE one, it's your call.
###
act: (character, system, action) ->
# default Raconteur action
if (action.match(/^_(writer|replacer|inserter)_.+$/))
return RaconteurSituation.prototype.act.call(this, character, system, f)
if (link = action.match(/^_act_(.+)$/)) #object action
for thing in @objects
if thing.name == link[1]
@ -142,6 +173,9 @@ class SaletRoom extends RaconteurSituation
return print(thing.act.fcall(thing, character, system))
# the loop is done but no return came - match not found
console.error("Could not find #{link[1]} in current room.")
# default Raconteur action
return RaconteurSituation.prototype.act.call(this, character, system, action)
# Marks every room in the game with distance to this room
destination: () ->

View file

@ -29,7 +29,7 @@ String.prototype.fcall = () -> return this
#Adds the "fade" class to a htmlString.
String.prototype.fade = () ->
return this.classList.add("fade")
return '<div class="fade">'+this+'</div>'
###
The prototype RaconteurSituation is the basic spec for situations
@ -66,15 +66,15 @@ RaconteurSituation.prototype.act = (character, system, action) ->
responses = {
writer: (ref) ->
content = @writers[ref].fcall(that, character, system, action)
content = that.writers[ref].fcall(that, character, system, action)
output = markdown(content).fade()
system.writeInto(output, '#current-situation')
replacer: (ref) ->
content = @writers[ref].fcall(that, character, system, action)
content = that.writers[ref].fcall(that, character, system, action)
output = markdown(content).fade()
system.replaceWith(output, '#'+ref)
inserter: (ref) ->
content = @writers[ref].fcall(that, character, system, action)
content = that.writers[ref].fcall(that, character, system, action)
output = markdown(content).fade()
system.writeInto(output, '#'+ref)
}

View file

@ -151,9 +151,8 @@ var assert = function(expression, message) {
var Situation = function(opts) {
if (opts) {
if (opts.enter) this._enter = opts.enter;
if (opts.entering) this._enter = opts.entering;
if (opts.act) this._act = opts.act;
if (opts.exit) this._exit = opts.exit;
// Options related to this situation being automatically
// selected and displayed in a list of options.
@ -194,19 +193,14 @@ var Situation = function(opts) {
* may be null if this is the starting situation. Unlike the
* exit() method, this method cannot prevent the transition
* happening: its return value is ignored. */
Situation.prototype.enter = function(character, system, from) {
if (this._enter) this._enter(character, system, from);
Situation.prototype.entering = function(character, system, from) {
if (this._entering) this._entering(character, system, from);
};
/* A function that takes action when we carry out some action in a
* situation that isn't intended to lead to a new situation. */
Situation.prototype.act = function(character, system, action) {
if (this._act) this._act(character, system, action);
};
/* A function that takes action when we exit a situation. The last
* parameter indicates the situation we are going to. */
Situation.prototype.exit = function(character, system, to) {
if (this._exit) this._exit(character, system, to);
};
/* Determines whether this situation should be contained within a
* list of options generated automatically by the given
* situation. */
@ -300,7 +294,7 @@ var SimpleSituation = function(content, opts) {
this.maxChoices = opts && opts.maxChoices;
};
SimpleSituation.inherits(Situation);
SimpleSituation.prototype.enter = function(character, system, from) {
SimpleSituation.prototype.entering = function(character, system, from) {
if (this.heading) {
if ($.isFunction(this.heading)) {
system.writeHeading(this.heading());
@ -308,7 +302,7 @@ SimpleSituation.prototype.enter = function(character, system, from) {
system.writeHeading(this.heading);
}
}
if (this._enter) this._enter(character, system, from);
if (this._entering) this._entering(character, system, from);
if (this.content) {
if ($.isFunction(this.content)) {
system.write(this.content());
@ -1454,8 +1448,6 @@ var doTransitionTo = function(newSituationId) {
// We might not have an old situation if this is the start of
// the game.
if (oldSituation) {
// Notify the exiting situation.
oldSituation.exit(character, system, newSituationId);
if (game.exit) {
game.exit(character, system, oldSituationId, newSituationId);
}
@ -1489,7 +1481,7 @@ var doTransitionTo = function(newSituationId) {
if (game.enter) {
game.enter(character, system, oldSituationId, newSituationId);
}
newSituation.enter(character, system, oldSituationId);
newSituation.entering(character, system, oldSituationId);
// additional hook for when the situation text has already been printed
if (game.afterEnter) {