Skip to content

Commit 7c89cef

Browse files
committed
pyDuckHunt: bring the beta flock under the right spells 🦆🪄
Make the accumulated beta gameplay fixes consistent across live commands, private administration, player profiles, ranking pages and durable replay. - Keep a fixed 24-flight daily base and restore hourly Tcl bread attraction with longer new flights, expiry-aware replanning and durable paid calls. - Bind Owner commands to stable IRC identities and keep planning and item administration private, with complete partyline and debug visibility. - Apply shared fatigue, overexcitation and calculated scope accuracy; set new thermos purchases to -3 fatigue and shorten item confirmations. - Count three noisy misses per ordinary duck, preserve silence and target immunity, and use the proper explosive-hit and missed-shot feedback. - Add consistent operator exclusions, responsive ranking cards and complete inventory previews without removing player history. - Preserve historical settlements and checkpoints through schema 23, and consolidate documentation around the final beta rules. Validate the complete candidate with one visible full lane before committing. Keep VERSION at 0.1.0-dev; no stable release or tag is created.
1 parent fb7bf39 commit 7c89cef

67 files changed

Lines changed: 4166 additions & 397 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,69 @@
11
# Changelog
22

3-
All notable changes to pyDuckHunt will be documented in this file.
3+
All notable changes to pyDuckHunt are documented here. The project remains beta;
4+
these changes do not create a stable release or a tag.
45

56
## Unreleased
67

8+
### Scheduling and channel items
9+
10+
- Fix the daily base at 24 flights regardless of activity, retaining replay of
11+
historical 18- and 21-flight plans. Upgrade those plans with future slots.
12+
- Restore Tcl 2.11 method-2 bread: each piece lasts one hour across flights
13+
and adds 20 seconds to every new duck's lifetime. Adding or expiring bread
14+
redraws 24 + active-piece slots (up to 20 pieces); preserve the next deadline
15+
on addition and partial expiry. An existing duck's deadline stays unchanged.
16+
Attraction does not guarantee an extra flight during the bread's hour.
17+
- Apply the same item effects to player purchases and Owner commands. Bread
18+
retains its 4 XP price and +2 temporary karma; no takeoff consumes a piece.
19+
- Wake paid duck calls and mechanical actions at their recorded deadlines,
20+
keep them while another flight is active, and consume one only when its
21+
matching flight starts. Bread expiry and replanning cannot discard a call.
22+
- Bind Owner permissions to the IRC account or registered ident@host rather
23+
than the current nickname. Owner bread and call replies, including refusals,
24+
stay private. Player replies expose no exact future flight time.
25+
- Add Owner-only channel/PM duckplanning NOTICE views and partyline
26+
`.duckplanning`, listing every slot in Europe/Paris, actual wake-up, pending
27+
actions and bread expiry. Refresh partyline/debug facts when those change;
28+
elapsed slots in a redrawn plan are not presented as real hunting history.
29+
30+
### Accuracy, fatigue and shot feedback
31+
32+
- Share one accuracy calculation between live shots and player profiles.
33+
Fatigue above 12 costs three accuracy points per extra fatigue point;
34+
endurance suppresses the penalty. Show the final probability and relevant
35+
fatigued marker without claiming fatigue caused any particular miss.
36+
- Make new 10 XP thermos purchases set fatigue to -3.00 and show before/after
37+
values. Each negative point costs three accuracy points; show overexcitation
38+
in profiles, inventory and affected shots. Keep fixed-point arithmetic.
39+
- Compute scope bonuses as floor((100 - base accuracy percent) / 3), including
40+
equipped scopes and loot. Level 9 receives +11 points. Preserve the 5 XP
41+
price and six uses; keep purchase/loot messages concise and document the formula.
42+
- Count three unsuppressed misses per ordinary duck, shared across hunters,
43+
as configured in the supplied Tcl 2.11. Silencers and silent weapons do not
44+
add noise; golden and mechanical ducks are immune to noise escape.
45+
- Use plain missed-shot feedback. Explosive impacts use BOUM and triple damage;
46+
golden impacts retain ammunition markers. Verify the lucky charm adds its
47+
actual bonus: a standard 10 XP duck with a +6 charm awards 16 XP.
48+
49+
### Ranking, statistics and durability
50+
51+
- Add an RFC1459-aware exclusion list for non-playing operators across IRC,
52+
partyline, generated ranking and aggregate metrics, without deleting history.
53+
- Give the generated ranking a hover/focus/touch inventory view, eleven compact
54+
desktop columns and responsive player cards without hidden statistics.
55+
- Extend persistence through schema 23 for Owner channel items, hourly bread,
56+
settled fatigue/scope rules and counted duck noise. Preserve historical
57+
outcomes and authoritative schema-21/22 checkpoints; new counters survive restart.
58+
- Update configuration examples and game/operator documentation. The separately
59+
deployed shop catalog follows the bread, scope and thermos descriptions in
60+
`docs/SHOP.md`; its static deployment assets are outside this repository.
61+
62+
## Initial public beta — 2026-09-07
63+
64+
The following entries describe the foundation committed in `fb7bf39`. Rules
65+
superseded by the Unreleased section are retained here as development history.
66+
767
### Fixed
868

969
- Partyline recovery is now possible without deleting its private identity

‎README.md‎

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ Observed unusual rewards now include durable shop vouchers, bounded promotion
102102
coupons, abundance, endurance, blessing, baker and prankster amulets. Their
103103
effects compose with purchases, fatigue, curses and channel actions while the
104104
uncalibrated unusual-drop frequency remains explicitly disabled. A pure runtime
105-
policy validates adaptive 24-, 21- or 18-deadline daily plans, the one-in-eighteen golden
105+
policy fixes new daily plans at 24 deadlines, retains replay compatibility for
106+
historical 18- and 21-deadline plans, preserves the one-in-eighteen golden
106107
weight, golden health and the five-minute flight lifetime without reading a
107108
clock or drawing randomness inside the game engine.
108109
The observed permanent protection set now also covers indestructible
@@ -152,6 +153,31 @@ updates. Its least-privilege publication pattern keeps Coin outside the Apache
152153
document root and delegates one validated root-owned file replacement to a
153154
hardened path/`oneshot` pair. See `docs/RANKING_PAGE.md`.
154155

156+
## Current beta gameplay
157+
158+
The daily base is fixed at 24 flights. Active bread lasts one hour across
159+
flights, adds 20 seconds per piece to new ducks and replans method-2 attraction
160+
at 24 + active pieces (up to 20 pieces). The next deadline is preserved on
161+
addition and partial expiry; attraction guarantees no extra flight within the
162+
hour. Paid calls wait durably for an available flight slot. See
163+
[Channel actions](docs/CHANNEL_ACTIONS.md).
164+
165+
Owner-only `!duckplanning`, private-message `duckplanning` and partyline
166+
`.duckplanning` expose every planned time and pending action. Owner item replies
167+
stay private. Player replies reveal no exact future takeoff time.
168+
169+
Profiles show the current scope, fatigue and overexcitation modifiers used by
170+
live shots. Scope purchases keep six uses and a calculated bonus; new thermos
171+
purchases set fatigue to -3.00. Ordinary ducks flee after three unsuppressed
172+
misses, while golden/mechanical ducks are immune to noise. Silencers and silent
173+
weapons prevent noise. See [Shop rules](docs/SHOP.md) and
174+
[Player profiles](docs/PLAYER_PROFILE.md).
175+
176+
The generated ranking provides responsive player cards and complete inventory
177+
previews. An optional exclusion list keeps non-playing operators out of every
178+
statistical view without erasing their records. State schema 23 retains old
179+
replay decisions and preserves new counters and effects across restarts.
180+
155181
## Requirements
156182

157183
- Python 3.11 or newer

‎config/pyduckhunt.example.toml‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ log_directory = "logs"
1919

2020
[game]
2121
enabled = false
22-
flights_per_day = 18
22+
flights_per_day = 24
2323
golden_weight_per_eighteen = 1
2424
flight_lifetime_seconds = 300
2525
# Kept at zero until an unusual-loot frequency is approved for the pilot.
@@ -30,6 +30,9 @@ anti_cheat = false
3030
shop_url = ""
3131
# Empty keeps !duckrank link-free until an operator publishes a ranking page.
3232
ranking_url = ""
33+
# Optional RFC1459 identities omitted from rankings and aggregate statistics.
34+
# Historical journal records remain intact.
35+
statistics_excluded_nicknames = []
3336

3437
[partyline]
3538
# Disabled for fresh installs. The beta deployment binds this listener to loopback.

‎docs/CHANNEL_ACTIONS.md‎

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,42 @@
1-
# Scheduled channel actions
1+
# Bread and scheduled channel actions
22

3-
Channel-wide purchases that create a future event are durable game facts rather
4-
than in-process timers. Each scheduled action carries a monotonic identifier,
5-
the catalog item, its source player, creation time and exact due time.
3+
Live bread follows the reference method-2 behaviour. Each item-21 purchase
4+
costs 4 XP, grants +2 temporary karma and creates an independent one-hour effect.
5+
Owner bread uses the same channel effect without charging a player. A maximum
6+
of 20 active pieces is accepted for new player and Owner requests; refusals do
7+
not spend XP. Existing historical surplus is retained until expiry, with the
8+
attraction count capped at 20.
69

7-
The duck call accepts an injected deadline strictly after purchase and no later
8-
than ten minutes afterward. The mechanical duck always uses an exact ten-minute
9-
delay. The caller resolves the variable call delay before settlement, and the
10-
journal records that concrete deadline so recovery never samples it again.
10+
Bread remains in place across every successful flight during that hour. At each
11+
new takeoff, the engine adds 20 seconds per active piece to the flight's normal
12+
lifetime, including called, mechanical and Owner flights. Adding or expiring
13+
bread does not change the expiry of a duck already in flight. No piece is eaten
14+
or removed by takeoff and no false consumption announcement is emitted.
1115

12-
Advancing the game clock removes every due action and emits one
13-
`channel_action_due` outcome. Simultaneous actions are ordered by due time and
14-
then identifier. A later runtime dispatcher will translate those outcomes into
15-
real or mechanical flights; no timer, socket or channel operation exists in the
16-
game engine.
16+
The scheduler's fixed base is 24 slots per UTC day. Adding bread or expiring a
17+
piece redraws a whole-day plan of 24 + active pieces. Hours are selected without
18+
replacement, resetting the hour pool when exhausted; minutes are unique within
19+
the resulting day. The nearest existing future time is retained on addition,
20+
and also on expiry while at least one piece remains. When the last piece
21+
expires the plan is redrawn with 24 slots. This is attraction, not a guarantee
22+
of an additional duck during the hour. Past times in the newly drawn plan are
23+
not fired retroactively. Existing UTC boundaries and Europe/Paris display are
24+
preserved; the underlying reference scheduling method is used without changing
25+
the bot's operating timezone or configured base quota.
1726

18-
The duck detector is a player-scoped one-use effect. A successfully started
19-
flight consumes every waiting detector and emits a private-alert outcome. A
20-
rejected start while another flight is active consumes nothing. IRC NOTICE
21-
routing is performed once per detector owner by the runtime scheduling adapter.
27+
Expiry participates in the runtime wake-up even without chat activity. Bread
28+
fingerprints and concrete plan draws are journaled; reconnecting or restarting
29+
with unchanged bread does not redraw the schedule. Paid duck calls and mechanical
30+
actions remain queued across bread expiry/replanning, including while another
31+
flight blocks them. A successful matching start completes only one due action.
2232

23-
Channel bread is also tied to a successful start: one active stack is consumed,
24-
oldest activation and then lowest identifier first. Other active stacks remain
25-
available until a later flight or their independent one-hour deadline. Rejected
26-
starts consume no bread.
33+
The detector retains its one-shot private alert contract. All precise planning,
34+
expiry and delay diagnostics go to the Owner NOTICE, partyline or application
35+
log. Player confirmations contain durations and effects, not takeoff times.
36+
37+
The first live scheduler step writes an explicit `enable_hourly_bread` event.
38+
Before that event, old purchases and flights replay their original one-hour /
39+
one-consumption semantics. Existing flight deadlines and old player scores are
40+
not recalculated. New `replan_bread_schedule` events contain the chosen deadlines.
41+
Schema 22 carries the optional bread plan fingerprint; schema-21 checkpoints
42+
remain authoritative and byte-identical old event payloads remain valid.

‎docs/CONFIGURATION.md‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,18 @@ keeps public export disabled. See `RANKING_PAGE.md` for the publication boundary
2424
The metrics path receives only aggregate, bounded-cardinality observations; its
2525
omission disables Prometheus export. See `METRICS_GRAFANA.md`.
2626
Game configuration keeps the
27-
adaptive 24/21/18-flight schedule, one-in-eighteen golden weight, five-minute
27+
fixed 24-flight schedule, one-in-eighteen golden weight, five-minute
2828
flight lifetime and disabled unusual-loot boundary exact. Its optional
2929
`shop_url` is either empty or omitted, which keeps `!shop` link-free, or one
3030
bounded credential-free HTTPS URL selected by the operator. The optional
3131
`ranking_url` follows the same strict HTTPS boundary. Empty or omitted keeps
3232
`!duckrank` link-free; when configured, it points players to the separately
3333
published complete ranking without coupling IRC rendering to its deployment
34-
hostname. The optional
34+
hostname. `statistics_excluded_nicknames` is an optional array of unique
35+
RFC1459 identities. It removes non-playing operators from IRC rankings, direct
36+
`!duckstats` lookup, the partyline summary, the generated HTML page and
37+
aggregate Prometheus player statistics; it never deletes or rewrites their
38+
durable history. The optional
3539
`anti_cheat` truth value defaults to false. A live operator may enable it to
3640
draw independently randomized flight trails, silhouettes and utterances from
3741
the same operating-system-backed bounded integer source used by runtime

‎docs/PARTYLINE.md‎

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ appearance. A disconnected bot, missing channel, active flight or persistence
143143
backpressure skips that occurrence and draws a new full interval; it never
144144
polls aggressively or catches up with a burst. This transient timer changes no
145145
durable daily-schedule cursor, while the accepted flight itself uses the same
146-
journaled transition, bread consumption and detector notices as `.duck`.
146+
journaled transition, bread lifetime effects and detector notices as `.duck`.
147147

148148
## Replayable player administration
149149

@@ -182,15 +182,18 @@ least 12 characters. No password is written to application logs.
182182

183183
## Owner commands on IRC
184184

185-
The partyline owner may issue two narrowly scoped commands in a channel Coin is
185+
The partyline owner may issue these narrowly scoped commands in a channel Coin is
186186
currently joined to:
187187

188188
```text
189189
!rearm <nick>
190190
!unarm [-permanent] <nick>
191+
!pain
192+
!appeau
193+
!duckplanning
191194
```
192195

193-
The same controls are available by private message, without the public-command
196+
The weapon controls are also available by private message, without the public-command
194197
prefix:
195198

196199
```text
@@ -211,6 +214,29 @@ carry the owner handle in an `admin_weapon_control` journal event, broadcast to
211214
the partyline and acknowledge the result in the IRC channel or by private
212215
NOTICE, matching the command scope.
213216

217+
`!pain` adds one stack of the same one-hour channel bread as `!shop 21`.
218+
`!appeau` schedules the same within-ten-minutes duck call as `!shop 20`.
219+
Neither command charges XP or creates a player profile. Bread updates attraction
220+
and redraws the plan; a duck call keeps its separate scheduled deadline. Each accepted action is attributed to the authenticated owner in an
221+
`admin_channel_item` journal event; unauthorized attempts remain silent.
222+
Both commands always acknowledge privately by NOTICE to the current authenticated
223+
sender nickname, including usage and refusal messages. The exact call deadline
224+
is shown only to the Owner in Europe/Paris time and can be deferred by an active
225+
flight. Channel observers receive no administrative item acknowledgement.
226+
227+
Player purchases `!shop 20` and `!shop 21` retain public gameplay confirmations.
228+
An appeau reports only an approximate ten-minute window, as in Tcl 2.11; it never
229+
reveals a timestamp or the daily schedule. Live hourly bread remains in place at takeoff; no consumption message is emitted. Inventory and catalog queries remain
230+
private notices without exposing pending call deadlines.
231+
232+
`!duckplanning` is accepted only from the registered Owner in a joined channel
233+
and always answers privately by NOTICE. `/msg Coin duckplanning` provides the
234+
same private view. It lists every daily flight in Europe/Paris time, the daily
235+
cursor, effective runtime wake-up, active flight, bread stacks and every pending
236+
duck call. The partyline command `.duckplanning` renders the same view. Coin
237+
also broadcasts the refreshed view to authenticated partyline sessions whenever
238+
the durable bread or channel-action set changes.
239+
214240
The same owner identity may launch a flight privately:
215241

216242
```text
@@ -252,3 +278,10 @@ hours. Enabling the partyline requires at least one bootstrap identity. The list
252278
before the IRC adapter and any bind failure stops startup rather than silently
253279
running without the expected administration path. Shutdown closes partyline
254280
and DCC sockets before persistence is drained.
281+
282+
With hourly bread enabled, `duckplanning` lists every time in the current plan,
283+
its 24-slot base and active-bread contribution. Passed times refer to the current
284+
redraw, not to a retrospective count of actual launches. Bread expiry appears
285+
in the effective wake-up time. Addition and expiration automatically refresh
286+
the private partyline plan. Owner `!pain` explains the one-hour lifetime and the
287+
20-second per-piece extension of subsequent flights, in private NOTICE only.

0 commit comments

Comments
 (0)