DuelMatch
The umpire nobody sees. One instance, on the `DuelDirector` entity.
DuelMatch
The umpire nobody sees. One instance, on the DuelDirector entity.
Asks garden for the walled garden and the boundary fence, spawns the rival,
resolves every exchange between the two Fencers through duel.resolveTouch,
plants a post and drives the property line into the loser's garden on a touch,
resets both fencers and runs the salute, and calls the match when the line
reaches a hedge.
The boundary is the health bar: line is the fence's leading post, and the
fence is rebuilt from the player's hedge out to it whenever line changes, so
the score is a physical object standing in the world.
What a touch is worth
How far a post drives the line is duel.postDrive, and it is a property of the
ground rather than a constant: fresh lawn in the middle of a garden gives, the
last feet before a hedge are rooted and stubborn, lawn already conceded holds
somebody else's posts and has to be cleared before the line passes back over it,
and every post driven breaks the ground a little further for the next one.
postsDriven counts the posts this bout and lastDrive reports the metres the
last one bought. Between them these are what give a bout a length rather than
only a variance.
Resolution
An attack whose blade is live inside its measure is an exchange. Two live
blades in the same tempo is a clash: neither scores and both pay for it,
which is what stops the umpire's own resolution order from deciding the bout.
An attack outside its measure is recorded as SHORT or CROWDED and never
touches its man, so the fencer who threw it pays the whiff debt.
A touch taken inside a riposte window plants RIPOSTE_POSTS posts rather than
one, and lastPosts reports which it was.
The event bus
fxEvent names the moment and fxSeq moves on every write, including a
repeat of the same event — so a reader polls fxSeq against the last one it saw
rather than diffing fields for edges. Vocabulary: salute, allez,
short:player, short:rival, clash, parry:player, parry:rival,
riposte:player, riposte:rival, touch:player, touch:rival, post,
over:player, over:rival. ":player" means the player did it.
fxQueue is the lossless read of the same vocabulary: every event since the
last frame, in the order it happened. DuelMatch empties it at the top of its
own update, and it runs before everything that reads it, so a reader gets the
whole of this frame's list — including a touch:player and the post that
follows it in the same frame, which a single slot cannot carry.
The roster
neighbour (1..3), neighbourKey ("pettifer" | "wickham" | "ashcombe")
and skill are one identity written three ways. Writing any of them settles the
other two off duel.NEIGHBOURS and pushes the matching style onto the live
rival's FencerAI, so a garden, a turnout and a verdict can all name the same
person without any of them guessing. DuelHud keeps ownership of the prose.
Fields
line, state (salute | fence | touch | over), lastTouch, winner,
playerTouches, rivalTouches, skill (the rival's quality — writing it
retunes the live rival), announce, lastPosts, postsDriven, lastDrive,
matchClock (seconds since this bout's first allez), neighbour,
neighbourKey, fxEvent / fxSeq / fxQueue, and lastExchange /
lastExchangeSeq / exchanges — the tuning record, naming who struck into what
and what the triangle made of it, including attacks that fell short of their
reach or were smothered inside it.
Method
restart() — a fresh assize, the line back to nought. Callable at any time,
including from state == "over", where the restart action also reaches it.
Pairs with DuelHud on the same entity. Requires the duel and garden
modules and @builtin::modules.zinput.
Scoped to this part · feeds back into the world's score.