window.GDD = window.GDD || {}; const { useState, useEffect, useCallback, useRef } = React; function RefiningDemo() { const [inventory, setInventory] = useState([]); const [orePrices, setOrePrices] = useState({}); const [selectedOre, setSelectedOre] = useState(null); const [refineQty, setRefineQty] = useState(0); const [skillLevel, setSkillLevel] = useState(2); const [refining, setRefining] = useState(false); const [results, setResults] = useState([]); const [manufacturingTab, setManufacturingTab] = useState(false); const [manufacturingJobs, setManufacturingJobs] = useState([]); const [notifications, setNotifications] = useState([]); const timerRef = useRef(null); const mineralData = { Veldspar: { mineral: 'Tritanium', yield: 415, batch: 333, time: 45 }, Scordite: { mineral: 'Pyerite', yield: 171, batch: 333, time: 45 }, Pyroxeres: { mineral: 'Nocxium', yield: 8, batch: 333, time: 60 }, Kernite: { mineral: 'Isogen', yield: 107, batch: 200, time: 60 }, Omber: { mineral: 'Isogen', yield: 86, batch: 500, time: 75 }, Jaspet: { mineral: 'Zydrine', yield: 8, batch: 500, time: 75 }, Hemorphite: { mineral: 'Nocxium', yield: 21, batch: 500, time: 90 }, Arkonor: { mineral: 'Megacyte', yield: 18, batch: 200, time: 120 }, }; const manufacturingRecipes = [ { id: 1, product: 'Mining Laser I', minerals: { Tritanium: 200, Pyerite: 80 }, time: 300, skill: 1 }, { id: 2, product: '150mm Railgun', minerals: { Tritanium: 400, Pyerite: 150, Nocxium: 20 }, time: 900, skill: 2 }, { id: 3, product: 'Shield Booster I', minerals: { Tritanium: 300, Isogen: 50 }, time: 600, skill: 2 }, { id: 4, product: 'Frigate Hull', minerals: { Tritanium: 2000, Pyerite: 800, Nocxium: 100 }, time: 1800, skill: 3 }, { id: 5, product: '1MN Afterburner', minerals: { Tritanium: 150, Pyerite: 50, Isogen: 20 }, time: 480, skill: 2 }, ]; const [playerMinerals, setPlayerMinerals] = useState({ Tritanium: 0, Pyerite: 0, Nocxium: 0, Isogen: 0, Zydrine: 0, Megacyte: 0, }); const skillEfficiency = { 0: 0.50, 1: 0.60, 2: 0.70, 3: 0.80, 4: 0.875, 5: 0.95 }; useEffect(() => { window.GDD.api.getPlayerInventory().then(i => { setInventory(i); if (i.length > 0) { setSelectedOre(i[0].item); setRefineQty(i[0].quantity); } }); window.GDD.api.getOrePrices().then(p => setOrePrices(p)); }, []); const addNotif = useCallback((msg, color) => { const id = Date.now(); setNotifications(prev => [...prev, { id, msg, color }]); setTimeout(() => setNotifications(prev => prev.filter(n => n.id !== id)), 3500); }, []); const handleRefine = useCallback(async () => { if (!selectedOre || refineQty <= 0) return; const data = mineralData[selectedOre]; if (!data) return; if (refineQty < data.batch) { addNotif(`Need at least ${data.batch} units for a batch.`, 'var(--red)'); return; } setRefining(true); const inv = inventory.find(i => i.item === selectedOre); const batches = Math.floor(refineQty / data.batch); const used = batches * data.batch; const eff = skillEfficiency[skillLevel]; const mineralYield = Math.floor(batches * data.yield * eff); const rawValue = used * (orePrices[selectedOre] || 0); const mineralValue = mineralYield * Math.floor((orePrices[selectedOre] || 0) * 2.5); // Simulate delay await new Promise(r => setTimeout(r, data.time * 10)); setPlayerMinerals(prev => ({ ...prev, [data.mineral]: prev[data.mineral] + mineralYield, })); setInventory(prev => prev.map(i => i.item === selectedOre ? { ...i, quantity: i.quantity - used } : i ).filter(i => i.quantity > 0)); setResults(prev => [{ ore: selectedOre, batches, used, mineral: data.mineral, yield: mineralYield, efficiency: eff, rawValue, mineralValue, better: mineralValue > rawValue, }, ...prev.slice(0, 9)]); setRefining(false); addNotif(`Refined ${used.toLocaleString()} ${selectedOre} → ${mineralYield.toLocaleString()} ${data.mineral} (${(eff * 100).toFixed(0)}% eff)`, 'var(--green)'); }, [selectedOre, refineQty, skillLevel, inventory, orePrices, addNotif]); const handleManufacture = useCallback((recipe) => { if (skillLevel < recipe.skill) { addNotif(`Need Industry level ${recipe.skill} to manufacture ${recipe.product}.`, 'var(--red)'); return; } // Check minerals for (const [mineral, qty] of Object.entries(recipe.minerals)) { if ((playerMinerals[mineral] || 0) < qty) { addNotif(`Not enough ${mineral}. Need ${qty}, have ${playerMinerals[mineral] || 0}.`, 'var(--red)'); return; } } // Deduct minerals setPlayerMinerals(prev => { const next = { ...prev }; for (const [mineral, qty] of Object.entries(recipe.minerals)) { next[mineral] -= qty; } return next; }); const job = { id: Date.now(), product: recipe.product, totalTime: recipe.time, remaining: recipe.time, started: Date.now(), }; setManufacturingJobs(prev => [...prev, job]); addNotif(`Manufacturing job started: ${recipe.product}. ETA: ${Math.floor(recipe.time / 60)}m ${recipe.time % 60}s`, 'var(--cyan)'); }, [skillLevel, playerMinerals, addNotif]); // Manufacturing timer useEffect(() => { const interval = setInterval(() => { setManufacturingJobs(prev => { const updated = prev.map(j => ({ ...j, remaining: Math.max(0, j.remaining - 1), })); const completed = updated.filter(j => j.remaining <= 0 && prev.find(p => p.id === j.id && p.remaining > 0)); completed.forEach(j => { addNotif(`Manufacturing complete: ${j.product}`, 'var(--green)'); }); return updated.filter(j => j.remaining > 0); }); }, 1000); return () => clearInterval(interval); }, [addNotif]); const formatTime = (s) => `${Math.floor(s / 60)}m ${String(s % 60).padStart(2, '0')}s`; return (
Refine raw ore into minerals, then use minerals to manufacture ships and modules. Industry skill level determines refining efficiency — higher skill means more minerals per batch.
{/* HUD-style industry strip */}| Ore | Batches | Mineral | Yield | Efficiency | Raw Value | Refined Value | Verdict |
|---|---|---|---|---|---|---|---|
| {r.ore} | {r.batches} | {r.mineral} | {r.yield.toLocaleString()} | {(r.efficiency * 100).toFixed(0)}% | ₢{r.rawValue.toLocaleString()} | ₢{r.mineralValue.toLocaleString()} | {r.better ? 'REFINE ▲' : 'SELL RAW ▼'} |