Technische Referenz
My Fishing Kaktus
Mechanik-Doku für alle Systeme: Area-Werte, Rarity-Wahrscheinlichkeiten, Upgrade-Formeln, Wetter-Buffs, Karl-Rewards, Daily-Schedule, Save-Format. Kein Spielratgeber — nur Fakten und Formeln.
Übersicht
My Fishing Kaktus ist ein aktives Sammel-Fischspiel. Spieler tippen auf Fischstellen, lösen ein Fang-Minispiel aus, sammeln Fische in einem Index, verkaufen sie für Coins, kaufen Upgrades und prestigen sich in tiefere Areas.
- 3 Areas: Pond (Start), Lake (Prestige 1), Ocean (Prestige 2).
- 132 Fische total, aufgeteilt nach Rarity in jeder Area.
- 5 Upgrades: Rute, Schnur, Haken, Köder, Glück (max Level 5).
- 10 Wetter-Events (5 Standard mit Buffs, Abyss + 4 Mutation-Events) — 15-min-Slots, 2,5-min aktiv.
- Mutationen: Standard (BIG/HUGE/SHINY, 10 %) + Event-spezifisch (ABYSSAL → HAUNTED ×4–×10) — stacken multiplikativ.
- Karl Bonus-Event mit Putz-Minispiel und Glücksrad.
- Daily-Rewards mit Streak-System (Tag 7 = Epic, ab Woche 3 = Legendary).
Areas
Jede Area hat eigene Rarity-Gewichte, Gewichtsbereiche und Wert-Multiplikatoren. Spieler starten im Pond. Lake wird mit Prestige 1 freigeschaltet, Ocean mit Prestige 2.
| Area | Prestige | valueMult | upgradeMult | Spawn-Intervall | Prestige-Coins-Anker |
|---|---|---|---|---|---|
| Pond | 0 | ×1,05 | ×1 | 30–52 s (Basis) | 24.000 |
| Lake | 1 | ×0,46 | ×6 | 26–46 s (Basis) | 750.000 |
| Ocean | 2 | ×0,60 | ×10 | 22–40 s (Basis) | — |
valueMult kommt in die Coin-Wert-Berechnung beim Verkauf,
upgradeMult macht Upgrades in höheren Areas teurer (Pond Rod
L0 = 80 Coins, Lake = 480 Coins, Ocean = 800 Coins).
Spawn-Intervall ist die Basis-Wartezeit vor Köder-Upgrade — Köder reduziert pro Level (siehe Köder im Upgrades-Abschnitt).
Rarity-Gewichte (Roll-Wahrscheinlichkeiten)
Innerhalb einer Area wird beim Anangeln eine Rarity per gewichtetem Zufall bestimmt. Glück-Upgrade verschiebt die Verteilung Richtung seltene Rarities:
luckPower = 1 + glückLevel × 0.26
gewicht(rarity) = baseGewicht × luckPower ^ rarity.luckImpact
| Area | Common | Uncommon | Rare | Epic | Legendary |
|---|---|---|---|---|---|
| Pond | 80 | 15 | 4,5 | 0,5 | — |
| Lake | 68 | 22 | 8 | 1,8 | 0,2 |
| Ocean | 55 | 26 | 14 | 4,3 | 0,7 |
Gewichts-Bereiche (kg pro Fang)
Pro Rarity in jeder Area gibt es einen kg-Bereich. rollWeight picked
aus diesem Bereich; mit 4 % Chance gibt es einen Trophy-Roll
(oberste 25 % des Bereichs).
| Area / Rarity | Common | Uncommon | Rare | Epic | Legendary |
|---|---|---|---|---|---|
| Pond | 0,05–0,5 | 0,12–0,9 | 0,25–1,8 | 0,6–3,5 | — |
| Lake | 0,2–1,5 | 0,5–3,2 | 1–7 | 2,5–16 | 6–38 |
| Ocean | 0,8–4,5 | 2–11 | 5–32 | 12–85 | 30–220 |
Raritäten
5 Stufen, global definiert. Beeinflussen Wert, Glück-Shift und Fang-Schwierigkeit:
| Rarity | Farbe | valuePerKg | luckImpact | difficulty |
|---|---|---|---|---|
| Common | #79d9f7 (cyan) | 8 | −0,4 | 0,92 |
| Uncommon | #65e2a2 (grün) | 20 | +0,2 | 1,00 |
| Rare | #9f9dff (violett) | 55 | +0,7 | 1,12 |
| Epic | #d58cff (magenta) | 150 | +1,3 | 1,28 |
| Legendary | #ffc86c (gold) | 500 | +1,8 | 1,46 |
Coin-Wert-Formel
coinWert = max(1, round(kg × valuePerKg × fish.valueMultiplier × area.valueMultiplier))
fish.valueMultiplier ist pro Fisch leicht unterschiedlich (siehe
Fish-Pool-Weights im Code, basiert auf Pool-Größe der Rarity in dieser Area).
Fisch-Index
Pond hat 36 Fische, Lake 44, Ocean 52 — total 132. Aufteilung nach Rarity:
| Area | Common | Uncommon | Rare | Epic | Legendary | Total |
|---|---|---|---|---|---|---|
| Pond | 14 | 10 | 8 | 4 | — | 36 |
| Lake | 10 | 12 | 12 | 8 | 2 | 44 |
| Ocean | 6 | 12 | 16 | 12 | 6 | 52 |
Beim Fang wird ein zufälliger Fisch aus dem Area-Rarity-Pool per gewichtetem
Pick gewählt (Pool-Gewichte siehe FISH_POOL_WEIGHTS). Im Fish-Index
wird nur die aktuelle Area mit voller SVG-Liste gerendert, andere Areas zeigen
nur den Counter (Performance).
Vollständige Fisch-Namen siehe js/data/fish.js im Code.
Upgrades
5 Upgrade-Pfade mit max Level 5. Kostensteigerung pro Level: 1,62
bis 1,72 Multiplier (variiert leicht). Skaliert mit area.upgradeMultiplier.
kaufPreis = round(baseCost × area.upgradeMultiplier × costGrowth^level)
| Upgrade | baseCost | costGrowth | Effekt |
|---|---|---|---|
| Rute | 80 | 1,62 | Breitere Fangzone (+0,035 pro Level), reduziert Fisch-Speed um max 35 % |
| Schnur | 110 | 1,64 | Reduziert Tension-Drain um 12 % pro Level (max 60 %) |
| Haken | 150 | 1,66 | +15 % Fang-Balken-Fill pro Level, +35 % Tension-Refill pro Level |
| Glück | 240 | 1,72 | luckPower +0,26 pro Level → seltenere Fische öfter |
| Köder | 180 | 1,65 | +1 Spot Cap pro Level, +2s Lifetime pro Level, -1s Spawn-Wait pro Level |
Rute (Fish-Speed-Modifier)
rodSpeedMult = max(0.65, 1 − rodLevel × 0.06) // L0=1.0 ... L5=0.70 (Cap)
rodTurnMult = 1 + rodLevel × 0.08 // L0=1.0 ... L5=1.40
Köder (Spawn + Spot-Lifetime)
Handpicked-Tuning für klar spürbare Progression pro Level. Lookup-Tabelle:
| Level | Max Spots parallel | Lifetime | Spawn-Wait |
|---|---|---|---|
| L0 | 1 | 5 s | 6 s |
| L1 | 2 | 7 s | 5 s |
| L2 | 3 | 9 s | 4 s |
| L3 | 4 | 11 s | 3 s |
| L4 | 5 | 13 s | 2 s |
| L5 | 6 | 15 s | 1 s |
nextDelay = waitSec / spawnMultiplier — kein + lifetimeSec,
sodass Spots sich überlappen und der maxSpots-Wert tatsächlich greift.
Bei L5 spawnt alle 1 s ein neuer Spot, jeder lebt 15 s → bis zu 6 parallel sichtbar.
Visuelle Angel-Themes pro Area
Im Angel-UI (Shop) wird eine SVG-Angel gerendert, deren Look pro Area und Upgrade-Level wechselt.
Architektur in js/systems/angel/ (Composer + Themes + Shapes).
| Area | Rod | Grip | Reel | Hook | Bait | Aura |
|---|---|---|---|---|---|---|
| Pond | classic | cork | spinning | j | spinner | none |
| Lake | driftwood | wrap | fly | barbed | fly | leaves |
| Ocean | tactical | rubber | baitcaster | treble | jig | bubbles |
Neue Areas brauchen nur einen Daten-Block in themes.js — keine neue Render-Logik.
Shape-Slots: rod/grip/reel/eyelet/hook/bait/aura mit je 2-5 Varianten;
weitere Auras (embers, runes) sind für künftige Areas (Volcano, Cosmic) schon vorbereitet.
Fang-Minispiel
Beim Antippen einer Fischstelle öffnet sich das Minispiel mit zwei Bars: Fang-Fortschritt (oben, grün/blau/gold) und Schnur-Spannung (unten, rot).
Fang-Fortschritt
Steigt wenn der Fisch in der grünen Catch-Zone ist, fällt sonst. Bei 100 % = Catch.
catchSpeed = (0.3 + hookLevel × 0.045) / rarity.difficulty
lossSpeed = max(0.035, 0.13 × rarity.difficulty × (1 − lineLevel × 0.11))
zoneWidth = min(0.44, 0.19 + rodLevel × 0.035)
Schnur-Spannung
Startet bei 1.0. Drainet wenn Fisch ausserhalb der Zone, refillt wenn drinnen. Bei 0 → Catch verloren.
tensionDrain = max(0.04, TENSION_DRAIN[rarity] × (1 − lineLevel × 0.12))
tensionRefill = 0.36 × (1 + hookLevel × 0.35)
| Rarity | Drain/s (L0) | ~Sek. bis Ausriss (L0) | ~Sek. bis Ausriss (Line L5) |
|---|---|---|---|
| Common | 0,167 | 6,0 s | 15,0 s |
| Uncommon | 0,21 | 4,8 s | 11,9 s |
| Rare | 0,27 | 3,7 s | 9,3 s |
| Epic | 0,34 | 2,9 s | 7,4 s |
| Legendary | 0,42 | 2,4 s | 6,0 s |
Fisch-Bewegung pro Rarity
// Speed = (baseSpeed + rand × speedVariance) × rodSpeedMult
// TurnIn = (minTurn + rand × (maxTurn − minTurn)) × rodTurnMult
// Beim Turn: flipChance = Wahrscheinlichkeit für Richtungswechsel
| Rarity | baseSpeed | speedVariance | minTurn (s) | maxTurn (s) | flipChance |
|---|---|---|---|---|---|
| Common | 0,10 | 0,06 | 0,70 | 1,60 | 45 % |
| Uncommon | 0,14 | 0,10 | 0,55 | 1,35 | 55 % |
| Rare | 0,22 | 0,14 | 0,40 | 1,05 | 65 % |
| Epic | 0,30 | 0,18 | 0,28 | 0,85 | 72 % |
| Legendary | 0,42 | 0,22 | 0,20 | 0,68 | 78 % |
Coin-Fische (Timer-Fische)
Schwimmen ab und zu durchs Wasser. Klick = direkter Coin-Reward. Vier Tiers (small / big / sword / shark) mit unterschiedlichen Reward-Tabellen pro Area:
| Area / Tier | small | big | sword | shark |
|---|---|---|---|---|
| Pond | 8 | 23 | 50 | 107 |
| Lake | 46 | 138 | 300 | 632 |
| Ocean | 1.300 | 3.900 | 8.600 | 18.000 |
Wetter-Events
Global synchron für alle Spieler. Slot = 15 Minuten, davon 2,5 Minuten aktiv. Buff wird multiplikativ auf den entsprechenden Stat angewendet. Slot-Bestimmung per deterministischem Hash vom Epoch-Index.
| Event | Weight | Chance | Effekt | Wasser-Look |
|---|---|---|---|---|
| ☀ Sonniges Wetter | 20 | 16,7 % | luck ×2 · SUNNY-Mutation ×2 (20 %) | Calm preset, helles Licht |
| 🌧 Regenschauer | 20 | 16,7 % | spawnRate ×2 · WET-Mutation ×2 (20 %) | Rain im Shader |
| ⛈ Sturm | 20 | 16,7 % | hook ×2 · STORMY-Mutation ×2 (20 %) | Storm preset, Sturm-Wellen + Regen |
| 🌫 Nebel | 20 | 16,7 % | rod ×2 · MISTY-Mutation ×2 (20 %) | Weißer Nebel-Overlay |
| 🌙 Nachtangeln | 20 | 16,7 % | line ×2 · NOCTURNAL-Mutation ×2 (20 %) | Deepsea preset, Night-Veil |
| 🌌 Abyss | 5 | 4,2 % | Epic+ ×2 · ABYSSAL-Mutation ×4 (15 %) | Tiefblauer Veil + Neon-Partikel |
| 🌠 Polarlicht | 6 | 5,0 % | AURORA-Mutation ×3 (30 %) | Grün-violetter Schleier + drifting Wisps |
| 🔥 Glutsturm | 4 | 3,3 % | EMBER-Mutation ×5 (25 %) | Storm-Wasser + orange Glut-Funken |
| 🌑 Blutmond | 3 | 2,5 % | CRIMSON-Mutation ×7 (20 %) | Deepsea + tiefroter Schleier |
| 👻 Geistermeer | 2 | 1,7 % | HAUNTED-Mutation ×10 (15 %) | Deepsea + cyan Geister-Wisps von oben |
Event-Pick: hash(slotIndex) % totalWeight (total = 120), dann gewichtetes Bucket-Mapping.
Neue seltene Events einfach mit kleinem weight in WEATHER_EVENTS ergänzen.
Abyss-Spezial: Statt einen Minispiel-Stat zu boosten, multipliziert es direkt
die Roll-Wahrscheinlichkeit für Epic- und Legendary-Rarities (Logik in
weatherEventSystem.getRarityMultipliers()). Zusätzlich Chance auf ABYSSAL-Mutation.
Mutation-Only Events: Polarlicht / Glutsturm / Blutmond / Geistermeer haben keinen Stat-Buff — ihre einzige Wirkung ist die jeweilige Event-Mutation während der 5-Min-Phase. Je seltener das Event, desto höher der Multiplier (Polarlicht ×3 → Geistermeer ×10). Details s. Mutationen.
Buffs gehen direkt in die Minispiel-Bonus-Berechnung — z.B. „Sturm" verdoppelt den effektiven Hook-Level, was sowohl Fang-Speed als auch Tension-Refill steigert.
Mutationen
Bei jedem Fang werden unabhängig zwei Würfe gemacht: Standard-Mutation
(immer, 10 %) und Event-Mutation (nur während eines passenden Wetter-Events).
Beide können gleichzeitig zuschlagen → multiplikativ stackbar.
Der finale Coin-Wert ist base × prod(mutations.mult).
Standard-Mutationen (immer würfelbar)
P(standard) = 10 % × (1 + Glück × 0.08)
Pool (gewichtet): BIG 65 / HUGE 25 / SHINY 10
| ID | Name | Multiplier | Pool-Anteil | Chance Glück Lvl 0 | Chance Glück Lvl 5 |
|---|---|---|---|---|---|
| big | BIG | ×1,5 | 65 % | 6,5 % | 9,1 % |
| huge | HUGE | ×2,0 | 25 % | 2,5 % | 3,5 % |
| shiny | SHINY 🌟 | ×3,0 | 10 % | 1,0 % | 1,4 % |
Glück-Bonus: jedes Level Glück (max 5) erhöht alle Mutationen-Wahrscheinlichkeiten
um +8 % (sanft). Bei Lvl 5: ×1,40 auf alle Mutationen.
Event-Mutationen (nur während aktivem Event)
Jedes der 10 Wetter-Events hat eine eigene Mutation. Standard-5 ×2 (zusätzlich zum Stat-Buff), Rare-5 ×3 bis ×10. In-Event-Chance ist die Wahrscheinlichkeit pro Catch während das Event läuft, "Über-alles-Chance" rechnet das mit der Slot-Häufigkeit hoch.
| Event | Mutation | Mult | in-Event-Chance | Über-alles-Chance |
|---|---|---|---|---|
| ☀ Sonniges Wetter | SUNNY | ×2 | 20 % | ~3,3 % |
| 🌧 Regenschauer | WET | ×2 | 20 % | ~3,3 % |
| ⛈ Sturm | STORMY | ×2 | 20 % | ~3,3 % |
| 🌫 Nebel | MISTY | ×2 | 20 % | ~3,3 % |
| 🌙 Nachtangeln | NOCTURNAL | ×2 | 20 % | ~3,3 % |
| 🌌 Abyss | ABYSSAL | ×4 | 15 % | ~0,63 % |
| 🌠 Polarlicht | AURORA | ×3 | 30 % | ~1,5 % |
| 🔥 Glutsturm | EMBER | ×5 | 25 % | ~0,83 % |
| 🌑 Blutmond | CRIMSON | ×7 | 20 % | ~0,5 % |
| 👻 Geistermeer | HAUNTED | ×10 | 15 % | ~0,25 % |
Stacking-Beispiel: Du fängst während Geistermeer (1,7 % Slot) einen
Common-Fisch (10 Coins base). Du würfelst SHINY (×3) UND HAUNTED (×10) → finaler Wert
10 × 3 × 10 = 300 Coins. Die seltensten Catches überhaupt im Spiel.
Event-Mutationen Glück-Skalierung (analog Standard): jeweilige in-Event-Chance × (1 + Glück × 0,08). Bei Lvl 5: HAUNTED-Chance steigt von 15 % auf 21 % innerhalb von Geistermeer.
Was ist die seltenste Catch-Kombi?
Theoretisches Optimum: Legendary + SHINY + HAUNTED + ≥99 % kg während Geistermeer aktiv.
- P(Legendary) ohne Glück: 0,5 %, mit Glück Lvl 5 (Luck-Boost auf Rarity): ~2,3 %
- P(SHINY): 1 % (Lvl 0) / 1,4 % (Lvl 5)
- P(HAUNTED): 0,25 % (Lvl 0) / 0,35 % (Lvl 5)
- P(kg ≥ 99 %): ~0,8 %
Kombiniert ohne Glück: ~1 in 1 Milliarde (1 / 1.000.000.000). Mit Glück Lvl 5 auf den Rarity- und Mutation-Buffs zusammen: ~1 in 110 Millionen. Das wäre der absolute Trophäen-Fang — praktisch nicht erreichbar ohne forciertes Spielen aller Geistermeer-Events.
P(SHINY HAUNTED) im Detail: Pro Catch während Geistermeer 1 % × 15 % = 0,15 %. Pro 15-Catch-Window ~2,2 %. Geistermeer triggert ~0,8 mal/Tag → bei aktivem Mitgrinden aller Events erwartet man ein SHINY HAUNTED nach ~3 Wochen, 95 % nach ~170 Tagen.
Implementation: rollMutations(event) in data/mutations.js
wird beim Cast in startFishing() aufgerufen, das Ergebnis fliesst per
applyMutationsToCandidate direkt in candidate.value.
Anzeige als Badges (Glow für SHINY + alle Event-Mutationen) über dem Fischnamen,
plus Broadcast-Push an alle Spieler bei Event-Mutationen und SHINY.
Karl die Schildkröte
Bonus-Event. Karl taucht maximal 1× pro Stunde auf, zu einer deterministisch-zufälligen Sekunde innerhalb der Stunde (global synchron). Sichtbar für 30 Sekunden — wer nicht antippt, verpasst ihn.
KARL_SLOT_MS = 3.600.000 // 1 Stunde
KARL_VISIBLE_MS = 30.000 // 30 Sekunden
appearOffset = hash(slotIndex) → zwischen 60s und (SLOT_MS − VISIBLE_MS − 60s)
Cleaning-Minispiel
- Karls Panzer ist mit braun-grünem Schmutz bedeckt (Karl-Silhouette als Mask).
- Spieler wischt mit Maus/Finger → destination-out Erase auf dem Canvas.
- Brush-Radius:
5.5 %der Canvas-Breite. - Tolerance: 93 % Sauberkeit → Cleaning fertig.
Glücksrad-Belohnungen
Pro Area unterschiedliche Reward-Tabelle. Gewichte = Häufigkeit:
| Area | Belohnungen (Gewicht: Reward) |
|---|---|
| Pond | 30: +10 · 25: +25 · 20: +50 · 15: +100 · 7: +250 · 3: ★ Epic-Spot |
| Lake | 25: +50 · 25: +150 · 20: +400 · 15: +800 · 10: +1.500 · 5: ★ Epic-Spot |
| Ocean | 22: +200 · 22: +600 · 20: +1.500 · 15: +4.000 · 10: +10.000 · 8: ★ Epic · 3: ★ Legendary |
Daily Rewards
Streak-System. Pro täglichem Login wird belohnt; ein verpasster Tag resettet den Streak. Basis lokales Datum (Spieler-Zeitzone, nicht UTC).
Reward-Formel
dayInWeek = ((streakDay − 1) mod 7) + 1 // 1..7
weekNum = ceil(streakDay / 7) // 1, 2, 3, ...
dayMultipliers = [1, 1.5, 2.2, 3.2, 4.5, 6.0, 8.0] // Tag 1..7
baseCoins(week 1) = 50
baseCoins(week 2) = 90
baseCoins(week 3) = 140
baseCoins(week 4+) = min(2500, 140 × 1.12^(weekNum − 3))
coins = round(baseCoins × dayMultipliers[dayInWeek − 1])
Tag-7 Spezial
- Woche 1: 1× Epic-Fischstelle
- Woche 2: 2× Epic-Fischstelle
- Woche 3+: 1× Legendary-Fischstelle
Beispiel-Werte
| Tag | Woche | Coins | Spezial |
|---|---|---|---|
| 1 | 1 | 50 | — |
| 7 | 1 | 400 | Epic-Spot |
| 14 | 2 | 720 | 2× Epic-Spot |
| 21 | 3 | 1.120 | Legendary-Spot |
| 70 | 10 | ~2.475 | Legendary-Spot |
| 105 | 15 | ~4.360 | Legendary-Spot |
Daily-Spawned Fischstellen bleiben 90 Sekunden sichtbar (statt 12 s wie reguläre Force-Spawns) damit niemand seine Belohnung verpasst.
Admin-Events (Live-Push)
Admins können globale Events an alle Online-Spieler pushen. Events laufen über
die Supabase-Tabelle admin_game_events, Auto-Expire nach 60 s.
| Event | Effekt |
|---|---|
| weather-{sunny,rain,storm,fog,night,abyss,polarlicht,glutsturm,blutmond,geistermeer,clear} | Forciert das Wetter-Event |
| spawn-fish-{small,big,sword,shark} | Spawnt einen Coin-Fisch im Tier |
| broadcast | Eigener Text im Broadcast-Feed (max 200 Zeichen) |
| force-spawn-{epic,legendary} | Garantierte Fischstelle dieser Rarity (12 s sichtbar) |
| spawn-karl | Karl die Schildkröte spawnen |
| force-reload | Alle Clients reloaden nach 1,5 s (cross-game) |
Prestige
Spieler prestigen sich in die nächste Area. Cap aktuell bei Prestige 2 (Ocean = letzte Area). Anker-Werte für „Du kannst jetzt prestigen":
- Pond → Lake: erst möglich ab 24.000 Coins totalEarned
- Lake → Ocean: erst möglich ab 750.000 Coins totalEarned
Was bleibt / wird zurückgesetzt
Bleibt
- Fish-Index (alle gefangenen Fische)
- Stats (totalCaught, bestCatchValue, bestWeightKg)
- Prestige-Zähler
- Unlocked Areas
- Daily-Streak
Zurückgesetzt
- Coins (auf 0)
- Alle 5 Upgrades (auf Level 0)
- Inventar (verkauft / verworfen)
Save-Format (game_saves Tabelle)
Im Supabase-Save (game_id = my-fishing-kaktus) wird gespeichert:
{
version: 1,
coins: 0,
currentArea: "pond",
unlockedAreas: ["pond"],
prestige: 0,
upgrades: { rod: 0, line: 0, hook: 0, luck: 0, sonar: 0 }, // sonar = Köder intern
inventory: { [fishId]: { count, totalKg, totalValue, bestKg } },
index: { [fishId]: { count, bestKg } },
stats: {
totalCaught: 0,
totalSold: 0,
totalCoinsEarned: 0,
bestCatchValue: 0,
bestWeightKg: 0
},
settings: { reducedMotion: false },
daily: {
streak: 0,
lastClaimedDay: null, // "YYYY-MM-DD" (lokal)
totalClaimed: 0,
bestStreak: 0
}
}
total_earned Spalte in der Tabelle wird mit stats.totalCaught
synchronisiert (für die Rangliste-Sortierung als Sekundär-Schlüssel hinter Prestige).