Initial commit
This commit is contained in:
commit
c436ca3335
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||
*.dll filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
/build/
|
||||
/node_modules
|
||||
/yarn.lock
|
||||
/package-lock.json
|
||||
*.ink.json
|
11
README.md
Normal file
11
README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# inkjs boilerplate
|
||||
|
||||
Console commands to start working
|
||||
|
||||
1. `git clone`
|
||||
2. `npm install` or better `pnpm install`
|
||||
3. `webpack prod` and you'll have the game in the `build` folder.
|
||||
|
||||
### Screenshot
|
||||
|
||||
![Screenshot](./screenshot.png)
|
19
game/fogg.ink
Normal file
19
game/fogg.ink
Normal file
|
@ -0,0 +1,19 @@
|
|||
- I looked at Monsieur Fogg
|
||||
* ... and I could contain myself no longer.<st>Continues the story.</st>
|
||||
'What is the purpose of our journey, Monsieur?'
|
||||
'A wager,' he replied.
|
||||
* * 'A wager!'[] I returned.
|
||||
He nodded.
|
||||
* * * 'But surely that is foolishness!'
|
||||
* * * 'A most serious matter then!'
|
||||
- - - He nodded again.
|
||||
* * * 'But can we win?'
|
||||
'That is what we will endeavour to find out,' he answered.
|
||||
* * * 'A modest wager, I trust?'
|
||||
'Twenty thousand pounds,' he replied, quite flatly.
|
||||
* * * I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <>
|
||||
* * 'Ah[.'],' I replied, uncertain what I thought.
|
||||
- - After that, <>
|
||||
* ... but I said nothing<st>Ends the story</st>[] and <>
|
||||
- we passed the day in silence.
|
||||
- -> END
|
25
html/index.html
Normal file
25
html/index.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="main.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="page" class="container">
|
||||
<button id="restart" type="button" class="btn btn-warning">Restart</button>
|
||||
<div class="row">
|
||||
<div id="content" class="col"></div>
|
||||
<div class="col col-md-10 offset-md-1">
|
||||
<ul id="options">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CDN JS Libraries -->
|
||||
<script src="main.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
120
js/script.js
Normal file
120
js/script.js
Normal file
|
@ -0,0 +1,120 @@
|
|||
import jQuery from 'jquery'
|
||||
const inkjs = require('inkjs').Story;
|
||||
const entryPoint = 'game/fogg.ink.json';
|
||||
|
||||
let continueToNextChoice, displayText, loadGame, saveChoice, s;
|
||||
|
||||
saveChoice = function(index) {
|
||||
window.progress.push(index);
|
||||
return localStorage.setItem("progress", JSON.stringify(window.progress));
|
||||
};
|
||||
|
||||
displayText = function(s, interactive = true) {
|
||||
let block, delay, html, i, paragraphs, results;
|
||||
results = [];
|
||||
while (s.canContinue) {
|
||||
paragraphs = s.Continue().split("\n");
|
||||
if (interactive) {
|
||||
delay = 1000;
|
||||
}
|
||||
results.push((function() {
|
||||
let j, len, results1;
|
||||
results1 = [];
|
||||
for (j = 0, len = paragraphs.length; j < len; j++) {
|
||||
i = paragraphs[j];
|
||||
if (i !== "") {
|
||||
i = i.replace('<st>', '<span class="subtitle">');
|
||||
i = i.replace('</st>', '</span>');
|
||||
html = jQuery.parseHTML(i);
|
||||
block = jQuery('<p>').html(html);
|
||||
if (interactive) {
|
||||
block.hide();
|
||||
}
|
||||
jQuery("#content").append(block);
|
||||
if (interactive) {
|
||||
block.fadeIn(delay);
|
||||
results1.push(delay += 500);
|
||||
} else {
|
||||
results1.push(void 0);
|
||||
}
|
||||
} else {
|
||||
results1.push(void 0);
|
||||
}
|
||||
}
|
||||
return results1;
|
||||
})());
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
continueToNextChoice = function(s) {
|
||||
let choice, j, len, ref, scrollTo;
|
||||
displayText(s, true);
|
||||
scrollTo = jQuery('#options').offset().top;
|
||||
if (s.currentChoices.length > 0) {
|
||||
jQuery("#options").html("").hide();
|
||||
ref = s.currentChoices;
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
choice = ref[j];
|
||||
let text = choice.text.replace('<st>', '<span class="subtitle">');
|
||||
text = text.replace('</st>', '</span>')
|
||||
jQuery("#options").append(`<li><a href='#' id='choice-${choice.index}' data-index=${choice.index}>${text}</a></li>`);
|
||||
}
|
||||
jQuery("#options").fadeIn(500);
|
||||
} else {
|
||||
jQuery("#content").append("<p>THE END</p>");
|
||||
jQuery("#options").html("");
|
||||
}
|
||||
return jQuery('html, body').animate({
|
||||
scrollTop: scrollTo
|
||||
}, 800);
|
||||
};
|
||||
|
||||
loadGame = function(s) {
|
||||
let index, j, len, ref, results;
|
||||
ref = window.progress;
|
||||
results = [];
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
index = ref[j];
|
||||
displayText(s, false);
|
||||
results.push(s.ChooseChoiceIndex(index));
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
jQuery.ajax({
|
||||
url: entryPoint,
|
||||
dataType: 'text',
|
||||
success: function(data) {
|
||||
let progress;
|
||||
progress = localStorage.getItem("progress");
|
||||
if (progress != null) {
|
||||
window.progress = JSON.parse(progress);
|
||||
} else {
|
||||
window.progress = [];
|
||||
}
|
||||
s = new inkjs(data);
|
||||
if (window.progress !== []) {
|
||||
loadGame(s);
|
||||
}
|
||||
return continueToNextChoice(s);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery(document).on('click', "#restart", function() {
|
||||
localStorage.setItem("progress", '[]');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
jQuery(document).on('click', "#options li a", function() {
|
||||
s.ChooseChoiceIndex(jQuery(this).data("index"));
|
||||
saveChoice(jQuery(this).data("index"));
|
||||
continueToNextChoice(s);
|
||||
return false;
|
||||
});
|
||||
jQuery(document).on('click', "#options li", function() {
|
||||
s.ChooseChoiceIndex(jQuery(this).find('a').data("index"));
|
||||
saveChoice(jQuery(this).data("index"));
|
||||
continueToNextChoice(s);
|
||||
return false;
|
||||
});
|
29
package.json
Normal file
29
package.json
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"scripts": {
|
||||
"build": "webpack --config ./webpack.config.js",
|
||||
"start": "webpack-dev-server --content-base public/ --inline --port 3001",
|
||||
"prod": "./node_modules/cross-env/src/bin/cross-env.js NODE_ENV=production ./node_modules/webpack/bin/webpack.js --mode=production",
|
||||
"dev": "./node_modules/cross-env/src/bin/cross-env.js NODE_ENV=development ./node_modules/webpack/bin/webpack.js",
|
||||
"watch": "./node_modules/webpack/bin/webpack.js --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"autoprefixer": "^10.3.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
"bootstrap": "^5.1.0",
|
||||
"browser-sync": "^2.27.5",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^6.2.0",
|
||||
"execa-webpack-plugin": "^6.0.2",
|
||||
"inkjs": "^2.0.0",
|
||||
"jquery": "^3.6.0",
|
||||
"mini-css-extract-plugin": "^2.2.0",
|
||||
"postcss-loader": "^6.1.1",
|
||||
"sass": "^1.37.5",
|
||||
"sass-loader": "^12.1.0",
|
||||
"webpack": "^5.50.0",
|
||||
"webpack-cli": "^4.7.2"
|
||||
}
|
||||
}
|
3896
pnpm-lock.yaml
Normal file
3896
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
5
postcss.config.js
Normal file
5
postcss.config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
'autoprefixer': {}
|
||||
}
|
||||
}
|
BIN
screenshot.png
(Stored with Git LFS)
Normal file
BIN
screenshot.png
(Stored with Git LFS)
Normal file
Binary file not shown.
113
scss/style.scss
Normal file
113
scss/style.scss
Normal file
|
@ -0,0 +1,113 @@
|
|||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
|
||||
$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;
|
||||
|
||||
$grey-color: #cc925d;
|
||||
$body-bg: #E4CDD4;
|
||||
$content-bg: rgba(202,158,185, 0.4);
|
||||
$body-color: #3A2D42;
|
||||
$link-color: #7D6393;
|
||||
$link-button-background: rgb(202, 158, 185);
|
||||
$link-button-background-hover: $body-color;
|
||||
$link-button-foreground: $body-color;
|
||||
$link-button-foreground-hover: $body-bg;
|
||||
$status-color: #7E5980;
|
||||
$btn-bg: grey;
|
||||
$btn-color: lighten($btn-bg, 50%);
|
||||
$secondary-bg: #F1EED9;
|
||||
|
||||
$primary: $link-color;
|
||||
$brand-primary: lighten($body-color, 20%);
|
||||
$brand-danger: darken($body-bg, 30%);
|
||||
|
||||
$waycolor: $link-color;
|
||||
$animation_duration: 2s;
|
||||
|
||||
$enable-rounded: true;
|
||||
$enable-shadows: false;
|
||||
$enable-gradients: false;
|
||||
$enable-transitions: false;
|
||||
$enable-hover-media-query: false;
|
||||
$enable-grid-classes: true;
|
||||
$enable-print-styles: true;
|
||||
|
||||
$ok-color: $link-color;
|
||||
$neutral-color: brown;
|
||||
$warning-color: darkred;
|
||||
|
||||
@import 'bootstrap/scss/mixins';
|
||||
@import 'bootstrap/scss/utilities';
|
||||
@import 'bootstrap/scss/root';
|
||||
@import 'bootstrap/scss/reboot';
|
||||
@import 'bootstrap/scss/type';
|
||||
@import 'bootstrap/scss/images';
|
||||
@import 'bootstrap/scss/containers';
|
||||
@import 'bootstrap/scss/grid';
|
||||
@import 'bootstrap/scss/buttons';
|
||||
@import 'bootstrap/scss/transitions';
|
||||
|
||||
h1,h2,h3 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
h2 {
|
||||
color: #666;
|
||||
}
|
||||
#page {
|
||||
background: $content-bg;
|
||||
border-radius: 5px;
|
||||
margin-top: $font-size-base;
|
||||
padding-top: ($font-size-base / 2);
|
||||
}
|
||||
#restart {
|
||||
position: fixed;
|
||||
top: $font-size-base / 2;
|
||||
right: $font-size-base / 2;
|
||||
}
|
||||
#content {
|
||||
.subtitle {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#options {
|
||||
border: 1px solid #876;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
border-radius: 4px;
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
li {
|
||||
background-color: $link-button-background;
|
||||
padding: 0.5em;
|
||||
border-bottom: 1px solid #876;
|
||||
&,a {
|
||||
color: $link-button-foreground;
|
||||
}
|
||||
}
|
||||
li:hover {
|
||||
background-color: $link-button-background-hover;
|
||||
cursor: pointer;
|
||||
&,a {
|
||||
color: $link-button-foreground-hover;
|
||||
}
|
||||
}
|
||||
li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.subtitle {
|
||||
display: block;
|
||||
font-size: ($font-size-base * 0.9);
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.room-start {
|
||||
border-top: none;
|
||||
}
|
60
webpack.config.js
Normal file
60
webpack.config.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
const path = require('path')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const ExecaPlugin = require("execa-webpack-plugin");
|
||||
|
||||
module.exports = {
|
||||
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
|
||||
entry: [
|
||||
'./js/script.js',
|
||||
'./scss/style.scss'
|
||||
],
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin(),
|
||||
new ExecaPlugin({
|
||||
onBeforeRun: [
|
||||
{
|
||||
cmd: "inklecate",
|
||||
args: ["game/fogg.ink"],
|
||||
options: {
|
||||
cwd: process.cwd()
|
||||
}
|
||||
}
|
||||
]
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
{ from: './html/', to: '' },
|
||||
{ from: './game/*.json', to: '' },
|
||||
],
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
exclude: /(node_modules)/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.s[ac]ss$/i,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
// Translates CSS into CommonJS
|
||||
'css-loader',
|
||||
'postcss-loader',
|
||||
// Compiles Sass to CSS
|
||||
'sass-loader'
|
||||
]
|
||||
},
|
||||
]
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build')
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue