Modular API (WIP)

This commit is contained in:
Alexander Yakovlev 2016-01-25 23:05:32 +07:00
parent 63dbeb49f4
commit 566c8b27a2
6 changed files with 81 additions and 96 deletions

View file

@ -3,10 +3,7 @@ room = require("../../lib/room.coffee")
obj = require('../../lib/obj.coffee')
dialogue = require('../../lib/dialogue.coffee')
oneOf = require('../../lib/oneOf.coffee')
salet = require('../../lib/salet.coffee')
salet.game_id = "your-game-id-here"
salet.game_version = "1.0"
require('../../lib/salet.coffee')
###
Element helpers. There is no real need to build monsters like a().id("hello")
@ -26,29 +23,9 @@ textcycle = (content, ref) ->
cyclelink = (content) ->
return "<a href='./_replacer_cyclewriter' class='cycle' id='cyclewriter'>#{content}</a>"
# usage: writemd( system, "Text to write")
writemd = (system, text) ->
text = markdown(text)
system.write(text)
get_room = (name) ->
return undum.game.situations[name]
# Function to return the current room.
# Works because our `enter()` function sets the `data-situation` attribute.
here = () ->
return undum.game.situations[document.getElementById("current-situation").getAttribute("data-situation")]
# The first room of the game.
# For accessibility reasons the text is provided in HTML, not here.
room "start",
dsc: """
""",
choices: "#start"
# This function needs to go after the start room.
is_visited = (situation) ->
place = undum.game.situations[situation]
if place
return Boolean place.visited
return 0

View file

@ -1,4 +1,7 @@
# This is where you initialize your game.
# All code in this file comes last, so the game is almost ready by this point.
salet.init = (character, system) ->
$(document).ready(() ->
salet.game_id = "your-game-id-here"
salet.game_version = "1.0"
salet.beginGame()
)

View file

@ -1,5 +1,5 @@
markdown = require('./markdown.coffee')
salet = require('./salet.coffee')
require('./salet.coffee')
objlink = (content, ref) ->
return "<a href='./_act_#{ref}' class='once'>#{content}</a>"

View file

@ -5,7 +5,7 @@ markdown = require('./markdown.coffee')
cycle = require('./cycle.coffee')
Random = require('./random.js')
languages = require('./localize.coffee')
salet = require('./salet.coffee')
require('./salet.coffee')
# Assertion
assert = console.assert
@ -21,10 +21,6 @@ addClass = (element, className) ->
else
element.className += ' ' + className
cls = (system) ->
system.clearContent()
system.clearContent("#intro")
update_ways = (ways, name) ->
content = ""
distances = []
@ -118,41 +114,41 @@ class SaletRoom
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: (system, f) =>
if @clear and f?
cls(system)
system.view.clearContent()
if f != @name and f?
@visited++
if salet.rooms[f].exit?
salet.rooms[f].exit(character, system, @name)
if system.rooms[f].exit?
system.rooms[f].exit system, @name
if @enter
@enter character, system, f
@enter system, f
current_situation = ""
room_content = ""
if not @extendSection
classes = if @classes then ' ' + @classes.join(' ') else ''
situation = document.getElementById('current-room')
if situation?
situation.removeAttribute('id')
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.
current_situation = "<section id='current-room' data-situation='#{@name}' class='situation-#{@name}#{classes}'>"
room_content = "<section id='current-room' data-room='#{@name}' class='room-#{@name}#{classes}'>"
if f != @name and @before?
current_situation += markdown(@before.fcall(this, character, system, f))
room_content += markdown(@before.fcall(this, system, f))
current_situation += @look character, system, f
room_content += @look system, f
if f != @name and @after?
current_situation += markdown(@after.fcall(this, character, system, f))
room_content += markdown(@after.fcall(this, system, f))
if not @extendSection
current_situation += "</section>"
room_content += "</section>"
system.write(current_situation)
system.write(room_content)
if @choices
system.writeChoices(system.getSituationIdChoices(@choices, @minChoices, @maxChoices))
@ -272,7 +268,13 @@ room = (name, spec) ->
spec ?= {}
spec.name = name
retval = new SaletRoom(spec)
retval.register()
$(document).ready(() ->
if salet
retval.register()
else
sleep(1000)
retval.register()
)
return retval
module.exports = room

View file

@ -1,5 +1,5 @@
markdown = require('./markdown.coffee')
view = require('./view.coffee')
SaletView = require('./view.coffee')
Random = require('./random.js')
###
@ -48,7 +48,7 @@ augmentLinks = (content) ->
# If we're a once-click, remove all matching links.
if (a.hasClass("once") || href.match(/[?&]once[=&]?/))
view.clearLinks(href)
@view.clearLinks(href)
processClick(href)
return false
@ -92,13 +92,13 @@ class Salet
situation. It is called before the corresponding situation
has its `enter` method called.
###
entering: (character, oldSituationId, newSituationId) ->
enter: (oldSituationId, newSituationId) ->
###
Hook for when the situation has already been carried out
and printed.
###
afterEnter: (character, oldSituationId, newSituationId) ->
afterEnter: (oldSituationId, newSituationId) ->
###
This function is called before carrying out any action in
@ -110,21 +110,21 @@ class Salet
on to the situation. Note that this is the only one of
these global handlers that can consume the event.
###
beforeAction: (character, situationId, actionId) ->
beforeAction: (situationId, actionId) ->
###
This function is called after carrying out any action in
any situation. It is called after the corresponding
situation has its `act` method called.
###
afterAction: (character, situationId, actionId) ->
afterAction: (situationId, actionId) ->
###
This function is called after leaving any situation. It is
called after the corresponding situation has its `exit`
method called.
###
exit: (character, oldSituationId, newSituationId) ->
exit: (oldSituationId, newSituationId) ->
###
Returns a list of situation ids to choose from, given a set of
@ -307,7 +307,7 @@ class Salet
@linkStack.push(code)
return
view.mark_all_links_old
@view.mark_all_links_old
# We're processing, so make the stack available.
@linkStack = []
@ -375,32 +375,30 @@ class Salet
processLink(code)
# Transitions between situations.
doTransitionTo: (newSituationId) ->
oldSituationId = current
oldSituation = @getCurrentRoom()
newSituation = @rooms[newSituationId]
doTransitionTo: (newRoomId) ->
oldRoomId = @current
oldRoom = @getCurrentRoom()
newRoom = @rooms[newRoomId]
assert(newSituation, "unknown_situation".l({id:newSituationId}))
assert(newRoom, "unknown_situation".l({id:newRoomId}))
# We might not have an old situation if this is the start of the game.
if (oldSituation)
if (@exit)
@exit(@character, oldSituationId, newSituationId);
if (oldRoom and @exit)
@exit(oldRoomId, newRoomId)
@current = newRoomId
# Remove links and transient sections.
view.remove_transient(@interactive)
# Move the character.
current = newSituationId
@view.remove_transient(@interactive)
# Notify the incoming situation.
if (@enter)
@enter(@character, this, oldSituationId, newSituationId)
newSituation.entering(@character, oldSituationId)
@enter(oldRoomId, newRoomId)
newRoom.entering(this, oldRoomId)
# additional hook for when the situation text has already been printed
if (@afterEnter)
@afterEnter(@character, oldSituationId, newSituationId)
@afterEnter(oldRoomId, newRoomId)
###
Erases the character in local storage. This is permanent!
@ -436,9 +434,9 @@ class Salet
localStorage.setItem(getSaveId(), JSON.stringify(@progress))
# Switch the button highlights.
view.disableSaving()
view.enableErasing()
view.enableLoading()
@view.disableSaving()
@view.enableErasing()
@view.enableLoading()
# Loads the game from the given data
loadGame: (characterData) ->
@ -447,7 +445,7 @@ class Salet
character = new Character()
@rnd = new Random(@progress.seed)
view.clearContent()
@view.clearContent()
# Now play through the actions so far:
if (@init)
@ -465,17 +463,19 @@ class Salet
now = new Date().getTime() * 0.001
startTime = now - @progress.saveTime
view: new SaletView
beginGame: () ->
# Handle storage.
storedCharacter = false
if (view.hasLocalStorage())
if (@view.hasLocalStorage())
storedCharacter = localStorage.getItem(@getSaveId())
if (storedCharacter)
try
@loadGame(JSON.parse(storedCharacter))
view.disableSaving()
view.enableErasing()
@view.disableSaving()
@view.enableErasing()
catch err
@erase_save(true)
else
@ -485,16 +485,15 @@ class Salet
@rnd = new Random(@progress.seed)
@progress.sequence = [{link:@start, when:0}]
view.clearContent()
@view.clearContent()
# Start the game
startTime = new Date().getTime() * 0.001
@time = 0
@startTime = new Date().getTime() * 0.001
if (@init)
@init(character)
# Do the first state.
@doTransitionTo(@start);
@doTransitionTo(@start)
# Any point that an option list appears, its options are its first links.
$("body").on('click', "ul.options li, #menu li", (event) ->
@ -502,17 +501,25 @@ class Salet
link = $("a", this)
if (link.length > 0)
$(link.get(0)).click()
);
)
salet = new Salet
getRoom: (name) ->
return @rooms[name]
# Just an alias for getCurrentRoom
here: () -> @getCurrentRoom()
isVisited: (name) ->
place = @getRoom(name)
if place
return Boolean place.visited
return 0
# Set up the game when everything is loaded.
$(document).ready(() ->
if (view.hasLocalStorage())
salet = new Salet
salet.view.init()
if (salet.view.hasLocalStorage())
$("#erase").click(salet.erase_save) # is Salet defined here?
$("#save").click(salet.saveGame)
salet.beginGame()
)
module.exports = salet

View file

@ -12,12 +12,13 @@ but they could be something else entirely. (That's why IDs are hardcoded.)
class SaletView
init: () ->
$("#ways").on("click", "a", (event) ->
$("#content, #ways").on("click", "a", (event) ->
event.preventDefault()
salet.processClick($(this).attr("href"))
)
$("#inventory").on("click", "a", (event) ->
event.preventDefault()
alert("Not done yet")
)
$("#load").on("click", "a", (event) ->
window.location.reload()
@ -192,9 +193,4 @@ class SaletView
hasStorage = false
return hasStorage
view = new SaletView
$(document).ready(() ->
view.init()
)
module.exports = view
module.exports = SaletView