XTaylorSpenceX

Mirage Market Mystery

Sep 20th, 2025
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 35.16 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>Mirage Market Mystery - Enhanced</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  13.         }
  14.      
  15.         body {
  16.             background: linear-gradient(to bottom, #f5d76e, #d4ac0d, #7d6608);
  17.             color: #3e2723;
  18.             min-height: 100vh;
  19.             overflow-x: hidden;
  20.             padding: 20px;
  21.         }
  22.      
  23.         .container {
  24.             max-width: 1200px;
  25.             margin: 0 auto;
  26.             padding: 20px;
  27.         }
  28.      
  29.         header {
  30.             text-align: center;
  31.             margin-bottom: 30px;
  32.             position: relative;
  33.         }
  34.      
  35.         h1 {
  36.             font-size: 3rem;
  37.             color: #3e2723;
  38.             text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.5);
  39.             margin-bottom: 10px;
  40.         }
  41.      
  42.         .subtitle {
  43.             font-size: 1.2rem;
  44.             color: #5d4037;
  45.             margin-bottom: 20px;
  46.         }
  47.      
  48.         .stats {
  49.             display: flex;
  50.             justify-content: center;
  51.             gap: 30px;
  52.             margin-bottom: 20px;
  53.             background: rgba(255, 236, 179, 0.7);
  54.             padding: 15px;
  55.             border-radius: 10px;
  56.             box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  57.         }
  58.      
  59.         .stat-item {
  60.             text-align: center;
  61.         }
  62.      
  63.         .stat-value {
  64.             font-size: 1.8rem;
  65.             font-weight: bold;
  66.             color: #3e2723;
  67.         }
  68.      
  69.         .instructions {
  70.             background: rgba(255, 236, 179, 0.9);
  71.             padding: 20px;
  72.             border-radius: 10px;
  73.             margin-bottom: 30px;
  74.             box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  75.         }
  76.      
  77.         .instructions h2 {
  78.             margin-bottom: 10px;
  79.             color: #5d4037;
  80.         }
  81.      
  82.         .instructions ul {
  83.             list-style-type: none;
  84.             padding-left: 20px;
  85.         }
  86.      
  87.         .instructions li {
  88.             margin-bottom: 8px;
  89.             position: relative;
  90.             padding-left: 25px;
  91.         }
  92.      
  93.         .instructions li:before {
  94.             content: "•";
  95.             color: #d4ac0d;
  96.             font-weight: bold;
  97.             position: absolute;
  98.             left: 0;
  99.             font-size: 1.5rem;
  100.         }
  101.      
  102.         .inventory {
  103.             background: rgba(255, 236, 179, 0.9);
  104.             padding: 20px;
  105.             border-radius: 10px;
  106.             margin-bottom: 30px;
  107.             box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  108.         }
  109.      
  110.         .inventory h2 {
  111.             margin-bottom: 15px;
  112.             color: #5d4037;
  113.         }
  114.      
  115.         .inventory-slots {
  116.             display: grid;
  117.             grid-template-columns: repeat(6, 1fr);
  118.             gap: 10px;
  119.         }
  120.      
  121.         .inventory-slot {
  122.             width: 60px;
  123.             height: 60px;
  124.             background: rgba(212, 172, 13, 0.3);
  125.             border: 2px solid #d4ac0d;
  126.             border-radius: 5px;
  127.             display: flex;
  128.             justify-content: center;
  129.             align-items: center;
  130.             font-size: 1.8rem;
  131.             cursor: pointer;
  132.             position: relative;
  133.         }
  134.      
  135.         .inventory-slot:hover {
  136.             background: rgba(212, 172, 13, 0.5);
  137.         }
  138.      
  139.         .sell-tooltip {
  140.             position: fixed;
  141.             background: rgba(255, 236, 179, 0.95);
  142.             padding: 10px;
  143.             border-radius: 5px;
  144.             box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
  145.             pointer-events: none;
  146.             z-index: 100;
  147.             display: none;
  148.         }
  149.      
  150.         .market {
  151.             display: grid;
  152.             grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  153.             gap: 25px;
  154.             margin-bottom: 30px;
  155.             perspective: 1000px;
  156.         }
  157.      
  158.         .stall {
  159.             background: rgba(255, 236, 179, 0.9);
  160.             border-radius: 10px;
  161.             padding: 20px;
  162.             text-align: center;
  163.             box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
  164.             transition: transform 0.5s ease, opacity 0.5s ease;
  165.             position: relative;
  166.             overflow: hidden;
  167.         }
  168.      
  169.         .stall:before {
  170.             content: "";
  171.             position: absolute;
  172.             top: 0;
  173.             left: -100%;
  174.             width: 100%;
  175.             height: 100%;
  176.             background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
  177.             transition: 0.5s;
  178.         }
  179.      
  180.         .stall:hover:before {
  181.             left: 100%;
  182.         }
  183.      
  184.         .stall h3 {
  185.             color: #5d4037;
  186.             margin-bottom: 15px;
  187.             font-size: 1.4rem;
  188.         }
  189.      
  190.         .item {
  191.             font-size: 3rem;
  192.             margin-bottom: 15px;
  193.             transition: all 0.3s ease;
  194.         }
  195.      
  196.         .price {
  197.             font-size: 1.2rem;
  198.             color: #3e2723;
  199.             margin-bottom: 15px;
  200.         }
  201.      
  202.         .timer {
  203.             height: 5px;
  204.             background: #d4ac0d;
  205.             width: 100%;
  206.             margin-bottom: 15px;
  207.             border-radius: 5px;
  208.             overflow: hidden;
  209.         }
  210.      
  211.         .timer-bar {
  212.             height: 100%;
  213.             background: #ff5722;
  214.             width: 100%;
  215.             transition: width 1s linear;
  216.         }
  217.      
  218.         .barter-container {
  219.             display: flex;
  220.             justify-content: center;
  221.             align-items: center;
  222.             gap: 10px;
  223.         }
  224.      
  225.         .barter-btn {
  226.             background: #d4ac0d;
  227.             color: #3e2723;
  228.             border: none;
  229.             width: 30px;
  230.             height: 30px;
  231.             border-radius: 50%;
  232.             cursor: pointer;
  233.             font-weight: bold;
  234.             display: flex;
  235.             justify-content: center;
  236.             align-items: center;
  237.             transition: background 0.3s;
  238.         }
  239.      
  240.         .barter-btn:hover {
  241.             background: #f5d76e;
  242.         }
  243.      
  244.         .barter-btn:disabled {
  245.             background: #cccccc;
  246.             cursor: not-allowed;
  247.         }
  248.      
  249.         .buy-btn {
  250.             background: #d4ac0d;
  251.             color: #3e2723;
  252.             border: none;
  253.             padding: 8px 15px;
  254.             border-radius: 5px;
  255.             cursor: pointer;
  256.             font-weight: bold;
  257.             transition: background 0.3s;
  258.         }
  259.      
  260.         .buy-btn:hover {
  261.             background: #f5d76e;
  262.         }
  263.      
  264.         .buy-btn:disabled {
  265.             background: #cccccc;
  266.             cursor: not-allowed;
  267.         }
  268.      
  269.         .message-box {
  270.             position: fixed;
  271.             top: 50%;
  272.             left: 50%;
  273.             transform: translate(-50%, -50%);
  274.             background: rgba(255, 236, 179, 0.95);
  275.             padding: 30px;
  276.             border-radius: 10px;
  277.             box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
  278.             text-align: center;
  279.             z-index: 100;
  280.             display: none;
  281.         }
  282.      
  283.         .message-box h2 {
  284.             margin-bottom: 20px;
  285.             color: #5d4037;
  286.         }
  287.      
  288.         .message-box p {
  289.             margin-bottom: 20px;
  290.             font-size: 1.2rem;
  291.         }
  292.      
  293.         .close-btn {
  294.             background: #d4ac0d;
  295.             color: #3e2723;
  296.             border: none;
  297.             padding: 10px 20px;
  298.             border-radius: 5px;
  299.             cursor: pointer;
  300.             font-weight: bold;
  301.         }
  302.      
  303.         .heat-wave {
  304.             position: fixed;
  305.             top: 0;
  306.             left: 0;
  307.             width: 100%;
  308.             height: 100%;
  309.             pointer-events: none;
  310.             background: linear-gradient(to bottom, rgba(255, 255, 255, 0.1) 0%, transparent 50%, rgba(255, 255, 255, 0.1) 100%);
  311.             background-size: 100% 5px;
  312.             animation: heatWave 2s infinite linear;
  313.             z-index: 50;
  314.             opacity: 0.6;
  315.         }
  316.      
  317.         @keyframes heatWave {
  318.             0% {
  319.                 background-position: 0 0;
  320.             }
  321.             100% {
  322.                 background-position: 0 50px;
  323.             }
  324.         }
  325.      
  326.         .mirage {
  327.             animation: shimmer 3s infinite alternate;
  328.         }
  329.      
  330.         @keyframes shimmer {
  331.             0% {
  332.                 opacity: 0.7;
  333.                 transform: scale(0.95);
  334.             }
  335.             100% {
  336.                 opacity: 1;
  337.                 transform: scale(1.05);
  338.             }
  339.         }
  340.      
  341.         .fade-out {
  342.             animation: fadeOut 1s forwards;
  343.         }
  344.      
  345.         @keyframes fadeOut {
  346.             to {
  347.                 opacity: 0;
  348.                 transform: translateY(20px) scale(0.9);
  349.             }
  350.         }
  351.      
  352.         .artifact {
  353.             position: relative;
  354.         }
  355.      
  356.         .artifact:after {
  357.             content: "✨";
  358.             position: absolute;
  359.             top: -10px;
  360.             right: -10px;
  361.             font-size: 1.5rem;
  362.             animation: glow 2s infinite alternate;
  363.         }
  364.      
  365.         @keyframes glow {
  366.             from {
  367.                 text-shadow: 0 0 5px #fff, 0 0 10px #fff, 0 0 15px #ffdd00, 0 0 20px #ffdd00;
  368.             }
  369.             to {
  370.                 text-shadow: 0 0 10px #fff, 0 0 20px #fff, 0 0 30px #ffdd00, 0 0 40px #ffdd00;
  371.             }
  372.         }
  373.      
  374.         .shimmer {
  375.             position: relative;
  376.         }
  377.      
  378.         .shimmer:before {
  379.             content: "";
  380.             position: absolute;
  381.             top: -50%;
  382.             left: -50%;
  383.             width: 200%;
  384.             height: 200%;
  385.             background: linear-gradient(45deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.3) 50%, rgba(255,255,255,0) 100%);
  386.             transform: rotate(45deg);
  387.             animation: shine 3s infinite;
  388.         }
  389.      
  390.         @keyframes shine {
  391.             0% {
  392.                 left: -100%;
  393.             }
  394.             100% {
  395.                 left: 100%;
  396.             }
  397.         }
  398.      
  399.         footer {
  400.             text-align: center;
  401.             margin-top: 30px;
  402.             color: #5d4037;
  403.             font-size: 0.9rem;
  404.         }
  405.      
  406.         #startScreen {
  407.             position: fixed;
  408.             top: 0;
  409.             left: 0;
  410.             width: 100%;
  411.             height: 100%;
  412.             background: rgba(0,0,0,0.7);
  413.             display: flex;
  414.             justify-content: center;
  415.             align-items: center;
  416.             z-index: 1000;
  417.         }
  418.      
  419.         @media (max-width: 768px) {
  420.             .market {
  421.                 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  422.             }
  423.          
  424.             .inventory-slots {
  425.                 grid-template-columns: repeat(4, 1fr);
  426.             }
  427.          
  428.             h1 {
  429.                 font-size: 2.2rem;
  430.             }
  431.          
  432.             .stat-value {
  433.                 font-size: 1.5rem;
  434.             }
  435.         }
  436.      
  437.         .shake {
  438.             animation: shake 0.5s;
  439.             animation-iteration-count: 1;
  440.         }
  441.      
  442.         @keyframes shake {
  443.             0% { transform: translate(1px, 1px) rotate(0deg); }
  444.             10% { transform: translate(-1px, -2px) rotate(-1deg); }
  445.             20% { transform: translate(-3px, 0px) rotate(1deg); }
  446.             30% { transform: translate(3px, 2px) rotate(0deg); }
  447.             40% { transform: translate(1px, -1px) rotate(1deg); }
  448.             50% { transform: translate(-1px, 2px) rotate(-1deg); }
  449.             60% { transform: translate(-3px, 1px) rotate(0deg); }
  450.             70% { transform: translate(3px, 1px) rotate(-1deg); }
  451.             80% { transform: translate(-1px, -1px) rotate(1deg); }
  452.             90% { transform: translate(1px, 2px) rotate(0deg); }
  453.             100% { transform: translate(1px, -2px) rotate(-1deg); }
  454.         }
  455.        
  456.         /* New styles for mirage explosion */
  457.         .explode {
  458.             animation: explode 0.8s forwards;
  459.         }
  460.        
  461.         @keyframes explode {
  462.             0% { transform: scale(1); opacity: 1; }
  463.             50% { transform: scale(1.5); opacity: 0.5; }
  464.             100% { transform: scale(2); opacity: 0; }
  465.         }
  466.        
  467.         .artifact-chance {
  468.             font-size: 0.9rem;
  469.             color: #5d4037;
  470.             margin-top: 5px;
  471.             height: 20px;
  472.         }
  473.     </style>
  474. </head>
  475. <body>
  476.     <div class="heat-wave"></div>
  477.     <div class="sell-tooltip" id="sellTooltip"></div>
  478.  
  479.     <div id="startScreen">
  480.         <div style="text-align: center; color: white;">
  481.             <h2 style="margin-bottom: 20px;">Mirage Market Mystery</h2>
  482.             <p style="margin-bottom: 30px;">Now with enhanced economy and better artifact chances!</p>
  483.             <button class="close-btn" onclick="startGame()">Start</button>
  484.         </div>
  485.     </div>
  486.  
  487.     <div class="container">
  488.         <header>
  489.             <h1>Mirage Market Mystery</h1>
  490.             <p class="subtitle">Navigate the shifting sands of the bazaar to uncover rare artifacts</p>
  491.          
  492.             <div class="stats">
  493.                 <div class="stat-item">
  494.                     <div class="stat-label">Gold</div>
  495.                     <div class="stat-value" id="gold">100</div>
  496.                 </div>
  497.                 <div class="stat-item">
  498.                     <div class="stat-label">Artifacts</div>
  499.                     <div class="stat-value" id="artifacts">0</div>
  500.                 </div>
  501.                 <div class="stat-item">
  502.                     <div class="stat-label">Time</div>
  503.                     <div class="stat-value" id="timer">120</div>
  504.                 </div>
  505.             </div>
  506.         </header>
  507.      
  508.         <div class="instructions">
  509.             <h2>How to Play</h2>
  510.             <ul>
  511.                 <li>Stalls shift positions and goods appear/disappear randomly</li>
  512.                 <li>Use + and - to barter - + increases artifact chance, - lowers price but risks</li>
  513.                 <li>Buy items before they vanish - but beware of mirages!</li>
  514.                 <li>Look for shimmering items - they might be rare artifacts</li>
  515.                 <li>Sell items from your inventory by clicking on them</li>
  516.                 <li>Manage your gold wisely - mirages will waste your gold</li>
  517.                 <li>Find 5 artifacts before time runs out to win!</li>
  518.             </ul>
  519.         </div>
  520.      
  521.         <div class="inventory">
  522.             <h2>Inventory <span id="inventoryCount">(0/12)</span></h2>
  523.             <div class="inventory-slots" id="inventorySlots">
  524.                 <!-- Inventory slots will be generated by JavaScript -->
  525.             </div>
  526.         </div>
  527.      
  528.         <div class="market" id="market">
  529.             <!-- Stalls will be generated by JavaScript -->
  530.         </div>
  531.      
  532.         <footer>
  533.             <p>Mirage Market Mystery - Can you master the shifting bazaar?</p>
  534.         </footer>
  535.     </div>
  536.  
  537.     <div class="message-box" id="messageBox">
  538.         <h2 id="messageTitle">Game Over</h2>
  539.         <p id="messageText">You've run out of gold!</p>
  540.         <button id="messageButton" class="close-btn">Play Again</button>
  541.     </div>
  542.     <script>
  543.         // Game state
  544.         const gameState = {
  545.             gold: 100.0,
  546.             artifacts: 0,
  547.             time: 120,
  548.             stalls: [],
  549.             inventory: new Array(12).fill(null),
  550.             gameInterval: null,
  551.             shiftInterval: null,
  552.             goldInterval: null,
  553.             isGameActive: false,
  554.             globalPriceModifier: 1.0 // Starts at 1, changes with buys/sells
  555.         };
  556.      
  557.         // Items data with 80% reduced prices
  558.         const items = [
  559.             { name: "Desert Rose", emoji: "🌹", basePrice: 4 },
  560.             { name: "Magic Lamp", emoji: "🪔", basePrice: 8 },
  561.             { name: "Silk Scarf", emoji: "🧣", basePrice: 3 },
  562.             { name: "Sandstone Tablet", emoji: "📜", basePrice: 9 },
  563.             { name: "Pyramid Crystal", emoji: "🔮", basePrice: 14 },
  564.             { name: "Ancient Potion", emoji: "🧪", basePrice: 6 },
  565.             { name: "Golden Scarab", emoji: "🐞", basePrice: 10 },
  566.             { name: "Pharaoh's Mask", emoji: "🎭", basePrice: 12 },
  567.             { name: "Desert Dagger", emoji: "🔪", basePrice: 5 }
  568.         ];
  569.      
  570.         // Start the game
  571.         function startGame() {
  572.             document.getElementById('startScreen').style.display = 'none';
  573.             initGame();
  574.         }
  575.      
  576.         // Initialize the game
  577.         function initGame() {
  578.             gameState.gold = 100.0;
  579.             gameState.artifacts = 0;
  580.             gameState.time = 120;
  581.             gameState.inventory = new Array(12).fill(null);
  582.             gameState.isGameActive = true;
  583.             gameState.globalPriceModifier = 1.0;
  584.          
  585.             updateUI();
  586.             generateStalls();
  587.             initializeInventory();
  588.          
  589.             // Start game timer
  590.             clearInterval(gameState.gameInterval);
  591.             gameState.gameInterval = setInterval(gameTick, 1000);
  592.          
  593.             // Start shifting stalls
  594.             clearInterval(gameState.shiftInterval);
  595.             gameState.shiftInterval = setInterval(shiftStalls, 5000);
  596.          
  597.             // Start gold increase
  598.             clearInterval(gameState.goldInterval);
  599.             gameState.goldInterval = setInterval(() => {
  600.                 if (gameState.isGameActive) {
  601.                     gameState.gold += (0.5 + Math.random() * 2); // Reduced gold income
  602.                     updateUI();
  603.                 }
  604.             }, 1000);
  605.         }
  606.      
  607.         // Main game tick (every second)
  608.         function gameTick() {
  609.             if (gameState.isGameActive) {
  610.                 gameState.time--;
  611.                 updateUI();
  612.              
  613.                 if (gameState.time <= 0) {
  614.                    endGame(`The market gates are closing! You found ${gameState.artifacts} artifacts but needed 5 to prove your expertise as a master collector. The desert sun sets on today's opportunities, but new treasures await tomorrow.`);
  615.                }
  616.            }
  617.        }
  618.      
  619.        // Initialize inventory slots
  620.        function initializeInventory() {
  621.            const inventorySlots = document.getElementById('inventorySlots');
  622.            inventorySlots.innerHTML = '';
  623.          
  624.            for (let i = 0; i < 12; i++) {
  625.                const slot = document.createElement('div');
  626.                slot.className = 'inventory-slot';
  627.                slot.dataset.index = i;
  628.                slot.innerHTML = '<div style="opacity: 0.3;">+</div>';
  629.                 slot.addEventListener('click', () => sellItem(i));
  630.                 slot.addEventListener('mousemove', (e) => showSellTooltip(e, i));
  631.                 slot.addEventListener('mouseout', hideSellTooltip);
  632.              
  633.                 inventorySlots.appendChild(slot);
  634.             }
  635.          
  636.             updateInventoryCount();
  637.         }
  638.      
  639.         // Show sell tooltip
  640.         function showSellTooltip(e, index) {
  641.             const tooltip = document.getElementById('sellTooltip');
  642.             const item = gameState.inventory[index];
  643.          
  644.             if (item) {
  645.                 let statusHtml = item.isArtifact
  646.                     ? '<span style="color: purple;">Status: Artifact</span>'
  647.                     : '<span style="color: blue;">Status: Common</span>';
  648.              
  649.                 if (item.isArtifact) {
  650.                     tooltip.innerHTML = `${statusHtml}<br>Cannot sell`;
  651.                 } else {
  652.                     const sellPrice = Math.floor(item.price * 0.5);
  653.                     tooltip.innerHTML = `${statusHtml}<br>Sell for ${sellPrice} gold<br>Left-click to sell`;
  654.                 }
  655.                 tooltip.style.display = 'block';
  656.                 tooltip.style.left = (e.pageX + 10) + 'px';
  657.                 tooltip.style.top = (e.pageY + 10) + 'px';
  658.             }
  659.         }
  660.      
  661.         // Hide sell tooltip
  662.         function hideSellTooltip() {
  663.             const tooltip = document.getElementById('sellTooltip');
  664.             tooltip.style.display = 'none';
  665.         }
  666.      
  667.         // Sell item from inventory
  668.         function sellItem(index) {
  669.             if (!gameState.isGameActive) return;
  670.          
  671.             const item = gameState.inventory[index];
  672.             if (item) {
  673.                 if (item.isArtifact) {
  674.                     showMessage("Cannot Sell", "Artifacts cannot be sold!", false);
  675.                     return;
  676.                 }
  677.              
  678.                 const sellPrice = Math.floor(item.price * 0.5);
  679.                 gameState.gold += sellPrice;
  680.              
  681.                 // Update global price modifier slightly on sell
  682.                 gameState.globalPriceModifier *= 0.98; // Slight decrease on sell
  683.              
  684.                 // Update inventory
  685.                 gameState.inventory[index] = null;
  686.              
  687.                 // Update slot
  688.                 const slot = document.querySelector(`.inventory-slot[data-index="${index}"]`);
  689.                 slot.innerHTML = '<div style="opacity: 0.3;">+</div>';
  690.              
  691.                 updateUI();
  692.                 updateInventoryCount();
  693.             }
  694.         }
  695.      
  696.         // Update inventory count
  697.         function updateInventoryCount() {
  698.             const count = gameState.inventory.filter(item => item !== null).length;
  699.             document.getElementById('inventoryCount').textContent = `(${count}/12)`;
  700.         }
  701.      
  702.         // Generate stalls for the market
  703.         function generateStalls() {
  704.             const market = document.getElementById('market');
  705.             market.innerHTML = '';
  706.             gameState.stalls = [];
  707.          
  708.             const stallCount = 6;
  709.          
  710.             for (let i = 0; i < stallCount; i++) {
  711.                const stall = document.createElement('div');
  712.                stall.className = 'stall';
  713.                stall.dataset.id = i;
  714.              
  715.                // Decide shimmer first
  716.                const hasShimmer = Math.random() < 0.2;
  717.              
  718.                // Base artifact chance (10-20%)
  719.                const baseArtifactChance = 0.1 + (Math.random() * 0.1);
  720.                const item = JSON.parse(JSON.stringify(items[Math.floor(Math.random() * items.length)]));
  721.              
  722.                // Apply global modifier and shimmer inflation
  723.                item.basePrice = Math.floor(item.basePrice * gameState.globalPriceModifier);
  724.                if (hasShimmer) item.basePrice += 2;
  725.              
  726.                const timerDuration = 8000 + Math.random() * 7000;
  727.              
  728.                gameState.stalls.push({
  729.                    element: stall,
  730.                    item: item,
  731.                    hasShimmer: hasShimmer,
  732.                    timerDuration: timerDuration,
  733.                    timer: null,
  734.                    currentPrice: item.basePrice,
  735.                    barterCount: 0,
  736.                    maxBarter: Math.floor(Math.random() * 3) + 4,
  737.                    lockBarter: false,
  738.                    artifactChance: baseArtifactChance
  739.                });
  740.              
  741.                renderStall(i);
  742.              
  743.                market.appendChild(stall);
  744.              
  745.                startItemTimer(i, timerDuration);
  746.            }
  747.        }
  748.      
  749.        // Render a stall
  750.        function renderStall(stallId) {
  751.            const stall = gameState.stalls[stallId];
  752.            const item = stall.item;
  753.          
  754.            let className = 'item';
  755.            if (stall.hasShimmer) className += ' shimmer';
  756.          
  757.            stall.element.innerHTML = `
  758.                <h3>${item.name}</h3>
  759.                 <div class="${className}">${item.emoji}</div>
  760.                 <div class="price">${stall.currentPrice} gold</div>
  761.                 <div class="artifact-chance">Artifact chance: ${Math.round(stall.artifactChance * 100)}%</div>
  762.                 <div class="timer"><div class="timer-bar" style="width: 100%;"></div></div>
  763.                 <div class="barter-container">
  764.                     <button class="barter-btn" onclick="barter(${stallId}, -1)" ${stall.lockBarter ? 'disabled' : ''}>-</button>
  765.                     <button class="buy-btn" onclick="buyItem(${stallId})">Purchase</button>
  766.                     <button class="barter-btn" onclick="barter(${stallId}, 1)" ${stall.lockBarter ? 'disabled' : ''}>+</button>
  767.                 </div>
  768.             `;
  769.         }
  770.      
  771.         // Barter for an item
  772.         function barter(stallId, direction) {
  773.             if (!gameState.isGameActive) return;
  774.          
  775.             const stall = gameState.stalls[stallId];
  776.          
  777.             if (stall.lockBarter) return;
  778.          
  779.             if (stall.barterCount >= stall.maxBarter) {
  780.                 showMessage("Barter Failed", "The trader refuses to negotiate further.", false);
  781.                 return;
  782.             }
  783.          
  784.             stall.barterCount++;
  785.          
  786.             if (direction === -1) { // Decrease price
  787.                 // Sometimes increase by 3 and lock
  788.                 if (Math.random() < 0.2) {
  789.                    stall.currentPrice += 3;
  790.                    stall.lockBarter = true;
  791.                    stall.element.classList.add('shake');
  792.                    setTimeout(() => stall.element.classList.remove('shake'), 500);
  793.                 } else {
  794.                     stall.currentPrice = Math.max(1, stall.currentPrice - 1);
  795.                  
  796.                     // Slight decrease to artifact chance (2-5%)
  797.                     stall.artifactChance = Math.max(0.05, stall.artifactChance - (0.02 + Math.random() * 0.03));
  798.                 }
  799.             } else { // Increase for +
  800.                 stall.currentPrice += 3;
  801.              
  802.                 // Increase artifact chance based on barter count
  803.                 if (stall.barterCount === 1) {
  804.                     stall.artifactChance = 0.15 + (Math.random() * 0.1); // 15-25%
  805.                 } else if (stall.barterCount === 2) {
  806.                     stall.artifactChance = 0.2 + (Math.random() * 0.1); // 20-30%
  807.                 } else {
  808.                     stall.artifactChance = Math.min(0.9, stall.artifactChance + 0.05); // +5% each additional click
  809.                 }
  810.             }
  811.          
  812.             renderStall(stallId);
  813.          
  814.             if (stall.barterCount >= stall.maxBarter) {
  815.                 const barterButtons = stall.element.querySelectorAll('.barter-btn');
  816.                 barterButtons.forEach(btn => btn.disabled = true);
  817.             }
  818.         }
  819.      
  820.         // Start timer for item
  821.         function startItemTimer(stallId, duration) {
  822.             const stall = gameState.stalls[stallId];
  823.             const timerBar = stall.element.querySelector('.timer-bar');
  824.          
  825.             if (stall.timer) clearTimeout(stall.timer);
  826.          
  827.             timerBar.style.transition = `width ${duration}ms linear`;
  828.             timerBar.style.width = '0%';
  829.          
  830.             stall.timer = setTimeout(() => {
  831.                 if (stall.element.parentNode) {
  832.                     stall.element.classList.add('fade-out');
  833.                     setTimeout(() => {
  834.                         if (stall.element.parentNode) replaceStallItem(stallId);
  835.                     }, 1000);
  836.                 }
  837.             }, duration);
  838.         }
  839.      
  840.         // Replace stall item
  841.         function replaceStallItem(stallId) {
  842.             const stall = gameState.stalls[stallId];
  843.          
  844.             const hasShimmer = Math.random() < 0.2;
  845.          
  846.            // Base artifact chance (10-20%)
  847.            const baseArtifactChance = 0.1 + (Math.random() * 0.1);
  848.            const newItem = JSON.parse(JSON.stringify(items[Math.floor(Math.random() * items.length)]));
  849.          
  850.            newItem.basePrice = Math.floor(newItem.basePrice * gameState.globalPriceModifier);
  851.            if (hasShimmer) newItem.basePrice += 2;
  852.          
  853.            stall.item = newItem;
  854.            stall.hasShimmer = hasShimmer;
  855.            stall.timerDuration = 8000 + Math.random() * 7000;
  856.            stall.currentPrice = newItem.basePrice;
  857.            stall.barterCount = 0;
  858.            stall.maxBarter = Math.floor(Math.random() * 3) + 4;
  859.            stall.lockBarter = false;
  860.            stall.artifactChance = baseArtifactChance;
  861.          
  862.            stall.element.classList.remove('fade-out');
  863.            renderStall(stallId);
  864.          
  865.            startItemTimer(stallId, stall.timerDuration);
  866.        }
  867.      
  868.        // Shift stalls
  869.        function shiftStalls() {
  870.            if (!gameState.isGameActive) return;
  871.          
  872.            const market = document.getElementById('market');
  873.            const stalls = Array.from(market.children);
  874.          
  875.            for (let i = stalls.length - 1; i > 0; i--) {
  876.                 const j = Math.floor(Math.random() * (i + 1));
  877.                 market.appendChild(stalls[j]);
  878.             }
  879.          
  880.             stalls.forEach(stall => {
  881.                 stall.style.transform = 'translateX(20px)';
  882.                 setTimeout(() => stall.style.transform = 'translateX(0)', 300);
  883.             });
  884.         }
  885.      
  886.         // Buy item
  887.         function buyItem(stallId) {
  888.             if (!gameState.isGameActive) return;
  889.          
  890.             const stall = gameState.stalls[stallId];
  891.             const price = stall.currentPrice;
  892.          
  893.             if (gameState.inventory.filter(item => item !== null).length >= 12) {
  894.                 showMessage("Inventory Full", "Your inventory is full! Sell some items first.", false);
  895.                 return;
  896.             }
  897.          
  898.             if (gameState.gold >= price) {
  899.                 // 10% chance of mirage
  900.                 const isMirage = Math.random() < 0.1;
  901.              
  902.                // Determine if this is actually an artifact based on artifact chance
  903.                const isActuallyArtifact = Math.random() < stall.artifactChance;
  904.              
  905.                if (isMirage) {
  906.                    // Mirage effect - item explodes and disappears
  907.                    stall.element.classList.add('explode');
  908.                    gameState.gold -= price;
  909.                  
  910.                    setTimeout(() => {
  911.                         stall.element.classList.remove('explode');
  912.                         showMessage("Mirage!", "The item vanished into thin air! You wasted your gold.", false);
  913.                         replaceStallItem(stallId);
  914.                     }, 800);
  915.                 } else {
  916.                     gameState.gold -= price;
  917.                  
  918.                     // Update global price modifier on buy
  919.                     gameState.globalPriceModifier *= 1.02; // Slight increase on buy
  920.                  
  921.                     const inventoryIndex = gameState.inventory.findIndex(slot => slot === null);
  922.                     if (inventoryIndex !== -1) {
  923.                         // Use the same displayed item, but set isArtifact based on chance
  924.                         const actualItem = JSON.parse(JSON.stringify(stall.item));
  925.                         actualItem.isArtifact = isActuallyArtifact;
  926.                         actualItem.price = price;
  927.                        
  928.                         gameState.inventory[inventoryIndex] = actualItem;
  929.                      
  930.                         const slot = document.querySelector(`.inventory-slot[data-index="${inventoryIndex}"]`);
  931.                         let slotClass = actualItem.isArtifact ? 'artifact' : '';
  932.                         slot.innerHTML = `<div class="${slotClass}">${actualItem.emoji}</div>`;
  933.                      
  934.                         if (actualItem.isArtifact) {
  935.                             gameState.artifacts++;
  936.                             updateUI(); // Update UI before checking win
  937.                             showMessage("Artifact Found!", `You acquired a rare ${actualItem.name}!`, false);
  938.                             if (gameState.artifacts >= 5) {
  939.                                 endGame("Congratulations! You've uncovered 5 rare artifacts and mastered the Mirage Market. With these treasures in hand, venture forth to fence them in shadowy black markets, turning your savvy acquisitions into fortunes beyond imagination—your legend as a bazaar whisperer begins anew!");
  940.                                 return;
  941.                             }
  942.                         } else {
  943.                             showMessage("Purchase Successful", `You bought a ${actualItem.name}.`, false);
  944.                         }
  945.                     }
  946.                 }
  947.              
  948.                 updateUI();
  949.                 updateInventoryCount();
  950.              
  951.                 if (!isMirage) {
  952.                     replaceStallItem(stallId);
  953.                 }
  954.              
  955.                 if (gameState.gold < 1) {
  956.                    endGame("You've run out of gold!");
  957.                }
  958.            } else {
  959.                showMessage("Not Enough Gold", "You don't have enough gold to buy this item.", false);
  960.            }
  961.        }
  962.      
  963.        // Update UI
  964.        function updateUI() {
  965.            document.getElementById('gold').textContent = Math.round(gameState.gold);
  966.            document.getElementById('artifacts').textContent = gameState.artifacts;
  967.            document.getElementById('timer').textContent = gameState.time;
  968.        }
  969.      
  970.        // Show message
  971.        function showMessage(title, text, isGameOver = false) {
  972.            const messageBox = document.getElementById('messageBox');
  973.            const messageTitle = document.getElementById('messageTitle');
  974.            const messageText = document.getElementById('messageText');
  975.            const messageButton = document.getElementById('messageButton');
  976.          
  977.            messageTitle.textContent = title;
  978.            messageText.textContent = text;
  979.          
  980.            if (isGameOver) {
  981.                messageButton.textContent = 'Play Again';
  982.                messageButton.onclick = resetGame;
  983.            } else {
  984.                messageButton.textContent = 'Close';
  985.                messageButton.onclick = () => messageBox.style.display = 'none';
  986.             }
  987.          
  988.             messageBox.style.display = 'block';
  989.         }
  990.      
  991.         // End game
  992.         function endGame(message) {
  993.             gameState.isGameActive = false;
  994.             clearInterval(gameState.gameInterval);
  995.             clearInterval(gameState.shiftInterval);
  996.             clearInterval(gameState.goldInterval);
  997.          
  998.             showMessage("Game Over", message, true);
  999.         }
  1000.      
  1001.         // Reset game
  1002.         function resetGame() {
  1003.             document.getElementById('messageBox').style.display = 'none';
  1004.             document.getElementById('startScreen').style.display = 'flex';
  1005.         }
  1006.      
  1007.         // On load, show start screen
  1008.         window.onload = () => {
  1009.             document.getElementById('startScreen').style.display = 'flex';
  1010.         };
  1011.     </script>
  1012. </body>
  1013. </html>
  1014.  
Add Comment
Please, Sign In to add comment