# ============================================================================= # Fishing Mini-Project - Main Game File (OUTLINE ONLY) # ============================================================================= # This file is a STRUCTURAL OUTLINE: function signatures + descriptive comments. # The actual implementation will be written by the project author (human). # # Engine: cmu_graphics | Pattern: MVC (Model-View-Controller) # Data: creatures.tsv (tab-separated database at repo root) # Save: save.json (persistent progress in the script directory) # ============================================================================= from cmu_graphics import * import json # ============================================================================= # SECTION 1: DATA LOADING / FILE I/O # ----------------------------------------------------------------------------- # Helpers that read from and write to disk. Kept separate from game logic so # the data source (TSV path, save path) can change without touching gameplay. # ============================================================================= def loadCreatures(path="creatures.tsv"): # Read creatures.tsv (tab-separated) and parse it into a usable structure. # Suggested return: a list of dicts, one per creature, with keys matching # the header row: name, description, price, sprite-file, difficulty, # length, weight. Convert numeric columns (price, difficulty, length, # weight) from strings to int/float here; leave missing fields as sensible # defaults so partially-filled rows (like the current TSV) don't crash. creatures = [] with open(path) as f: lines = f.readlines() for line in lines[1:]: #ignore header data = line.split("\t") creatures.append({ "name": data[0], "description": data[1], "price": float(data[2]), "sprite-file": data[3], "difficulty": int(data[4]), "length": float(data[5]), #inches "weight": float(data[6]) #pounds }) return creatures def loadSave(path="save.json"): # Load save.json and return the player's saved state (money, owned baits, # owned upgrades, current bait, caught log, etc.). If the file is missing # or unreadable, return a fresh default-state dict so a first-time player # starts cleanly. This is the only place that reads the save file. defaultState = { "cash": 0, "owned_baits": [], "owned_upgrades": [], "current_bait": "worm", "catch_log": [] } try: with open(path, "r") as f: return json.load(f) except (FileNotFoundError, IOError): return defaultState def writeSave(saveState, path="save.json"): # Serialize the current player state to save.json. Call this at key moments # (after a sale, after a purchase, on quit) so progress persists between # sessions. Keep the written structure identical to what loadSave expects. with open(path, "w") as f: #overwrite existing f.write(json.dumps(saveState)) # ============================================================================= # SECTION 2: MODEL - STATE SETUP & GAME DATA # ----------------------------------------------------------------------------- # Everything that initializes and holds game state on the cmu_graphics `app`. # No drawing and no event handling here - just state. # ============================================================================= def onAppStart(app): # cmu_graphics entry point. Initialize ALL app.* state here: # - window/layout constants (width, height, dock/water/grass regions) # - app.creatures (from loadCreatures) # - app.save (from loadSave) and derived player values # - app.scene (which screen is active: 'dock', 'shop', 'catch', ...) # - fishing state (idle / waiting-for-bite / skill-check / result) # - skill-check state placeholders (cursor angle, bars, speed, result) # - app.stepsPerSecond for the game loop cadence # Delegates to the smaller setup helpers below to keep this readable. pass def resetFishingState(app): # Return the fishing cycle to its starting "idle" point so a new cast can # begin. Clears any active skill-check data, the pending random bite timer, # and the currently-hooked creature. Called at startup and after each catch # is resolved/dismissed. pass def pickRandomCreature(app): # Choose which creature the player hooks on this cast. Selection is filtered # by the current bait (bait gates which difficulty tiers are available) and # weighted toward easier creatures, while still giving rarer/harder ones a # real chance (per the spec's "skewed toward easier but still fun" goal). # Returns the chosen creature record (one entry from app.creatures). pass def startSkillCheck(app, creature): # Configure a new skill check based on the hooked creature's difficulty. # Difficulty maps to: cursor rotation speed, number of target bars, and # bar length/width. Also apply any owned upgrades that modify these values # (e.g. slower cursor, wider bars, extra forgiveness). Stores the resulting # parameters on app for the controller/view to use. pass # ============================================================================= # SECTION 3: CONTROLLER - GAME LOOP & INPUT HANDLING # ----------------------------------------------------------------------------- # cmu_graphics event hooks. These advance state and route input; they should # call Model helpers rather than contain heavy logic themselves. # ============================================================================= def onStep(app): # Runs every time step (the game loop / "controller tick"). # Responsibilities depend on the current fishing phase: # - waiting-for-bite: count down the random timer; when it elapses, pick a # creature and transition into the skill check. # - skill-check: advance the cursor's angle around the circle each step. # - otherwise (idle, viewing a catch, in shop): do nothing time-based. pass def onMousePress(app, mouseX, mouseY): # Primary input router. Behavior depends on app.scene / fishing phase: # - dock idle: clicking starts a cast (begin waiting-for-bite). # - skill-check active: register the click as a timing attempt and # evaluate it via checkSkillHit. # - catch popup showing: dismiss the popup and reset fishing. # - shop / UI sprites clicked: open the shop or trigger that UI action. # Keep this as dispatch only - defer the real work to helper functions. pass def onKeyPress(app, key): # Optional keyboard controls. Candidates: a key to cast/reel as an # alternative to clicking, a key to open/close the shop, or a debug/reset # key during development. Remove if you decide the game is mouse-only. pass def checkSkillHit(app): # Evaluate a skill-check click: is the cursor's current angle inside one of # the active target bars? Decide hit vs miss. Define the multi-bar flow here # (e.g. must the player clear every bar, or is one good hit enough?) and # advance or fail the skill check accordingly. On full success, mark the # creature as caught and move to the catch-display phase; on failure, end # the cast without a catch. pass # ============================================================================= # SECTION 4: SHOP / ECONOMY LOGIC # ----------------------------------------------------------------------------- # Buying/selling and the rogue-like upgrade system. Pure state changes that the # controller invokes; no drawing here. # ============================================================================= def sellCreature(app, creature): # Add the creature's market value to the player's money. Value scales with # difficulty (harder creatures pay more, per the spec). Persist the updated # money via writeSave. Decide here whether selling is automatic on catch or # a deliberate action in the shop/market. pass def buyUpgrade(app, upgradeId): # Attempt to purchase an upgrade. Check the player can afford it and doesn't # already own it; if valid, deduct money, record ownership in app.save, and # persist. Upgrades modify the skill check (cursor speed, bar size/count, # extra attempts, etc.) and are read back in startSkillCheck. pass def buyBaitLicense(app, baitId): # Purchase a one-time license for a bait tier. Once owned, the player can # freely switch to that bait at no further cost (switching handled by # setActiveBait). Bait determines which creatures are reachable in # pickRandomCreature. Deduct money, record ownership, persist. pass def setActiveBait(app, baitId): # Switch the currently-equipped bait to any bait the player already owns a # license for. Free action. Updates app state so the next cast's creature # pool reflects the new bait. Reject the switch if the bait isn't owned. pass # ============================================================================= # SECTION 5: VIEW - DRAWING # ----------------------------------------------------------------------------- # redrawAll + per-scene draw helpers. These ONLY read state and draw; they must # never mutate app state. Composed top-down so redrawAll stays legible. # ============================================================================= def redrawAll(app): # Master draw routine. Draw the persistent world first (background, grass, # water, dock, player), then layer the active scene/phase on top: # - the shop UI, or # - the active skill-check overlay, or # - the catch-display popup. # Delegates each piece to the helpers below. pass def drawBackground(app): # Draw the static scene layout from the spec: grass behind, the dock, and # the lake occupying the bottom ~1/3 of the screen (blue water, optional # wave patterns). This is the backdrop present in every scene. pass def drawPlayerAndRod(app): # Draw the character sprite seated at the end of the dock with the fishing # rod. When a cast is active, draw the line and the bobber dropping onto the # water surface. Reflects the current fishing phase visually. pass def drawShopEntities(app): # Draw the clickable shop/UI sprites standing on the grass (per the spec). # Positions here must line up with the hit-testing done in onMousePress so # clicks land on the right entity. pass def drawSkillCheck(app): # Draw the active skill-check overlay: the circle, the target bars placed # around it (count/length from difficulty), and the rotating cursor at its # current angle. Optionally show which bars are already cleared. Read-only. pass def drawCatchDisplay(app): # Draw the "you caught it!" popup: the creature's sprite coming out of the # water, plus its name, description, and stats (length, weight, value). # Stays up until dismissed by a click (handled in onMousePress). Read-only. pass def drawHud(app): # Draw the persistent heads-up display: current money, equipped bait, and # any brief status/instruction text ("click to cast", etc.). Overlaid on # every scene so the player always sees their core stats. pass # ============================================================================= # SECTION 6: PROGRAM ENTRY # ----------------------------------------------------------------------------- def main(): # Start the cmu_graphics app (runApp with the chosen window dimensions). pass main()