XTaylorSpenceX

Dream Weaver Web

Sep 16th, 2025
26
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 30.68 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Dream Weaver Web</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.  
  14.         body {
  15.             font-family: 'Georgia', serif;
  16.             background: radial-gradient(ellipse at center, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
  17.             overflow: hidden;
  18.             height: 100vh;
  19.             position: relative;
  20.         }
  21.  
  22.         .dream-canvas {
  23.             width: 100%;
  24.             height: 100vh;
  25.             position: relative;
  26.             cursor: crosshair;
  27.         }
  28.  
  29.         .thought-node {
  30.             position: absolute;
  31.             width: 140px;
  32.             height: 90px;
  33.             border-radius: 25px;
  34.             backdrop-filter: blur(15px);
  35.             display: flex;
  36.             align-items: center;
  37.             justify-content: center;
  38.             cursor: grab;
  39.             transition: all 0.4s ease;
  40.             color: white;
  41.             text-align: center;
  42.             font-size: 12px;
  43.             font-weight: 500;
  44.             padding: 12px;
  45.             box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  46.             border: 2px solid;
  47.             animation: gentle-float 6s ease-in-out infinite;
  48.             user-select: none;
  49.         }
  50.  
  51.         .thought-node.positive {
  52.             background: linear-gradient(135deg, rgba(100,255,150,0.15) 0%, rgba(50,200,255,0.1) 100%);
  53.             border-color: rgba(100,255,150,0.4);
  54.             box-shadow: 0 8px 32px rgba(100,255,150,0.2);
  55.         }
  56.  
  57.         .thought-node.negative {
  58.             background: linear-gradient(135deg, rgba(255,100,100,0.15) 0%, rgba(200,50,50,0.1) 100%);
  59.             border-color: rgba(255,100,100,0.4);
  60.             box-shadow: 0 8px 32px rgba(255,100,100,0.2);
  61.         }
  62.  
  63.         .thought-node.neutral {
  64.             background: linear-gradient(135deg, rgba(200,200,255,0.15) 0%, rgba(150,150,200,0.1) 100%);
  65.             border-color: rgba(200,200,255,0.4);
  66.             box-shadow: 0 8px 32px rgba(200,200,255,0.2);
  67.         }
  68.  
  69.         .thought-node:hover {
  70.             transform: scale(1.1);
  71.             filter: brightness(1.2);
  72.         }
  73.  
  74.         .thought-node.dragging {
  75.             cursor: grabbing;
  76.             z-index: 1000;
  77.             transform: scale(1.2);
  78.             filter: brightness(1.3);
  79.         }
  80.  
  81.         .thought-node.connected {
  82.             filter: brightness(1.1) saturate(1.2);
  83.             animation: connected-pulse 4s ease-in-out infinite;
  84.         }
  85.  
  86.         .thought-node.nightmare {
  87.             background: linear-gradient(135deg, rgba(255,0,0,0.3) 0%, rgba(150,0,0,0.2) 100%);
  88.             border-color: rgba(255,0,0,0.7);
  89.             animation: nightmare-shake 0.5s ease-in-out infinite;
  90.         }
  91.  
  92.         @keyframes gentle-float {
  93.             0%, 100% { transform: translateY(0px) rotate(0deg); }
  94.             33% { transform: translateY(-8px) rotate(0.5deg); }
  95.             66% { transform: translateY(-4px) rotate(-0.5deg); }
  96.         }
  97.  
  98.         @keyframes connected-pulse {
  99.             0%, 100% { filter: brightness(1.1) saturate(1.2); }
  100.             50% { filter: brightness(1.3) saturate(1.4); }
  101.         }
  102.  
  103.         @keyframes nightmare-shake {
  104.             0%, 100% { transform: translateX(0); }
  105.             25% { transform: translateX(-2px); }
  106.             75% { transform: translateX(2px); }
  107.         }
  108.  
  109.         .connection-svg {
  110.             position: absolute;
  111.             top: 0;
  112.             left: 0;
  113.             width: 100%;
  114.             height: 100%;
  115.             pointer-events: none;
  116.             z-index: -1;
  117.         }
  118.  
  119.         .connection-line {
  120.             stroke-width: 3;
  121.             fill: none;
  122.             filter: drop-shadow(0 0 8px currentColor);
  123.             animation: energy-flow 2s ease-in-out infinite;
  124.         }
  125.  
  126.         .positive-connection {
  127.             stroke: rgba(100,255,150,0.8);
  128.         }
  129.  
  130.         .negative-connection {
  131.             stroke: rgba(255,100,100,0.8);
  132.         }
  133.  
  134.         .neutral-connection {
  135.             stroke: rgba(200,200,255,0.6);
  136.         }
  137.  
  138.         .nightmare-connection {
  139.             stroke: rgba(255,0,0,0.9);
  140.             stroke-width: 4;
  141.             stroke-dasharray: 8,4;
  142.             animation: nightmare-flow 1s linear infinite, energy-flow 2s ease-in-out infinite;
  143.         }
  144.  
  145.         @keyframes energy-flow {
  146.             0%, 100% { opacity: 0.6; }
  147.             50% { opacity: 1; }
  148.         }
  149.  
  150.         @keyframes nightmare-flow {
  151.             0% { stroke-dashoffset: 0; }
  152.             100% { stroke-dashoffset: 12; }
  153.         }
  154.  
  155.         .temp-line {
  156.             stroke: rgba(255,255,255,0.8);
  157.             stroke-width: 2;
  158.             fill: none;
  159.             stroke-dasharray: 5,5;
  160.         }
  161.  
  162.         .ui-panel {
  163.             position: fixed;
  164.             top: 20px;
  165.             left: 20px;
  166.             background: rgba(0,0,0,0.8);
  167.             padding: 25px;
  168.             border-radius: 20px;
  169.             color: white;
  170.             backdrop-filter: blur(15px);
  171.             border: 2px solid rgba(255,255,255,0.2);
  172.             min-width: 280px;
  173.         }
  174.  
  175.         .score-section {
  176.             margin-bottom: 15px;
  177.         }
  178.  
  179.         .score-item {
  180.             display: flex;
  181.             justify-content: space-between;
  182.             align-items: center;
  183.             margin: 8px 0;
  184.             font-size: 16px;
  185.         }
  186.  
  187.         .score-value {
  188.             font-weight: bold;
  189.             color: #4fc3f7;
  190.         }
  191.  
  192.         .combo-indicator {
  193.             background: linear-gradient(135deg, #ff6b6b, #feca57);
  194.             color: white;
  195.             padding: 5px 12px;
  196.             border-radius: 15px;
  197.             font-size: 14px;
  198.             margin-top: 10px;
  199.             text-align: center;
  200.             display: none;
  201.         }
  202.  
  203.         .legend {
  204.             margin-top: 20px;
  205.             padding-top: 15px;
  206.             border-top: 1px solid rgba(255,255,255,0.3);
  207.         }
  208.  
  209.         .legend-item {
  210.             display: flex;
  211.             align-items: center;
  212.             margin: 5px 0;
  213.             font-size: 12px;
  214.         }
  215.  
  216.         .legend-color {
  217.             width: 15px;
  218.             height: 15px;
  219.             border-radius: 3px;
  220.             margin-right: 8px;
  221.             border: 1px solid rgba(255,255,255,0.3);
  222.         }
  223.  
  224.         .positive-color { background: rgba(100,255,150,0.6); }
  225.         .negative-color { background: rgba(255,100,100,0.6); }
  226.         .neutral-color { background: rgba(200,200,255,0.6); }
  227.  
  228.         .progress-bar {
  229.             width: 200px;
  230.             height: 8px;
  231.             background: rgba(255,255,255,0.2);
  232.             border-radius: 4px;
  233.             overflow: hidden;
  234.             margin: 8px 0;
  235.         }
  236.  
  237.         .progress-fill {
  238.             height: 100%;
  239.             background: linear-gradient(90deg, #4fc3f7, #29b6f6);
  240.             transition: width 0.5s ease;
  241.             border-radius: 4px;
  242.         }
  243.  
  244.         .completion-modal {
  245.             position: fixed;
  246.             top: 50%;
  247.             left: 50%;
  248.             transform: translate(-50%, -50%);
  249.             background: rgba(0,0,0,0.95);
  250.             padding: 40px;
  251.             border-radius: 25px;
  252.             color: white;
  253.             text-align: center;
  254.             backdrop-filter: blur(25px);
  255.             border: 3px solid rgba(255,255,255,0.3);
  256.             max-width: 600px;
  257.             display: none;
  258.             z-index: 2000;
  259.         }
  260.  
  261.         .completion-modal h2 {
  262.             color: #4fc3f7;
  263.             margin-bottom: 20px;
  264.             font-size: 28px;
  265.         }
  266.  
  267.         .final-score {
  268.             font-size: 24px;
  269.             color: #feca57;
  270.             margin: 15px 0;
  271.         }
  272.  
  273.         .new-game-btn {
  274.             background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  275.             border: none;
  276.             padding: 15px 35px;
  277.             border-radius: 30px;
  278.             color: white;
  279.             cursor: pointer;
  280.             font-size: 18px;
  281.             transition: transform 0.3s ease;
  282.             margin-top: 20px;
  283.         }
  284.  
  285.         .new-game-btn:hover {
  286.             transform: scale(1.05);
  287.         }
  288.  
  289.         .floating-particles {
  290.             position: fixed;
  291.             top: 0;
  292.             left: 0;
  293.             width: 100%;
  294.             height: 100%;
  295.             pointer-events: none;
  296.             z-index: -2;
  297.         }
  298.  
  299.         .particle {
  300.             position: absolute;
  301.             width: 3px;
  302.             height: 3px;
  303.             background: rgba(255,255,255,0.4);
  304.             border-radius: 50%;
  305.             animation: float-particle 20s linear infinite;
  306.         }
  307.  
  308.         @keyframes float-particle {
  309.             0% {
  310.                 transform: translateY(100vh) translateX(0);
  311.                 opacity: 0;
  312.             }
  313.             10% {
  314.                 opacity: 1;
  315.             }
  316.             90% {
  317.                 opacity: 1;
  318.             }
  319.             100% {
  320.                 transform: translateY(-50px) translateX(50px);
  321.                 opacity: 0;
  322.             }
  323.         }
  324.  
  325.         .spawn-effect {
  326.             animation: spawn-in 1s ease-out;
  327.         }
  328.  
  329.         @keyframes spawn-in {
  330.             0% {
  331.                 transform: scale(0) rotate(180deg);
  332.                 opacity: 0;
  333.             }
  334.             100% {
  335.                 transform: scale(1) rotate(0deg);
  336.                 opacity: 1;
  337.             }
  338.         }
  339.  
  340.         .reward-popup {
  341.             position: absolute;
  342.             background: rgba(255,215,0,0.9);
  343.             color: #333;
  344.             padding: 8px 16px;
  345.             border-radius: 20px;
  346.             font-weight: bold;
  347.             pointer-events: none;
  348.             z-index: 1500;
  349.             animation: reward-float 2s ease-out forwards;
  350.         }
  351.  
  352.         @keyframes reward-float {
  353.             0% {
  354.                 transform: translateY(0) scale(0);
  355.                 opacity: 0;
  356.             }
  357.             20% {
  358.                 transform: translateY(-10px) scale(1.2);
  359.                 opacity: 1;
  360.             }
  361.             100% {
  362.                 transform: translateY(-60px) scale(1);
  363.                 opacity: 0;
  364.             }
  365.         }
  366.     </style>
  367. </head>
  368. <body>
  369.     <div class="floating-particles" id="particles"></div>
  370.    
  371.     <div class="dream-canvas" id="canvas">
  372.         <svg class="connection-svg" id="svg">
  373.             <defs>
  374.                 <filter id="glow">
  375.                     <feGaussianBlur stdDeviation="4" result="coloredBlur"/>
  376.                     <feMerge>
  377.                         <feMergeNode in="coloredBlur"/>
  378.                         <feMergeNode in="SourceGraphic"/>
  379.                     </feMerge>
  380.                 </filter>
  381.             </defs>
  382.         </svg>
  383.     </div>
  384.  
  385.     <div class="ui-panel">
  386.         <div class="score-section">
  387.             <div class="score-item">
  388.                 <span>Dream Score:</span>
  389.                 <span class="score-value" id="score">0</span>
  390.             </div>
  391.             <div class="score-item">
  392.                 <span>Harmony Bonus:</span>
  393.                 <span class="score-value" id="harmony">0</span>
  394.             </div>
  395.             <div class="score-item">
  396.                 <span>Connections:</span>
  397.                 <span class="score-value" id="connections">0</span>
  398.             </div>
  399.             <div class="combo-indicator" id="combo">Harmony Streak!</div>
  400.         </div>
  401.  
  402.         <div>Dream Progress:</div>
  403.         <div class="progress-bar">
  404.             <div class="progress-fill" id="progress" style="width: 0%"></div>
  405.         </div>
  406.  
  407.         <div class="legend">
  408.             <div class="legend-item">
  409.                 <div class="legend-color positive-color"></div>
  410.                 <span>Positive Dreams (+50 pts)</span>
  411.             </div>
  412.             <div class="legend-item">
  413.                 <div class="legend-color negative-color"></div>
  414.                 <span>Nightmares (-25 pts)</span>
  415.             </div>
  416.             <div class="legend-item">
  417.                 <div class="legend-color neutral-color"></div>
  418.                 <span>Neutral (+20 pts)</span>
  419.             </div>
  420.         </div>
  421.  
  422.         <div style="margin-top: 15px; font-size: 11px; opacity: 0.9;">
  423.             🎯 Connect <strong>Positive to Positive</strong> for huge bonuses!<br>
  424.             ⚡ Avoid connecting opposite emotions<br>
  425.             🌟 Build harmony streaks for multipliers
  426.         </div>
  427.     </div>
  428.  
  429.     <div class="completion-modal" id="modal">
  430.         <h2 id="modalTitle">Dream Complete!</h2>
  431.         <div class="final-score">Final Score: <span id="finalScore">0</span></div>
  432.         <p id="modalText"></p>
  433.         <button class="new-game-btn" onclick="newGame()">Weave Another Dream</button>
  434.     </div>
  435.  
  436.     <script>
  437.         class DreamWeaver {
  438.             constructor() {
  439.                 this.canvas = document.getElementById('canvas');
  440.                 this.svg = document.getElementById('svg');
  441.                 this.nodes = [];
  442.                 this.connections = [];
  443.                 this.isDragging = false;
  444.                 this.dragNode = null;
  445.                 this.tempLine = null;
  446.                 this.score = 0;
  447.                 this.harmonyBonus = 0;
  448.                 this.harmonyStreak = 0;
  449.                 this.gameComplete = false;
  450.                 this.targetConnections = 15;
  451.  
  452.                 // Enhanced dream content with clear emotional categories
  453.                 this.dreamContent = {
  454.                     positive: [
  455.                         "Soaring through starlight", "Childhood laughter echoing", "Warm golden meadows",
  456.                         "Dancing with butterflies", "Gentle ocean waves", "Rainbow bridge pathway",
  457.                         "Singing crystal fountains", "Floating flower gardens", "Sunlit forest clearing",
  458.                         "Angels whispering hope", "Peaceful mountain vista", "Luminous healing light"
  459.                     ],
  460.                     negative: [
  461.                         "Falling into darkness", "Endless maze of mirrors", "Screaming silent winds",
  462.                         "Shadowy figures lurking", "Bleeding crimson sky", "Frozen in terror",
  463.                         "Drowning in black water", "Thorns piercing flesh", "Empty hollow voices",
  464.                         "Crumbling stone walls", "Suffocating dense fog", "Eyes watching always"
  465.                     ],
  466.                     neutral: [
  467.                         "Clock ticking steadily", "Empty white corridors", "Floating geometric shapes",
  468.                         "Mechanical gears turning", "Gray misty landscapes", "Silent library halls",
  469.                         "Drifting paper planes", "Reflecting still water", "Ancient stone circles",
  470.                         "Distant city lights", "Wandering endless roads", "Spinning compass needles"
  471.                     ]
  472.                 };
  473.  
  474.                 this.dreamEndings = {
  475.                     transcendent: "Your harmonious dream web ascends into pure light, each connection a note in the symphony of consciousness. You have achieved perfect dream mastery.",
  476.                     balanced: "Your dream tapestry weaves together light and shadow in perfect balance, creating a masterpiece of subconscious artistry.",
  477.                     chaotic: "Your dream fragments scatter like broken glass, each piece reflecting a different reality. Beautiful chaos reigns in your sleeping mind.",
  478.                     nightmare: "The shadows have consumed your dream web, leaving only whispers of what might have been. Even nightmares teach us about ourselves.",
  479.                     incomplete: "Your dream fades before completion, leaving mysterious fragments that hint at deeper truths waiting to be discovered."
  480.                 };
  481.  
  482.                 this.init();
  483.             }
  484.  
  485.             init() {
  486.                 this.createParticles();
  487.                 this.createInitialNodes();
  488.                 this.setupEventListeners();
  489.                 this.gameLoop();
  490.             }
  491.  
  492.             createParticles() {
  493.                 const particleContainer = document.getElementById('particles');
  494.                 for (let i = 0; i < 25; i++) {
  495.                    const particle = document.createElement('div');
  496.                    particle.className = 'particle';
  497.                    particle.style.left = Math.random() * 100 + '%';
  498.                    particle.style.animationDelay = Math.random() * 20 + 's';
  499.                    particle.style.animationDuration = (15 + Math.random() * 10) + 's';
  500.                    particleContainer.appendChild(particle);
  501.                }
  502.            }
  503.  
  504.            createInitialNodes() {
  505.                // Start with just 5 well-spaced nodes
  506.                const positions = [
  507.                    { x: 200, y: 150 },
  508.                    { x: 600, y: 200 },
  509.                    { x: 400, y: 400 },
  510.                    { x: 800, y: 350 },
  511.                    { x: 300, y: 600 }
  512.                ];
  513.  
  514.                positions.forEach((pos, i) => {
  515.                     setTimeout(() => {
  516.                         this.createNode(pos.x, pos.y);
  517.                     }, i * 300);
  518.                 });
  519.             }
  520.  
  521.             createNode(x, y) {
  522.                 // Random emotional type with balanced distribution
  523.                 const types = ['positive', 'negative', 'neutral'];
  524.                 const weights = [0.4, 0.3, 0.3]; // Slightly favor positive
  525.                 const type = this.weightedRandom(types, weights);
  526.                
  527.                 const node = document.createElement('div');
  528.                 node.className = `thought-node ${type} spawn-effect`;
  529.                 node.textContent = this.getRandomText(type);
  530.                
  531.                 // Better positioning - ensure nodes stay within visible area
  532.                 const finalX = x || (100 + Math.random() * (window.innerWidth - 300));
  533.                 const finalY = y || (100 + Math.random() * (window.innerHeight - 200));
  534.                
  535.                 node.style.left = finalX + 'px';
  536.                 node.style.top = finalY + 'px';
  537.                 node.style.animationDelay = Math.random() * 6 + 's';
  538.  
  539.                 node.dataset.id = this.nodes.length;
  540.                 node.dataset.type = type;
  541.                 node.dataset.connections = '0';
  542.                 node.dataset.x = finalX + 70; // center point
  543.                 node.dataset.y = finalY + 45; // center point
  544.  
  545.                 this.canvas.appendChild(node);
  546.                 this.nodes.push(node);
  547.                 this.setupNodeEvents(node);
  548.             }
  549.  
  550.             weightedRandom(items, weights) {
  551.                 const random = Math.random();
  552.                 let sum = 0;
  553.                 for (let i = 0; i < weights.length; i++) {
  554.                    sum += weights[i];
  555.                    if (random <= sum) return items[i];
  556.                }
  557.                return items[items.length - 1];
  558.            }
  559.  
  560.            getRandomText(type) {
  561.                const texts = this.dreamContent[type];
  562.                return texts[Math.floor(Math.random() * texts.length)];
  563.            }
  564.  
  565.            setupNodeEvents(node) {
  566.                node.addEventListener('mousedown', (e) => this.startDrag(e, node));
  567.                 node.addEventListener('mouseup', (e) => this.endDrag(e, node));
  568.             }
  569.  
  570.             setupEventListeners() {
  571.                 this.canvas.addEventListener('mousemove', (e) => this.onMouseMove(e));
  572.                 this.canvas.addEventListener('mouseup', (e) => this.onMouseUp(e));
  573.                 this.canvas.addEventListener('contextmenu', (e) => e.preventDefault());
  574.             }
  575.  
  576.             startDrag(e, node) {
  577.                 e.preventDefault();
  578.                 this.isDragging = true;
  579.                 this.dragNode = node;
  580.                 node.classList.add('dragging');
  581.  
  582.                 this.tempLine = document.createElementNS('http://www.w3.org/2000/svg', 'line');
  583.                 this.tempLine.setAttribute('class', 'temp-line');
  584.                 this.tempLine.setAttribute('x1', node.dataset.x);
  585.                 this.tempLine.setAttribute('y1', node.dataset.y);
  586.                 this.tempLine.setAttribute('x2', e.clientX);
  587.                 this.tempLine.setAttribute('y2', e.clientY);
  588.                 this.svg.appendChild(this.tempLine);
  589.             }
  590.  
  591.             onMouseMove(e) {
  592.                 if (this.isDragging && this.tempLine) {
  593.                    this.tempLine.setAttribute('x2', e.clientX);
  594.                     this.tempLine.setAttribute('y2', e.clientY);
  595.                 }
  596.             }
  597.  
  598.             endDrag(e, targetNode) {
  599.                 if (this.isDragging && this.dragNode && targetNode !== this.dragNode) {
  600.                    this.createConnection(this.dragNode, targetNode);
  601.                 }
  602.                 this.onMouseUp(e);
  603.             }
  604.  
  605.             onMouseUp(e) {
  606.                 if (this.isDragging) {
  607.                     this.isDragging = false;
  608.                     if (this.dragNode) {
  609.                         this.dragNode.classList.remove('dragging');
  610.                         this.dragNode = null;
  611.                     }
  612.                     if (this.tempLine) {
  613.                         this.svg.removeChild(this.tempLine);
  614.                         this.tempLine = null;
  615.                     }
  616.                 }
  617.             }
  618.  
  619.             createConnection(node1, node2) {
  620.                 const id1 = parseInt(node1.dataset.id);
  621.                 const id2 = parseInt(node2.dataset.id);
  622.  
  623.                 // Check if connection already exists
  624.                 const existingConnection = this.connections.find(conn =>
  625.                     (conn.node1 === id1 && conn.node2 === id2) ||
  626.                    (conn.node1 === id2 && conn.node2 === id1)
  627.                );
  628.  
  629.                 if (existingConnection) return;
  630.  
  631.                 const type1 = node1.dataset.type;
  632.                 const type2 = node2.dataset.type;
  633.                 const { score, connectionType, isHarmony } = this.calculateConnectionScore(type1, type2);
  634.  
  635.                 // Create visual connection
  636.                 const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
  637.                 line.setAttribute('x1', node1.dataset.x);
  638.                 line.setAttribute('y1', node1.dataset.y);
  639.                 line.setAttribute('x2', node2.dataset.x);
  640.                 line.setAttribute('y2', node2.dataset.y);
  641.                 line.setAttribute('class', `connection-line ${connectionType}-connection`);
  642.                 line.setAttribute('filter', 'url(#glow)');
  643.                
  644.                 this.svg.appendChild(line);
  645.  
  646.                 // Update node connections
  647.                 const conn1 = parseInt(node1.dataset.connections) + 1;
  648.                 const conn2 = parseInt(node2.dataset.connections) + 1;
  649.                
  650.                 node1.dataset.connections = conn1;
  651.                 node2.dataset.connections = conn2;
  652.                 node1.classList.add('connected');
  653.                 node2.classList.add('connected');
  654.  
  655.                 // Handle scoring and effects
  656.                 this.score += score;
  657.                 if (isHarmony) {
  658.                     this.harmonyStreak++;
  659.                     const bonus = this.harmonyStreak * 10;
  660.                     this.harmonyBonus += bonus;
  661.                     this.showRewardPopup(node1, `+${score + bonus} Harmony!`);
  662.                     this.showCombo();
  663.                 } else {
  664.                     this.harmonyStreak = 0;
  665.                     this.hideCombo();
  666.                     if (score < 0) {
  667.                        this.showRewardPopup(node1, `${score} Nightmare!`);
  668.                    } else {
  669.                        this.showRewardPopup(node1, `+${score}`);
  670.                    }
  671.                }
  672.  
  673.                // Check for nightmare tangles (too many connections)
  674.                if (conn1 > 4 || conn2 > 4) {
  675.                     this.createNightmareTangle(conn1 > 4 ? node1 : node2);
  676.                 }
  677.  
  678.                 // Store connection
  679.                 this.connections.push({
  680.                     node1: id1,
  681.                     node2: id2,
  682.                     type: connectionType,
  683.                     line: line,
  684.                     score: score
  685.                 });
  686.  
  687.                 this.updateUI();
  688.                 this.checkWinCondition();
  689.  
  690.                 // Spawn new nodes strategically
  691.                 if (this.connections.length % 3 === 0 && this.nodes.length < 12) {
  692.                    setTimeout(() => this.createNode(), 1000);
  693.                 }
  694.             }
  695.  
  696.             calculateConnectionScore(type1, type2) {
  697.                 if (type1 === 'positive' && type2 === 'positive') {
  698.                    return { score: 50, connectionType: 'positive', isHarmony: true };
  699.                 } else if (type1 === 'negative' && type2 === 'negative') {
  700.                    return { score: 30, connectionType: 'negative', isHarmony: true };
  701.                 } else if (type1 === 'neutral' && type2 === 'neutral') {
  702.                    return { score: 40, connectionType: 'neutral', isHarmony: true };
  703.                 } else if ((type1 === 'positive' && type2 === 'negative') || (type1 === 'negative' && type2 === 'positive')) {
  704.                    return { score: -25, connectionType: 'nightmare', isHarmony: false };
  705.                 } else {
  706.                     // Mixed neutral connections
  707.                     return { score: 20, connectionType: 'neutral', isHarmony: false };
  708.                 }
  709.             }
  710.  
  711.             showRewardPopup(node, text) {
  712.                 const popup = document.createElement('div');
  713.                 popup.className = 'reward-popup';
  714.                 popup.textContent = text;
  715.                 popup.style.left = node.style.left;
  716.                 popup.style.top = (parseInt(node.style.top) - 20) + 'px';
  717.                
  718.                 this.canvas.appendChild(popup);
  719.                 setTimeout(() => {
  720.                     if (popup.parentNode) {
  721.                         popup.parentNode.removeChild(popup);
  722.                     }
  723.                 }, 2000);
  724.             }
  725.  
  726.             showCombo() {
  727.                 const combo = document.getElementById('combo');
  728.                 combo.textContent = `${this.harmonyStreak}x Harmony Streak!`;
  729.                 combo.style.display = 'block';
  730.             }
  731.  
  732.             hideCombo() {
  733.                 document.getElementById('combo').style.display = 'none';
  734.             }
  735.  
  736.             createNightmareTangle(node) {
  737.                 node.classList.add('nightmare');
  738.                 this.score -= 50;
  739.                 this.showRewardPopup(node, '-50 Tangle!');
  740.             }
  741.  
  742.             updateUI() {
  743.                 document.getElementById('score').textContent = Math.max(0, this.score);
  744.                 document.getElementById('harmony').textContent = this.harmonyBonus;
  745.                 document.getElementById('connections').textContent = this.connections.length;
  746.                
  747.                 const progress = Math.min(100, (this.connections.length / this.targetConnections) * 100);
  748.                 document.getElementById('progress').style.width = progress + '%';
  749.             }
  750.  
  751.             checkWinCondition() {
  752.                 if (this.connections.length >= this.targetConnections) {
  753.                     setTimeout(() => this.endGame(), 1000);
  754.                 }
  755.             }
  756.  
  757.             endGame() {
  758.                 if (this.gameComplete) return;
  759.                 this.gameComplete = true;
  760.  
  761.                 const finalScore = this.score + this.harmonyBonus;
  762.                 let endingType;
  763.  
  764.                 if (finalScore > 800 && this.harmonyStreak > 5) {
  765.                    endingType = 'transcendent';
  766.                 } else if (finalScore > 400) {
  767.                     endingType = 'balanced';
  768.                 } else if (finalScore > 0) {
  769.                     endingType = 'chaotic';
  770.                 } else {
  771.                     endingType = 'nightmare';
  772.                 }
  773.  
  774.                 const modal = document.getElementById('modal');
  775.                 const title = document.getElementById('modalTitle');
  776.                 const text = document.getElementById('modalText');
  777.                 const finalScoreElement = document.getElementById('finalScore');
  778.  
  779.                 title.textContent = this.getEndingTitle(endingType);
  780.                 text.textContent = this.dreamEndings[endingType];
  781.                 finalScoreElement.textContent = finalScore;
  782.  
  783.                 modal.style.display = 'block';
  784.             }
  785.  
  786.             getEndingTitle(type) {
  787.                 const titles = {
  788.                     transcendent: '✨ Dream Transcendence ✨',
  789.                     balanced: '🌟 Harmonious Dreams 🌟',
  790.                     chaotic: '🌪️ Beautiful Chaos 🌪️',
  791.                     nightmare: '👻 Shadow Realm 👻',
  792.                     incomplete: '💭 Mysterious Fragments 💭'
  793.                 };
  794.                 return titles[type] || 'Dream Complete';
  795.             }
  796.  
  797.             gameLoop() {
  798.                 // Gentle node movement
  799.                 this.nodes.forEach((node, index) => {
  800.                     if (!node.classList.contains('dragging')) {
  801.                         const time = Date.now() * 0.0005;
  802.                         const driftX = Math.sin(time + index) * 0.3;
  803.                         const driftY = Math.cos(time + index * 1.3) * 0.2;
  804.                        
  805.                         const currentX = parseFloat(node.style.left);
  806.                         const currentY = parseFloat(node.style.top);
  807.                        
  808.                         node.style.left = (currentX + driftX) + 'px';
  809.                         node.style.top = (currentY + driftY) + 'px';
  810.                         node.dataset.x = currentX + 70 + driftX;
  811.                         node.dataset.y = currentY + 45 + driftY;
  812.                     }
  813.                 });
  814.  
  815.                 // Update connection lines
  816.                 this.connections.forEach(conn => {
  817.                     const node1 = this.nodes[conn.node1];
  818.                     const node2 = this.nodes[conn.node2];
  819.                     if (node1 && node2 && conn.line) {
  820.                        conn.line.setAttribute('x1', node1.dataset.x);
  821.                         conn.line.setAttribute('y1', node1.dataset.y);
  822.                         conn.line.setAttribute('x2', node2.dataset.x);
  823.                         conn.line.setAttribute('y2', node2.dataset.y);
  824.                     }
  825.                 });
  826.  
  827.                 if (!this.gameComplete) {
  828.                     requestAnimationFrame(() => this.gameLoop());
  829.                 }
  830.             }
  831.         }
  832.  
  833.         function newGame() {
  834.             location.reload();
  835.         }
  836.  
  837.         // Initialize the game
  838.         let dreamWeaver;
  839.         window.addEventListener('DOMContentLoaded', () => {
  840.             dreamWeaver = new DreamWeaver();
  841.         });
  842.     </script>
  843. </body>
  844. </html>
  845.  
Advertisement
Add Comment
Please, Sign In to add comment