Compare commits

...

10 commits

Author SHA1 Message Date
Jeremy Penner d0af05dabf regen index 2011-03-05 16:32:53 -08:00
Jeremy Penner f0390ef49c fix typos: explanation 2011-03-05 16:32:12 -08:00
Jeremy Penner 862aef3dee readme / index.html 2011-03-05 16:26:52 -08:00
Jeremy Penner 178499f5a6 rename to kliffy 2011-03-03 22:47:56 -08:00
Jeremy Penner ee08d270a5 puzzle thoughts 2011-03-03 22:42:48 -08:00
Jeremy Penner 813f1d10e6 authors notes 2011-03-03 22:42:38 -08:00
Jeremy Penner db65294e2c rename html, add title 2011-03-03 22:42:26 -08:00
Jeremy Penner 23d3abb351 first cut at authors notes 2011-03-03 11:42:41 -08:00
Jeremy Penner 679cad5078 better verb 2011-03-03 11:42:18 -08:00
Jeremy Penner f00bc2d94c write section two 2011-03-03 11:42:10 -08:00
10 changed files with 410 additions and 21 deletions

View file

@ -30,4 +30,6 @@ MULTIPLE ACTORS:
- could provide a world-simulating primitive that action validity calls could run
GAME IDEAS:
"I'm thinking of a number"
"I'm thinking of a number"
irreversible actions (that you can, of course, reverse)

3
genindex.sh Normal file
View file

@ -0,0 +1,3 @@
cat index.header > index.html
perl ../Markdown_1.0.1/Markdown.pl readme.md >> index.html
cat index.footer >> index.html

2
index.footer Normal file
View file

@ -0,0 +1,2 @@
</body>
</html>

94
index.header Normal file
View file

@ -0,0 +1,94 @@
<html>
<head>
<title>Kliffy - Klickable Interactive Fiction For You!</title>
<style>
h1,.demobutton {
background: rgb(75,156,0);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(75,156,0)),
color-stop(1, rgb(112,224,0))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(75,156,0) 0%,
rgb(112,224,0) 100%
);
}
h1 {
text-align: center;
text-shadow: 1px 1px #88FF88;
font-size: 8em;
margin: 0px;
}
h3 {
font-style: italic;
text-align: center;
text-shadow: 1px 1px #88FF88;
font-size: 1.5em;
margin: 0px;
background:rgb(75,156,0);
}
h4 {
padding-left: 1em;
padding-right: 1em;
}
body {
margin: 0px;
background: #ccccff;
}
p {
padding-left: 2em;
padding-right: 2em;
}
pre {
margin-left: 10%;
margin-right: 10%;
padding: 0.5em;
width: 80%;
background: #AAAAAA;
border-radius: 5px;
-moz-border-radius: 5px;
}
a:visited {
color: #000077;
}
a {
color: #000044;
}
.demobutton {
background: green;
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(75,156,0)),
color-stop(1, rgb(112,224,0))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(75,156,0) 0%,
rgb(112,224,0) 100%
);
text-align: center;
margin-left: 35%;
margin-right: 35%;
border-radius: 15px;
-moz-border-radius: 15px;
padding-top: 1em;
padding-bottom: 1em;
box-shadow: 5px 5px #002200;
-webkit-box-shadow: 5px 5px #002200;
-moz-box-shadow: 5px 5px #002200;
}
.demobutton a {
color: #000044;
text-shadow: 1px 1px #88FF88;
text-decoration: none;
font-size: 2em;
}
</style>
</head>
<body>

129
index.html Normal file
View file

@ -0,0 +1,129 @@
<html>
<head>
<title>Kliffy - Klickable Interactive Fiction For You!</title>
<style>
h1,.demobutton {
background: rgb(75,156,0);
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(75,156,0)),
color-stop(1, rgb(112,224,0))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(75,156,0) 0%,
rgb(112,224,0) 100%
);
}
h1 {
text-align: center;
text-shadow: 1px 1px #88FF88;
font-size: 8em;
margin: 0px;
}
h3 {
font-style: italic;
text-align: center;
text-shadow: 1px 1px #88FF88;
font-size: 1.5em;
margin: 0px;
background:rgb(75,156,0);
}
h4 {
padding-left: 1em;
padding-right: 1em;
}
body {
margin: 0px;
background: #ccccff;
}
p {
padding-left: 2em;
padding-right: 2em;
}
pre {
margin-left: 10%;
margin-right: 10%;
padding: 0.5em;
width: 80%;
background: #AAAAAA;
border-radius: 5px;
-moz-border-radius: 5px;
}
a:visited {
color: #000077;
}
a {
color: #000044;
}
.demobutton {
background: green;
background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(75,156,0)),
color-stop(1, rgb(112,224,0))
);
background-image: -moz-linear-gradient(
center bottom,
rgb(75,156,0) 0%,
rgb(112,224,0) 100%
);
text-align: center;
margin-left: 35%;
margin-right: 35%;
border-radius: 15px;
-moz-border-radius: 15px;
padding-top: 1em;
padding-bottom: 1em;
box-shadow: 5px 5px #002200;
-webkit-box-shadow: 5px 5px #002200;
-moz-box-shadow: 5px 5px #002200;
}
.demobutton a {
color: #000044;
text-shadow: 1px 1px #88FF88;
text-decoration: none;
font-size: 2em;
}
</style>
</head>
<body><h1>Kliffy</h1>
<h3>Klickable Interactive Fiction For You!</h3>
<p><em>Kliffy</em> is an engine for writing parserless point-and-click interactive fiction, in which the entirety of the story uncovered so far is visible at all times, and the player is able to take action or undo previous actions at any point in the story.</p>
<p>Thus far, there is one proof-of-concept game written in Kliffy, which I call <a href="timemachine.html">Richard and Larry Build a Time Machine</a>. It is to be presented at the <a href="http://emshort.wordpress.com/2011/01/31/announce-if-demo-fair/">2011 IF Demo Fair</a>.</p>
<div class="demobutton"><a href="timemachine.html">Play Demo</a></div>
<hr />
<h4>For players</h4>
<p>You can always go back and change the past, in any story written using Kliffy, without losing work. If you do something on your first move, and come to regret it on your second-to-last move, Kliffy aims to let you see what will happen if you try something different without starting your game over.</p>
<p>The way it works in practice can be slightly surprising, however. I'm working to figure out the rough edges, but I'm not there yet.</p>
<p>When you take an action in Kliffy, it records it as a <em>reaction</em> to the paragraph you clicked on. As you progress through the story, you are building up chain reactions -- when thing A happens, my character reacts this way, which makes thing B happen, which makes my character react that way, etc. If you don't have a reaction to the last paragraph or two, the story will stop and wait for you to specify what the player character will do. This can be surprising if, for example, you go back to undo an action much earlier in the story -- suddenly the chain breaks, the rest of the story disappears, and it looks like your hard work has been lost! Don't worry, it hasn't. As soon as you find your new path to the next part of the story, the game will re-do everything you had told it to do after that point.</p>
<p>If you have any thoughts on this, or any other interface issue, I'd be delighted to <a href="mailto:jeremy%20dot%20penner%20at%20gmail%20dot%20com">hear from you</a>.</p>
<h4>For authors</h4>
<p>If you're interested in writing stories using Kliffy, the good news is that there is no technical reason that I'm aware of why you couldn't start today. The bad news is that stories are written in a completely undocumented dialect of XML. The worse news is that the Kliffy is likely to behave strangely or simply not display anything if you make an error in your story source code, rather than give you a useful error message. If none of these things bother you, feel free to <a href="mailto:jeremy%20dot%20penner%20at%20gmail%20dot%20com">drop me a line</a> and I'd be happy to help you get started.</p>
<h4>For developers</h4>
<p>If you are interested in the source code, simply run the following command:</p>
<pre><code>git clone http://www.information-superhighway.net/kliffy/.git
</code></pre>
<p>Be warned: It's an enormous mess, mangled to accommodate the needs of code which attempts to violate causality. Hungarian notation is used heavily with little explanation. If you would like to attempt to write your own story using Kliffy, know that there will be no error messages to guide your way if you do something wrong; your story will just cease to appear in the browser. Also, there are almost certainly bugs I'm not aware of, in addition to the handful that I am already aware of and have worked around in my story for the purposes of making the deadline.</p>
</body>
</html>

View file

@ -1,6 +1,6 @@
###
Iffy - parserless interactive fiction for the web
(c)2010 Jeremy Penner
Kliffy - Klikable Interactive Fiction For You!
(c)2010-2011 Jeremy Penner
###
#lazy enumeration
@ -176,13 +176,13 @@ class Gst
# show "previous section" link
if @rgsection.length > 1
@jDiv.append("<div class='iffy-section-nav'>#{@Link("Previous section", () => @GoBackOneSection())}</div>")
@jDiv.append("<div class='kliffy-section-nav'>#{@Link("Previous section", () => @GoBackOneSection())}</div>")
# show all nevs in section
@rgwst = null
@rgwst = @RgwstRun()
for wst in @rgwst
jDivNev = $("<div class='iffy-nev'/>")
jDivNev = $("<div class='kliffy-nev'/>")
jDivNev.append(wst.nev.StHtmlDisplay(this, wst))
@jDiv.append(jDivNev)
jDivNev.hover(dgEnter, dgLeave)
@ -191,7 +191,7 @@ class Gst
# show "next section" link
stHtmlNav = @wstLast.nev.StHtmlNextSection(this, @wstLast)
if stHtmlNav?
@jDiv.append("<div class='iffy-section-nav'>#{stHtmlNav}</div>")
@jDiv.append("<div class='kliffy-section-nav'>#{stHtmlNav}</div>")
for stId_dgOnClick in @mpstId_dgOnClick
@jDiv.find("##{stId_dgOnClick[0]}").click(stId_dgOnClick[1])
@ -205,7 +205,7 @@ class Gst
ShowMenu: (ev, dLink, rgverb) ->
@ClearMenu(true)
jMenu = $("<div class='iffy-menu'/>").hide()
jMenu = $("<div class='kliffy-menu'/>").hide()
for verb in rgverb
dgClick = ((verbT) => () => verbT.dgActivate(); @Display())(verb)
jMenuItem = $("<a href='javascript:void(0)'>#{verb.stDisplay}</a><br/>").click(dgClick)
@ -340,7 +340,7 @@ class Nev
if not fReserved
jdivTmp.append(document.importNode(dHTML, true))
stHtml = jdivTmp[0].innerHTML
"<div class='iffy-nev-ui'>#{gst.StHtmlUi(wst)}</div><div class='iffy-nev-text'>#{gst.FilterStHtml(stHtml, wst)}</div>"
"<div class='kliffy-nev-ui'>#{gst.StHtmlUi(wst)}</div><div class='kliffy-nev-text'>#{gst.FilterStHtml(stHtml, wst)}</div>"
#[word text to display] -- links to a word, usually a noun, that the player can interact with in some way.
#[word] == [word word]
@ -432,7 +432,7 @@ TemplateFromStNev = (st, wst) ->
word = wst.gst.SectionCurrent().WordByName(wst.gst, stWord)
if word? and (rgverb = word.Rgverb(wst)).length > 0
JsStringLit(wst.gst.Link(stDisplay, ((ev) -> wst.gst.ShowMenu(ev, this, rgverb)), "class='iffy-word'"))
JsStringLit(wst.gst.Link(stDisplay, ((ev) -> wst.gst.ShowMenu(ev, this, rgverb)), "class='kliffy-word'"))
else
JsStringLit(stDisplay)
MatchInWord = MatchBracket(1, 0, () -> PushText(true, StWord))
@ -509,7 +509,7 @@ class ActorPlayer
StHtmlUi: (wst) ->
if (wst.nev.player_nevIDRespondedTo?)
wst.gst.Link("Undo", (() => @RemoveResponse(wst.nev); wst.gst.Display()), "class='iffy-undo'")
wst.gst.Link("Undo", (() => @RemoveResponse(wst.nev); wst.gst.Display()), "class='kliffy-undo'")
class ActorNext
constructor: (@story) ->

37
readme.md Normal file
View file

@ -0,0 +1,37 @@
# Kliffy
### Klickable Interactive Fiction For You!
_Kliffy_ is an engine for writing parserless point-and-click interactive fiction, in which the entirety of the story uncovered so far is visible at all times, and the player is able to take action or undo previous actions at any point in the story.
Thus far, there is one proof-of-concept game written in Kliffy, which I call [Richard and Larry Build a Time Machine][1]. It is to be presented at the [2011 IF Demo Fair][2].
<div class="demobutton"><a href="timemachine.html">Play Demo</a></div>
[1]: timemachine.html
[2]: http://emshort.wordpress.com/2011/01/31/announce-if-demo-fair/
* * * * *
#### For players
You can always go back and change the past, in any story written using Kliffy, without losing work. If you do something on your first move, and come to regret it on your second-to-last move, Kliffy aims to let you see what will happen if you try something different without starting your game over.
The way it works in practice can be slightly surprising, however. I'm working to figure out the rough edges, but I'm not there yet.
When you take an action in Kliffy, it records it as a _reaction_ to the paragraph you clicked on. As you progress through the story, you are building up chain reactions -- when thing A happens, my character reacts this way, which makes thing B happen, which makes my character react that way, etc. If you don't have a reaction to the last paragraph or two, the story will stop and wait for you to specify what the player character will do. This can be surprising if, for example, you go back to undo an action much earlier in the story -- suddenly the chain breaks, the rest of the story disappears, and it looks like your hard work has been lost! Don't worry, it hasn't. As soon as you find your new path to the next part of the story, the game will re-do everything you had told it to do after that point.
If you have any thoughts on this, or any other interface issue, I'd be delighted to [hear from you][email].
#### For authors
If you're interested in writing stories using Kliffy, the good news is that there is no technical reason that I'm aware of why you couldn't start today. The bad news is that stories are written in a completely undocumented dialect of XML. The worse news is that the Kliffy is likely to behave strangely or simply not display anything if you make an error in your story source code, rather than give you a useful error message. If none of these things bother you, feel free to [drop me a line][email] and I'd be happy to help you get started.
#### For developers
If you are interested in the source code, simply run the following command:
git clone http://www.information-superhighway.net/kliffy/.git
Be warned: It's an enormous mess, mangled to accommodate the needs of code which attempts to violate causality. Hungarian notation is used heavily with little explanation. If you would like to attempt to write your own story using Kliffy, know that there will be no error messages to guide your way if you do something wrong; your story will just cease to appear in the browser. Also, there are almost certainly bugs I'm not aware of, in addition to the handful that I am already aware of and have worked around in my story for the purposes of making the deadline.
[email]: mailto:jeremy%20dot%20penner%20at%20gmail%20dot%20com

View file

@ -1,5 +1,5 @@
###
RetroChronal -- an iffy module for violating causality
RetroChronal -- a kliffy module for violating causality
Usage:
<pastresponse after="nev" future_cause="nev" [name="name"]>

View file

@ -3,39 +3,41 @@
<head>
<link rel="stylesheet" href="jqueryui/css/ui-lightness/jquery-ui-1.8.5.custom.css">
<style>
div.iffy-menu {
.kliffy-menu {
border: 1px solid #777;
position: absolute;
background-color: #eeeeee;
}
div.hover div {
.hover div {
background-color: #f2f2f2;
}
div.iffy-nev-ui {
.kliffy-nev-ui {
display: none;
}
div.hover div.iffy-nev-ui {
.hover .kliffy-nev-ui {
display: inline;
float: right;
}
// a.iffy-word:link {
// a.kliffy-word:link {
// text-decoration: none;
// color: #000000;
// }
// a.iffy-word:hover {
// a.kliffy-word:hover {
// color: #0000dd;
// }
</style>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jqueryui/js/jquery-ui-1.8.5.custom.min.js"></script>
<script type="text/javascript" src="iffy.js"></script>
<script type="text/javascript" src="kliffy.js"></script>
<script type="text/javascript">
$(document).ready(function () {
PlayStory("timemachine.xml", $("#story"));
});
</script>
<title>Richard and Larry Build a Time Machine</title>
</head>
<body>
<div style="float:right;"><b><a href="javascript:location.reload()">Restart game</a></b></div>
<div id="story" />
</body>
</html>

View file

@ -16,7 +16,7 @@
</verb>
</word>
<word name="Richard">
<verb name="how" display='Say, "What have you done?"'>
<verb name="how" display='Ask to explain'>
<p>"So, run it by me again," says Larry.</p>
<p>"I modified this [DeLorean] to send information backwards through time," says [Richard].</p>
<p>"Just information. Not matter."</p>
@ -46,8 +46,128 @@
</pastresponse>
</section>
<section name="next">
<nev name="start">
Larry is alone with the DeLorean in the lab, for the first time.
<nev name="start">
<set var="number">null</set>
<set var="fInRoom">false</set>
<set var="fBeenInRoom">false</set>
<donext nev="realstart"/>
</nev>
<nev name="realstart">
<p>"So I just write down the number I see on the screen?" says Larry.</p>
<p>"Yep," says Richard.</p>
<p>"And what does this tell us, exactly?" says Larry.</p>
<p>"Well, when you come out of the [room], I'm going to type the number you give me into the computer, which
will make it show up on the screen before you wrote it down," says Richard.</p>
<p>"And what does this tell us, exactly?" says Larry again, exasperated.</p>
<p>"A number that neither of us picked," says Richard.</p>
</nev>
<word name="room">
<verb name="Enter">
<cond>!fInRoom</cond>
<cond>!fBeenInRoom</cond>
<set var="fInRoom">true</set>
<set var="fBeenInRoom">true</set>
<p>Larry sighs and opens the door. Inside the [room] is a computer [screen].</p>
</verb>
<verb name="Leave">
<cond>fInRoom</cond>
<set var="fInRoom">false</set>
Larry goes back into the lab. [Richard] looks at him expectantly. "Well?" he asks.
</verb>
</word>
<word name="screen">
<verb name="Read">
<cond>fInRoom</cond>
$[if (number === null) {]
<p>
Larry looks at the screen. It's blank. "Well, hell," he says, feebly scanning the [room]
for another, hidden screen that might have a number on it. He doesn't find one.
</p>
$[} else {]
<p>
Larry looks at the screen. The number $(number) is displayed on it.
</p>
$[}]
<p>He looks down at his piece of [paper] for a moment.</p>
</verb>
</word>
<pastresponse after="start" future_cause="paper.write">
<set var="number">6</set>
</pastresponse>
<word name="paper">
<verb name="write" display="Write down number">
<cond>fInRoom</cond>
$[if (false) {]
<p>
Larry is at a loss for a moment, but then decides that the thing to do is to just write down a number.
He chooses six.
</p>
$[} else {]
<p>"Huh," says Larry, scrawling down a large number $(number) on his paper. "Wonder what that means."</p>
$[}]
<donext nev="room.Leave"/>
</verb>
</word>
<word name="Richard">
<verb name="give" display="Give paper" nextsection="notes">
<cond>fBeenInRoom</cond>
$[if (number === null) {]
<p>Larry shows Richard the blank piece of paper. "Nothing on the screen," he says.</p>
<p>
Richard slaps himself on the forehead. "Of course! I can't believe I didn't think of that. If you
don't show me a number, I won't type it in, which means you won't see a number, which means no paradox.
Duh. How stupid of me. Forget I even asked."
</p>
$[} else {]
<p>Larry holds up the piece of paper. "It said $(number)".</p>
<p>Richard looks quizzically at the paper. "$(number)? Are you sure?"</p>
<p>A look of alarm crosses Larry's face. "Is... is $(number) bad?"</p>
<p>"No, no, it's just I would have expected something, I don't know, more random, or meaningful, I guess,"
says Richard. "You didn't just make up some number?"</p>
<p>"Of course not!" says Larry, offended. "Go ahead and look for yourself. The screen says $(number)."</p>
<p>"No, no, I believe you," says Richard, and types a $(number) into his computer.</p>
$[}]
</verb>
</word>
</section>
<section name="notes">
<nev name="start">
<h2>Author's Notes</h2>
<p>
Hi there. That's all I've got for now. Here's some thoughts about what I'm trying to accomplish.
</p>
<p>
There are two ideas at play in this prototype. The first is that it might be interesting to see what
happens when we get rid of the parser, and simply give the player the ability to know what she is capable of
doing at any particular moment in the game. I don't see any reason why we can't create rich and interesting
worlds by doing so. What appeals to me about this idea is not just the simpler interaction from the user's
perspective, but the ability to have greater control of what the author has to model -- if something is not
important to your game, you simply don't present the option to the player. Conversely, if an interaction is
subtle or non-standard, you don't need to worry about teaching the player what the parser understands -- the
verb is there. Your job is to make it interesting.
</p>
<p>
The second is to allow the player to interact with the story at any point that he has uncovered. Quite
frankly, I am really uncomfortable making big decisions in most games. But a game should be the perfect
place to make big decisions and explore the consequences!
What bothers me is not that the consequences are unknown, but that my actions are irrevocable; that if I do
something that I later understand was foolish, I am unlikely to be given a chance to redeem myself without
playing through the game again. Always showing the player the entire story and allowing him to make changes
at any point is a promise that he will never be punished for trying something, even if his character
is; that he can learn from mistakes and move on. In this way, I can construct much harsher situations than may
ordinarily be considered "fair"; I can do away with repetition of description and dialogue "just in case" the
player forgets the vital information contained within; I can allow the player to dig himself into a hole, because
I can give him the tools to quickly dig himself out.
</p>
<p>
I guess there's the time travel bit, too. I don't advise trying it, personally; building a model of the world
in code where causality can occasionally be violated turned out to be much more difficult and time-consuming
than I expected. I have no explanation for why I would have thought coding time travel paradoxes would be easy.
</p>
<p>
I would love to hear any and all feedback about your experience playing this game. I can be reached
at jeremy dot penner at gmail dot com. Thanks for playing.
</p>
</nev>
</section>
</story>