mirror of
https://gitlab.com/Oreolek/salet.git
synced 2024-05-17 08:28:28 +03:00
Object manipulation - WIP
I'm stuck because of a COFFEESCRIPT bug or whatever.
This commit is contained in:
parent
8ad06c0d0a
commit
0ed4f98098
|
@ -51,21 +51,21 @@ opts = _.assign({}, watchify.args, {
|
|||
debug: true
|
||||
transform: [coffeify]
|
||||
});
|
||||
bundler = watchify(browserify(opts));
|
||||
bundler = watchify(browserify(opts))
|
||||
|
||||
bundle = () ->
|
||||
return bundler.bundle()
|
||||
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
|
||||
.pipe(source('bundle.js'))
|
||||
.pipe(gulp.dest('./build/game'));
|
||||
.pipe(gulp.dest('./build/game'))
|
||||
|
||||
gulp.task('concatCoffee', () ->
|
||||
return gulp.src(sources)
|
||||
.pipe(concat('./main.coffee'))
|
||||
.pipe(gulp.dest('./build/game'));
|
||||
);
|
||||
.pipe(gulp.dest('./build/game'))
|
||||
)
|
||||
|
||||
gulp.task('coffee', ['concatCoffee'], bundle);
|
||||
gulp.task('coffee', ['concatCoffee'], bundle)
|
||||
|
||||
bundler.on('update', bundle);
|
||||
bundler.on('log', gutil.log);
|
||||
|
@ -77,21 +77,20 @@ gulp.task('serve', ['build'], () ->
|
|||
server: {
|
||||
baseDir: 'build'
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
sassListener = () ->
|
||||
reload('./build/css/main.css');
|
||||
reload('./build/css/main.css')
|
||||
|
||||
gulp.watch(['./html/*.html'], ['html']);
|
||||
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(['./html/*.html'], ['html'])
|
||||
gulp.watch(['./sass/*.scss'], ['sass'])
|
||||
gulp.watch(['./img/*.png', './img/*.jpeg', './img/*.jpg'], ['img'])
|
||||
gulp.watch(['./lib/*.coffee', './lib/*.js', './game/*.coffee'], ['coffee'])
|
||||
|
||||
gulp.watch(['./build/css/main.css'], sassListener);
|
||||
gulp.watch(['./build/css/main.css'], sassListener)
|
||||
gulp.watch(
|
||||
['./build/game/bundle.js', './build/img/*', './build/index.html'],
|
||||
browserSync.reload);
|
||||
browserSync.reload)
|
||||
)
|
||||
|
||||
gulp.task('html-dist', html('./dist'));
|
||||
|
|
|
@ -42,6 +42,9 @@ writemd = (system, text) ->
|
|||
text = markdown(text)
|
||||
system.write(text)
|
||||
|
||||
get_room = (name) ->
|
||||
return undum.game.situations[name]
|
||||
|
||||
# The first room of the game.
|
||||
# For accessibility reasons the text is provided in HTML, not here.
|
||||
room "start",
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
# All code in this file comes last, so the game is almost ready by this point.
|
||||
|
||||
undum.game.init = (character, system) ->
|
||||
bugg.put("lair")
|
||||
|
||||
window.onload = undum.begin
|
||||
|
|
|
@ -2,6 +2,8 @@ room "world",
|
|||
tags: ["start"],
|
||||
optionText: "Enter the world",
|
||||
ways: ["plaza"]
|
||||
enter: () ->
|
||||
bugg.put(@name)
|
||||
content: """
|
||||
### Rhinestone Room
|
||||
|
||||
|
@ -40,7 +42,7 @@ room "plaza",
|
|||
if character.sandbox.has_mark?
|
||||
return "You already talked to him, no need to bug the man twice."
|
||||
character.sandbox.has_mark ?= true
|
||||
undum.game.situations["lair"].destination()
|
||||
get_room("lair").destination()
|
||||
"""
|
||||
“Here, let me mark it on your map.”
|
||||
"""
|
||||
|
@ -48,7 +50,7 @@ room "plaza",
|
|||
|
||||
room "shop",
|
||||
title: "The Shop"
|
||||
ways: ["plaza", "lair"]
|
||||
ways: ["plaza", "shop-inside", "lair"]
|
||||
content: """
|
||||
Being the only shop in town, this trendy establishment did not need a name.
|
||||
It's an open question why it had one, especially because its name was "Hung Crossing".
|
||||
|
@ -57,8 +59,8 @@ room "shop",
|
|||
"""
|
||||
|
||||
room "lair",
|
||||
ways: ["shop"]
|
||||
title: "The Lair"
|
||||
before: "Seems like you can't leave this just like that."
|
||||
content: """
|
||||
The Lair of Yog-Sothoth is a very *n'gai* cave, full of *buggs-shoggogs* and *n'ghaa ng'aa*.
|
||||
"""
|
||||
|
@ -68,7 +70,6 @@ bugg = obj "bugg-shoggog",
|
|||
act: () ->
|
||||
this.delete()
|
||||
return "You eat the bugg mass. Delicious and raw."
|
||||
bugg.put("lair")
|
||||
|
||||
room "shop-inside",
|
||||
ways: ["shop"]
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
<p>There are no either cool editor or clear instructions.
|
||||
You'll have to copy the source code and edit the CoffeeScript files in the <code>game</code> folder.
|
||||
Then <em>compile</em> them.</p>
|
||||
<p>This is not a technical documentation or UI tutorial, this is a <em>game.</em>
|
||||
<p>This is neither a technical documentation nor UI tutorial, this is a <em>game.</em>
|
||||
You're supposed to note all the cool and curious features yourself.
|
||||
If you want some technical info, there is the <a href="http://git.oreolek.ru/oreolek/salet">source code</a> and a <a href="http://git.oreolek.ru/oreolek/salet/wikis/home">wiki.</a></p>
|
||||
If you want some technical info, there are the <a href="http://git.oreolek.ru/oreolek/salet">source code</a> and a <a href="http://git.oreolek.ru/oreolek/salet/wikis/home">wiki.</a></p>
|
||||
<p>I'm just here to point out that you are playing this in the web browser, online.
|
||||
And you don't need to learn <em>The Complete Javascript, Volumes I-III</em> to write in this style.</p>
|
||||
<p>So let me show you... The World.</p>
|
||||
|
|
|
@ -5,35 +5,42 @@ objlink = (content, ref) ->
|
|||
|
||||
Array::remove = (e) -> @[t..t] = [] if (t = @indexOf(e)) > -1
|
||||
|
||||
class RaconteurObj
|
||||
parsedsc = (text, name) ->
|
||||
window.objname = name
|
||||
text = text.replace /([\s^])\{\{(.+)\}\}([\s$])/g, (str, p1, p2, p3) ->
|
||||
name = window.objname
|
||||
window.objname = undefined
|
||||
return p1+objlink(p2, name)+p3
|
||||
return text
|
||||
|
||||
# An object class.
|
||||
# An object cannot be in several locations at once, you must clone the variable.
|
||||
class SaletObj
|
||||
constructor: (spec) ->
|
||||
for key, value of spec
|
||||
this[key] ?= value
|
||||
level: 0
|
||||
look: (character, system, f) ->
|
||||
look: (character, system, f) =>
|
||||
if @dsc
|
||||
text = markdown(@dsc.fcall(this, character, system, f))
|
||||
text = "<span class='look lvl#{@level}'>" + text + "</span>"
|
||||
window.name = @name
|
||||
text = text.replace /([\s^])\{\{(\w+)\}\}([\s$])/g, (str, p1, p2, p3) ->
|
||||
name = window.name
|
||||
window.name = undefined
|
||||
return p1+objlink(p2, name)+p3
|
||||
return text
|
||||
take: () -> "You take the #{@name}." # taking to inventory
|
||||
act: () -> "You don't find anything extraordinary about the #{@name}." # object action
|
||||
dsc: () -> "You see a {{#{@name}}} here." # object description
|
||||
inv: () -> "It's a {{#{@name}.}}" # inventory description
|
||||
# replace braces {{}} with link to _act_
|
||||
return parsedsc(text, @name)
|
||||
take: (character, system) => "You take the #{@name}." # taking to inventory
|
||||
act: (character, system) => "You don't find anything extraordinary about the #{@name}." # object action
|
||||
dsc: (character, system) => "You see a {{#{@name}}} here." # object description
|
||||
inv: (character, system) => "It's a {{#{@name}.}}" # inventory description
|
||||
location: ""
|
||||
put: (location) ->
|
||||
put: (location) =>
|
||||
@level = 0 # this is scenery
|
||||
undum.game.situations[location].objects[@name] = this
|
||||
@location = location
|
||||
delete: () ->
|
||||
if undum.game.situations[location]?
|
||||
undum.game.situations[location].take(this)
|
||||
@location = location
|
||||
delete: () =>
|
||||
undum.game.situations[@location].objects.remove(this)
|
||||
|
||||
obj = (name, spec) ->
|
||||
spec ?= {}
|
||||
spec.name = name
|
||||
return new RaconteurObj(spec)
|
||||
return new SaletObj(spec)
|
||||
module.exports = obj
|
||||
|
|
|
@ -31,6 +31,10 @@ addClass = (element, className) ->
|
|||
here = () ->
|
||||
return undum.game.situations[document.getElementById("current-situation").getAttribute("data-situation")]
|
||||
|
||||
cls = (system) ->
|
||||
system.clearContent()
|
||||
system.clearContent("#intro")
|
||||
|
||||
update_ways = (ways, name) ->
|
||||
content = ""
|
||||
distances = []
|
||||
|
@ -62,23 +66,11 @@ update_ways = (ways, name) ->
|
|||
class SaletRoom extends RaconteurSituation
|
||||
constructor: (spec) ->
|
||||
RaconteurSituation.call(this, spec)
|
||||
if spec.objects?
|
||||
@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
|
||||
if spec.extendSection?
|
||||
@extendSection = spec.extendSection
|
||||
if spec.title?
|
||||
@title = spec.title
|
||||
for index, value of spec
|
||||
this[index] = value
|
||||
return this
|
||||
title: "Room"
|
||||
objects: []
|
||||
objects: {}
|
||||
extendSection: false
|
||||
distance: Infinity # distance to the destination
|
||||
clear: true # clear the screen on entering the room?
|
||||
|
@ -88,7 +80,7 @@ class SaletRoom extends RaconteurSituation
|
|||
Unlike @after this gets called after the section is closed.
|
||||
It's a styling difference.
|
||||
###
|
||||
exit: (character, system, to) ->
|
||||
exit: (character, system, to) =>
|
||||
return true
|
||||
|
||||
###
|
||||
|
@ -99,7 +91,7 @@ class SaletRoom extends RaconteurSituation
|
|||
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) ->
|
||||
enter: (character, system, from) =>
|
||||
return true
|
||||
|
||||
###
|
||||
|
@ -111,10 +103,9 @@ 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.
|
||||
###
|
||||
entering: (character, system, f) ->
|
||||
entering: (character, system, f) =>
|
||||
if @clear and f?
|
||||
system.clearContent()
|
||||
system.clearContent("#intro")
|
||||
cls(system)
|
||||
|
||||
if f != @name and f?
|
||||
@visited++
|
||||
|
@ -138,8 +129,7 @@ class SaletRoom extends RaconteurSituation
|
|||
if f != @name and @before?
|
||||
current_situation += markdown(@before.fcall(this, character, system, f))
|
||||
|
||||
if @look
|
||||
current_situation += @look character, system, f
|
||||
current_situation += @look character, system, f
|
||||
|
||||
if f != @name and @after?
|
||||
current_situation += markdown(@after.fcall(this, character, system, f))
|
||||
|
@ -152,7 +142,11 @@ class SaletRoom extends RaconteurSituation
|
|||
if @choices
|
||||
system.writeChoices(system.getSituationIdChoices(@choices, @minChoices, @maxChoices))
|
||||
|
||||
look: (character, system, f) ->
|
||||
###
|
||||
An internal function to get the room's description and the descriptions of
|
||||
every object in this room.
|
||||
###
|
||||
look: (character, system, f) =>
|
||||
update_ways(@ways, @name)
|
||||
retval = ""
|
||||
|
||||
|
@ -160,25 +154,37 @@ class SaletRoom extends RaconteurSituation
|
|||
if @content
|
||||
retval += markdown(@content.fcall(this, character, system, f))
|
||||
|
||||
if @objects? then for thing in @objects
|
||||
console.log @objects
|
||||
for name, thing of @objects
|
||||
retval += thing.look()
|
||||
|
||||
return retval
|
||||
|
||||
###
|
||||
Puts an object in this room.
|
||||
###
|
||||
take: (thing) =>
|
||||
@objects[thing.name] = thing
|
||||
# BUG: for some really weird reason if the call is made in init function or
|
||||
# during the initialization, this ALSO puts the thing in the start room.
|
||||
undum.game.situations["start"].objects = {}
|
||||
|
||||
###
|
||||
Object action. A function or a string which comes when you click on the object link.
|
||||
You could interpret this as an EXAMINE verb or USE one, it's your call.
|
||||
###
|
||||
act: (character, system, action) ->
|
||||
act: (character, system, action) =>
|
||||
if (link = action.match(/^_act_(.+)$/)) #object action
|
||||
for thing in @objects
|
||||
if thing.name == link[1]
|
||||
for name, thing of @objects
|
||||
if name == link[1]
|
||||
# We check the "take" function. If it exists, the player can take this object.
|
||||
# If not, we check the "act" function.
|
||||
if thing.take
|
||||
@objects.remove(thing)
|
||||
character.sandbox.inventory.push thing
|
||||
@enter(character, system, @name)
|
||||
delete @objects[name]
|
||||
console.log @objects
|
||||
cls(system)
|
||||
@entering.fcall(this, character, system, @name)
|
||||
return print(thing.take.fcall(thing, character, system))
|
||||
if thing.act
|
||||
return print(thing.act.fcall(thing, character, system))
|
||||
|
@ -189,7 +195,7 @@ class SaletRoom extends RaconteurSituation
|
|||
return RaconteurSituation.prototype.act.call(this, character, system, action)
|
||||
|
||||
# Marks every room in the game with distance to this room
|
||||
destination: () ->
|
||||
destination: () =>
|
||||
@distance = 0
|
||||
|
||||
candidates = [this]
|
||||
|
@ -202,9 +208,9 @@ class SaletRoom extends RaconteurSituation
|
|||
candidates.push(node)
|
||||
|
||||
room = (name, spec) ->
|
||||
if spec
|
||||
spec.name = name
|
||||
retval = new SaletRoom(spec)
|
||||
return retval.register()
|
||||
spec ?= {}
|
||||
spec.name = name
|
||||
retval = new SaletRoom(spec)
|
||||
return retval.register()
|
||||
|
||||
module.exports = room
|
||||
|
|
|
@ -17,16 +17,6 @@ all copies or substantial portions of the Software.
|
|||
undum = require('./undum.js')
|
||||
markdown = require('./markdown.coffee')
|
||||
|
||||
###
|
||||
fcall() (by analogy with fmap) is added to the prototypes of both String and
|
||||
Function. When called on a Function, it's an
|
||||
alias for Function#call(); when called on a String, it only returns the
|
||||
string itself, discarding any input.
|
||||
###
|
||||
|
||||
Function.prototype.fcall = Function.prototype.call;
|
||||
String.prototype.fcall = () -> return this
|
||||
|
||||
###
|
||||
The prototype RaconteurSituation is the basic spec for situations
|
||||
created with Raconteur. It should be able to handle any use case for Undum.
|
||||
|
@ -56,7 +46,7 @@ RaconteurSituation.inherits(undum.Situation)
|
|||
Undum API.
|
||||
###
|
||||
|
||||
RaconteurSituation.prototype.act = (character, system, action) ->
|
||||
RaconteurSituation.prototype.act = (character, system, action) =>
|
||||
actionClass = action.match(/^_(\w+)_(.+)$/)
|
||||
that = this
|
||||
|
||||
|
|
21
lib/undum.js
21
lib/undum.js
|
@ -87,7 +87,7 @@ var assert = function(expression, message) {
|
|||
* parameter is an object. So you could write:
|
||||
*
|
||||
* var situation = Situation({
|
||||
* enter: function(character, system, from) {
|
||||
* entering: function(character, system, from) {
|
||||
* ... your implementation ...
|
||||
* }
|
||||
* });
|
||||
|
@ -151,7 +151,7 @@ var assert = function(expression, message) {
|
|||
|
||||
var Situation = function(opts) {
|
||||
if (opts) {
|
||||
if (opts.entering) this._enter = opts.entering;
|
||||
if (opts.entering) this._entering = opts.entering;
|
||||
if (opts.act) this._act = opts.act;
|
||||
|
||||
// Options related to this situation being automatically
|
||||
|
@ -691,7 +691,7 @@ System.prototype.writeChoices = function(listOfIds, elementSelector) {
|
|||
continue;
|
||||
}
|
||||
|
||||
var optionText = situation.optionText(character, this,
|
||||
var optionText = situation.optionText.fcall(this, character, this,
|
||||
currentSituation);
|
||||
if (!optionText) optionText = "choice".l({number:i+1});
|
||||
var $option = $("<li>");
|
||||
|
@ -708,6 +708,15 @@ System.prototype.writeChoices = function(listOfIds, elementSelector) {
|
|||
doWrite($options, elementSelector, 'append', 'after');
|
||||
};
|
||||
|
||||
/*
|
||||
* fcall() (by analogy with fmap) is added to the prototypes of both String and
|
||||
* Function. When called on a Function, it's an
|
||||
* alias for Function#call(); when called on a String, it only returns the
|
||||
* string itself, discarding any input.
|
||||
*/
|
||||
Function.prototype.fcall = Function.prototype.call;
|
||||
String.prototype.fcall = function() { return this; }
|
||||
|
||||
/* Returns a list of situation ids to choose from, given a set of
|
||||
* specifications.
|
||||
*
|
||||
|
@ -961,7 +970,9 @@ System.prototype.setQuality = function(quality, newValue) {
|
|||
*/
|
||||
var Character = function() {
|
||||
this.qualities = {};
|
||||
this.sandbox = {};
|
||||
this.sandbox = {
|
||||
inventory: []
|
||||
};
|
||||
};
|
||||
|
||||
/* The data structure holding the content for the game. By default
|
||||
|
@ -1021,7 +1032,7 @@ var game = {
|
|||
*
|
||||
* function(character, system, oldSituationId, newSituationId);
|
||||
*/
|
||||
enter: null,
|
||||
entering: null,
|
||||
|
||||
/* Hook for when the situation has already been carried out
|
||||
* and printed. The signature is:
|
||||
|
|
Loading…
Reference in a new issue