fix: Q returns to lobby instead of killing SSH session

Pressing Q in game now cleans up the session and returns to lobby,
instead of calling tea.Quit which terminates the SSH connection and
shows "Connection lost" on web. Only Ctrl+C force-quits now.

Also cleans up room on exit so abandoned rooms don't persist in lobby.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-25 23:18:36 +09:00
parent 24d9982b15
commit 206ac522c5
3 changed files with 30 additions and 4 deletions

View File

@@ -31,6 +31,23 @@ func NewGameScreen() *GameScreen {
} }
} }
func (s *GameScreen) leaveGame(ctx *Context) (Screen, tea.Cmd) {
if ctx.Lobby != nil && ctx.Fingerprint != "" {
ctx.Lobby.UnregisterSession(ctx.Fingerprint)
}
if ctx.Session != nil {
ctx.Session.Stop()
ctx.Session = nil
}
if ctx.Lobby != nil && ctx.RoomCode != "" {
ctx.Lobby.RemoveRoom(ctx.RoomCode)
}
ctx.RoomCode = ""
ls := NewLobbyScreen()
ls.refreshLobby(ctx)
return ls, ls.pollLobby()
}
func (s *GameScreen) pollState() tea.Cmd { func (s *GameScreen) pollState() tea.Cmd {
return tea.Tick(time.Millisecond*200, func(t time.Time) tea.Msg { return tea.Tick(time.Millisecond*200, func(t time.Time) tea.Msg {
return tickMsg{} return tickMsg{}
@@ -247,10 +264,13 @@ func (s *GameScreen) Update(msg tea.Msg, ctx *Context) (Screen, tea.Cmd) {
switch s.gameState.Phase { switch s.gameState.Phase {
case game.PhaseExploring: case game.PhaseExploring:
if isForceQuit(key) {
return s, tea.Quit
}
for _, p := range s.gameState.Players { for _, p := range s.gameState.Players {
if p.Fingerprint == ctx.Fingerprint && p.IsDead() { if p.Fingerprint == ctx.Fingerprint && p.IsDead() {
if isQuit(key) { if isKey(key, "q") {
return s, tea.Quit return s.leaveGame(ctx)
} }
return s, nil return s, nil
} }
@@ -286,8 +306,10 @@ func (s *GameScreen) Update(msg tea.Msg, ctx *Context) (Screen, tea.Cmd) {
return s, s.pollState() return s, s.pollState()
} }
} }
} else if isQuit(key) { } else if isForceQuit(key) {
return s, tea.Quit return s, tea.Quit
} else if isKey(key, "q") {
return s.leaveGame(ctx)
} }
case game.PhaseCombat: case game.PhaseCombat:
isPlayerDead := false isPlayerDead := false

View File

@@ -94,6 +94,10 @@ func isQuit(key tea.KeyMsg) bool {
return isKey(key, "q", "ctrl+c") || key.Type == tea.KeyCtrlC return isKey(key, "q", "ctrl+c") || key.Type == tea.KeyCtrlC
} }
func isForceQuit(key tea.KeyMsg) bool {
return isKey(key, "ctrl+c") || key.Type == tea.KeyCtrlC
}
func isUp(key tea.KeyMsg) bool { func isUp(key tea.KeyMsg) bool {
return isKey(key, "up") || key.Type == tea.KeyUp return isKey(key, "up") || key.Type == tea.KeyUp
} }

View File

@@ -36,7 +36,7 @@ func (s *ResultScreen) Update(msg tea.Msg, ctx *Context) (Screen, tea.Cmd) {
ls := NewLobbyScreen() ls := NewLobbyScreen()
ls.refreshLobby(ctx) ls.refreshLobby(ctx)
return ls, ls.pollLobby() return ls, ls.pollLobby()
} else if isQuit(key) { } else if isForceQuit(key) {
return s, tea.Quit return s, tea.Quit
} }
} }