extends CanvasLayer class_name Receipt ## The incident report. When a meltdown ends, HR itemizes what you broke DURING that ## window and prints it, line by line, on green-bar paper: OBJECT · unit $ · ×N, then ## the total, then DEDUCTED FROM PAY. It's the comedy payoff the payslip earns — a ## reading of score data you already have, with a dot-matrix chirp per line. ## ## No textures, no fonts on disk, no audio assets. Any key or five seconds dismisses it. const UNIT := { "paper": 5, "cardboard": 10, "plastic": 20, "vinyl": 25, "wood": 30, "glass": 40, "steel": 60, "produce": 8, } const LABEL := { "paper": "Loose paper", "cardboard": "Cardboard box", "plastic": "Moulded plastic", "vinyl": "Vinyl record", "wood": "Timber furniture", "glass": "Glazing / bottle", "steel": "Steel fixture", "produce": "Fresh produce", } const LINE_S := 0.11 ## seconds between printed lines var _tally: Dictionary = {} ## kind -> count, for the window in progress var _panel: PanelContainer var _label: Label var _lines: PackedStringArray var _shown := 0 var _tick: Timer var _dismiss: Timer var _chirp: AudioStreamWAV var _printer: AudioStreamPlayer var _active := false func _ready() -> void: layer = 80 visible = false _panel = PanelContainer.new() _panel.anchor_left = 0.5 _panel.anchor_top = 0.5 _panel.anchor_right = 0.5 _panel.anchor_bottom = 0.5 _panel.grow_horizontal = Control.GROW_DIRECTION_BOTH _panel.grow_vertical = Control.GROW_DIRECTION_BOTH var sb := StyleBoxFlat.new() sb.bg_color = Color(0.87, 0.90, 0.80) # green-bar computer paper sb.border_color = Color(0.20, 0.22, 0.16) sb.set_border_width_all(2) sb.set_content_margin_all(18) sb.shadow_color = Color(0, 0, 0, 0.5) sb.shadow_size = 12 _panel.add_theme_stylebox_override("panel", sb) add_child(_panel) _label = Label.new() var mono := SystemFont.new() mono.font_names = PackedStringArray(["Menlo", "SF Mono", "Courier New", "monospace"]) _label.add_theme_font_override("font", mono) _label.add_theme_font_size_override("font_size", 17) _label.add_theme_color_override("font_color", Color(0.12, 0.14, 0.10)) _panel.add_child(_label) _tick = Timer.new() _tick.wait_time = LINE_S _tick.timeout.connect(_print_next) add_child(_tick) _dismiss = Timer.new() _dismiss.one_shot = true _dismiss.wait_time = 5.0 _dismiss.timeout.connect(hide_report) add_child(_dismiss) _chirp = _make_chirp() _printer = AudioStreamPlayer.new() _printer.stream = _chirp _printer.volume_db = -8.0 add_child(_printer) ## Wire: rage.snapped -> begin_window, rage.calmed -> show_report; Main.add() each smash ## that happened while is_meltdown(). func begin_window() -> void: _tally.clear() func add(kind: String, _value: int) -> void: _tally[kind] = int(_tally.get(kind, 0)) + 1 func show_report() -> void: if _tally.is_empty(): return # snapped and calmed without breaking anything — no receipt _lines = PackedStringArray() _lines.append("MONSTER ROBOT PARTY · INCIDENT REPORT") _lines.append("employee outburst — itemized") _lines.append("----------------------------------------") var total := 0 var kinds := _tally.keys() kinds.sort() for k in kinds: var n := int(_tally[k]) var unit := int(UNIT.get(k, 15)) var sub := unit * n total += sub _lines.append("%-18s $%3d x%-2d $%5d" % [LABEL.get(k, k.capitalize()), unit, n, sub]) _lines.append("----------------------------------------") _lines.append("%-28s $%5d" % ["TOTAL DAMAGES", total]) _lines.append("%-28s -$%4d" % ["DEDUCTED FROM PAY", total]) _lines.append("") _lines.append(" [ any key ]") _shown = 0 _label.text = "" visible = true _active = true _dismiss.stop() _tick.start() func _print_next() -> void: if _shown >= _lines.size(): _tick.stop() _dismiss.start() # fully printed — now the 5 s auto-dismiss begins return _label.text += ("" if _shown == 0 else "\n") + _lines[_shown] _shown += 1 if _lines[_shown - 1] != "": _printer.pitch_scale = randf_range(0.96, 1.06) _printer.play() func hide_report() -> void: visible = false _active = false _tick.stop() _dismiss.stop() func _unhandled_input(event: InputEvent) -> void: if not _active: return if (event is InputEventKey and event.pressed) or (event is InputEventMouseButton and event.pressed): # a key mid-print finishes it instantly; a key once printed dismisses it if _shown < _lines.size(): _label.text = "\n".join(_lines) _shown = _lines.size() _tick.stop() _dismiss.start() else: hide_report() get_viewport().set_input_as_handled() ## A short square-wave blip — the sound of an impact printer landing one line. func _make_chirp() -> AudioStreamWAV: var rate := 22050 var n := int(rate * 0.045) var out := PackedFloat32Array() out.resize(n) for i in n: var t := float(i) / float(rate) var env := exp(-t * 55.0) out[i] = (1.0 if sin(TAU * 1400.0 * t) > 0.0 else -1.0) * 0.3 * env var w := AudioStreamWAV.new() w.format = AudioStreamWAV.FORMAT_16_BITS w.mix_rate = rate w.stereo = false var bytes := PackedByteArray() bytes.resize(n * 2) for i in n: bytes.encode_s16(i * 2, int(clampf(out[i], -1.0, 1.0) * 32767.0)) w.data = bytes return w