1
0
Fork 0
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:
Alexander Yakovlev 2016-01-16 23:24:23 +07:00
parent 8ad06c0d0a
commit 0ed4f98098
9 changed files with 105 additions and 87 deletions

View file

@ -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'));

View file

@ -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",

View file

@ -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

View file

@ -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"]

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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: