<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}
.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox where print preview displays the noscript content */
noscript {display:none;}
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

Also see AdvancedOptions

Get [[Eclipse 3.4|http://www.eclipse.org]]
*[''DONE''] The Wedge
**Remote scripting
**Sauerbraten scripting hooks into event flows using the Chain of Command pattern
**Simple server
*[''DONE'']Two guys in a box
**Peer sends login request
**Master sends reference to map and initial location (coordinates and orientation)
**location updates
**N player enhancements
**use Scribe instead of point-to-point messaging
**map sharing with PAST
**Wow Mode
***remote status
7/18/08 Roy: Upgrade to latest code base (2008 6/19)
# quit eclipse
# find your eclipse workspace directory
# rename .metadata to .metadata.bak
# restart eclilpse
# File->Import...
# General->Existing Projects into Workspace
# select your workspace directory as the root directory
# import the projects
Dev Features (copied from Roy's post on the cubedevblog)

*P2P Networking – All information is stored in a cloud. Models, maps, everything. No central server means that there’s no downtime, and no need to worry about which server your friends are on. Uses Free Pastry for communication. Although this is all independent of our Sauer mods, it's a big deal, so I had to mention it!

*Socket level control of Sauerbraten - We've spliced in a socket to communicate with Sauer so you can control the engine from any outside application that uses this protocol. We're writing our stuff in Groovy but you could make your own game using Python or what have you. This allows developers to use whatever language they wish.

*World of Warcraft style mouse handling - Sauers mouse handling is frightening for anything other than an FPS, so we've reworked it to be exactly like WoW's. You can even orbit the camera around your toon for screenshots. There are still some bugs/quirks with this in edit mode, but in general it makes editing Sauer maps so much easier.

*Randomly generated maze maps - Nothing too fancy, but we don't have many artists helping on the project yet so anything that up the appearance of content is good. Our sauer socket protocol has additional functions to allow external creation of maps.
*Importing of Dwarf Fortress maps - There's a popular indie game called Dwarf Fortress which uses old school ASCII style maps. We have an importer that can load these maps into Sauer using the same interface as the random maze generation.

*Custom models/costumes – I wrote a model importer that imports md2 and md3 models and creates the md3.cfg so you can load them into Sauer. We modded the engine to allow changing player models on the fly.

*Glass Pane Image Layer. Add in images and text to the hud on the fly.
*Sandboxed, mobile code (attached to maps, libraries in the cloud)
~PCs can only perform limited actions without approval
* talking
* looking around
* walking within range of the current beacon

Actions requiring approval
* moving to another beacon
* shooting things
* moving things
* opening things (doors, chests, etc.)

When a PC is awaiting approval, it FREEZES
* it doesn't queue up multiple requests and overload the moderator

The hudgun will change based on context (i.e. where the cursor is)
* walking
* interacting with an object
* interacting with a monster

* if there is one choice, indicate it with the hudgun
* if there is more than one choice
** indicate multiple with the hudgun
** pop up a menu for the player to choose an appropriate action
*Basic Interaction
**Sauerbraten uses a high performance, client/server network layer.
**Since we are using Java to control Sauerbraten, we have the option of using one of several available p2p platforms instead of Sauerbraten's networking
**This may unacceptably impact performance, but we'll start off using [[Pastry|http://freepastry.rice.edu]] and see where that leads us
**Since MUDS are more social, they may not need such rapid interaction (the ones we wrote in the late 80s were certainly a lot slower than what we can do today).
*MUD (automatic moderation)
# select the project in the Package Explorer view
# uncheck the menu item Project->Build Automatically
# choose the menu item Project->Clean...
# make sure Clean projects selected below is selected
# make sure your project is selected in the list
# click OK
# recheck Project->Build Automatically
# if the project is a groovy project, right-click on it and choose Refresh
Plexus uses the very friendly, ZLIB open source license (http://www.opensource.org/licenses/zlib-license.php):

Copyright (c) 2008 TEAM CTHULHU, Bill Burdick, Roy Riggs

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

    1. The origin of this software must not be misrepresented; you must not
    claim that you wrote the original software. If you use this software
    in a product, an acknowledgment in the product documentation would be
    appreciated but is not required.

    2. Altered source versions must be plainly marked as such, and must not be
    misrepresented as being the original software.

    3. This notice may not be removed or altered from any source
[img[TEAM CTHULHU|docs/images/cthulhu.jpg][http://teamcthulhu.com]]

[[TiddlyWiki|http://www.tiddlywiki.com]] <<version>>
groovy scripts
[DONE] Directories
*[DONE] stored by ID
*[DONE] properties file: path -> id (+ metadata)
[DONE] Root documents
*[DONE] directories stored by well known keys, and mutable
[DONE] Files
*[DONE] stored by ID
*way to save the cloud to disk that handles old versions
**save replace operation in cloud queue
**store new map
**update map list
**remove old map
**update cloud queue
*save the map list to the cloud
*way to save map to the cloud
!Mobile Code
What can you use a peer-to-peer network for?  Messaging and file sharing.  Duh.

How about a hive-mind?

We have a new feature now: Groovy code for maps.  In Sauerbraten, your map is stored in a map.ogz file.  Plexus stores each map in its own directory in your profile's cache.  You can use textures and sounds just like you would normally, store in the packages directory and also from the current map's directory, using a variable that provides the cache directory which currently contains the map.  As usualy, there is a map.cfg file, but there is also an important map.groovy file which you can provide.

Map.groovy can contain Groovy code which executes in a sandbox in the peer.  This means you can load other peoples' maps with their associated Groovy code and you don't have to worry about their code accessing your files.  We use the Java sandbox to restrict read and write access to only the map's directory (among other draconian restrictions).  Please, if you are into this sort of thing, check out our Sandbox.groovy code to verify for yourself!  So you have groovy code that can live in each map.  We also provide a mapProps map (i.e. hash table) for you which you can use to store persistent map data.  It's reinitialized when maps load, but map.groovy can save and load data with it.  And we provide a globalProps map that maps can share with each other.  We'll also provide some cloud storage access for stronger persistence.

OK, so you have code for each map.  Now you can make brains for shop keepers, traps, etc. and of course you can use this to implement game mechanics.  In the next weeks and months, we're going to implement "cloud libraries" which you can use in your map.groovy code.  This will allow people to write game mechanics and other frameworks that you can use across different maps.  We'll be upgrading the plexus cache to be a real Git cache (it already shares some ideas with Git anyway; it implements content-addressable files and directories) and you'll be able to configure your peer to back up selected parts of the cloud in your own private Git cache, for good measure. This will help protect the integrity of the cloud, since there is no central server.

That's all kind of a logical extension of what we have, but there's something more that I'm pretty interested in seeing actually run.  We plan to allow distributed control of brains.  The current idea is to make brains //relatively// stateless, so that each "tick," a brain "wakes up" and starts over (kind of like the movie Memento).  This model allows brains to transfer around between peers.  The peer in a world with an ID closest to the brain's ID will control it.  This is using a DHT to arbitrate control over the set of available brains.  When peers join or leave from a world, brains will shuffle around to accommodate the new state of the ring (Pastry nodes are arranged in a ring, according to their ~IDs).  To help manage this, brains will have two "storage areas:" a local "peer area" for incidental bookkeeping and a global "cloud area" for major information that has to be restored when a brain jarringly transfers over to another peer.

All of the peers have the code for all of the brains because they come with the map but a given brain will only have one 'pilot peer' at a time.  A world's DHT consists of only the peers in that world, not the full Plexus Pastry ring. Pastry doesn't have "subrings" right now that would make this easy to implement, but each world does use a SCRIBE topic for communication, so we can leverage that.  My current approach is to use a cloud properties object (like the one that Plexus uses for players, maps, and costumes) to assign brains to peers.  Maybe the topic root can be in charge of shuffling brains after a join or leave.  Right now, cloud properties are not stored in PAST -- they are read in by the root peer and then managed entirely with SCRIBE and direct messaging (for booting), but that can change if it's not good enough.
A primordial language of creation
!2008 6/19 Capture the Flag
Well, a new version of Sauerbraten is out: Capture the Flag (http://www.cubeengine.com/forum.php4?action=display_thread&thread_id=1782).  I made a "dist" branch and put it in there and tagged the assassin version and that one (with date tags).  I'll have to merge that into the main branch now.  Let's see how well git's famous merging capabilities work...
Here is a slippery topic.  At the most basic level, peer to peer (p2p) used to mean that applications communicate directly instead of having to use a server (or several servers).  Peer to peer has come to mean the use of an "overlay" network atop a conventional network.  There is no central control in a pure p2p network.
Plexus uses Groovy, instead of Javascript
Plexus uses Sauerbraten and SwingX, instead of a web browser (XUL and HTML)
Plexus uses Pastry for true peer-to-peer networking, instead of AJAX

<p><h2>Basic design goals and philosophy behind the p2pmud project</h2>
<p>Read this if you're interested in developing with p2pmud

<p>p2pmud is written in a combination of XUL and Javascript. XUL is an XML based language used for describing UI
 (user interface) and if you are a coding/scripting type of person you've surely heard of Javascript. Odds are
  however, you probably don't really know today's Javascript.

<p>Javascript has silently evolved over the last few years. While it started out as a clunkly little scripting 
language, it has blossomed into a very dynamic, full-featured language. Java may have gotten the spotlight 
for a long time, but its going to have to move over and make way for Javascript sometime soon.

<h2>p2pmud is a layered system</h2>
Each layer builds or relies on the previous layers beneath them. You can choose 
to pitch in and help out on the project at any layer(s) that suit you. There is a core layer, Level I, which 
provides a foundation layer. The next layer implementing actual game mechanics, is called Level II. Sometimes 
people are referred to by their Level, where Level here describes what they like to do. Someone who likes to 
create adventures and populate them with monsters and treasure is referred to Level III. They may or may not 
write anything in Javascript, they may just use what was provided by Level II. Level IV is considered a player 
who doesn't code or build at all, they just want to play. Level IV's are not to be looked down upon, after all, 
they are ultimately the ones we went to all this trouble for!

<h2 class="cmd">Level I</h2>
P2PMud at its heart implements mechanism, NOT policy. P2PMud is an enabling technology to provide the framework 
to make distributed MUDs work. It provides the ability for each local mud to discover other MUDs and create dynamic 
portals between them. We're not talking just instant messages here either. When your character steps through a portal, 
they and all their inventory are streamed across the virtual network so they actually appear in the other MUD. It also 
affords transaction base world persistence, meaning it continuously saves the state of your local MUD so it is *always* 
backed up and can be restored from any point. No matter whatever happens out there, you are safe in knowing you can always 
put things back the way they were on your own MUD. p2pmud provides access to all of this from a Javascript interface.

<h2 class="cmd">Level II</h2>
Since just a framework by itself is not very interesting, p2pmud provides a default game mechanics system (GMS) 
written in Javascript. This reference layer can be used as is to create your own world, or you can modify it as you see 
fit to build your own GMS! This is where all of the game mechanics are described and game policy is implemented. Love d20 
rules? Start a project to implement d20!

<h2 class="cmd">Level III</h2>
Even a GMS by itself is not too useful to players. If your love is building worlds and adventures, just pick a 
GMS that suits you and start building away. Each GMS will have a set of tools or commands you can use to create rooms, 
spaceships, weapons, monsters, or whatever. They likely will come will entire libraries of objects you can use to build with. 
If you get bit by the scripting bug, you too can use Javascript to implement that +20 flaming broadsword with whatever special 
powers you can dream up! Whichever GMS you choose will provide an interface for game interactions your scripts can build on.

<h2 class="cmd">Level IV</h2>
If you're screaming that you just want to play already, the intent is that each GMS comes with a default world 
that consists of a single house your character can live in. Install p2pmud and your GMS of choice. Once you've launched it, 
you can use the peer discovery to create portals to worlds created by other people. Venture out through a portal into the virtual 
world, kill the baddies and get the girl! Maybe some day you'll learn to understand why others love to build so much and choose 
to expand your own little corner of the world!

<p>Objects created in one GMS are not likely to work in another, so we expect to see a number of different virtual worlds spring 
up around each GMS. Since the GMS layers implement policy, these will likely start to develop around particular themes. For 
example, one GMS might be more suited for space adventures, one for ancient worlds, etc.
P2PMud is a peer-to-peer multiuser dungeon with a [[long history|Reloaded]]

And it's The Killer App of the Future!

The //''P2PMud [[Reloaded]]''// project adds support to the fantastic ''[[Sauerbraten|http://sauerbraten.org]]'' engine to allow remote scripting and hooking in at deep levels, with the goal of minimizing changes to the Sauerbraten source code.

Part of this is putting in hooks for moderated play, for instance, chain of command-style hooks for weapon hits.  You can register a hook that Sauerbraten calls instead of the normal hit code.  The hook may invoke a "defaulthit" command to proceed with normal damage.

[[Here|http://repo.or.cz/w/SauerbratenRemote.git?a=blob_plain;f=index.html;hb=HEAD]] is the latest version of this document and [[here|http://repo.or.cz/w/SauerbratenRemote.git]] is the source code repository.
relaying (if using Sauerbraten's server)
*to prevent, set curmsg = p.length(), otherwise it multicasts the current message
P2PMud traces its roots back to the murky depths history in 1988 when Roy Riggs first wrote a tiny multi-user dungeon in C, one of the earliest ~MMORPGs that ran over the Internet (while, maybe an MORPG, anyway.)  It took only a matter of days, or perhaps even hours, for Bill Burdick to join Roy in this glorious endevour and together they formed the sinister TEAM CTHULHU!

Since that time, TEAM CTHULHU's MUD has metamophosed many times, each time shedding its carapace to reveal something bizarrely different from its predecessor.

You can even see a reference to TEAM CTHULHU in the CREDITS file of [[LPMud|http://www.genesismud.org/]].  We came up with an idea called "forwarders" for our original MUD which became "shadows" in ~LPMud.  There's a fairly early version of ~LPMud [[here|http://ibiblio.net/pub/historic-linux/ftp-archives/sunsite.unc.edu/Nov-06-1994/games/muds/]].

#Fall 1988, Roy Riggs write a miniscule MUD in C
#Fall 1988, Bill Burdick jumps on board and we write a Franz LISP-based version, quickly switching to KCL
#Fall 1988, we switch to our own language, MOB, a multiple-inheritance, OOPL on top of LISP, with Smalltalk-like syntax in square brackets (ala Objective-C)
**over the next two years, we get 4 semesters of credit for enhancements to this version
#Summer 1990, we switch to Sean Barrett's excellent Sludge VM, which supports prototype-based inheritance.
#Spring 2002, we start p2pmud in using JXTA and Kawa, a Scheme implementation on top of Java
#Early 2004, we switch to Mozilla and Javascript.  The MUD lives entirely in one HTML file on your disk (like tiddly wiki).  Your browser hooks up to other browsers via a PHP "switchboard"
**Several releases on the p2pmud.com website
#Fall 2005, we commission Steven Missal to create Lovecraftian art
#Spring 2008, we switch to Sauerbraten, Groovy, and Pastry (on top of Java)
**remove date from directory properties so that dirs are not mistakenly unique
**if this is a new plexus version, offer to toast the cache
**make updateMappingDiag() also display results for dumpents
**cloud "power light"
**test 0 byte file uploading
**aiming/edit selection problem
**map/costume export
**cleanup connecting to existing sauer
**plexus profile editor in sauer (prepopulate wizard)
**set CPPFLAGS -DTC in src/Makefile's call to src/enet/configure
**taunt bug
**Pastry reconnect business (multiple root peers?)
**camera rotation problem on Linux
***Save hook defined in map.groovy
***Save menu choice (which calls map's save hook)
**World Building
***clean up obsolete maps
**Simple game
***use crosshairs for aiming when they are visible
***register sauer cmds for hit effects based on shooter and/or target
***show bio when you shoot someone with an examination gun
***DONE Finish tutorial menus
***DONE [replaced by map.groovy] fix bug in saveGroovyData()
***DONE [replaced by map.groovy & mapProps] persist JSON object as groovy file in map dir for metadata map development
***DONE allow turning off recoil for shots
***DONE allow user to restart plexus from sauer
**DONE cache player updates for your map so follow can teleport immediately
***DONE restore world when you restart sauer
**DONE pick random port in range
**DONE disable Launch Sauer until connected
**DONE test costume uploading
**DONE broadcast disconnect with shutting down
**DONE check java version on startup
**DONE remote guild names not showing
**DONE incoming cloud change notification to user
**DONE show feedback for unsuccessful port back-connection during ip discovery
**DONE Missing player problem -- when loading map, players clear out of sauer but not out of plexus id/name tables
**DONE Groovy version of build script
**DONE JSON format for cloud properties
**DONE (fluke?) on find map, couldn't find map with tume id instead of map id
**DONE upload/download progress notification
**DONE notification of droppage
**DONE testing peer
**DONE Clean button in prep gui
**DONE options for cleanup on start/completely fresh start
**DONE ZLIB licensing
**DONE left msg uses nodename instead of player name
**DONE switches remote player costume before d/l completed
**DONE download into temp dirs and only rename when completed
**DONE map member count is always 0
**DONE don't subscribe to map until successfully downloaded
**DONE Deadlocking?
**DONE Rework existing editing menu, much doesn't apply
**DONE decouple camera speed from players speed
**DONE Make players start off in Limbo
**DONE World portals
**DONE make LMB detach camera to orbit around the toon
**DONE make sauer load models from plexus folder
**DONE Global whispers
**DONE Map name on load screen
**DONE Make push handle regular maps (make manifest that places it in a subdir)
**DONE MapStorage
**DONE Replace map should broadcast "switchmap" pastry cmd
**DONE Message dialog: showmessage title text
**DONE make cursors load from plexus/dist
**DONE separate backup directory
**DONE Use UPnP to discover external IP address
**DONE delete player on peer disconnect
**DONE clean up players on world connection
**DONE Show connection count in world menu
**DONE Investigate occasional sauer/groovy lag on linux
**DONE Headless peer on Plubble
**DONE include UPnP to open external port in firewall
**DONE add tc_respawn command to put players back at spawn points
**DONE don't show original menu on startup
**DONE Hide Gun in First Person mode
**DONE Disable weapon swapping, disable shooting
**DONE Make Limbo map come up by default
**DONE Rename wowmode to tcmode
**DONE make cursor float above HUD
**DONE load limbo in sauer on startup
**DONE Show only filename on map thumbnails when loading
**DONE HUD add peer count
**DONE launch sauer in sep thread while connecting to pastry
**DONE add button to reload sauer
**DONE move commands from groovy init into a .cfg file
**DONE Storage
***DONE Check out out of PAST disk space errors
***DONE Global, shared directory for cloud
***DONE Costumes
**DONE Plexus topic
***DONE Presence topic for total online count
***DONE available world listing/selection from gui
***DONE Current map
***DONE Map connection count
**DONE Plubble Peer
***DONE Test
**groovy libraries in the cloud
**responsibility allocation doc for each world allocates responsibilities among the peers of a world
***when responsibilities or peers join or leave, the topic master reallocates them
***we can store doc in PAST
***probably need a world-ping
***Directory entry ownership by digital signatures (peers and groups) -- only an owner can change it
**Create, destroy, and move objects (GUIDs)
**Hidden worlds (not advertised, but part of the cloud)
**Tomb files!

!Long Term
**materials for sensors (use var to set material id) (callback set on material id)
**inventory mgmt (+ gui)
**stats (gold)
**shop keeper
**basic monster
**dead monsters drop loot
**wizard guns (create monster, move, talk, paralyze, destroy)
**saved map chunks
The Killer App of the Future! //[[Reloaded]]//
*P2PMud is currently based on the Assassin version of Sauerbraten, which you can download [[here|http://sourceforge.net/project/showfiles.php?group_id=102911&package_id=110363&release_id=563483]]
*This repository is an Eclipse project, so you'll probably want Eclipse and the CDT feature for C/C++
Once you have the stuff, you need to:
*Build the project
*Copy/link sauer_client and scripts/autoexec.cfg into the top level of the sauerbraten directory (in the same directory as server.bat).
*Start the groovy command server in Eclipse (using the Cmd Server launcher)
*Start sauer (I find it's much better to start up with the -t option when testing, so it doesn't take over my screen)
!<html><span style="background: red">HAVING PROBLEMS?</span></html>
.cthulhu {  text-decoration: none;
            color: #cccccc;
            font-family: "arial";
            font-size: 12pt;
            font-weight: medium;
            background-color: #282619;
            padding-top: 3px;
            padding-bottom: 3px;
.cmd.cthulhu {  text-decoration: none;
            color: #FF9900;
            font-family: "arial";
            font-size: 16pt;
            font-weight: medium;
a.cthulhu:link {  text-decoration: none;
             color: #FF9900; 
             font-family: "arial";
             font-size: 12pt;
             font-weight: heavy;
a.cthulhu:visited {  text-decoration: none;
             color: #FF9900; 
             font-family: "arial";
             font-size: 12pt;
             font-weight: heavy;

Use Scribe
fix orientation

Update docs to refer to new platform (Groovy/Sauerbraten) instead of old (Javascript/Mozilla)

browser plugin
Drag and drop for browser images?

master player -- invisible/intangible and does not transmit coords to the server
movement modes
	puppet -- move according to instructions (default is frozen)
	normal -- moves with limitations (movement blockers)
movement blockers
	beacons: players can move as long as they remain within the radius of at least one authorized beacon
		This allows cell-style hand off
	walls: players can pass through authorized walls

moveto id x y z -- sets id's movement target to location
gunset id model
contexthook hook -- when active, execute hook on context change for player1
usecontext on/off -- set whether player1's contexthook is active
monstersay command
authorize id blocker
unauthorize id blocker
puppet id -- makes id move toward its movement target and if it's a player unyoke the controls
unpuppet id -- makes id ignore its movement target and if it's a player, yoke the controls

move -- shoot destination, then target(s) 
authorize -- shoot blocker, then target(s)
unauthorize -- shoot blocker, then target(s)
die roll

slaverequest req
mastercommand cmd
launch gun -- sets velocity on opponents
jet pack
Acme world
*jet-skate ramp target contest: skates raise your max speed, turn on rumble pack, and apply small random adjustments to your position and orientation at random intervals
*cannon golf
might be doable with only triggers and watcher code
Guns and weapons
roman candles/wand of fireballs
physics for wall splat
monsters control assigned by DHT
map sharing includes map.groovy file in addition to map.ogz and map.cfg
Sharing with Jgit
*Each world gets a branch off the initial starting directory (a dir with a readme)
*Git tree objects are stored in PAST, cached in a local Git repo, and extracted into a local directory
##player rolls over an item
##item adds to inventory
##player presses "i" key
##inventory menu pops up
##player chooses a different item from menu
##submenu pops up
##player chooses drop
##item leaves inventory and appears on map
#Keys and Doors
##player approaches door
##door says "locked"
##player finds key and reapproaches door
##door opens
#The Shop Keeper
##player enters shop
##shop keeper says "welcome to the shop"
##player switches to shopping gun
##items are visible on the counter
##player shoots item
##menu pops up and offers buy choice
##player selects "buy" and item gets added to inventory and gold is deducted
##player shoots shop keeper
##shop keeper menu pops up and offers to buy items
Zot is one of the founding members of [[TEAM CTHULHU|http://teamcthulhu.com]]