feat: nickname input screen for first-time players

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-24 15:42:06 +09:00
parent ef9a713696
commit 43a9a0d9ad
3 changed files with 150 additions and 23 deletions

View File

@@ -24,6 +24,7 @@ const (
screenStats
screenAchievements
screenLeaderboard
screenNickname
)
// StateUpdateMsg is sent by GameSession to update the view
@@ -53,8 +54,9 @@ type Model struct {
moveCursor int // selected neighbor index during exploration
chatting bool
chatInput string
rankingSaved bool
shopMsg string
rankingSaved bool
shopMsg string
nicknameInput string
}
func NewModel(width, height int, fingerprint string, lobby *game.Lobby, db *store.DB) Model {
@@ -116,6 +118,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m.updateAchievements(msg)
case screenLeaderboard:
return m.updateLeaderboard(msg)
case screenNickname:
return m.updateNickname(msg)
}
return m, nil
}
@@ -162,6 +166,8 @@ func (m Model) View() string {
byGold, _ = m.store.TopRunsByGold(10)
}
return renderLeaderboard(byFloor, byGold, m.width, m.height)
case screenNickname:
return renderNickname(m.nicknameInput, m.width, m.height)
}
return ""
}
@@ -195,25 +201,37 @@ func isDown(key tea.KeyMsg) bool {
func (m Model) updateTitle(msg tea.Msg) (tea.Model, tea.Cmd) {
if key, ok := msg.(tea.KeyMsg); ok {
if isEnter(key) {
if m.store != nil {
name, err := m.store.GetProfile(m.fingerprint)
if err != nil {
m.playerName = "Adventurer"
if m.store != nil && m.fingerprint != "" {
m.store.SaveProfile(m.fingerprint, m.playerName)
}
} else {
m.playerName = name
}
} else {
m.playerName = "Adventurer"
}
if m.fingerprint == "" {
m.fingerprint = fmt.Sprintf("anon-%d", time.Now().UnixNano())
}
if m.store != nil {
name, err := m.store.GetProfile(m.fingerprint)
if err != nil {
// First time player — show nickname input
m.screen = screenNickname
m.nicknameInput = ""
return m, nil
}
m.playerName = name
} else {
m.playerName = "Adventurer"
}
if m.lobby != nil {
m.lobby.PlayerOnline(m.fingerprint, m.playerName)
}
// Check for active session to reconnect
if m.lobby != nil {
code, session := m.lobby.GetActiveSession(m.fingerprint)
if session != nil {
m.roomCode = code
m.session = session
m.gameState = m.session.GetState()
m.screen = screenGame
m.session.TouchActivity(m.fingerprint)
m.session.SendChat("System", m.playerName+" reconnected!")
return m, m.pollState()
}
}
m.screen = screenLobby
m = m.withRefreshedLobby()
} else if isKey(key, "h") {
@@ -231,6 +249,48 @@ func (m Model) updateTitle(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m Model) updateNickname(msg tea.Msg) (tea.Model, tea.Cmd) {
if key, ok := msg.(tea.KeyMsg); ok {
if isEnter(key) && len(m.nicknameInput) > 0 {
m.playerName = m.nicknameInput
if m.store != nil && m.fingerprint != "" {
m.store.SaveProfile(m.fingerprint, m.playerName)
}
m.nicknameInput = ""
if m.lobby != nil {
m.lobby.PlayerOnline(m.fingerprint, m.playerName)
}
// Check for active session to reconnect
if m.lobby != nil {
code, session := m.lobby.GetActiveSession(m.fingerprint)
if session != nil {
m.roomCode = code
m.session = session
m.gameState = m.session.GetState()
m.screen = screenGame
m.session.TouchActivity(m.fingerprint)
m.session.SendChat("System", m.playerName+" reconnected!")
return m, m.pollState()
}
}
m.screen = screenLobby
m = m.withRefreshedLobby()
} else if isKey(key, "esc") || key.Type == tea.KeyEsc {
m.nicknameInput = ""
m.screen = screenTitle
} else if key.Type == tea.KeyBackspace && len(m.nicknameInput) > 0 {
m.nicknameInput = m.nicknameInput[:len(m.nicknameInput)-1]
} else if len(key.Runes) == 1 && len(m.nicknameInput) < 12 {
ch := string(key.Runes)
// Only allow alphanumeric and some special chars
if len(ch) == 1 && ch[0] >= 32 && ch[0] < 127 {
m.nicknameInput += ch
}
}
}
return m, nil
}
func (m Model) updateStats(msg tea.Msg) (tea.Model, tea.Cmd) {
if key, ok := msg.(tea.KeyMsg); ok {
if isKey(key, "s") || isEnter(key) || isQuit(key) {
@@ -351,6 +411,9 @@ func (m Model) updateClassSelect(msg tea.Msg) (tea.Model, tea.Cmd) {
player := entity.NewPlayer(m.playerName, selectedClass)
player.Fingerprint = m.fingerprint
m.session.AddPlayer(player)
if m.lobby != nil {
m.lobby.RegisterSession(m.fingerprint, m.roomCode)
}
m.session.StartGame()
m.lobby.StartRoom(m.roomCode)
m.gameState = m.session.GetState()
@@ -600,6 +663,9 @@ func (m Model) updateShop(msg tea.Msg) (tea.Model, tea.Cmd) {
func (m Model) updateResult(msg tea.Msg) (tea.Model, tea.Cmd) {
if key, ok := msg.(tea.KeyMsg); ok {
if isEnter(key) {
if m.lobby != nil && m.fingerprint != "" {
m.lobby.UnregisterSession(m.fingerprint)
}
if m.session != nil {
m.session.Stop()
m.session = nil