package game import ( "fmt" "math/rand" "strconv" "strings" "thirdcollapse/internal/net" "thirdcollapse/internal/object" "thirdcollapse/internal/player" "thirdcollapse/internal/world" ) var EquipSlots = []object.EquipSlot{ object.SlotHead, object.SlotNeck, object.SlotTorso, object.SlotLegs, object.SlotHands, object.SlotFeet, object.SlotBack, object.SlotAmmo, object.SlotMainHand, object.SlotOffHand, object.SlotRing, } type itemMatch struct { ID string Name string Slot int } type xpGain struct { Skill string XP int } type deathDrop struct { itemID string quantity int totalVal int isEquip bool equipSlot object.EquipSlot invSlot int } func plural(n int) string { if n == 1 { return "" } return "s" } func parseQty(input string) (int, string) { parts := strings.Fields(input) if len(parts) > 1 { if n, err := strconv.Atoi(parts[0]); err == nil && n > 0 { return n, strings.Join(parts[1:], " ") } } return 0, input } func parseIndex(s string) (int, error) { var idx int _, err := fmt.Sscanf(s, "%d", &idx) return idx, err } func mobDisplayName(m *world.MobInstance, definite bool) string { if m.Unique { return m.Name } if definite { return "the " + m.Name } return "a " + m.Name } func mobCombatLevel(m *world.MobInstance) int { return int(0.25*float64(m.Attack+m.Strength+m.Defense+m.MaxHP) + 0.5) } func uniqueItemNames(matches []itemMatch) []string { seen := make(map[string]bool) var out []string for _, m := range matches { if !seen[m.Name] { seen[m.Name] = true out = append(out, m.Name) } } return out } func randInt(max int) int { if max <= 0 { return 0 } return rand.Intn(max) } func innerPickupReport(sess *net.Session, picked []string) { for i, name := range picked { if i == len(picked)-1 { sess.WriteLine(name) } else if i == len(picked)-2 { sess.Write(name + " and ") } else { sess.Write(name + ", ") } } } func actionDesc(p *player.Player) string { if p.Action == nil { return "" } target := p.Action.TargetName if idx, ok := p.Action.Data["instance_idx"]; ok { target += fmt.Sprintf(" [%d]", idx) } switch p.Action.Type { case "gather": return "mining a " + target case "talk": return "talking to " + target case "use": return "using a " + target case "burn": return "trying to start a fire" case "stoke": return "tending to a fire" } return "" } func (g *Game) newInvSlot(itemID string, qty int) *player.InventorySlot { slot := &player.InventorySlot{ItemID: itemID, Quantity: qty} if def, err := g.ItemStore.Load(itemID); err == nil && def.MaxQuality > 0 { slot.Quality = def.Quality slot.MaxQuality = def.MaxQuality } return slot }