diff --git a/public/assets/css/dragon.css b/public/assets/css/dragon.css index 523e04b..dd235f1 100644 --- a/public/assets/css/dragon.css +++ b/public/assets/css/dragon.css @@ -1 +1 @@ -:root{--main-font:Cambria,Cochin,Georgia,Times,"Times New Roman",serif;font-size:16px}*{box-sizing:border-box;margin:0;padding:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.container-960{width:960px;margin:0 auto}.ui.button{cursor:pointer;font-size:1rem;font-family:var(--main-font);color:#111;text-align:center;user-select:none;-webkit-tap-highlight-color:transparent;background:#f7f8fa linear-gradient(#fff0,#0000001a);border:none;border-radius:3px;padding:.5rem 1rem;text-decoration:none;transition:opacity .1s,background-color .1s,color .1s,background .1s;display:inline-block;box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb;&:hover{color:#000c;background-color:#e0e0e0;background-image:linear-gradient(#fff0,#0000001a);box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb}&.badge{padding:.1rem .25rem;font-size:10px}&.primary{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3;&:hover{background-color:#fac847;border-color:#c59f43 #aa8326 #957321}}&.secondary{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&:hover{background-color:#4e5964;border-color:#32373e #24282d #212429}}&.danger{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3;&:hover{background-color:#d95c5c;border-color:#b71c1c #a52727 #8e1f1f}}}.form.control{appearance:none;color:#fff;background-color:#0003;border:1px solid #0000;border-radius:4px;outline:none;width:100%;padding:.5rem;font-size:1rem;display:block;box-shadow:inset 0 1px 4px #0000001a;&::placeholder{color:#ffffffb3}&:hover{background-color:#0000004d}&:focus{background-color:#00000080;border-color:#000c}&.error{background-color:#ff2b2b33;&:hover{background-color:#ff2b2b4d}&:focus{background-color:#ff2b2b4d;border-color:#ff2b2bcc}}}.form.group{margin-bottom:1rem;&>label{margin-bottom:.5rem;display:block}&>.form.control:not(:last-child){margin-bottom:.5rem}}.character-select>.radio-block{background-color:#0003;border-radius:.15rem;display:inline-block;&:not(:last-child){margin-bottom:.25rem}&>input[type=radio]{display:none}&>label{cursor:pointer;background-image:linear-gradient(#fff0,#0000);border:1px solid #0000;border-radius:.15rem;align-items:center;width:100%;padding:.5rem;transition:color,background-color,border-color,background-image .2s;display:flex;&:hover{color:#fff;background-color:#0000004d}&>.badge{margin-left:.25rem}&>span.selected{display:none}&>.char-icon{margin-right:.25rem}}&.active>label{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&>span.selected{display:inline-block}}&>input[type=radio]:checked+label{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}&>input[type=radio]:disabled+label{cursor:default}}.character-select:not(:has(input[type=radio]:checked))>.buttons{display:none}section.profile{& header{text-align:center;margin-bottom:3rem;& h3{font-size:1rem}& h5{color:#00000080;font-size:.75rem}}&>div.grid{gap:1rem;display:flex;&>section{width:50%;&>div:not(:last-child){margin-bottom:2rem}}}& div.avatar{justify-content:center;align-items:center;padding-bottom:1rem;display:flex;& img{width:185px;height:185px}& .border{width:250px;height:250px;position:absolute}}& h4{text-align:center;text-transform:uppercase;color:#fff;background-image:url(/assets/img/bar.jpg);background-position:bottom;margin-bottom:.5rem;padding:.5rem;font-size:.75rem}& div.stats{&>.grid{grid-template-columns:1fr 1fr;gap:.25rem;display:grid;&>div.cell{justify-content:space-between;align-items:center;padding:.25rem .5rem;display:flex;& .label{text-transform:uppercase;margin-right:.25rem;font-size:.75rem}}}}& #equipped-gear{flex-direction:column;justify-content:center;align-items:center;gap:.5rem;display:flex;& div.item{justify-content:center;align-items:center;display:flex;&.i-1x1{background-image:url(/assets/img/ui/1x1.png);width:30px;height:30px}&.i-2x2{background-image:url(/assets/img/ui/2x2.png);width:60px;height:60px}&.i-2x3{background-image:url(/assets/img/ui/2x3.png);width:60px;height:90px}}&>div{gap:.5rem;display:flex;&>div{justify-content:center;align-items:center;width:60px;display:flex;&.top,&.bot{width:60px;height:60px}&.mid{width:60px;height:90px}}}}}body{font-family:var(--main-font);background-color:#bcc6cf;background-image:url(/assets/img/bg.jpg);background-position:top;background-repeat:no-repeat;background-attachment:fixed;min-width:968px;max-width:1640px;margin:0 auto}header#main-header{color:#fff;background-image:url(/assets/img/header.jpg);justify-content:space-between;align-items:center;height:76px;padding:0 1rem;display:flex;& h1{margin:0;padding:0}& .right{align-items:center;display:flex;& p{margin-right:1rem}}}main{gap:2rem;width:100%;padding:1rem;display:flex;& #center{flex:1}}aside{min-width:200px;& .box{background-color:#0003;border-radius:.15rem;padding:.5rem}}aside#left nav{&>:not(:last-child){margin-bottom:.25rem}& div.stack{background-color:#0003;border-radius:.15rem;& input[type=checkbox]{display:none;&:checked~div.list{display:block}&:checked+label{color:#fff;background-color:#00000080}}& label{color:#000;cursor:pointer;border-radius:.15rem;align-items:center;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:flex;& img{height:18px;margin-right:.25rem}& span.text{width:100%;display:block}&:hover{color:#fff;background-color:#0000004d}& span.arrow{position:relative;top:5px}}& div.list{display:none;&>a{color:#000;border-radius:.15rem;width:100%;padding:.5rem 1rem .5rem 1.35rem;text-decoration:none;transition:color,background-color .2s;display:block;&:not(:last-child):before{content:"├";margin-right:.25rem;display:inline-block}&:last-child:before{content:"└";margin-right:.25rem;display:inline-block;position:relative;top:3px}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}}&>a{color:#000;background-color:#0003;border-radius:.15rem;width:100%;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:block;&:has(img){align-items:center;display:flex;& img{height:18px;margin-right:.25rem}}&:hover,&.active{color:#fff}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}footer{text-align:center;color:#666;justify-content:center;align-items:center;margin:1rem 0;padding:1rem;display:flex;&>p:not(:last-child){margin-right:2rem}}#character{&>.name{align-items:center;display:flex}&>div:not(:last-child){margin-bottom:.5rem}}span.badge{color:#111;background-color:#f7f8fa;border-radius:.25rem;padding:.1rem .25rem;font-size:10px;box-shadow:inset 0 0 0 1px #0000001a;&.dark{color:#fff;background-color:#444c55}&.green{background-color:#a6e3a1}}.char-meter{background-color:#000;border-radius:.1rem;min-width:100px;height:16px;position:relative;&>div{border-radius:.1rem;height:100%;overflow:hidden;&.hp{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3}&.mp{background-color:#5a9bd4;background-image:linear-gradient(#ffffff26,#3c64961a);border:1px solid #3a7a9c;border-color:#4a8ab0 #3a7a9c #2a6a88;box-shadow:inset 0 1px #fff3}&.tp{background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}}}.tooltip{color:#fff;text-align:center;background-color:#000;border:1px solid #666;border-radius:.1rem;padding:.5rem;font-size:14px;position:absolute;box-shadow:0 0 .5rem .1rem #0003}.tooltip-trigger{width:100%;height:100%;position:absolute;top:0;left:0}.debug-query-log{color:#666;padding:1rem;font-family:monospace;font-size:14px;&:last-child{padding-top:0}}#center>section{&:not(:last-child){border-bottom:1px solid #0000001a;margin-bottom:1rem;padding-bottom:1rem}}h1:has(.badge),h2:has(.badge),h3:has(.badge),h4:has(.badge),h5:has(.badge),h6:has(.badge){align-items:center;display:flex;&>.badge{margin-left:.5rem}}.alert{color:#000000de;background:#f8f8f9;border-radius:.285714rem;justify-content:space-between;align-items:center;min-height:1rem;margin:1rem 0;padding:.5rem 1rem;line-height:1.4285rem;transition:opacity .1s,color .1s,background .1s,box-shadow .1s;display:flex;position:relative;box-shadow:inset 0 0 0 1px #22242638,0 0 #0000;&.success{color:#2c662d;background-color:#f0f9eb;border-color:#b3dc9d}&.danger{color:#9f3a38;background-color:#f9e9eb;border-color:#e0b4b4}&.warning{color:#573a08;background-color:#fff8e1;border-color:#f9e79f}&.info{color:#2c7fba;background-color:#f0f9fb;border-color:#b3d7f9}&.dark{color:#2c2c2c;background-color:#f0f0f0;border-color:#b3b3b3}& a[alert-close]{cursor:pointer;color:inherit;font-size:2rem;text-decoration:none}}a{color:#4c0515;text-decoration:none;transition:color .2s;&:hover{color:#6c0515;text-decoration:underline}}body::-webkit-scrollbar{width:.5rem}body::-webkit-scrollbar-track{background:#0000001a}body::-webkit-scrollbar-thumb{background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}#canvas-container{&>canvas{image-rendering:pixelated;image-rendering:crisp-edges;image-rendering:-webkit-optimize-contrast;width:100%;height:440px;display:block}}.char-icon{background-image:url(/assets/img/world/rogues.png);width:32px;height:32px;&.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}} \ No newline at end of file +:root{--main-font:Cambria,Cochin,Georgia,Times,"Times New Roman",serif;font-size:16px}*{box-sizing:border-box;margin:0;padding:0}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.my-3{margin-top:.75rem;margin-bottom:.75rem}.my-4{margin-top:1rem;margin-bottom:1rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.container-960{width:960px;margin:0 auto}.ui.button{cursor:pointer;font-size:1rem;font-family:var(--main-font);color:#111;text-align:center;user-select:none;-webkit-tap-highlight-color:transparent;background:#f7f8fa linear-gradient(#fff0,#0000001a);border:none;border-radius:3px;padding:.5rem 1rem;text-decoration:none;transition:opacity .1s,background-color .1s,color .1s,background .1s;display:inline-block;box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb;&:hover{color:#000c;background-color:#e0e0e0;background-image:linear-gradient(#fff0,#0000001a);box-shadow:inset 0 1px 0 1px #ffffff4d,inset 0 0 0 1px #adb2bb}&.badge{padding:.1rem .25rem;font-size:10px}&.primary{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3;&:hover{background-color:#fac847;border-color:#c59f43 #aa8326 #957321}}&.secondary{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&:hover{background-color:#4e5964;border-color:#32373e #24282d #212429}}&.danger{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3;&:hover{background-color:#d95c5c;border-color:#b71c1c #a52727 #8e1f1f}}}.form.control{appearance:none;color:#fff;background-color:#0003;border:1px solid #0000;border-radius:4px;outline:none;width:100%;padding:.5rem;font-size:1rem;display:block;box-shadow:inset 0 1px 4px #0000001a;&::placeholder{color:#ffffffb3}&:hover{background-color:#0000004d}&:focus{background-color:#00000080;border-color:#000c}&.error{background-color:#ff2b2b33;&:hover{background-color:#ff2b2b4d}&:focus{background-color:#ff2b2b4d;border-color:#ff2b2bcc}}}.form.group{margin-bottom:1rem;&>label{margin-bottom:.5rem;display:block}&>.form.control:not(:last-child){margin-bottom:.5rem}}.character-select>.radio-block{background-color:#0003;border-radius:.15rem;display:inline-block;&:not(:last-child){margin-bottom:.25rem}&>input[type=radio]{display:none}&>label{cursor:pointer;background-image:linear-gradient(#fff0,#0000);border:1px solid #0000;border-radius:.15rem;align-items:center;width:100%;padding:.5rem;transition:color,background-color,border-color,background-image .2s;display:flex;&:hover{color:#fff;background-color:#0000004d}&>.badge{margin-left:.25rem}&>span.selected{display:none}&>.char-icon{margin-right:.25rem}}&.active>label{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3;&>span.selected{display:inline-block}}&>input[type=radio]:checked+label{color:#111;background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}&>input[type=radio]:disabled+label{cursor:default}}.character-select:not(:has(input[type=radio]:checked))>.buttons{display:none}section.profile{& header{text-align:center;margin-bottom:2rem;& h3{color:#0000004d;text-transform:uppercase;font-size:1rem}& h4{font-size:.75rem}}&>div.grid{gap:1rem;display:flex;&>section{width:50%;&>div:not(:last-child){margin-bottom:1rem}}}& div.avatar{justify-content:center;align-items:center;display:flex;& img{max-width:250px}}& h4{text-align:center;text-transform:uppercase;color:#fff;background-image:url(/assets/img/bar.jpg);background-position:bottom;margin-bottom:.5rem;padding:.5rem;font-size:.75rem}& div.stats{&>.grid{grid-template-columns:1fr 1fr;gap:.25rem;display:grid;&>div.cell{justify-content:space-between;align-items:center;padding:.25rem .5rem;display:flex;& .label{text-transform:uppercase;margin-right:.25rem;font-size:.75rem}}}}}main#game-container{width:100vw;height:100vh}canvas#game-canvas{width:100%;height:100%}body{min-width:968px;max-width:1640px;font-family:var(--main-font);background-color:#bcc6cf;background-image:url(/assets/img/bg.jpg);background-position:top;background-repeat:no-repeat;background-attachment:fixed;margin:0 auto}header#main-header{color:#fff;background-image:url(/assets/img/header.jpg);justify-content:space-between;align-items:center;height:76px;padding:0 1rem;display:flex;& h1{margin:0;padding:0}& .right{align-items:center;display:flex;& p{margin-right:1rem}}}main{gap:2rem;width:100%;padding:1rem;display:flex;& #center{flex:1}}aside{min-width:200px;& .box{background-color:#0003;border-radius:.15rem;padding:.5rem}}aside#left nav{&>:not(:last-child){margin-bottom:.25rem}& div.stack{background-color:#0003;border-radius:.15rem;& input[type=checkbox]{display:none;&:checked~div.list{display:block}&:checked+label{color:#fff;background-color:#00000080}}& label{color:#000;cursor:pointer;border-radius:.15rem;align-items:center;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:flex;& img{height:18px;margin-right:.25rem}& span.text{width:100%;display:block}&:hover{color:#fff;background-color:#0000004d}& span.arrow{position:relative;top:5px}}& div.list{display:none;&>a{color:#000;border-radius:.15rem;width:100%;padding:.5rem 1rem .5rem 1.35rem;text-decoration:none;transition:color,background-color .2s;display:block;&:not(:last-child):before{content:"├";margin-right:.25rem;display:inline-block}&:last-child:before{content:"└";margin-right:.25rem;display:inline-block;position:relative;top:3px}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}}&>a{color:#000;background-color:#0003;border-radius:.15rem;width:100%;padding:.5rem 1rem;text-decoration:none;transition:color,background-color .2s;display:block;&:has(img){align-items:center;display:flex;& img{height:18px;margin-right:.25rem}}&:hover,&.active{color:#fff}&:hover{background-color:#0000004d}&.active{color:#fff;background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}}}footer{text-align:center;color:#666;justify-content:center;align-items:center;margin:1rem 0;padding:1rem;display:flex;&>p:not(:last-child){margin-right:2rem}}#character{&>.name{align-items:center;display:flex}&>div:not(:last-child){margin-bottom:.5rem}}span.badge{color:#111;background-color:#f7f8fa;border-radius:.25rem;padding:.1rem .25rem;font-size:10px;box-shadow:inset 0 0 0 1px #0000001a;&.dark{color:#fff;background-color:#444c55}&.green{background-color:#a6e3a1}}.char-meter{background-color:#000;border-radius:.1rem;min-width:100px;height:16px;position:relative;&>div{border-radius:.1rem;height:100%;overflow:hidden;&.hp{background-color:#e57373;background-image:linear-gradient(#ffffff26,#8b00001a);border:1px solid #c62828;border-color:#d32f2f #c62828 #b71c1c;box-shadow:inset 0 1px #fff3}&.mp{background-color:#5a9bd4;background-image:linear-gradient(#ffffff26,#3c64961a);border:1px solid #3a7a9c;border-color:#4a8ab0 #3a7a9c #2a6a88;box-shadow:inset 0 1px #fff3}&.tp{background-color:#f4cc67;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #aa8326;border-color:#c59f43 #aa8326 #957321;box-shadow:inset 0 1px #fff3}}}.tooltip{color:#fff;text-align:center;background-color:#000;border:1px solid #666;border-radius:.1rem;padding:.5rem;font-size:14px;box-shadow:0 0 .5rem .1rem #0003}.tooltip-trigger{width:100%;height:100%;position:absolute;top:0;left:0}.debug-query-log{color:#666;padding:1rem;font-family:monospace;font-size:14px;&:last-child{padding-top:0}}#center>section{&:not(:last-child){border-bottom:1px solid #0000001a;margin-bottom:1rem;padding-bottom:1rem}}h1:has(.badge),h2:has(.badge),h3:has(.badge),h4:has(.badge),h5:has(.badge),h6:has(.badge){align-items:center;display:flex;&>.badge{margin-left:.5rem}}.alert{color:#000000de;background:#f8f8f9;border-radius:.285714rem;justify-content:space-between;align-items:center;min-height:1rem;margin:1rem 0;padding:.5rem 1rem;line-height:1.4285rem;transition:opacity .1s,color .1s,background .1s,box-shadow .1s;display:flex;position:relative;box-shadow:inset 0 0 0 1px #22242638,0 0 #0000;&.success{color:#2c662d;background-color:#f0f9eb;border-color:#b3dc9d}&.danger{color:#9f3a38;background-color:#f9e9eb;border-color:#e0b4b4}&.warning{color:#573a08;background-color:#fff8e1;border-color:#f9e79f}&.info{color:#2c7fba;background-color:#f0f9fb;border-color:#b3d7f9}&.dark{color:#2c2c2c;background-color:#f0f0f0;border-color:#b3b3b3}& a[alert-close]{cursor:pointer;color:inherit;font-size:2rem;text-decoration:none}}a{color:#4c0515;text-decoration:none;transition:color .2s;&:hover{color:#6c0515;text-decoration:underline}}body::-webkit-scrollbar{width:.5rem}body::-webkit-scrollbar-track{background:#0000001a}body::-webkit-scrollbar-thumb{background-color:#444c55;background-image:linear-gradient(#ffffff26,#0000001a);border:1px solid #2f353b;border-color:#3d444c #2f353b #2c3137;box-shadow:inset 0 1px #fff3}#canvas-container{&>canvas{width:100%;height:440px;image-rendering:pixelated;image-rendering:crisp-edges;image-rendering:-webkit-optimize-contrast;display:block}}.char-icon{background-image:url(/assets/img/world/rogues.png);width:32px;height:32px;&.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}} diff --git a/public/assets/css/game.css b/public/assets/css/game.css new file mode 100644 index 0000000..f87e31f --- /dev/null +++ b/public/assets/css/game.css @@ -0,0 +1,159 @@ +@import 'src/buttons.css'; + +:root { + font-size: 16px; + --main-font: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: #bcc6cf; + background-image: url('/assets/img/bg.jpg'); + background-attachment: fixed; + background-position: center top; + background-repeat: no-repeat; + font-family: var(--main-font); +} + +main#game-container { + width: 100vw; + height: 100vh; + overflow: hidden; + position: relative; +} + +div#game-ui, div#game-windows { + position: absolute; + top: 0; + left: 0; + z-index: 2; + padding: 1rem; + width: 100%; + height: 100%; +} + +div#game-windows { + display: flex; + align-items: center; + justify-content: center; + z-index: 3; + pointer-events: none; + + & > div.window { + pointer-events: auto; + background-color: #bcc6cf; + background-image: url('/assets/img/bg.jpg'); + background-attachment: fixed; + background-position: center top; + background-repeat: no-repeat; + box-shadow: 0px 0px 5px black; + border-radius: 4px; + position: absolute; + + &.hidden { + display: none; + } + + header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 1rem 0.5rem 1rem; + cursor: grab; + + .title { + font-weight: bold; + margin-right: 1rem; + user-select: none; + + &:empty { + margin-right: 0; + } + } + + .close { + width: 1.5rem; + height: 1.5rem; + user-select: none; + cursor: pointer; + } + } + + .body { + padding: 0 1rem 1rem 1rem; + + &:empty { + padding: 0; + display: none; + } + } + } +} + +canvas#game-canvas { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 1; +} + +section#character-hud { + width: 300px; + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-bottom: 1rem; + + span#character-name { + color: white; + } + + span#character-title { + color: white; + } + + div.hud-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; + } + } + } +} diff --git a/public/assets/css/src/main.css b/public/assets/css/src/main.css index b2facef..c943db0 100644 --- a/public/assets/css/src/main.css +++ b/public/assets/css/src/main.css @@ -2,6 +2,7 @@ @import 'buttons.css'; @import 'forms.css'; @import 'profile.css'; +@import 'game.css'; body { background-color: #bcc6cf; diff --git a/public/assets/scripts/WindowManager.js b/public/assets/scripts/WindowManager.js new file mode 100644 index 0000000..92dc5c8 --- /dev/null +++ b/public/assets/scripts/WindowManager.js @@ -0,0 +1,176 @@ +/* + The WindowManager is responsible for creation, destruction, modification and tracking of game UI windows. +*/ + +class WindowManager +{ + constructor(container) + { + this.windows = {} + this.container = container + } + + updateWindow(id, content, title = '') + { + if (id in this.windows) { + let w = this.windows[id] + w.querySelector('header .title').innerHTML = title + w.querySelector('.body').innerHTML = content + return + } + + this.createWindow(id, content, title) + } + + createWindow(id, content, title = '') + { + // create window + let w = document.createElement('div') + w.id = `window-${id}` + w.classList.add('window') + + // create header + let h = document.createElement('header') + w.appendChild(h) + + // create header title + let ht = document.createElement('span') + ht.classList.add('title') + ht.innerHTML = title + h.appendChild(ht) + + // create close button + ht.insertAdjacentHTML('afterend', ` + + + + `) + h.querySelector('svg').addEventListener('click', () => { + this.windows[id].remove() + delete this.windows[id] + }) + + // create body + let b = document.createElement('div') + b.classList.add('body') + b.innerHTML = content + w.appendChild(b) + + // track window and add it to the container + this.makeWindowDraggable(w, this.container) + this.windows[id] = w + this.container.appendChild(w) + } + + makeWindowDraggable(w, c) + { + const header = w.querySelector('header'); + if (!header) return; + + let isDragging = false; + let currentX; + let currentY; + let initialX; + let initialY; + + header.addEventListener('mousedown', startDragging); + document.addEventListener('mousemove', drag); + document.addEventListener('mouseup', stopDragging); + + w.addEventListener('mousedown', () => this.bringToFront(w)); + + function startDragging(e) + { + isDragging = true; + initialX = e.clientX - w.offsetLeft; + initialY = e.clientY - w.offsetTop; + } + + function drag(e) + { + if (!isDragging) return; + + e.preventDefault(); + + // Calculate new position + currentX = e.clientX - initialX; + currentY = e.clientY - initialY; + + // Get viewport dimensions + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Get window dimensions + const windowRect = w.getBoundingClientRect(); + + // Constrain to viewport bounds + // Left edge + currentX = Math.max(0, currentX); + // Right edge + currentX = Math.min(viewportWidth - windowRect.width, currentX); + // Top edge + currentY = Math.max(0, currentY); + // Bottom edge + currentY = Math.min(viewportHeight - windowRect.height, currentY); + + // Apply the constrained position + w.style.left = currentX + 'px'; + w.style.top = currentY + 'px'; + } + + function stopDragging() + { + isDragging = false; + } + + // Handle window resize + window.addEventListener('resize', () => { + // Get current position and dimensions + const rect = w.getBoundingClientRect(); + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + + // Adjust position if window is outside viewport after resize + let newX = parseInt(w.style.left); + let newY = parseInt(w.style.top); + + // Constrain to new viewport bounds + newX = Math.min(Math.max(0, newX), viewportWidth - rect.width); + newY = Math.min(Math.max(0, newY), viewportHeight - rect.height); + + w.style.left = newX + 'px'; + w.style.top = newY + 'px'; + }); + } + + normalizeZIndices() + { + const array = Array.from(this.windows); + array.sort((a, b) => (parseInt(a.style.zIndex) || 0) - (parseInt(b.style.zIndex) || 0)); + + // Reassign z-indices starting from 1 + array.forEach((win, index) => { + win.style.zIndex = index + 1; + }); + + return array.length + 1; // Return next available z-index + } + + bringToFront(windowElement) + { + const currentMax = Math.max(...Object.values(this.windows) + .map(w => parseInt(w.style.zIndex) || 0)); + + if (parseInt(windowElement.style.zIndex) >= currentMax) { + return + } + + // If z-index is getting too high, normalize all z-indices + if (currentMax > 10000) { + const newZ = this.normalizeZIndices(); + windowElement.style.zIndex = newZ; + } else { + windowElement.style.zIndex = currentMax + 1; + } + } +} diff --git a/public/index.php b/public/index.php index fcf7986..e2dfebd 100644 --- a/public/index.php +++ b/public/index.php @@ -57,6 +57,11 @@ $r->get('/settings', 'settings_controller_get'); */ $r->get('/auctions', 'auctions_controller_get'); +/* + UI +*/ +router_post($r, '/ui/stats', 'ui_contoller_stats_post'); + /* Testing */ @@ -91,8 +96,3 @@ stopwatch_stop('handler'); Cleanup */ clear_flashes(); - -/* - Stopwatch -*/ -if (env('debug')) echo c_debug_stopwatch(); diff --git a/src/bootstrap.php b/src/bootstrap.php index ae90cde..93a8816 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -25,12 +25,13 @@ require_once SRC . '/models/session.php'; require_once SRC . '/models/token.php'; // Controllers -require_once SRC . '/controllers/char.php'; -require_once SRC . '/controllers/auth.php'; -require_once SRC . '/controllers/world.php'; -require_once SRC . '/controllers/settings.php'; -require_once SRC . '/controllers/auctions.php'; -require_once SRC . '/controllers/profile.php'; +require_once SRC . '/controller/char.php'; +require_once SRC . '/controller/auth.php'; +require_once SRC . '/controller/world.php'; +require_once SRC . '/controller/settings.php'; +require_once SRC . '/controller/auctions.php'; +require_once SRC . '/controller/profile.php'; +require_once SRC . '/controller/ui.php'; spl_autoload_register(function (string $class) { if (array_key_exists($class, CLASS_MAP)) require_once SRC . CLASS_MAP[$class]; diff --git a/src/controllers/ui.php b/src/controllers/ui.php new file mode 100644 index 0000000..3c3174b --- /dev/null +++ b/src/controllers/ui.php @@ -0,0 +1,7 @@ + -

Stats

-
-
Max HP m_hp) ?>
-
Max MP m_mp) ?>
-
Power pow) ?>
-
Accuracy acc) ?>
-
Penetration pen) ?>
-
Focus foc) ?>
-
Toughness tou) ?>
-
Armor arm) ?>
-
Resist res) ?>
-
Precision pre) ?>
-
Ferocity fer) ?>
-
Luck luck) ?>
-
+
Max HP m_hp) ?>
+
Max MP m_mp) ?>
+
Power pow) ?>
+
Accuracy acc) ?>
+
Penetration pen) ?>
+
Focus foc) ?>
+
Toughness tou) ?>
+
Armor arm) ?>
+
Resist res) ?>
+
Precision pre) ?>
+
Ferocity fer) ?>
+
Luck luck) ?>
diff --git a/templates/layouts/game.php b/templates/layouts/game.php new file mode 100644 index 0000000..f9e677c --- /dev/null +++ b/templates/layouts/game.php @@ -0,0 +1,325 @@ + + + + + + Dragon Knight + + + + + +
+
+
+ name ?> + Llevel ?> title()['name'] ?> + +
+
+ +
+ +
+
+ +
+
+ + +
+ +
+ + +
+ + + + + +