mirror of
https://gitlab.com/Oreolek/salet-module.git
synced 2024-07-08 01:34:24 +03:00
Fixed the prototype variables. Resolves #5.
This commit is contained in:
parent
07b994cc7f
commit
43c66af5a6
|
@ -8,10 +8,11 @@ room "world", salet,
|
||||||
You're in a large room carved inside a giant milky rock mountain.
|
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.
|
The floor and walls are littered with signs and signatures of the previous visitors.
|
||||||
"""
|
"""
|
||||||
objects:
|
objects: [
|
||||||
well: obj "well",
|
obj "well",
|
||||||
dsc: "A steep narrow {{well}} proceeds upward."
|
dsc: "A steep narrow {{well}} proceeds upward."
|
||||||
act: "There is only one passage out. See the „Other rooms“ block popped up? Click it."
|
act: "There is only one passage out. See the „Other rooms“ block popped up? Click it."
|
||||||
|
]
|
||||||
|
|
||||||
room "plaza", salet,
|
room "plaza", salet,
|
||||||
title: (from) ->
|
title: (from) ->
|
||||||
|
@ -29,8 +30,8 @@ room "plaza", salet,
|
||||||
"""
|
"""
|
||||||
else
|
else
|
||||||
"You quickly find the central plaza."
|
"You quickly find the central plaza."
|
||||||
objects:
|
objects: [
|
||||||
policeman: obj "policeman",
|
obj "policeman",
|
||||||
dsc: "There is a policeman nearby. You could ask him {{for directions.}}"
|
dsc: "There is a policeman nearby. You could ask him {{for directions.}}"
|
||||||
act: (salet) ->
|
act: (salet) ->
|
||||||
if salet.character.has_mark?
|
if salet.character.has_mark?
|
||||||
|
@ -40,9 +41,10 @@ room "plaza", salet,
|
||||||
"""
|
"""
|
||||||
“Here, let me mark it on your map.”
|
“Here, let me mark it on your map.”
|
||||||
"""
|
"""
|
||||||
people: obj "people",
|
obj "people",
|
||||||
dsc: "There are {{people shouting}} nearby."
|
dsc: "There are {{people shouting}} nearby."
|
||||||
act: 'Just some weirdos shouting "Viva la Cthulhu!". Typical.'
|
act: 'Just some weirdos shouting "Viva la Cthulhu!". Typical.'
|
||||||
|
]
|
||||||
|
|
||||||
room "shop", salet,
|
room "shop", salet,
|
||||||
title: "The Shop"
|
title: "The Shop"
|
||||||
|
@ -61,13 +63,15 @@ room "lair", salet,
|
||||||
dsc: """
|
dsc: """
|
||||||
The Lair of Yog-Sothoth is a very *n'gai* cave, full of *buggs-shoggogs* and *n'ghaa ng'aa*.
|
The Lair of Yog-Sothoth is a very *n'gai* cave, full of *buggs-shoggogs* and *n'ghaa ng'aa*.
|
||||||
"""
|
"""
|
||||||
objects:
|
ways: ["shop"]
|
||||||
bugg: obj "bugg",
|
objects: [
|
||||||
|
obj "bugg",
|
||||||
dsc: "You see a particularly beautiful slimy {{bugg.}}"
|
dsc: "You see a particularly beautiful slimy {{bugg.}}"
|
||||||
takeable: false
|
takeable: false
|
||||||
act: (salet) =>
|
act: (salet) =>
|
||||||
salet.here().drop(@name)
|
salet.rooms[salet.current].drop(@name)
|
||||||
return "You eat the bugg mass. Delicious and raw. Perhaps it's a good lair to live in."
|
return "You eat the bugg mass. Delicious and raw. Perhaps it's a good lair to live in."
|
||||||
|
]
|
||||||
|
|
||||||
dialogue "Yes", salet, "merchant", "merchant", """
|
dialogue "Yes", salet, "merchant", "merchant", """
|
||||||
Yes.
|
Yes.
|
||||||
|
@ -81,25 +85,25 @@ room "shop-inside", salet,
|
||||||
dsc: """
|
dsc: """
|
||||||
The insides are painted pastel white, honouring The Great Milk Spill of 1985.
|
The insides are painted pastel white, honouring The Great Milk Spill of 1985.
|
||||||
"""
|
"""
|
||||||
objects:
|
objects: [
|
||||||
merchant: obj "merchant",
|
merchant: obj "merchant",
|
||||||
dsc: "A {{merchant}} eyes you warily."
|
dsc: "A {{merchant}} eyes you warily."
|
||||||
takeable: false
|
takeable: false
|
||||||
act: (system) =>
|
act: (system) =>
|
||||||
salet.processClick("merchdialogue")
|
salet.processClick("merchdialogue")
|
||||||
return ""
|
return ""
|
||||||
|
]
|
||||||
|
|
||||||
###
|
###
|
||||||
I want to be able to do this but I can't because I'm lost in all the `this` and @objects and `new`.
|
I want to be able to do this but I can't because I'm lost in all the `this` and @objects and `new`.
|
||||||
The chain of calls is very weird and this puts an object IN EVERY ROOM for God's sake.
|
The chain of calls is very weird and this puts an object IN EVERY ROOM for God's sake.
|
||||||
I need someone smarter than me to fix this.
|
I need someone smarter than me to fix this.
|
||||||
|
|
||||||
lamp = obj "lamp",
|
|
||||||
dsc: "You see a {{lamp.}}"
|
|
||||||
takeable: true
|
|
||||||
lamp.put("shop-inside")
|
|
||||||
###
|
###
|
||||||
|
|
||||||
|
lamp = obj "lamp", salet,
|
||||||
|
takeable: true
|
||||||
|
lamp.put(salet, "shop-inside")
|
||||||
|
|
||||||
room "merchdialogue", salet,
|
room "merchdialogue", salet,
|
||||||
choices: "#merchant",
|
choices: "#merchant",
|
||||||
dsc: """
|
dsc: """
|
||||||
|
|
|
@ -20,32 +20,34 @@ class SaletObj
|
||||||
unless spec.name?
|
unless spec.name?
|
||||||
console.error("Trying to create an object with no name")
|
console.error("Trying to create an object with no name")
|
||||||
return null
|
return null
|
||||||
|
|
||||||
|
@level = 0 # if > 0 it's hidden
|
||||||
|
@order = 0 # you can use this to sort the descriptions
|
||||||
|
@look = (system, f) =>
|
||||||
|
if @dsc and @dsc != ""
|
||||||
|
text = markdown(@dsc.fcall(this, system, f).toString())
|
||||||
|
text = system.view.wrapLevel(text, @level)
|
||||||
|
# replace braces {{}} with link to _act_
|
||||||
|
return parsedsc(text, @name)
|
||||||
|
@takeable = false
|
||||||
|
@take = (system) => "You take the #{@name}." # taking to inventory
|
||||||
|
@act = (system) => "You don't find anything extraordinary about the #{@name}." # object action
|
||||||
|
@dsc = (system) => "You see a {{#{@name}}} here." # object description
|
||||||
|
@inv = (system) => "It's a {{#{@name}.}}" # inventory description
|
||||||
|
@location = ""
|
||||||
|
@put = (salet, location) =>
|
||||||
|
@level = 0 # this is scenery
|
||||||
|
if salet.rooms[location]?
|
||||||
|
@location = location
|
||||||
|
salet.rooms[location].take(this)
|
||||||
|
@delete = (salet, location = false) =>
|
||||||
|
if location == false
|
||||||
|
location = @location
|
||||||
|
salet.rooms[location].drop(this)
|
||||||
|
|
||||||
for key, value of spec
|
for key, value of spec
|
||||||
this[key] = value
|
this[key] = value
|
||||||
level: 0 # if > 0 it's hidden
|
|
||||||
order: 0 # you can use this to sort the descriptions
|
|
||||||
look: (system, f) =>
|
|
||||||
if @dsc and @dsc != ""
|
|
||||||
text = markdown(@dsc.fcall(this, system, f).toString())
|
|
||||||
text = system.view.wrapLevel(text, @level)
|
|
||||||
# replace braces {{}} with link to _act_
|
|
||||||
return parsedsc(text, @name)
|
|
||||||
takeable: false
|
|
||||||
take: (system) => "You take the #{@name}." # taking to inventory
|
|
||||||
act: (system) => "You don't find anything extraordinary about the #{@name}." # object action
|
|
||||||
dsc: (system) => "You see a {{#{@name}}} here." # object description
|
|
||||||
inv: (system) => "It's a {{#{@name}.}}" # inventory description
|
|
||||||
location: ""
|
|
||||||
put: (location) =>
|
|
||||||
@level = 0 # this is scenery
|
|
||||||
if salet.rooms[location]?
|
|
||||||
salet.rooms[location].take(this)
|
|
||||||
@location = location
|
|
||||||
delete: (location = false) =>
|
|
||||||
if location == false
|
|
||||||
location = @location
|
|
||||||
salet.rooms[location].drop(this)
|
|
||||||
|
|
||||||
obj = (name, spec) ->
|
obj = (name, spec) ->
|
||||||
spec ?= {}
|
spec ?= {}
|
||||||
spec.name = name
|
spec.name = name
|
||||||
|
|
457
lib/room.coffee
457
lib/room.coffee
|
@ -19,239 +19,236 @@ Array::remove = (e) -> @[t..t] = [] if (t = @indexOf(e)) > -1
|
||||||
|
|
||||||
class SaletRoom
|
class SaletRoom
|
||||||
constructor: (spec) ->
|
constructor: (spec) ->
|
||||||
|
@visited = 0
|
||||||
|
@title = "Room"
|
||||||
|
@objects = {}
|
||||||
|
@canView = true
|
||||||
|
@canChoose = true
|
||||||
|
@priority = 1
|
||||||
|
@displayOrder = 1
|
||||||
|
@tags = []
|
||||||
|
@choices = ""
|
||||||
|
@optionText = "Choice"
|
||||||
|
|
||||||
|
# room illustration image, VN-style. Can be a GIF or WEBM. Can be a function.
|
||||||
|
@pic = false
|
||||||
|
@dsc = false # room description
|
||||||
|
@extendSection = false
|
||||||
|
@distance = Infinity # distance to the destination
|
||||||
|
@clear = true # clear the screen on entering the room?
|
||||||
|
@entering = (system, from) =>
|
||||||
|
###
|
||||||
|
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 = (system, to) =>
|
||||||
|
return true
|
||||||
|
|
||||||
|
###
|
||||||
|
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 = (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).
|
||||||
|
|
||||||
|
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 = (system, f) =>
|
||||||
|
if @clear and f?
|
||||||
|
system.view.clearContent()
|
||||||
|
|
||||||
|
if f != @name and f?
|
||||||
|
@visited++
|
||||||
|
if system.rooms[f].exit?
|
||||||
|
system.rooms[f].exit system, @name
|
||||||
|
|
||||||
|
if @enter
|
||||||
|
@enter system, f
|
||||||
|
|
||||||
|
room_content = ""
|
||||||
|
if not @extendSection
|
||||||
|
classes = if @classes then ' ' + @classes.join(' ') else ''
|
||||||
|
room = document.getElementById('current-room')
|
||||||
|
if room?
|
||||||
|
room.removeAttribute('id')
|
||||||
|
# Javascript DOM manipulation functions like jQuery's append() or document.createElement
|
||||||
|
# don't work like a typical printLn - they create *DOM nodes*.
|
||||||
|
# You can't leave an unclosed tag just like that. So we have to buffer the output.
|
||||||
|
room_content = "<section id='current-room' data-room='#{@name}' class='room-#{@name}#{classes}'>"
|
||||||
|
|
||||||
|
if f != @name and @before?
|
||||||
|
room_content += markdown(@before.fcall(this, system, f))
|
||||||
|
|
||||||
|
room_content += @look system, f
|
||||||
|
|
||||||
|
if f != @name and @after?
|
||||||
|
room_content += markdown(@after.fcall(this, system, f))
|
||||||
|
|
||||||
|
if not @extendSection
|
||||||
|
room_content += "</section>"
|
||||||
|
|
||||||
|
system.view.write(room_content)
|
||||||
|
|
||||||
|
if @choices
|
||||||
|
system.view.writeChoices(system, system.getSituationIdChoices(@choices, @maxChoices))
|
||||||
|
|
||||||
|
if system.autosave
|
||||||
|
system.saveGame()
|
||||||
|
|
||||||
|
###
|
||||||
|
An internal function to get the room's description and the descriptions of
|
||||||
|
every object in this room.
|
||||||
|
###
|
||||||
|
@look = (system, f) =>
|
||||||
|
system.view.updateWays(system, @ways, @name)
|
||||||
|
retval = ""
|
||||||
|
|
||||||
|
if @pic
|
||||||
|
retval += '<div class="pic">'+system.view.pictureTag(@pic.fcall(this, system, f))+'</div>'
|
||||||
|
|
||||||
|
# Print the room description
|
||||||
|
if @dsc and @dsc != ""
|
||||||
|
dsc = @dsc.fcall(this, system, f).toString()
|
||||||
|
retval += markdown(dsc)
|
||||||
|
|
||||||
|
objDescriptions = []
|
||||||
|
for thing in @objects
|
||||||
|
if thing.name and typeof(thing.look) == "function" and thing.level == 0 and thing.look(system, f)
|
||||||
|
objDescriptions.push ({
|
||||||
|
order: thing.order,
|
||||||
|
content: thing.look(system, f)
|
||||||
|
})
|
||||||
|
|
||||||
|
objDescriptions.sort((a, b) ->
|
||||||
|
return a.order - b.order
|
||||||
|
)
|
||||||
|
|
||||||
|
for description in objDescriptions
|
||||||
|
retval += description.content
|
||||||
|
|
||||||
|
return retval
|
||||||
|
|
||||||
|
###
|
||||||
|
Puts an object in this room.
|
||||||
|
###
|
||||||
|
@take = (thing) =>
|
||||||
|
@objects[thing.name] = thing
|
||||||
|
|
||||||
|
@drop = (name) =>
|
||||||
|
for thing in @objects
|
||||||
|
if thing.name == name
|
||||||
|
index = @objects.indexOf(thing)
|
||||||
|
@objects.splice(index, 1)
|
||||||
|
|
||||||
|
###
|
||||||
|
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 = (system, action) =>
|
||||||
|
if (link = action.match(/^_(act|cycle)_(.+)$/)) #object action
|
||||||
|
for thing in @objects
|
||||||
|
if thing.name == link[2]
|
||||||
|
if link[1] == "act"
|
||||||
|
# If it's takeable, the player can take this object.
|
||||||
|
# If not, we check the "act" function.
|
||||||
|
if thing.takeable
|
||||||
|
system.character.inventory.push thing
|
||||||
|
@drop name
|
||||||
|
system.view.clearContent()
|
||||||
|
@entering.fcall(this, system, @name)
|
||||||
|
return system.view.write(thing.take.fcall(thing, system).toString())
|
||||||
|
if thing.act
|
||||||
|
system.view.changeLevel(thing.level)
|
||||||
|
return system.view.write(
|
||||||
|
system.view.wrapLevel(
|
||||||
|
thing.act.fcall(thing, system).toString(),
|
||||||
|
thing.level
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# the loop is done but no return came - match not found
|
||||||
|
console.error("Could not find #{link[2]} in current room.")
|
||||||
|
|
||||||
|
# we're done with objects, now check the regular actions
|
||||||
|
actionClass = action.match(/^_(\w+)_(.+)$/)
|
||||||
|
that = this
|
||||||
|
|
||||||
|
responses = {
|
||||||
|
writer: (ref) ->
|
||||||
|
content = that.writers[ref].fcall(that, system, action)
|
||||||
|
output = markdown(content)
|
||||||
|
system.view.write(output)
|
||||||
|
replacer: (ref) ->
|
||||||
|
content = that.writers[ref].fcall(that, system, action)
|
||||||
|
system.view.replace(content, '#'+ref)
|
||||||
|
inserter: (ref) ->
|
||||||
|
content = that.writers[ref].fcall(that, system, action)
|
||||||
|
output = markdown(content)
|
||||||
|
system.view.write(output, '#'+ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionClass)
|
||||||
|
# Matched a special action class
|
||||||
|
[responder, ref] = [actionClass[1], actionClass[2]]
|
||||||
|
|
||||||
|
if(!@writers.hasOwnProperty(actionClass[2]))
|
||||||
|
throw new Error("Tried to call undefined writer: #{action}");
|
||||||
|
responses[responder](ref);
|
||||||
|
else if (@actions.hasOwnProperty(action))
|
||||||
|
@actions[action].call(this, system, action);
|
||||||
|
else
|
||||||
|
throw new Error("Tried to call undefined action: #{action}");
|
||||||
|
|
||||||
|
# Marks every room in the game with distance to this room
|
||||||
|
@destination = () =>
|
||||||
|
@distance = 0
|
||||||
|
|
||||||
|
candidates = [this]
|
||||||
|
while candidates.length > 0
|
||||||
|
current_room = candidates.shift()
|
||||||
|
if current_room.ways
|
||||||
|
for node in current_room.ways
|
||||||
|
if node.distance == Infinity
|
||||||
|
node.distance = current_room.distance + 1
|
||||||
|
candidates.push(node)
|
||||||
|
|
||||||
|
@register = (salet) =>
|
||||||
|
if not @name?
|
||||||
|
console.error("Situation has no name")
|
||||||
|
return this
|
||||||
|
salet.rooms[@name] = this
|
||||||
|
return this
|
||||||
|
|
||||||
|
@writers = {
|
||||||
|
cyclewriter: (salet) =>
|
||||||
|
responses = @cycle
|
||||||
|
if typeof responses == "function"
|
||||||
|
responses = responses()
|
||||||
|
cycleIndex = window.localStorage.getItem("cycleIndex")
|
||||||
|
cycleIndex ?= 0
|
||||||
|
response = responses[cycleIndex]
|
||||||
|
cycleIndex++
|
||||||
|
if cycleIndex == responses.length
|
||||||
|
cycleIndex = 0
|
||||||
|
window.localStorage.setItem("cycleIndex", cycleIndex)
|
||||||
|
return salet.view.cycleLink(response)
|
||||||
|
}
|
||||||
|
|
||||||
for index, value of spec
|
for index, value of spec
|
||||||
this[index] = value
|
this[index] = value
|
||||||
return this
|
return this
|
||||||
visited: 0
|
|
||||||
title: "Room"
|
|
||||||
objects: {}
|
|
||||||
|
|
||||||
# room illustration image, VN-style. Can be a GIF or WEBM. Can be a function.
|
|
||||||
pic: false
|
|
||||||
|
|
||||||
canView: true
|
|
||||||
canChoose: true
|
|
||||||
priority: 1
|
|
||||||
displayOrder: 1
|
|
||||||
tags: []
|
|
||||||
choices: ""
|
|
||||||
optionText: "Choice"
|
|
||||||
|
|
||||||
dsc: false # room description
|
|
||||||
extendSection: false
|
|
||||||
distance: Infinity # distance to the destination
|
|
||||||
clear: true # clear the screen on entering the room?
|
|
||||||
|
|
||||||
entering: (system, from) =>
|
|
||||||
|
|
||||||
###
|
|
||||||
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: (system, to) =>
|
|
||||||
return true
|
|
||||||
|
|
||||||
###
|
|
||||||
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: (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).
|
|
||||||
|
|
||||||
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: (system, f) =>
|
|
||||||
if @clear and f?
|
|
||||||
system.view.clearContent()
|
|
||||||
|
|
||||||
if f != @name and f?
|
|
||||||
@visited++
|
|
||||||
if system.rooms[f].exit?
|
|
||||||
system.rooms[f].exit system, @name
|
|
||||||
|
|
||||||
if @enter
|
|
||||||
@enter system, f
|
|
||||||
|
|
||||||
room_content = ""
|
|
||||||
if not @extendSection
|
|
||||||
classes = if @classes then ' ' + @classes.join(' ') else ''
|
|
||||||
room = document.getElementById('current-room')
|
|
||||||
if room?
|
|
||||||
room.removeAttribute('id')
|
|
||||||
# Javascript DOM manipulation functions like jQuery's append() or document.createElement
|
|
||||||
# don't work like a typical printLn - they create *DOM nodes*.
|
|
||||||
# You can't leave an unclosed tag just like that. So we have to buffer the output.
|
|
||||||
room_content = "<section id='current-room' data-room='#{@name}' class='room-#{@name}#{classes}'>"
|
|
||||||
|
|
||||||
if f != @name and @before?
|
|
||||||
room_content += markdown(@before.fcall(this, system, f))
|
|
||||||
|
|
||||||
room_content += @look system, f
|
|
||||||
|
|
||||||
if f != @name and @after?
|
|
||||||
room_content += markdown(@after.fcall(this, system, f))
|
|
||||||
|
|
||||||
if not @extendSection
|
|
||||||
room_content += "</section>"
|
|
||||||
|
|
||||||
system.view.write(room_content)
|
|
||||||
|
|
||||||
if @choices
|
|
||||||
system.view.writeChoices(system, system.getSituationIdChoices(@choices, @maxChoices))
|
|
||||||
|
|
||||||
if system.autosave
|
|
||||||
system.saveGame()
|
|
||||||
|
|
||||||
###
|
|
||||||
An internal function to get the room's description and the descriptions of
|
|
||||||
every object in this room.
|
|
||||||
###
|
|
||||||
look: (system, f) =>
|
|
||||||
system.view.updateWays(system, @ways, @name)
|
|
||||||
retval = ""
|
|
||||||
|
|
||||||
if @pic
|
|
||||||
retval += '<div class="pic">'+system.view.pictureTag(@pic.fcall(this, system, f))+'</div>'
|
|
||||||
|
|
||||||
# Print the room description
|
|
||||||
if @dsc and @dsc != ""
|
|
||||||
dsc = @dsc.fcall(this, system, f).toString()
|
|
||||||
retval += markdown(dsc)
|
|
||||||
|
|
||||||
objDescriptions = []
|
|
||||||
for thing in @objects
|
|
||||||
console.log thing
|
|
||||||
if thing.name and typeof(thing.look) == "function" and thing.level == 0 and thing.look(system, f)
|
|
||||||
objDescriptions.push ({
|
|
||||||
order: thing.order,
|
|
||||||
content: thing.look(system, f)
|
|
||||||
})
|
|
||||||
|
|
||||||
objDescriptions.sort((a, b) ->
|
|
||||||
return a.order - b.order
|
|
||||||
)
|
|
||||||
|
|
||||||
for description in objDescriptions
|
|
||||||
retval += description.content
|
|
||||||
|
|
||||||
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.
|
|
||||||
salet.rooms["start"].objects = {}
|
|
||||||
|
|
||||||
drop: (name) =>
|
|
||||||
delete @objects[name]
|
|
||||||
|
|
||||||
###
|
|
||||||
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: (system, action) =>
|
|
||||||
if (link = action.match(/^_(act|cycle)_(.+)$/)) #object action
|
|
||||||
for thing in @objects
|
|
||||||
if thing.name == link[2]
|
|
||||||
if link[1] == "act"
|
|
||||||
# If it's takeable, the player can take this object.
|
|
||||||
# If not, we check the "act" function.
|
|
||||||
if thing.takeable
|
|
||||||
system.character.inventory.push thing
|
|
||||||
@drop name
|
|
||||||
system.view.clearContent()
|
|
||||||
@entering.fcall(this, system, @name)
|
|
||||||
return system.view.write(thing.take.fcall(thing, system).toString())
|
|
||||||
if thing.act
|
|
||||||
system.view.changeLevel(thing.level)
|
|
||||||
return system.view.write(
|
|
||||||
system.view.wrapLevel(
|
|
||||||
thing.act.fcall(thing, system).toString(),
|
|
||||||
thing.level
|
|
||||||
)
|
|
||||||
)
|
|
||||||
# the loop is done but no return came - match not found
|
|
||||||
console.error("Could not find #{link[2]} in current room.")
|
|
||||||
|
|
||||||
# we're done with objects, now check the regular actions
|
|
||||||
actionClass = action.match(/^_(\w+)_(.+)$/)
|
|
||||||
that = this
|
|
||||||
|
|
||||||
responses = {
|
|
||||||
writer: (ref) ->
|
|
||||||
content = that.writers[ref].fcall(that, system, action)
|
|
||||||
output = markdown(content)
|
|
||||||
system.view.write(output)
|
|
||||||
replacer: (ref) ->
|
|
||||||
content = that.writers[ref].fcall(that, system, action)
|
|
||||||
system.view.replace(content, '#'+ref)
|
|
||||||
inserter: (ref) ->
|
|
||||||
content = that.writers[ref].fcall(that, system, action)
|
|
||||||
output = markdown(content)
|
|
||||||
system.view.write(output, '#'+ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionClass)
|
|
||||||
# Matched a special action class
|
|
||||||
[responder, ref] = [actionClass[1], actionClass[2]]
|
|
||||||
|
|
||||||
if(!@writers.hasOwnProperty(actionClass[2]))
|
|
||||||
throw new Error("Tried to call undefined writer: #{action}");
|
|
||||||
responses[responder](ref);
|
|
||||||
else if (@actions.hasOwnProperty(action))
|
|
||||||
@actions[action].call(this, system, action);
|
|
||||||
else
|
|
||||||
throw new Error("Tried to call undefined action: #{action}");
|
|
||||||
|
|
||||||
# Marks every room in the game with distance to this room
|
|
||||||
destination: () =>
|
|
||||||
@distance = 0
|
|
||||||
|
|
||||||
candidates = [this]
|
|
||||||
while candidates.length > 0
|
|
||||||
current_room = candidates.shift()
|
|
||||||
if current_room.ways
|
|
||||||
for node in current_room.ways
|
|
||||||
if node.distance == Infinity
|
|
||||||
node.distance = current_room.distance + 1
|
|
||||||
candidates.push(node)
|
|
||||||
|
|
||||||
register: (salet) =>
|
|
||||||
if not @name?
|
|
||||||
console.error("Situation has no name")
|
|
||||||
return this
|
|
||||||
salet.rooms[@name] = this
|
|
||||||
return this
|
|
||||||
|
|
||||||
writers:
|
|
||||||
cyclewriter: (salet) =>
|
|
||||||
responses = @cycle
|
|
||||||
if typeof responses == "function"
|
|
||||||
responses = responses()
|
|
||||||
cycleIndex = window.localStorage.getItem("cycleIndex")
|
|
||||||
cycleIndex ?= 0
|
|
||||||
response = responses[cycleIndex]
|
|
||||||
cycleIndex++
|
|
||||||
if cycleIndex == responses.length
|
|
||||||
cycleIndex = 0
|
|
||||||
window.localStorage.setItem("cycleIndex", cycleIndex)
|
|
||||||
return salet.view.cycleLink(response)
|
|
||||||
|
|
||||||
room = (name, salet, spec) ->
|
room = (name, salet, spec) ->
|
||||||
spec ?= {}
|
spec ?= {}
|
||||||
spec.name = name
|
spec.name = name
|
||||||
|
|
|
@ -23,6 +23,8 @@ class Character
|
||||||
###
|
###
|
||||||
This is the control structure, it has minimal amount of data and
|
This is the control structure, it has minimal amount of data and
|
||||||
this data is volatile anyway (as in, it won't get saved).
|
this data is volatile anyway (as in, it won't get saved).
|
||||||
|
|
||||||
|
There is only one instance of this class.
|
||||||
###
|
###
|
||||||
class Salet
|
class Salet
|
||||||
# REDEFINE THIS IN YOUR GAME
|
# REDEFINE THIS IN YOUR GAME
|
||||||
|
|
|
@ -9,6 +9,8 @@ You don't need to call this module from the game directly.
|
||||||
The abstraction goal here is to provide the author with a freedom to style his
|
The abstraction goal here is to provide the author with a freedom to style his
|
||||||
game as he wants to. The save and erase buttons are not necessary buttons,
|
game as he wants to. The save and erase buttons are not necessary buttons,
|
||||||
but they could be something else entirely. (That's why IDs are hardcoded.)
|
but they could be something else entirely. (That's why IDs are hardcoded.)
|
||||||
|
|
||||||
|
There is only one instance of this class, and it's stored as `salet.view`.
|
||||||
###
|
###
|
||||||
|
|
||||||
assert = (msg, assertion) -> console.assert assertion, msg
|
assert = (msg, assertion) -> console.assert assertion, msg
|
||||||
|
|
Loading…
Reference in a new issue