Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/games.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,10 @@ username hit a duck in the flock for 1 damage! It has 0 HP left. +10 XP

The active-duck announcement stays compact for terminal clients: `\_o< QUACK!`.
When IRC colors are supported, the duck uses a soft tan approximation, green
head, and yellow bill. The `GOLDEN DUCK` label is reserved for hit, befriending, and
escape messages, where it is shown in yellow; it is not inserted into the duck
ASCII itself.
head, and yellow bill. The exact `GOLDEN DUCK` label is reserved for hit,
befriending, escape, and achievement messages, where it is shown with IRC's
gold/yellow color code; it is not inserted into the duck ASCII itself. Clients
without color support still receive the same readable label.

Before the duck appears, GoBot may send one randomly timed, colorized teaser
such as a flight trail, quack, or flap. There is at most one teaser per hunt
Expand Down Expand Up @@ -402,7 +403,7 @@ achievements include Golden Slayer, Golden Companion, Flock Buster, Deadeye
Duck, Pond Patroller, Quackstorm, Willow Whisperer, Marsh Marksman, and Golden
Arsenal. Long-term achievements include Wing Commander, Legendary Slayer, Pond
Peacemaker, Friend of All Feathers, XP Voyager, and Point Hoarder. Golden Duck
phrases in achievement messages are highlighted in yellow. Use
phrases in achievement messages are highlighted in gold. Use
`!achievements [nickname]` to view unlocked achievements; `!duckstats` also
shows the unlocked/total count. Existing players begin with zero achievements
and can earn them without losing any existing progress.
Expand Down
8 changes: 5 additions & 3 deletions plugins/duckhunt.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ type duckAchievementEvent struct {
BoughtGoldenWeapon bool
}

const goldenDuckLabel = "GOLDEN DUCK"

var duckAchievementCatalog = []duckAchievementDefinition{
{Key: "first_shot", Name: "First Shot", Description: "Landed your first hit"},
{Key: "first_quackdown", Name: "First Quackdown", Description: "Killed your first duck"},
Expand Down Expand Up @@ -1127,8 +1129,8 @@ func duckAchievementCondition(key string, player duckPlayer, kills, friends uint

func formatDuckAchievement(nick string, achievement duckAchievementDefinition) string {
description := achievement.Description
if strings.Contains(description, "GOLDEN DUCK") {
description = strings.Replace(description, "GOLDEN DUCK", ircColor(ircYellow, "GOLDEN DUCK"), 1)
if strings.Contains(description, goldenDuckLabel) {
description = strings.Replace(description, goldenDuckLabel, ircColor(ircGold, goldenDuckLabel), 1)
}
return fmt.Sprintf("%s %s unlocked: %s - %s", ircColor(ircGreen, "[Achievement]"), ircColor(ircCyan, nick), ircColor(ircYellow, achievement.Name), description)
}
Expand Down Expand Up @@ -1898,7 +1900,7 @@ func xpToNextLevel(xp int64) int64 {

func duckName(state *duckHuntState) string {
if state != nil && state.golden {
return "the " + ircColor(ircYellow, "GOLDEN DUCK")
return "the " + ircColor(ircGold, goldenDuckLabel)
}
if state != nil && state.flockRemaining > 1 {
return ircColor(ircCyan, "a duck in the flock")
Expand Down
22 changes: 19 additions & 3 deletions plugins/duckhunt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestDuckHuntGoldenAchievementColorsOnlyGoldenDuck(t *testing.T) {
}
}
message := formatDuckAchievement("GoBot", golden)
if !strings.Contains(message, "Killed a "+ircColor(ircYellow, "GOLDEN DUCK")) {
if !strings.Contains(message, "Killed a "+ircColor(ircGold, goldenDuckLabel)) {
t.Fatalf("achievement message = %q, want only GOLDEN DUCK highlighted", message)
}
if strings.Contains(message, ircYellow+"Killed a") || strings.Contains(message, ircYellow+"a ") {
Expand Down Expand Up @@ -390,7 +390,7 @@ func TestDuckHuntAnnouncementKeepsDuckASCIICompact(t *testing.T) {

func TestDuckHuntGoldenDuckColorStartsAtLabel(t *testing.T) {
got := duckName(&duckHuntState{golden: true})
want := "the " + ircColor(ircYellow, "GOLDEN DUCK")
want := "the " + ircColor(ircGold, goldenDuckLabel)
if got != want {
t.Fatalf("golden duck name = %q, want %q", got, want)
}
Expand All @@ -399,6 +399,22 @@ func TestDuckHuntGoldenDuckColorStartsAtLabel(t *testing.T) {
}
}

func TestDuckHuntGoldenDuckUsesGoldInEveryOutputPath(t *testing.T) {
gold := ircColor(ircGold, goldenDuckLabel)
outputs := []string{
duckName(&duckHuntState{golden: true}),
formatDuckAchievement("GoBot", duckAchievementDefinition{Description: "Found a GOLDEN DUCK"}),
}
for i := 0; i < 100; i++ {
outputs = append(outputs, randomDuckEscapeForState(&duckHuntState{golden: true}))
}
for _, output := range outputs {
if strings.Contains(output, goldenDuckLabel) && !strings.Contains(output, gold) {
t.Fatalf("golden duck output is not gold-highlighted: %q", output)
}
}
}

func TestDuckHuntSchedulesAfterActivityThreshold(t *testing.T) {
plugin := &DuckHunt{}
if err := plugin.Init(bot.PluginConfig{
Expand Down Expand Up @@ -835,7 +851,7 @@ func TestDuckHuntEscapeIncludesColorAndMotion(t *testing.T) {
}

goldenEscape := randomDuckEscapeForState(&duckHuntState{golden: true})
if !strings.Contains(goldenEscape, "the "+ircColor(ircYellow, "GOLDEN DUCK")) {
if !strings.Contains(goldenEscape, "the "+ircColor(ircGold, goldenDuckLabel)) {
t.Fatalf("golden escape = %q, want colored GOLDEN DUCK label", goldenEscape)
}
}
Expand Down
3 changes: 2 additions & 1 deletion plugins/formatting.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ const (
ircRed = "\x0304"
ircTan = "\x0307" // mIRC orange, a practical tan approximation
ircCyan = "\x0311"
ircYellow = "\x0308"
ircGold = "\x0308" // mIRC yellow, rendered as gold by common IRC clients
ircYellow = ircGold // keep the existing name for non-golden UI accents
)

func ircColor(color, text string) string {
Expand Down