* Multiple games at once

* New theme
* Network games somewhat broken
This commit is contained in:
Wanja 2012-04-09 01:29:42 +02:00
parent ff1ffc407d
commit 0539b0b114
8 changed files with 1247 additions and 128 deletions

View file

@ -0,0 +1,921 @@
/**********************************************************
GENERAL UI ELEMENTS
**********************************************************/
* {
-webkit-user-select:none; /* Prevent copy paste for all elements except text fields */
-webkit-tap-highlight-color:rgba(255, 255, 255, 0); /* set highlight color for user interaction */
margin:0;
padding:0;/* Remove default padding and margins for all elements */
-webkit-box-sizing:border-box; box-sizing:border-box;
}
input,textarea { -webkit-user-select:text; } /* allow users to select text that appears in input fields */
img { border:none; } /* Remove default borders for images */
body {
overflow-x:hidden;
-webkit-text-size-adjust:none;
font:normal 14px/18px Arial, Helvetica, sans-serif;
color:#36251B;
background:#9EA172; /* primary background color */
display:-webkit-box; /* We want to layout our first container vertically */
-webkit-box-orient:vertical; /* we want our child elements to stretch to fit the container */
-webkit-box-align:stretch;
} /* General styles that apply to elements not contained within other classes and styles */
p {
font:normal 14px/18px Arial, Helvetica, sans-serif;
color:#36251B;
background:#9EA172;
padding:16px;
} /* Paragraph class used for text areas. */
#jQui_modal {
-webkit-transform:translate3d(100%,0,0);
-webkit-backface-visibility:hidden;
z-index:9999 !important;
width:100%; height:100%;
display:none;
position:absolute; top:0px; left:-100%;
overflow:hidden;
background:rgba(54,37,27,1) !important;
-webkit-perspective:1000;
}
#modalContainer {
width:100%;
}
.horzRule {
position:relative;
display:block;
background:#E6E2B5;
width:100%; height:1px;
} /* Horizontal line. */
.jqmScrollbar { background:#E6E2B5 !important; } /* Sets the color of the scrollbar */
#jQUi {
position:absolute;
width:100%;
top:0px;
bottom:0px;
}
#jQUi > #splashscreen {
position:absolute;
top:0px;bottom:0px;
width:100%;
left:0px;
min-height:100%;
background:#9EA172 !important;
color:#E6E2B5 !important;
font-size:30px;
text-align:center;
z-index:9999;
display:block;
margin-left:auto !important; margin-right:auto !important;
padding-top:80px !important;
}
/**********************************************************
header
**********************************************************/
#jQUi > #header {
display:block;
z-index:250;
-webkit-box-sizing:border-box; box-sizing:border-box;
height:48px;
left:0px;right:0px;
background-color:#424D00;
background-image:-webkit-gradient(linear, left top, left bottom, from(#798E19), to(#424D00));
-webkit-box-shadow:0px 0px 24px rgba(54,37,27,0.4); box-shadow:0px 0px 24px rgba(54,37,27,0.4);
} /* This is masthead bar that appears at the top of the UI */
#header > h1 {
position:absolute;
overflow:hidden;
width:100%;
z-index:-11;
left:-10px;
text-align:center;
height:48px;
font:bold 24px/44px Arial, Helvetica, sans-serif;
color:#E6E2B5;
text-shadow:0px -1px rgba(54,37,27,.5);
text-align:center;
text-overflow:ellipsis;
white-space:nowrap;
} /* This is text that appears in the header at the top of the screen */
body[orient="landscape"] > #header > h1 {
margin-left:-125px;
width:250px;
} /* Updates the available text area and positioning when the screen is held in landscape orientation. */
/**********************************************************
BUTTON STYLES
**********************************************************/
#backButton {
display:block;
position:absolute;
left:0px;
top:0px;
max-width:60px;
text-overflow:ellipsis;
} /* Sets up positioning of the back button which appears in the header */
#backButton > div {
max-width:60px;
overflow:hidden;
text-overflow:ellipsis;
} /* sets up sizing and handling of excess text for the type in the back button */
.button {
position:relative;
display:inline-block;
height:36px; min-width:60px;
cursor:pointer;
font:bold 14px/34px Helvetica, Arial, sans-serif;
color:#E6E2B5;
text-decoration:none;
text-align:center;
text-shadow:0px -1px 0px rgba(54,37,27,.5);
padding:0px 8px;
border:1px solid #7C543B;
margin-top:6px; margin-left:6px;
text-overflow:ellipsis;
-webkit-border-radius:6px; border-radius:6px;
background:#7C543B;
background-image:-webkit-gradient(linear, left top, left bottom, from(#A48161), to(#7C543B));
} /* Styling for CSS-generated buttons, including the back button. These buttons can bue used anywhere in the UI. */
.button.pressed {
color:#fff;
text-shadow:0px -1px 0px rgba(54,37,27,1);
background-color:rgba(50,50,50,1);
border:1px solid rgba(54,37,27,1);
} /* behavior of button for touch interaction */
.modalbutton {
position:absolute;
top:0px;
right:5px;
height:32px;
width:58px;
line-height:32px;
z-index:9999;
}
/**********************************************************
CONTENT AREA
**********************************************************/
#content{
z-index:180;
display:block;
position:absolute;
top:48px;
bottom:62px;
left:0px;right:0px;
} /* Accounts for positioning of the content area, which is everything below the header and above the navbar. */
.panel {
-webkit-backface-visibility:hidden;
z-index:180;
width:100%;
height:100%;
display:none;
position:absolute; top:0px; left:-100%;
overflow:hidden;
background:transparent;
-webkit-perspective:1000;
} /* This class is applied to the divs that contain the various "views" or pages of the app. */
.panel > * {
-webkit-backface-visibility:hidden;
-webkit-perspective:1000;
}
/**********************************************************
TOOL BAR
**********************************************************/
/* Tool bar appears locked to the bottom of the screen. It is the primary navigation. can contain text or graphical navigation */
#navbar {
position:absolute;
bottom:0px;
z-index:1000;
text-align:center;
left:0px;right:0px;
height:62px; padding:0px 1px;
background-color:#424D00;
background-image:-webkit-gradient(linear, left top, left bottom, from(#798E19), to(#424D00));
-webkit-box-shadow:0px 0px 24px rgba(54,37,27,0.4); box-shadow:0px 0px 24px rgba(54,37,27,0.4);
}
#navbar a {
width:62px; height:62px;
overflow:hidden;
display:inline-block;
font:bold 12px/100px Helvetica, Arial, sans-serif;
color:#E6E2B5;
text-decoration:none;
text-align:center;
text-shadow:0px -1px rgba(54,37,27,.5);
margin:0px auto;
position:relative;
}
#navbar a:active, #navbar a:focus, #navbar a:active:focus, #navbar .selected { background-color:rgba(218,221,80,.2); }
#navbar .icon:before {
line-height:62px;
text-align:center;
position:absolute;
top:-10px;
left:10px;
font-size:48px;
}
/* jqMobi navbar */
#navbar a:not(:last-of-type):after {
display:block;
content:"";
width:1px;
height:60px;
float:right;
}
.jq-badge {
display:-webkit-box;
-webkit-box-direction:reverse;
position:absolute;
font-size:10px;
border:2px solid white;
color:white;
background:red;
line-height:12px;
border-radius:10px;
overflow:hidden;
text-overflow:ellipsis;
min-width:20px;
max-width:90%;
height:20px;
margin:2px;
padding:1px 4px 1px 4px;
top:2px;
right:2px;
text-align:center;
z-index:100;
}
.jq-badge.br {
bottom:2px;
right:2px;
top:auto;
left:auto;
}
.jq-badge.bl {
-webkit-box-direction:normal !important;
bottom:2px;
left:2px;
top:auto;
right:auto;
}
.jq-badge.tl {
-webkit-box-direction:normal !important;
top:2px;
left:2px;
right:auto;
bottom:auto;
}
.closebutton {
background:url('images/eco/close.png');
height:23px !important;
width:23px !important;
}
#jQUi footer { display:none; } /* Custom footers - always hidden */
#jQUi nav { display:none; } /* side menu - always hidden */
#jQUi > #menu {
z-index:200;
display:none;
width:200px; height:100%;
position:absolute;
bottom:0px; top:0px; left:-200px;
background:#493325;
-webkit-transform:translate3d(0,0,0);
-webkit-transition: all 300ms !important;
}
#menu_scroller { padding-bottom:10px; }
#menu > * {
width:90%;
margin-left:auto; margin-right:auto;
}
.jqMenuHeader {
position:relative;
text-align:left;
margin:4px 0px;
font-size:21px;
font-weight:bold;
text-transform:uppercase;
z-index:1;
color:#E6E2B5;
}
.jqMenuClose{
position:absolute;
top:5px;
right:10px;
z-index:2;
}
#menu .title {
font-size:16px;
margin-bottom:3px;
font-weight:bold;
color:#E6E2B5;
}
#menu ul {
margin:0px;
padding:0px;
margin-bottom:5px;
}
#menu ul > li {
padding-left:10px;
display:block;
width:100%; height:28px;
list-style:none;
background:inherit;
} /* A plain, non-interactive list item--best suited to a heading. */
#menu ul > li > a {
display:block;
width:100%; height:28px;
font:normal 14px/28px Helvetica, Arial, sans-serif;
color:#E6E2B5;
text-decoration:none;
border-top:1px solid #A48161;
background:#7C543B;
}
#menu ul > li > a:after { content:""; }
#menu ul > li:last-child > a { border-bottom:1px solid black; }
/* End side menu css */
.splashscreen {
background:#E6E2B5; !important;
padding-left:40px;
padding-top:30px !important;
min-height:100%;
}
/**********************************************************
UL > LI
**********************************************************/
/* A touchable, interactive list item. */
/* The unordered list/list item classes are the basis of the secondary navigation used in JQ.Mobi:the stacked, listed menu system. */
ul {
margin:0px;
padding:0px;
}
ul > li {
display:block;
width:100%; height:48px;
list-style:none;
background:#BB2620;
} /* A plain, non-interactive list item--best suited to a heading. */
ul > li > a {
display:block;
width:100%; height:48px;
font:bold 18px/48px Helvetica, Arial, sans-serif;
color:#E6E2B5;
text-decoration:none;
border-bottom:1px solid black;
padding-left:8px;
padding-right:-80px;
} /* A touchable, interactive list item. */
ul > li > a:after {
content:">";
position:absolute;
right:15px;
}
ul > li > a[selected], ul > li > a:active {
color:#E6E2B5; !important;
background:#DD4037;
} /* A selected and active states for interactive list items. */
ul > li.group {
position:relative;
top:-1px;
margin-bottom:-2px;
border-top:1px solid #666;
border-bottom:1px solid #333;
padding:1px 10px;
font-size:17px;
font-weight:bold;
color:#E6E2B5;
}
ul > li.group:first-child { top:0; }
h2 {
display:block;
width:100%; height:48px;
font:bold 18px/48px Helvetica, Arial, sans-serif;
color:#E6E2B5;
background:#006B71;
padding:0px 8px 0px 8px;
} /* Header class used for non-navigable header bars (h1 is reserved for the header) */
.collapsed:after{content:url("images/eco/collapse.png");position:absolute;top:5px;right:5px;}
.expanded:after{content:url("images/eco/expand.png");position:absolute;top:5px;right:5px;}
/**********************************************************
UI
**********************************************************/
.ui-icon {
background:#666;
background:rgba(0,0,0,.4);
background-repeat:no-repeat;
border-radius:9px;
}
.ui-loader { display: none; position: absolute; opacity: .85; z-index: 100; left: 50%; width: 200px; margin-left: -100px; margin-top: -35px; padding: 10px 30px; background: #666;background:rgba(0,0,0,.4);border-radius:9px;}
.ui-loader h1 {
font-size:15px;
text-align:center;
}
.ui-loader .ui-icon {
position:static;
display:block;
opacity:.9;
margin:0 auto;
width:35px;
height:35px;
background-color:transparent;
}
.spin {
-webkit-transform:rotate(360deg);
-webkit-animation-name:spin;
-webkit-animation-duration:1s;
-webkit-animation-iteration-count:infinite;
}
@-webkit-keyframes spin {
from { -webkit-transform:rotate(0deg); }
to { -webkit-transform:rotate(360deg); }
}
.ui-icon-loading {
background-image:url('images/eco/ajax-loader.png');
width:40px;
height:40px;
border-radius:20px;
background-size:35px 35px;
}
.ui-corner-all { border-radius:.6em; }
#jQui_mask { position:absolute; top:45%; }
/**********************************************************
FORM ELEMENTS
**********************************************************/
fieldset h4 {
text-align:left;
font:bold 18px/21px Helvetica, Arial, sans-serif;
color:#36251B;
margin-bottom:-8px; margin-top:8px;
} /* Style for subhead for a group of labels/inputs within a fieldset. */
fieldset {
margin:12px 8px;
padding:12px 18px 12px 18px;
-webkit-border-radius:5px; border-radius:5px;
outline:0;
border:1px solid #E6E2B5;
width:95%;
background:transparent;
} /* Styles the border line, background image and spacing for fieldsets. */
fieldset p {
display:block;
position:relative;
height:37px !important;
overflow:hidden;
padding:8px 0px;
font:normal 14px/10px Helvetica, Arial, sans-serif;
background:transparent;
-webkit-box-shadow:none;
} /* The paragraph within a fieldset is used as a wrapper to help manage the replacement of native input elements. */
legend {
font:bold 18px/24px Helvetica, Arial, sans-serif;
color:#36251B;
text-transform:uppercase;
overflow:hidden;
margin:0;
} /* This is the name that appears at the top left of the fieldset. */
textarea.jq-ui-forms {
display:block;
margin-top:4px; margin-bottom:18px;
padding:8px;
font:normal 1em/1.5em Helvetica, Arial, sans-serif;
color:#36251B;
border:solid 1px #493325;
outline:0;
background:#E6E2B5;
-webkit-border-radius:6px; border-radius:6px;
-webkit-box-shadow:inset 1px 1px 4px rgba(54,37,27,0.3); box-shadow:inset 1px 1px 4px rgba(54,37,27,0.3);
width:85%;
min-height:150px;
line-height:120%;
} /* These properties determine the look of textarea inputs. */
input.jq-ui-forms {
display:inline-block;
width:65%;
margin-top:4px; margin-bottom:12px;
padding:8px;
border:solid 1px #493325;
outline:0;
font:normal 1em/1.5em Helvetica, Arial, sans-serif;
color:#36251B;
background:#E6E2B5;
-webkit-border-radius:6px; border-radius:6px;
-webkit-box-shadow:inset 1px 1px 4px rgba(54,37,27,0.3); box-shadow:inset 1px 1px 4px rgba(54,37,27,0.3);
} /* These properties combine to create the look of the input fields. */
input.jq-ui-forms:hover, textarea.jq-ui-forms:hover, input.jq-ui-forms:focus, textarea.jq-ui-forms:focus { border-color:#BB2620; } /* Changes the border color of the input field while active. */
input.jq-ui-forms[type=checkbox] ,input.jq-ui-forms[type=radio] {
position:absolute;
left:0;
-webkit-appearance:none;
opacity:0;
margin-bottom:30px;
width:0px;
} /* Blocks rendering of the native radio controls. */
input.jq-ui-forms[type=checkbox] + label, input.jq-ui-forms[type=radio] + label {
float:left;
font-size:15px;
font-weight:bold;
line-height:26px; /* changing this value will change the vertical relationship to the radios & checkboxes. */
margin-left:10px;
padding-left:30px;
background:url('images/eco/custom_inputs.png') 0px 0px no-repeat;
background-repeat:none;
height:25px;
} /* Styling for the labels. */
/* Following block of paragraph classes sets up the usage of the custom radio and checkbox graphics. */
input.jq-ui-forms[type=radio] + label { background-position:0 -225px; }
input.jq-ui-forms[type=checkbox] + label { background-position:0 -25px; }
/* Styles for "checked." */
input.jq-ui-forms[type=radio]:checked + label { background-position:0 -300px; }
input.jq-ui-forms[type=radio]:hover:checked + label,
input.jq-ui-forms[type=radio]:focus:checked + label,
input.jq-ui-forms[type=radio]:checked + label:hover,
input.jq-ui-forms[type=radio]:focus:checked + label { background-position:0 -300px; }
input.jq-ui-forms[type=checkbox]:checked + label { background-position:0 -100px; }
input.jq-ui-forms[type=checkbox]:hover:checked + label,
input.jq-ui-forms[type=checkbox]:focus:checked + label,
input.jq-ui-forms[type=checkbox]:checked + label:hover,
input.jq-ui-forms[type=checkbox]:focus:checked + label { background-position:0 -100px; }
/* Styles for "hover/focus." */
input.jq-ui-forms[type=checkbox]:hover + label,
input.jq-ui-forms[type=checkbox]:focus + label,
input.jq-ui-forms[type=checkbox] + label:hover { background-position:0 -0x; }
input.jq-ui-forms[type=radio]:hover + label,
input.jq-ui-forms[type=radio]:focus + label,
input.jq-ui-forms[type=radio] + label:hover { background-position:0 -200px; }
/* Styles for "active." */
input.jq-ui-forms[type=checkbox]:active + label,
input.jq-ui-forms[type=checkbox] + label:hover:active { background-position:0 -0px; }
input.jq-ui-forms[type=radio]:active + label,
input.jq-ui-forms[type=radio] + label:hover:active { background-position:0 -200px; }
input.jq-ui-forms[type=checkbox]:active:checked + label,
input.jq-ui-forms[type=checkbox]:checked + label:hover:active { background-position:0 -100px; }
input.jq-ui-forms[type=radio]:active:checked + label,
input.jq-ui-forms[type=radio]:checked + label:hover:active { background-position:0 -300px; }
/* Styles for "disabled." */
input.jq-ui-forms[type=checkbox]:disabled + label,
input.jq-ui-forms[type=checkbox]:hover:disabled + label,
input.jq-ui-forms[type=checkbox]:focus:disabled + label,
input.jq-ui-forms[type=checkbox]:disabled + label:hover,
input.jq-ui-forms[type=checkbox]:disabled + label:hover:active { background-position:0 -175px; opacity:.5 !important; }
input.jq-ui-forms[type=radio]:disabled + label,
input.jq-ui-forms[type=radio]:hover:disabled + label,
input.jq-ui-forms[type=radio]:focus:disabled + label,
input.jq-ui-forms[type=radio]:disabled + label:hover,
input.jq-ui-forms[type=radio]:disabled + label:hover:active { background-position:0 -250px; opacity:.5 !important; }
input.jq-ui-forms[type=checkbox]:disabled:checked + label,
input.jq-ui-forms[type=checkbox]:hover:disabled:checked + label,
input.jq-ui-forms[type=checkbox]:focus:disabled:checked + label,
input.jq-ui-forms[type=checkbox]:disabled:checked + label:hover,
input.jq-ui-forms[type=checkbox]:disabled:checked + label:hover:active { background-position:0 -200px; opacity:.5 !important; }
input.jq-ui-forms[type=radio]:disabled:checked + label,
input.jq-ui-forms[type=radio]:hover:disabled:checked + label,
input.jq-ui-forms[type=radio]:focus:disabled:checked + label,
input.jq-ui-forms[type=radio]:disabled:checked + label:hover,
input.jq-ui-forms[type=radio]:disabled:checked + label:hover:active { background-position:0 -375px; opacity:.5 !important; }
input.jq-ui-forms[type=radio]:active:checked + label,
input.jq-ui-forms[type=checkbox]:active:checked + label,
input.jq-ui-forms[type=radio]:active + label,
input.jq-ui-forms[type=checkbox]:active + label,
input.jq-ui-slider[type=checkbox]:checked + label ,
input.jq-ui-slider[type=radio]:checked + label
{ background-position:-28px 0px; }
input.jq-ui-slider[type=radio]:disabled:checked + label,
input.jq-ui-slider[type=radio]:focus:disabled:checked + label,
input.jq-ui-slider[type=checkbox]:disabled:checked + label,
input.jq-ui-slider[type=checkbox]:focus:disabled:checked + label
{ background-position:-28px 0px; opacity:.7 !important;}
/* Styles for "disabled." */
input.jq-ui-slider[type=checkbox]:disabled + label,
input.jq-ui-slider[type=checkbox]:focus:disabled + label,
input.jq-ui-slider[type=radio]:disabled + label,
input.jq-ui-slider[type=radio]:focus:disabled + label
{ background-position:0 0; opacity:.7 !important; }
select[disabled]~div { opacity:.7; }
/* slider controls */
input.jq-ui-slider {
position:absolute;
left:0;
opacity:0;
-webkit-appearance:none;
} /* Blocks rendering of the native radio controls. */
input.jq-ui-slider + label {
float:left;
font-size:15px;
font-weight:normal;
line-height:24px; /* changing this value will change the vertical relationship to the radios & checkboxes. */
margin-left:10px;
padding-left:57px;
color:#fff;
background:url('images/Off-On_Slider.png') 0 0px no-repeat;
height:24px;
width:57px;
display:inline-block;
-webkit-transition:all 0.3s ease-in-out;
}
.hasMenu{
-webkit-transition: all 300ms;
position:absolute !important;
left:0px !important;
}
.hasMenu.on {
position:absolute !important;
left:200px;
}
#menu.on {
left:0px !important;
}
#badgetablet{
display:none !important;
}
@media handheld, only screen and (min-width: 768px){
.hasMenu, .hasMenu.on {
position:absolute !important;
left:256px !important;
-webkit-transition: all 0ms !important;
}
#badgephone{ display:none !important; }
#badgetablet{ display:inline-block !important; }
.jqMenuClose { display:none !important; }
nav~#menu {
z-index:200 !important;
width:256px !important;
bottom:0px !important;
height:100% !important;
display:block !important;
position:absolute !important; top:0px !important; left:0px !important;
background:rgba(29,29,28,1) !important;
-webkit-transform:translate3d(0,0,0) !important;
-webkit-transition: all 0ms !important;
}
}
/** Below are styles for plugins */
#jq_actionsheet {
position:absolute;
left:0px;
right:0px;
padding-left:10px;
padding-right:10px;
padding-top:10px;
margin:auto;
background:black;
float:left;
z-index:1000;
border-top:#fff 1px solid;
background:rgba(71,71,71,.95);
background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.4)), to(rgba(255,255,255,0)), color-stop(.08,rgba(255,255,255,.1)), color-stop(.08,rgba(255,255,255,0)));
background-image:-webkit-linear-gradient(top, rgba(255,255,255,.4) 0%, rgba(255,255,255,.1) 8%, rgba(255,255,255,0) 8%);
box-shadow:0px -1px 2px rgba(0,0,0,.4);
}
#jq_actionsheet a {
text-decoration:none;
-webkit-transition:all 0.4s ease;
text-shadow:0px -1px rgba(0,0,0,.8);
padding:0px .25em;
border:1px solid rgba(0,0,0,.8);
text-overflow:ellipsis;
-webkit-border-radius:.75em; border-radius:.75em;
background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,.4)), to(rgba(255,255,255,0)), color-stop(.5,rgba(255,255,255,.1)), color-stop(.5,rgba(255,255,255,0)));
background-image:-webkit-linear-gradient(top, rgba(255,255,255,.5) 0%, rgba(255,255,255,.2) 50%, rgba(255,255,255,0) 50%);
-webkit-box-shadow:0px 1px 1px rgba(255,255,255,0.7); box-shadow:0px 1px 1px rgba(255,255,255,0.7);
display:block;
color:white;
text-align:center;
line-height:36px;
font-size:20px;
font-weight:bold;
margin-bottom:10px;
background-color:rgba(130,130,130,1);
}
#jq_actionsheet a.selected {
background-color:rgba(150,150,150,1);
}
#jq_actionsheet a.cancel {
background-color:rgba(43,43,43,1);
}
#jq_actionsheet a.cancel.selected {
background-color:rgba(73,73,73,1);
}
#jq_actionsheet a.red {
color:white;
background-color:rgba(204,0,0,1);
}
#jq_actionsheet a.red.selected {
background-color:rgba(255,0,0,1);
}
BODY>DIV#mask{
display:block;
width:100%;
height:100%;
background:#000;
z-index: 999999;
position:absolute;
top:0;
left:0;
}
.jqPopup {
display: block;
width: 300px;
border: solid 1px #72767b;
-webkit-box-shadow: 0px 4px 6px #555, 0 0 20px rgba(255,255,255,0.5);
-webkit-border-radius: 10px;
padding: 10px;
opacity: 1;
-webkit-transform: scale(1);
-webkit-transition: all 0.20s ease-in-out;
position: absolute;
z-index: 1000000;
margin-left: auto!important;
margin-right: auto!important;
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(70,70,70,0.8)), to(rgba(0,20,20,0.8)));
}
.jqPopup >* {
color:white;
}
.jqPopup.hidden {
opacity: 0;
-webkit-transform: scale(0);
top: 50%;
left: 50%;
margin: 0px auto;
}
.jqPopup>HEADER{
font-weight:bold;
font-size:20px;
margin:0;
padding:0;
}
.jqPopup>DIV{
font-size:12px;
margin:8px;
}
.jqPopup>FOOTER{
width:100%;
text-align:center;
display:block !important;
}
.jqPopup>FOOTER>A#cancel{
float:left;
}
.jqPopup>FOOTER>A#action{
float:right;
margin-right:4px;
}
.jqPopup>FOOTER>A.center{
float:none!important;
width:80%;
margin:8px;
}/** This can be your default scrollbar class. You must use !important to override the default inline styles */
.scrollBar {
position:absolute !important;
width:5px !important;
height:20px !important;
border-radius:2px !important;
border:1px soldid black !important;
background:black !important;
opacity:0 !important;
}/*
* Since the styles are built in, you have to override values with !important
*/
/* Row of selected item */
.jqmobiSelectRowFound {
}
/* Button (radio) for the found item in the list */
.jqmobiSelectRowButtonFound{
}
/* Row for items in the list */
.jqmobiSelectRow{
}
/* button for the items in the list */
.jqmobiSelectRowButton{
}
/* class for the item text displayed */
.jqmobiSelectRowText{
}
/* Header for select box */
#jqmobiSelectBoxHeader{
}
/* div that holds the options listed*/
#jqmobiSelectBoxFix {
}

View file

@ -1,4 +1,11 @@
#backButton {
display:none;
}
#header > h1 {
z-index: 0;
}
#board {
display: table;
@ -62,14 +69,4 @@
background-color: #dd6;
}
@media only screen and (orientation:landscape) {
#header, #menu {
display: none;
}
#navbar {
display: block;
}
}

View file

@ -13,7 +13,8 @@
<script type="text/javascript" charset="utf-8" src="js/cordova-1.5.0.js"></script>
<script type="text/javascript" charset="utf-8" src="js/socket.io.min.js"></script>
<link rel="stylesheet" type="text/css" href="css/jq.ui.css" />
<link rel="stylesheet" type="text/css" href="css/jq.ui.eco.css" />
<link rel="stylesheet" type="text/css" href="css/icons.css" />
<script type="text/javascript" charset="utf-8" src="js/jq.mobi.min.js"></script>
<script type="text/javascript" charset="utf-8" src="js/jq.ui.min.js"></script>
@ -32,6 +33,7 @@
<!-- Application Code -->
<link rel="stylesheet" type="text/css" href="css/ui.css" />
<script type="text/javascript" charset="utf-8" src="js/tools.js"></script>
<script type="text/javascript" charset="utf-8" src="js/tafl.js"></script>
<script type="text/javascript" charset="utf-8" src="js/net.js"></script>
<script type="text/javascript" charset="utf-8" src="js/ui.js"></script>
@ -39,18 +41,29 @@
<body>
<div id="jQUi">
<div id="header">
<p>Score <span id="score"></span></p>
</div>
<div id="content">
<div id="main_panel" title="Androtafl" class="panel" selected="true">
<ul>
<li><a href="#game_panel" onclick="javascript:game_starter.network_game();">Network: random opponent</a></li>
<li><a href="#game_panel" onclick="javascript:game_starter.game_vs_black_ai();">Game against black AI</a></li>
<li><a href="#game_panel" onclick="javascript:game_starter.game_vs_white_ai();">Game against white AI</a></li>
</ul>
<div id="main_panel" data-load="gameStarterLoadGameList" title="Androtafl" class="panel" selected="true">
<div class="group">
<h2>New game</h2>
<ul>
<li><a href="#game_panel" onclick="javascript:game_starter.network_game();">Network: random opponent</a></li>
<li><a href="#game_panel" onclick="javascript:game_starter.game_vs_black_ai();">Game against black AI</a></li>
<li><a href="#game_panel" onclick="javascript:game_starter.game_vs_white_ai();">Game against white AI</a></li>
</ul>
</div>
<div class="group">
<h2>Open games</h2>
<ul id="game_list">
</ul>
</div>
</div>
<div id="game_panel" title="Androtafl" class="panel" scrolling="no">
<div id="game_panel" data-load="boardUiInitializeBoard" data-unload="boardUiLeaveBoard" title="Androtafl" class="panel" scrolling="no">
<div style="display: none;" id="wait_for_game">
<h2>We're looking for an opponent... Please wait...</h2>
</div>
<div id="game_container">
<div id="board"></div>
</div>
@ -58,7 +71,7 @@
</div>
<div id="navbar">
<div class="horzRule"></div>
<a href="#main" id="navbar_home" class="icon home">home</a>
<a href="#main_panel" id="navbar_home" class="icon home">home</a>
<a href="javascript:boardui.rate_current_state();" id="navbar_rate_this" class="icon">rate</a>
</div>
</div>

View file

@ -1,6 +1,8 @@
var TaflNet = {
user_id: null,
connect: function(address) {
if (!address) address = "chrummibei.ch:47413";
@ -9,13 +11,21 @@ var TaflNet = {
this.socket = s;
s.on('connect', function() {
s.emit('client.hello');
if (user_id) {
s.emit('client.hello', {user_id: this.user_id});
} else {
s.emit('client.hello');
}
});
s.on('server.hello', function(data) {
s.emit('game.find_opponent');
});
s.on('player.id.set', function(data) {
TaflNet.user_id = data.user_id;
});
s.on('game.start', function(data) {
TaflNet.on_game_start(data);
});

View file

@ -24,43 +24,50 @@ function TaflState() {
this.legal_moves_cache = null;
this.winner = null;
this.win_reason = null;
this.move_history = [];
// AI related variables
this.initial_W = null;
this.initial_B = null;
this.loadBoard = function(board) {
var i, j, pieces;
this.board = board;
this.N = board.length;
if (board[0].length !== this.N) throw "BoardNotSquare";
pieces = Tafl.count_pieces(board);
this.initial_W = pieces.W;
this.initial_B = pieces.B;
};
this.clone = function() {
var i, t = new TaflState();
for (i = 0; i < this.N; ++i) {
t.board[i] = this.board[i];
}
t.N = this.N;
t.to_move = this.to_move;
t.legal_moves_cache = this.legal_moves_cache;
t.winner = this.winner;
t.win_reason = this.win_reason;
t.initial_W = this.initial_W;
t.initial_B = this.initial_B;
return t;
}
}
TaflState.prototype.loadBoard = function(board) {
var i, j, pieces;
this.board = board;
this.N = board.length;
if (board[0].length !== this.N) throw "BoardNotSquare";
pieces = Tafl.count_pieces(board);
this.initial_W = pieces.W;
this.initial_B = pieces.B;
};
TaflState.prototype.clone = function() {
var i, t = new TaflState();
for (i = 0; i < this.N; ++i) {
t.board[i] = this.board[i];
}
t.N = this.N;
t.to_move = this.to_move;
t.legal_moves_cache = this.legal_moves_cache;
t.winner = this.winner;
t.win_reason = this.win_reason;
t.initial_W = this.initial_W;
t.initial_B = this.initial_B;
t.move_history = [];
for (i = 0; i < this.move_history.length; ++i) {
var move = this.move_history[i];
t.move_history.push([ [ move[0][0], move[0][1] ], [ move[1][0], move[1][1] ] ]);
}
return t;
};
var Tafl = {
legal_moves : function(s) {
@ -153,6 +160,8 @@ var Tafl = {
else
s.to_move = 'W';
s.move_history.push(move);
s.legal_moves_cache = null;
},

14
assets/www/js/tools.js Normal file
View file

@ -0,0 +1,14 @@
function generateRandomString(entropy) {
if (! entropy) { entropy = 8; }
var characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
var randStr = '';
for (var i = 0; i < entropy; ++i) {
randStr += characters[Math.floor(Math.random() * characters.length)];
}
return randStr;
}
var exports = {};
exports.generateRandomString = generateRandomString;

View file

@ -2,28 +2,133 @@
//Test
//TaflUnitTest();
/* Initialize and prepare the game */
var tafl_game = new TaflState();
tafl_game.loadBoard(Tafl.initialStates.Hnefatafl.board());
tafl_game.to_move = Tafl.initialStates.Hnefatafl.to_move();
var uisettings = {
notification: {
vibrate: true,
vibrate_length: 200, // in ms
beep: true,
beep_times: 1,
},
};
var storage = {
store: function(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get: function(key, deflt) {
var value = localStorage.getItem(key);
return (value !== null)?JSON.parse(value):deflt;
},
remove: function(key) {
localStorage.removeItem(key);
},
save_game: function(safegame) {
var games = storage.get('open_games', []);
var has_gameid = false;
for (var i = 0; i < games.length; ++i) {
if (games[i].id === safegame.game_id) {
has_gameid = true;
games[i].turn = safegame.game_state.move_history.length;
break;
}
}
if (has_gameid === false) {
games.push({id: safegame.game_id, name: safegame.game_name, turn: safegame.game_state.move_history.length});
storage.store('open_games', games);
}
storage.store('safegame_' + safegame.game_id, safegame);
},
};
// Hook up listeners to save game state if we're shut down
document.addEventListener("pause", killNet, false);
document.addEventListener("offline", killNet, false);
/* Create special boardui objects that handles ui related game functions */
var boardui = {
moveFrom: null,
my_color: 'W',
my_color: null,
activeField: null,
active_field: null,
max_width: null,
max_height: null,
game_state: null,
network_game: false,
is_ai: {'W': false, 'B': true },
game_name: 'Unnamed game',
game_id: null,
board_size_fixed: false,
is_ai: {'W': false, 'B': false },
init: function() {
this.max_width = document.getElementById('board').offsetWidth;
this.max_height = document.getElementById('board').offsetHeight;
if (boardui.board_size_fixed === false) {
console.log("Board size fix");
boardui.fix_board_size();
boardui.board_size_fixed = true;
}
},
load_state: function(game_state) {
if (! game_state) {
game_state = boardui.create_new_state();
} else {
// Make sure game_state is a TaflState
game_state.__proto__ = TaflState.prototype;
}
return (this.max_width > 0 && this.max_height > 0);
boardui.game_state = game_state;
boardui.fill_board(game_state.board);
},
save_game: function() {
if (! boardui.game_id) {
boardui.game_id = generateRandomString();
}
var safegame = {};
safegame.my_color = boardui.my_color;
safegame.game_id = boardui.game_id;
safegame.game_name = boardui.game_name;
safegame.is_ai = boardui.is_ai;
safegame.network_game = boardui.network_game;
// Get rid of legal_move_cache before storing
boardui.game_state.legal_move_cache = null;
safegame.game_state = boardui.game_state;
storage.save_game(safegame);
},
load_game: function(safegame) {
boardui.my_color = safegame.my_color;
boardui.game_id = safegame.game_id;
boardui.game_name = safegame.game_name;
boardui.is_ai = safegame.is_ai;
boardui.network_game = safegame.network_game;
boardui.moveFrom = null;
boardui.deactivate();
boardui.load_state(safegame.game_state);
},
create_new_state: function() {
game_state = new TaflState();
game_state.loadBoard(Tafl.initialStates.Hnefatafl.board());
game_state.to_move = Tafl.initialStates.Hnefatafl.to_move();
return game_state;
},
get_classes: function(type) {
@ -40,6 +145,8 @@ var boardui = {
fill_board: function(board) {
var N = board.length;
$("#board").empty();
for (var i = 0; i < N; ++i) {
var row = $('<div class="row"></div>');
@ -117,8 +224,12 @@ var boardui = {
},
square_clicked: function() {
if (tafl_game.to_move !== boardui.my_color) {
if (boardui.game_state === null) { return; }
console.log('game_state');
if (boardui.game_state.to_move !== boardui.my_color) {
// not my turn
console.log('not my turn');
return;
};
@ -128,10 +239,14 @@ var boardui = {
//this.style.border = '2px solid green';
if (boardui.moveFrom === null) {
if (Tafl.is_moving_color(tafl_game, [i, j])) {
console.log('wee');
console.log(boardui.game_state.to_move);
if (Tafl.is_moving_color(boardui.game_state, [i, j])) {
console.log("asd");
// Check if there is a move possible from this location
var legal_moves = Tafl.legal_moves(tafl_game);
var legal_moves = Tafl.legal_moves(boardui.game_state);
for (var k = 0; k < legal_moves.length; ++k) {
if (legal_moves[k][0][0] === i && legal_moves[k][0][1] === j) {
@ -143,6 +258,7 @@ var boardui = {
// If this is reached, no possible move from here
}
console.log("clock");
} else {
if (boardui.moveFrom[0] === i && boardui.moveFrom[1] === j) { // Deactivate active piece
boardui.moveFrom = null;
@ -153,7 +269,10 @@ var boardui = {
try {
var move = [boardui.moveFrom, [i, j]];
boardui.make_move(move);
TaflNet.send_move(move);
if (boardui.network_game === true) {
TaflNet.send_move(move);
}
boardui.moveFrom = null;
boardui.deactivate();
@ -174,22 +293,22 @@ var boardui = {
},
make_move: function(move) {
Tafl.make_move(tafl_game, move);
Tafl.make_move(boardui.game_state, move);
this.update_board(tafl_game.board);
this.update_board(boardui.game_state.board);
if (Tafl.terminal_test(tafl_game) === true) {
if (Tafl.terminal_test(boardui.game_state) === true) {
// Game ended
var win_reason;
switch(tafl_game.win_reason) {
switch(boardui.game_state.win_reason) {
case 'NoKing': win_reason = 'The King was captured.'; break;
case 'KingEscaped': win_reason = 'The King escaped.'; break;
case 'NoLegalMoves': win_reason = 'There are no legal moves.'; break;
default: win_reason = 'For a unknown reason';
}
var winner = (tafl_game.winner == 'W')?'White':'Black';
var winner = (boardui.game_state.winner == 'W')?'White':'Black';
boardui.alert(win_reason + "<br/>" + winner + " player wins.");
} else {
@ -199,72 +318,95 @@ var boardui = {
},
make_ai_move: function() {
console.log(boardui.is_ai[tafl_game.to_move]);
if (boardui.is_ai[tafl_game.to_move] !== true) {
if (boardui.is_ai[boardui.game_state.to_move] !== true) {
return;
}
// Start new thread for this
setTimeout(function() {
var ai_move = TaflAI.get_best_move(tafl_game, 2);
var ai_move = TaflAI.get_best_move(boardui.game_state, 2);
boardui.make_move(ai_move.move);
boardui.activate(ai_move.move[1][0], ai_move.move[1][1]);
boardui.notifiy(); // Notify user of the new ai move
}, 0);
},
on_leave_board: function() {
boardui.save_game();
},
alert: function(message) {
$.ui.popup(message);
this.notifiy();
},
notifiy: function() {
if (! navigator || ! navigator.notification) { return; }
if (uisettings.notification.vibrate) {
navigator.notification.vibrate(uisettings.notification.vibrate_length);
}
if (uisettings.notification.beep) {
navigator.notification.beep(uisettings.notification.beep_times);
}
},
rate_current_state: function() {
var score = TaflAI.rate_state(tafl_game);
var score = TaflAI.rate_state(boardui.game_state);
$("#score").text(score);
},
};
$().ready(function(){
// Fill board
var waitForCss = setInterval(function(){
if (boardui.init()) {
// Game init successful
clearInterval(waitForCss);
boardui.fix_board_size();
boardui.fill_board(tafl_game.board);
}
}, 50);
window.onresize = function() {
setTimeout(boardui.fix_board_size, 50);
};
/*
window.onorientationchange = function() {
console.log(window.orientation);
switch (window.orientation) {
case 90:
case -90:
boardui.fix_board_size();
break;
default:
boardui.fix_board_size();
break;
}
};
*/
});
var boardUiInitializeBoard = boardui.init;
var boardUiLeaveBoard = boardui.on_leave_board;
var game_starter = {
load_game_list: function() {
$.ui.setTitle("Androtafl");
console.log("game list");
var games = storage.get('open_games', []);
$("#game_list").empty();
for (var i = 0; i < games.length; ++i) {
//if (options !== undefined) {
$("#game_list").append('<li><a href="#game_panel" onclick="javascript:game_starter.load_game(\''+
games[i].id+'\');">' + games[i].name + ' (turn ' + games[i].turn + ')</a></li>');
//}
}
},
load_game: function(game_id) {
console.log("load game");
var safegame = storage.get("safegame_" + game_id);
if (safegame === null) {
return;
}
boardui.load_game(safegame);
},
network_game: function() {
TaflNet.connect();
document.addEventListener("pause", killNet, false);
document.addEventListener("offline", killNet, false);
$.ui.setTitle("Network game");
boardui.game_name = "Network game";
boardui.network_game = true;
$("#wait_for_game").css('display','block');
$("#game_container").css('display','none');
},
game_vs_white_ai: function() {
@ -272,6 +414,11 @@ var game_starter = {
boardui.is_ai['B'] = false;
boardui.my_color = 'B';
boardui.game_name = "You VS. CPU";
boardui.load_state();
$.ui.setTitle("You VS. CPU");
boardui.make_ai_move();
},
@ -280,12 +427,25 @@ var game_starter = {
boardui.is_ai['B'] = true;
boardui.my_color = 'W';
boardui.game_name = "CPU VS. You";
boardui.load_state();
$.ui.setTitle("CPU VS. You");
boardui.make_ai_move();
},
};
var gameStarterLoadGameList = game_starter.load_game_list; // To be accessed via data-load
TaflNet.on_game_start = function(data) {
$("#wait_for_game").css('display','none');
$("#game_container").css('display','block');
boardui.my_color = data.your_color;
boardui.game_id = data.game_id;
boardui.load_state();
var colorName = (data.your_color == 'W')?'White':'Black';
boardui.alert("Game started. You're " + colorName);
@ -294,6 +454,8 @@ TaflNet.on_game_start = function(data) {
TaflNet.on_move = function(move) {
boardui.make_move(move);
boardui.activate(move[1][0], move[1][1]);
boardui.notifiy(); // Notify the user of the opponents move
};

View file

@ -3,6 +3,7 @@
// TODO: Rewrite the initialisation to be used behind apache
var io = require('socket.io').listen(47413);
var tafllib = require('../assets/www/js/tafl');
var tools = require('../assets/www/js/tools');
var tafl = tafllib.tafl;
var games = {};
@ -11,18 +12,6 @@ var sockets_waiting = [];
var ready = function(socket) { socket.emit('ready'); };
function generateRandomString(entropy) {
if (! entropy) { entropy = 8; }
var characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
var randStr = '';
for (var i = 0; i < entropy; ++i) {
randStr += characters[Math.floor(Math.random() * characters.length)];
}
return randStr;
}
io.sockets.on('connection', function(socket) {
socket.emit('server.hello');
@ -37,11 +26,13 @@ io.sockets.on('connection', function(socket) {
socket.on('client.hello', function(user_id) {
// generate user-id
if (! user_id)
if (! user_id) {
user_id = generateRandomString(16);
socket.emit('player.id.set', user_id);
}
socket.set('player.id', user_id);
socket.emit('player.id.set', user_id);
players[user_id] = socket;
@ -61,9 +52,11 @@ io.sockets.on('connection', function(socket) {
socket.opponent = socket2;
socket2.opponent = socket;
var game_id = generateRandomString();
socket2.emit('game.start', {your_color: 'W'});
socket.emit('game.start', {your_color: 'B'});
socket2.emit('game.start', {your_color: 'W', board_id: game_id });
socket.emit('game.start', {your_color: 'B', board_id: game_id });
});
socket.on('board.get', function() {