Upload files to "/"
This commit is contained in:
174
index.html
Normal file
174
index.html
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="pl">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>Symulacja minigierki z rzucaniem zaklęć z Reksio i Czarodzieje</title>
|
||||||
|
<style>
|
||||||
|
body { margin: 0; display:flex; height:100vh; align-items:center; justify-content:center; background:#f0f0f0; }
|
||||||
|
canvas { background: #ffffff; border:1px solid #ccc; }
|
||||||
|
#coords { position:fixed; left:10px; top:10px; background:rgba(0,0,0,0.6); color:#fff; padding:6px 8px; border-radius:4px; font-family:monospace; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="coords">x: -, y: - | down: false</div>
|
||||||
|
<canvas id="canvas" width="800" height="600"></canvas>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('canvas');
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const coordsEl = document.getElementById('coords');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
const spellDirections = {
|
||||||
|
'Sen': [270,45,315,90],
|
||||||
|
'Zamiana w żabę': [90,0,270,180,45,135],
|
||||||
|
'Plaga much': [90,225,0,225],
|
||||||
|
'Kula budyniu': [180,90,0,90,180],
|
||||||
|
'Koła i wiry': [270,45,270,135,0],
|
||||||
|
'Ciemność': [0,225,315,180],
|
||||||
|
'Obrona przed Snem': [0,90,180,270,0],
|
||||||
|
'Obrona przed Zamianą w żabę': [280,0,90,0,270,135], // nope, that 280 is not a typo, that was in the original code
|
||||||
|
'Obrona przed Plagą much': [225,135,45,315,180],
|
||||||
|
'Obrona przed Kulą budyniu': [270,180,90,180,270],
|
||||||
|
'Obrona przed Kołami i wirami': [45,180,315,180],
|
||||||
|
'Obrona przed Ciemnością': [180,45,135,0]
|
||||||
|
};
|
||||||
|
|
||||||
|
const ANGLE_TOLERANCE = 35.5; // used in shape comparison, not in point probing
|
||||||
|
const POINT_DISTANCE_THRESHOLD = 30;
|
||||||
|
let lastPoint = null;
|
||||||
|
let drawnAngles = [];
|
||||||
|
|
||||||
|
clearCanvas();
|
||||||
|
|
||||||
|
let isDown = false;
|
||||||
|
|
||||||
|
function updateDisplay(x, y) {
|
||||||
|
coordsEl.textContent = `x: ${x}, y: ${y} | down: ${isDown}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCanvas() {
|
||||||
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle = '#ffffff';
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPos(evt) {
|
||||||
|
const r = canvas.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
x: Math.round(evt.clientX - r.left),
|
||||||
|
y: Math.round(evt.clientY - r.top)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareAngle(a, b) {
|
||||||
|
return (a - b + 540.0) % 360.0 - 180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function angleNear(angle, target, margin) {
|
||||||
|
return Math.abs(compareAngle(angle, target)) <= margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function probePoint(p) {
|
||||||
|
// probing by >= 30 pixels
|
||||||
|
if (lastPoint) {
|
||||||
|
const dx = p.x - lastPoint.x;
|
||||||
|
const dy = p.y - lastPoint.y;
|
||||||
|
const distance = Math.hypot(dx, dy);
|
||||||
|
if (distance >= POINT_DISTANCE_THRESHOLD) {
|
||||||
|
const angle = Math.atan2(dy, dx) * 180 / Math.PI;
|
||||||
|
|
||||||
|
// normalize angle to [0, 360) (ATAN2 in Piklib was normalized)
|
||||||
|
const normalizedAngle = (angle + 360) % 360;
|
||||||
|
|
||||||
|
// calculate the difference between the last angle and the current angle
|
||||||
|
if (drawnAngles.length > 0) {
|
||||||
|
const lastAngle = drawnAngles[drawnAngles.length - 1];
|
||||||
|
const angleDifference = Math.abs(compareAngle(normalizedAngle, lastAngle));
|
||||||
|
if (angleDifference > 45) {
|
||||||
|
drawnAngles.push(normalizedAngle);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// technically game scripts force the first angle to have difference of 46 degrees, so it pushes the first angle regardless of the tolerance
|
||||||
|
drawnAngles.push(normalizedAngle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw a line from lastPoint to current point
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(lastPoint.x, lastPoint.y);
|
||||||
|
ctx.lineTo(p.x, p.y);
|
||||||
|
ctx.strokeStyle = '#ff0000';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
// override last point
|
||||||
|
lastPoint = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.addEventListener('mousedown', (e) => {
|
||||||
|
// left button is a 0
|
||||||
|
if (e.button === 0) {
|
||||||
|
isDown = true;
|
||||||
|
const p = getPos(e);
|
||||||
|
lastPoint = p;
|
||||||
|
drawnAngles = [];
|
||||||
|
clearCanvas();
|
||||||
|
updateDisplay(p.x, p.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('mouseup', (e) => {
|
||||||
|
if (e.button === 0) {
|
||||||
|
isDown = false;
|
||||||
|
const p = getPos(e);
|
||||||
|
probePoint(p);
|
||||||
|
|
||||||
|
console.log('Drawn angles:', drawnAngles);
|
||||||
|
|
||||||
|
// break a spell and compare with the known spell directions
|
||||||
|
const spellName = Object.keys(spellDirections).find(name => {
|
||||||
|
const directions = spellDirections[name];
|
||||||
|
|
||||||
|
// when lengths of array are different, it cancels the comparison
|
||||||
|
if (directions.length !== drawnAngles.length) {
|
||||||
|
console.log(`Spell "${name}" rejected due to length mismatch: expected ${directions.length}, got ${drawnAngles.length}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare each angle with the corresponding drawn angle with angle tolerance
|
||||||
|
for (let i = 0; i < directions.length; i++) {
|
||||||
|
const expectedAngle = directions[i];
|
||||||
|
const drawnAngle = drawnAngles[i];
|
||||||
|
if (!angleNear(drawnAngle, expectedAngle, ANGLE_TOLERANCE)) {
|
||||||
|
console.log(`Spell "${name}" rejected due to angle mismatch at index ${i}: expected ${expectedAngle}, got ${drawnAngle}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
console.log(spellName);
|
||||||
|
if (spellName) {
|
||||||
|
console.log(`Spell cast: ${spellName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplay(p.x, p.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener('mousemove', (e) => {
|
||||||
|
const p = getPos(e);
|
||||||
|
updateDisplay(p.x, p.y);
|
||||||
|
if (isDown) {
|
||||||
|
probePoint(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// zapobiegaj zaznaczaniu tekstu/dragowaniu
|
||||||
|
canvas.addEventListener('dragstart', e => e.preventDefault());
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user