1
0
Fork 0
Browse Source

Initial commit - Being Astrid: The Game

master
Alexander Yakovlev 5 years ago
commit
162135e13e
  1. 4
      .gitignore
  2. 121
      Gulpfile.coffee
  3. 30
      README.md
  4. 76
      game/begin.coffee
  5. 23
      game/dialogue.coffee
  6. 26
      game/phrase.coffee
  7. 15
      game/story.coffee
  8. 70
      html/index.html
  9. 21
      package.json
  10. 17
      sass/_variables.scss
  11. 152
      sass/main.scss

4
.gitignore vendored

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

121
Gulpfile.coffee

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

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

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

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

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

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

70
html/index.html

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

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

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

@ -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;
}
Loading…
Cancel
Save