Move CSS around, add render loop
This commit is contained in:
parent
17f06fd1d8
commit
a6e959b8ef
File diff suppressed because one or more lines are too long
69
public/assets/css/src/buttons.css
Normal file
69
public/assets/css/src/buttons.css
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
.ui.button {
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
border: none;
|
||||||
|
font-size: 1rem;
|
||||||
|
background: #f7f8fa linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1));
|
||||||
|
box-shadow: 0 1px 0 1px rgba(255, 255, 255, 0.3) inset, 0 0 0 1px #adb2bb inset;
|
||||||
|
color: #111111;
|
||||||
|
padding: 0.5rem 1rem 0.5rem;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
user-select: none;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, background 0.1s ease;
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0), rgba(0, 0, 0, 0.1));
|
||||||
|
box-shadow: 0 1px 0 1px rgba(255, 255, 255, 0.3) inset, 0 0 0 1px #adb2bb inset;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.badge {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 0.1rem 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background-color: #f4cc67;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
color: #111111;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #C59F43 #AA8326 #957321;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fac847;
|
||||||
|
border-color: #C59F43 #AA8326 #957321;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
background-color: #444c55;
|
||||||
|
color: #ffffff;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #3D444C #2F353B #2C3137;
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #4e5964;
|
||||||
|
border-color: #32373E #24282D #212429;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
background-color: #e57373;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(139, 0, 0, 0.1));
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #d32f2f #c62828 #b71c1c;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #d95c5c;
|
||||||
|
border-color: #b71c1c #a52727 #8e1f1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
450
public/assets/css/src/main.css
Normal file
450
public/assets/css/src/main.css
Normal file
|
@ -0,0 +1,450 @@
|
||||||
|
@import 'utilities.css';
|
||||||
|
@import 'buttons.css';
|
||||||
|
@import 'forms.css';
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #bcc6cf;
|
||||||
|
background-image: url('/assets/img/bg.jpg');
|
||||||
|
background-attachment: fixed;
|
||||||
|
background-position: center top;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
max-width: 1640px;
|
||||||
|
margin: 0px auto;
|
||||||
|
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
height: 76px;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0 1rem;
|
||||||
|
background-image: url('/assets/img/header.jpg');
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
padding: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
gap: 2rem;
|
||||||
|
|
||||||
|
#center {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aside {
|
||||||
|
min-width: 200px;
|
||||||
|
|
||||||
|
.box {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aside#left nav {
|
||||||
|
& > *:not(:last-child) {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.stack {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&:checked ~ div.list {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked + label {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
transition: color, background-color 0.2s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.text {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
span.arrow {
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.list {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 1rem 0.5rem 1.35rem;
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
transition: color, background-color 0.2s ease;
|
||||||
|
|
||||||
|
&:not(:last-child)::before {
|
||||||
|
content: '├';
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child::before {
|
||||||
|
content: '└';
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #444c55;
|
||||||
|
color: #ffffff;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #3D444C #2F353B #2C3137;
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
transition: color, background-color 0.2s ease;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.15rem;
|
||||||
|
|
||||||
|
&:has(img) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 18px;
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover, &.active {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #444c55;
|
||||||
|
color: #ffffff;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #3D444C #2F353B #2C3137;
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
& > p:not(:last-child) {
|
||||||
|
margin-right: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#char-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 0 1rem;
|
||||||
|
height: 34px;
|
||||||
|
color: white;
|
||||||
|
gap: 1rem;
|
||||||
|
background-image: url('/assets/img/bar.jpg');
|
||||||
|
|
||||||
|
& > div.container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 18px;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span.badge {
|
||||||
|
font-size: 10px;
|
||||||
|
background-color: #f7f8fa;
|
||||||
|
color: #111111;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.1rem 0.25rem;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset;
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background-color: #444c55;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.green {
|
||||||
|
background-color: #a6e3a1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-meter {
|
||||||
|
background-color: black;
|
||||||
|
height: 16px;
|
||||||
|
min-width: 100px;
|
||||||
|
border-radius: 0.1rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0.1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.hp {
|
||||||
|
background-color: #e57373;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(139, 0, 0, 0.1));
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #d32f2f #c62828 #b71c1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.mp {
|
||||||
|
background-color: #5a9bd4;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(60, 100, 150, 0.1));
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #4a8ab0 #3a7a9c #2a6a88;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.tp {
|
||||||
|
background-color: #f4cc67;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #C59F43 #AA8326 #957321;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip {
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid #666;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0.5rem;
|
||||||
|
box-shadow: 0 0 0.5rem 0.1rem rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-trigger {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.debug-query-log {
|
||||||
|
padding: 2rem;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
#center section {
|
||||||
|
&:not(:last-child) {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:has(.badge), h2:has(.badge), h3:has(.badge), h4:has(.badge), h5:has(.badge), h6:has(.badge) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& > .badge {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
position: relative;
|
||||||
|
min-height: 1rem;
|
||||||
|
margin: 1rem 0;
|
||||||
|
background: #f8f8f9;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
line-height: 1.4285rem;
|
||||||
|
color: rgba(0, 0, 0, .87);
|
||||||
|
transition: opacity .1s ease, color .1s ease, background .1s ease, box-shadow .1s ease;
|
||||||
|
border-radius: .28571429rem;
|
||||||
|
box-shadow: 0 0 0 1px rgba(34, 36, 38, .22) inset, 0 0 0 0 transparent;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
background-color: #f0f9eb;
|
||||||
|
color: #2c662d;
|
||||||
|
border-color: #b3dc9d;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
background-color: #f9e9eb;
|
||||||
|
color: #9f3a38;
|
||||||
|
border-color: #e0b4b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warning {
|
||||||
|
background-color: #fff8e1;
|
||||||
|
color: #573a08;
|
||||||
|
border-color: #f9e79f;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.info {
|
||||||
|
background-color: #f0f9fb;
|
||||||
|
color: #2c7fba;
|
||||||
|
border-color: #b3d7f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
color: #2c2c2c;
|
||||||
|
border-color: #b3b3b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
a[alert-close] {
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #4C0515;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #6C0515;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body::-webkit-scrollbar {
|
||||||
|
width: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::-webkit-scrollbar-track {
|
||||||
|
background: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
body::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #444c55;
|
||||||
|
background-image: linear-gradient(rgba(255, 255, 255, 0.15), rgba(0, 0, 0, 0.1));
|
||||||
|
border: 1px solid;
|
||||||
|
border-color: #3D444C #2F353B #2C3137;
|
||||||
|
box-shadow: 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canvas-container {
|
||||||
|
& > canvas {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 440px;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
image-rendering: crisp-edges;
|
||||||
|
image-rendering: -webkit-optimize-contrast;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.char-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-image: url('/assets/img/world/rogues.png');
|
||||||
|
|
||||||
|
&.index-0 {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.index-1 {
|
||||||
|
background-position: -32px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.index-2 {
|
||||||
|
background-position: -64px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.index-3 {
|
||||||
|
background-position: -96px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.index-4 {
|
||||||
|
background-position: -128px 0;
|
||||||
|
}
|
||||||
|
}
|
40
public/assets/css/src/utilities.css
Normal file
40
public/assets/css/src/utilities.css
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
:root {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-1 { margin-bottom: 0.25rem; margin-top: 0.25rem; }
|
||||||
|
.my-2 { margin-bottom: 0.5rem; margin-top: 0.5rem; }
|
||||||
|
.my-3 { margin-bottom: 0.75rem; margin-top: 0.75rem; }
|
||||||
|
.my-4 { margin-bottom: 1rem; margin-top: 1rem; }
|
||||||
|
|
||||||
|
.ml-1 { margin-left: 0.25rem; }
|
||||||
|
.ml-2 { margin-left: 0.5rem; }
|
||||||
|
.ml-3 { margin-left: 0.75rem; }
|
||||||
|
.ml-4 { margin-left: 1rem; }
|
||||||
|
|
||||||
|
.mr-1 { margin-right: 0.25rem; }
|
||||||
|
.mr-2 { margin-right: 0.5rem; }
|
||||||
|
.mr-3 { margin-right: 0.75rem; }
|
||||||
|
.mr-4 { margin-right: 1rem; }
|
||||||
|
|
||||||
|
.mb-1 { margin-bottom: 0.25rem; }
|
||||||
|
.mb-2 { margin-bottom: 0.5rem; }
|
||||||
|
.mb-3 { margin-bottom: 0.75rem; }
|
||||||
|
.mb-4 { margin-bottom: 1rem; }
|
||||||
|
|
||||||
|
.mt-1 { margin-top: 0.25rem; }
|
||||||
|
.mt-2 { margin-top: 0.5rem; }
|
||||||
|
.mt-3 { margin-top: 0.75rem; }
|
||||||
|
.mt-4 { margin-top: 1rem; }
|
||||||
|
|
||||||
|
|
||||||
|
.container-960 {
|
||||||
|
width: 960px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
|
@ -104,11 +104,11 @@ function user($field = '')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the user has selected a character. If so, return the character's ID.
|
* Check whether the user has selected a character.
|
||||||
*/
|
*/
|
||||||
function user_selected_char(): int
|
function user_selected_char()
|
||||||
{
|
{
|
||||||
return (int) $_SESSION['user']['char_id'];
|
return user('char_id') > 0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,7 +124,7 @@ function char($field = '')
|
||||||
$GLOBALS['char'] = db_query(
|
$GLOBALS['char'] = db_query(
|
||||||
db_live(),
|
db_live(),
|
||||||
"SELECT * FROM characters WHERE id = :c",
|
"SELECT * FROM characters WHERE id = :c",
|
||||||
[':c' => user_selected_char()]
|
[':c' => user('char_id')]
|
||||||
)->fetchArray(SQLITE3_ASSOC);
|
)->fetchArray(SQLITE3_ASSOC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<aside id="left">
|
<aside id="left">
|
||||||
<?php if (user()) echo c_left_nav($activeTab ?? 0); ?>
|
<?php if (user() && user_selected_char()) echo c_left_nav($activeTab ?? 0); ?>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
<div id="center">
|
<div id="center">
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<aside id="right">
|
<aside id="right">
|
||||||
<?php if (user()): ?>
|
<?php if (user() && user_selected_char()): ?>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
@TODO
|
@TODO
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
<a href="/auth/login" class="ui button primary">Login</a>
|
<a href="/auth/login" class="ui button primary">Login</a>
|
||||||
<a href="/auth/register" class="ui button secondary">Register</a>
|
<a href="/auth/register" class="ui button secondary">Register</a>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<h1 class="tooltip-click" data-tooltip-content="Hover-based tooltip">Home</h1>
|
<h1>Home</h1>
|
||||||
<?= print_r(char()) ?>
|
<p>Welcome, <?= user('username') ?>!</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
|
@ -55,13 +55,25 @@
|
||||||
y: document.getElementById('char_y')
|
y: document.getElementById('char_y')
|
||||||
}
|
}
|
||||||
|
|
||||||
let player = { x: <?= location('x') ?>, y: <?= location('y') ?>, char: 23, sprite: { x: 0, y: 0 } }
|
let player = {
|
||||||
|
location: { x: <?= location('x') ?>, y: <?= location('y') ?> },
|
||||||
|
current: { x: <?= location('x') ?>, y: <?= location('y') ?> },
|
||||||
|
target: { x: <?= location('x') ?>, y: <?= location('y') ?> },
|
||||||
|
char: 23, sprite: { x: 0, y: 0 },
|
||||||
|
tweenDuration: 0.2, // seconds
|
||||||
|
tweenProgress: 0
|
||||||
|
}
|
||||||
let camera = { x: 0, y: 0 }
|
let camera = { x: 0, y: 0 }
|
||||||
let visible = { x: 0, y: 0 }
|
let visible = { x: 0, y: 0 }
|
||||||
|
|
||||||
game.tiles.img.src = '/assets/img/world/tiles.jpg';
|
game.tiles.img.src = '/assets/img/world/tiles.jpg';
|
||||||
game.sprites.img.src = '/assets/img/world/rogues.png';
|
game.sprites.img.src = '/assets/img/world/rogues.png';
|
||||||
|
|
||||||
|
let lastFrameTime = 0;
|
||||||
|
let fps = 0;
|
||||||
|
|
||||||
|
let debounce = false;
|
||||||
|
|
||||||
function getPlayerSprite() {
|
function getPlayerSprite() {
|
||||||
let col = player.char % game.sprites.cols
|
let col = player.char % game.sprites.cols
|
||||||
let row = Math.floor(player.char / game.sprites.cols)
|
let row = Math.floor(player.char / game.sprites.cols)
|
||||||
|
@ -73,17 +85,18 @@
|
||||||
game.canvas.height = game.canvas.clientHeight
|
game.canvas.height = game.canvas.clientHeight
|
||||||
visible.x = Math.ceil(game.canvas.width / game.tiles.size)
|
visible.x = Math.ceil(game.canvas.width / game.tiles.size)
|
||||||
visible.y = Math.ceil(game.canvas.height / game.tiles.size)
|
visible.y = Math.ceil(game.canvas.height / game.tiles.size)
|
||||||
updateCamera()
|
|
||||||
render()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupEventListeners() {
|
function setupEventListeners() {
|
||||||
window.addEventListener('resize', updateCanvasSize)
|
window.addEventListener('resize', updateCanvasSize)
|
||||||
window.addEventListener('keydown', handleKeyPress)
|
window.addEventListener('keydown', handleKeyPress)
|
||||||
|
window.addEventListener('keyup', () => debounce = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle keyboard input
|
// Handle keyboard input
|
||||||
function handleKeyPress(e) {
|
function handleKeyPress(e) {
|
||||||
|
if (debounce) return;
|
||||||
|
debounce = true;
|
||||||
let moved = false;
|
let moved = false;
|
||||||
const newPos = { ...player }
|
const newPos = { ...player }
|
||||||
|
|
||||||
|
@ -104,8 +117,8 @@
|
||||||
const dy = [-1, 1, 0, 0];
|
const dy = [-1, 1, 0, 0];
|
||||||
|
|
||||||
// Calculate new position
|
// Calculate new position
|
||||||
const newX = player.x + dx[direction];
|
const newX = player.location.x + dx[direction];
|
||||||
const newY = player.y + dy[direction];
|
const newY = player.location.y + dy[direction];
|
||||||
|
|
||||||
if (direction !== undefined) {
|
if (direction !== undefined) {
|
||||||
// Check if the new position is outside the map bounds
|
// Check if the new position is outside the map bounds
|
||||||
|
@ -124,12 +137,11 @@
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
response.json().then(data => {
|
response.json().then(data => {
|
||||||
player.x = data.x
|
player.location = { x: data.x, y: data.y }
|
||||||
player.y = data.y
|
player.target = { x: data.x, y: data.y }
|
||||||
loc_span.x.textContent = player.x
|
player.tweenProgress = 0
|
||||||
loc_span.y.textContent = player.y
|
loc_span.x.textContent = player.location.x
|
||||||
updateCamera()
|
loc_span.y.textContent = player.location.y
|
||||||
render()
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Failed to move character');
|
throw new Error('Failed to move character');
|
||||||
|
@ -140,8 +152,8 @@
|
||||||
|
|
||||||
// Update camera position
|
// Update camera position
|
||||||
function updateCamera() {
|
function updateCamera() {
|
||||||
camera.x = player.x * game.tiles.size - canvas.width / 2;
|
camera.x = player.current.x * game.tiles.size - canvas.width / 2;
|
||||||
camera.y = player.y * game.tiles.size - canvas.height / 2;
|
camera.y = player.current.y * game.tiles.size - canvas.height / 2;
|
||||||
|
|
||||||
// Clamp camera to map bounds
|
// Clamp camera to map bounds
|
||||||
camera.x = Math.max(0, Math.min(camera.x,
|
camera.x = Math.max(0, Math.min(camera.x,
|
||||||
|
@ -150,10 +162,21 @@
|
||||||
map.length * game.tiles.size - canvas.height));
|
map.length * game.tiles.size - canvas.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lerp(start, end, t) {
|
||||||
|
return start + (end - start) * t;
|
||||||
|
}
|
||||||
|
|
||||||
// Render the game
|
// Render the game
|
||||||
function render() {
|
function render(t) {
|
||||||
const ctx = game.canvas.getContext('2d')
|
const ctx = game.canvas.getContext('2d')
|
||||||
|
|
||||||
|
// Calculate FPS
|
||||||
|
if (lastFrameTime) {
|
||||||
|
const delta = (t - lastFrameTime) / 1000;
|
||||||
|
fps = Math.round(1 / delta);
|
||||||
|
}
|
||||||
|
lastFrameTime = t;
|
||||||
|
|
||||||
ctx.clearRect(0, 0, game.canvas.width, game.canvas.height)
|
ctx.clearRect(0, 0, game.canvas.width, game.canvas.height)
|
||||||
|
|
||||||
// Calculate visible tile range
|
// Calculate visible tile range
|
||||||
|
@ -169,24 +192,43 @@
|
||||||
for (let x = startTileX; x < endTileX; x++) {
|
for (let x = startTileX; x < endTileX; x++) {
|
||||||
if (x >= map[0].length) continue
|
if (x >= map[0].length) continue
|
||||||
|
|
||||||
const screenX = x * game.tiles.size - camera.x
|
const screenX = Math.round(x * game.tiles.size - camera.x)
|
||||||
const screenY = y * game.tiles.size - camera.y
|
const screenY = Math.round(y * game.tiles.size - camera.y)
|
||||||
|
|
||||||
ctx.drawImage(game.tiles.img, map[y][x] * game.tiles.size, 0, game.tiles.size, game.tiles.size,
|
ctx.drawImage(game.tiles.img, map[y][x] * game.tiles.size, 0, game.tiles.size, game.tiles.size,
|
||||||
screenX, screenY, game.tiles.size, game.tiles.size)
|
screenX, screenY, game.tiles.size, game.tiles.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tween player position
|
||||||
|
if (player.tweenProgress < 1) {
|
||||||
|
player.tweenProgress += 1 / player.tweenDuration / 60
|
||||||
|
player.current.x = lerp(player.current.x, player.target.x, player.tweenProgress)
|
||||||
|
player.current.y = lerp(player.current.y, player.target.y, player.tweenProgress)
|
||||||
|
} else {
|
||||||
|
player.current = { x: player.current.x, y: player.current.y }
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCamera()
|
||||||
|
|
||||||
// Render the player on top of the map using their current position
|
// Render the player on top of the map using their current position
|
||||||
|
const playerX = Math.round((player.current.x * game.tiles.size) - camera.x)
|
||||||
|
const playerY = Math.round((player.current.y * game.tiles.size) - camera.y)
|
||||||
ctx.drawImage(game.sprites.img, player.sprite.x, player.sprite.y, game.sprites.size, game.sprites.size,
|
ctx.drawImage(game.sprites.img, player.sprite.x, player.sprite.y, game.sprites.size, game.sprites.size,
|
||||||
(player.x * game.sprites.size) - camera.x, (player.y * game.sprites.size) - camera.y,
|
playerX, playerY, game.sprites.size, game.sprites.size)
|
||||||
game.sprites.size, game.sprites.size)
|
|
||||||
|
// Render FPS counter
|
||||||
|
ctx.fillStyle = 'white';
|
||||||
|
ctx.font = '16px Arial';
|
||||||
|
ctx.fillText(`FPS: ${fps}`, game.canvas.width - 70, 20);
|
||||||
|
|
||||||
|
requestAnimationFrame(render);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
getPlayerSprite()
|
getPlayerSprite()
|
||||||
updateCanvasSize()
|
updateCanvasSize()
|
||||||
setupEventListeners()
|
setupEventListeners()
|
||||||
render()
|
requestAnimationFrame(render)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user