diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bd20e04
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.docs.txt
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..a4951e7
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,50 @@
+version: "3.8"
+
+services:
+ phpapache:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: codebeater_phpapache
+ ports:
+ - "8080:80"
+ volumes:
+ - ./src:/var/www/html
+ depends_on:
+ - db
+ networks:
+ - codebeater_net
+
+ db:
+ image: mysql:8.0
+ container_name: codebeater_mysql
+ command: --default-authentication-plugin=mysql_native_password
+ environment:
+ MYSQL_ROOT_PASSWORD: root
+ MYSQL_DATABASE: codebeater
+ MYSQL_USER: admin
+ MYSQL_PASSWORD: admin
+ volumes:
+ - db_codebeater:/var/lib/mysql
+ networks:
+ - codebeater_net
+
+ phpmyadmin:
+ image: phpmyadmin/phpmyadmin:latest
+ container_name: codebeater_phpmyadmin
+ ports:
+ - "8081:80"
+ environment:
+ PMA_HOST: db
+ PMA_PORT: 3306
+ depends_on:
+ - db
+ networks:
+ - codebeater_net
+
+volumes:
+ db_codebeater:
+
+networks:
+ codebeater_net:
+ driver: bridge
diff --git a/dockerfile b/dockerfile
new file mode 100644
index 0000000..a8f0b15
--- /dev/null
+++ b/dockerfile
@@ -0,0 +1,7 @@
+FROM php:8.2-apache
+
+RUN docker-php-ext-install mysqli
+
+COPY ./src /var/www/html
+
+EXPOSE 80
diff --git a/logout.php b/logout.php
new file mode 100644
index 0000000..4537a38
--- /dev/null
+++ b/logout.php
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
+
+
+
✖
+
+
+
+
👾 codebeater 👾
+
+
lecturer Counselors
+
Bu Devi
+
Koh Andrew
+
+
Development Team
+
Owen
+
Matthew Florentino
+
Carolus Bramantyo
+
Yohannes Marcel
+
+
Frontend Developer
+
Yohannes Marcel
+
Matthew Florentino
+
Owen
+
+
backend Developer
+
Carolus Bramantyo
+
Matthew Florentino
+
+
Game Designers
+
Yohannes Marcel
+
+
Assets Designers
+
Yohannes Marcel
+
+
Questions Designers
+
Yohannes Marcel
+
Owen
+
+
CSS Specialist
+
Matthew Florentino
+
+
JS Specialist
+
Matthew Florentino
+
+
PHP Specialist
+
Carolus Bramantyo
+
+
SQL Specialist
+
Carolus Bramantyo
+
+
Advicer
+
Rafael
+
Erlang
+
Bu Devi
+
koh Andrew
+
+
Libary
+
Animate on Scroll
+
+
Font
+
Jetbrains Mono
+
+
Reference Game
+
Undertale
+
Soul Knight
+
Tomb of the Mask
+
+
Reference Music
+
+
+
+
+
+
+
+
👾 codebeater 👾
+
+
lecturer Counselors
+
Bu Devi
+
Koh Andrew
+
+
Development Team
+
Owen
+
Matthew Florentino
+
Carolus Bramantyo
+
Yohannes Marcel
+
+
Frontend Developer
+
Yohannes Marcel
+
Matthew Florentino
+
Owen
+
+
backend Developer
+
Carolus Bramantyo
+
Matthew Florentino
+
+
Game Designers
+
Yohannes Marcel
+
+
Assets Designers
+
Yohannes Marcel
+
+
Questions Designers
+
Yohannes Marcel
+
Owen
+
+
CSS Specialist
+
Matthew Florentino
+
+
JS Specialist
+
Matthew Florentino
+
+
PHP Specialist
+
Carolus Bramantyo
+
+
SQL Specialist
+
Carolus Bramantyo
+
+
Advicer
+
Rafael
+
Erlang
+
Bu Devi
+
koh Andrew
+
+
Libary
+
Animate on Scroll
+
+
Font
+
Jetbrains Mono
+
+
Reference Game
+
Undertale
+
Soul Knight
+
Tomb of the Mask
+
+
Reference Music
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/css/game.css b/src/css/game.css
new file mode 100644
index 0000000..85ac9ae
--- /dev/null
+++ b/src/css/game.css
@@ -0,0 +1,264 @@
+.container-third .bg {
+ width: 100%;
+ height: 100dvh;
+}
+
+.container-third .bg {
+ position: relative;
+}
+
+
+.container-third .bg img {
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.container-third .hero img {
+ width: 150px;
+ position: absolute;
+ bottom: 100px;
+ left: 50px;
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.container-third .boss img {
+ width: 300px;
+ position: absolute;
+ bottom: 100px;
+ right: 50px;
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.container-first {
+ background-image: url(/assets/Design/newBGBOSSFIGHT.gif);
+ background-repeat: no-repeat;
+ background-size: cover;
+ image-rendering: pixelated;
+ background-position: center;
+}
+
+.container-first .content .boss {
+ width: 100%;
+ height: 100dvh;
+ position: relative;
+ animation: beat 2s infinite;
+ transform-origin: center;
+}
+
+.container-first .content .boss img {
+ width: 600px;
+ position: absolute;
+ bottom: 100px;
+ left: 50%;
+ transform: translateX(-50%);
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
+
+.container-first .content .boss .dmg {
+ width: 600px;
+ position: absolute;
+ bottom: 100px;
+ left: 50%;
+ transform: translateX(-50%);
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+ display: none;
+}
+
+@keyframes shake {
+ 0% {
+ transform: translateX(-50%);
+ }
+
+ 25% {
+ transform: translateX(calc(-50% - 5px));
+ }
+
+ 50% {
+ transform: translateX(calc(-50% + 5px));
+ }
+
+ 75% {
+ transform: translateX(calc(-50% - 5px));
+ }
+
+ 100% {
+ transform: translateX(-50%);
+ }
+}
+
+.animate-shake {
+ animation: shake 0.3s ease-in-out;
+}
+
+.container-first .hearts {
+ position: absolute;
+ top: 322px;
+ left: 50%;
+ transform: translateX(-50%);
+ image-rendering: pixelated;
+ z-index: 999;
+}
+
+.container-first .hearts img {
+ width: 50px;
+}
+
+.container-first .content .quiz {
+ width: 1000px;
+ height: 200px;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ background-color: #101010f5;
+ position: absolute;
+ display: flex;
+ justify-content: start;
+ text-align: center;
+ align-content: center;
+ padding: 10px;
+ display: flex;
+ flex-direction: column;
+ border: 10px solid white;
+ border-radius: 10px;
+}
+
+.container-first .content .quiz h2 {
+ margin-bottom: 30px;
+ padding: 10px;
+ color: #ffdf12;
+ font-size: 40px;
+}
+
+.container-first #scoreAlert {
+ text-align: center;
+ padding: 10px;
+ color: #ffdf12;
+ font-size: 40px;
+ bottom: 22px;
+ background-color: #101010f5;
+ left: 50%;
+ transform: translateX(-50%);
+ position: absolute;
+}
+
+.container-first #scoreAlert.border {
+ width: 550px;
+ border: 6px solid white;
+ border-radius: 10px;
+}
+
+.container-first .content .quiz #btn-answer {
+ color: #ffdf12;
+ display: flex;
+ justify-content: center;
+}
+
+.container-first .content .quiz #btn-answer button {
+ padding: 10px;
+ color: #ffdf12;
+ font-size: 30px;
+ background-color: #f7e62e34;
+ margin: 5px;
+ border-radius: 10px;
+ cursor: pointer;
+}
+
+@keyframes beat {
+ 0% {
+ transform: scale(1);
+ }
+
+ 50% {
+ transform: scale(0.95);
+ }
+
+ 100% {
+ transform: scale(1);
+ }
+}
+
+.container-load {
+ position: relative;
+ min-height: 100dvh;
+}
+
+.container-load .bg {
+ background-size: cover;
+ width: 100%;
+ height: 100dvh;
+ position: absolute;
+ z-index: -999;
+}
+
+.container-load .anm {
+ font-size: 25px;
+ background-size: cover;
+ position: absolute;
+ bottom: 50%;
+ text-align: center;
+ width: 100%;
+}
+
+.container-load .hero {
+ width: 100px;
+ position: absolute;
+ image-rendering: pixelated;
+ bottom: -5%;
+ left: 5%;
+ transform: translate(-50%, -50%);
+ z-index: 999;
+}
+
+.floating-points {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ color: #ffdf12;
+ font-size: 3rem;
+ font-weight: bold;
+ text-shadow: 2px 2px 0px #000;
+ pointer-events: none;
+ z-index: 999;
+ animation: floatUp 1s ease-out forwards;
+}
+
+@keyframes floatUp {
+ 0%{
+ opacity: 1;
+ transform: translate(-50%,-50%) scale(1);
+ }
+ 100%{
+ opacity: 0;
+ transform: translate(-50%, -150%) scale(1.5)
+ }
+}
+
+.dmg{
+ width: 800px;
+
+ position: absolute;
+ top: 40%;
+ left: 50%;
+ transform: translate(-50%,-50%);
+
+ z-index: 9999;
+ pointer-events: none;
+
+ display: none;
+ image-rendering: pixelated;
+ background-repeat: no-repeat;
+ background-size: cover;
+}
diff --git a/src/css/global.css b/src/css/global.css
new file mode 100644
index 0000000..deaae3c
--- /dev/null
+++ b/src/css/global.css
@@ -0,0 +1,13 @@
+@import url('https://fonts.googleapis.com/css2?family=Jersey+15&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
+
+*{
+ font-family: "Jersey 15", sans-serif;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ color: white;
+ background-color: black;
+}
+
diff --git a/src/css/style.css b/src/css/style.css
new file mode 100644
index 0000000..b6d4b27
--- /dev/null
+++ b/src/css/style.css
@@ -0,0 +1,347 @@
+input:-webkit-autofill {
+ -webkit-box-shadow: 0 0 0 1000px #000 inset !important;
+ -webkit-text-fill-color: #fff !important;
+}
+
+.container-login {
+ display: flex;
+ width: 100%;
+ height: 100dvh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.container-login h1 {
+ font-size: 130px;
+ font-weight: 400;
+}
+
+.container-login form {
+ text-align: center;
+ padding: 30px;
+}
+
+.container-login form h2 {
+ margin-bottom: 20px;
+ font-size: 40px;
+ text-transform: capitalize;
+}
+
+.container-login form input {
+ margin-bottom: 10px;
+ width: 300px;
+ height: 40px;
+ border-radius: 6px;
+ font-size: 20px;
+ text-align: center;
+ background-color: black;
+ border: 1px solid white;
+ color: white;
+}
+
+.container-login form input::placeholder {
+ color: #919191;
+}
+
+.container-login form button {
+ border-radius: 6px;
+ width: 300px;
+ height: 40px;
+ margin-top: 40px;
+ font-size: 30px
+}
+
+.container-login form p {
+ margin-top: 10px;
+}
+
+.container-login form p a {
+ color: white;
+ text-decoration: none;
+}
+
+.container-login form p a span {
+ color: yellow;
+}
+
+.container-register {
+ display: flex;
+ width: 100%;
+ height: 100dvh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.container-register h1 {
+ font-size: 120px;
+ font-weight: 400;
+}
+
+.container-register form {
+ text-align: center;
+ padding: 30px;
+}
+
+.container-register form h2 {
+ margin-bottom: 10px;
+ font-size: 30px;
+ text-transform: capitalize;
+}
+
+.container-register form input {
+ margin-bottom: 10px;
+ width: 300px;
+ height: 40px;
+ border-radius: 6px;
+ font-size: 20px;
+ text-align: center;
+ background-color: black;
+ border: 1px solid white;
+ color: white;
+}
+
+.container-register form input::placeholder {
+ color: #919191;
+}
+
+.container-register form button {
+ border-radius: 6px;
+ width: 300px;
+ height: 40px;
+ margin-top: 10px;
+ font-size: 30px
+}
+
+.container-register form p {
+ margin-top: 10px;
+}
+
+.container-register form p a {
+ color: white;
+ text-decoration: none;
+}
+
+.container-register form p a span {
+ color: yellow;
+}
+
+.container-board {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ height: 100dvh;
+ position: relative;
+ z-index: 1;
+}
+
+
+.container-board::before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-image: url(/assets/Design/CampFire8WESFIX!-export.png);
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center;
+ image-rendering: pixelated;
+ opacity: 1;
+ z-index: -1;
+}
+
+.container-board .chara {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ align-items: center;
+}
+
+.container-board .chara .character {
+ display: flex;
+ width: 100%;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+}
+
+.container-board .chara .character img {
+ width: 300px;
+ image-rendering: pixelated;
+ margin: 20px;
+}
+
+.container-board .menu {
+ margin: 0 auto;
+ border-radius: 6px;
+ width: 400px;
+ height: 40px;
+ align-content: center;
+}
+
+.container-board .board table {
+ width: 600px;
+ margin: 40px auto;
+ border-collapse: collapse;
+ /*menghilangkan gap antar border*/
+ font-family: "Segoe UI", Tahoma, sans-serif;
+ color: white;
+ font-weight: 200;
+ font-size: 20px;
+ border-radius: 10px;
+ overflow: hidden;
+}
+
+.container-board .board table th,
+td {
+ border: 5px solid #ffffff;
+ padding: 14px 18px;
+ white-space: nowrap;
+ text-align: center;
+}
+
+.container-board .board table thead th {
+ font-weight: 400;
+ font-size: 20px;
+ color: #bbd000;
+ letter-spacing: .4px;
+}
+
+
+.container-board .board table {
+ background: #0b0e00f3;
+}
+
+.container-board .board table tbody tr:hover {
+ background: #c1fc0032;
+}
+
+.container-board .back {
+ color: #ffff009a;
+ text-decoration: none;
+ font-size: 30px;
+ position: absolute;
+ z-index: 99999;
+ left: 2%;
+ top: 5%;
+}
+
+.container-board .back:hover {
+ color: yellow;
+}
+
+.container-onboard {
+ display: flex;
+ width: 100%;
+ height: 100dvh;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ background-image: url(/assets/Design/landingPage.png);
+ background-position: center;
+}
+
+.container-onboard h1 {
+ font-size: 150px;
+ color: yellow;
+ font-weight: 400;
+ margin-bottom: 50px;
+}
+
+.container-onboard .menu {
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+}
+
+.container-onboard .menu a {
+ padding: 10px 80px;
+ background-color: #87871b23;
+ margin: 8px;
+ border-radius: 5px;
+ font-size: 30px;
+ color: yellow;
+ border: 1px solid #8170029f;
+ text-decoration: none;
+}
+
+.container-onboard .menu a:hover {
+ transition: 0.4s ease-out;
+ color: #dd85fa;
+ border: 1px solid #dd85fa;
+ background-color: #871b8323;
+}
+
+.container-credits {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100vh;
+ background-image: url(/assets/Design/creditbg.png);
+ margin: 0;
+ background-position: center;
+ background-size:cover ;
+}
+
+.container-credits .credits {
+ width: 100%;
+ height: var(--height);
+ overflow: hidden;
+ border-radius: 8px;
+ padding: 24px 12px;
+ position: relative;
+}
+
+.container-credits .credits .credits-inner {
+ display: flex;
+ flex-direction: column;
+ transform: translateY(0);
+ will-change: transform;
+}
+
+.container-credits .credits .credits-inner h1 {
+ font-size: 150px;
+ color: yellow;
+ font-weight: 400;
+ margin-bottom: 50px;
+ text-align: center;
+}
+
+.container-credits .credits .credits-inner .role {
+ font-weight: 400;
+ color: yellow;
+ margin-top: 10px;
+ text-align: center;
+ padding: 6px 0;
+ font-size: 50px;
+ line-height: 1.25;
+ text-shadow: 0 1px 0 rgba(0, 0, 0, .6);
+}
+
+.container-credits .credits .credits-inner .name {
+ font-weight: 400;
+ color: #ffffff;
+ font-size: 14px;
+ text-align: center;
+ padding: 6px 0;
+ font-size: 30px;
+ line-height: 1.25;
+ text-shadow: 0 1px 0 rgba(0, 0, 0, .6);
+}
+
+.container-credits .back {
+ color: #ffff009a;
+ text-decoration: none;
+ font-size: 30px;
+ position: absolute;
+ z-index: 99999;
+ left: 2%;
+ top: 5%;
+}
+
+.container-credits .back:hover {
+ color: yellow;
+}
\ No newline at end of file
diff --git a/src/game/firstperson.html b/src/game/firstperson.html
new file mode 100644
index 0000000..1a0e96e
--- /dev/null
+++ b/src/game/firstperson.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/game/loading.html b/src/game/loading.html
new file mode 100644
index 0000000..20dd048
--- /dev/null
+++ b/src/game/loading.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
Welcome to the Python
+ Quiz! You’ll face multiple-choice questions designed to test your logic and Python skills.
+ Let’s see how well you can outsmart the code!
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/game/thirdperson.html b/src/game/thirdperson.html
new file mode 100644
index 0000000..8c9014f
--- /dev/null
+++ b/src/game/thirdperson.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/index.php b/src/index.php
new file mode 100644
index 0000000..7adf652
--- /dev/null
+++ b/src/index.php
@@ -0,0 +1,81 @@
+prepare($sql); // agar aman dari sql injection
+ $stmt->bind_param("s", $username); // agar rapi tidak muncul di bagian atas query
+ $stmt->execute();
+ $result = $stmt->get_result();
+
+ if ($result->num_rows === 1) {
+
+ $user = $result->fetch_assoc();
+
+ if (password_verify($password, $user['password'])) {
+ $_SESSION['loggedin'] = true;
+ $_SESSION['username'] = $user['username'];
+ $_SESSION['id'] = $user['id'];
+ $_SESSION['flash'] = "Wellcome to Dungeon, player $username";
+ header("Location: onboard.php");
+ exit();
+
+ } else {
+ $_SESSION['flash'] = "Password salah!";
+ }
+
+ } else {
+ $_SESSION['flash'] = "Username tidak ditemukan!";
+ }
+ }
+
+}
+?>
+
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+ showNotif(" . json_encode($_SESSION['flash']) . ");";
+ unset($_SESSION['flash']);
+ }
+ ?>
+
+
codebeater
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/js/firstperson.js b/src/js/firstperson.js
new file mode 100644
index 0000000..84080ae
--- /dev/null
+++ b/src/js/firstperson.js
@@ -0,0 +1,195 @@
+import { questions } from "./soal.js";
+
+const questionElement = document.getElementById("question")
+const answerBtn = document.getElementById("btn-answer")
+const answerBorder = document.getElementById("border")
+
+let currentQuestionIndex = 0;
+let score = 0;
+
+let wrongCount = 0;
+let maxWrong = 3;
+
+function shuffle(array) {
+ for (let i = array.length - 1; i > 0; i--) {
+ const j = Math.floor(Math.random() * (i + 1));
+ [array[i], array[j]] = [array[j], array[i]];
+ }
+ return array;
+}
+
+function startQuiz(){
+ currentQuestionIndex = 0;
+ score = 0;
+ shuffle(questions);
+ showQuestion();
+}
+
+
+function showQuestion(){
+ resetState();
+ let currentQuestion = questions[currentQuestionIndex]
+ let questionNumber = currentQuestionIndex + 1
+ questionElement.innerHTML = questionNumber + ". " + currentQuestion.question;
+ currentQuestion.answers.forEach(answer => {
+ const button = document.createElement("button");
+ button.innerHTML = answer.text;
+ button.classList.add("btn");
+ answerBtn.appendChild(button);
+ button.dataset.correct = answer.correct;
+ button.addEventListener("click", selectAnswer)
+ });
+}
+
+function resetState(){
+ while(answerBtn.firstChild){
+ answerBtn.removeChild(answerBtn.firstChild)
+ }
+}
+
+function updateHearts(){
+ const hearts = [
+ document.getElementById("h1"),
+ document.getElementById("h2"),
+ document.getElementById("h3")
+ ];
+
+ hearts.forEach((h, i) => {
+ if(i < wrongCount){
+ h.src = "/assets/Design/HeartEmpty.png";
+ } else {
+ h.src = "/assets/Design/Heartfull.png";
+ }
+ });
+
+}
+
+function dmg(){
+ const dmg = document.getElementById("dmg");
+
+ dmg.style.display = "block";
+
+ setTimeout(() => {
+ dmg.style.display = "none";
+ }, 450);
+}
+
+function shake(el){
+ el.classList.remove("animate-shake");
+ void el.offsetWidth;
+ el.classList.add("animate-shake");
+
+ el.addEventListener("animationend", () => {
+ el.classList.remove("animate-shake");
+ }, { once: true });
+}
+
+
+function selectAnswer(e){
+ const selectedBtn = e.target;
+ const isCorrect = selectedBtn.dataset.correct === "true";
+ if(isCorrect){
+ selectedBtn.classList.add("correct");
+ score += 10;
+
+ showFloatingText();
+
+ shake(document.getElementById("boss"))
+ dmg();
+ const bgm = document.getElementById("sfx");
+ bgm.play()
+ } else {
+ selectedBtn.classList.add("Incorrect");
+ wrongCount ++;
+ shake(document.getElementById("hrt"))
+ updateHearts();
+ const bgm = document.getElementById("sfxhrt");
+ bgm.play()
+
+ if(wrongCount >= maxWrong){
+ showScore();
+ return;
+ }
+ }
+
+ Array.from(answerBtn.children).forEach(button => {
+ if(button.dataset.correct === "true") button.classList.add("correct");
+ button.disabled = true;
+ });
+ setTimeout(nextQuestion, 500)
+}
+
+function showScore(){
+ resetState();
+ answerBorder.remove();
+ document.getElementById("h1").remove();
+ document.getElementById("h2").remove();
+ document.getElementById("h3").remove();
+ const bgm = document.getElementById("win");
+ bgm.play()
+ setTimeout(()=> {
+ const alerts = document.getElementById("scoreAlert")
+ alerts.classList.add("border")
+ alerts.textContent = `you scored ${score} out of 200 !`;
+ }, 200);
+ setTimeout(()=> {
+ postScore(score);
+ }, 3200);
+}
+
+function handleNextBtn(){
+ currentQuestionIndex++;
+ if(currentQuestionIndex < questions.length){
+ showQuestion();
+ } else {
+ showScore();
+ }
+}
+
+function nextQuestion(){
+ if(currentQuestionIndex < questions.length){
+ handleNextBtn()
+ } else {
+ showScore()
+ }
+}
+
+function postScore(score){
+ fetch('/score.php', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ score: score })
+ })
+ .then(r => r.json())
+ .then(data => {
+ console.log("Server response:", data);
+
+ if(data.success || data.message === "Score accumulated") {
+ setTimeout(() => {
+ window.location.href = "../leaderboard.php";
+ }, 3000);
+ } else {
+ setTimeout(() => {
+ window.location.href = "../leaderboard.php";
+ }, 3000);
+ }
+ })
+ .catch(err => {
+ console.error("Fetch error:", err);
+ alert("Terjadi kesalahan koneksi.");
+ });
+}
+function showFloatingText(){
+ const bossContainer = document.querySelector(".boss");
+ const point = document.createElement("div");
+
+ point.textContent = "+10";
+ point.classList.add("floating-points");
+
+ bossContainer.appendChild(point);
+
+ setTimeout(()=>{
+ point.remove();
+ }, 800);
+}
+startQuiz()
\ No newline at end of file
diff --git a/src/js/notif.js b/src/js/notif.js
new file mode 100644
index 0000000..41ddb93
--- /dev/null
+++ b/src/js/notif.js
@@ -0,0 +1,9 @@
+function showNotif(msg) {
+ const n = document.getElementById("notif");
+ n.textContent = msg;
+ n.classList.add("show");
+
+ setTimeout(() => {
+ n.classList.remove("show");
+ }, 3000);
+}
\ No newline at end of file
diff --git a/src/js/soal.js b/src/js/soal.js
new file mode 100644
index 0000000..01323f8
--- /dev/null
+++ b/src/js/soal.js
@@ -0,0 +1,182 @@
+export const questions = [
+ {
+ question: "what is Python ?",
+ answers: [
+ {text: "Programming Lang", correct: true},
+ {text: "Animal", correct: false},
+ {text: "Danger", correct: false},
+ {text: "All Answer Correct", correct: false},
+ ]
+ },
+ {
+ question: "Data type at python ?",
+ answers: [
+ {text: "Docx", correct: false},
+ {text: "CSV", correct: false},
+ {text: "String", correct: true},
+ {text: "SQL", correct: false},
+ ]
+ },
+ {
+ question: "Index at python start from ?",
+ answers: [
+ {text: "1", correct: false},
+ {text: "-1", correct: false},
+ {text: "10", correct: false},
+ {text: "0", correct: true},
+ ]
+ },
+ {
+ question: "How do you start a comment in Python code ?",
+ answers: [
+ {text: "// This is a comment", correct: true},
+ {text: "/* This is a comment */", correct: false},
+ {text: "`this is comment`", correct: false},
+ {text: "# This is a comment", correct: false},
+ ]
+ },
+ {
+ question: "What is the result of the following operation ? (print('5'+'5'))",
+ answers: [
+ {text: "10", correct: false},
+ {text: "55", correct: true},
+ {text: "error", correct: false},
+ {text: "NaN", correct: false},
+ ]
+ },
+ {
+ question: "Correct string format ?",
+ answers: [
+ {text: "'bahlil'", correct: true},
+ {text: "(bahlil)", correct: false},
+ {text: "[bahlil]", correct: false},
+ {text: "{bahlil}", correct: false},
+ ]
+ },
+ {
+ question: "Correct loop syntax ?",
+ answers: [
+ {text: "for i in range(5):", correct: true},
+ {text: "loop 5 time", correct: false},
+ {text: "foreach i in 5", correct: false},
+ {text: "repeat", correct: false},
+ ]
+ },
+ {
+ question: "Function to get user input ?",
+ answers: [
+ {text: "scan()", correct: false},
+ {text: "input()", correct: true},
+ {text: "error", correct: false},
+ {text: "get()", correct: false},
+ ]
+ },
+ {
+ question: "Convert integer to string ?",
+ answers: [
+ {text: "text(5)", correct: false},
+ {text: "toStr(5)", correct: false},
+ {text: "str(5)", correct: true},
+ {text: "char(5)", correct: false},
+ ]
+ },
+ {
+ question: "Stop a loop ?",
+ answers: [
+ {text: "break", correct: true},
+ {text: "stop", correct: false},
+ {text: "exit", correct: false},
+ {text: "kill", correct: false},
+ ]
+ },
+ {
+ question: "Symbol for tuples?",
+ answers: [
+ {text: "[ ]", correct: false},
+ {text: "{ }", correct: false},
+ {text: "( )", correct: true},
+ {text: "< >", correct: false},
+ ]
+ },
+ {
+ question: "Output of int(3.9) ?",
+ answers: [
+ {text: "4", correct: false},
+ {text: "3,9", correct: false},
+ {text: "3", correct: true},
+ {text: "tiga koma sembilan", correct: false},
+ ]
+ },
+ {
+ question: "Find max number ?",
+ answers: [
+ {text: "top()", correct: false},
+ {text: "max()", correct: true},
+ {text: "high()", correct: false},
+ {text: "largest()", correct: false},
+ ]
+ },
+ {
+ question: '(3 * "A") output ?',
+ answers: [
+ {text: "error", correct: false},
+ {text: "none", correct: false},
+ {text: "AAA", correct: true},
+ {text: "A3A", correct: false},
+ ]
+ },
+ {
+ question: "Logical OR operator ?",
+ answers: [
+ {text: "||", correct: false},
+ {text: "%%", correct: false},
+ {text: "or", correct: true},
+ {text: "&&", correct: false},
+ ]
+ },
+ {
+ question: "result of not True ?",
+ answers: [
+ {text: "true", correct: false},
+ {text: "false", correct: true},
+ {text: "null", correct: false},
+ {text: "0", correct: false},
+ ]
+ },
+ {
+ question: "Check if item exists ?",
+ answers: [
+ {text: "exists", correct: false},
+ {text: "inside", correct: false},
+ {text: "in", correct: true},
+ {text: "has", correct: false},
+ ]
+ },
+ {
+ question: "x += 1 means?",
+ answers: [
+ {text: "x = 1", correct: false},
+ {text: "x = x + 1", correct: true},
+ {text: "x = x - 1", correct: false},
+ {text: "idk", correct: false},
+ ]
+ },
+ {
+ question: "Define a class ?",
+ answers: [
+ {text: "struct", correct: false},
+ {text: "object", correct: false},
+ {text: "type", correct: false},
+ {text: "class", correct: true},
+ ]
+ },
+ {
+ question: "how much data type in python ?",
+ answers: [
+ {text: "5", correct: true},
+ {text: "1", correct: false},
+ {text: "2", correct: false},
+ {text: "100", correct: false},
+ ]
+ },
+];
\ No newline at end of file
diff --git a/src/js/thirdperson.js b/src/js/thirdperson.js
new file mode 100644
index 0000000..331e40b
--- /dev/null
+++ b/src/js/thirdperson.js
@@ -0,0 +1,18 @@
+const hero = document.getElementById('hero');
+const boss = document.getElementById('boss');
+
+boss.style.transition = '2s cubic-bezier(0.4, 0, 0.2, 1)';
+hero.style.transition = '2s cubic-bezier(0.4, 0, 0.2, 1)';
+
+setTimeout(() => {
+ hero.style.left = '1000px';
+}, 500);
+setTimeout(()=> {
+ hero.src = "/assets/Design/KnightPixLE2-exporgift.gif";
+}, 1700);
+
+setTimeout(()=> {
+ window.location.href = "/game/loading.html"
+}, 3000)
+
+
diff --git a/src/leaderboard.php b/src/leaderboard.php
new file mode 100644
index 0000000..fe2631b
--- /dev/null
+++ b/src/leaderboard.php
@@ -0,0 +1,116 @@
+0){
+ $row = mysqli_fetch_assoc($result_me);
+ $score = $row['score'];
+}
+
+$queryrank = "SELECT COUNT(*) as ranking FROM users WHERE score > $score";
+$resultrank = mysqli_query($db, $queryrank);
+$rowrank = mysqli_fetch_assoc($resultrank);
+$realrank = $rowrank['ranking']+1;
+
+$result = mysqli_query($db, $sql);
+$leaderboard = [];
+
+if($result){
+ $leaderboard = mysqli_fetch_all($result, MYSQLI_ASSOC);
+}
+
+?>
+
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
✖
+
+
+
Knight
+
+
+
+
+
+
+
+ #
+ Username
+ Score
+
+
+
+
+
+
+
+
+ PTS
+
+
+ Belum ada pemain ';
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/logout.php b/src/logout.php
new file mode 100644
index 0000000..4537a38
--- /dev/null
+++ b/src/logout.php
@@ -0,0 +1,11 @@
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/onboard.php b/src/onboard.php
new file mode 100644
index 0000000..3dcd6e2
--- /dev/null
+++ b/src/onboard.php
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+
+
+
+
+ showNotif(" . json_encode($_SESSION['flash']) . ");";
+ unset($_SESSION['flash']);
+ }
+ ?>
+
👾 codebeater 👾
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/register.php b/src/register.php
new file mode 100644
index 0000000..19891f5
--- /dev/null
+++ b/src/register.php
@@ -0,0 +1,88 @@
+ prepare($sql);
+
+ $stmt->bind_param("sss",$email,$username,$hashpw);
+
+
+ if($stmt->execute()){
+
+ header("location:index.php");
+ exit();
+
+ }else{
+ if($stmt->erno==1602){
+ $_SESSION['flash'] = "email atau username sudah pernah terdaftar";
+ }else{
+ $_SESSION['flash'] = "Regitrasi gagal: ".$stmt->error;
+ }
+ }
+ $stmt -> close();
+ }
+}$db->close()
+?>
+
+
+
+
+
+
+
+ codebeater
+
+
+
+
+
+
+
+ showNotif(" . json_encode($_SESSION['flash']) . ");";
+ unset($_SESSION['flash']);
+ }
+ ?>
+
+
codebeater
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/score.php b/src/score.php
new file mode 100644
index 0000000..97421af
--- /dev/null
+++ b/src/score.php
@@ -0,0 +1,38 @@
+ "score missing"]);
+ exit;
+}
+
+$score = (int)$data['score'];
+$user_id = isset($_SESSION['id']) ? (int)$_SESSION['id'] : null;
+
+if (!$user_id) {
+ echo json_encode(["error" => "no session user"]);
+ exit;
+}
+
+$sql = "UPDATE users SET score = score + ? where id =? ";
+$stmt = $db ->prepare($sql);
+
+if ($stmt){
+ $stmt->bind_param("ii",$score,$user_id);
+ if($stmt->execute()){
+ echo json_encode(["success" => true, "message" => "Score accumulated"]);
+ }else{
+ echo json_encode(["error" => "update failed: " . $stmt->error]);
+ }
+ $stmt->close();
+}else{
+ echo json_encode(["error" => "stetment prep failed"]);
+}
+
+$db->close();
+?>
\ No newline at end of file
diff --git a/users.sql b/users.sql
new file mode 100644
index 0000000..86575b3
--- /dev/null
+++ b/users.sql
@@ -0,0 +1,80 @@
+-- phpMyAdmin SQL Dump
+-- version 5.2.3
+-- https://www.phpmyadmin.net/
+--
+-- Host: db:3306
+-- Generation Time: Dec 01, 2025 at 08:08 AM
+-- Server version: 8.0.44
+-- PHP Version: 8.3.26
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `codebeater`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `users`
+--
+
+CREATE TABLE `users` (
+ `id` int NOT NULL,
+ `username` varchar(50) NOT NULL,
+ `email` varchar(100) NOT NULL,
+ `password` varchar(255) NOT NULL,
+ `score` int NOT NULL DEFAULT '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+
+--
+-- Dumping data for table `users`
+--
+
+INSERT INTO `users` (`id`, `username`, `email`, `password`, `score`) VALUES
+(1, 'bram', 'bahlil@gmail.com', '$2y$10$tOKCS5lO0/lRUW9c.VmsAeMu1M5LxO9F2lq/44yLk3Dl7FvmFUWEu', 100),
+(4, 'bahlil', 'bahlil1@gmail.com', '$2y$10$qmU02E22qB6MD5RR8Bopi.nBI38jk2mOht2SHnXb64m30fpyg8cf6', 0),
+(8, 'fork', 'bolo@gmail.com', '$2y$10$XZ/uNqSGiZhfCjDEaZUzner0L2tKRBrEVX5cNG0nK4f/IFuf42jCK', 0),
+(13, 'adsasd', 'da@gmail.com', '$2y$10$lOWJD1OLc9/pREEvH72b4u7YDZpekwX9W/Wt7mlhSnJuhKNC2dm1i', 0),
+(20, 'bobi', 'skibidi@gmail.com', '$2y$10$v2SToxPT3kzfD1BPMJuQGe2kOKqaX7ZcHyuvyUaAWm/GySx2RaAqW', 0),
+(21, 'sada', 'sad@gmail.com', '$2y$10$JO0oMbKmJHbUhRNCcyYxnOwK0OFLv69FCItzwCK0h0p6KeAzvekGW', 0),
+(24, 'orgil', 'fasfa@gmail.com', '$2y$10$rxkVaEwirysMIiaDgrixQeCbuGpkMdbvA2Kvw.l2t0hk7PO4KzZ4i', 0),
+(28, 'bencong', 'bahliltod@gmai.com', '$2y$10$yM13E5kcWDU.FPUpuWkWbuGqpq9tMfS2vKE1Wu8xMPbHleNSCI5pW', 0),
+(29, 'adudu', 'adudu@gmail.com', '$2y$10$MW5hI5zKBNDHpEgGOipozOVPaH985N0.J1qxHen15eK1KVI6HfKa.', 0),
+(30, 'kkhungke', 'cuki@gmail.com', '$2y$10$6u2vzf6icHzmZeIqDfBHqOEwjGEcpuo0c7QGmZeuzICq71Af0vY6y', 0),
+(33, 'koko', 'kkhungke@gmail.com', '$2y$10$ys7rs4PAtl0z74RfgNuu9O50t.ibMgljWEC8x.9Anm3DBw5aB7q8C', 0);
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `users`
+--
+ALTER TABLE `users`
+ ADD PRIMARY KEY (`id`),
+ ADD UNIQUE KEY `username` (`username`),
+ ADD UNIQUE KEY `email` (`email`);
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `users`
+--
+ALTER TABLE `users`
+ MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=34;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;