diff --git a/cmd/gennames/main.go b/cmd/gennames/main.go index 2a8474d..dfba21a 100644 --- a/cmd/gennames/main.go +++ b/cmd/gennames/main.go @@ -2,7 +2,9 @@ package main import ( "bufio" + "bytes" "fmt" + "go/format" "os" "regexp" "strings" @@ -10,15 +12,22 @@ import ( ) func main() { + if err := run(); err != nil { + panic(err) + } +} + +func run() error { // Read items.go f, err := os.Open("pkg/data/item/items.go") if err != nil { - panic(err) + return err } defer f.Close() nameRe := regexp.MustCompile(`Name:\s*"([^"]*)"`) var names []string + seenNames := make(map[string]string) scanner := bufio.NewScanner(f) for scanner.Scan() { @@ -27,37 +36,43 @@ func main() { if m == nil { continue } - raw := strings.TrimSpace(m[1]) - // Remove apostrophes - raw = strings.ReplaceAll(raw, "'", "") - // Split by whitespace, capitalize each word, join - words := strings.Fields(raw) - var camel strings.Builder - for _, w := range words { - if len(w) == 0 { - continue - } - runes := []rune(w) - runes[0] = unicode.ToUpper(runes[0]) - camel.WriteString(string(runes)) + raw := m[1] + canonical := canonicalizeName(raw) + if canonical == "" { + return fmt.Errorf("unable to generate canonical name for item %q", raw) } - names = append(names, camel.String()) + + if existingRaw, exists := seenNames[canonical]; exists && existingRaw != raw { + return fmt.Errorf("duplicate generated item name %q from %q and %q", canonical, existingRaw, raw) + } + if _, exists := seenNames[canonical]; !exists { + seenNames[canonical] = raw + } + names = append(names, canonical) + } + if err := scanner.Err(); err != nil { + return err } fmt.Printf("Extracted %d names from items.go\n", len(names)) // Write name.go - out, err := os.Create("pkg/data/item/name.go") - if err != nil { - panic(err) - } - defer out.Close() - - w := bufio.NewWriter(out) - w.WriteString(`package item + var b bytes.Buffer + b.WriteString(`package item import "strings" +const ( + ExpCharItemIDThreshold = 508 + ExpCharItemIDOffset = 15 +) + +var ExpChar uint16 + +func SetExpChar(expChar uint16) { + ExpChar = expChar +} + const ( ScrollOfTownPortal = "ScrollOfTownPortal" ScrollOfIdentify = "ScrollOfIdentify" @@ -67,15 +82,22 @@ const ( ) func GetNameByEnum(itemNumber uint) Name { - if int(itemNumber) >= len(Names) { + idx := int(itemNumber) + if ExpChar >= 3 && idx >= ExpCharItemIDThreshold { + idx += ExpCharItemIDOffset + } + if idx < 0 || idx >= len(Names) { return Name("") } - return Name(Names[itemNumber]) + return Name(Names[idx]) } func GetIDByName(itemName string) int { for i, name := range Names { if strings.EqualFold(name, itemName) { + if ExpChar >= 3 && i >= ExpCharItemIDThreshold+ExpCharItemIDOffset { + return i - ExpCharItemIDOffset + } return i } } @@ -88,10 +110,42 @@ type Name string var Names = []string{ `) for _, n := range names { - fmt.Fprintf(w, "\t\"%s\",\n", n) + fmt.Fprintf(&b, "\t\"%s\",\n", n) + } + b.WriteString("}\n") + + formatted, err := format.Source(b.Bytes()) + if err != nil { + return fmt.Errorf("formatting generated name.go: %w", err) + } + + if err := os.WriteFile("pkg/data/item/name.go", formatted, 0644); err != nil { + return err } - w.WriteString("}\n") - w.Flush() fmt.Println("Generated name.go successfully") + return nil +} + +func canonicalizeName(raw string) string { + raw = strings.TrimSpace(raw) + raw = strings.ReplaceAll(raw, "'", "") + + var canonical strings.Builder + capitalizeNext := true + + for _, r := range raw { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + if capitalizeNext && unicode.IsLetter(r) { + r = unicode.ToUpper(r) + } + canonical.WriteRune(r) + capitalizeNext = false + continue + } + + capitalizeNext = true + } + + return canonical.String() } diff --git a/cmd/txttocode/templates.go b/cmd/txttocode/templates.go index 29e04a5..90d034f 100644 --- a/cmd/txttocode/templates.go +++ b/cmd/txttocode/templates.go @@ -32,7 +32,7 @@ package skill var Desc = map[SkillDesc]Description{ {{- range $key, $value := . }} - {{- if and (contains (index $value "str name") "kill") (extractInt (index $value "str name")) }} + {{- if index $value "str name" }} {{- if ne (index $value "skilldesc") "townportal" }} "{{ $value.skilldesc }}": {Page: {{ $value.SkillPage }}, Row: {{ $value.SkillRow }}, Column: {{ $value.SkillColumn }}, ListRow: {{ $value.ListRow }}, IconCel: {{ $value.IconCel }}}, {{- end }} @@ -242,7 +242,7 @@ type UniqueName string const ( None UniqueName = "" {{- range $key, $value := . }} - {{- if and (ne $value.index "") (ne $value.enabled "0") (ne (index $value "lvl req") "") }} + {{- if and (ne $value.index "") (ne $value.spawnable "0") (ne (index $value "lvl req") "") }} {{- if eq $value.index "Rainbow Facet" }} {{- if contains $value.prop4 "death-skill" }} RainbowFacet{{ replace $value.par4 " " "" }}Death UniqueName = "Rainbow Facet ({{ $value.par4 }} Death)" @@ -266,7 +266,7 @@ type UniqueItemInfo struct { var UniqueItems = map[UniqueName]UniqueItemInfo{ {{- range $key, $value := . }} - {{- if and (ne $value.index "") (ne $value.enabled "0") (ne (index $value "lvl req") "") }} + {{- if and (ne $value.index "") (ne $value.spawnable "0") (ne (index $value "lvl req") "") }} {{- if eq $value.index "Rainbow Facet" }} {{- if contains $value.prop4 "death-skill" }} RainbowFacet{{ replace $value.par4 " " "" }}Death: {Name: "Rainbow Facet", Code: "{{ $value.code }}", LevelReq: {{ index $value "lvl req" }}, Rarity: {{ $value.rarity }}, ID: {{ index $value "*ID" }}}, diff --git a/pkg/data/item/name.go b/pkg/data/item/name.go index df47715..5986f62 100644 --- a/pkg/data/item/name.go +++ b/pkg/data/item/name.go @@ -2,6 +2,17 @@ package item import "strings" +const ( + ExpCharItemIDThreshold = 508 + ExpCharItemIDOffset = 15 +) + +var ExpChar uint16 + +func SetExpChar(expChar uint16) { + ExpChar = expChar +} + const ( ScrollOfTownPortal = "ScrollOfTownPortal" ScrollOfIdentify = "ScrollOfIdentify" @@ -11,15 +22,22 @@ const ( ) func GetNameByEnum(itemNumber uint) Name { - if int(itemNumber) >= len(Names) { + idx := int(itemNumber) + if ExpChar >= 3 && idx >= ExpCharItemIDThreshold { + idx += ExpCharItemIDOffset + } + if idx < 0 || idx >= len(Names) { return Name("") } - return Name(Names[itemNumber]) + return Name(Names[idx]) } func GetIDByName(itemName string) int { for i, name := range Names { if strings.EqualFold(name, itemName) { + if ExpChar >= 3 && i >= ExpCharItemIDThreshold+ExpCharItemIDOffset { + return i - ExpCharItemIDOffset + } return i } } @@ -63,7 +81,7 @@ var Names = []string{ "BroadSword", "LongSword", "WarSword", - "Two-HandedSword", + "TwoHandedSword", "Claymore", "GiantSword", "BastardSword", @@ -184,7 +202,7 @@ var Names = []string{ "Bill", "BattleScythe", "Partizan", - "Bec-de-Corbin", + "BecDeCorbin", "GrimScythe", "JoStaff", "Quarterstaff", @@ -202,7 +220,7 @@ var Names = []string{ "Arbalest", "SiegeCrossbow", "Ballista", - "Chu-Ko-Nu", + "ChuKoNu", "KhalimsFlail", "KhalimsWill", "Katar", @@ -232,7 +250,7 @@ var Names = []string{ "WarSpike", "BerserkerAxe", "FeralAxe", - "Silver-edgedAxe", + "SilverEdgedAxe", "Decapitator", "ChampionAxe", "GloriousAxe", diff --git a/pkg/data/item/uniqueitems.go b/pkg/data/item/uniqueitems.go index d29b5ce..4aecb67 100644 --- a/pkg/data/item/uniqueitems.go +++ b/pkg/data/item/uniqueitems.go @@ -35,7 +35,6 @@ const ( BloodCrescent UniqueName = "Blood Crescent" KrintizsSkewer UniqueName = "Krintizs Skewer" Gleamscythe UniqueName = "Gleamscythe" - AzurewrathCrystalSword UniqueName = "Azurewrath" GriswoldsEdge UniqueName = "Griswolds Edge" Hellplague UniqueName = "Hellplague" CulwensPoint UniqueName = "Culwens Point" @@ -267,7 +266,6 @@ const ( Doombringer UniqueName = "Doombringer" TheGrandfather UniqueName = "The Grandfather" Wizardspike UniqueName = "Wizardspike" - ConstrictingRing UniqueName = "Constricting Ring" Stormspire UniqueName = "Stormspire" Eaglehorn UniqueName = "Eaglehorn" Windforce UniqueName = "Windforce" @@ -440,36 +438,35 @@ type UniqueItemInfo struct { } var UniqueItems = map[UniqueName]UniqueItemInfo{ - TheGnasher: {Name: "The Gnasher", Code: "hax", LevelReq: 5, Rarity: 1, ID: 0}, - Deathspade: {Name: "Deathspade", Code: "axe", LevelReq: 9, Rarity: 1, ID: 1}, - Bladebone: {Name: "Bladebone", Code: "2ax", LevelReq: 15, Rarity: 1, ID: 2}, - Mindrend: {Name: "Mindrend", Code: "mpi", LevelReq: 21, Rarity: 1, ID: 3}, - Rakescar: {Name: "Rakescar", Code: "wax", LevelReq: 27, Rarity: 1, ID: 4}, - FechmarsAxe: {Name: "Fechmars Axe", Code: "lax", LevelReq: 8, Rarity: 1, ID: 5}, - Goreshovel: {Name: "Goreshovel", Code: "bax", LevelReq: 14, Rarity: 1, ID: 6}, - TheChieftan: {Name: "The Chieftan", Code: "btx", LevelReq: 19, Rarity: 1, ID: 7}, - Brainhew: {Name: "Brainhew", Code: "gax", LevelReq: 25, Rarity: 1, ID: 8}, - TheHumongous: {Name: "The Humongous", Code: "gix", LevelReq: 29, Rarity: 1, ID: 9}, - IrosTorch: {Name: "Iros Torch", Code: "wnd", LevelReq: 5, Rarity: 1, ID: 10}, - Maelstromwrath: {Name: "Maelstromwrath", Code: "ywn", LevelReq: 14, Rarity: 1, ID: 11}, - Gravenspine: {Name: "Gravenspine", Code: "bwn", LevelReq: 20, Rarity: 1, ID: 12}, - UmesLament: {Name: "Umes Lament", Code: "gwn", LevelReq: 28, Rarity: 1, ID: 13}, - Felloak: {Name: "Felloak", Code: "clb", LevelReq: 3, Rarity: 1, ID: 14}, - KnellStriker: {Name: "Knell Striker", Code: "scp", LevelReq: 5, Rarity: 1, ID: 15}, - Rusthandle: {Name: "Rusthandle", Code: "gsc", LevelReq: 17, Rarity: 1, ID: 16}, - Stormeye: {Name: "Stormeye", Code: "wsp", LevelReq: 23, Rarity: 1, ID: 17}, - Stoutnail: {Name: "Stoutnail", Code: "spc", LevelReq: 5, Rarity: 1, ID: 18}, - Crushflange: {Name: "Crushflange", Code: "mac", LevelReq: 9, Rarity: 1, ID: 19}, - Bloodrise: {Name: "Bloodrise", Code: "mst", LevelReq: 15, Rarity: 1, ID: 20}, - TheGeneralsTanDoLiGa: {Name: "The Generals Tan Do Li Ga", Code: "fla", LevelReq: 21, Rarity: 1, ID: 21}, - Ironstone: {Name: "Ironstone", Code: "whm", LevelReq: 27, Rarity: 1, ID: 22}, - Bonesob: {Name: "Bonesob", Code: "mau", LevelReq: 24, Rarity: 1, ID: 23}, - Steeldriver: {Name: "Steeldriver", Code: "gma", LevelReq: 29, Rarity: 1, ID: 24}, - RixotsKeen: {Name: "Rixots Keen", Code: "ssd", LevelReq: 2, Rarity: 1, ID: 25}, - BloodCrescent: {Name: "Blood Crescent", Code: "scm", LevelReq: 7, Rarity: 1, ID: 26}, - KrintizsSkewer: {Name: "Krintizs Skewer", Code: "sbr", LevelReq: 10, Rarity: 1, ID: 27}, - Gleamscythe: {Name: "Gleamscythe", Code: "flc", LevelReq: 13, Rarity: 1, ID: 28}, - // AzurewrathCrystalSword (ID: 29, Code: "crs") omitted: duplicate name with Phase Blade Azurewrath (ID: 301) + TheGnasher: {Name: "The Gnasher", Code: "hax", LevelReq: 5, Rarity: 1, ID: 0}, + Deathspade: {Name: "Deathspade", Code: "axe", LevelReq: 9, Rarity: 1, ID: 1}, + Bladebone: {Name: "Bladebone", Code: "2ax", LevelReq: 15, Rarity: 1, ID: 2}, + Mindrend: {Name: "Mindrend", Code: "mpi", LevelReq: 21, Rarity: 1, ID: 3}, + Rakescar: {Name: "Rakescar", Code: "wax", LevelReq: 27, Rarity: 1, ID: 4}, + FechmarsAxe: {Name: "Fechmars Axe", Code: "lax", LevelReq: 8, Rarity: 1, ID: 5}, + Goreshovel: {Name: "Goreshovel", Code: "bax", LevelReq: 14, Rarity: 1, ID: 6}, + TheChieftan: {Name: "The Chieftan", Code: "btx", LevelReq: 19, Rarity: 1, ID: 7}, + Brainhew: {Name: "Brainhew", Code: "gax", LevelReq: 25, Rarity: 1, ID: 8}, + TheHumongous: {Name: "The Humongous", Code: "gix", LevelReq: 29, Rarity: 1, ID: 9}, + IrosTorch: {Name: "Iros Torch", Code: "wnd", LevelReq: 5, Rarity: 1, ID: 10}, + Maelstromwrath: {Name: "Maelstromwrath", Code: "ywn", LevelReq: 14, Rarity: 1, ID: 11}, + Gravenspine: {Name: "Gravenspine", Code: "bwn", LevelReq: 20, Rarity: 1, ID: 12}, + UmesLament: {Name: "Umes Lament", Code: "gwn", LevelReq: 28, Rarity: 1, ID: 13}, + Felloak: {Name: "Felloak", Code: "clb", LevelReq: 3, Rarity: 1, ID: 14}, + KnellStriker: {Name: "Knell Striker", Code: "scp", LevelReq: 5, Rarity: 1, ID: 15}, + Rusthandle: {Name: "Rusthandle", Code: "gsc", LevelReq: 17, Rarity: 1, ID: 16}, + Stormeye: {Name: "Stormeye", Code: "wsp", LevelReq: 23, Rarity: 1, ID: 17}, + Stoutnail: {Name: "Stoutnail", Code: "spc", LevelReq: 5, Rarity: 1, ID: 18}, + Crushflange: {Name: "Crushflange", Code: "mac", LevelReq: 9, Rarity: 1, ID: 19}, + Bloodrise: {Name: "Bloodrise", Code: "mst", LevelReq: 15, Rarity: 1, ID: 20}, + TheGeneralsTanDoLiGa: {Name: "The Generals Tan Do Li Ga", Code: "fla", LevelReq: 21, Rarity: 1, ID: 21}, + Ironstone: {Name: "Ironstone", Code: "whm", LevelReq: 27, Rarity: 1, ID: 22}, + Bonesob: {Name: "Bonesob", Code: "mau", LevelReq: 24, Rarity: 1, ID: 23}, + Steeldriver: {Name: "Steeldriver", Code: "gma", LevelReq: 29, Rarity: 1, ID: 24}, + RixotsKeen: {Name: "Rixots Keen", Code: "ssd", LevelReq: 2, Rarity: 1, ID: 25}, + BloodCrescent: {Name: "Blood Crescent", Code: "scm", LevelReq: 7, Rarity: 1, ID: 26}, + KrintizsSkewer: {Name: "Krintizs Skewer", Code: "sbr", LevelReq: 10, Rarity: 1, ID: 27}, + Gleamscythe: {Name: "Gleamscythe", Code: "flc", LevelReq: 13, Rarity: 1, ID: 28}, GriswoldsEdge: {Name: "Griswolds Edge", Code: "bsd", LevelReq: 17, Rarity: 1, ID: 30}, Hellplague: {Name: "Hellplague", Code: "lsd", LevelReq: 22, Rarity: 1, ID: 31}, CulwensPoint: {Name: "Culwens Point", Code: "wsd", LevelReq: 29, Rarity: 1, ID: 32}, @@ -701,7 +698,6 @@ var UniqueItems = map[UniqueName]UniqueItemInfo{ Doombringer: {Name: "Doombringer", Code: "7b7", LevelReq: 69, Rarity: 1, ID: 260}, TheGrandfather: {Name: "The Grandfather", Code: "7gd", LevelReq: 81, Rarity: 1, ID: 261}, Wizardspike: {Name: "Wizardspike", Code: "7dg", LevelReq: 61, Rarity: 1, ID: 262}, - ConstrictingRing: {Name: "Constricting Ring", Code: "rin", LevelReq: 95, Rarity: 1, ID: 263}, Stormspire: {Name: "Stormspire", Code: "7wc", LevelReq: 70, Rarity: 1, ID: 264}, Eaglehorn: {Name: "Eaglehorn", Code: "6l7", LevelReq: 69, Rarity: 1, ID: 265}, Windforce: {Name: "Windforce", Code: "6lw", LevelReq: 73, Rarity: 1, ID: 266}, diff --git a/pkg/data/items.go b/pkg/data/items.go index e089df3..8f593ad 100644 --- a/pkg/data/items.go +++ b/pkg/data/items.go @@ -120,7 +120,11 @@ type Drop struct { } func (i Item) Desc() item.Description { - return item.Desc[i.ID] + id := i.ID + if item.ExpChar >= 3 && id >= item.ExpCharItemIDThreshold { + id += item.ExpCharItemIDOffset + } + return item.Desc[id] } func (i Item) Type() item.Type { diff --git a/pkg/data/skill/skilldesc.go b/pkg/data/skill/skilldesc.go index 0573f2b..7b7196a 100644 --- a/pkg/data/skill/skilldesc.go +++ b/pkg/data/skill/skilldesc.go @@ -3,7 +3,9 @@ package skill var Desc = map[SkillDesc]Description{ + "abyss": {Page: 3, Row: 6, Column: 3, ListRow: 3, IconCel: 58}, "amplify damage": {Page: 1, Row: 1, Column: 2, ListRow: 1, IconCel: 0}, + "apocalypse": {Page: 3, Row: 6, Column: 1, ListRow: 3, IconCel: 56}, "arctic blast": {Page: 3, Row: 2, Column: 3, ListRow: 3, IconCel: 36}, "armageddon": {Page: 3, Row: 6, Column: 1, ListRow: 3, IconCel: 50}, "attack": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, @@ -15,15 +17,19 @@ var Desc = map[SkillDesc]Description{ "battle cry": {Page: 3, Row: 4, Column: 1, ListRow: 3, IconCel: 40}, "battle orders": {Page: 3, Row: 5, Column: 2, ListRow: 3, IconCel: 46}, "berserk": {Page: 1, Row: 6, Column: 2, ListRow: 1, IconCel: 52}, + "bind demon": {Page: 1, Row: 6, Column: 3, ListRow: 1, IconCel: 18}, "blade fury": {Page: 1, Row: 4, Column: 3, ListRow: 1, IconCel: 10}, "blade mastery": {Page: 2, Row: 1, Column: 1, ListRow: 2, IconCel: 2}, "blade sentinel": {Page: 1, Row: 2, Column: 3, ListRow: 1, IconCel: 4}, "blade shield": {Page: 1, Row: 6, Column: 3, ListRow: 1, IconCel: 18}, + "blade warp": {Page: 2, Row: 4, Column: 1, ListRow: 2, IconCel: 34}, "blades of ice": {Page: 3, Row: 5, Column: 1, ListRow: 3, IconCel: 52}, "blaze": {Page: 1, Row: 3, Column: 1, ListRow: 1, IconCel: 20}, "blessed aim": {Page: 2, Row: 3, Column: 1, ListRow: 2, IconCel: 24}, "blessed hammer": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 32}, "blizzard": {Page: 3, Row: 5, Column: 1, ListRow: 3, IconCel: 46}, + "blood boil": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 14}, + "blood oath": {Page: 1, Row: 2, Column: 1, ListRow: 1, IconCel: 4}, "bloodgolem": {Page: 3, Row: 4, Column: 2, ListRow: 3, IconCel: 38}, "bone armor": {Page: 2, Row: 1, Column: 3, ListRow: 2, IconCel: 4}, "bone prison": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 44}, @@ -42,6 +48,7 @@ var Desc = map[SkillDesc]Description{ "claws of thunder": {Page: 3, Row: 4, Column: 1, ListRow: 3, IconCel: 58}, "clay golem": {Page: 3, Row: 2, Column: 2, ListRow: 3, IconCel: 18}, "cleansing": {Page: 3, Row: 3, Column: 1, ListRow: 3, IconCel: 38}, + "cleave": {Page: 2, Row: 2, Column: 2, ListRow: 2, IconCel: 36}, "cloak of shadows": {Page: 2, Row: 3, Column: 3, ListRow: 2, IconCel: 24}, "cobra strike": {Page: 3, Row: 3, Column: 2, ListRow: 3, IconCel: 50}, "cold arrow": {Page: 1, Row: 2, Column: 1, ListRow: 1, IconCel: 10}, @@ -49,15 +56,20 @@ var Desc = map[SkillDesc]Description{ "concentrate": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 36}, "concentration": {Page: 2, Row: 4, Column: 1, ListRow: 2, IconCel: 34}, "confuse": {Page: 1, Row: 4, Column: 1, ListRow: 1, IconCel: 30}, + "consume": {Page: 1, Row: 6, Column: 1, ListRow: 1, IconCel: 16}, "conversion": {Page: 1, Row: 5, Column: 1, ListRow: 1, IconCel: 30}, "conviction": {Page: 2, Row: 6, Column: 3, ListRow: 2, IconCel: 56}, "corpse explosion": {Page: 2, Row: 2, Column: 2, ListRow: 2, IconCel: 16}, "critical strike": {Page: 2, Row: 1, Column: 3, ListRow: 2, IconCel: 6}, + "cubeloot": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "cycle of life": {Page: 1, Row: 3, Column: 3, ListRow: 1, IconCel: 8}, "cyclone armor": {Page: 3, Row: 3, Column: 3, ListRow: 3, IconCel: 40}, + "death mark": {Page: 1, Row: 2, Column: 2, ListRow: 1, IconCel: 6}, "death sentry": {Page: 1, Row: 6, Column: 1, ListRow: 1, IconCel: 16}, "decrepify": {Page: 1, Row: 5, Column: 3, ListRow: 1, IconCel: 42}, "defiance": {Page: 3, Row: 2, Column: 2, ListRow: 3, IconCel: 16}, + "delerium change": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, + "demonic mastery": {Page: 1, Row: 1, Column: 1, ListRow: 1, IconCel: 0}, "dim vision": {Page: 1, Row: 2, Column: 1, ListRow: 1, IconCel: 10}, "dodge": {Page: 2, Row: 2, Column: 2, ListRow: 2, IconCel: 14}, "dopplezon": {Page: 2, Row: 5, Column: 1, ListRow: 2, IconCel: 44}, @@ -67,8 +79,13 @@ var Desc = map[SkillDesc]Description{ "dragon flight": {Page: 3, Row: 5, Column: 3, ListRow: 3, IconCel: 54}, "dragon tail": {Page: 3, Row: 4, Column: 3, ListRow: 3, IconCel: 48}, "dragon talon": {Page: 3, Row: 1, Column: 3, ListRow: 3, IconCel: 42}, + "echoing strike": {Page: 2, Row: 3, Column: 1, ListRow: 2, IconCel: 30}, + "eldritchblast": {Page: 2, Row: 5, Column: 2, ListRow: 2, IconCel: 28}, + "emotewheel": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "enchant": {Page: 1, Row: 4, Column: 3, ListRow: 1, IconCel: 32}, "energy shield": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 44}, + "engorge": {Page: 1, Row: 5, Column: 2, ListRow: 1, IconCel: 12}, + "enhanced entropy": {Page: 3, Row: 5, Column: 3, ListRow: 3, IconCel: 54}, "eruption": {Page: 3, Row: 3, Column: 1, ListRow: 3, IconCel: 38}, "evade": {Page: 2, Row: 5, Column: 2, ListRow: 2, IconCel: 46}, "exploding arrow": {Page: 1, Row: 3, Column: 3, ListRow: 1, IconCel: 20}, @@ -89,6 +106,7 @@ var Desc = map[SkillDesc]Description{ "firestorm": {Page: 3, Row: 1, Column: 1, ListRow: 3, IconCel: 32}, "fist of the heavens": {Page: 1, Row: 6, Column: 2, ListRow: 1, IconCel: 50}, "fists of fire": {Page: 3, Row: 2, Column: 1, ListRow: 3, IconCel: 44}, + "flame wave": {Page: 3, Row: 4, Column: 1, ListRow: 3, IconCel: 50}, "freezing arrow": {Page: 1, Row: 6, Column: 1, ListRow: 1, IconCel: 50}, "frenzy": {Page: 1, Row: 5, Column: 3, ListRow: 1, IconCel: 42}, "frost nova": {Page: 3, Row: 2, Column: 1, ListRow: 3, IconCel: 16}, @@ -100,6 +118,9 @@ var Desc = map[SkillDesc]Description{ "grim ward": {Page: 3, Row: 5, Column: 3, ListRow: 3, IconCel: 48}, "guided arrow": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 32}, "heart of wolverine": {Page: 1, Row: 4, Column: 1, ListRow: 1, IconCel: 10}, + "hex bane": {Page: 2, Row: 1, Column: 3, ListRow: 2, IconCel: 24}, + "hex purge": {Page: 2, Row: 3, Column: 3, ListRow: 2, IconCel: 32}, + "hex siphon": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 26}, "holy bolt": {Page: 1, Row: 2, Column: 2, ListRow: 1, IconCel: 10}, "holy fire": {Page: 2, Row: 2, Column: 2, ListRow: 2, IconCel: 12}, "holy freeze": {Page: 2, Row: 4, Column: 2, ListRow: 2, IconCel: 36}, @@ -119,6 +140,7 @@ var Desc = map[SkillDesc]Description{ "inferno": {Page: 1, Row: 2, Column: 1, ListRow: 1, IconCel: 10}, "inferno sentry": {Page: 1, Row: 5, Column: 2, ListRow: 1, IconCel: 14}, "inner sight": {Page: 2, Row: 1, Column: 1, ListRow: 2, IconCel: 4}, + "interact": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "iron maiden": {Page: 1, Row: 3, Column: 2, ListRow: 1, IconCel: 20}, "iron skin": {Page: 2, Row: 4, Column: 3, ListRow: 2, IconCel: 38}, "irongolem": {Page: 3, Row: 5, Column: 2, ListRow: 3, IconCel: 48}, @@ -128,6 +150,7 @@ var Desc = map[SkillDesc]Description{ "leap attack": {Page: 1, Row: 4, Column: 1, ListRow: 1, IconCel: 34}, "left hand swing": {Page: 0, Row: 0, Column: 0, ListRow: -1, IconCel: 10}, "left hand throw": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 12}, + "levitate": {Page: 2, Row: 1, Column: 1, ListRow: 2, IconCel: 20}, "life tap": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 32}, "lightning": {Page: 2, Row: 3, Column: 2, ListRow: 2, IconCel: 26}, "lightning bolt": {Page: 3, Row: 3, Column: 3, ListRow: 3, IconCel: 28}, @@ -135,14 +158,21 @@ var Desc = map[SkillDesc]Description{ "lightning mastery": {Page: 2, Row: 6, Column: 2, ListRow: 2, IconCel: 54}, "lightning sentry": {Page: 1, Row: 5, Column: 1, ListRow: 1, IconCel: 12}, "lightning strike": {Page: 3, Row: 6, Column: 2, ListRow: 3, IconCel: 56}, + "loot": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "lower resist": {Page: 1, Row: 6, Column: 2, ListRow: 1, IconCel: 50}, "mace mastery": {Page: 2, Row: 1, Column: 3, ListRow: 2, IconCel: 6}, "magic arrow": {Page: 1, Row: 1, Column: 2, ListRow: 1, IconCel: 0}, + "map": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, + "mark of the bear": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, + "mark of the wolf": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "maul": {Page: 2, Row: 3, Column: 3, ListRow: 2, IconCel: 56}, "meditation": {Page: 3, Row: 5, Column: 1, ListRow: 3, IconCel: 48}, "meteor": {Page: 1, Row: 5, Column: 2, ListRow: 1, IconCel: 40}, + "miasma bolt": {Page: 3, Row: 1, Column: 3, ListRow: 3, IconCel: 46}, + "miasma chains": {Page: 3, Row: 3, Column: 3, ListRow: 3, IconCel: 52}, "might": {Page: 2, Row: 1, Column: 1, ListRow: 2, IconCel: 4}, "mind blast": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 34}, + "mirrored blades": {Page: 2, Row: 6, Column: 2, ListRow: 2, IconCel: 38}, "molten boulder": {Page: 3, Row: 2, Column: 1, ListRow: 3, IconCel: 34}, "multiple shot": {Page: 1, Row: 2, Column: 2, ListRow: 1, IconCel: 12}, "natural resistance": {Page: 2, Row: 6, Column: 3, ListRow: 2, IconCel: 54}, @@ -161,6 +191,7 @@ var Desc = map[SkillDesc]Description{ "power strike": {Page: 3, Row: 2, Column: 2, ListRow: 3, IconCel: 16}, "prayer": {Page: 3, Row: 1, Column: 1, ListRow: 3, IconCel: 6}, "psychic hammer": {Page: 2, Row: 1, Column: 3, ListRow: 2, IconCel: 22}, + "psychic ward": {Page: 2, Row: 4, Column: 2, ListRow: 2, IconCel: 22}, "quickness": {Page: 2, Row: 2, Column: 1, ListRow: 2, IconCel: 36}, "rabies": {Page: 2, Row: 4, Column: 1, ListRow: 2, IconCel: 24}, "raise skeletal mage": {Page: 3, Row: 3, Column: 3, ListRow: 3, IconCel: 28}, @@ -171,7 +202,9 @@ var Desc = map[SkillDesc]Description{ "resist fire": {Page: 3, Row: 1, Column: 3, ListRow: 3, IconCel: 8}, "resist lightning": {Page: 3, Row: 3, Column: 3, ListRow: 3, IconCel: 28}, "revive": {Page: 3, Row: 6, Column: 3, ListRow: 3, IconCel: 58}, + "ring of fire": {Page: 3, Row: 2, Column: 1, ListRow: 3, IconCel: 42}, "royal strike": {Page: 3, Row: 6, Column: 2, ListRow: 3, IconCel: 56}, + "runtoggle": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "sacrifice": {Page: 1, Row: 1, Column: 1, ListRow: 1, IconCel: 0}, "salvation": {Page: 3, Row: 6, Column: 3, ListRow: 3, IconCel: 58}, "sanctuary": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 46}, @@ -184,6 +217,10 @@ var Desc = map[SkillDesc]Description{ "shock field": {Page: 1, Row: 2, Column: 1, ListRow: 1, IconCel: 2}, "shock wave": {Page: 2, Row: 5, Column: 3, ListRow: 2, IconCel: 28}, "shout": {Page: 3, Row: 2, Column: 2, ListRow: 3, IconCel: 24}, + "showitems": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, + "sigil death": {Page: 3, Row: 5, Column: 2, ListRow: 3, IconCel: 48}, + "sigil lethargy": {Page: 3, Row: 2, Column: 2, ListRow: 3, IconCel: 40}, + "sigil rancor": {Page: 3, Row: 3, Column: 2, ListRow: 3, IconCel: 44}, "skeleton mastery": {Page: 3, Row: 1, Column: 1, ListRow: 3, IconCel: 6}, "slow missiles": {Page: 2, Row: 3, Column: 1, ListRow: 2, IconCel: 22}, "smite": {Page: 1, Row: 1, Column: 3, ListRow: 1, IconCel: 2}, @@ -192,10 +229,14 @@ var Desc = map[SkillDesc]Description{ "static field": {Page: 2, Row: 2, Column: 1, ListRow: 2, IconCel: 12}, "strafe": {Page: 1, Row: 5, Column: 2, ListRow: 1, IconCel: 40}, "stun": {Page: 1, Row: 3, Column: 2, ListRow: 1, IconCel: 26}, + "summon defiler": {Page: 1, Row: 4, Column: 3, ListRow: 1, IconCel: 10}, "summon fenris": {Page: 1, Row: 4, Column: 2, ListRow: 1, IconCel: 12}, + "summon goatman": {Page: 1, Row: 1, Column: 3, ListRow: 1, IconCel: 2}, "summon grizzly": {Page: 1, Row: 6, Column: 2, ListRow: 1, IconCel: 18}, "summon resist": {Page: 3, Row: 5, Column: 1, ListRow: 3, IconCel: 46}, "summon spirit wolf": {Page: 1, Row: 2, Column: 2, ListRow: 1, IconCel: 6}, + "summon tainted": {Page: 1, Row: 3, Column: 3, ListRow: 1, IconCel: 8}, + "swapweapons": {Page: 0, Row: 0, Column: 0, ListRow: 0, IconCel: 2}, "taunt": {Page: 3, Row: 2, Column: 1, ListRow: 3, IconCel: 22}, "teeth": {Page: 2, Row: 1, Column: 2, ListRow: 2, IconCel: 2}, "telekinesis": {Page: 2, Row: 2, Column: 3, ListRow: 2, IconCel: 14}, diff --git a/pkg/memory/game_reader.go b/pkg/memory/game_reader.go index 0e65efb..e8b720a 100644 --- a/pkg/memory/game_reader.go +++ b/pkg/memory/game_reader.go @@ -20,6 +20,7 @@ type GameReader struct { monstersLastUpdate time.Time inventoryLastUpdate time.Time objectsLastUpdate time.Time + ExpChar uint16 cachedMonsters data.Monsters cachedInventory data.Inventory diff --git a/pkg/memory/item.go b/pkg/memory/item.go index 014c236..a1d495b 100644 --- a/pkg/memory/item.go +++ b/pkg/memory/item.go @@ -14,6 +14,7 @@ import ( ) func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverData) data.Inventory { + item.SetExpChar(gd.ExpChar) mainPlayer := rawPlayerUnits.GetMainPlayer() baseAddr := gd.Process.moduleBaseAddressPtr + gd.offset.UnitTable + (4 * 1024) unitTableBuffer := gd.Process.ReadBytesFromMemory(baseAddr, 128*8) @@ -355,7 +356,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD if location == item.LocationSocket { if itm.Desc().Code == "jew" { // Base requirement for jewels - itm.LevelReq = item.Desc[itm.ID].RequiredLevel + itm.LevelReq = itm.Desc().RequiredLevel // For magic/rare jewels, check affixes if itm.Quality == item.QualityMagic || itm.Quality == item.QualityRare { @@ -371,7 +372,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD } } else { // Normal socketed items (runes,gems) just use base requirement - itm.LevelReq = item.Desc[itm.ID].RequiredLevel + itm.LevelReq = itm.Desc().RequiredLevel } itemExtraData := uintptr(gd.Process.ReadUInt(unitDataPtr+0xA0, Uint64)) if itemExtraData != 0 { @@ -442,7 +443,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD // Build final inventory inventory.AllItems = make([]data.Item, len(allItems)) for i, itm := range allItems { - baseDesc := item.Desc[itm.ID] + baseDesc := itm.Desc() maxReq := calculateItemLevelReq(itm, baseDesc) // Check magic/rare affixes @@ -452,7 +453,7 @@ func (gd *GameReader) Inventory(rawPlayerUnits RawPlayerUnits, hover data.HoverD // Check socketed items for _, socketItem := range itm.Sockets { - socketBaseDesc := item.Desc[socketItem.ID] + socketBaseDesc := socketItem.Desc() socketReq := calculateItemLevelReq(&socketItem, socketBaseDesc) if socketReq > maxReq { diff --git a/pkg/memory/keybindings.go b/pkg/memory/keybindings.go index ad0cdb5..6082a28 100644 --- a/pkg/memory/keybindings.go +++ b/pkg/memory/keybindings.go @@ -12,6 +12,7 @@ func (gd *GameReader) GetKeyBindings() data.KeyBindings { blobSkills := gd.ReadBytesFromMemory(gd.moduleBaseAddressPtr+gd.offset.KeyBindingsSkillsOffset, 0x500) skillsKB := [16]data.SkillBinding{} + // Skills 0-6: slots 14-20 for i := 0; i < 7; i++ { skillsKB[i] = data.SkillBinding{ SkillID: skill.ID(binary.LittleEndian.Uint32(blobSkills[i*0x1c : i*0x1c+4])), @@ -21,8 +22,20 @@ func (gd *GameReader) GetKeyBindings() data.KeyBindings { }, } } - for i := 0; i < 9; i++ { + // Skills 7-13: slots 26-32 + for i := 0; i < 7; i++ { skillIdx := i + 7 + skillsKB[skillIdx] = data.SkillBinding{ + SkillID: skill.ID(binary.LittleEndian.Uint32(blobSkills[skillIdx*0x1c : skillIdx*0x1c+4])), + KeyBinding: data.KeyBinding{ + Key1: [2]byte{blob[0x208+(i*0x14)], blob[0x209+(i*0x14)]}, + Key2: [2]byte{blob[0x212+(i*0x14)], blob[0x213+(i*0x14)]}, + }, + } + } + // Skills 14-15: slots 45-46 + for i := 0; i < 2; i++ { + skillIdx := i + 14 skillsKB[skillIdx] = data.SkillBinding{ SkillID: skill.ID(binary.LittleEndian.Uint32(blobSkills[skillIdx*0x1c : skillIdx*0x1c+4])), KeyBinding: data.KeyBinding{ diff --git a/pkg/memory/offset.go b/pkg/memory/offset.go index 6e24274..9090251 100644 --- a/pkg/memory/offset.go +++ b/pkg/memory/offset.go @@ -26,61 +26,61 @@ type Offset struct { func calculateOffsets(_ *Process) Offset { // UnitTable - unitTableOffset := uintptr(0x1D95AF0) + unitTableOffset := uintptr(0x1E9B350) // UI - uiOffsetPtr := uintptr(0x1DA57DA) + uiOffsetPtr := uintptr(0x1EAB042) // Hover - hoverOffset := uintptr(0x1CE8400) + hoverOffset := uintptr(0x1DEF000) // Expansion - expOffset := uintptr(0x1CE78D0) + expOffset := uintptr(0x1DEE468) // Party members offset - rosterOffset := uintptr(0x1DABD60) + rosterOffset := uintptr(0x1EB1660) // PanelManagerContainer - panelManagerContainerOffset := uintptr(0x1D00968) + panelManagerContainerOffset := uintptr(0x1E05DC0) // WidgetStates - WidgetStatesOffset := uintptr(0x1DCDD40) + WidgetStatesOffset := uintptr(0x1ED3678) // Waypoints - WaypointTableOffset := uintptr(0x1C468B0) + WaypointTableOffset := uintptr(0x1D4D3C0) // FPS - fpsOffset := uintptr(0x1C46894) + fpsOffset := uintptr(0x1D4D394) // KeyBindings - keyBindingsOffset := uintptr(0x18C2894) + keyBindingsOffset := uintptr(0x19C65B4) // KeyBindings Skills - keyBindingsSkillsOffset := uintptr(0x1CE8510) + keyBindingsSkillsOffset := uintptr(0x1DEF110) // QuestInfo - questInfoOffset := uintptr(0x1DB23D8) + questInfoOffset := uintptr(0x1EB7CD8) // Terror Zones - tzOffset := uintptr(0x248D430) + tzOffset := uintptr(0x25A5AB0) // Ping - pingOffset := uintptr(0x1CE78D0) + pingOffset := uintptr(0x1DEE468) // LegacyGraphics - legacyGfxOffset := uintptr(0x1DB263E) + legacyGfxOffset := uintptr(0x1EB7E7E) // CharData - charDataOffset := uintptr(0x1CED5E8) + charDataOffset := uintptr(0x1DF25F8) // Selected Char Name - selectedCharNameOffset := uintptr(0x1C3D694) + selectedCharNameOffset := uintptr(0x1D44195) // Last Game Name - lastGameNameOffset := uintptr(0x24D5A90) + lastGameNameOffset := uintptr(0x25EE370) // Last Game Password - lastGamePasswordOffset := uintptr(0x24D5AE8) + lastGamePasswordOffset := uintptr(0x25EE3C8) return Offset{ UnitTable: unitTableOffset, diff --git a/pkg/memory/player.go b/pkg/memory/player.go index d34fdc0..7ea40a9 100644 --- a/pkg/memory/player.go +++ b/pkg/memory/player.go @@ -38,8 +38,9 @@ func (gd *GameReader) GetRawPlayerUnits() RawPlayerUnits { expCharPtr := uintptr(gd.Process.ReadUInt(gd.moduleBaseAddressPtr+gd.offset.Expansion, Uint64)) expChar := gd.Process.ReadUInt(expCharPtr+0x5C, Uint16) + gd.ExpChar = uint16(expChar) isMainPlayer := gd.Process.ReadUInt(inventoryAddr+0x30, Uint16) - if expChar > 0 { + if expChar >= 2 { isMainPlayer = gd.Process.ReadUInt(inventoryAddr+0x70, Uint16) } isCorpse := gd.Process.ReadUInt(playerUnit+0x1AE, Uint8) diff --git a/pkg/nip/rule_test.go b/pkg/nip/rule_test.go index 5b38e60..78b6ece 100644 --- a/pkg/nip/rule_test.go +++ b/pkg/nip/rule_test.go @@ -36,7 +36,7 @@ func TestRule_Evaluate(t *testing.T) { }, args: args{ item: data.Item{ - ID: 603, + ID: 618, Name: "SmAlLCharM", Quality: item.QualityMagic, Identified: true,