1
0
Fork 0

Initial commit - Being Astrid: The Game

This commit is contained in:
Alexander Yakovlev 2017-01-23 21:28:42 +07:00
commit 162135e13e
11 changed files with 555 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules
build
dist
dist.zip

121
Gulpfile.coffee Normal file
View File

@ -0,0 +1,121 @@
browserSync = require('browser-sync')
gulp = require('gulp')
source = require('vinyl-source-stream')
gutil = require('gulp-util')
coffee = require("gulp-coffee")
sass = require('gulp-sass')
uglify = require('gulp-uglify')
buffer = require('vinyl-buffer')
zip = require('gulp-zip')
concat = require('gulp-concat')
rename = require('gulp-rename')
reload = browserSync.reload
html = (target) ->
return () ->
gulp.src(['html/index.html'])
.pipe(gulp.dest(target))
gulp.src(['node_modules/salet/lib/index.min.js'])
.pipe(rename('salet.min.js'))
.pipe(gulp.dest(target+"/game"))
# Images
img = (target) ->
return () ->
return gulp.src(['img/*.png', 'img/*.jpeg', 'img/*.jpg']).pipe(gulp.dest(target))
# Audio assets
audio = (target) ->
return () ->
return gulp.src(['audio/*.mp3']).pipe(gulp.dest(target))
gulp.task('html', html('./build'))
gulp.task('img', img('./build/img'))
gulp.task('audio', audio('./build/audio'))
# SCSS styles
gulp.task('sass', () ->
gulp.src('sass/main.scss')
.pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError))
.pipe(gulp.dest('./build/css'))
)
gulp.task('concatCoffee', () ->
gulp.src([
## additional functions
'./game/dialogue.coffee',
'./game/phrase.coffee',
## the actual game
'./game/begin.coffee',
'./game/story.coffee',
]).pipe(concat('./main.coffee'))
.pipe(gulp.dest('./build/game'))
)
gulp.task('coffee', ['concatCoffee'], () ->
gulp.src('./build/game/main.coffee')
.pipe(coffee({bare: true}))
.pipe(gulp.dest('./build/game/'))
)
gulp.task('build', ['html', 'img', 'sass', 'coffee', 'audio'])
gulp.task('serve', ['build'], () ->
browserSync({
server: {
baseDir: 'build'
}
})
sassListener = () ->
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(['./build/css/main.css'], sassListener)
gulp.watch(
['./build/game/bundle.js', './build/img/*', './build/index.html'],
browserSync.reload)
)
gulp.task('html-dist', html('./dist'))
gulp.task('img-dist', img('./dist/img'))
gulp.task('audio-dist', audio('./dist/audio'))
gulp.task('legal-dist', () ->
return gulp.src(['LICENSE.txt'])
.pipe(gulp.dest("./dist"))
)
gulp.task('sass-dist', () ->
return gulp.src('./sass/main.scss')
.pipe(sass({outputStyle: 'compressed'}))
.pipe(gulp.dest('./dist/css'))
)
gulp.task('coffee-dist', ['concatCoffee'], () ->
gulp.src('./build/game/main.coffee', {sourcemaps: false})
.pipe(coffee())
.pipe(buffer())
.pipe(uglify())
.on('error', gutil.log)
.pipe(gulp.dest('./dist/game/'))
)
gulp.task('dist', [
'html-dist',
'img-dist',
'sass-dist',
'coffee-dist',
'audio-dist',
'legal-dist'
])
gulp.task('zip', ['dist'], () ->
return gulp.src('dist/**')
.pipe(zip('dist.zip'))
.pipe(gulp.dest('.'))
)

30
README.md Normal file
View File

@ -0,0 +1,30 @@
# Salet
A general client-side framework for cybertext interactive fiction games.
**Salet** is based upon [Undum,](https://github.com/idmillington/undum) rewritten in CoffeeScript and altered to its own needs.
It also uses some code from [Raconteur,](https://github.com/sequitur/raconteur) same deal.
## License
The code, documentation, styles, design and images are all distributed under the MIT license.
This permits you to modify and use them, even for commercial use.
A copy of the MIT license is found in the LICENSE file.
*Raconteur is copyright (c) 2015 Bruno Dias, released under the similar license terms.*
*Undum is copyright (c) 2009-2015 Ian Millington, released under the similar license terms.*
## List of contributors
The list is alphabetical.
Hopefully it will grow.
* Alexander Yakovlev - Salet's original author
* Andrew Plotkin
* Bruno Dias - Raconteur's original author
* David Eyk
* Dmitry Eliseev
* Ian Millington - Undum's original author
* Ivan Narozhny
* Juhana Leinonen
* Michael Neal Tenuis
* Selene

76
game/begin.coffee Normal file
View File

@ -0,0 +1,76 @@
salet.game_id = "your-game-id-here"
salet.game_version = "1.6"
ably = new Ably.Realtime('v6yAiA.PKvuDg:iJhwQu-DkAWpDOUB')
channel = ably.channels.get('astrid')
$(document).ready(() ->
window.addEventListener('popstate', (event) ->
salet.goBack()
)
$("#night").on("click", () ->
if (window.night)
styles = {
"-webkit-filter": ""
"filter": ""
"background-color": ""
}
$("body").css(styles)
$("#night").removeClass("active")
window.night = false
else
styles = {
"-webkit-filter": "invert(1)hue-rotate(180deg)"
"filter": "invert(1)hue-rotate(180deg)"
"background-color": "#000"
}
$("body").css(styles)
$("#night").addClass("active")
window.night = true
)
channel.subscribe('enter', (message) ->
if (
message.data.room == salet.current and
message.data.name != salet.character.name
)
salet.view.write("В комнату входит "+message.data.name+".")
)
salet.beginGame()
)
###
Element helpers. There is no real need to build monsters like a().id("hello")
because you won't use them as is. It does not make sense in context, the
author has Markdown and all utilities to *forget* about the markup.
###
way_to = (content, ref) ->
return "<a href='#{ref}' class='way'>#{content}</a>"
textlink = (content, ref) ->
return "<a href='./_writer_#{ref}' class='once'>#{content}</a>"
actlink = (content, ref) ->
return "<a href='./#{ref}' class='once'>#{content}</a>"
# The first room of the game.
# For accessibility reasons the text is provided in HTML, not here.
room "start",
enter: () ->
names = [
'рыжая Астрид',
'Астрид-хулиганка',
'волшебная русалка Астрид',
'Астрид-ведьма'
]
salet.character.name = names[salet.rnd.randomInt(names.length)]
dsc: ""
choices: "#start"
croom = (name, options) ->
options.enter = () ->
if (salet.interactive)
channel.publish('enter', {
room: @name,
name: salet.character.name
})
options.dsc = "### #{options.title}\n" + options.dsc
return room(name,options)

23
game/dialogue.coffee Normal file
View File

@ -0,0 +1,23 @@
###
A dialogue shortcut.
Usage:
dialogue "Point out a thing in her purse (mildly)", "start", "mild", """
Point out a thing in her purse (mildly)
""", "character.mild = true"
###
dialogue = (title, startTag, endTag, text, effect) ->
retval = room("dialogue_"+Object.keys(salet.rooms).length, {
optionText: title
dsc: text
clear: false # backlog is useful in dialogues
choices: "#"+endTag
})
if typeof(startTag) == "string"
retval.tags = [startTag]
else if typeof(startTag) == "object"
retval.tags = startTag
if effect?
retval.before = (character, system) ->
eval(effect)
return retval

26
game/phrase.coffee Normal file
View File

@ -0,0 +1,26 @@
###
A phrase shortcut.
Usage:
phrase "Point out a thing in her purse (mildly)", "start", """
Point out a thing in her purse (mildly)
""", "character.sandbox.mild = true"
@param title phrase Phrase (question)
@param salet Salet core
@param string tag tag marking viewing condition
@param string text Response
@param string effect an optional parameter, eval'd code
###
phrase = (title, tag, text, effect) ->
retval = room("phrase_"+salet.rooms.length, {
optionText: title
dsc: text
clear: false # backlog is useful in dialogues
choices: "#"+tag
tags: [tag]
})
if effect?
retval.before = (character, system) ->
eval(effect)
return retval

15
game/story.coffee Normal file
View File

@ -0,0 +1,15 @@
croom "entry",
tags: ["start"],
optionText: "Быть Астрид"
title: "Прихожая"
ways: ["corridor"]
dsc: """
Вы находитесь в красивой подводной прихожей. За прозрачными стенами плавают рыбки.
"""
croom "corridor",
ways: ["entry"]
title: "Коридор"
dsc: """
Короткий коридор, который замыкается в себе.
"""

70
html/index.html Normal file
View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Быть Астрид</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=PT+Sans:400,400italic|PT+Sans+Caption' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<div id="page">
<div class="fixed container">
<div id="tools_wrapper" class="row">
<div class='ways'>
<small class="text-muted" id="ways_hint">Эти ссылки ведут в соседние комнаты</small>
<ul class="nav nav-pills" id="ways">
</ul>
</div>
<div class="buttons">
<button id="night" class="btn btn-outline-primary">Ночной режим</button>
<button id="erase" class="btn btn-outline-danger">Заново</button>
</div>
</div> <!-- End of div.tools_wrapper -->
</div>
<div class="container">
<div class="row">
<div id="title" class="title">
<div class="label">
<h1>Быть Астрид</h1>
<noscript>
<p class="noscript_message">This game requires Javascript.</p>
</noscript>
</div>
</div>
</div>
<div id="content_wrapper" class="row">
<div id="intro" class="content">
<section>
<p>Вы — Астрид.</p>
<p>Астрид спит и видит себя.</p>
<p>Во сне все люди равны, потому что все они — Астрид.</p>
<noscript>You need to turn on Javascript to play this game.</noscript>
</section>
</div>
<div id="content" class="content">
</div>
<a name="end_of_content"></a>
</div>
<div id="legal" class="row">
<div id="footleft">
<p>&copy; 2017 Oreolek.</p>
</div>
<div id="footright">
</div>
</div>
</div>
</div> <!-- End of div.page -->
<!-- CDN JS Libraries -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.min.js" crossorigin="anonymous"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js" crossorigin="anonymous"></script>
<script type="text/javascript" src="game/salet.min.js"></script>
<script src="https://cdn.ably.io/lib/ably.min.js"></script>
<script type="text/javascript" defer="defer" src="game/main.js"></script>
</body>
</html>

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"dependencies": {
"gulp-rename": "^1.2.2",
"salet": "^1.6.15"
},
"private": true,
"devDependencies": {
"bootstrap": "^4.0.0-alpha.5",
"browser-sync": "^2.18.6",
"coffee-script": "^1.12.2",
"gulp": "^3.8.11",
"gulp-coffee": "^2.3.3",
"gulp-concat": "^2.6.1",
"gulp-sass": "^3.1.0",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.8",
"gulp-zip": "^3.0.2",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
}
}

17
sass/_variables.scss Normal file
View File

@ -0,0 +1,17 @@
$font-family-sans-serif: 'PT Sans','Open Sans',"Helvetica Neue", Helvetica, Arial, sans-serif;
$headings-font-family: "PT Sans Caption",$font-family-sans-serif;
$font-family-base: $font-family-sans-serif;
$body-bg: #fff;
$body-color: #000;
$link-color: blue;
$btn-bg: grey;
$btn-color: lighten($btn-bg, 50%);
$secondary-bg: #F1EED9;
$brand-primary: lighten($body-color, 20%);
$brand-danger: darken($body-bg, 30%);
$waycolor: $link-color;
$text_background: $body-bg; // can be btn-bg
$animation_duration: 2s;

152
sass/main.scss Normal file
View File

@ -0,0 +1,152 @@
@import "variables";
@import "../node_modules/bootstrap/scss/bootstrap.scss";
// The title block
.title {
margin-top: 3.5em;
@extend .col-xs-12;
.label {
margin-top: 1.5em;
margin-bottom: 1em;
@extend .col-md-8;
@extend .offset-md-2;
@extend .col-xs-12;
text-align: center;
}
.subtitle {
font-size: smaller;
color: #aaa;
}
h2 {
font-size: 1.5rem;
}
.warnings {
font-size: small;
font-style: italic;
p {
margin-bottom: 1em;
}
}
.noscript_message {
left: 0;
right: 0;
bottom: 0;
position: absolute;
font-size: 0.9em;
font-style: italic;
text-align: center;
color: #943;
}
}
#choices {
@extend .col-xs-12;
}
.fixed {
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 1000;
width: 100%;
}
#tools_wrapper {
background: $body-bg;
.ways {
padding: 0.5em;
@extend .col-md-6;
}
.buttons {
@extend .col-md-6;
text-align: right;
}
button {
display: inline-block;
}
}
#content_wrapper {
background: $text_background;
border-radius: 5px;
}
.content {
@extend .col-md-10;
@extend .offset-md-1;
@extend .col-xs-12;
padding: 1em;
ul {
margin: 0;
padding: 0 0 0 1em;
}
ul.options {
padding: 0;
text-align: center;
margin-top: 0.5em;
margin-bottom: 0.7em;
list-style-type: none;
border-radius: 4px;
li {
padding: 0.5em;
}
li:hover {
cursor: pointer;
}
li:last-child {
border-bottom: none;
}
}
section {
border-top: 1px dashed #bbb;
}
.room-start {
border-top: none;
}
h3 {
text-align: center;
}
}
#legal {
margin-top: 1em;
color: darken($body-color, 10%);
font-size: smaller;
#footleft {
@extend .col-md-5;
@extend .offset-md-2;
@extend .col-xs-12;
}
#footright {
text-align: right;
@extend .col-md-2;
@extend .offset-md-2;
@extend .col-xs-12;
}
}
.way {
color: $waycolor;
margin-right: 1em;
}
.cycle {
color: darkgreen;
border-bottom: darkgreen dashed 1px;
}
ul.options {
border: 1px solid #876;
li {
border-bottom: 1px solid #876;
}
li:hover {
background-color: rgba(153,136,119,0.2);
}
}
#legal {
.muted {
color: grey;
}
}
hr {
width: 50%;
border-color: $body-color;
}
.center {
text-align: center;
}