Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion changelog.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
added new project: crasher, update styles for tik tak toe
New mayor project: TypeWord. Check it out in the projects tab
22 changes: 22 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { rooms } from "./routes/ttt.js";
import { readFileSync, writeFileSync } from "fs";
import { addClick, getClicks, getMessage, setMessage } from "./functions.js";
import * as discojs from "@thenamelessdev/discojs";
import { typeWordRooms } from "./routes/typeword.js";

//vars and conf
dotenv.config();
Expand Down Expand Up @@ -136,6 +137,27 @@ io.on("connection", async (socket) => {
io.emit("delete", ({ room: room }));
delete rooms[room];
});

socket.on("typewordstart", async (data) => {
try{
const response = await fetch("https://random-word-api.herokuapp.com/word");
const json = await response.json();
if(response.ok){
io.emit("typewordstart", {"room": data.room, "word": json[0]});
}
else{
io.emit("typewordstart", {"room": data.room, "word": "error"});
}
}
catch{
io.emit("typewordstart", {"room": data.room, "word": "error"});
}
});

socket.on("typewordfinish", (data) => {
typeWordRooms[data.room].winner = data.player;
io.emit("typewordwinner", {"room": data.room, "player": data.player});
});
});

server.listen({port, host: "0.0.0.0"});
3 changes: 3 additions & 0 deletions src/routes/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const router = express.Router();
import tttRouter from "./ttt.js";
router.use("/ttt", tttRouter);

import typeWordRouter from "./typeword.js";
router.use("/typeword", typeWordRouter);

router.get("/", (req: Request, res: Response) => {
res.render("projects");
});
Expand Down
67 changes: 67 additions & 0 deletions src/routes/typeword.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import express, { Request, Response } from "express";
import { verify } from "../functions.js";
import { io } from "../index.js";
const router = express.Router();

interface typeWordRoom {
name: string,
host: string,
player?: string,
winner?: string,
}

export let typeWordRooms: Record<string, typeWordRoom> = {};

router.get("/", (req: Request, res: Response) => {
res.render("projects/typeword/index")
});

router.post("/create", async (req: Request, res: Response) => {
const { username, room } = req.body;

if(username && room){
if(await verify(req)){
if(typeWordRooms[room]){
res.render("error", { error: "Room name already exists" });
}
else{
typeWordRooms[room] = {
name: room,
host: username
}
res.render("projects/typeword/game", { room: room, user: username, host: username, player: "none" });
}
}
else{
res.render("error", { error: "Cloudflare turnstile failed" });
}
}
else{
res.status(400).render("error", { error: "missing username or room name" });
}
});

router.post("/join", async (req: Request, res: Response) => {
const { username, room } = req.body;

if(username && room){
if(await verify(req)){
if(typeWordRooms[room]){
typeWordRooms[room].player = username;
io.emit("typewordjoin", {"room": room, "username": username});
res.render("projects/typeword/game", { room: room, user: username, host: typeWordRooms[room].host, player: username });
}
else{
res.status(404).render("error", { error: "Room doesn't exists" })
}
}
else{
res.render("error", { error: "Cloudflare turnstile failed" });
}
}
else{
res.status(400).render("error", { error: "missing username or room name" });
}
});

export default router;
2 changes: 2 additions & 0 deletions views/projects.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
<br>
<a href="/projects/crasher">Crasher</a>
<br>
<a href="/projects/typeword">TypeWord</a>
<br>
<br>
<p>&copy; 2025 thenamelessdev. Licensed under the <a href="https://opensource.org/license/mit">MIT license.</a></p>
<p>By using the website you aggree to our <a href="/privacy">privacy policy</a></p>
Expand Down
104 changes: 104 additions & 0 deletions views/projects/typeword/game.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TypeWord - <%= room %></title>
<link rel="shortcut icon" href="/logo" type="image/x-icon">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
crossorigin="anonymous">
</head>
<body class="text-center">
<h1><%= room %></h1>
<p>Host: <%= host %></p>
<p>You: <%= user %></p>
<p id="playerText">Player: <%= player %></p>
<hr>

<p><b>Word:</b></p>
<p id="wordText"></p>
<div class="d-flex justify-content-center mt-4">
<input type="text" class="form-control w-25" id="wordInp">
</div>
<br>
<p id="timeText">Time: 0s</p>


<br>

<div>
<button id="startGameBtn" class="btn btn-success" disabled>Start</button>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
const you = "<%= user %>";
const room = "<%= room %>";
const host = "<%= host %>";
const socket = io();
const playerText = document.getElementById("playerText");
const wordText = document.getElementById("wordText");
const startGameBtn = document.getElementById("startGameBtn");
const timeText = document.getElementById("timeText");
const wordInp = document.getElementById("wordInp");
let word;
let time = 0;

if(you == host){
startGameBtn.disabled = false;
}

function startGame(){
socket.emit("typewordstart", {"room": room});
}

function checkWord(){
if(wordInp.value == word){
const finishTime = time;
time = undefined;
socket.emit("typewordfinish", {"room": room, "time": finishTime, "player": you});
}
}

setInterval(() => {
if(word){
time = time + 0.01;
timeText.textContent = `Time: ${time.toFixed(2)}`;
checkWord();
}
}, 10);


socket.on("typewordjoin", (data) => {
if(data.room == room){
playerText.textContent = `Player: ${data.username}`;
}
});

socket.on("typewordwinner", (data) => {
if(data.room = room){
word = undefined;
time = 0;
timeText.textContent = `Winner: ${data.player}`;
}
});

socket.on("typewordstart", (data) => {
if(data.room == room){
wordText.textContent = "3";
setTimeout(() => {
wordText.textContent = "2";
setTimeout(() => {
wordText.textContent = "1";
setTimeout(() => {
word = data.word;
wordText.textContent = word;
}, 1000);
}, 1000);
}, 1000);
}
});

startGameBtn.addEventListener("click", () => startGame());
</script>
</body>
</html>
69 changes: 69 additions & 0 deletions views/projects/typeword/index.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TypeWord</title>
<link rel="shortcut icon" href="/logo" type="image/x-icon">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
crossorigin="anonymous">
<script
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
async
defer
></script>
</head>
<body class="text-center">
<h1>TypeWord</h1>
<p><b>A fun game to play with friends</b></p>
<p>How to play: after both players join the room the game will give you a world. You have to type the word as fast as you can and whoewer types it faster wins.</p>
<hr>
<div>
<h5>Create Room</h5>
<form action="/projects/typeword/create" method="post">
<div class="d-flex justify-content-center mt-4">
<div class="form-floating w-25">
<input type="text" name="room" id="room" class="form-control" placeholder="Room name" required>
<label for="room">Room Name</label>
</div>
</div>

<div class="d-flex justify-content-center mt-4">
<div class="form-floating w-25">
<input type="text" name="username" id="username" class="form-control" placeholder="Username" required>
<label for="room">Username</label>
</div>
</div>
<br>
<div class="cf-turnstile" data-sitekey="0x4AAAAAACAX5hJ5rxxG4bFv"></div>
<br>
<input type="submit" value="Create Room" class="btn btn-success">
</form>
</div>

<br>

<div>
<h5>Join Room</h5>
<form action="/projects/typeword/join" method="post">
<div class="d-flex justify-content-center mt-4">
<div class="form-floating w-25">
<input type="text" name="room" id="room" class="form-control" placeholder="Room name" required>
<label for="room">Room Name</label>
</div>
</div>

<div class="d-flex justify-content-center mt-4">
<div class="form-floating w-25">
<input type="text" name="username" id="username" class="form-control" placeholder="Username" required>
<label for="room">Username</label>
</div>
</div>
<br>
<div class="cf-turnstile" data-sitekey="0x4AAAAAACAX5hJ5rxxG4bFv"></div>
<br>
<input type="submit" value="Join Room" class="btn btn-success">
</form>
</div>
</body>
</html>