/* ============================================================================================== DTIM-ZEC MARS MISSION: COMPLETE MASTER CODE (DAMTP ACADEMIC STANDARD) Theoretical Framework : Discrete Topological Information Matrix (DTIM) Academic Target : DAMTP (Department of Applied Mathematics & Theoretical Physics) Version : 3.0.2 (Processing 4.5.6 Strict AST, HUD Layout & Alignment Fixes) Author : Jan Buehring License : MIT License / CC0 1.0 Universal Sequence: [Stage 0] : Crowdfunding & Algorithmic Spammer [Stage 1] : Werft & ZEC-Schiff Konstruktion [Stage 2] : Transit & Topologischer Flug [Stage 3] : Mars Terraforming (Atmosphere, Temperature, Water via Graph-Laplace) [Stage 4] : Base Building (Token Collection, Core, Shield, ISRU) [Stage 5] : Colonization (Population Management, Trade, Second Ship) ============================================================================================== */ import java.util.ArrayList; int stage = 0; // ================================================================= // STAGE 0 VARIABLES // ================================================================= float money = 0.0f; int contactsCount = 0; float viralMultiplier = 1.0f; int pythonBots = 0; float pythonPrice = 30.0f; int geminiAIs = 0; float geminiPrice = 150.0f; int recipientClass = 0; ArrayList stage0Logs; float clickPulse0 = 0.0f; // ================================================================= // STAGE 1 VARIABLES // ================================================================= int rawMaterials = 0; int researchers = 0; boolean part1Built = false, part2Built = false, part3Built = false, part4Built = false; ArrayList stage1Logs; // ================================================================= // STAGE 2 VARIABLES // ================================================================= float zeit = 0.0f; float starshipX = 140.0f, starshipY = 240.0f; float[] qX = new float[4]; float[] qY = new float[4]; float[] qSpeed = new float[4]; float[] sX = new float[3]; float[] sY = new float[3]; float[] sSpeed = new float[3]; float schockX = 0.0f, schockY = 0.0f, schockRadius = 0.0f, schockIntensitaet = 0.0f; int ladung = 0, score = 0, schild = 3; boolean gameOver = false, sieg = false; boolean kiGelernt = false, kiPopupOffen = false, bechzahlFeldAktiv = false, autoAim = false; // ================================================================= // STAGE 3 VARIABLES (Terraforming) // ================================================================= int zecEnergyWatts = 50; float marsPressure = 6.0f; float marsTemp = -63.0f; float marsWater = 0.5f; int dipolNodes = 0; int bechResonators = 0; int regolithExtractors = 0; boolean marsTerraformed = false; // ================================================================= // STAGE 4 & 5 VARIABLES (Base Building & Colonists) // ================================================================= float shipX = 0.0f, shipY = 0.0f; float velocityX = 0.0f, velocityY = 0.0f; float tlwEnergy = 70.0f, maxEnergy = 400.0f; ArrayList tokens; ArrayList particles; ArrayList fieldNodes; ArrayList projectiles; boolean colonistsArrived = false; float colonistCount = 0.0f, satisfaction = 80.0f, shipPoints = 0.0f; boolean inRebellion = false, hasSecondShip = false; float ship2X = 0.0f, ship2Y = 0.0f, ship2Vx = 0.0f, ship2Vy = 0.0f; float supplyTimer = 0.0f, drugSupply = 0.0f; int tradePolicy = 0; float solarRisk = 0.0f, meteorRisk = 0.0f; boolean isSolarFlare = false, isMeteor = false; boolean solarWarning = false, meteorWarning = false; int warningTimer = 0, flareTimer = 0; float meteorX, meteorY, meteorSize = 60.0f, meteorHP = 100.0f; String activePopupTitle = "", activePopupText = ""; boolean showPopup = false, pauseForWarning = false; boolean coreBought = false; boolean shieldBought = false, shieldOn = false; boolean defenseBought = false, defenseOn = false; boolean isruBought = false; boolean autoShieldBought = false, autoDefenseBought = false; boolean autoIsruBought = false, autoIsruActive = false; float greenLevel = 0.0f; float waterLevel = 0.0f; boolean balanceReached = false; boolean aiUnlocked = false, aiActive = false; int manualTokensCollected = 0; TLWToken ship1Target = null, ship2Target = null; PFont uiFont; // ================================================================= // SETUP // ================================================================= public void setup() { size(900, 680); uiFont = createFont("SansSerif", 12); textFont(uiFont); tokens = new ArrayList(); particles = new ArrayList(); fieldNodes = new ArrayList(); projectiles = new ArrayList(); stage0Logs = new ArrayList(); addStage0Log("SYSTEM: DTIM-ZEC Node V2.0 online."); addStage0Log("INFO: Starte Lokale Kontaktaufnahme..."); stage1Logs = new ArrayList(); addStage1Log("SYSTEM: DTIM-ZEC Werft-Terminal online."); initStage2(); initStage4(); } public void initStage2() { starshipX = 140.0f; starshipY = 240.0f; ladung = 0; score = 0; schild = 3; gameOver = false; sieg = false; kiGelernt = false; kiPopupOffen = false; bechzahlFeldAktiv = false; autoAim = false; for (int i = 0; i < 4; i++) { qX[i] = width + random(50.0f, 400.0f + i * 100.0f); qY[i] = random(80.0f, 420.0f); qSpeed[i] = random(1.0f, 1.5f); } for (int i = 0; i < 3; i++) { sX[i] = width + random(200.0f, 600.0f + i * 150.0f); sY[i] = random(80.0f, 420.0f); sSpeed[i] = random(1.2f, 1.8f); } } public void initStage4() { shipX = width / 2.0f; shipY = (height - 150.0f) / 2.0f; for (int i = 0; i < 7; i++) { tokens.add(new TLWToken(random(50.0f, width - 50.0f), random(50.0f, height - 180.0f))); } for (int x = 40; x < width; x += 70) { for (int y = 40; y < height - 160; y += 70) { fieldNodes.add(new TLWFieldNode((float)x, (float)y)); } } } public void draw() { background(6, 8, 15); if (stage == 0) { drawStage0_Spammer(); } else if (stage == 1) { drawStage1_Bau(); } else if (stage == 2) { drawStage2_Transit(); } else if (stage == 3) { drawStage3_Terraforming(); } else if (stage == 4) { drawStage4_BaseBuilding(); } else if (stage == 5) { drawStage5_Colonists(); } } // ================================================================= // STAGE 0: SPAMMER // ================================================================= void drawStage0_Spammer() { if (frameCount % 120 == 0 && pythonBots > 0) { contactsCount += pythonBots; } if (frameCount % 60 == 0) { if (geminiAIs > 0) { money += geminiAIs * 3.50f * viralMultiplier; } if (recipientClass == 0 && viralMultiplier > 1.0f) { contactsCount += (int)(viralMultiplier * 0.8f); } } fill(18, 24, 36); stroke(0, 180, 255, 80); strokeWeight(1.5f); rect(20, 20, width - 40, 70, 8); fill(0, 220, 255); textSize(13); textAlign(LEFT, CENTER); text("KONTOSTAND:", 40.0f, 45.0f); fill(0, 255, 150); textSize(20); text(nf(money, 1, 2) + " EUR", 145.0f, 44.0f); fill(0, 220, 255); textSize(13); text("REICHWEITE / KONTAKTE:", 300.0f, 45.0f); fill(255, 200, 0); textSize(18); text(contactsCount + " Adressen", 475.0f, 44.0f); float btnX = 40.0f, btnY = 110.0f, btnW = 380.0f, btnH = 150.0f; if (clickPulse0 > 0.0f) { clickPulse0 -= 0.1f; } fill(18, 28, 45); stroke(0, 200, 255, 150.0f + clickPulse0 * 100.0f); strokeWeight(2.0f + clickPulse0 * 2.0f); rect(btnX, btnY, btnW, btnH, 12); fill(0, 220, 255); textAlign(CENTER, CENTER); textSize(17); text("MAIL ABSENDEN", btnX + btnW / 2.0f, btnY + 45.0f); fill(200); textSize(11); text("(Klicken oder LEERTASTE)", btnX + btnW / 2.0f, btnY + 75.0f); fill(0, 255, 180); textSize(12); text("+1 bis 2 Adressen | Chance auf SPENDE!", btnX + btnW / 2.0f, btnY + 115.0f); fill(15, 20, 30); stroke(40, 50, 70); strokeWeight(1.0f); rect(40.0f, 280.0f, 380.0f, 140.0f, 8); fill(0, 180, 255); textSize(12); textAlign(LEFT, TOP); text("EMPFAENGER-KLASSE WAEHLEN:", 55.0f, 292.0f); drawClassBtn(55.0f, 315.0f, 350.0f, 28.0f, "1. Hilfseinrichtung (+Virales Marketing)", recipientClass == 0); drawClassBtn(55.0f, 348.0f, 350.0f, 28.0f, "2. Physik-Professoren (+Hohe Spenden)", recipientClass == 1); drawClassBtn(55.0f, 381.0f, 350.0f, 28.0f, "3. Science-Blogs & Presse (+Reichweite)", recipientClass == 2); float shopX = 440.0f, shopY = 110.0f, shopW = 620.0f; fill(15, 20, 30); stroke(40, 50, 70); rect(shopX, shopY, shopW, 310, 10); fill(0, 180, 255); textSize(14); textAlign(LEFT, TOP); text("AUTOMATISIERUNG", shopX + 20.0f, shopY + 15.0f); drawShopBtn(shopX + 20.0f, shopY + 45.0f, shopW - 40.0f, 75.0f, "Python Address-Scraper", "Sammelt langsam Adressen im Netz.", pythonPrice, "Aktiv: " + pythonBots, money >= pythonPrice); drawShopBtn(shopX + 20.0f, shopY + 130.0f, shopW - 40.0f, 75.0f, "Gemini Auto-Mail AI", "Verfasst Mails & erzeugt Spenden.", geminiPrice, "Aktiv: " + geminiAIs, money >= geminiPrice); if (contactsCount >= 100 || money >= 200.0f) { fill(0, 200, 120); rect(shopX + 20.0f, shopY + 220.0f, shopW - 40.0f, 70.0f, 8); fill(10); textSize(15); textAlign(CENTER, CENTER); text("DURCHBRUCH ERREICHT!\nWECHSEL ZUM RAUMSCHIFF-BAU (STAGE 1) ->", shopX + shopW / 2.0f, shopY + 255.0f); } fill(8, 12, 16); stroke(0, 180, 255, 60); rect(40.0f, 440.0f, 1020.0f, 280.0f, 8); fill(0, 180, 255); textSize(11); textAlign(LEFT, TOP); text("LIVE MAIL-LOGS", 55.0f, 450.0f); textSize(10); for (int i = 0; i < stage0Logs.size(); i++) { fill(120, 160, 180); text(stage0Logs.get(i), 55.0f, 474.0f + i * 19.0f); } } void addStage0Log(String txt) { stage0Logs.add("[" + nf(hour(),2) + ":" + nf(minute(),2) + "] " + txt); if (stage0Logs.size() > 12) { stage0Logs.remove(0); } } // ================================================================= // STAGE 1: BAUMODUS // ================================================================= void drawStage1_Bau() { if (frameCount % 90 == 0 && researchers > 0) { rawMaterials += researchers * 2; } fill(18, 24, 36); stroke(0, 180, 255, 80); strokeWeight(1.5f); rect(20.0f, 20.0f, width - 40.0f, 70.0f, 8); fill(0, 220, 255); textSize(13); textAlign(LEFT, CENTER); text("FORSCHER IM TEAM:", 40.0f, 45.0f); fill(0, 255, 150); textSize(20); text(researchers + " Mann", 185.0f, 44.0f); fill(0, 220, 255); textSize(13); text("ROHSTOFFE (TITAN / ZEC-KNOTEN):", 420.0f, 45.0f); fill(255, 200, 0); textSize(20); text(rawMaterials + " u", 665.0f, 44.0f); fill(18, 28, 45); stroke(0, 200, 255); rect(40.0f, 110.0f, 380.0f, 140.0f, 12); fill(0, 220, 255); textAlign(CENTER, CENTER); textSize(17); text("MAILS VERSCHICKEN", 230.0f, 150.0f); fill(0, 255, 180); textSize(12); text("Anwerben von Forschern & Rohstoffen", 230.0f, 215.0f); float x = 440.0f, y = 110.0f, w = 620.0f; fill(15, 20, 30); stroke(40, 50, 70); rect(x, y, w, 420.0f, 10); fill(0, 180, 255); textSize(14); textAlign(LEFT, TOP); text("SCHIFFSBAU-MONTAGERAUM (ZEC-1 ENDEAVOUR)", x + 20.0f, y + 15.0f); drawPartBtn(x + 20.0f, y + 45.0f, w - 40.0f, 75.0f, "1. ZEC-Quanten-Reaktor", "Liefert die 120°-Spannung für die Raumkrümmung.", 150, part1Built); drawPartBtn(x + 20.0f, y + 130.0f, w - 40.0f, 75.0f, "2. Hexagonales Waben-Chassis", "3D-Rumpf aus Graph-verstärktem Titan.", 350, part2Built); drawPartBtn(x + 20.0f, y + 215.0f, w - 40.0f, 75.0f, "3. Photonen-Laser & Schild", "Abwehr von Mikrometeoriten im Transit.", 600, part3Built); drawPartBtn(x + 20.0f, y + 300.0f, w - 40.0f, 75.0f, "4. KI-Navigations-Bruecke", "Berechnet die Adjazenzmatrix in Echtzeit.", 1000, part4Built); fill(8, 12, 16); stroke(0, 180, 255, 60); rect(40.0f, 540.0f, 1020.0f, 180.0f, 8); fill(0, 180, 255); textSize(11); textAlign(LEFT, TOP); text("WERFT-LOGBUCH", 55.0f, 548.0f); textSize(10); for (int i = 0; i < stage1Logs.size(); i++) { fill(120, 160, 180); text(stage1Logs.get(i), 55.0f, 568.0f + i * 16.0f); } if (part1Built && part2Built && part3Built && part4Built) { fill(0, 200, 120); rect(x + 20.0f, y + 360.0f, w - 40.0f, 50.0f, 8); fill(10); textSize(16); textAlign(CENTER, CENTER); text("ALLE MODULE MONTIERT! ZUENDUNG & TRANSIT (STAGE 2) ->", x + w / 2.0f, y + 385.0f); } } void addStage1Log(String txt) { stage1Logs.add("[" + nf(hour(),2) + ":" + nf(minute(),2) + "] " + txt); if (stage1Logs.size() > 9) { stage1Logs.remove(0); } } // ================================================================= // STAGE 2: TRANSIT FLUG // ================================================================= void drawStage2_Transit() { if (!kiPopupOffen && !gameOver && !sieg) { zeit += 0.02f; if (autoAim && kiGelernt) { float nearestY = starshipY; float minD = 9999.0f; for (int i = 0; i < 4; i++) { if (qX[i] > starshipX) { float d = dist(starshipX, starshipY, qX[i], qY[i]); if (d < minD) { minD = d; nearestY = qY[i]; } } } starshipY += (nearestY - starshipY) * 0.1f; } else { float mY = constrain(mouseY, 60.0f, 480.0f); starshipY += (mY - starshipY) * 0.2f; } if (schockIntensitaet > 0.0f) { schockRadius += 11.0f; schockIntensitaet -= 5.0f; } } float schiffSkalierung = 1.0f + (ladung / 100.0f) * 0.25f; float wurzelSpeed = 3.5f + sqrt((float)ladung) * 1.4f; int schritt = 32; float offsetGitter = (frameCount * 2.5f) % schritt; for (int x = -30; x <= width + 30; x += schritt) { for (int y = -30; y <= height - 230; y += schritt) { float drawX = x - offsetGitter; float dx = starshipX - drawX; float dy = starshipY - y; float abstand = sqrt(dx * dx + dy * dy); if (abstand == 0.0f) { abstand = 0.1f; } float kompression = 0.0f; if (abstand < 180.0f) { kompression = map(abstand, 0.0f, 180.0f, 22.0f * (ladung / 100.0f), 0.0f); } float posX = drawX + (dx / abstand) * kompression; float posY = y + (dy / abstand) * kompression; stroke(0, 180, 255, map(abstand, 0.0f, 400.0f, 35.0f, 8.0f)); strokeWeight(1.0f); noFill(); beginShape(); for (int i = 0; i < 6; i++) { vertex(posX + cos(PI / 3.0f * i + zeit * 0.01f) * 15.0f, posY + sin(PI / 3.0f * i + zeit * 0.01f) * 15.0f); } endShape(CLOSE); } } for (int i = 0; i < 4; i++) { if (!kiPopupOffen && !gameOver && !sieg) { qX[i] -= wurzelSpeed * qSpeed[i]; if (qX[i] < -30.0f) { qX[i] = width + random(50.0f, 300.0f); qY[i] = random(80.0f, 440.0f); } } stroke(0, 255, 180, 200); strokeWeight(1.5f); fill(8, 32, 38); ellipse(qX[i], qY[i], 18.0f, 18.0f); fill(255, 180); noStroke(); ellipse(qX[i], qY[i], 6.0f, 6.0f); if (dist(starshipX, starshipY, qX[i], qY[i]) < 36.0f * schiffSkalierung && !kiPopupOffen && !gameOver && !sieg) { schockX = qX[i]; schockY = qY[i]; schockRadius = 0.0f; schockIntensitaet = 255.0f; qX[i] = width + random(100.0f, 400.0f); score += 50; ladung = (int)constrain(ladung + 15, 0, 100); if (ladung >= 100) { sieg = true; } } } for (int i = 0; i < 3; i++) { if (!kiPopupOffen && !gameOver && !sieg) { sX[i] -= wurzelSpeed * sSpeed[i] * 1.05f; if (bechzahlFeldAktiv) { float dShip = dist(starshipX, starshipY, sX[i], sY[i]); if (dShip < 140.0f) { sY[i] += (sY[i] < starshipY) ? -4.5f : 4.5f; } } if (sX[i] < -30.0f) { sX[i] = width + random(100.0f, 400.0f); sY[i] = random(80.0f, 440.0f); } } stroke(255, 40, 40, 220); strokeWeight(2.0f); fill(30, 6, 12); ellipse(sX[i], sY[i], 22.0f, 22.0f); fill(255, 50, 50, 120.0f + sin(zeit * 20.0f) * 100.0f); noStroke(); ellipse(sX[i], sY[i], 10.0f, 10.0f); if (dist(starshipX, starshipY, sX[i], sY[i]) < 32.0f * schiffSkalierung && !kiPopupOffen && !gameOver && !sieg) { schild--; sX[i] = width + random(300.0f, 600.0f); if (schild == 1 && !kiGelernt) { kiGelernt = true; bechzahlFeldAktiv = true; autoAim = true; kiPopupOffen = true; } else if (schild <= 0) { gameOver = true; } } } pushMatrix(); translate(starshipX, starshipY); scale(schiffSkalierung); translate(-starshipX, -starshipY); drawStarshipTransit(starshipX, starshipY); popMatrix(); drawStage2_HUD(wurzelSpeed); if (gameOver) { fill(255, 50, 50); textAlign(CENTER, CENTER); textSize(24); text("GAME OVER\nHuellenkollaps im Vakuum!", width / 2.0f, height / 2.0f - 40.0f); } if (sieg) { fill(0, 255, 180); textSize(22); textAlign(CENTER, CENTER); text("MARS-ORBIT ERREICHT!\n(Klicke auf den Bildschirm fuer Stage 3)", width / 2.0f, height / 2.0f); } if (kiPopupOffen) { fill(10, 20, 35, 235); rect(150.0f, 180.0f, 550.0f, 260.0f, 8); fill(255, 150, 0); textSize(17); textAlign(CENTER, TOP); text("BECHZAHL-FELD GENERIERT!", width / 2.0f, 205.0f); fill(235); textSize(12); text("Die KI schuetzt das Schiff durch Erhitzen von Nano-Roehren im Schaumstoff.\nTruemmer werden reibungsfrei im Bogen abgewiesen!", width / 2.0f, 245.0f); fill(0, 200, 120); rect(width / 2.0f - 110.0f, 375.0f, 220.0f, 40.0f, 5); fill(255); text("AKTIVIEREN ->", width / 2.0f, 395.0f); } } void drawStage2_HUD(float akSpeed) { fill(12, 14, 22); rect(0.0f, 530.0f, width, 220.0f); stroke(35, 48, 68); line(0.0f, 530.0f, width, 530.0f); fill(255); textSize(12); textAlign(LEFT, TOP); text("SCHILD-STATUS:", 35.0f, 550.0f); for (int i = 0; i < 3; i++) { if (i < schild) { fill(0, 255, 150); } else { fill(50, 20, 20); } stroke(0); rect(140.0f + i * 45.0f, 548.0f, 40.0f, 18.0f, 4); } fill(0, 255, 150); text((schild * 33) + "%", 280.0f, 550.0f); fill(255); text("BATTERIE-LADUNG:", 380.0f, 550.0f); fill(40, 50, 65); rect(510.0f, 548.0f, 200.0f, 18.0f, 4); fill(0, 220, 255); rect(510.0f, 548.0f, map(ladung, 0.0f, 100.0f, 0.0f, 200.0f), 18.0f, 4); fill(255); text(ladung + "%", 720.0f, 550.0f); fill(130, 150, 170); textSize(11); text("TLW-Gleichung: v_gitter = 3.5 + sqrt(" + ladung + ") * 1.4 = " + nf(akSpeed, 1, 2) + " L_t", 35.0f, 585.0f); fill(0, 220, 255); text("Steuerung: Bewege die Maus nach oben/unten!", 510.0f, 585.0f); } void drawStarshipTransit(float cx, float cy) { if (bechzahlFeldAktiv) { noFill(); stroke(255, 150, 0, 180.0f + sin(zeit * 30.0f) * 70.0f); strokeWeight(3.0f); arc(cx + 80.0f, cy, 160.0f, 120.0f, -HALF_PI * 0.8f, HALF_PI * 0.8f); } stroke(0, 255, 200, 180.0f + ladung); strokeWeight(2.5f); fill(18, 28, 45); ellipse(cx - 30.0f, cy, 18.0f, 55.0f); if (ladung > 0) { fill(0, 255, 180, 100.0f + sin(zeit * 25.0f) * 80.0f); noStroke(); ellipse(cx - 30.0f, cy, 8.0f, 30.0f); } fill(235, 240, 250); stroke(30, 40, 55); strokeWeight(1.5f); beginShape(); vertex(cx - 35.0f, cy - 10.0f); vertex(cx + 40.0f, cy - 8.0f); vertex(cx + 110.0f, cy); vertex(cx + 40.0f, cy + 8.0f); vertex(cx - 35.0f, cy + 10.0f); vertex(cx - 20.0f, cy); endShape(CLOSE); fill(70, 80, 95); stroke(30, 40, 55); rect(cx - 15.0f, cy - 16.0f, 25.0f, 4.0f); rect(cx - 15.0f, cy + 12.0f, 25.0f, 4.0f); } // ================================================================= // STAGE 3: MARS TERRAFORMING (JUST PLANET AND KW UPGRADES) // ================================================================= void drawStage3_Terraforming() { if (frameCount % 60 == 0 && !marsTerraformed) { if (dipolNodes > 0) { marsPressure = min(600.0f, marsPressure + dipolNodes * 1.2f); } if (bechResonators > 0 && marsPressure > 50.0f) { marsTemp = min(15.0f, marsTemp + bechResonators * 0.4f); } if (regolithExtractors > 0 && marsTemp > -10.0f) { marsWater = min(35.0f, marsWater + regolithExtractors * 0.3f); } zecEnergyWatts += 5 + dipolNodes * 2 + bechResonators * 3; if (marsPressure >= 500.0f && marsTemp >= 10.0f && marsWater >= 25.0f) { marsTerraformed = true; } } fill(map(marsWater, 0.5f, 35.0f, 180.0f, 40.0f), map(marsWater, 0.5f, 35.0f, 60.0f, 140.0f), map(marsWater, 0.5f, 35.0f, 40.0f, 200.0f)); noStroke(); ellipse(240.0f, 280.0f, 320.0f, 320.0f); if (dipolNodes > 0) { noFill(); stroke(0, 220, 255, 120); strokeWeight(2.0f); ellipse(240.0f, 280.0f, 360.0f, 360.0f); } float shopX = 460.0f, shopY = 40.0f, shopW = 420.0f; fill(15, 20, 30); stroke(40, 50, 70); rect(shopX, shopY, shopW, 600.0f, 10); fill(0, 180, 255); textSize(16); textAlign(LEFT, TOP); text("TERRAFORMING KONTROLLZENTRUM", shopX + 20.0f, shopY + 20.0f); fill(255); textSize(12); text("Atmosphaerendruck: " + nf(marsPressure, 1, 1) + " mbar / 600 mbar", shopX + 20.0f, shopY + 55.0f); text("Durchschnitts-Temp: " + nf(marsTemp, 1, 1) + " C / +15 C", shopX + 20.0f, shopY + 75.0f); text("Oberflaechen-Wasser: " + nf(marsWater, 1, 1) + " % / 35 %", shopX + 20.0f, shopY + 95.0f); text("ZEC-Energie: " + zecEnergyWatts + " kW (Druecke LEERTASTE)", shopX + 20.0f, shopY + 115.0f); drawMarsTechBtn(shopX + 20.0f, shopY + 150.0f, shopW - 40.0f, 80.0f, "1. Dipol-ZEC-Knoten", "Schuetzt Atmosphaere", 100, "Aktiv: " + dipolNodes, zecEnergyWatts >= 100); drawMarsTechBtn(shopX + 20.0f, shopY + 245.0f, shopW - 40.0f, 80.0f, "2. Bechzahl-Resonator", "Verdampft Pole", 250, "Aktiv: " + bechResonators, zecEnergyWatts >= 250 && marsPressure > 30.0f); drawMarsTechBtn(shopX + 20.0f, shopY + 340.0f, shopW - 40.0f, 80.0f, "3. Regolith Synthese", "Fluessiges Wasser", 500, "Aktiv: " + regolithExtractors, zecEnergyWatts >= 500 && marsTemp > -15.0f); fill(8, 12, 16); stroke(0, 180, 255, 60); rect(shopX + 20.0f, shopY + 440.0f, shopW - 40.0f, 140.0f, 8); fill(0, 255, 180); textSize(12); textAlign(LEFT, TOP); text("PLANETARER STATUS:", shopX + 35.0f, shopY + 455.0f); fill(220); textSize(11); if (marsTerraformed) { fill(0, 255, 150); textSize(13); text("VICTORY! DER MARS IST TERRAFORMIERT!", shopX + 35.0f, shopY + 480.0f); fill(0, 200, 120); rect(shopX + 20.0f, shopY + 530.0f, shopW - 40.0f, 50.0f, 8); fill(10); textSize(16); textAlign(CENTER, CENTER); text("WEITER ZU STAGE 4: BASISBAU ->", shopX + shopW / 2.0f, shopY + 555.0f); } else { text("• Baue Dipol-Knoten fuer Atmosphaere.\n" + "• Bechzahl-Resonatoren heizen.\n" + "• Regolith-Synthese macht Ozeane.", shopX + 35.0f, shopY + 485.0f); } } // ================================================================= // STAGE 4: BASE BUILDING (SHIP COLLECTS ENERGY) // ================================================================= void drawStage4_BaseBuilding() { drawTLWSpaceBackground(); for (int i = 0; i < tokens.size(); i++) { tokens.get(i).display(); } if (!pauseForWarning) { updateAITargets(); updateShipMovement(); manageTokens(); updateEvents(); } updateParticles(); drawShip(shipX, shipY); drawAlarms(); drawHUD(4); drawStoryPopup(); if (isruBought) { fill(0, 255, 150); rect(width / 2.0f - 150.0f, 250.0f, 300.0f, 50.0f, 8); fill(10); textSize(16); textAlign(CENTER, CENTER); text("WEITER ZU STAGE 5: KOLONISTEN ->", width / 2.0f, 275.0f); } } // ================================================================= // STAGE 5: COLONISTS // ================================================================= void drawStage5_Colonists() { drawTLWSpaceBackground(); for (int i = 0; i < tokens.size(); i++) { tokens.get(i).display(); } if (!pauseForWarning && !balanceReached) { updateAITargets(); updateShipMovement(); updateSecondShip(); manageTokens(); updateGaiaSystem(); updateEvents(); updateColonistsAndSupply(); } updateParticles(); if (!balanceReached) { drawShip(shipX, shipY); drawSecondShip(); } else { shipX = lerp(shipX, width / 2.0f - 30.0f, 0.05f); shipY = lerp(shipY, height / 2.0f - 50.0f, 0.05f); ship2X = lerp(ship2X, width / 2.0f + 30.0f, 0.05f); ship2Y = lerp(ship2Y, height / 2.0f - 50.0f, 0.05f); drawShip(shipX, shipY); if (hasSecondShip) { drawSecondShip(); } } drawAlarms(); drawHUD(5); drawStoryPopup(); } // ================================================================= // INTERNAL LOGIC UPDATES (STAGES 4 & 5) // ================================================================= void updateAITargets() { ship1Target = null; ship2Target = null; if (aiActive && tokens.size() > 0) { float minDist = 9999.0f; for (int i = 0; i < tokens.size(); i++) { TLWToken t = tokens.get(i); float d = dist(shipX, shipY, t.x, t.y); if (d < minDist) { minDist = d; ship1Target = t; } } } if (hasSecondShip && colonistCount >= 50.0f && tokens.size() > 0) { float minDist = 9999.0f; for (int i = 0; i < tokens.size(); i++) { TLWToken t = tokens.get(i); if (ship1Target != null && t == ship1Target && tokens.size() > 1) { continue; } float d = dist(ship2X, ship2Y, t.x, t.y); if (d < minDist) { minDist = d; ship2Target = t; } } } } void updateShipMovement() { float targetX = mouseX; float targetY = mouseY; if (aiActive && ship1Target != null) { targetX = ship1Target.x; targetY = ship1Target.y; } boolean isMoving = false; if (aiActive && dist(shipX, shipY, targetX, targetY) > 10.0f) { isMoving = true; } if (!aiActive && mousePressed && mouseY < height - 150.0f) { isMoving = true; } if (isMoving && tlwEnergy > 0.2f) { velocityX += (targetX - shipX) * 0.006f; velocityY += (targetY - shipY) * 0.006f; tlwEnergy -= 0.05f; if (frameCount % 2 == 0) { particles.add(new Particle(shipX, shipY, -velocityX * 0.6f + random(-0.5f, 0.5f), -velocityY * 0.6f + random(-0.5f, 0.5f), color(0, 200, 255), 1)); } } velocityX *= 0.94f; velocityY *= 0.94f; shipX = constrain(shipX + velocityX, 30.0f, width - 30.0f); shipY = constrain(shipY + velocityY, 30.0f, height - 160.0f); } void updateSecondShip() { if (hasSecondShip && colonistCount >= 50.0f && ship2Target != null) { ship2Vx += (ship2Target.x - ship2X) * 0.004f; ship2Vy += (ship2Target.y - ship2Y) * 0.004f; ship2Vx *= 0.92f; ship2Vy *= 0.92f; ship2X = constrain(ship2X + ship2Vx, 30.0f, width - 30.0f); ship2Y = constrain(ship2Y + ship2Vy, 30.0f, height - 160.0f); if (frameCount % 3 == 0) { particles.add(new Particle(ship2X, ship2Y, -ship2Vx * 0.5f, -ship2Vy * 0.5f, color(0, 255, 150), 1)); } } } void manageTokens() { int spawned = 0; for (int i = tokens.size() - 1; i >= 0; i--) { TLWToken t = tokens.get(i); boolean collected = false; if (dist(shipX, shipY, t.x, t.y) < 25.0f) { collected = true; } if (hasSecondShip && colonistCount >= 50.0f && dist(ship2X, ship2Y, t.x, t.y) < 25.0f) { collected = true; } if (collected) { tlwEnergy = min(maxEnergy, tlwEnergy + 15.0f); int pc = color(0, 255, 220); for(int k = 0; k < 5; k++) { particles.add(new Particle(t.x, t.y, random(-3.0f, 3.0f), random(-3.0f, 3.0f), pc, 2)); } tokens.remove(i); spawned++; if (!aiUnlocked) { manualTokensCollected++; if (manualTokensCollected >= 5) { aiUnlocked = true; triggerStory("KI BEREIT", "KI-Sammler online. Die Schiffs-KI hilft nun beim Sammeln."); } } } } for (int i = 0; i < spawned; i++) { tokens.add(new TLWToken(random(50.0f, width - 50.0f), random(50.0f, height - 180.0f))); } } void updateGaiaSystem() { if (autoIsruBought && autoIsruActive) { if (waterLevel < 50.0f && shipPoints >= 20.0f) { shipPoints -= 20.0f; waterLevel += 12.0f; } if (greenLevel < 50.0f && shipPoints >= 30.0f) { shipPoints -= 30.0f; greenLevel += 12.0f; } } float energyDrain = 0.0f; if (isruBought && greenLevel > 0.0f) { energyDrain += (greenLevel * 0.008f); } if (isruBought && waterLevel > 0.0f) { energyDrain += (waterLevel * 0.005f); } if (shieldOn) { energyDrain += 0.15f; } if (defenseOn) { energyDrain += 0.15f; } if (tlwEnergy >= energyDrain) { tlwEnergy -= energyDrain; } else { tlwEnergy = 0.0f; shieldOn = false; defenseOn = false; if (greenLevel > 0.0f) { greenLevel -= 0.03f; } if (waterLevel > 0.0f) { waterLevel -= 0.03f; } } if (greenLevel >= 100.0f && waterLevel >= 100.0f && !balanceReached) { balanceReached = true; greenLevel = 100.0f; waterLevel = 100.0f; triggerStory("TOPOLOGISCHE BALANCE", "Sieg! Der Planet traegt sich von selbst."); } } void updateColonistsAndSupply() { if (isruBought && !colonistsArrived) { supplyTimer += 0.04f; if (supplyTimer >= 100.0f) { colonistsArrived = true; colonistCount = 10.0f; supplyTimer = 0.0f; triggerStory("KOLONISTEN", "Die Siedler sind gelandet! Versorgungsschiffe folgen."); } } if (colonistsArrived) { supplyTimer += 0.05f; if (supplyTimer >= 100.0f) { supplyTimer = 0.0f; colonistCount += 5.0f; if (tradePolicy == 0) { satisfaction = min(100.0f, satisfaction + 15.0f); } else { drugSupply += 100.0f; } } float demand = 0.015f + (colonistCount * 0.0005f); boolean waterOk = false, greenOk = false; if (waterLevel >= demand) { waterLevel -= demand; waterOk = true; } else { waterLevel = 0.0f; } if (greenLevel >= demand) { greenLevel -= demand; greenOk = true; } else { greenLevel = 0.0f; } if (waterOk && greenOk) { if (tradePolicy == 1) { if (drugSupply > 0.0f) { drugSupply -= (0.05f + colonistCount * 0.001f); satisfaction = min(100.0f, satisfaction + 0.08f); } else { satisfaction = max(0.0f, satisfaction - 0.15f); } } else { satisfaction = min(100.0f, satisfaction + 0.03f); } if (satisfaction > 60.0f) { colonistCount += 0.03f; } } else { satisfaction = max(0.0f, satisfaction - 0.1f); if (satisfaction < 30.0f && colonistCount > 0.0f) { colonistCount -= 0.02f; } } if (!inRebellion) { shipPoints += colonistCount * 0.01f; } if (satisfaction <= 15.0f && !inRebellion) { inRebellion = true; aiActive = false; triggerStory("AUFSTAND", "Die Kolonisten hungern! KI sabotiert."); } else if (satisfaction > 35.0f && inRebellion) { inRebellion = false; } if (inRebellion) { aiActive = false; if (frameCount % 10 == 0 && tlwEnergy > 0.0f) { tlwEnergy -= 1.0f; } } } } void updateEvents() { if (coreBought && !isSolarFlare && !solarWarning) { solarRisk += 0.03f; } if (coreBought && !isMeteor && !meteorWarning) { meteorRisk += 0.02f; } if (solarRisk > 100.0f && !solarWarning && !isSolarFlare) { solarWarning = true; warningTimer = 180; if (autoShieldBought && !shieldOn) { shieldOn = true; } } if (solarWarning) { warningTimer--; if (warningTimer <= 0) { solarWarning = false; isSolarFlare = true; flareTimer = 300; solarRisk = 0.0f; } } if (meteorRisk > 100.0f && !meteorWarning && !isMeteor) { meteorWarning = true; warningTimer = 180; if (autoDefenseBought && !defenseOn) { defenseOn = true; } } if (meteorWarning) { warningTimer--; if (warningTimer <= 0) { meteorWarning = false; isMeteor = true; meteorRisk = 0.0f; meteorX = random(100.0f, width - 100.0f); meteorY = -50.0f; meteorHP = 100.0f; } } if (isSolarFlare) { flareTimer--; if (!shieldOn && frameCount % 5 == 0) { if (tlwEnergy > 0.0f) { tlwEnergy -= 2.0f; } else { if (greenLevel > 0.0f) { greenLevel -= 0.5f; } if (waterLevel > 0.0f) { waterLevel -= 0.5f; } } } if (flareTimer <= 0) { isSolarFlare = false; } } if (isMeteor) { meteorY += 0.8f; meteorX += sin(frameCount * 0.05f) * 0.5f; if (defenseOn && frameCount % 12 == 0 && tlwEnergy >= 1.5f) { tlwEnergy -= 1.5f; projectiles.add(new Projectile(shipX, shipY, meteorX, meteorY)); } for (int i = projectiles.size() - 1; i >= 0; i--) { Projectile p = projectiles.get(i); p.update(); p.display(); if (dist(p.x, p.y, meteorX, meteorY) < meteorSize / 2.0f) { meteorHP -= 25.0f; projectiles.remove(i); int pc = color(0, 255, 220); for(int k = 0; k < 5; k++) { particles.add(new Particle(p.x, p.y, random(-2.0f, 2.0f), random(-2.0f, 2.0f), pc, 2)); } } else if (p.isOffScreen()) { projectiles.remove(i); } } fill(180, 60, 40); stroke(255, 120, 50); strokeWeight(2.0f); ellipse(meteorX, meteorY, meteorSize, meteorSize); fill(40); noStroke(); rect(meteorX - 40.0f, meteorY - 45.0f, 80.0f, 6.0f, 2.0f); fill(255, 50, 50); rect(meteorX - 40.0f, meteorY - 45.0f, map(meteorHP, 0.0f, 100.0f, 0.0f, 80.0f), 6.0f, 2.0f); if (meteorHP <= 0.0f) { isMeteor = false; } if (meteorY > height - 130.0f) { isMeteor = false; if (greenLevel > 20.0f) { greenLevel -= 20.0f; } else { greenLevel = 0.0f; } if (waterLevel > 20.0f) { waterLevel -= 20.0f; } else { waterLevel = 0.0f; } int ec = color(255, 100, 50); for(int k = 0; k < 20; k++) { particles.add(new Particle(meteorX, meteorY, random(-5.0f, 5.0f), random(-5.0f, 5.0f), ec, 2)); } } } } // ================================================================= // HELPER RENDERERS // ================================================================= void drawTLWSpaceBackground() { for (int i = 0; i < fieldNodes.size(); i++) { TLWFieldNode node = fieldNodes.get(i); float sx2 = shipX; float sy2 = shipY; if (hasSecondShip) { sx2 = ship2X; sy2 = ship2Y; } node.updateAndDisplay(shipX, shipY, sx2, sy2); } boolean flash = false; if (isSolarFlare) { flash = true; } if (solarWarning && frameCount % 10 < 5) { flash = true; } if (flash) { fill(255, 120, 0, 40); rect(0.0f, 0.0f, width, height - 150.0f); } fill(120, 45, 25); noStroke(); rect(0.0f, height - 150.0f, width, 150.0f); fill(190, 75, 40); rect(0.0f, height - 158.0f, width, 8.0f); if (waterLevel > 0.0f) { fill(50, 150, 255, map(waterLevel, 0.0f, 100.0f, 0.0f, 120.0f)); rect(0.0f, height - 150.0f, width, 150.0f); } if (greenLevel > 0.0f) { float alphaGreen = map(greenLevel, 0.0f, 100.0f, 0.0f, 255.0f); fill(30, 150, 50, alphaGreen); rect(0.0f, height - 150.0f, width, 150.0f); fill(50, 200, 70, alphaGreen); rect(0.0f, height - 158.0f, width, 8.0f); } if (shieldOn) { noFill(); stroke(0, 200, 255, 100); strokeWeight(3.0f); arc(width / 2.0f, height - 150.0f, width, 250.0f, PI, TWO_PI); } } void drawAlarms() { boolean showAlarm = false; if (solarWarning || meteorWarning) { if (frameCount % 20 < 10) { showAlarm = true; } } if (showAlarm) { fill(255, 50, 50); textSize(24); textAlign(CENTER, CENTER); text("NOTFALL ALARM!", width / 2.0f, height / 2.0f - 100.0f); } } void updateParticles() { for (int i = particles.size() - 1; i >= 0; i--) { Particle p = particles.get(i); p.update(); p.display(); if (p.isDead()) { particles.remove(i); } } } void drawShip(float cx, float cy) { pushMatrix(); translate(cx, cy); rotate(atan2(velocityY, velocityX) + HALF_PI); fill(0, 200, 255); stroke(255); strokeWeight(1.5f); triangle(0.0f, -18.0f, -12.0f, 16.0f, 12.0f, 16.0f); fill(255, 100, 255); ellipse(0.0f, 2.0f, 6.0f, 6.0f); popMatrix(); } void drawSecondShip() { if (hasSecondShip) { pushMatrix(); translate(ship2X, ship2Y); if (colonistCount >= 50.0f) { rotate(frameCount * 0.08f); stroke(0, 255, 150); } else { rotate(frameCount * 0.01f); stroke(150, 50, 50); } noFill(); strokeWeight(1.5f); for(int i = 0; i < 3; i++) { rotate(TWO_PI / 3.0f); triangle(0.0f, -12.0f, -10.0f, 10.0f, 10.0f, 10.0f); pushMatrix(); scale(0.5f); rotate(-frameCount * 0.15f); triangle(0.0f, -12.0f, -10.0f, 10.0f, 10.0f, 10.0f); popMatrix(); } popMatrix(); } } void drawMarsTechBtn(float x, float y, float w, float h, String title, String desc, int cost, String status, boolean canAfford) { if (canAfford) { fill(24, 36, 52); stroke(0, 180, 255); } else { fill(16, 20, 28); stroke(40, 45, 55); } rect(x, y, w, h, 6); fill(255); textSize(13); textAlign(LEFT, TOP); text(title, x + 15.0f, y + 10.0f); fill(160); textSize(10); text(desc, x + 15.0f, y + 30.0f); fill(255, 200, 0); textSize(12); text("Kosten: " + cost + " kW", x + 15.0f, y + 52.0f); fill(0, 200, 255); textAlign(RIGHT, TOP); textSize(11); text(status, x + w - 15.0f, y + 10.0f); } void drawClassBtn(float x, float y, float w, float h, String label, boolean active) { if (active) { fill(0, 150, 220); } else { fill(22, 30, 42); } stroke(40, 50, 60); rect(x, y, w, h, 4); fill(255); textSize(11); textAlign(LEFT, CENTER); text(label, x + 10.0f, y + h / 2.0f); } void drawShopBtn(float x, float y, float w, float h, String title, String desc, float price, String status, boolean canAfford) { if (canAfford) { fill(24, 36, 52); stroke(0, 180, 255); } else { fill(16, 20, 28); stroke(40, 45, 55); } rect(x, y, w, h, 8); fill(255); textSize(13); textAlign(LEFT, TOP); text(title, x + 15.0f, y + 10.0f); fill(160); textSize(10); text(desc, x + 15.0f, y + 28.0f); fill(0, 255, 150); textSize(12); text("Preis: " + nf(price, 1, 2) + " EUR", x + 15.0f, y + 48.0f); fill(0, 200, 255); textAlign(RIGHT, TOP); textSize(11); text(status, x + w - 15.0f, y + 10.0f); } void drawPartBtn(float x, float y, float w, float h, String title, String desc, int cost, boolean built) { if (built) { fill(0, 180, 100, 40); stroke(0, 255, 150); } else if (rawMaterials >= cost) { fill(24, 36, 52); stroke(0, 180, 255); } else { fill(16, 20, 28); stroke(0, 180, 255); } rect(x, y, w, h, 6); fill(255); textSize(13); textAlign(LEFT, TOP); text(title, x + 15.0f, y + 10.0f); fill(160); textSize(11); text(desc, x + 15.0f, y + 32.0f); if (built) { fill(0, 255, 180); text("MONTIERT", x + 15.0f, y + 54.0f); } else { fill(255, 200, 0); text("Kosten: " + cost + " Rohstoffe", x + 15.0f, y + 54.0f); } } void drawHUD(int currentDrawStage) { fill(15, 20, 35, 240); stroke(60, 110, 190); strokeWeight(2.0f); rect(10.0f, 10.0f, width - 20.0f, 140.0f, 8); fill(40); noStroke(); rect(20.0f, 20.0f, 150.0f, 18.0f, 4); fill(255, 0, 200); rect(20.0f, 20.0f, map(tlwEnergy, 0.0f, maxEnergy, 0.0f, 150.0f), 18.0f, 4); fill(255); textSize(11); textAlign(LEFT, CENTER); text("ENERGIE: " + (int)tlwEnergy + " / " + (int)maxEnergy, 25.0f, 29.0f); textAlign(CENTER, CENTER); if (aiUnlocked) { if (aiActive) { fill(0, 255, 100); } else if (inRebellion) { fill(255, 50, 50); } else { fill(80); } rect(180.0f, 16.0f, 100.0f, 22.0f, 4); fill(0); textSize(10); if (inRebellion) { text("KI SABOTIERT", 230.0f, 27.0f); } else if (aiActive) { text("KI: AN", 230.0f, 27.0f); } else { text("KI: AUS", 230.0f, 27.0f); } } else { fill(150); textSize(10); textAlign(LEFT, CENTER); text("KI lernt (" + manualTokensCollected + "/5)", 180.0f, 27.0f); textAlign(CENTER, CENTER); } if (currentDrawStage == 5) { if (isruBought) { if (!colonistsArrived) { fill(255, 200, 0); textSize(11); textAlign(LEFT, CENTER); text("KOLONISTEN ANKUNFT: " + (int)supplyTimer + "%", 300.0f, 27.0f); textAlign(CENTER, CENTER); } else { if (inRebellion) { fill(255, 50, 50); } else { fill(0, 255, 150); } textSize(11); textAlign(LEFT, CENTER); text("POP: " + (int)colonistCount + " | ZUF: " + (int)satisfaction + "% | SP: " + (int)shipPoints, 300.0f, 27.0f); textAlign(CENTER, CENTER); if (!hasSecondShip) { if (shipPoints >= 500.0f && colonistCount >= 50.0f) { fill(0, 255, 150); } else { fill(80); } rect(475.0f, 16.0f, 170.0f, 22.0f, 4); fill(0); textSize(10); text("FRAKTAL KAUFEN (500 SP)", 560.0f, 27.0f); } else { if (colonistCount >= 50.0f) { fill(0, 255, 150); } else { fill(255, 80, 80); } rect(475.0f, 16.0f, 170.0f, 22.0f, 4); fill(0); textSize(10); if (colonistCount >= 50.0f) { text("FRAKTAL: AKTIV", 560.0f, 27.0f); } else { text("FRAKTAL: ZU WENIG CREW", 560.0f, 27.0f); } } } } } else { fill(100); textSize(11); textAlign(LEFT, CENTER); text("KOLONISTEN: GESPERRT (ERST BASISBAU)", 300.0f, 27.0f); textAlign(CENTER, CENTER); } fill(200, 220, 255); textSize(11); textAlign(LEFT, CENTER); text("BASIS:", 20.0f, 56.0f); textAlign(CENTER, CENTER); if (coreBought) { fill(0, 255, 100); } else { fill(80); } rect(65.0f, 45.0f, 80.0f, 22.0f, 4); fill(0); textSize(10); text(coreBought ? "Kern: OK" : "Kern (50E)", 105.0f, 56.0f); boolean sEm = (solarWarning || isSolarFlare); if (!shieldBought) { fill(80); } else if (shieldOn) { fill(0, 200, 255); } else { fill(100); } rect(155.0f, 45.0f, 100.0f, 22.0f, 4); if (shieldOn) { fill(0); } else if (sEm && shieldBought) { fill(255, 100, 100); } else { fill(255); } if (shieldBought) { text(shieldOn ? "Schild: AN" : (sEm ? "Schild (30E!)" : "Schild: AUS"), 205.0f, 56.0f); } else { text("Schild (70E)", 205.0f, 56.0f); } boolean mEm = (meteorWarning || isMeteor); if (!defenseBought) { fill(80); } else if (defenseOn) { fill(0, 200, 255); } else { fill(100); } rect(265.0f, 45.0f, 100.0f, 22.0f, 4); if (defenseOn) { fill(0); } else if (mEm && defenseBought) { fill(255, 100, 100); } else { fill(255); } if (defenseBought) { text(defenseOn ? "Abwehr: AN" : (mEm ? "Abwehr (30E!)" : "Abwehr: AUS"), 315.0f, 56.0f); } else { text("Abwehr (80E)", 315.0f, 56.0f); } if (isruBought) { fill(0, 255, 100); } else { fill(80); } rect(375.0f, 45.0f, 90.0f, 22.0f, 4); fill(0); text(isruBought ? "ISRU: OK" : "ISRU (90E)", 420.0f, 56.0f); if (isruBought) { if (autoShieldBought) { fill(200, 100, 255); } else { fill(60); } rect(475.0f, 45.0f, 150.0f, 22.0f, 4); fill(255); text(autoShieldBought ? "AUTO-SCHILD: OK" : "Auto-Schild (200 SP)", 550.0f, 56.0f); if (autoDefenseBought) { fill(200, 100, 255); } else { fill(60); } rect(635.0f, 45.0f, 150.0f, 22.0f, 4); fill(255); text(autoDefenseBought ? "AUTO-ABWEHR: OK" : "Auto-Abwehr (200 SP)", 710.0f, 56.0f); } if (isruBought) { fill(200, 220, 255); textSize(11); textAlign(LEFT, CENTER); text("PROD:", 20.0f, 86.0f); textAlign(CENTER, CENTER); fill(50, 150, 255); rect(65.0f, 75.0f, 90.0f, 22.0f, 4); fill(255); text("WASSER (15E)", 110.0f, 86.0f); fill(0); rect(160.0f, 78.0f, 40.0f, 16.0f, 2); fill(50, 200, 255); rect(160.0f, 78.0f, map(waterLevel, 0.0f, 100.0f, 0.0f, 40.0f), 16.0f, 2); fill(255); textAlign(LEFT, CENTER); text((int)waterLevel + "%", 205.0f, 86.0f); textAlign(CENTER, CENTER); fill(40, 180, 60); rect(250.0f, 75.0f, 90.0f, 22.0f, 4); fill(255); text("FLORA (20E)", 295.0f, 86.0f); fill(0); rect(345.0f, 78.0f, 40.0f, 16.0f, 2); fill(0, 255, 100); rect(345.0f, 78.0f, map(greenLevel, 0.0f, 100.0f, 0.0f, 40.0f), 16.0f, 2); fill(255); textAlign(LEFT, CENTER); text((int)greenLevel + "%", 390.0f, 86.0f); textAlign(CENTER, CENTER); if (!autoIsruBought) { fill(60); } else if (autoIsruActive) { fill(200, 100, 255); } else { fill(100); } rect(475.0f, 75.0f, 150.0f, 22.0f, 4); fill(255); if (autoIsruBought) { text(autoIsruActive ? "AUTO-ISRU: AN (-SP)" : "AUTO-ISRU: AUS", 550.0f, 86.0f); } else { text("Auto-ISRU (150 SP)", 550.0f, 86.0f); } if (greenLevel >= 10.0f) { fill(180, 50, 50); rect(635.0f, 75.0f, 150.0f, 22.0f, 4); fill(255); text("Notverkauf -10% Flora", 710.0f, 86.0f); } } if (currentDrawStage == 5 && colonistsArrived) { fill(200, 220, 255); textSize(11); textAlign(LEFT, CENTER); text("VERSORGUNG IN: " + (int)supplyTimer + "%", 20.0f, 116.0f); textAlign(CENTER, CENTER); if (tradePolicy == 0) { fill(0, 255, 150); } else { fill(255, 80, 80); } rect(180.0f, 105.0f, 180.0f, 22.0f, 4); fill(0); textSize(10); text(tradePolicy == 0 ? "LEGAL (Tech/Med)" : "SCHWARZMARKT (Drogen)", 270.0f, 116.0f); if (tradePolicy == 1) { fill(255, 100, 200); textAlign(LEFT, CENTER); text("DROGEN: " + (int)drugSupply, 370.0f, 116.0f); textAlign(CENTER, CENTER); } fill(200, 180, 50); rect(475.0f, 105.0f, 150.0f, 22.0f, 4); fill(0); text("EXPRESS KOLONIST (100)", 550.0f, 116.0f); fill(200, 180, 50); rect(635.0f, 105.0f, 150.0f, 22.0f, 4); fill(0); text("EXPRESS FRACHT (100)", 710.0f, 116.0f); } textAlign(RIGHT, TOP); textSize(11); if (solarRisk > 75.0f) { fill(255, 100, 100); } else { fill(200, 220, 255); } text("SONNEN-GEFAHR: " + (int)min(100.0f, solarRisk) + "%", width - 25.0f, 25.0f); if (meteorRisk > 75.0f) { fill(255, 100, 100); } else { fill(200, 220, 255); } text("METEOR-GEFAHR: " + (int)min(100.0f, meteorRisk) + "%", width - 25.0f, 45.0f); textAlign(LEFT, TOP); } void drawStoryPopup() { if (showPopup) { fill(10, 15, 30, 250); stroke(0, 200, 255); strokeWeight(2.0f); rect(width / 2.0f - 220.0f, height / 2.0f - 90.0f, 440.0f, 180.0f, 10); textAlign(CENTER, TOP); fill(0, 255, 200); textSize(15); text(activePopupTitle, width / 2.0f, height / 2.0f - 70.0f); fill(255); textSize(12); text(activePopupText, width / 2.0f - 180.0f, height / 2.0f - 40.0f, 360.0f, 100.0f); textSize(11); fill(150, 180, 220); text("[Klicken zum Fortfahren]", width / 2.0f, height / 2.0f + 60.0f); textAlign(LEFT, TOP); } } // ================================================================= // USER INPUTS // ================================================================= public void mousePressed() { if (showPopup) { showPopup = false; pauseForWarning = false; return; } if (stage == 0) { if (mouseX > 40 && mouseX < 420 && mouseY > 110 && mouseY < 260) { clickPulse0 = 1.0f; contactsCount += (int)random(1.0f, 3.0f); if (recipientClass == 0) { viralMultiplier += 0.08f; addStage0Log("Hilfseinrichtung teilt Post. Multiplikator " + nf(viralMultiplier, 1, 2) + "x"); } else if (recipientClass == 1) { if (random(1.0f) < 0.4f) { money += random(10.0f, 50.0f) * viralMultiplier; } addStage0Log("Mail an Prof. gesendet (+Spende)."); } else { if (random(1.0f) < 0.15f) { contactsCount += 50; } addStage0Log("Science-Blog berichtet ueber DTIM-ZEC!"); } } if (mouseX > 55 && mouseX < 405) { if (mouseY > 315 && mouseY < 343) recipientClass = 0; if (mouseY > 348 && mouseY < 376) recipientClass = 1; if (mouseY > 381 && mouseY < 409) recipientClass = 2; } float shopX = 440.0f, shopY = 110.0f, shopW = 620.0f; if (mouseX > shopX + 20.0f && mouseX < shopX + shopW - 20.0f) { if (mouseY > shopY + 45.0f && mouseY < shopY + 120.0f && money >= pythonPrice) { money -= pythonPrice; pythonBots++; pythonPrice *= 1.4f; } if (mouseY > shopY + 130.0f && mouseY < shopY + 205.0f && money >= geminiPrice) { money -= geminiPrice; geminiAIs++; geminiPrice *= 1.5f; } if ((contactsCount >= 100 || money >= 200.0f) && mouseY > shopY + 220.0f && mouseY < shopY + 290.0f) { stage = 1; } } } else if (stage == 1) { float x = 440.0f, y = 110.0f, w = 620.0f; if (mouseX > 40 && mouseX < 420 && mouseY > 110 && mouseY < 250) { if (random(1.0f) < 0.4f) { researchers++; } rawMaterials += (int)random(10.0f, 30.0f); addStage1Log("Neuer Forscher / Rohstoffe dazugekommen!"); } if (mouseX > x + 20.0f && mouseX < x + w - 20.0f) { if (!part1Built && mouseY > y + 45.0f && mouseY < y + 120.0f && rawMaterials >= 150) { rawMaterials -= 150; part1Built = true; addStage1Log("ZEC-Reaktor montiert!"); } if (!part2Built && mouseY > y + 130.0f && mouseY < y + 205.0f && rawMaterials >= 350) { rawMaterials -= 350; part2Built = true; addStage1Log("Chassis montiert!"); } if (!part3Built && mouseY > y + 215.0f && mouseY < y + 290.0f && rawMaterials >= 600) { rawMaterials -= 600; part3Built = true; addStage1Log("Laser montiert!"); } if (!part4Built && mouseY > y + 300.0f && mouseY < y + 375.0f && rawMaterials >= 1000) { rawMaterials -= 1000; part4Built = true; addStage1Log("Bruecke montiert!"); } } if (part1Built && part2Built && part3Built && part4Built && mouseY > y + 360.0f && mouseY < y + 410.0f) { stage = 2; initStage2(); } } else if (stage == 2) { if (kiPopupOffen) { if (mouseX > width / 2.0f - 130.0f && mouseX < width / 2.0f + 130.0f && mouseY > 380 && mouseY < 422) { kiPopupOffen = false; } return; } if (sieg) { stage = 3; } } else if (stage == 3) { float shopX = 460.0f, shopY = 40.0f, shopW = 420.0f; if (mouseX > shopX + 20.0f && mouseX < shopX + shopW - 20.0f) { if (mouseY > shopY + 150.0f && mouseY < shopY + 230.0f && zecEnergyWatts >= 100) { zecEnergyWatts -= 100; dipolNodes++; } if (mouseY > shopY + 245.0f && mouseY < shopY + 325.0f && zecEnergyWatts >= 250 && marsPressure > 30.0f) { zecEnergyWatts -= 250; bechResonators++; } if (mouseY > shopY + 340.0f && mouseY < shopY + 420.0f && zecEnergyWatts >= 500 && marsTemp > -15.0f) { zecEnergyWatts -= 500; regolithExtractors++; } } if (marsTerraformed && mouseX > shopX + 20.0f && mouseX < shopX + shopW - 20.0f && mouseY > shopY + 530.0f && mouseY < shopY + 580.0f) { stage = 4; supplyTimer = 0.0f; colonistsArrived = false; triggerStory("BASISBAU (STAGE 4)", "Der Planet ist nun bewohnbar. Sammle DTIM-Energie, um die Basismodule hochzufahren!"); } } else if (stage == 4 || stage == 5) { if (aiUnlocked && !inRebellion && mouseX > 180 && mouseX < 280 && mouseY > 16 && mouseY < 38) { aiActive = !aiActive; return; } if (mouseX > 65 && mouseX < 145 && mouseY > 45 && mouseY < 67 && !coreBought && tlwEnergy >= 50.0f) { tlwEnergy -= 50.0f; coreBought = true; } if (mouseX > 155 && mouseX < 255 && mouseY > 45 && mouseY < 67) { if (!shieldBought && tlwEnergy >= 70.0f) { tlwEnergy -= 70.0f; shieldBought = true; shieldOn = true; } else if (shieldBought) { if (!shieldOn && (solarWarning || isSolarFlare)) { if (tlwEnergy >= 30.0f) { tlwEnergy -= 30.0f; shieldOn = true; } } else { shieldOn = !shieldOn; } } } if (mouseX > 265 && mouseX < 365 && mouseY > 45 && mouseY < 67) { if (!defenseBought && tlwEnergy >= 80.0f) { tlwEnergy -= 80.0f; defenseBought = true; defenseOn = true; } else if (defenseBought) { if (!defenseOn && (meteorWarning || isMeteor)) { if (tlwEnergy >= 30.0f) { tlwEnergy -= 30.0f; defenseOn = true; } } else { defenseOn = !defenseOn; } } } if (mouseX > 375 && mouseX < 465 && mouseY > 45 && mouseY < 67 && !isruBought && tlwEnergy >= 90.0f) { tlwEnergy -= 90.0f; isruBought = true; } if (isruBought && mouseX > 475 && mouseX < 625 && mouseY > 45 && mouseY < 67 && !autoShieldBought && shipPoints >= 200.0f) { shipPoints -= 200.0f; autoShieldBought = true; } if (isruBought && mouseX > 635 && mouseX < 785 && mouseY > 45 && mouseY < 67 && !autoDefenseBought && shipPoints >= 200.0f) { shipPoints -= 200.0f; autoDefenseBought = true; } if (isruBought && mouseX > 475 && mouseX < 625 && mouseY > 75 && mouseY < 97) { if (!autoIsruBought && shipPoints >= 150.0f) { shipPoints -= 150.0f; autoIsruBought = true; autoIsruActive = true; } else if (autoIsruBought) { autoIsruActive = !autoIsruActive; } } if (isruBought && !balanceReached) { if (mouseX > 65 && mouseX < 155 && mouseY > 75 && mouseY < 97 && tlwEnergy >= 15.0f) { tlwEnergy -= 15.0f; waterLevel = min(100.0f, waterLevel + 12.0f); } if (mouseX > 250 && mouseX < 340 && mouseY > 75 && mouseY < 97 && tlwEnergy >= 20.0f) { tlwEnergy -= 20.0f; greenLevel = min(100.0f, greenLevel + 12.0f); } if (greenLevel >= 10.0f && mouseX > 635 && mouseX < 785 && mouseY > 75 && mouseY < 97) { greenLevel -= 10.0f; tlwEnergy = min(maxEnergy, tlwEnergy + 45.0f); int pc = color(100, 255, 100); for(int k=0; k<15; k++) { particles.add(new Particle(width / 2.0f, height - 60.0f, random(-3.0f, 3.0f), random(-3.0f, -1.0f), pc, 2)); } } } if (stage == 4 && isruBought && mouseX > width / 2.0f - 150.0f && mouseX < width / 2.0f + 150.0f && mouseY > 250.0f && mouseY < 300.0f) { stage = 5; supplyTimer = 0.0f; colonistsArrived = false; triggerStory("KOLONISATION (STAGE 5)", "Die Basis steht. Das erste Kolonistenschiff befindet sich im Anflug! Verwalte Nahrung und Zufriedenheit."); } if (stage == 5 && colonistsArrived) { if (mouseX > 180 && mouseX < 360 && mouseY > 105 && mouseY < 127) { if (tradePolicy == 0) { tradePolicy = 1; } else { tradePolicy = 0; } } if (mouseX > 475 && mouseX < 625 && mouseY > 105 && mouseY < 127 && shipPoints >= 100.0f) { shipPoints -= 100.0f; colonistCount += 5.0f; } if (mouseX > 635 && mouseX < 785 && mouseY > 105 && mouseY < 127 && shipPoints >= 100.0f) { shipPoints -= 100.0f; if (tradePolicy == 0) { satisfaction = min(100.0f, satisfaction + 15.0f); } else { drugSupply += 100.0f; } } if (!hasSecondShip && mouseX > 475 && mouseX < 645 && mouseY > 16 && mouseY < 38) { if (shipPoints >= 500.0f && colonistCount >= 50.0f) { shipPoints -= 500.0f; hasSecondShip = true; ship2X = width / 2.0f; ship2Y = height / 2.0f; } } } } } public void keyPressed() { if (key == ' ' && stage == 0) { clickPulse0 = 1.0f; contactsCount += (int)random(1.0f, 3.0f); if (random(1.0f) < 0.3f) { money += random(5.0f, 15.0f); } } else if (key == ' ' && stage == 1) { rawMaterials += 15; addStage1Log("Rohstoff-Spende erhalten (+15u)."); } else if (key == ' ' && stage == 3) { zecEnergyWatts += 50; } } void triggerStory(String title, String txt) { activePopupTitle = title; activePopupText = txt; showPopup = true; pauseForWarning = true; } // ================================================================= // CLASSES // ================================================================= class TLWFieldNode { float baseX, baseY; TLWFieldNode(float x, float y) { baseX = x; baseY = y; } void updateAndDisplay(float sx, float sy, float sx2, float sy2) { float x = baseX, y = baseY; float dShip1 = dist(x, y, sx, sy), dShip2 = dist(x, y, sx2, sy2); if (dShip1 < 140.0f) { float f = (140.0f - dShip1) * 0.12f; x += cos(atan2(y - sy, x - sx)) * f; y += sin(atan2(y - sy, x - sx)) * f; } if (hasSecondShip && colonistCount >= 50.0f && dShip2 < 100.0f) { float f = (100.0f - dShip2) * 0.15f; x += cos(atan2(y - sy2, x - sx2)) * f; y += sin(atan2(y - sy2, x - sx2)) * f; } stroke(40, 80, 150, 70); point(x, y); if (baseX < width - 70 && baseY < height - 170) { stroke(35, 70, 130, 45); line(baseX, baseY, x, y); } } } class TLWToken { float x, y; TLWToken(float px, float py) { x = px; y = py; } void display() { noStroke(); fill(0, 255, 220, 80); ellipse(x, y, 22.0f, 22.0f); fill(0, 255, 220, 220); ellipse(x, y, 12.0f, 12.0f); fill(255); ellipse(x, y, 5.0f, 5.0f); } } class Projectile { float x, y, vx, vy; Projectile(float startX, float startY, float targetX, float targetY) { x = startX; y = startY; float angle = atan2(targetY - startY, targetX - startX); vx = cos(angle) * 14.0f; vy = sin(angle) * 14.0f; } void update() { x += vx; y += vy; } void display() { noStroke(); fill(255, 100, 255, 180); ellipse(x, y, 12.0f, 22.0f); fill(0, 255, 255); ellipse(x, y, 6.0f, 14.0f); fill(255); ellipse(x, y, 3.0f, 8.0f); } boolean isOffScreen() { if (x < 0) return true; if (x > width) return true; if (y < 0) return true; if (y > height) return true; return false; } } class Particle { float x, y, vx, vy, alpha; int col; int type; Particle(float px, float py, float dirX, float dirY, int c, int t) { x = px; y = py; vx = dirX; vy = dirY; alpha = 255.0f; col = c; type = t; } void update() { x += vx; y += vy; if (type == 1) { alpha -= 16.0f; } else { vx *= 0.92f; vy *= 0.92f; alpha -= 12.0f; } } void display() { noStroke(); fill(col, alpha); float s = 6.0f; if (type == 1) s = 4.0f; ellipse(x, y, s, s); } boolean isDead() { if (alpha <= 0.0f) return true; return false; } }