No description
  • Game Maker Language 84.4%
  • C 5.5%
  • C++ 3.7%
  • Python 3.2%
  • C# 1%
  • Other 2.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-24 15:35:39 +02:00
ext Access Delicious 1: framework for Cook, Serve, Delicious! (speech, text capture, patcher, tools) 2026-09-24 10:36:08 +02:00
gml Battle Kitchen strike stars, difficulty, character select labels; hungry festival unlocks; README status 2026-09-24 15:35:39 +02:00
hotspots Main menu: labels for mail, food icons, slots; Active Menu drag and drop; tutorial pages transcribed; column reading order 2026-09-24 11:21:06 +02:00
installer Release: xdelta3 encoder from the vendored source; CrossOver files in the zip 2026-09-24 12:54:06 +02:00
patch Virtual pointer for the mouse-only menus, save slots, tutorial, orders and prep screens 2026-09-24 11:01:08 +02:00
tools Battle Kitchen strike stars, difficulty, character select labels; hungry festival unlocks; README status 2026-09-24 15:35:39 +02:00
vendor Day events, gauges, special-event status, results; README; CrossOver speech files; test bot 2026-09-24 12:10:03 +02:00
.gitattributes Day events, gauges, special-event status, results; README; CrossOver speech files; test bot 2026-09-24 12:10:03 +02:00
.gitignore Access Delicious 1: framework for Cook, Serve, Delicious! (speech, text capture, patcher, tools) 2026-09-24 10:36:08 +02:00
Makefile Release: xdelta3 encoder from the vendored source; CrossOver files in the zip 2026-09-24 12:54:06 +02:00
README.md Battle Kitchen strike stars, difficulty, character select labels; hungry festival unlocks; README status 2026-09-24 15:35:39 +02:00
run.sh Access Delicious 1: framework for Cook, Serve, Delicious! (speech, text capture, patcher, tools) 2026-09-24 10:36:08 +02:00

Access Delicious 1

Screen-reader accessibility mod for Cook, Serve, Delicious! (the first game; Windows, Steam app 247020, "CSD v3.251F (SDC Edition)", data.win SHA-256 c18adf88…). A sibling of Access Delicious for CSD3 (../access-delicious): same approach (GML injected into the GameMaker bytecode data.win with UndertaleModTool, plus a small DLL speaking through PRISM: NVDA, JAWS, SAPI…), but CSD1's code is entirely different, so all game handlers are new.

Development is on Windows (this machine): the game at C:\Program Files (x86)\Steam\steamapps\common\CookServeDelicious, NVDA running. Game logic questions: read the decompiled code in re/CodeEntries/ (make decompile; local only, not in git), then check in the game (tools/ctl.py, tools/winshot.ps1).

How it works

  • gml/gml_Object_obj_csd1a_*.gml: the controller's events (Create, Begin Step, End Step). Created from initvarsO Create (the first room), persistent.
  • gml/lib/*.gml: all mod functions, as methods on the controller, concatenated alphabetically into Create by the patcher. Create-time statements in a lib file may only use things defined in files that sort before it.
  • ext/accessdelicious.c → accessdelicious.dll (mingw): PRISM speech, the log, the development TCP control server (127.0.0.1:47701). CSD1A_MUTE=1 in the environment: speech is logged, not spoken (automated test runs, so they don't talk over NVDA).
  • patch/patch.csx (UndertaleModCli script):
    1. imports the mod code;
    2. appends the controller's creation to initvarsO Create;
    3. around every instance_deactivate_all (the pause screen, backgroundchangeO): obj_csd1a.before_pause() and re-activates the controller;
    4. rewrites every draw_text* call to obj_csd1a.dt_text*(object_index, ...) (text capture); draw_sprite(arrow<dir>S, ...) (arrow-key bindings in the key legends) to dt_arrow;
    5. rewrites every mouse_x / mouse_y in the game's code to global.csd1a_mx/my (the virtual pointer).
  • hotspots/gen.py → gml/lib/hotspots.gml (generated, committed): the clickable spots.

The virtual pointer (the menus are mouse-only)

With keyboard and mouse, CSD1's menus have no keyboard navigation at all (only a gamepad cursor, which GML can't fake). Every object tests rectangles in its global-click event: if (mouse_x > A && mouse_y > B && mouse_x < C && mouse_y < D && ...) inside screen-state conditions. hotspots/gen.py turns each object's Mouse_53 into a function that keeps the control flow, drops the actions, and calls hs_add(rect) where a click would do something in the current state. Temporaries the event assigns and then tests (LVkeepgoing) become locals. At runtime (lib/pointer.gml):

  • spots = those functions run on each live instance + instances with their own click event (hs_inst_objects: email rows and folders, food icons, bubbles, tickets);
  • Arrows move to the nearest spot in that direction (45° cone, then 60°); Tab / Shift+Tab go through them in reading order (loose spots, then columns top to bottom, grids row by row); Enter clicks: the game's global and instance left-press events, release 2 frames later;
  • the pointer sets global.csd1a_mx/my, so the game's hover logic (Step) sees it; moving the real mouse hands control back to it. The real cursor never moves;
  • labels: a per-object describer (hs_describers, in screens_*.gml) for state drawn as pictures, else the text whose box centre (from font, scale and alignment at draw time) is inside the spot, else text just to its right (checkboxes);
  • after a click, a spot whose label changed (a toggle) is re-read;
  • drag and drop (Active Menu): Enter on a food picks it up (press only; the icon follows mouse_x), Enter on a slot drops it (release after the icon has touched the slot).
  • Allowed everywhere except during play (arrows and Enter cook); in a day only on the results screen, special-event cards, the pause screen (the day is deactivated) and the two tutorial slides that teach the mouse.

Modules (gml/lib)

file covers
text.gml text capture (text_of(obj, age), text_new, box centre per entry), grace 12 frames
fallback.gml speaks new drawn text (batched, top to bottom); clean_text (# line breaks, "(SL)", "click to continue")
pointer.gml the virtual pointer (above)
hotspots.gml generated by hotspots/gen.py
screens_title.gml title, save slots (day, money, stars, Extreme), delete/restore modes, options
screens_menu.gml main menu: tutorial pages (pictures, transcribed), food icons (name, price, owned, stars), Active Menu slots, mail rows and folders, booster/detractor bubbles, toggles, Shift+S
screens_day.gml spot labels in a day: corner toggles, pause button, tickets
tutorial.gml opening tutorial: Enter on "click to continue" slides, keyboard hints for the mouse slides
orders.gml tickets: new, leaving (under 3 s of patience), ready to serve / to prep (blue vs yellow foods), burnt, lost; results (Perfect/Average/Bad chimes); Shift+O, Shift+number, Shift+S (also special events)
prep.gml the open ticket: recipe, key legend (letters and arrow sprites), Enter/Space action; placed ingredients; page turns; gauges (fryer done/burning, beer fill verdict)
day_events.gml flashing words (open, closed, rush hour), the hour, inspector, VIP, robbery verdict, photo chore's food
settings.gml ini settings, hotkeys, per-handler error isolation, help
ctl.gml development control commands

Keys (mod)

  • Menus: arrows / Tab / Shift+Tab move, Enter clicks (Active Menu: Enter picks a food up, Enter on a slot drops it; Enter elsewhere takes it off the menu).
  • Day: the game's keys (number keys open orders, letters add ingredients, Enter serves, Esc pauses). Shift+O all orders · Shift+number one order (state, seconds left, heat) · Shift+K the open order's keys · Shift+W what it wants · Shift+S time, money, buzz, results (special events: served, strikes, wave, timer).
  • Anywhere: Shift+R read the screen · Shift+H help · Shift+= / Shift+- speech rate (SAPI only) · Left Ctrl stop speech.

Build, deploy, run, test

Tools on this machine: msys2 mingw64 gcc + mingw32-make (tools/make.sh puts them on PATH), UndertaleModCli 0.9.2.0 in ~/tools/utmt, Python 3.

tools/make.sh            # dist/: accessdelicious.dll, patched data.win, prism files
tools/make.sh deploy     # closes the game, copies dist/ into the game folder
tools/make.sh restore    # the original data.win back (orig/data.win: untouched copy, not in git)
tools/make.sh decompile  # re/ from orig/data.win
CSD1A_MUTE=1 ./run.sh    # relaunch the game (Steam must be running), wait for the controller
  • Log: <game folder>/accessdelicious.log (previous run .log.1).
  • tools/ctl.py <cmd>: ping, room (also game speed: 30 fps), insts, vars <Obj|id|global> [prefix], get, gml_set, screen [obj], hs (the pointer's spots and labels), orders, order <n>, prep, status, say.
  • tools/keys.py: presses keys in the game window without focusing it (PostMessage); down@1.4 holds a key. (ctl.py key needs the game focused.)
  • tools/goto.sh "<regex>" [enter]: Tab until the pointer says a matching label.
  • tools/fresh.sh (empties save slot 1 through the game's Delete Saves: Steam Cloud restores deleted files otherwise), tools/to_menu.sh (new game, skip tutorial, Management), tools/day1.sh (…buy three foods, Active Menu, start day 1), tools/bot.py [secs] (plays a day from the mod's speech).
  • tools/winshot.ps1 [out.png]: screenshot of the game window.
  • Saves: %LOCALAPPDATA%\CSDSteamBuild\Ndata<n>file.ini (+ Steam Cloud Cdata<n>file.ini).
  • Release: tools/make.sh release VERSION=x.y → build/AccessDelicious1-x.y.zip (installer with the xdelta3 decoder, delta from orig/data.win, DLLs). Needs an xdelta3 encoder (XDELTA=).

UndertaleModTool compiler traps

Same as CSD3 (see its README), plus: no local named like a built-in (score, id); no indexing a call result (f()[1]); a literal newline inside a string breaks the build (write \n). Scripted edits from Python on Windows: write with newline="\n" and beware "\b" in non-raw strings (a backspace ends up in the file).

Game facts worth knowing

  • Game speed 30 fps; action_set_alarm(steps, n) means alarm[n] = steps; numeric object ids in the code are one higher than __global_object_depths names: use object_get_name.
  • A ticket is its food object (<CODE>_barO, e.g. BUGR_barO), in slot Lwhichprepstationvar (keys 1-9; slot 0 has no key). Lstatusvar: 0 waiting, 1 prep stage one, 2 on the heat, 3 prep (second or only stage), 4 done/leaving. One open at a time (Gfoodbeingpreppedvar). Lcookingvar 9..34 done, 35+ burnt. Blue (back to prep when cooked): burger, nachos, pasta, pancakes, lobster, baked potato; the rest are served by selecting them (yellow).
  • Patience: alarm[0] = Gcustomerwaitvar (a couple of seconds), then the ticket slides left (gravity 0.005) and is lost when wholly off screen.
  • Prep screen text: title (280,565), wants (280,605), legend key at x 900/1100 with the name 35 px right, "Enter"/"Space" + "to serve"/"to cook" near (1115,488). Mistakes are not shown at all.
  • Chores (W_*_barO) share the slots and Lstatusvar (0/3/4); prompts are drawn text.
  • Main menu screen: global.Gwhichmenuvar (table in screens_menu.gml). Food ids: 1-20, 1001-1010 (grid icons 21-30 = 1001-1010). GT_AMslot1..6var = the Active Menu.
  • Results screen (GTdayfinishedvar == 2) is drawn text; its Continue is mouse-only.

Tested in play

Tutorial; career day 1 (full day, results, checklist); buying, upgrading, equipment, not enough money; Active Menu; mail; options; key binding; catering, Iron Cook (waves), Hungry Festivities (and unlocking with tickets), Battle Kitchen strike challenge (character select); chores: restroom, trash, dishes, rodents, robbery, photo, texting; the inspector; rush hour; fryer foods, beer, soda, soup, pizza, pasta, burger, ice cream. tools/ctl.py spawn <W_*_barO> puts a chore in the first free slot (testing).

Next

  • Not heard yet: VIP taster, Battle Kitchen endurance / eSports / mystery box / co-op, the character wheel, Daily Special, CookBets, dating emails' buttons.
  • Pictures not read: Credits, Battle Kitchen help pages, food pin / checklist done marks.
  • Beer: a timing cue better than the after-the-fact verdict (the perfect window is 5 frames).
  • The last strike of a failed event is not said (the result card says it).