2026-07-14 19:14:49 -04:00
|
|
|
# mcrf: objects=[Caption,Color,Frame,Scene,Sprite] verified=0.2.8-dev status=ok
|
test(snippets): the docs site's 130 code samples are now part of the test suite
The samples published on mcrogueface.github.io were executed by nothing at all.
Each carried a machine-readable header -- objects=[...] verified=0.2.8@b6720f6
status=ok -- and every one of those fields was hand-typed. 130 snippets asserted
"status=ok" while no run had ever confirmed it. This is the same failure mode as
the 82 rotted tests in 112f357, at a larger scale and with no gate whatsoever.
The samples now live here, in the engine repo, so that breaking the API breaks the
build. The site pulls them from tests/snippets/ rather than keeping a copy to rot
in parallel (build_library.py, site-side).
They are display scripts: each builds a scene and stops. They deliberately do NOT
call sys.exit(), because they must stay copy-pasteable -- a reader who pastes one
into their game should get a running scene, not an interpreter that quits. Since
#350 that also makes them un-runnable on their own, so _harness.py is chained as a
second --exec to supply the ending the snippet must not have. Chaining rather than
exec()-ing the source is deliberate: the snippet travels the same path a real
user's script travels, and nothing has to read the file -- which is how the first
draft of this harness tripped over #378 and mistook three healthy snippets for
broken ones.
A snippet passes only if it runs clean AND leaves a scene with something in it.
Not raising is not enough: a sample whose body silently no-ops still renders as
code on the docs site, and would still be wrong.
tools/stamp_snippets.py makes the header a measurement instead of a claim: status
comes from an actual run, verified from the engine that ran it, and objects is
derived from the source intersected with what the engine exports -- so a snippet
that starts using a new type gets tagged for it without anyone remembering to. It
immediately found tags the humans had missed (062 uses Transition, Key and
InputState; the hand-written header listed none of them). --check is the CI gate.
The gate earned its keep on the first run, catching #379 (fixed here): configuring
default_transition before the first scene activation made the engine transition
FROM the internal "uitest" bootstrap scene, which is not a PyScene and has no
Python wrapper -- so mcrfpy.current_scene reported None for the transition's full
duration, immediately after the user had assigned it. A transition with nothing
meaningful to transition from now changes scene immediately. Scene-to-scene
transitions still report the outgoing scene until they complete.
Suite: 468/468 (336 + 130 snippets + 2 regressions).
closes #379
2026-07-14 18:29:37 -04:00
|
|
|
# Game Inventory - Grid-based inventory UI
|
|
|
|
|
import mcrfpy
|
|
|
|
|
|
|
|
|
|
scene = mcrfpy.Scene("demo")
|
|
|
|
|
mcrfpy.current_scene = scene
|
|
|
|
|
|
|
|
|
|
scene.children.append(mcrfpy.Frame(pos=(0, 0), size=(1024, 768), fill_color=mcrfpy.Color(30, 30, 40)))
|
|
|
|
|
|
|
|
|
|
# Inventory grid
|
|
|
|
|
inv_frame = mcrfpy.Frame(
|
|
|
|
|
pos=(262, 184), size=(500, 400),
|
|
|
|
|
fill_color=mcrfpy.Color(40, 40, 60),
|
|
|
|
|
outline=3.0, outline_color=mcrfpy.Color(100, 100, 140)
|
|
|
|
|
)
|
|
|
|
|
scene.children.append(inv_frame)
|
|
|
|
|
|
|
|
|
|
inv_frame.children.append(mcrfpy.Caption(text="Inventory", pos=(200, 20)))
|
|
|
|
|
|
|
|
|
|
# Create inventory slots
|
|
|
|
|
slots = []
|
|
|
|
|
items = [84, 17, 65, 0, 0, 0, 112, 0, 88, 0, 0, 0] # Sprite indices, 0 = empty
|
|
|
|
|
|
|
|
|
|
for i in range(12):
|
|
|
|
|
x = 30 + (i % 4) * 115
|
|
|
|
|
y = 70 + (i // 4) * 100
|
|
|
|
|
|
|
|
|
|
slot = mcrfpy.Frame(
|
|
|
|
|
pos=(x, y), size=(90, 80),
|
|
|
|
|
fill_color=mcrfpy.Color(60, 60, 80),
|
|
|
|
|
outline=2.0, outline_color=mcrfpy.Color(80, 80, 100)
|
|
|
|
|
)
|
|
|
|
|
inv_frame.children.append(slot)
|
|
|
|
|
|
|
|
|
|
if items[i] > 0:
|
|
|
|
|
sprite = mcrfpy.Sprite(
|
|
|
|
|
texture=mcrfpy.default_texture,
|
|
|
|
|
sprite_index=items[i],
|
|
|
|
|
pos=(25, 15),
|
|
|
|
|
scale=3.0
|
|
|
|
|
)
|
|
|
|
|
slot.children.append(sprite)
|
|
|
|
|
|
|
|
|
|
# Hover effect
|
|
|
|
|
def make_hover(s):
|
|
|
|
|
def enter(pos): s.fill_color = mcrfpy.Color(80, 80, 100)
|
|
|
|
|
def exit(pos): s.fill_color = mcrfpy.Color(60, 60, 80)
|
|
|
|
|
return enter, exit
|
|
|
|
|
|
|
|
|
|
enter, exit = make_hover(slot)
|
|
|
|
|
slot.on_enter = enter
|
|
|
|
|
slot.on_exit = exit
|
|
|
|
|
|
|
|
|
|
status = mcrfpy.Caption(text="Hover over slots to highlight", pos=(400, 620))
|
|
|
|
|
status.outline = 2
|
|
|
|
|
status.outline_color = mcrfpy.Color(0, 0, 0)
|
|
|
|
|
scene.children.append(status)
|