missing match crazy shit
This commit is contained in:
@@ -31,6 +31,10 @@ python3 -m http.server 8080
|
|||||||
I posti con **jacuzzi** (Argo, Eolo, "Quanto te la rischi") sono i jackpot e
|
I posti con **jacuzzi** (Argo, Eolo, "Quanto te la rischi") sono i jackpot e
|
||||||
vengono rivelati per ultimi, con celebrazione extra.
|
vengono rivelati per ultimi, con celebrazione extra.
|
||||||
|
|
||||||
|
**Nessun match (~30%):** ogni tanto i 3 rulli si fermano su stanze diverse →
|
||||||
|
effetto pazzo (sirena + strobo + glitch + timbro "NO MATCH"), le puntate del giro
|
||||||
|
vengono annullate e la persona **ri-tira** (senza avanzare). Max 2 no-match di fila.
|
||||||
|
|
||||||
## Regole del matching
|
## Regole del matching
|
||||||
|
|
||||||
- Ogni stanza è **mono-genere** (M con M, F con F).
|
- Ogni stanza è **mono-genere** (M con M, F con F).
|
||||||
|
|||||||
102
app.js
102
app.js
@@ -55,6 +55,22 @@
|
|||||||
buzz() {
|
buzz() {
|
||||||
this.blip(140, 0.45, "sawtooth", 0.3, 70);
|
this.blip(140, 0.45, "sawtooth", 0.3, 70);
|
||||||
},
|
},
|
||||||
|
// sirena da allarme per il "nessun match"
|
||||||
|
siren() {
|
||||||
|
if (!this.on || !this.ctx) return;
|
||||||
|
const t = this.ctx.currentTime;
|
||||||
|
const o = this.ctx.createOscillator();
|
||||||
|
const g = this.ctx.createGain();
|
||||||
|
o.type = "sawtooth";
|
||||||
|
const freqs = [880, 440, 880, 440, 880, 440, 880];
|
||||||
|
freqs.forEach((f, i) => o.frequency.setValueAtTime(f, t + i * 0.16));
|
||||||
|
g.gain.setValueAtTime(0.16, t);
|
||||||
|
g.gain.setValueAtTime(0.16, t + 1.05);
|
||||||
|
g.gain.exponentialRampToValueAtTime(0.0001, t + 1.2);
|
||||||
|
o.connect(g).connect(this.master);
|
||||||
|
o.start(t);
|
||||||
|
o.stop(t + 1.25);
|
||||||
|
},
|
||||||
// nota di ottone per la fanfara
|
// nota di ottone per la fanfara
|
||||||
brass(freq, when, dur, vol = 0.25) {
|
brass(freq, when, dur, vol = 0.25) {
|
||||||
if (!this.on || !this.ctx) return;
|
if (!this.on || !this.ctx) return;
|
||||||
@@ -198,6 +214,38 @@
|
|||||||
f.classList.add("go");
|
f.classList.add("go");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EFFETTO PAZZO quando i rulli non combaciano: sirena + strobo + glitch + timbro
|
||||||
|
function crazyNoMatch() {
|
||||||
|
Audio.siren();
|
||||||
|
screenShake();
|
||||||
|
|
||||||
|
// strobo a schermo intero
|
||||||
|
let strobe = $(".strobe");
|
||||||
|
if (!strobe) {
|
||||||
|
strobe = document.createElement("div");
|
||||||
|
strobe.className = "strobe";
|
||||||
|
document.body.appendChild(strobe);
|
||||||
|
}
|
||||||
|
strobe.classList.remove("go");
|
||||||
|
void strobe.offsetWidth;
|
||||||
|
strobe.classList.add("go");
|
||||||
|
|
||||||
|
// glitch sui rulli
|
||||||
|
const win = $(".reel-window");
|
||||||
|
win.classList.add("glitch");
|
||||||
|
setTimeout(() => win.classList.remove("glitch"), 900);
|
||||||
|
|
||||||
|
// timbro "NESSUN MATCH"
|
||||||
|
const stamp = document.createElement("div");
|
||||||
|
stamp.className = "nomatch-stamp";
|
||||||
|
stamp.innerHTML = "<span>❌ NO MATCH ❌</span>";
|
||||||
|
document.body.appendChild(stamp);
|
||||||
|
setTimeout(() => stamp.remove(), 1300);
|
||||||
|
|
||||||
|
// coriandoli "sbagliati" (solo rossi) per rincarare la beffa
|
||||||
|
myConfetti({ particleCount: 120, spread: 180, startVelocity: 40, origin: { y: 0.4 }, colors: ["#ff3b5c", "#8b0022"] });
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- Sfondo three.js: pioggia di monete ---------- */
|
/* ---------- Sfondo three.js: pioggia di monete ---------- */
|
||||||
function initBackground() {
|
function initBackground() {
|
||||||
if (typeof THREE === "undefined") return;
|
if (typeof THREE === "undefined") return;
|
||||||
@@ -332,8 +380,15 @@
|
|||||||
const roomAtIndex = (el, i) =>
|
const roomAtIndex = (el, i) =>
|
||||||
el.children[i] ? roomById[el.children[i].dataset.room] : null;
|
el.children[i] ? roomById[el.children[i].dataset.room] : null;
|
||||||
|
|
||||||
// Probabilità di ragebait (finto stop) sul rullo finale.
|
// Probabilità di ragebait (finto stop) per colonna.
|
||||||
const TEASE_CHANCE = 0.3;
|
const TEASE_CHANCE = 0.3;
|
||||||
|
// Probabilità che il giro NON dia match (3 stanze diverse) -> respin.
|
||||||
|
const NOMATCH_CHANCE = 0.3;
|
||||||
|
|
||||||
|
// 3 stanze DIVERSE per un "nessun match" (mai una linea vincente)
|
||||||
|
function pickMismatch() {
|
||||||
|
return Matching.shuffle(ROOMS.map((r) => r.id), Math.random).slice(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
function bounceReel(el, finalY) {
|
function bounceReel(el, finalY) {
|
||||||
return el.animate(
|
return el.animate(
|
||||||
@@ -398,10 +453,11 @@
|
|||||||
// allineandosi sulla stanza assegnata. OGNI colonna può fare il ragebait
|
// allineandosi sulla stanza assegnata. OGNI colonna può fare il ragebait
|
||||||
// (in modo indipendente); le colonne più a destra tengono la suspense più a
|
// (in modo indipendente); le colonne più a destra tengono la suspense più a
|
||||||
// lungo, così il dramma "cascata" verso l'ultimo rullo.
|
// lungo, così il dramma "cascata" verso l'ultimo rullo.
|
||||||
async function spinReel(targetId) {
|
async function spinReel(reelTargets, opts) {
|
||||||
const targetIndex = reelEls.map((el) => buildStripIn(el, targetId))[0]; // uguale per tutti
|
const tease = !opts || opts.tease !== false;
|
||||||
|
// ogni rullo può atterrare su una stanza diversa (per il "nessun match")
|
||||||
|
const targetIndex = reelEls.map((el, i) => buildStripIn(el, reelTargets[i]))[0];
|
||||||
const finalY = -(targetIndex - 1) * ITEM_H;
|
const finalY = -(targetIndex - 1) * ITEM_H;
|
||||||
const targetRoom = roomById[targetId];
|
|
||||||
$("#reel-result").innerHTML = " ";
|
$("#reel-result").innerHTML = " ";
|
||||||
|
|
||||||
// ZOOM + shake; lo shake si ferma a metà spin (quando inizia a rallentare)
|
// ZOOM + shake; lo shake si ferma a metà spin (quando inizia a rallentare)
|
||||||
@@ -428,7 +484,7 @@
|
|||||||
await Promise.all(
|
await Promise.all(
|
||||||
reelEls.map((el, i) => {
|
reelEls.map((el, i) => {
|
||||||
// ogni colonna ha una sua chance di bluff; suspense crescente verso destra
|
// ogni colonna ha una sua chance di bluff; suspense crescente verso destra
|
||||||
const teaseMs = Math.random() < TEASE_CHANCE ? 380 + i * 260 : 0;
|
const teaseMs = tease && Math.random() < TEASE_CHANCE ? 380 + i * 260 : 0;
|
||||||
return reelLand(el, targetIndex, finalY, durs[i], teaseMs);
|
return reelLand(el, targetIndex, finalY, durs[i], teaseMs);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -436,7 +492,6 @@
|
|||||||
ticking = false;
|
ticking = false;
|
||||||
stopRiser();
|
stopRiser();
|
||||||
zoomMachineSteady();
|
zoomMachineSteady();
|
||||||
$("#reel-result").innerHTML = `${targetRoom.jacuzzi ? "🛁 " : ""}<b>${targetRoom.nome}</b>${targetRoom.jacuzzi ? " 🛁" : ""}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Zoom macchina ---------- */
|
/* ---------- Zoom macchina ---------- */
|
||||||
@@ -476,6 +531,7 @@
|
|||||||
let auto = false;
|
let auto = false;
|
||||||
let busy = false;
|
let busy = false;
|
||||||
let leverArmed = false;
|
let leverArmed = false;
|
||||||
|
let noMatchStreak = 0; // no-match consecutivi (tetto per non incastrare)
|
||||||
|
|
||||||
// scommettitori (TU + banco simulato)
|
// scommettitori (TU + banco simulato)
|
||||||
let players = [];
|
let players = [];
|
||||||
@@ -501,6 +557,7 @@
|
|||||||
ROOMS.forEach((r) => (occupants[r.id] = []));
|
ROOMS.forEach((r) => (occupants[r.id] = []));
|
||||||
cursor = 0;
|
cursor = 0;
|
||||||
currentBet = null;
|
currentBet = null;
|
||||||
|
noMatchStreak = 0;
|
||||||
if (!keepChips) {
|
if (!keepChips) {
|
||||||
players = [
|
players = [
|
||||||
{ name: "TU", chips: 100, you: true },
|
{ name: "TU", chips: 100, you: true },
|
||||||
@@ -686,7 +743,38 @@
|
|||||||
setTimeout(() => $("#lever").classList.remove("pull"), 320);
|
setTimeout(() => $("#lever").classList.remove("pull"), 320);
|
||||||
if (window.__coinBoost) window.__coinBoost();
|
if (window.__coinBoost) window.__coinBoost();
|
||||||
|
|
||||||
await spinReel(roomId);
|
// 30% dei giri: NESSUN MATCH (3 stanze diverse) -> effetto pazzo + respin.
|
||||||
|
// Tetto di 2 no-match di fila per non bloccare nessuno.
|
||||||
|
const noMatch = noMatchStreak < 2 && Math.random() < NOMATCH_CHANCE;
|
||||||
|
|
||||||
|
if (noMatch) {
|
||||||
|
noMatchStreak++;
|
||||||
|
await spinReel(pickMismatch(), { tease: false });
|
||||||
|
$("#reel-result").innerHTML = `<b class="rr-nomatch">NESSUN MATCH</b>`;
|
||||||
|
crazyNoMatch();
|
||||||
|
currentBet = null; // puntate annullate (push): nessun gettone cambia
|
||||||
|
log(`${person}: nessun match! Si ri-tira 💥`);
|
||||||
|
mc("💥 NESSUN MATCH! Ri-tira la leva! ⬇️");
|
||||||
|
setTimeout(zoomMachineOut, 1000);
|
||||||
|
busy = false;
|
||||||
|
// stesso giocatore: NON avanza il cursore
|
||||||
|
if (auto) {
|
||||||
|
setTimeout(nextTurn, 1600);
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!busy && cursor < revealQueue.length && !auto) {
|
||||||
|
armLever(true);
|
||||||
|
mc("💥 NESSUN MATCH! Ri-tira la leva! ⬇️");
|
||||||
|
}
|
||||||
|
}, 1100);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- MATCH: i 3 rulli si allineano sulla stanza assegnata ---
|
||||||
|
noMatchStreak = 0;
|
||||||
|
await spinReel([roomId, roomId, roomId], { tease: true });
|
||||||
|
$("#reel-result").innerHTML = `${room.jacuzzi ? "🛁 " : ""}<b>${room.nome}</b>${room.jacuzzi ? " 🛁" : ""}`;
|
||||||
|
|
||||||
// atterraggio
|
// atterraggio
|
||||||
occupants[roomId].push(person);
|
occupants[roomId].push(person);
|
||||||
|
|||||||
62
styles.css
62
styles.css
@@ -668,6 +668,68 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== NESSUN MATCH: effetto pazzo ===== */
|
||||||
|
.strobe {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 58;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.strobe.go {
|
||||||
|
animation: strobe 1s linear;
|
||||||
|
}
|
||||||
|
@keyframes strobe {
|
||||||
|
0%, 100% { opacity: 0; }
|
||||||
|
8% { opacity: 1; background: rgba(255, 0, 60, 0.45); }
|
||||||
|
16% { opacity: 1; background: rgba(0, 229, 255, 0.4); }
|
||||||
|
24% { opacity: 1; background: rgba(255, 210, 63, 0.4); }
|
||||||
|
40% { opacity: 1; background: rgba(255, 0, 60, 0.4); }
|
||||||
|
56% { opacity: 1; background: rgba(0, 229, 255, 0.38); }
|
||||||
|
72% { opacity: 1; background: rgba(255, 46, 136, 0.4); }
|
||||||
|
88% { opacity: 1; background: rgba(255, 0, 60, 0.35); }
|
||||||
|
}
|
||||||
|
.reel-window.glitch {
|
||||||
|
animation: glitch 0.08s steps(2) infinite;
|
||||||
|
}
|
||||||
|
@keyframes glitch {
|
||||||
|
0% { transform: translate(0, 0) skewX(0); filter: hue-rotate(0deg); }
|
||||||
|
25% { transform: translate(-7px, 3px) skewX(4deg); filter: hue-rotate(90deg); }
|
||||||
|
50% { transform: translate(6px, -4px) skewX(-4deg); filter: hue-rotate(200deg); }
|
||||||
|
75% { transform: translate(-5px, 5px) skewX(3deg); filter: hue-rotate(300deg); }
|
||||||
|
100% { transform: translate(0, 0) skewX(0); filter: hue-rotate(0deg); }
|
||||||
|
}
|
||||||
|
.nomatch-stamp {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 59;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.nomatch-stamp span {
|
||||||
|
font-family: "Anton", sans-serif;
|
||||||
|
font-size: clamp(44px, 10vw, 140px);
|
||||||
|
letter-spacing: 3px;
|
||||||
|
color: var(--red);
|
||||||
|
text-shadow: 0 0 30px var(--red), 0 0 70px #ff004c;
|
||||||
|
transform: rotate(-8deg) scale(0.3);
|
||||||
|
opacity: 0;
|
||||||
|
animation: stampIn 1.3s ease;
|
||||||
|
}
|
||||||
|
@keyframes stampIn {
|
||||||
|
0% { opacity: 0; transform: rotate(-8deg) scale(0.3); }
|
||||||
|
15% { opacity: 1; transform: rotate(-8deg) scale(1.15); }
|
||||||
|
28% { transform: rotate(-8deg) scale(1); }
|
||||||
|
82% { opacity: 1; transform: rotate(-8deg) scale(1); }
|
||||||
|
100% { opacity: 0; transform: rotate(-8deg) scale(1.05); }
|
||||||
|
}
|
||||||
|
.rr-nomatch {
|
||||||
|
color: var(--red);
|
||||||
|
text-shadow: 0 0 16px var(--red);
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 980px) {
|
@media (max-width: 980px) {
|
||||||
.stage {
|
.stage {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
|
|||||||
Reference in New Issue
Block a user