mirror of
https://gitlab.com/Oreolek/salet.git
synced 2024-07-07 01:04:25 +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:
parent
b0c0804b43
commit
828962b1ff
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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: () ->
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
20
lib/undum.js
20
lib/undum.js
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue