aboutsummaryrefslogtreecommitdiff
path: root/internal/game/login_char.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-06-14 21:07:26 -0400
committerhistoria <[not public]>2026-06-14 21:07:26 -0400
commit1aba2bdd23aebed4032333e74aa553c40a31fcbd (patch)
treec004f4c2a139df5c3cf4029b2611bdfa09b40f86 /internal/game/login_char.go
parenta19e6b6ab01670a5932308c7bd0e0e5eed8cbcad (diff)
downloadthehouseoficarus-1aba2bdd23aebed4032333e74aa553c40a31fcbd.tar.gz
refactor: added docs, split up some components in game package
Diffstat (limited to 'internal/game/login_char.go')
-rw-r--r--internal/game/login_char.go236
1 files changed, 236 insertions, 0 deletions
diff --git a/internal/game/login_char.go b/internal/game/login_char.go
new file mode 100644
index 0000000..ba034bb
--- /dev/null
+++ b/internal/game/login_char.go
@@ -0,0 +1,236 @@
+package game
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "thirdcollapse/internal/net"
+ "thirdcollapse/internal/player"
+)
+
+func (g *Game) handleNewCharName(sess *net.Session, input string) {
+ name := strings.TrimSpace(input)
+
+ if sess.PendingChar == "connect" && len(sess.Account.Characters) > 0 {
+ if idx, err := parseChoiceIndex(name); err == nil && idx > 0 && idx <= len(sess.Account.Characters) {
+ sess.PendingChar = ""
+ g.connectCharacter(sess, sess.Account.Characters[idx-1])
+ return
+ }
+ sess.WriteLine("Invalid choice.")
+ sess.Write("\n> ")
+ return
+ }
+
+ if name == "" {
+ sess.Write("Character name: ")
+ return
+ }
+
+ if verr := player.ValidName(name); verr != nil {
+ sess.WriteLine(verr.Error())
+ sess.Write("Character name: ")
+ return
+ }
+
+ if g.AccountStore.CharacterExists(name) {
+ sess.WriteLine("A character with that name already exists.")
+ sess.Write("Character name: ")
+ return
+ }
+
+ p := player.New(name)
+ p.RoomID = 1
+
+ if err := g.AccountStore.SaveCharacter(p); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error creating character: %v", err))
+ sess.State = net.StateMenu
+ g.showMenu(sess)
+ return
+ }
+
+ acc, _ := g.AccountStore.LoadAccount(sess.Account.Name)
+ acc.Characters = append(acc.Characters, name)
+ g.AccountStore.SaveAccount(acc)
+ sess.Account.Characters = acc.Characters
+
+ g.connectCharacter(sess, name)
+}
+
+func (g *Game) connectCharacter(sess *net.Session, name string) {
+ g.charsMu.Lock()
+ if existing := g.loggedInChars[name]; existing != nil {
+ g.charsMu.Unlock()
+ sess.WriteLine("This character is logged in elsewhere.")
+ sess.State = net.StateMenu
+ g.showMenu(sess)
+ return
+ }
+
+ p, err := g.AccountStore.LoadCharacter(name)
+ if err != nil {
+ g.charsMu.Unlock()
+ sess.WriteLine(fmt.Sprintf("Error loading character: %v", err))
+ sess.State = net.StateMenu
+ g.showMenu(sess)
+ return
+ }
+
+ sess.Player = p
+ sess.State = net.StateGame
+ g.loggedInChars[name] = sess
+ g.charsMu.Unlock()
+
+ g.World.SeedGroundItems(p.RoomID)
+ g.seedRoomMobs(p.RoomID)
+ g.seedRoomObjects(p.RoomID)
+
+ if g.Hub != nil {
+ g.Hub.EnterRoom(sess, p.RoomID)
+ }
+
+ g.doLook(sess)
+ sess.Write("\r\n> ")
+}
+
+func (g *Game) handleRenameChar(sess *net.Session, input string) {
+ name := strings.TrimSpace(input)
+ if idx, err := parseChoiceIndex(name); err == nil && idx > 0 && idx <= len(sess.Account.Characters) {
+ sess.PendingChar = sess.Account.Characters[idx-1]
+ } else {
+ sess.PendingChar = name
+ }
+
+ found := false
+ for _, c := range sess.Account.Characters {
+ if c == sess.PendingChar {
+ found = true
+ break
+ }
+ }
+ if !found {
+ sess.WriteLine(fmt.Sprintf("No character named %s on this account.", sess.PendingChar))
+ g.showMenu(sess)
+ return
+ }
+
+ sess.State = net.StateRenameCharName
+ sess.WriteLine(fmt.Sprintf("Renaming %s.", sess.PendingChar))
+ sess.Write("New name: ")
+}
+
+func (g *Game) handleRenameCharName(sess *net.Session, input string) {
+ newName := strings.TrimSpace(input)
+ oldName := sess.PendingChar
+ if newName == "" {
+ sess.Write("New name: ")
+ return
+ }
+ if verr := player.ValidName(newName); verr != nil {
+ sess.WriteLine(verr.Error())
+ sess.Write("New name: ")
+ return
+ }
+ if newName == oldName {
+ sess.WriteLine("That's already the character's name.")
+ g.showMenu(sess)
+ return
+ }
+ if g.AccountStore.CharacterExists(newName) {
+ sess.WriteLine("A character with that name already exists.")
+ sess.Write("New name: ")
+ return
+ }
+
+ oldPath := g.AccountStore.CharPath(oldName)
+ newPath := g.AccountStore.CharPath(newName)
+ if err := os.Rename(oldPath, newPath); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error renaming: %v", err))
+ g.showMenu(sess)
+ return
+ }
+
+ p, _ := g.AccountStore.LoadCharacter(newName)
+ if p != nil {
+ p.Name = newName
+ g.AccountStore.SaveCharacter(p)
+ }
+
+ acc, _ := g.AccountStore.LoadAccount(sess.Account.Name)
+ for i, c := range acc.Characters {
+ if c == oldName {
+ acc.Characters[i] = newName
+ break
+ }
+ }
+ g.AccountStore.SaveAccount(acc)
+ sess.Account.Characters = acc.Characters
+
+ sess.PendingChar = ""
+ sess.WriteLine(fmt.Sprintf("%s renamed to %s.", oldName, newName))
+ g.showMenu(sess)
+}
+
+func (g *Game) showDeleteConfirm(sess *net.Session) {
+ sess.State = net.StateDeleteChar
+ sess.WriteLine(fmt.Sprintf("\nDelete %s? Type DELETE %s to confirm, or anything else to cancel.", sess.PendingChar, sess.PendingChar))
+}
+
+func (g *Game) handleDeleteChar(sess *net.Session, input string) {
+ if sess.PendingChar == "" {
+ name := strings.TrimSpace(input)
+ if idx, err := parseChoiceIndex(name); err == nil && idx > 0 && idx <= len(sess.Account.Characters) {
+ sess.PendingChar = sess.Account.Characters[idx-1]
+ } else {
+ sess.PendingChar = name
+ }
+ found := false
+ for _, c := range sess.Account.Characters {
+ if c == sess.PendingChar {
+ found = true
+ break
+ }
+ }
+ if !found {
+ sess.WriteLine(fmt.Sprintf("No character named %s on this account.", sess.PendingChar))
+ sess.PendingChar = ""
+ g.showMenu(sess)
+ return
+ }
+ g.showDeleteConfirm(sess)
+ return
+ }
+
+ input = strings.TrimSpace(input)
+ expected := "DELETE " + sess.PendingChar
+ if strings.ToUpper(input) != strings.ToUpper(expected) {
+ sess.WriteLine("Delete cancelled.")
+ sess.PendingChar = ""
+ g.showMenu(sess)
+ return
+ }
+
+ charPath := g.AccountStore.CharPath(sess.PendingChar)
+ if err := os.Remove(charPath); err != nil {
+ sess.WriteLine(fmt.Sprintf("Error deleting: %v", err))
+ sess.PendingChar = ""
+ g.showMenu(sess)
+ return
+ }
+
+ acc, _ := g.AccountStore.LoadAccount(sess.Account.Name)
+ var newChars []string
+ for _, c := range acc.Characters {
+ if c != sess.PendingChar {
+ newChars = append(newChars, c)
+ }
+ }
+ acc.Characters = newChars
+ g.AccountStore.SaveAccount(acc)
+ sess.Account.Characters = newChars
+
+ sess.WriteLine(fmt.Sprintf("%s has been deleted.", sess.PendingChar))
+ sess.PendingChar = ""
+ g.showMenu(sess)
+}