mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
N3/P6b: a party you can actually ask someone to join
!expedition invite / accept / decline / party / leave. The invitee buys their own loadout and it pools -- a party is a shared burden, not a free ride. The plan said invites close "before the first walk". That is not a window, it is a race: autoRunMinExpeditionAge leaves a fresh expedition alone for thirty minutes and then the autopilot starts walking it, and the leader's own !expedition run can beat it there. Thirty minutes is not enough to ask a friend who is asleep. So two changes to what the plan specified: - The window is all of Day 1, not the first step. Supplies burn at the night rollover, so a companion who arrives three rooms in pays and receives exactly what one who arrived at the gate does. - An unanswered invite pins the autopilot: loadExpeditionsForAutoRun skips any expedition somebody has been asked to join. The leader must not be dragged into a boss room while their friend reads the DM. Bounded by expeditionInviteTTL (2h) in the query itself, so a forgotten invite costs an afternoon, not the expedition. New table expedition_invite. Absent == nobody was asked, which is true of every expedition predating N3 -- nothing to backfill, same reading that let expedition_party and roster_size ship without one. Details worth keeping: - Outstanding invites count against expeditionPartyMax. Otherwise a leader asks four people and three accept. - Pooling raises Current *and* Max. supplyDepletion reads the ratio, so folding in only Current would read as the party suddenly starving. - A member's supplies stay in the pool when they !leave. They were spent on the expedition, not lent to it; clawing them back would let someone starve the party on their way out. - assertNotAdventuring guards expeditions and rosters but not bare zone runs, so accept checks getActiveZoneRun itself -- startExpedition does. - A party is not a taxi: zoneOpenToLevel gates the invitee on the same tier rule !expedition start applies to the leader. - releaseParty now clears invites too, or someone could accept onto a corpse. - expeditionCmdStatus and the bare `!expedition` switched to activeExpeditionFor, and a member typing `!expedition go 2` is told the leader picks the path instead of falling through to `start` and being told "2" is an unknown zone. Combat still seats one player -- handleFightCmd is P6c. go test ./... green, golden byte-identical.
This commit is contained in:
@@ -48,8 +48,9 @@ func (p *AdventurePlugin) handleDnDExpeditionCmd(ctx MessageContext, args string
|
||||
sub, rest := splitFirstWord(args)
|
||||
switch strings.ToLower(sub) {
|
||||
case "":
|
||||
// If active, show status; otherwise help.
|
||||
if exp, _ := getActiveExpedition(ctx.Sender); exp != nil {
|
||||
// If active, show status; otherwise help. A party member is on an
|
||||
// expedition they do not own, so ask the leader-or-member resolver.
|
||||
if exp, _, _ := activeExpeditionFor(ctx.Sender); exp != nil {
|
||||
return p.expeditionCmdStatus(ctx, "")
|
||||
}
|
||||
return p.SendDM(ctx.Sender, expeditionHelpText())
|
||||
@@ -65,8 +66,16 @@ func (p *AdventurePlugin) handleDnDExpeditionCmd(ctx MessageContext, args string
|
||||
// player doesn't have to remember the !zone seam). Otherwise
|
||||
// fall back to the historical alias for `!expedition start`.
|
||||
if rest != "" && isAllDigits(strings.TrimSpace(rest)) {
|
||||
if exp, _ := getActiveExpedition(ctx.Sender); exp != nil {
|
||||
exp, isLeader, _ := activeExpeditionFor(ctx.Sender)
|
||||
switch {
|
||||
case exp != nil && isLeader:
|
||||
return p.zoneCmdGo(ctx, rest)
|
||||
case exp != nil:
|
||||
// A member reaching a fork must not silently fall through to
|
||||
// `!expedition start` and be told their path number is an
|
||||
// unknown zone. The leader picks the way (C1); P6c enforces
|
||||
// that at the !zone seam too.
|
||||
return p.SendDM(ctx.Sender, "The party leader picks the path.")
|
||||
}
|
||||
}
|
||||
return p.expeditionCmdStart(ctx, c, rest)
|
||||
@@ -76,6 +85,16 @@ func (p *AdventurePlugin) handleDnDExpeditionCmd(ctx MessageContext, args string
|
||||
return p.expeditionCmdLog(ctx)
|
||||
case "abandon", "quit":
|
||||
return p.expeditionCmdAbandon(ctx)
|
||||
case "invite":
|
||||
return p.expeditionCmdInvite(ctx, rest)
|
||||
case "accept", "join":
|
||||
return p.expeditionCmdAccept(ctx, c, rest)
|
||||
case "decline":
|
||||
return p.expeditionCmdDecline(ctx)
|
||||
case "party", "roster":
|
||||
return p.expeditionCmdParty(ctx)
|
||||
case "leave":
|
||||
return p.expeditionCmdLeave(ctx)
|
||||
case "extract":
|
||||
return p.handleExtractCmd(ctx, "")
|
||||
case "resume":
|
||||
@@ -99,6 +118,11 @@ func expeditionHelpText() string {
|
||||
b.WriteString("`!expedition start <zone>` — prompts a loadout: `lean` / `balanced` / `heavy`\n")
|
||||
b.WriteString("`!expedition run` — start (or resume) the autopilot walk (alias `!explore`)\n")
|
||||
b.WriteString("`!expedition status` — day, rooms, supplies, recent events\n\n")
|
||||
b.WriteString("**Bring someone** _(Day 1, up to three of you)_:\n")
|
||||
b.WriteString("`!expedition invite @user` — they buy their own supplies into the party pool\n")
|
||||
b.WriteString("`!expedition accept` / `!expedition decline` — answer an invite\n")
|
||||
b.WriteString("`!expedition party` — who's with you\n")
|
||||
b.WriteString("`!expedition leave` — turn back for town (members only)\n\n")
|
||||
b.WriteString("**Mid-expedition:**\n")
|
||||
b.WriteString("`!extract` — bail safely (resumable for 7 days)\n")
|
||||
b.WriteString("`!resume [loadout]` — resume an extracted expedition\n")
|
||||
@@ -393,7 +417,7 @@ func (p *AdventurePlugin) expeditionCmdStatus(ctx MessageContext, args string) e
|
||||
}
|
||||
|
||||
func (p *AdventurePlugin) expeditionCmdStatusImpl(ctx MessageContext, debug bool) error {
|
||||
exp, err := getActiveExpedition(ctx.Sender)
|
||||
exp, _, err := activeExpeditionFor(ctx.Sender)
|
||||
if err != nil {
|
||||
return p.SendDM(ctx.Sender, "Couldn't read expedition state: "+err.Error())
|
||||
}
|
||||
@@ -417,7 +441,7 @@ func (p *AdventurePlugin) expeditionCmdStatusImpl(ctx MessageContext, debug bool
|
||||
b.WriteString(fmt.Sprintf("🗺 **Region:** %s (%d/%d)%s\n",
|
||||
r.Name, r.Order, len(regionsForZone(exp.ZoneID)), marker))
|
||||
}
|
||||
if run, rerr := getActiveZoneRun(ctx.Sender); rerr == nil && run != nil && run.TotalRooms > 0 {
|
||||
if run, _, rerr := activeZoneRunFor(ctx.Sender); rerr == nil && run != nil && run.TotalRooms > 0 {
|
||||
b.WriteString(fmt.Sprintf("🚪 **Rooms:** %d / %d in this region\n",
|
||||
run.CurrentRoom+1, run.TotalRooms))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user