mirror of https://github.com/dirtbags/moth.git
Compare commits
No commits in common. "b135069851cc87e26256f49519dbaef9ff401da7" and "551afe04a5b8b2ba373dba934755591009facb23" have entirely different histories.
b135069851
...
551afe04a5
|
@ -5,150 +5,118 @@ function randint(max) {
|
||||||
const MILLISECOND = 1
|
const MILLISECOND = 1
|
||||||
const SECOND = MILLISECOND * 1000
|
const SECOND = MILLISECOND * 1000
|
||||||
|
|
||||||
class Point {
|
class Line {
|
||||||
constructor(x, y) {
|
|
||||||
this.x = x
|
|
||||||
this.y = y
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add n to this.
|
* @param {CanvasRenderingContext2D} ctx canvas context
|
||||||
*
|
* @param {Number} hue Hue, in % of one circle [0,tau)
|
||||||
* @param {Point} n What to add to this
|
* @param {Number} a First point of line
|
||||||
* @returns {Point}
|
* @param {Number} b Second point of line
|
||||||
*/
|
*/
|
||||||
Add(n) {
|
constructor(ctx, hue, a, b) {
|
||||||
return new Point(this.x + n.x, this.y + n.y)
|
this.ctx = ctx
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtract n from this.
|
|
||||||
*
|
|
||||||
* @param {Point} n
|
|
||||||
* @returns {Point}
|
|
||||||
*/
|
|
||||||
Subtract(n) {
|
|
||||||
return new Point(this.x - n.x, this.y - n.y)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add velocity, then bounce point off box defined by points at min and max
|
|
||||||
* @param {Point} velocity
|
|
||||||
* @param {Point} min
|
|
||||||
* @param {Point} max
|
|
||||||
* @returns {Point}
|
|
||||||
*/
|
|
||||||
Bounce(velocity, min, max) {
|
|
||||||
let p = this.Add(velocity)
|
|
||||||
if (p.x < min.x) {
|
|
||||||
p.x += (min.x - p.x) * 2
|
|
||||||
velocity.x *= -1
|
|
||||||
}
|
|
||||||
if (p.x > max.x) {
|
|
||||||
p.x += (max.x - p.x) * 2
|
|
||||||
velocity.x *= -1
|
|
||||||
}
|
|
||||||
if (p.y < min.y) {
|
|
||||||
p.y += (min.y - p.y) * 2
|
|
||||||
velocity.y *= -1
|
|
||||||
}
|
|
||||||
if (p.y > max.y) {
|
|
||||||
p.y += (max.y - p.y) * 2
|
|
||||||
velocity.y *= -1
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {Point} p
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
Equal(p) {
|
|
||||||
return (this.x == p.x) && (this.y == p.y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class QixLine {
|
|
||||||
/**
|
|
||||||
* @param {Number} hue
|
|
||||||
* @param {Point} a
|
|
||||||
* @param {Point} b
|
|
||||||
*/
|
|
||||||
constructor(hue, a, b) {
|
|
||||||
this.hue = hue
|
this.hue = hue
|
||||||
this.a = a
|
this.a = a
|
||||||
this.b = b
|
this.b = b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bounce(point, v) {
|
||||||
|
let ret = [
|
||||||
|
point[0] + v[0],
|
||||||
|
point[1] + v[1],
|
||||||
|
]
|
||||||
|
if ((ret[0] > this.ctx.canvas.width) || (ret[0] < 0)) {
|
||||||
|
v[0] *= -1
|
||||||
|
ret[0] += v[0] * 2
|
||||||
|
}
|
||||||
|
if ((ret[1] > this.ctx.canvas.height) || (ret[1] < 0)) {
|
||||||
|
v[1] *= -1
|
||||||
|
ret[1] += v[1] * 2
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
Add(hue, a, b) {
|
||||||
|
return new Line(
|
||||||
|
this.ctx,
|
||||||
|
(this.hue + hue) % 1.0,
|
||||||
|
this.bounce(this.a, a),
|
||||||
|
this.bounce(this.b, b),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw() {
|
||||||
|
this.ctx.save()
|
||||||
|
this.ctx.strokeStyle = `hwb(${this.hue}turn 0% 50%)`
|
||||||
|
this.ctx.beginPath()
|
||||||
|
this.ctx.moveTo(this.a[0], this.a[1])
|
||||||
|
this.ctx.lineTo(this.b[0], this.b[1])
|
||||||
|
this.ctx.stroke()
|
||||||
|
this.ctx.restore()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
class LengoBackground {
|
||||||
* Draw a line dancing around the screen,
|
constructor() {
|
||||||
* like the video game "qix"
|
this.canvas = document.createElement("canvas")
|
||||||
*/
|
document.body.insertBefore(this.canvas, document.body.firstChild)
|
||||||
class QixBackground {
|
this.canvas.style.position = "fixed"
|
||||||
constructor(ctx) {
|
this.canvas.style.zIndex = -1000
|
||||||
this.ctx = ctx
|
this.canvas.style.opacity = 0.3
|
||||||
this.min = new Point(0, 0)
|
this.canvas.style.top = 0
|
||||||
this.max = new Point(this.ctx.canvas.width, this.ctx.canvas.height)
|
this.canvas.style.left = 0
|
||||||
this.box = this.max.Subtract(this.min)
|
this.canvas.style.width = "99vw"
|
||||||
|
this.canvas.style.height = "99vh"
|
||||||
|
this.canvas.width = 2000
|
||||||
|
this.canvas.height = 2000
|
||||||
|
this.ctx = this.canvas.getContext("2d")
|
||||||
|
this.ctx.lineWidth = 1
|
||||||
|
|
||||||
this.lines = [
|
this.lines = []
|
||||||
new QixLine(
|
for (let i = 0; i < 18; i++) {
|
||||||
0,
|
this.lines.push(
|
||||||
new Point(randint(this.box.x), randint(this.box.y)),
|
new Line(this.ctx, 0, [0, 0], [0, 0])
|
||||||
new Point(randint(this.box.x), randint(this.box.y)),
|
|
||||||
)
|
)
|
||||||
]
|
|
||||||
while (this.lines.length < 18) {
|
|
||||||
this.lines.push(this.lines[0])
|
|
||||||
}
|
}
|
||||||
this.velocity = new QixLine(
|
this.velocities = {
|
||||||
0.001,
|
hue: 0.001,
|
||||||
new Point(1 + randint(this.box.x / 200), 1 + randint(this.box.y / 200)),
|
a: [20 + randint(10), 20 + randint(10)],
|
||||||
new Point(1 + randint(this.box.x / 200), 1 + randint(this.box.y / 200)),
|
b: [5 + randint(10), 5 + randint(10)],
|
||||||
)
|
}
|
||||||
|
this.nextFrame = performance.now()-1
|
||||||
|
this.frameInterval = 100 * MILLISECOND
|
||||||
|
|
||||||
setInterval(() => this.animate(), SECOND/6)
|
//addEventListener("resize", e => this.resizeEvent())
|
||||||
|
//this.resizeEvent()
|
||||||
|
//this.animate(this.nextFrame)
|
||||||
|
setInterval(() => this.animate(this.nextFrame+1), SECOND/6)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Animate one frame
|
* Animate one frame
|
||||||
|
*
|
||||||
|
* @param {DOMHighResTimeStamp} timestamp
|
||||||
*/
|
*/
|
||||||
animate() {
|
animate(timestamp) {
|
||||||
|
if (timestamp >= this.nextFrame) {
|
||||||
this.lines.shift()
|
this.lines.shift()
|
||||||
let lastLine = this.lines[this.lines.length - 1]
|
let lastLine = this.lines.pop()
|
||||||
let nextLine = new QixLine(
|
let nextLine = lastLine.Add(this.velocities.hue, this.velocities.a, this.velocities.b)
|
||||||
(lastLine.hue + this.velocity.hue) % 1.0,
|
this.lines.push(lastLine)
|
||||||
lastLine.a.Bounce(this.velocity.a, this.min, this.max),
|
|
||||||
lastLine.b.Bounce(this.velocity.b, this.min, this.max),
|
|
||||||
)
|
|
||||||
|
|
||||||
this.lines.push(nextLine)
|
this.lines.push(nextLine)
|
||||||
|
|
||||||
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height)
|
||||||
for (let line of this.lines) {
|
for (let line of this.lines) {
|
||||||
this.ctx.save()
|
line.Draw()
|
||||||
this.ctx.strokeStyle = `hwb(${line.hue}turn 0% 50%)`
|
|
||||||
this.ctx.beginPath()
|
|
||||||
this.ctx.moveTo(line.a.x, line.a.y)
|
|
||||||
this.ctx.lineTo(line.b.x, line.b.y)
|
|
||||||
this.ctx.stroke()
|
|
||||||
this.ctx.restore()
|
|
||||||
}
|
}
|
||||||
|
this.nextFrame += this.frameInterval
|
||||||
|
}
|
||||||
|
//requestAnimationFrame((ts) => this.animate(ts))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
let canvas = document.createElement("canvas")
|
new LengoBackground()
|
||||||
canvas.width = 640
|
|
||||||
canvas.height = 640
|
|
||||||
canvas.classList.add("wallpaper")
|
|
||||||
document.body.insertBefore(canvas, document.body.firstChild)
|
|
||||||
|
|
||||||
let ctx = canvas.getContext("2d")
|
|
||||||
|
|
||||||
new QixBackground(ctx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.readyState === "loading") {
|
if (document.readyState === "loading") {
|
||||||
|
|
|
@ -22,17 +22,6 @@ h1 {
|
||||||
a:any-link {
|
a:any-link {
|
||||||
color: #b9cbd8;
|
color: #b9cbd8;
|
||||||
}
|
}
|
||||||
canvas.wallpaper {
|
|
||||||
position: fixed;
|
|
||||||
display: block;
|
|
||||||
z-index: -1000;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
opacity: 0.3;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
}
|
|
||||||
.notification {
|
.notification {
|
||||||
background: #ac8f3944;
|
background: #ac8f3944;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,15 @@
|
||||||
<title>MOTH</title>
|
<title>MOTH</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<link rel="icon" href="luna-moth.svg">
|
|
||||||
<link rel="stylesheet" href="basic.css">
|
<link rel="stylesheet" href="basic.css">
|
||||||
<script src="moth.mjs" type="module"></script>
|
<script src="moth.js"></script>
|
||||||
<script src="background.mjs" type="module"></script>
|
<link rel="manifest" href="manifest.json">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1 id="title">MOTH</h1>
|
<h1 id="title">MOTH</h1>
|
||||||
<main>
|
<section>
|
||||||
<div id="messages notification">
|
<div id="messages">
|
||||||
|
<div id="notices"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="login">
|
<form id="login">
|
||||||
|
@ -22,7 +22,8 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<div id="puzzles"></div>
|
<div id="puzzles"></div>
|
||||||
</main>
|
|
||||||
|
</section>
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="scoreboard.html">Scoreboard</a></li>
|
<li><a href="scoreboard.html">Scoreboard</a></li>
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "Monarch of the Hill",
|
||||||
|
"short_name": "MOTH",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#282a33",
|
||||||
|
"theme_color": "#ECB",
|
||||||
|
"description": "The MOTH CTF engine"
|
||||||
|
}
|
|
@ -2,10 +2,9 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Puzzle</title>
|
<title>Puzzle</title>
|
||||||
|
<link rel="stylesheet" href="basic.css">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="icon" href="luna-moth.svg">
|
|
||||||
<link rel="stylesheet" href="basic.css">
|
|
||||||
<script src="puzzle.mjs" type="module"></script>
|
<script src="puzzle.mjs" type="module"></script>
|
||||||
<script src="background.mjs" type="module"></script>
|
<script src="background.mjs" type="module"></script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -21,9 +20,11 @@
|
||||||
<ul id="files"></ul>
|
<ul id="files"></ul>
|
||||||
<p>Puzzle by <span id="authors">[loading]</span></p>
|
<p>Puzzle by <span id="authors">[loading]</span></p>
|
||||||
</section>
|
</section>
|
||||||
<form class="answer">
|
<form>
|
||||||
|
<input type="hidden" name="cat">
|
||||||
|
<input type="hidden" name="points">
|
||||||
Team ID: <input type="text" name="id"> <br>
|
Team ID: <input type="text" name="id"> <br>
|
||||||
Answer: <input type="text" name="answer"> <span id="answer_ok"></span><br>
|
Answer: <input type="text" name="answer" id="answer"> <span id="answer_ok"></span><br>
|
||||||
<input type="submit" value="Submit">
|
<input type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
import * as moth from "./moth.mjs"
|
import * as moth from "./moth.mjs"
|
||||||
|
|
||||||
/** Stores the current puzzle, globally */
|
|
||||||
let puzzle = null
|
|
||||||
|
|
||||||
function submit(event) {
|
|
||||||
event.preventDefault()
|
|
||||||
console.log(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
function puzzleElement(clear=true) {
|
function puzzleElement(clear=true) {
|
||||||
let e = document.querySelector("#puzzle")
|
let e = document.querySelector("#puzzle")
|
||||||
if (clear) {
|
if (clear) {
|
||||||
|
@ -24,7 +16,7 @@ function error(message) {
|
||||||
|
|
||||||
async function loadPuzzle(category, points) {
|
async function loadPuzzle(category, points) {
|
||||||
let server = new moth.Server()
|
let server = new moth.Server()
|
||||||
puzzle = server.GetPuzzle(category, points)
|
let puzzle = server.GetPuzzle(category, points)
|
||||||
await puzzle.Populate()
|
await puzzle.Populate()
|
||||||
|
|
||||||
let title = `${category} ${points}`
|
let title = `${category} ${points}`
|
||||||
|
@ -57,9 +49,6 @@ function hashchange() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
for (let e of document.querySelectorAll("form.answer")) {
|
|
||||||
e.addEventListener("submit", submit)
|
|
||||||
}
|
|
||||||
window.addEventListener("hashchange", hashchange)
|
window.addEventListener("hashchange", hashchange)
|
||||||
hashchange()
|
hashchange()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue