1const gamepads = {};
2const deadZone = 0.05;
3
4let cheatcodes = [];
5const cheatkeys = ["h", "l", "k", "1", "8"];
6let cheatTimeout;
7let isCheatActivated = false;
8
9const tooltip = document.getElementById("tooltip");
10const keyboard = document.getElementById("keyboard");
11
12const w = document.querySelector("#w");
13const s = document.querySelector("#s");
14const a = document.querySelector("#a");
15const d = document.querySelector("#d");
16
17const controller = document.getElementById("controller");
18const hitbox = document.getElementById("character-hitbox");
19const character = document.getElementById("character");
20const dialog = document.querySelector(".character-dialog");
21
22const backBtn = document.getElementById("BACK");
23const startBtn = document.getElementById("START");
24const leftBtn = document.getElementById("LEFT");
25const rightBtn = document.getElementById("RIGHT");
26const upBtn = document.getElementById("UP");
27const downBtn = document.getElementById("DOWN");
28const btnX = document.getElementById("xbox-x");
29const btnY = document.getElementById("xbox-y");
30const btnA = document.getElementById("xbox-a");
31const btnB = document.getElementById("xbox-b");
32const btnL1 = document.getElementById("xbox-L1");
33const btnR1 = document.getElementById("xbox-R1");
34const btnL2 = document.getElementById("xbox-L2");
35const btnR2 = document.getElementById("xbox-R2");
36const btnL2Path = document.getElementById("xbox-L2-Path");
37const btnR2Path = document.getElementById("xbox-R2-Path");
38const leftAnalog = document.getElementById("xbox-LAnalog");
39const rightAnalog = document.getElementById("xbox-RAnalog");
40const leftAnalogPath = document.getElementById("xbox-LAnalog-Path");
41const rightAnalogPath = document.getElementById("xbox-RAnalog-Path");
42
43const dialogs = [
44 "I'm not a photographer,<br/> but I can picture us together.",
45 "Do you have a name, or can I call you mine?",
46 "If you were a vegetable,<br/> you'd be a cute-cumber.",
47 "Do you have a map?<br/> I keep getting lost in your eyes.",
48 "Are you a magician?<br/> Whenever I look at you, everyone else disappears.",
49 "If you were a fruit,<br/> you'd be a fineapple.",
50 "Do you like Star Wars?<br/> Because Yoda one for me!",
51 "If you were a cat,<br/> you'd purr-fect.",
52 "Are you a bank loan?<br/> Because you have my interest.",
53 "Do you have a sunburn,<br/> or are you always this hot?",
54 "Do you like raisins?<br/> How do you feel about a date?",
55 "If you were a triangle,<br/> you'd be acute one.",
56 "Are you a campfire?<br/> Because you're hot and I want s'more.",
57 "Do you like science?<br/> Because I've got my ion you.",
58 "Are you a beaver?<br/> Because daaaaaam.",
59 "Are you a parking ticket?<br/> Because you've got FINE written all over you.",
60]
61
62function removeGamepad(gamepad) {
63 delete gamepads[gamepad.index];
64}
65function addGamepad(gamepad) {
66 if (isCheatActivated) {
67 return;
68 }
69
70 gamepads[gamepad.index] = gamepad;
71 requestAnimationFrame(updateStatus);
72 if (Object.keys(gamepads).length > 1) {
73 tooltip.innerHTML = "Multiple gamepads connected! Please use only one.";
74 controller.style.opacity = 0.25;
75 return;
76 }
77 controller.style.opacity = 0.85;
78 tooltip.innerHTML = gamepad.id;
79 hitbox.style.visibility = "visible";
80 dialog.style.visibility = "visible";
81 dialog.innerHTML = "Hello Gorgeous! ";
82}
83function pressuredButton(btn, path, state) {
84 btn.style.opacity = state;
85 btn.style.transform = `translate(0,${state * 7}px)`
86 path.style.transform = `translate(0,${state * 7}px)`
87}
88function activateButton(btn, state,vibrate = false) {
89 if (state) {
90 btn.style.fill = "var(--lightGold)";
91 if (vibrate) {
92 gamepads[0].vibrationActuator.playEffect("dual-rumble", {
93 duration: 10,
94 strongMagnitude: 0.5,
95 weakMagnitude: 0.5
96 });
97 }
98 } else {
99 btn.style.fill = "black";
100 }
101}
102function analogButton(btn, path, x, y, isAnalogLeftStick) {
103 if (Math.abs(x) < deadZone) x = 0;
104 if (Math.abs(y) < deadZone) y = 0;
105
106 btn.style.transform = `translate(${x * 10}px,${y * 10}px)`
107 path.style.transform = `translate(${x * 10}px,${y * 10}px)`
108
109 if (!isAnalogLeftStick) {
110 return
111 }
112
113 let characterDirection = "";
114 character.classList.toggle("face-up", false);
115 character.classList.toggle("face-down", false);
116 character.classList.toggle("face-left", false);
117 character.classList.toggle("face-right", false);
118
119 if (x === 0 && y === 0) {
120 return;
121 }
122 if (x > 0) {
123 characterDirection = "right";
124 character.classList.toggle("face-right", true);
125 } else if (x < 0) {
126 character.classList.toggle("face-left", true);
127 characterDirection = "left";
128 } else if (y > 0) {
129 character.classList.toggle("face-down", true);
130 characterDirection = "down";
131 } else if (y < 0) {
132 character.classList.toggle("face-up", true);
133 characterDirection = "up";
134 }
135}
136function updateStatus() {
137 if (Object.keys(gamepads).length > 1) return;
138 let gamepad = navigator.getGamepads()[0];
139 if (gamepad) {
140 const {
141 buttons,
142 axes
143 } = gamepad;
144
145 const [
146 A_key,
147 B_key,
148 X_key,
149 Y_key,
150 L1_key,
151 R1_key,
152 L2_key,
153 R2_key,
154 bk_key,
155 strt_key,
156 LStick_key,
157 RStick_key,
158 dPad_up,
159 dPad_down,
160 dPad_left,
161 dPad_right
162 ] = buttons.map(button => button.value);
163
164 const [
165 leftAnalogX,
166 leftAnalogY,
167 rightAnalogX,
168 rightAnalogY
169 ] = axes;
170
171 activateButton(upBtn, dPad_up);
172 activateButton(downBtn, dPad_down);
173 activateButton(leftBtn, dPad_left);
174 activateButton(rightBtn, dPad_right);
175 activateButton(backBtn, bk_key);
176 activateButton(startBtn, strt_key);
177 activateButton(btnX, X_key,true);
178 activateButton(btnY, Y_key,true);
179 activateButton(btnA, A_key,true);
180 activateButton(btnB, B_key,true);
181 activateButton(btnL1, L1_key);
182 activateButton(btnR1, R1_key);
183 activateButton(btnL2, L2_key);
184 activateButton(btnR2, R2_key);
185 activateButton(leftAnalog, LStick_key);
186 activateButton(rightAnalog, RStick_key);
187
188 pressuredButton(btnL2, btnL2Path, L2_key);
189 pressuredButton(btnR2, btnR2Path, R2_key);
190
191 analogButton(leftAnalog, leftAnalogPath, leftAnalogX, leftAnalogY, true);
192 analogButton(rightAnalog, rightAnalogPath, rightAnalogX, rightAnalogY, false);
193 }
194 requestAnimationFrame(updateStatus);
195}
196
197window.addEventListener("gamepadconnected", (e) => addGamepad(e.gamepad));
198window.addEventListener("gamepaddisconnected", (e) => removeGamepad(e.gamepad));
199tooltip.innerHTML = "Connect a gamepad and press any button!";
200
201
202// ================== Keyboard Movement ==================
203function keyboardMovement() {
204 let posX = hitbox.offsetLeft;
205 let posY = hitbox.offsetTop;
206 const speed = 2;
207 const keysPressed = {};
208
209 function moveCharacter() {
210 let moved = false;
211
212 if (keysPressed["w"]) {
213 posY -= speed;
214 moved = true;
215 character.classList.toggle("face-up", true);
216 w.classList.toggle("lit", true);
217 } else {
218 character.classList.toggle("face-up", false);
219 w.classList.toggle("lit", false);
220 }
221
222 if (keysPressed["a"]) {
223 posX -= speed;
224 moved = true;
225 character.classList.toggle("face-left", true);
226 a.classList.toggle("lit", true);
227 } else {
228 character.classList.toggle("face-left", false);
229 a.classList.toggle("lit", false);
230 }
231
232 if (keysPressed["s"]) {
233 posY += speed;
234 moved = true;
235 character.classList.toggle("face-down", true);
236 s.classList.toggle("lit", true);
237 } else {
238 character.classList.toggle("face-down", false);
239 s.classList.toggle("lit", false);
240 }
241
242 if (keysPressed["d"]) {
243 posX += speed;
244 moved = true;
245 character.classList.toggle("face-right", true);
246 d.classList.toggle("lit", true);
247 } else {
248 character.classList.toggle("face-right", false);
249 d.classList.toggle("lit", false);
250 }
251
252 // Keep the character within the window boundaries
253 posX = Math.max(0, Math.min(window.innerWidth - 50, posX));
254 posY = Math.max(0, Math.min(window.innerHeight - 50, posY));
255
256 if (moved) {
257 hitbox.style.left = posX + "px";
258 hitbox.style.top = posY + "px";
259 }
260 }
261
262 function gameLoop() {
263 moveCharacter();
264 requestAnimationFrame(gameLoop);
265 }
266
267 document.addEventListener("keydown", function (event) {
268 keysPressed[event.key.toLowerCase()] = true;
269 });
270
271 document.addEventListener("keyup", function (event) {
272 keysPressed[event.key.toLowerCase()] = false;
273 });
274
275 gameLoop();
276};
277
278// ================== Cheat Code Section ==================
279function triggerCheat() {
280 document.querySelector("h1").textContent = "Gamer Mode";
281 controller.style.display = "none";
282 keyboard.style.display = "block";
283 character.style.visibility = "visible";
284 hitbox.style.position = "absolute";
285 hitbox.style.left = "48%";
286 hitbox.style.bottom = "20%";
287 dialog.style.display = "none";
288 keyboardMovement();
289}
290
291document.addEventListener("keydown", event => {
292 if (cheatkeys.includes(event.key.toLowerCase())) {
293 cheatcodes.push(event.key.toLowerCase());
294 clearTimeout(cheatTimeout);
295 cheatTimeout = setTimeout(() => {
296 cheatcodes = [];
297 }, 3000);
298
299 if (cheatcodes.length == 5) {
300 let cheatcode = cheatcodes.join("");
301 if (cheatcode === "hlk18") {
302 isCheatActivated = true;
303 triggerCheat()
304 tooltip.textContent = `Cheat code activated!`;
305 }
306 cheatcodes = [];
307 }
308 } else {
309 cheatcodes = [];
310 }
311});
312
313