dopamine effects
This commit is contained in:
@@ -1417,19 +1417,139 @@ body, html {
|
||||
/* Event Ticker Message */
|
||||
.event-ticker {
|
||||
position: absolute;
|
||||
bottom: 210px;
|
||||
bottom: calc(var(--card-height) + 65px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
border: 1px solid rgba(245, 176, 65, 0.4);
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
border: 1px solid rgba(245, 176, 65, 0.5);
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
padding: 5px 16px;
|
||||
padding: 6px 18px;
|
||||
border-radius: 20px;
|
||||
pointer-events: none;
|
||||
z-index: 40;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(6px);
|
||||
}
|
||||
|
||||
/* --- DOPAMINE POPUP BANNER --- */
|
||||
.dopamine-banner {
|
||||
position: absolute;
|
||||
top: 38%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%) scale(0.6);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 500;
|
||||
pointer-events: none;
|
||||
animation: dopamine-pop-in 0.45s cubic-bezier(0.175, 0.885, 0.32, 1.35) forwards;
|
||||
}
|
||||
|
||||
.dopamine-content {
|
||||
position: relative;
|
||||
padding: 12px 32px;
|
||||
border-radius: 40px;
|
||||
background: rgba(10, 15, 25, 0.92);
|
||||
border: 3px solid #ffd700;
|
||||
box-shadow: 0 0 50px rgba(255, 215, 0, 0.6), inset 0 0 25px rgba(255, 215, 0, 0.3);
|
||||
text-align: center;
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.dopamine-title {
|
||||
font-family: 'Cinzel', serif;
|
||||
font-size: 2.2rem;
|
||||
font-weight: 900;
|
||||
letter-spacing: 2px;
|
||||
color: #fff;
|
||||
text-shadow: 0 0 20px #ffd700, 0 4px 10px rgba(0,0,0,0.8);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dopamine-sub {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 800;
|
||||
color: #ffd700;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 2px;
|
||||
text-shadow: 0 2px 6px rgba(0,0,0,0.9);
|
||||
}
|
||||
|
||||
/* Types */
|
||||
.dopamine-double .dopamine-content {
|
||||
border-color: #00e5ff;
|
||||
box-shadow: 0 0 45px rgba(0, 229, 255, 0.7), inset 0 0 20px rgba(0, 229, 255, 0.3);
|
||||
}
|
||||
.dopamine-double .dopamine-title {
|
||||
text-shadow: 0 0 25px #00e5ff, 0 0 40px #00e5ff;
|
||||
}
|
||||
|
||||
.dopamine-triple .dopamine-content {
|
||||
border-color: #ff4500;
|
||||
box-shadow: 0 0 55px rgba(255, 69, 0, 0.8), inset 0 0 25px rgba(255, 140, 0, 0.4);
|
||||
}
|
||||
.dopamine-triple .dopamine-title {
|
||||
text-shadow: 0 0 30px #ff4500, 0 0 50px #ff8c00;
|
||||
}
|
||||
|
||||
.dopamine-quad .dopamine-content, .dopamine-mega .dopamine-content {
|
||||
border-color: #ffd700;
|
||||
background: linear-gradient(135deg, rgba(30, 20, 5, 0.95), rgba(15, 10, 0, 0.95));
|
||||
box-shadow: 0 0 80px rgba(255, 215, 0, 0.9), inset 0 0 35px rgba(255, 215, 0, 0.5);
|
||||
transform: scale(1.15);
|
||||
}
|
||||
.dopamine-quad .dopamine-title {
|
||||
font-size: 2.7rem;
|
||||
text-shadow: 0 0 35px #ffd700, 0 0 60px #ff8c00, 0 0 90px #ffd700;
|
||||
}
|
||||
|
||||
.dopamine-freeze .dopamine-content {
|
||||
border-color: #00ffff;
|
||||
box-shadow: 0 0 60px rgba(0, 255, 255, 0.8), inset 0 0 25px rgba(0, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
.dopamine-revive .dopamine-content {
|
||||
border-color: #ff0055;
|
||||
box-shadow: 0 0 65px rgba(255, 0, 85, 0.9), inset 0 0 30px rgba(255, 215, 0, 0.5);
|
||||
}
|
||||
|
||||
.dopamine-jackpot .dopamine-content {
|
||||
border-color: #ffd700;
|
||||
box-shadow: 0 0 90px rgba(255, 215, 0, 1), inset 0 0 40px rgba(255, 215, 0, 0.6);
|
||||
}
|
||||
|
||||
.dopamine-fadeout {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -70%) scale(1.2);
|
||||
transition: all 0.35s ease;
|
||||
}
|
||||
|
||||
@keyframes dopamine-pop-in {
|
||||
0% { transform: translate(-50%, -50%) scale(0.3); opacity: 0; }
|
||||
60% { transform: translate(-50%, -50%) scale(1.15); opacity: 1; }
|
||||
100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
|
||||
}
|
||||
|
||||
/* HOLOGRAPHIC FOIL SHINE ON CARDS */
|
||||
.game-card.playable::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: var(--card-radius);
|
||||
background: linear-gradient(115deg, transparent 20%, rgba(255, 255, 255, 0.4) 40%, rgba(255, 215, 0, 0.5) 50%, rgba(0, 229, 255, 0.4) 60%, transparent 80%);
|
||||
background-size: 200% 200%;
|
||||
animation: holo-shine 2.8s infinite linear;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
@keyframes holo-shine {
|
||||
0% { background-position: -200% -200%; }
|
||||
100% { background-position: 200% 200%; }
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
|
||||
@@ -617,6 +617,271 @@ window.FaraonFx = (function () {
|
||||
}
|
||||
}
|
||||
|
||||
// --- DOPAMINE PROCEDURAL AUDIO ---
|
||||
function playSelectStep(step = 1) {
|
||||
if (isMuted) return;
|
||||
const ctx = getAudioContext();
|
||||
if (!ctx) return;
|
||||
|
||||
const now = ctx.currentTime;
|
||||
// Pentatonic rising scale (C5, E5, G5, C6, E6)
|
||||
const freqs = [523.25, 659.25, 783.99, 1046.50, 1318.51];
|
||||
const freq = freqs[Math.min(step - 1, freqs.length - 1)] || 523.25;
|
||||
|
||||
const osc = ctx.createOscillator();
|
||||
const harm = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
|
||||
osc.type = 'triangle';
|
||||
osc.frequency.setValueAtTime(freq, now);
|
||||
osc.frequency.exponentialRampToValueAtTime(freq * 1.02, now + 0.12);
|
||||
|
||||
harm.type = 'sine';
|
||||
harm.frequency.setValueAtTime(freq * 2, now);
|
||||
|
||||
gain.gain.setValueAtTime(0.28, now);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, now + 0.14);
|
||||
|
||||
osc.connect(gain);
|
||||
harm.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
|
||||
osc.start(now);
|
||||
harm.start(now);
|
||||
osc.stop(now + 0.15);
|
||||
harm.stop(now + 0.15);
|
||||
}
|
||||
|
||||
function playComboSlam(count = 2) {
|
||||
if (isMuted) return;
|
||||
const ctx = getAudioContext();
|
||||
if (!ctx) return;
|
||||
|
||||
const now = ctx.currentTime;
|
||||
// Heavy 808 Sub-bass drop
|
||||
const sub = ctx.createOscillator();
|
||||
const subGain = ctx.createGain();
|
||||
sub.type = 'sine';
|
||||
sub.frequency.setValueAtTime(140 + count * 20, now);
|
||||
sub.frequency.exponentialRampToValueAtTime(32, now + 0.45);
|
||||
|
||||
subGain.gain.setValueAtTime(0.7, now);
|
||||
subGain.gain.exponentialRampToValueAtTime(0.001, now + 0.45);
|
||||
|
||||
sub.connect(subGain);
|
||||
subGain.connect(ctx.destination);
|
||||
|
||||
sub.start(now);
|
||||
sub.stop(now + 0.46);
|
||||
|
||||
// Metallic punch noise
|
||||
const bufferSize = ctx.sampleRate * 0.12;
|
||||
const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
|
||||
const data = buffer.getChannelData(0);
|
||||
for (let i = 0; i < bufferSize; i++) {
|
||||
data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (ctx.sampleRate * 0.03));
|
||||
}
|
||||
const noise = ctx.createBufferSource();
|
||||
noise.buffer = buffer;
|
||||
const filter = ctx.createBiquadFilter();
|
||||
filter.type = 'bandpass';
|
||||
filter.frequency.setValueAtTime(1800, now);
|
||||
filter.Q.setValueAtTime(4, now);
|
||||
|
||||
const noiseGain = ctx.createGain();
|
||||
noiseGain.gain.setValueAtTime(0.5, now);
|
||||
noiseGain.gain.exponentialRampToValueAtTime(0.001, now + 0.12);
|
||||
|
||||
noise.connect(filter);
|
||||
filter.connect(noiseGain);
|
||||
noiseGain.connect(ctx.destination);
|
||||
noise.start(now);
|
||||
|
||||
// Escalating screen shake
|
||||
triggerScreenShake(count >= 4 ? 16 : (count === 3 ? 10 : 6));
|
||||
}
|
||||
|
||||
function playJackpotCoins() {
|
||||
if (isMuted) return;
|
||||
const ctx = getAudioContext();
|
||||
if (!ctx) return;
|
||||
|
||||
const now = ctx.currentTime;
|
||||
const notes = [987.77, 1174.66, 1318.51, 1567.98, 1760.00, 2093.00, 2349.32, 2793.83];
|
||||
notes.forEach((freq, idx) => {
|
||||
const time = now + idx * 0.06;
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.type = 'sine';
|
||||
osc.frequency.setValueAtTime(freq, time);
|
||||
|
||||
gain.gain.setValueAtTime(0.22, time);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.22);
|
||||
|
||||
osc.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
|
||||
osc.start(time);
|
||||
osc.stop(time + 0.23);
|
||||
});
|
||||
}
|
||||
|
||||
function playReviveSound() {
|
||||
if (isMuted) return;
|
||||
const ctx = getAudioContext();
|
||||
if (!ctx) return;
|
||||
|
||||
const now = ctx.currentTime;
|
||||
const chord = [440, 554.37, 659.25, 880, 1108.73];
|
||||
chord.forEach((freq, i) => {
|
||||
const osc = ctx.createOscillator();
|
||||
const gain = ctx.createGain();
|
||||
osc.type = 'sawtooth';
|
||||
osc.frequency.setValueAtTime(freq, now + i * 0.04);
|
||||
osc.frequency.linearRampToValueAtTime(freq * 1.5, now + 0.5);
|
||||
|
||||
const filter = ctx.createBiquadFilter();
|
||||
filter.type = 'lowpass';
|
||||
filter.frequency.setValueAtTime(800, now);
|
||||
filter.frequency.exponentialRampToValueAtTime(3500, now + 0.4);
|
||||
|
||||
gain.gain.setValueAtTime(0.25, now + i * 0.04);
|
||||
gain.gain.exponentialRampToValueAtTime(0.001, now + 0.6);
|
||||
|
||||
osc.connect(filter);
|
||||
filter.connect(gain);
|
||||
gain.connect(ctx.destination);
|
||||
|
||||
osc.start(now + i * 0.04);
|
||||
osc.stop(now + 0.62);
|
||||
});
|
||||
|
||||
triggerScreenShake(8);
|
||||
}
|
||||
|
||||
// --- DOPAMINE BANNER SYSTEM ---
|
||||
function triggerDopamineBanner(title, subtitle = '', type = 'combo') {
|
||||
const container = document.getElementById('game-table-container') || document.body;
|
||||
|
||||
// Remove existing banner if any
|
||||
const oldBanner = document.querySelector('.dopamine-banner');
|
||||
if (oldBanner) oldBanner.remove();
|
||||
|
||||
const banner = document.createElement('div');
|
||||
banner.className = `dopamine-banner dopamine-${type}`;
|
||||
banner.innerHTML = `
|
||||
<div class="dopamine-halo"></div>
|
||||
<div class="dopamine-content">
|
||||
<div class="dopamine-title">${title}</div>
|
||||
${subtitle ? `<div class="dopamine-sub">${subtitle}</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.appendChild(banner);
|
||||
|
||||
// Sound & Particles based on type
|
||||
if (type === 'quad' || type === 'mega') {
|
||||
playComboSlam(4);
|
||||
triggerGoldStarExplosion();
|
||||
triggerConfetti();
|
||||
} else if (type === 'triple') {
|
||||
playComboSlam(3);
|
||||
triggerFireParticles(window.innerWidth / 2, window.innerHeight / 2, 45);
|
||||
} else if (type === 'double') {
|
||||
playComboSlam(2);
|
||||
triggerLightningSparks();
|
||||
} else if (type === 'freeze') {
|
||||
playAceFreeze();
|
||||
triggerIceParticles(window.innerWidth / 2, window.innerHeight / 2, 50);
|
||||
} else if (type === 'revive') {
|
||||
playReviveSound();
|
||||
triggerLightningSparks(window.innerWidth / 2, window.innerHeight / 2, 60);
|
||||
} else if (type === 'jackpot') {
|
||||
playJackpotCoins();
|
||||
triggerCoinJackpot();
|
||||
triggerConfetti();
|
||||
}
|
||||
|
||||
// Auto remove banner after animation
|
||||
setTimeout(() => {
|
||||
banner.classList.add('dopamine-fadeout');
|
||||
setTimeout(() => banner.remove(), 400);
|
||||
}, 1800);
|
||||
}
|
||||
|
||||
// --- ADVANCED PARTICLES ---
|
||||
function triggerCoinJackpot(x, y, count = 70) {
|
||||
if (!particleCanvas) return;
|
||||
const startX = x || window.innerWidth / 2;
|
||||
const startY = y || window.innerHeight / 2;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const angle = -Math.PI / 2 + (Math.random() - 0.5) * 2.2;
|
||||
const speed = 6 + Math.random() * 12;
|
||||
particles.push({
|
||||
x: startX,
|
||||
y: startY,
|
||||
vx: Math.cos(angle) * speed,
|
||||
vy: Math.sin(angle) * speed,
|
||||
gravity: 0.28,
|
||||
size: 10 + Math.random() * 6,
|
||||
aspect: 0.5 + Math.random() * 0.5,
|
||||
color: Math.random() > 0.3 ? '#ffd700' : '#f5b041',
|
||||
shape: 'rect',
|
||||
life: 1.2,
|
||||
decay: 0.012 + Math.random() * 0.008,
|
||||
rotation: Math.random() * Math.PI * 2,
|
||||
vRot: (Math.random() - 0.5) * 0.25
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function triggerLightningSparks(x, y, count = 40) {
|
||||
if (!particleCanvas) return;
|
||||
const colors = ['#00e5ff', '#ffd700', '#ffffff', '#e040fb'];
|
||||
const startX = x || window.innerWidth / 2;
|
||||
const startY = y || window.innerHeight / 2;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
const speed = 4 + Math.random() * 10;
|
||||
particles.push({
|
||||
x: startX,
|
||||
y: startY,
|
||||
vx: Math.cos(angle) * speed,
|
||||
vy: Math.sin(angle) * speed,
|
||||
gravity: 0,
|
||||
size: 3 + Math.random() * 4,
|
||||
color: colors[Math.floor(Math.random() * colors.length)],
|
||||
shape: 'spark',
|
||||
life: 0.8,
|
||||
decay: 0.035,
|
||||
rotation: Math.random() * Math.PI
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function triggerGoldStarExplosion(x, y, count = 60) {
|
||||
if (!particleCanvas) return;
|
||||
const startX = x || window.innerWidth / 2;
|
||||
const startY = y || window.innerHeight / 2;
|
||||
for (let i = 0; i < count; i++) {
|
||||
const angle = Math.random() * Math.PI * 2;
|
||||
const speed = 3 + Math.random() * 11;
|
||||
particles.push({
|
||||
x: startX,
|
||||
y: startY,
|
||||
vx: Math.cos(angle) * speed,
|
||||
vy: Math.sin(angle) * speed,
|
||||
gravity: 0.06,
|
||||
size: 6 + Math.random() * 6,
|
||||
color: '#ffd700',
|
||||
shape: 'circle',
|
||||
life: 1.1,
|
||||
decay: 0.02,
|
||||
rotation: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleMute() {
|
||||
isMuted = !isMuted;
|
||||
return isMuted;
|
||||
@@ -631,14 +896,23 @@ window.FaraonFx = (function () {
|
||||
playBurnExplosion,
|
||||
playVictory,
|
||||
playHeartbeat,
|
||||
playSelectStep,
|
||||
playComboSlam,
|
||||
playJackpotCoins,
|
||||
playReviveSound,
|
||||
triggerDopamineBanner,
|
||||
triggerScreenShake,
|
||||
initParticles,
|
||||
triggerFireParticles,
|
||||
triggerIceParticles,
|
||||
triggerBurnExplosion,
|
||||
triggerConfetti,
|
||||
triggerCoinJackpot,
|
||||
triggerLightningSparks,
|
||||
triggerGoldStarExplosion,
|
||||
animateCardPlay,
|
||||
animateCardDraw,
|
||||
toggleMute
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user