package commands import ( "fmt" "strings" ) // RegisterPlayerCommands registers all player-level commands func RegisterPlayerCommands(cm *CommandManager) error { commands := []*Command{ // Communication commands { Name: "say", Type: CommandTypePlayer, Description: "Says something to nearby players", Usage: "/say ", RequiredLevel: AdminLevelPlayer, Handler: HandleSay, }, { Name: "tell", Type: CommandTypePlayer, Description: "Sends a private message to a player", Usage: "/tell ", RequiredLevel: AdminLevelPlayer, Handler: HandleTell, }, { Name: "yell", Type: CommandTypePlayer, Description: "Yells something to a wider area", Usage: "/yell ", RequiredLevel: AdminLevelPlayer, Handler: HandleYell, }, { Name: "shout", Type: CommandTypePlayer, Description: "Shouts something zone-wide", Usage: "/shout ", RequiredLevel: AdminLevelPlayer, Handler: HandleShout, }, { Name: "ooc", Type: CommandTypePlayer, Description: "Sends an out-of-character message", Usage: "/ooc ", RequiredLevel: AdminLevelPlayer, Handler: HandleOOC, }, { Name: "emote", Type: CommandTypePlayer, Description: "Performs an emote", Usage: "/emote ", RequiredLevel: AdminLevelPlayer, Handler: HandleEmote, }, // Group commands { Name: "group", Type: CommandTypePlayer, Description: "Group management commands", Usage: "/group [player]", RequiredLevel: AdminLevelPlayer, Handler: HandleGroup, }, { Name: "groupsay", Type: CommandTypePlayer, Description: "Says something to your group", Usage: "/groupsay ", RequiredLevel: AdminLevelPlayer, Handler: HandleGroupSay, }, { Name: "gsay", Type: CommandTypePlayer, Description: "Says something to your group (short form)", Usage: "/gsay ", RequiredLevel: AdminLevelPlayer, Handler: HandleGroupSay, }, // Guild commands { Name: "guild", Type: CommandTypePlayer, Description: "Guild management commands", Usage: "/guild [player]", RequiredLevel: AdminLevelPlayer, Handler: HandleGuild, }, { Name: "guildsay", Type: CommandTypePlayer, Description: "Says something to your guild", Usage: "/guildsay ", RequiredLevel: AdminLevelPlayer, Handler: HandleGuildSay, }, { Name: "officersay", Type: CommandTypePlayer, Description: "Says something to guild officers", Usage: "/officersay ", RequiredLevel: AdminLevelPlayer, Handler: HandleOfficerSay, }, // Character commands { Name: "who", Type: CommandTypePlayer, Description: "Lists players online", Usage: "/who [name pattern]", RequiredLevel: AdminLevelPlayer, Handler: HandleWho, }, { Name: "time", Type: CommandTypePlayer, Description: "Shows current game time", Usage: "/time", RequiredLevel: AdminLevelPlayer, Handler: HandleTime, }, { Name: "afk", Type: CommandTypePlayer, Description: "Toggles AFK status", Usage: "/afk [message]", RequiredLevel: AdminLevelPlayer, Handler: HandleAFK, }, { Name: "anon", Type: CommandTypePlayer, Description: "Toggles anonymous status", Usage: "/anon", RequiredLevel: AdminLevelPlayer, Handler: HandleAnonymous, }, { Name: "lfg", Type: CommandTypePlayer, Description: "Toggles looking for group status", Usage: "/lfg", RequiredLevel: AdminLevelPlayer, Handler: HandleLFG, }, { Name: "location", Type: CommandTypePlayer, Description: "Shows current location", Usage: "/location", RequiredLevel: AdminLevelPlayer, Handler: HandleLocation, }, // Item commands { Name: "inventory", Type: CommandTypePlayer, Description: "Shows inventory information", Usage: "/inventory", RequiredLevel: AdminLevelPlayer, Handler: HandleInventory, }, { Name: "consider", Type: CommandTypePlayer, Description: "Considers a target", Usage: "/consider [target]", RequiredLevel: AdminLevelPlayer, Handler: HandleConsider, }, // Trade commands { Name: "trade", Type: CommandTypePlayer, Description: "Trade management", Usage: "/trade [player]", RequiredLevel: AdminLevelPlayer, Handler: HandleTrade, }, // Quest commands { Name: "quest", Type: CommandTypePlayer, Description: "Quest management", Usage: "/quest [quest_id]", RequiredLevel: AdminLevelPlayer, Handler: HandleQuest, }, // Misc commands { Name: "help", Type: CommandTypePlayer, Description: "Shows available commands", Usage: "/help [command]", RequiredLevel: AdminLevelPlayer, Handler: HandleHelp, }, { Name: "quit", Type: CommandTypePlayer, Description: "Safely logs out of the game", Usage: "/quit", RequiredLevel: AdminLevelPlayer, Handler: HandleQuit, }, } for _, cmd := range commands { if err := cm.Register(cmd); err != nil { return fmt.Errorf("failed to register command %s: %w", cmd.Name, err) } } return nil } // HandleSay handles the /say command func HandleSay(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /say ") return nil } message := ctx.RawArguments // TODO: Implement actual zone-wide say broadcast // For now, just confirm to the player ctx.AddMessage(ChannelSay, ColorWhite, fmt.Sprintf("You say, \"%s\"", message)) // TODO: Send to nearby players in zone // zone.SendNearbyMessage(ctx.Player.GetPosition(), ChannelSay, // fmt.Sprintf("%s says, \"%s\"", playerName, message)) return nil } // HandleTell handles the /tell command func HandleTell(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(2, -1); err != nil { ctx.AddErrorMessage("Usage: /tell ") return nil } targetName := ctx.Arguments[0] message := ctx.GetRemainingArguments(1) // TODO: Implement actual tell system // For now, just show what would be sent ctx.AddMessage(ChannelPrivateTell, ColorWhite, fmt.Sprintf("You tell %s, \"%s\"", targetName, message)) // TODO: Find target player and send message // if targetPlayer := world.FindPlayerByName(targetName); targetPlayer != nil { // targetPlayer.SendMessage(ChannelPrivateTell, // fmt.Sprintf("%s tells you, \"%s\"", playerName, message)) // } else { // ctx.AddErrorMessage(fmt.Sprintf("Player '%s' not found", targetName)) // } return nil } // HandleYell handles the /yell command func HandleYell(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /yell ") return nil } message := ctx.RawArguments ctx.AddMessage(ChannelYell, ColorWhite, fmt.Sprintf("You yell, \"%s\"", message)) // TODO: Send to wider area in zone return nil } // HandleShout handles the /shout command func HandleShout(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /shout ") return nil } message := ctx.RawArguments ctx.AddMessage(ChannelShout, ColorWhite, fmt.Sprintf("You shout, \"%s\"", message)) // TODO: Send zone-wide return nil } // HandleOOC handles the /ooc command func HandleOOC(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /ooc ") return nil } message := ctx.RawArguments playerName := ctx.GetPlayerName() ctx.AddMessage(ChannelOutOfCharacter, ColorWhite, fmt.Sprintf("[OOC] %s: %s", playerName, message)) // TODO: Send to zone OOC channel return nil } // HandleEmote handles the /emote command func HandleEmote(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /emote ") return nil } action := ctx.RawArguments playerName := ctx.GetPlayerName() ctx.AddMessage(ChannelEmote, ColorWhite, fmt.Sprintf("%s %s", playerName, action)) // TODO: Send emote to nearby players return nil } // HandleGroup handles the /group command func HandleGroup(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if ctx.ArgumentCount() == 0 { ctx.AddErrorMessage("Usage: /group [player]") return nil } subCommand := strings.ToLower(ctx.Arguments[0]) switch subCommand { case "invite": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /group invite ") return nil } targetName := ctx.Arguments[1] // TODO: Implement group invite ctx.AddStatusMessage(fmt.Sprintf("Invited %s to group", targetName)) case "leave": // TODO: Implement group leave ctx.AddStatusMessage("Left group") case "kick": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /group kick ") return nil } targetName := ctx.Arguments[1] // TODO: Implement group kick ctx.AddStatusMessage(fmt.Sprintf("Kicked %s from group", targetName)) case "disband": // TODO: Implement group disband ctx.AddStatusMessage("Disbanded group") default: ctx.AddErrorMessage("Usage: /group [player]") } return nil } // HandleGroupSay handles the /groupsay and /gsay commands func HandleGroupSay(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /groupsay ") return nil } message := ctx.RawArguments playerName := ctx.GetPlayerName() // TODO: Check if player is in a group ctx.AddMessage(ChannelGroupSay, ColorWhite, fmt.Sprintf("[Group] %s: %s", playerName, message)) // TODO: Send to group members return nil } // HandleGuild handles the /guild command func HandleGuild(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if ctx.ArgumentCount() == 0 { // TODO: Show guild information ctx.AddStatusMessage("Guild information (not yet implemented)") return nil } subCommand := strings.ToLower(ctx.Arguments[0]) switch subCommand { case "invite": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /guild invite ") return nil } targetName := ctx.Arguments[1] // TODO: Implement guild invite ctx.AddStatusMessage(fmt.Sprintf("Invited %s to guild", targetName)) case "leave": // TODO: Implement guild leave ctx.AddStatusMessage("Left guild") default: ctx.AddErrorMessage("Usage: /guild [player]") } return nil } // HandleGuildSay handles the /guildsay command func HandleGuildSay(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /guildsay ") return nil } message := ctx.RawArguments playerName := ctx.GetPlayerName() // TODO: Check if player is in a guild ctx.AddMessage(ChannelGuildSay, ColorWhite, fmt.Sprintf("[Guild] %s: %s", playerName, message)) return nil } // HandleOfficerSay handles the /officersay command func HandleOfficerSay(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if err := ctx.ValidateArgumentCount(1, -1); err != nil { ctx.AddErrorMessage("Usage: /officersay ") return nil } message := ctx.RawArguments playerName := ctx.GetPlayerName() // TODO: Check if player is guild officer ctx.AddMessage(ChannelOfficerSay, ColorWhite, fmt.Sprintf("[Officer] %s: %s", playerName, message)) return nil } // HandleWho handles the /who command func HandleWho(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Implement player listing ctx.AddMessage(ChannelWho, ColorWhite, "Players online:") ctx.AddMessage(ChannelWho, ColorWhite, fmt.Sprintf(" %s (You)", ctx.GetPlayerName())) ctx.AddMessage(ChannelWho, ColorWhite, "Total: 1 player online") return nil } // HandleTime handles the /time command func HandleTime(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Implement game time system ctx.AddStatusMessage("Game time: 12:00 PM (not yet implemented)") return nil } // HandleAFK handles the /afk command func HandleAFK(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } afkMessage := "" if ctx.ArgumentCount() > 0 { afkMessage = ctx.RawArguments } // TODO: Toggle AFK status if afkMessage != "" { ctx.AddStatusMessage(fmt.Sprintf("AFK status set with message: %s", afkMessage)) } else { ctx.AddStatusMessage("AFK status toggled") } return nil } // HandleAnonymous handles the /anon command func HandleAnonymous(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Toggle anonymous status ctx.AddStatusMessage("Anonymous status toggled") return nil } // HandleLFG handles the /lfg command func HandleLFG(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Toggle LFG status ctx.AddStatusMessage("Looking for group status toggled") return nil } // HandleLocation handles the /location command func HandleLocation(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Get actual player position zoneName := ctx.GetZoneName() ctx.AddStatusMessage(fmt.Sprintf("Location: %s (coordinates not yet implemented)", zoneName)) return nil } // HandleInventory handles the /inventory command func HandleInventory(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } // TODO: Show inventory information ctx.AddStatusMessage("Inventory information (not yet implemented)") return nil } // HandleConsider handles the /consider command func HandleConsider(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } targetName := ctx.GetTargetName() if targetName == "No Target" && ctx.ArgumentCount() > 0 { targetName = ctx.Arguments[0] } if targetName == "No Target" { ctx.AddErrorMessage("You must target something or specify a target name") return nil } // TODO: Implement consider system ctx.AddStatusMessage(fmt.Sprintf("You consider %s... (not yet implemented)", targetName)) return nil } // HandleTrade handles the /trade command func HandleTrade(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if ctx.ArgumentCount() == 0 { ctx.AddErrorMessage("Usage: /trade [player]") return nil } subCommand := strings.ToLower(ctx.Arguments[0]) switch subCommand { case "start": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /trade start ") return nil } targetName := ctx.Arguments[1] ctx.AddStatusMessage(fmt.Sprintf("Trade initiated with %s", targetName)) case "accept": ctx.AddStatusMessage("Trade accepted") case "reject": ctx.AddStatusMessage("Trade rejected") case "cancel": ctx.AddStatusMessage("Trade cancelled") default: ctx.AddErrorMessage("Usage: /trade [player]") } return nil } // HandleQuest handles the /quest command func HandleQuest(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } if ctx.ArgumentCount() == 0 { ctx.AddErrorMessage("Usage: /quest [quest_id]") return nil } subCommand := strings.ToLower(ctx.Arguments[0]) switch subCommand { case "list": // TODO: List active quests ctx.AddStatusMessage("Active quests (not yet implemented)") case "abandon": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /quest abandon ") return nil } questID := ctx.Arguments[1] ctx.AddStatusMessage(fmt.Sprintf("Abandoned quest %s", questID)) case "share": if ctx.ArgumentCount() < 2 { ctx.AddErrorMessage("Usage: /quest share ") return nil } questID := ctx.Arguments[1] ctx.AddStatusMessage(fmt.Sprintf("Shared quest %s", questID)) default: ctx.AddErrorMessage("Usage: /quest [quest_id]") } return nil } // HandleHelp handles the /help command func HandleHelp(ctx *CommandContext) error { // TODO: Show available commands based on admin level ctx.AddMessage(ChannelCommands, ColorWhite, "Available commands:") ctx.AddMessage(ChannelCommands, ColorWhite, "/say - Say something to nearby players") ctx.AddMessage(ChannelCommands, ColorWhite, "/tell - Send private message") ctx.AddMessage(ChannelCommands, ColorWhite, "/who - List online players") ctx.AddMessage(ChannelCommands, ColorWhite, "/time - Show game time") ctx.AddMessage(ChannelCommands, ColorWhite, "/location - Show current location") ctx.AddMessage(ChannelCommands, ColorWhite, "/help - Show this help") return nil } // HandleQuit handles the /quit command func HandleQuit(ctx *CommandContext) error { if err := ctx.RequirePlayer(); err != nil { return err } ctx.AddStatusMessage("Logging out safely...") // TODO: Implement safe logout // if ctx.Client != nil { // ctx.Client.Disconnect() // } return nil }