restyled doudizhu
|
@ -10,13 +10,6 @@
|
|||
/* card itself
|
||||
********************************************************************/
|
||||
|
||||
.playingCards.unselectable {
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.playingCards {
|
||||
visibility: visible;
|
||||
transform: translateY(0) scale(1);
|
||||
|
@ -184,7 +177,7 @@
|
|||
position: absolute;
|
||||
}
|
||||
.playingCards .card.joker .rank:before {
|
||||
content: "\2605";
|
||||
content: "";
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
@ -193,9 +186,19 @@
|
|||
}
|
||||
|
||||
/* inner multiple suits */
|
||||
.playingCards .card .suit:after {
|
||||
.playingCards .card:not(full-content) .suit:after {
|
||||
display: block;
|
||||
margin-top: -.8em;
|
||||
margin-top: -.2em;
|
||||
text-align: center;
|
||||
white-space: pre;
|
||||
line-height: .9;
|
||||
font-size: 2.5em;
|
||||
word-spacing: -.05em;
|
||||
}
|
||||
|
||||
.playingCards .card.full-content .suit:after {
|
||||
display: block;
|
||||
margin-top: -.9em;
|
||||
text-align: center;
|
||||
white-space: pre;
|
||||
line-height: .9;
|
||||
|
@ -204,158 +207,170 @@
|
|||
}
|
||||
|
||||
/* make the hearts and clubs symbols fit, because they are a bit bigger than the others */
|
||||
.playingCards .card.hearts .suit:after {
|
||||
.playingCards .card.full-content.hearts .suit:after {
|
||||
word-spacing: -.15em;
|
||||
}
|
||||
.playingCards .card.hearts.rank-10 .suit:after {
|
||||
.playingCards .card.full-content.hearts.rank-10 .suit:after {
|
||||
word-spacing: -.05em;
|
||||
letter-spacing: -.1em;
|
||||
}
|
||||
.playingCards .card.clubs.rank-10 .suit:after {
|
||||
.playingCards .card.full-content.clubs.rank-10 .suit:after {
|
||||
word-spacing: -.15em;
|
||||
}
|
||||
|
||||
/* 8, 9, 10 are the most crowded */
|
||||
.playingCards .card.rank-8 .suit:after,
|
||||
.playingCards .card.rank-9 .suit:after {
|
||||
.playingCards .card.full-content.rank-8 .suit:after,
|
||||
.playingCards .card.full-content.rank-9 .suit:after {
|
||||
letter-spacing: -.075em;
|
||||
}
|
||||
.playingCards .card.rank-10 .suit:after {
|
||||
.playingCards .card.full-content.rank-10 .suit:after {
|
||||
letter-spacing: -.1em;
|
||||
}
|
||||
.playingCards .card.clubs .suit:after {
|
||||
.playingCards .card.full-content.clubs .suit:after {
|
||||
letter-spacing: -.125em;
|
||||
}
|
||||
|
||||
/*____________ symbols in the middle (suits, full) ____________*/
|
||||
|
||||
/* diamonds */
|
||||
.playingCards .card.rank-2.diams .suit:after {
|
||||
.playingCards .card.diams:not(full-content) .suit:after {
|
||||
content: "\2666";
|
||||
}
|
||||
.playingCards .card.rank-2.diams.full-content .suit:after {
|
||||
content: "\2666 \A\A\2666";
|
||||
}
|
||||
.playingCards .card.rank-3.diams .suit:after {
|
||||
.playingCards .card.rank-3.diams.full-content .suit:after {
|
||||
content: "\2666 \A\2666 \A\2666";
|
||||
}
|
||||
.playingCards .card.rank-4.diams .suit:after {
|
||||
.playingCards .card.rank-4.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\00A0\00A0\2666 \A\A\2666\00A0\00A0\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-5.diams .suit:after {
|
||||
.playingCards .card.rank-5.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\00A0\00A0\2666 \A\2666 \A\2666\00A0\00A0\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-6.diams .suit:after {
|
||||
.playingCards .card.rank-6.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\00A0\00A0\2666 \A\2666\00A0\00A0\00A0\2666 \A\2666\00A0\00A0\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-7.diams .suit:after {
|
||||
.playingCards .card.rank-7.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\00A0\2666 \A\2666\00A0\2666\00A0\2666 \A\2666\00A0\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-8.diams .suit:after {
|
||||
.playingCards .card.rank-8.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\2666\00A0\2666 \A\2666\00A0\00A0\2666 \A\2666\00A0\2666\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-9.diams .suit:after {
|
||||
.playingCards .card.rank-9.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\2666\00A0\2666 \A\2666\00A0\2666\00A0\2666 \A\2666\00A0\2666\00A0\2666";
|
||||
}
|
||||
.playingCards .card.rank-10.diams .suit:after {
|
||||
.playingCards .card.rank-10.diams.full-content .suit:after {
|
||||
content: "\2666\00A0\2666\00A0\2666 \A\2666\00A0\2666\00A0\2666\00A0\2666 \A\2666\00A0\2666\00A0\2666";
|
||||
}
|
||||
|
||||
/* hearts */
|
||||
.playingCards .card.rank-2.hearts .suit:after {
|
||||
.playingCards .card.hearts:not(full-content) .suit:after {
|
||||
content: "\2665";
|
||||
}
|
||||
.playingCards .card.rank-2.hearts.full-content .suit:after {
|
||||
content: "\2665 \A\A\2665";
|
||||
}
|
||||
.playingCards .card.rank-3.hearts .suit:after {
|
||||
.playingCards .card.rank-3.hearts.full-content .suit:after {
|
||||
content: "\2665 \A\2665 \A\2665";
|
||||
}
|
||||
.playingCards .card.rank-4.hearts .suit:after {
|
||||
.playingCards .card.rank-4.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\00A0\00A0\2665 \A\A\2665\00A0\00A0\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-5.hearts .suit:after {
|
||||
.playingCards .card.rank-5.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\00A0\00A0\2665 \A\2665 \A\2665\00A0\00A0\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-6.hearts .suit:after {
|
||||
.playingCards .card.rank-6.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\00A0\00A0\2665 \A\2665\00A0\00A0\00A0\2665 \A\2665\00A0\00A0\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-7.hearts .suit:after {
|
||||
.playingCards .card.rank-7.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\00A0\2665 \A\2665\00A0\2665\00A0\2665 \A\2665\00A0\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-8.hearts .suit:after {
|
||||
.playingCards .card.rank-8.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\2665\00A0\2665 \A\2665\00A0\00A0\2665 \A\2665\00A0\2665\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-9.hearts .suit:after {
|
||||
.playingCards .card.rank-9.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\2665\00A0\2665 \A\2665\00A0\2665\00A0\2665 \A\2665\00A0\2665\00A0\2665";
|
||||
}
|
||||
.playingCards .card.rank-10.hearts .suit:after {
|
||||
.playingCards .card.rank-10.hearts.full-content .suit:after {
|
||||
content: "\2665\00A0\2665\00A0\2665 \A\2665\00A0\2665\00A0\2665\00A0\2665 \A\2665\00A0\2665\00A0\2665";
|
||||
}
|
||||
|
||||
/* spades */
|
||||
.playingCards .card.rank-2.spades .suit:after {
|
||||
.playingCards .card.spades:not(full-content) .suit:after {
|
||||
content: "\2660";
|
||||
}
|
||||
.playingCards .card.rank-2.spades.full-content .suit:after {
|
||||
content: "\2660 \A\A\2660";
|
||||
}
|
||||
.playingCards .card.rank-3.spades .suit:after {
|
||||
.playingCards .card.rank-3.spades.full-content .suit:after {
|
||||
content: "\2660 \A\2660 \A\2660";
|
||||
}
|
||||
.playingCards .card.rank-4.spades .suit:after {
|
||||
.playingCards .card.rank-4.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\00A0\00A0\2660 \A\A\2660\00A0\00A0\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-5.spades .suit:after {
|
||||
.playingCards .card.rank-5.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\00A0\00A0\2660 \A\2660 \A\2660\00A0\00A0\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-6.spades .suit:after {
|
||||
.playingCards .card.rank-6.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\00A0\00A0\2660 \A\2660\00A0\00A0\00A0\2660 \A\2660\00A0\00A0\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-7.spades .suit:after {
|
||||
.playingCards .card.rank-7.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\00A0\2660 \A\2660\00A0\2660\00A0\2660 \A\2660\00A0\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-8.spades .suit:after {
|
||||
.playingCards .card.rank-8.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\2660\00A0\2660 \A\2660\00A0\00A0\2660 \A\2660\00A0\2660\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-9.spades .suit:after {
|
||||
.playingCards .card.rank-9.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\2660\00A0\2660 \A\2660\00A0\2660\00A0\2660 \A\2660\00A0\2660\00A0\2660";
|
||||
}
|
||||
.playingCards .card.rank-10.spades .suit:after {
|
||||
.playingCards .card.rank-10.spades.full-content .suit:after {
|
||||
content: "\2660\00A0\2660\00A0\2660 \A\2660\00A0\2660\00A0\2660\00A0\2660 \A\2660\00A0\2660\00A0\2660";
|
||||
}
|
||||
|
||||
/* clubs */
|
||||
.playingCards .card.rank-2.clubs .suit:after {
|
||||
.playingCards .card.clubs:not(full-content) .suit:after {
|
||||
content: "\2663";
|
||||
}
|
||||
.playingCards .card.rank-2.clubs.full-content .suit:after {
|
||||
content: "\2663 \A\A\2663";
|
||||
}
|
||||
.playingCards .card.rank-3.clubs .suit:after {
|
||||
.playingCards .card.rank-3.clubs.full-content .suit:after {
|
||||
content: "\2663 \A\2663 \A\2663";
|
||||
}
|
||||
.playingCards .card.rank-4.clubs .suit:after {
|
||||
.playingCards .card.rank-4.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\00A0\00A0\2663 \A\A\2663\00A0\00A0\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-5.clubs .suit:after {
|
||||
.playingCards .card.rank-5.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\00A0\00A0\2663 \A\2663 \A\2663\00A0\00A0\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-6.clubs .suit:after {
|
||||
.playingCards .card.rank-6.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\00A0\00A0\2663 \A\2663\00A0\00A0\00A0\2663 \A\2663\00A0\00A0\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-7.clubs .suit:after {
|
||||
.playingCards .card.rank-7.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\00A0\2663 \A\2663\00A0\2663\00A0\2663 \A\2663\00A0\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-8.clubs .suit:after {
|
||||
.playingCards .card.rank-8.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\2663\00A0\2663 \A\2663\00A0\00A0\2663 \A\2663\00A0\2663\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-9.clubs .suit:after {
|
||||
.playingCards .card.rank-9.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\2663\00A0\2663 \A\2663\00A0\2663\00A0\2663 \A\2663\00A0\2663\00A0\2663";
|
||||
}
|
||||
.playingCards .card.rank-10.clubs .suit:after {
|
||||
.playingCards .card.rank-10.clubs.full-content .suit:after {
|
||||
content: "\2663\00A0\2663\00A0\2663 \A\2663\00A0\2663\00A0\2663\00A0\2663 \A\2663\00A0\2663\00A0\2663";
|
||||
}
|
||||
|
||||
/*____________ symbols in the middle (faces as images) ____________*/
|
||||
|
||||
.playingCards.faceImages .card.rank-j .suit:after,
|
||||
.playingCards.faceImages .card.rank-q .suit:after,
|
||||
.playingCards.faceImages .card.rank-k .suit:after {
|
||||
.playingCards.faceImages .card.rank-j.full-content .suit:after,
|
||||
.playingCards.faceImages .card.rank-q.full-content .suit:after,
|
||||
.playingCards.faceImages .card.rank-k.full-content .suit:after {
|
||||
content: '';
|
||||
}
|
||||
.playingCards.faceImages .card.rank-j,
|
||||
.playingCards.faceImages .card.rank-q,
|
||||
.playingCards.faceImages .card.rank-k,
|
||||
.playingCards.faceImages .card.joker {
|
||||
.playingCards.faceImages .card.rank-j.full-content,
|
||||
.playingCards.faceImages .card.rank-q.full-content,
|
||||
.playingCards.faceImages .card.rank-k.full-content,
|
||||
.playingCards.faceImages .card.joker.full-content {
|
||||
background-repeat: no-repeat;
|
||||
background-position: -1em 0;
|
||||
/* @change: smaller cards: more negative distance from the left
|
||||
|
@ -394,11 +409,11 @@
|
|||
/*____________ symbols in the middle (faces as dingbat symbols) ____________*/
|
||||
|
||||
.playingCards.simpleCards .card .suit:after,
|
||||
.playingCards .card.rank-j .suit:after,
|
||||
.playingCards .card.rank-q .suit:after,
|
||||
.playingCards .card.rank-k .suit:after,
|
||||
.playingCards .card.rank-a .suit:after,
|
||||
.playingCards .card.joker .rank:after {
|
||||
.playingCards .card.rank-j.full-content .suit:after,
|
||||
.playingCards .card.rank-q.full-content .suit:after,
|
||||
.playingCards .card.rank-k.full-content .suit:after,
|
||||
.playingCards .card.rank-a.full-content .suit:after,
|
||||
.playingCards .card.joker.full-content .rank:after {
|
||||
font-family: Georgia, serif;
|
||||
position: absolute;
|
||||
font-size: 3em;
|
||||
|
@ -424,9 +439,12 @@
|
|||
}
|
||||
.playingCards .card.joker .rank:after {
|
||||
position: absolute;
|
||||
content: "\2766";
|
||||
top: .4em;
|
||||
left: .1em;
|
||||
content: "JOKER";
|
||||
writing-mode: vertical-lr;
|
||||
font-weight: bold;
|
||||
font-size: 0.8em;
|
||||
top: 0;
|
||||
left: -0.1em;
|
||||
}
|
||||
|
||||
/* big suits in middle */
|
||||
|
@ -519,6 +537,35 @@
|
|||
.playingCards ul.hand li {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.playingCards.loose ul.hand li:nth-child(1) { left: 0; }
|
||||
.playingCards.loose ul.hand li:nth-child(2) { left: 1.4em; }
|
||||
.playingCards.loose ul.hand li:nth-child(3) { left: 2.8em; }
|
||||
.playingCards.loose ul.hand li:nth-child(4) { left: 4.2em; }
|
||||
.playingCards.loose ul.hand li:nth-child(5) { left: 5.6em; }
|
||||
.playingCards.loose ul.hand li:nth-child(6) { left: 7.0em; }
|
||||
.playingCards.loose ul.hand li:nth-child(7) { left: 8.4em; }
|
||||
.playingCards.loose ul.hand li:nth-child(8) { left: 9.8em; }
|
||||
.playingCards.loose ul.hand li:nth-child(9) { left: 11.2em; }
|
||||
.playingCards.loose ul.hand li:nth-child(10) { left: 12.6em; }
|
||||
.playingCards.loose ul.hand li:nth-child(11) { left: 14.0em; }
|
||||
.playingCards.loose ul.hand li:nth-child(12) { left: 15.4em; }
|
||||
.playingCards.loose ul.hand li:nth-child(13) { left: 16.8em; }
|
||||
|
||||
.playingCards.loose ul.hand li:nth-child(14) { left: 18.2em; }
|
||||
.playingCards.loose ul.hand li:nth-child(15) { left: 19.6em; }
|
||||
.playingCards.loose ul.hand li:nth-child(16) { left: 21em; }
|
||||
.playingCards.loose ul.hand li:nth-child(17) { left: 22.4em; }
|
||||
.playingCards.loose ul.hand li:nth-child(18) { left: 23.8em; }
|
||||
.playingCards.loose ul.hand li:nth-child(19) { left: 25.2em; }
|
||||
.playingCards.loose ul.hand li:nth-child(20) { left: 26.6em; }
|
||||
.playingCards.loose ul.hand li:nth-child(21) { left: 28em; }
|
||||
.playingCards.loose ul.hand li:nth-child(22) { left: 29.4em; }
|
||||
.playingCards.loose ul.hand li:nth-child(23) { left: 30.8em; }
|
||||
.playingCards.loose ul.hand li:nth-child(24) { left: 32.2em; }
|
||||
.playingCards.loose ul.hand li:nth-child(25) { left: 33.6em; }
|
||||
.playingCards.loose ul.hand li:nth-child(26) { left: 35em; }
|
||||
|
||||
.playingCards ul.hand li:nth-child(1) { left: 0; }
|
||||
.playingCards ul.hand li:nth-child(2) { left: 1.1em; }
|
||||
.playingCards ul.hand li:nth-child(3) { left: 2.2em; }
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
@import "cards.css";
|
||||
|
||||
.doudizhu-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FEF9E7;
|
||||
background-image: url("./images/table.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 70%;
|
||||
background-position: bottom;
|
||||
position: relative;
|
||||
|
||||
.played-card-area {
|
||||
font-size: 12px;
|
||||
|
@ -7,6 +16,37 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.timer.fade-in {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.timer.fade-out {
|
||||
visibility: hidden;
|
||||
transition: visibility 0.1s, opacity 0.05s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.timer {
|
||||
visibility: visible;
|
||||
transition: visibility 0s, opacity 0.2s, transform 0.3s;
|
||||
opacity: 1;
|
||||
width: 51px;
|
||||
height: 60px;
|
||||
.timer-text {
|
||||
color: #303133;
|
||||
margin-top: 3px;
|
||||
font-size: 23px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 2px #909399;
|
||||
line-height: 57px;
|
||||
}
|
||||
text-align: center;
|
||||
background-image: url("./images/timer.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.non-card {
|
||||
display: table;
|
||||
width: 280px;
|
||||
|
@ -16,7 +56,13 @@
|
|||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-size: 23px;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 2px 2px rgba(0, 0, 0, 0.87);
|
||||
//letter-spacing: -4px;
|
||||
color: #F2F6FC;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,14 +82,11 @@
|
|||
font-size: 16px;
|
||||
width: 130px;
|
||||
height: 130px;
|
||||
border-radius: 25px;
|
||||
border: 2px solid #73AD21;
|
||||
display: table;
|
||||
|
||||
div {
|
||||
text-align: center;
|
||||
}
|
||||
span {
|
||||
white-space: pre;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +218,7 @@
|
|||
}
|
||||
|
||||
.non-card {
|
||||
height: 138px;
|
||||
height: 70px;
|
||||
//transform: translateY(-25px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,77 @@
|
|||
.progress-bar {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
width: 1000px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
|
||||
.stretch {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.github-info {
|
||||
flex: 0 100px;
|
||||
cursor: pointer;
|
||||
transition: color 0.5s ease;
|
||||
|
||||
&:hover{
|
||||
transition: color 0.5s ease;
|
||||
color: #C0C4CC;
|
||||
}
|
||||
|
||||
.github-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
.MuiSvgIcon-root {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
.github-text {
|
||||
left: 45px;
|
||||
line-height: 18px;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
font-size: 18px;
|
||||
-ms-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
span {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 1px;
|
||||
-ms-transform:scale(1, 1.1) translateY(-1px);
|
||||
-webkit-transform:scale(1, 1.1) translateY(-1px);
|
||||
-moz-transform:scale(1, 1.1) translateY(-1px);
|
||||
-o-transform:scale(1, 1.1) translateY(-1px);
|
||||
|
||||
.subtitle {
|
||||
color: #C0C4CC;
|
||||
margin-left: 11px;
|
||||
font-size: 16px;
|
||||
-ms-transform: translateY(3px);
|
||||
-webkit-transform: translateY(3px);
|
||||
-moz-transform: translateY(3px);
|
||||
-o-transform: translateY(3px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.game-controller {
|
||||
//width: calc(100% - 20px*2);
|
||||
//padding: 20px;
|
||||
//.el-row {
|
||||
// margin-bottom: 10px;
|
||||
//}
|
||||
.game-controller-paper {
|
||||
margin: 5px;
|
||||
padding: 2px 10px;
|
||||
|
@ -31,6 +96,7 @@
|
|||
|
||||
.doudizhu-view-container {
|
||||
width: 1000px;
|
||||
margin-top: 5px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
|
|
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 526 KiB |
After Width: | Height: | Size: 13 KiB |
|
@ -11,3 +11,10 @@ code {
|
|||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
.unselectable {
|
||||
pointer-events: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
|
@ -2,7 +2,12 @@ import React from 'react';
|
|||
import { translateCardData, millisecond2Second, computeHandCardsWidth } from '../../utils'
|
||||
|
||||
import '../../assets/doudizhu.scss';
|
||||
import {fade} from "@material-ui/core";
|
||||
import Landlord_wName from '../../assets/images/Portrait/Landlord_wName.png';
|
||||
import Peasant_wName from '../../assets/images/Portrait/Peasant_wName.png';
|
||||
import PlaceHolderPlayer from '../../assets/images/Portrait/Player.png';
|
||||
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
|
||||
class DoudizhuGameBoard extends React.Component {
|
||||
constructor(props) {
|
||||
|
@ -10,12 +15,48 @@ class DoudizhuGameBoard extends React.Component {
|
|||
|
||||
}
|
||||
|
||||
computePlayerPortrait(playerId, playerIdx){
|
||||
if(this.props.playerInfo.length > 0){
|
||||
return this.props.playerInfo[playerIdx].role === "landlord" ?
|
||||
<div>
|
||||
<img src={Landlord_wName} alt={"Landlord"} height="70%" width="70%" />
|
||||
<Chip
|
||||
avatar={<Avatar>ID</Avatar>}
|
||||
label={playerId}
|
||||
clickable
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
:
|
||||
<div>
|
||||
<img src={Peasant_wName} alt={"Peasant"} height="70%" width="70%" />
|
||||
<Chip
|
||||
avatar={<Avatar>ID</Avatar>}
|
||||
label={playerId}
|
||||
clickable
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
}else
|
||||
return (
|
||||
<div>
|
||||
<img src={PlaceHolderPlayer} alt={"Player"} height="70%" width="70%" />
|
||||
<Chip
|
||||
avatar={<Avatar>ID</Avatar>}
|
||||
label={playerId}
|
||||
clickable
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
computeSingleLineHand(cards, fadeClassName="") {
|
||||
if(cards === "P"){
|
||||
return <div className="non-card"><span>Pass</span></div>
|
||||
return <div className="non-card"><span>PASS</span></div>
|
||||
}else{
|
||||
return (
|
||||
<div className={"playingCards unselectable "+fadeClassName}>
|
||||
<div className={"playingCards unselectable loose "+fadeClassName}>
|
||||
<ul className="hand" style={{width: computeHandCardsWidth(cards.length, 12)}}>
|
||||
{cards.map(card=>{
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
|
@ -46,7 +87,7 @@ class DoudizhuGameBoard extends React.Component {
|
|||
return (
|
||||
<div>
|
||||
<div className="player-hand-up">
|
||||
<div className="playingCards unselectable">
|
||||
<div className="playingCards unselectable loose">
|
||||
<ul className="hand">
|
||||
{upCards.map(card => {
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
|
@ -63,7 +104,7 @@ class DoudizhuGameBoard extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
<div className="player-hand-down">
|
||||
<div className="playingCards unselectable">
|
||||
<div className="playingCards unselectable loose">
|
||||
<ul className="hand">
|
||||
{downCards.map(card => {
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
|
@ -84,15 +125,18 @@ class DoudizhuGameBoard extends React.Component {
|
|||
}
|
||||
|
||||
playerDecisionArea(playerIdx){
|
||||
if(this.props.currentPlayer === playerIdx){
|
||||
return <div className="non-card"><span>{`Consideration Time: ${millisecond2Second(this.props.considerationTime)}s`}</span></div>
|
||||
}else{
|
||||
|
||||
let fadeClassName = "";
|
||||
if(this.props.toggleFade === "fade-out" && (playerIdx+2)%3 === this.props.currentPlayer)
|
||||
fadeClassName = "fade-out";
|
||||
else if(this.props.toggleFade === "fade-in" && (playerIdx+1)%3 === this.props.currentPlayer)
|
||||
fadeClassName = "scale-fade-in";
|
||||
if(this.props.currentPlayer === playerIdx){
|
||||
return (
|
||||
<div className={"timer "+fadeClassName}>
|
||||
<div className="timer-text">{millisecond2Second(this.props.considerationTime)}</div>
|
||||
</div>
|
||||
)
|
||||
}else{
|
||||
return this.computeSingleLineHand(this.props.latestAction[playerIdx], fadeClassName)
|
||||
}
|
||||
}
|
||||
|
@ -128,11 +172,11 @@ class DoudizhuGameBoard extends React.Component {
|
|||
leftId = found.id;
|
||||
}
|
||||
return (
|
||||
<div className="doudizhu-wrapper" style={{width: "100%", height: "100%", backgroundColor: "#ffcc99", position: "relative"}}>
|
||||
<div className="doudizhu-wrapper" style={{}}>
|
||||
<div id={"left-player"}>
|
||||
<div className="player-main-area">
|
||||
<div className="player-info">
|
||||
<span>{`Player Id ${leftId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[leftIdx].role : ""}`}</span>
|
||||
{this.computePlayerPortrait(leftId, leftIdx)}
|
||||
</div>
|
||||
{leftIdx >= 0 ? this.computeSideHand(this.props.hands[leftIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
|
||||
</div>
|
||||
|
@ -143,7 +187,7 @@ class DoudizhuGameBoard extends React.Component {
|
|||
<div id={"right-player"}>
|
||||
<div className="player-main-area">
|
||||
<div className="player-info">
|
||||
<span>{`Player Id ${rightId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[rightIdx].role : ""}`}</span>
|
||||
{this.computePlayerPortrait(rightId, rightIdx)}
|
||||
</div>
|
||||
{rightIdx >= 0 ? this.computeSideHand(this.props.hands[rightIdx]) : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
|
||||
</div>
|
||||
|
@ -157,7 +201,7 @@ class DoudizhuGameBoard extends React.Component {
|
|||
</div>
|
||||
<div className="player-main-area">
|
||||
<div className="player-info">
|
||||
<span>{`Player Id ${bottomId}\n${this.props.playerInfo.length > 0 ? this.props.playerInfo[bottomIdx].role : ""}`}</span>
|
||||
{this.computePlayerPortrait(bottomId, bottomIdx)}
|
||||
</div>
|
||||
{bottomIdx >= 0 ? <div className="player-hand">{this.computeSingleLineHand(this.props.hands[bottomIdx])}</div> : <div className="player-hand-placeholder"><span>Waiting...</span></div>}
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import React from 'react';
|
||||
import DoudizhuGameBoard from "./DoudizhuGameBoard";
|
||||
import LeducHoldemGameBoard from "./LeducHoldemGameBoard";
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import React, {useState} from "react";
|
||||
import logo_white from "../assets/images/logo_white.png";
|
||||
import GitHubIcon from "@material-ui/icons/GitHub";
|
||||
import AppBar from "@material-ui/core/AppBar";
|
||||
import axios from 'axios';
|
||||
|
||||
export function Navbar(props) {
|
||||
const [stars, setStars] = useState("...");
|
||||
axios.get("https://api.github.com/repos/datamllab/rlcard")
|
||||
.then(res=>{
|
||||
setStars(res.data.stargazers_count);
|
||||
});
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<div className={"header-bar"}>
|
||||
<img src={logo_white} alt={"Logo"} height="65px" />
|
||||
<div className={"title unselectable"}>Showdown<span className={"subtitle"}>/ {props.gameName}</span></div>
|
||||
<div className={"stretch"} />
|
||||
<div className={"github-info"} onClick={()=>{window.location.href = 'https://github.com/datamllab/rlcard'}}>
|
||||
<div className={"github-icon"}><GitHubIcon /></div>
|
||||
<div className={"github-text"}>Github<br /><span>{stars} stars</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</AppBar>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar;
|
|
@ -2,20 +2,19 @@ import React from 'react';
|
|||
import axios from 'axios';
|
||||
import '../assets/gameview.scss';
|
||||
import { DoudizhuGameBoard } from '../components/GameBoard';
|
||||
import Navbar from "../components/Navbar";
|
||||
import {removeCards, doubleRaf, deepCopy, computeHandCardsWidth, translateCardData} from "../utils";
|
||||
|
||||
import { Layout } from 'element-react';
|
||||
import { Layout, Message, Loading } from 'element-react';
|
||||
import Slider from '@material-ui/core/Slider';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
|
||||
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
|
||||
import NotInterestedIcon from '@material-ui/icons/NotInterested';
|
||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
||||
import SkipNextIcon from '@material-ui/icons/SkipNext';
|
||||
import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
|
||||
|
||||
|
@ -47,7 +46,8 @@ class DoudizhuGameView extends React.Component {
|
|||
this.state = {
|
||||
gameInfo: this.initGameState,
|
||||
gameStateLoop: null,
|
||||
gameSpeed: 0
|
||||
gameSpeed: 0,
|
||||
fullScreenLoading: false
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,11 @@ class DoudizhuGameView extends React.Component {
|
|||
if (remainedCards !== false) {
|
||||
gameInfo.hands[newMove.playerIdx] = remainedCards;
|
||||
} else {
|
||||
console.log("Cannot find cards in move from player's hand");
|
||||
Message({
|
||||
message: "Cannot find cards in move from player's hand",
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
// check if game ends
|
||||
if(remainedCards.length === 0){
|
||||
|
@ -92,7 +96,11 @@ class DoudizhuGameView extends React.Component {
|
|||
alert("Peasants Win");
|
||||
}, 200);
|
||||
}else{
|
||||
console.log("Error in finding winner");
|
||||
Message({
|
||||
message: "Error in finding winner",
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
});
|
||||
return gameInfo;
|
||||
|
@ -100,13 +108,21 @@ class DoudizhuGameView extends React.Component {
|
|||
gameInfo.considerationTime = this.initConsiderationTime;
|
||||
gameInfo.completedPercent += 100.0 / (this.moveHistory.length - 1);
|
||||
}else {
|
||||
console.log("Mismatched current player index");
|
||||
Message({
|
||||
message: "Mismatched current player index",
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
// if current state is new to game state history, push it to the game state history array
|
||||
if(gameInfo.turn === this.gameStateHistory.length){
|
||||
this.gameStateHistory.push(gameInfo);
|
||||
}else{
|
||||
console.log("inconsistent game state history length and turn number");
|
||||
Message({
|
||||
message: "inconsistent game state history length and turn number",
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
}
|
||||
}
|
||||
return gameInfo;
|
||||
|
@ -129,7 +145,7 @@ class DoudizhuGameView extends React.Component {
|
|||
this.gameStateTimer();
|
||||
}else{
|
||||
let gameInfo = this.generateNewState();
|
||||
if(gameInfo.gameStatus == "over") return;
|
||||
if(gameInfo.gameStatus === "over") return;
|
||||
gameInfo.gameStatus = "playing";
|
||||
if(this.state.gameInfo.toggleFade === "fade-out") {
|
||||
gameInfo.toggleFade = "fade-in";
|
||||
|
@ -152,6 +168,8 @@ class DoudizhuGameView extends React.Component {
|
|||
// for test use
|
||||
const replayId = 0;
|
||||
|
||||
// start full screen loading
|
||||
this.setState({fullScreenLoading: true});
|
||||
axios.get(`${this.apiUrl}/replay/doudizhu/${replayId}`)
|
||||
.then(res => {
|
||||
res = res.data;
|
||||
|
@ -168,7 +186,7 @@ class DoudizhuGameView extends React.Component {
|
|||
if(this.gameStateHistory.length === 0){ // fix replay bug
|
||||
this.gameStateHistory.push(gameInfo);
|
||||
}
|
||||
this.setState({gameInfo: gameInfo}, ()=>{
|
||||
this.setState({gameInfo: gameInfo, fullScreenLoading: false}, ()=>{
|
||||
if(this.gameStateTimeout){
|
||||
window.clearTimeout(this.gameStateTimeout);
|
||||
this.gameStateTimeout = null;
|
||||
|
@ -176,11 +194,18 @@ class DoudizhuGameView extends React.Component {
|
|||
// loop to update game state
|
||||
this.gameStateTimer();
|
||||
});
|
||||
})
|
||||
.catch(()=>{
|
||||
this.setState({fullScreenLoading: false});
|
||||
Message({
|
||||
message: "Error in getting replay data",
|
||||
type: "error",
|
||||
showClose: true
|
||||
});
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
runNewTurn(prevTurn){
|
||||
runNewTurn(){
|
||||
this.gameStateTimer();
|
||||
}
|
||||
|
||||
|
@ -225,7 +250,7 @@ class DoudizhuGameView extends React.Component {
|
|||
return <div className={"non-card "+this.state.gameInfo.toggleFade}><span>Pass</span></div>
|
||||
}else{
|
||||
return (
|
||||
<div className={"unselectable playingCards "+this.state.gameInfo.toggleFade}>
|
||||
<div className={"unselectable playingCards loose "+this.state.gameInfo.toggleFade}>
|
||||
<ul className="hand" style={{width: computeHandCardsWidth(cards.length, 10)}}>
|
||||
{cards.map(card=>{
|
||||
const [rankClass, suitClass, rankText, suitText] = translateCardData(card);
|
||||
|
@ -247,7 +272,7 @@ class DoudizhuGameView extends React.Component {
|
|||
computeProbabilityItem(idx){
|
||||
if(this.state.gameInfo.gameStatus !== "ready" && this.state.gameInfo.turn < this.moveHistory.length){
|
||||
let style = {};
|
||||
style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(189,183,107,${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
|
||||
style["backgroundColor"] = this.moveHistory[this.state.gameInfo.turn].probabilities.length > idx ? `rgba(245, 176, 65 , ${this.moveHistory[this.state.gameInfo.turn].probabilities[idx].probability})` : "#bdbdbd";
|
||||
return (
|
||||
<div className={"playing"} style={style}>
|
||||
<div className="probability-move">
|
||||
|
@ -322,6 +347,8 @@ class DoudizhuGameView extends React.Component {
|
|||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Navbar gameName={"Doudizhu"} />
|
||||
<div className={"doudizhu-view-container"}>
|
||||
<Layout.Row style={{"height": "540px"}}>
|
||||
<Layout.Col style={{"height": "100%"}} span="17">
|
||||
|
@ -370,6 +397,7 @@ class DoudizhuGameView extends React.Component {
|
|||
<div className="progress-bar">
|
||||
<LinearProgress variant="determinate" value={this.state.gameInfo.completedPercent} />
|
||||
</div>
|
||||
<Loading loading={this.state.fullScreenLoading}>
|
||||
<div className="game-controller">
|
||||
<Paper className={"game-controller-paper"} elevation={3}>
|
||||
<Layout.Row style={{"height": "51px"}}>
|
||||
|
@ -424,11 +452,8 @@ class DoudizhuGameView extends React.Component {
|
|||
</Layout.Col>
|
||||
</Layout.Row>
|
||||
</Paper>
|
||||
{/*<Layout.Row>*/}
|
||||
{/* <Layout.Col span="24">*/}
|
||||
{/* {`Current Player: ${this.state.gameInfo.currentPlayer} , Consideration Time: ${this.state.gameInfo.considerationTime}, Turn: ${this.state.gameInfo.turn}`}*/}
|
||||
{/* </Layout.Col>*/}
|
||||
{/*</Layout.Row>*/}
|
||||
</div>
|
||||
</Loading>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -10,12 +10,10 @@ import Button from '@material-ui/core/Button';
|
|||
import Paper from '@material-ui/core/Paper';
|
||||
import Divider from '@material-ui/core/Divider';
|
||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||
import ButtonGroup from '@material-ui/core/ButtonGroup';
|
||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import PauseCircleOutlineRoundedIcon from '@material-ui/icons/PauseCircleOutlineRounded';
|
||||
import ReplayRoundedIcon from '@material-ui/icons/ReplayRounded';
|
||||
import NotInterestedIcon from '@material-ui/icons/NotInterested';
|
||||
import PlayArrowIcon from '@material-ui/icons/PlayArrow';
|
||||
import SkipNextIcon from '@material-ui/icons/SkipNext';
|
||||
import SkipPreviousIcon from '@material-ui/icons/SkipPrevious';
|
||||
|
||||
|
@ -106,7 +104,7 @@ class LeducHoldemGameView extends React.Component {
|
|||
console.log("Error in player's latest action");
|
||||
}
|
||||
gameInfo.turn++;
|
||||
if(gameInfo.round !== 0 && gameInfo.turn == this.moveHistory[gameInfo.round].length){
|
||||
if(gameInfo.round !== 0 && gameInfo.turn === this.moveHistory[gameInfo.round].length){
|
||||
gameInfo.gameStatus = "over";
|
||||
this.setState({gameInfo: gameInfo});
|
||||
setTimeout(()=>{
|
||||
|
@ -150,7 +148,7 @@ class LeducHoldemGameView extends React.Component {
|
|||
this.gameStateTimer();
|
||||
}else{
|
||||
let gameInfo = this.generateNewState();
|
||||
if(gameInfo.gameStatus == "over") return;
|
||||
if(gameInfo.gameStatus === "over") return;
|
||||
this.gameStateTimer();
|
||||
gameInfo.gameStatus = "playing";
|
||||
if(this.state.gameInfo.toggleFade === "fade-out") {
|
||||
|
@ -244,7 +242,7 @@ class LeducHoldemGameView extends React.Component {
|
|||
currentMove = this.moveHistory[this.state.gameInfo.round][this.state.gameInfo.turn];
|
||||
}
|
||||
let style = {};
|
||||
style["backgroundColor"] = currentMove !== null ? `rgba(189,183,107,${currentMove.probabilities[idx].probability})` : "#bdbdbd";;
|
||||
style["backgroundColor"] = currentMove !== null ? `rgba(189,183,107,${currentMove.probabilities[idx].probability})` : "#bdbdbd";
|
||||
return (
|
||||
<div className={"playing"} style={style}>
|
||||
<div className="probability-move">
|
||||
|
@ -262,7 +260,7 @@ class LeducHoldemGameView extends React.Component {
|
|||
}
|
||||
|
||||
go2PrevGameState() {
|
||||
let gameInfo = null;
|
||||
let gameInfo;
|
||||
if(this.state.gameInfo.turn === 0 && this.state.gameInfo.round !== 0){
|
||||
let prevRound = this.gameStateHistory[this.state.gameInfo.round-1];
|
||||
gameInfo = deepCopy(prevRound[prevRound.length-1]);
|
||||
|
|