Web: add an app for storycraft, mainly for viewing completed games at the moment
This commit is contained in:
parent
91b276ece5
commit
632a3f5e99
|
@ -99,12 +99,13 @@ INSTALLED_APPS = (
|
||||||
#'django.contrib.contenttypes',
|
#'django.contrib.contenttypes',
|
||||||
#'django.contrib.sessions',
|
#'django.contrib.sessions',
|
||||||
#'django.contrib.sites',
|
#'django.contrib.sites',
|
||||||
#'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
# Uncomment the next line to enable the admin:
|
# Uncomment the next line to enable the admin:
|
||||||
#'django.contrib.admin',
|
#'django.contrib.admin',
|
||||||
# Uncomment the next line to enable admin documentation:
|
# Uncomment the next line to enable admin documentation:
|
||||||
# 'django.contrib.admindocs',
|
# 'django.contrib.admindocs',
|
||||||
'karma',
|
'karma',
|
||||||
|
'storycraft',
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
* {
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: #333333;
|
||||||
|
background: #efefef;
|
||||||
|
font-family: 'Bitstream Vera Sans', sans-serif;
|
||||||
|
font-size: 10pt;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
background: white;
|
||||||
|
min-height: 100%;
|
||||||
|
border-left: 1px solid #666666;
|
||||||
|
border-right: 1px solid #666666;
|
||||||
|
width: 85%;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages {
|
||||||
|
background: white;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
|
||||||
|
#messages .messagelist .error {
|
||||||
|
list-style-type: none;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mainpage {
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mainpage #title {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mainpage #title h1 {
|
||||||
|
font-family: 'Cardo', 'Times New Roman', serif;
|
||||||
|
font-size: 32pt;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem {
|
||||||
|
margin: 10px;
|
||||||
|
border: 1px solid #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameinfo {
|
||||||
|
padding: 0px;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameplayers {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameinfo li {
|
||||||
|
padding: 5px;
|
||||||
|
display: table-cell;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameplayers li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameplayers li:before {
|
||||||
|
content: ", ";
|
||||||
|
}
|
||||||
|
.gameitem .gameplayers li:first-child:before {
|
||||||
|
content: "Players: ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameinfo li.gameid {
|
||||||
|
width: 30%;
|
||||||
|
background: #e0e0e0;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameinfo li.gamestatus {
|
||||||
|
width: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem .gameinfo li.gamecode {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gameitem a {
|
||||||
|
color: #333333;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storyblock {
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
margin: 0px 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.storyblock p:first-letter {
|
||||||
|
font-size: 3.5em;
|
||||||
|
line-height: 0.8em;
|
||||||
|
float: left;
|
||||||
|
margin: 0 3px 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gamestory {
|
||||||
|
font-family: 'Cardo', 'Times New Roman', serif;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
position: relative;
|
||||||
|
margin-top: -50px;
|
||||||
|
height: 50px;
|
||||||
|
clear: both;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
background: #333333;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer p {
|
||||||
|
padding-top: 10px;
|
||||||
|
font-size: 8pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
vi:tabstop=4:expandtab:autoindent
|
||||||
|
*/
|
|
@ -0,0 +1,64 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class StorycraftGame(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
round_mode = models.IntegerField()
|
||||||
|
game_length = models.IntegerField()
|
||||||
|
line_length = models.IntegerField()
|
||||||
|
random_method = models.IntegerField()
|
||||||
|
lines_per_turn = models.IntegerField()
|
||||||
|
status = models.CharField()
|
||||||
|
owner_nick = models.CharField()
|
||||||
|
owner_userhost = models.CharField()
|
||||||
|
start_time = models.DateTimeField()
|
||||||
|
end_time = models.DateTimeField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'storycraft_game'
|
||||||
|
ordering = ['id']
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
"""Return a terse summary of the vital game info."""
|
||||||
|
|
||||||
|
return '#{0:d} - created on {1:s} by {2:s}, {3:s}'.format(self.id, self.start_time, self.owner_nick, self.status)
|
||||||
|
|
||||||
|
def is_completed(self):
|
||||||
|
"""Return if this game is completed."""
|
||||||
|
|
||||||
|
return self.status == 'COMPLETED' and self.end_time
|
||||||
|
|
||||||
|
class StorycraftPlayer(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
game = models.ForeignKey(StorycraftGame)
|
||||||
|
nick = models.CharField()
|
||||||
|
userhost = models.CharField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'storycraft_player'
|
||||||
|
ordering = ['id']
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
"""Return the nick!user@host."""
|
||||||
|
|
||||||
|
return '{0:s}!{1:s}'.format(self.nick, self.userhost)
|
||||||
|
|
||||||
|
class StorycraftLine(models.Model):
|
||||||
|
id = models.IntegerField(primary_key=True)
|
||||||
|
game = models.ForeignKey(StorycraftGame)
|
||||||
|
player = models.ForeignKey(StorycraftPlayer)
|
||||||
|
line = models.TextField()
|
||||||
|
time = models.DateTimeField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'storycraft_line'
|
||||||
|
ordering = ['id']
|
||||||
|
managed = False
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
"""Just return the line."""
|
||||||
|
|
||||||
|
return '{0:s}'.format(self.line)
|
||||||
|
|
||||||
|
# vi:tabstop=4:expandtab:autoindent
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
urlpatterns = patterns('storycraft.views',
|
||||||
|
(r'^$', 'index'),
|
||||||
|
(r'^games/(?P<game_id>\d+)/$', 'game_index', dict(), 'game_index'),
|
||||||
|
)
|
||||||
|
|
||||||
|
# vi:tabstop=4:expandtab:autoindent
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
|
from django.template import RequestContext
|
||||||
|
|
||||||
|
from storycraft.models import StorycraftGame, StorycraftLine, StorycraftPlayer
|
||||||
|
|
||||||
|
def index(request):
|
||||||
|
"""Display a short list of each game (and its summary) in the system.
|
||||||
|
|
||||||
|
TODO: add paginator.
|
||||||
|
"""
|
||||||
|
|
||||||
|
games = StorycraftGame.objects.all()
|
||||||
|
return render_to_response('storycraft/index.html', {'games': games}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
def game_index(request, game_id):
|
||||||
|
"""Display one individual game's details, including the story, if it's done."""
|
||||||
|
|
||||||
|
game = get_object_or_404(StorycraftGame, pk=game_id)
|
||||||
|
players = StorycraftPlayer.objects.filter(game=game.id)
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
if game.is_completed():
|
||||||
|
lines = StorycraftLine.objects.filter(game=game.id)
|
||||||
|
|
||||||
|
return render_to_response('storycraft/game_index.html', {'game': game, 'players': players, 'lines': lines}, context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
# vi:tabstop=4:expandtab:autoindent
|
|
@ -5,6 +5,9 @@
|
||||||
<title>dr.botzo</title>
|
<title>dr.botzo</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<ul><li><a href="karma/">Karma</a></li></ul>
|
<ul>
|
||||||
|
<li><a href="karma/">Karma</a></li>
|
||||||
|
<li><a href="storycraft/">Storycraft</a></li>
|
||||||
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=Cardo&subset=latin' rel='stylesheet' type='text/css' />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>dr.botzo — Storycraft</title>
|
||||||
|
<link rel="stylesheet" href="/static/storycraft/page.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% if messages %}
|
||||||
|
<div id="messages">
|
||||||
|
<ul class="messagelist">
|
||||||
|
{% for message in messages %}
|
||||||
|
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div id="container">
|
||||||
|
<div id="mainpage">
|
||||||
|
<div id="title">
|
||||||
|
<h1>Storycraft #{{ game.id }}</h1>
|
||||||
|
</div>
|
||||||
|
<div id="gamesummary">
|
||||||
|
{% include 'storycraft/tmpl_game_summary.html' %}
|
||||||
|
</div>
|
||||||
|
{% include 'storycraft/tmpl_game_story.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'storycraft/tmpl_footer.html' %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
vi:tabstop=2:expandtab:autoindent
|
||||||
|
-->
|
|
@ -0,0 +1,41 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
|
<head>
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=Cardo&subset=latin' rel='stylesheet' type='text/css' />
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<title>dr.botzo — Storycraft</title>
|
||||||
|
<link rel="stylesheet" href="/static/storycraft/page.css" type="text/css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% if messages %}
|
||||||
|
<div id="messages">
|
||||||
|
<ul class="messagelist">
|
||||||
|
{% for message in messages %}
|
||||||
|
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div id="container">
|
||||||
|
<div id="mainpage">
|
||||||
|
<div id="title">
|
||||||
|
<h1>Storycraft</h1>
|
||||||
|
</div>
|
||||||
|
<div id="gamelist">
|
||||||
|
{% if games %}
|
||||||
|
{% for game in games %}
|
||||||
|
{% include 'storycraft/tmpl_game_summary.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<p>No storycraft games. :(</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% include 'storycraft/tmpl_footer.html' %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
vi:tabstop=2:expandtab:autoindent
|
||||||
|
-->
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div id="footer">
|
||||||
|
<p>Storycraft is a game of collaborative storytelling, intentionally leading to much insanity and nonsense. All stories were made to be funny but may not even be coherent. Void where prohibited.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
vi:tabstop=2:expandtab:autoindent
|
||||||
|
-->
|
|
@ -0,0 +1,19 @@
|
||||||
|
<div class="storyblock">
|
||||||
|
{% if game.is_completed %}
|
||||||
|
<div class="gamestory">
|
||||||
|
<p>
|
||||||
|
{% for line in lines %}
|
||||||
|
<span title="{{ line.player.nick }} @ {{ line.time }}">{{ line }}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="gamenostory">
|
||||||
|
<p>This game has not been completed yet. Come back later (or get to work).</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
vi:tabstop=2:expandtab:autoindent
|
||||||
|
-->
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="gameitem">
|
||||||
|
<ul class="gameinfo">
|
||||||
|
<li class="gameid"><span><a href="{% url game_index game.id %}">{{ game.id }} — started by {{ game.owner_nick }}</a></span></li>
|
||||||
|
<li class="gamestatus"><span>{{ game.status }}</span></li>
|
||||||
|
<li class="gamecode"><span>o:{{ game.round_mode }}[{{ game.game_length }}],{{ game.line_length }},{{ game.random_method }},{{ game.lines_per_turn }}</span></li>
|
||||||
|
</ul>
|
||||||
|
{% if players %}
|
||||||
|
<ul class="gameplayers">
|
||||||
|
{% for player in players %}
|
||||||
|
<li>{{ player.nick }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
vi:tabstop=2:expandtab:autoindent
|
||||||
|
-->
|
|
@ -8,6 +8,7 @@ urlpatterns = patterns(
|
||||||
'',
|
'',
|
||||||
(r'^$', 'index.views.index'),
|
(r'^$', 'index.views.index'),
|
||||||
(r'^karma/', include('karma.urls')),
|
(r'^karma/', include('karma.urls')),
|
||||||
|
(r'^storycraft/', include('storycraft.urls')),
|
||||||
# Example:
|
# Example:
|
||||||
# (r'^web/', include('web.foo.urls')),
|
# (r'^web/', include('web.foo.urls')),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue