package main import ( "flag" "fmt" "log" "path/filepath" "strings" "code.ur.gs/lupine/ordoor/internal/config" "code.ur.gs/lupine/ordoor/internal/data" "code.ur.gs/lupine/ordoor/internal/fonts" "code.ur.gs/lupine/ordoor/internal/idx" "code.ur.gs/lupine/ordoor/internal/maps" "code.ur.gs/lupine/ordoor/internal/menus" "code.ur.gs/lupine/ordoor/internal/sets" ) var ( configFile = flag.String("config", "config.toml", "Config file") engine = flag.String("engine", "", "Override engine to use") skipObj = flag.Bool("skip-obj", true, "Skip loading .obj files") ) // FIXME: all these paths are hardcoded with Chaos Gate in mind func main() { flag.Parse() cfg, err := config.Load(*configFile, *engine) if err != nil { log.Fatalf("Failed to load config: %v", err) } engine := cfg.DefaultEngine() gamePath := engine.DataDir loadData(filepath.Join(gamePath, "Data")) if !*skipObj { loadObj(filepath.Join(gamePath, "Obj")) } loadMapsFrom(filepath.Join(gamePath, "Maps")) loadMapsFrom(filepath.Join(gamePath, "MultiMaps")) loadSets(filepath.Join(gamePath, "Sets")) loadMenus(filepath.Join(gamePath, "Menu")) loadFonts(filepath.Join(gamePath, "Fonts")) loadIdx(filepath.Join(gamePath, "Idx", "WarHammer.idx")) } func loadData(dataPath string) { accountingPath := filepath.Join(dataPath, "Accounting.dat") aniObDefPath := filepath.Join(dataPath, "AniObDef.dat") genericDataPath := filepath.Join(dataPath, "GenericData.dat") hasActionPath := filepath.Join(dataPath, "HasAction.dat") i18nPath := filepath.Join(dataPath, data.I18nFile) log.Printf("Loading %s...", accountingPath) accounting, err := data.LoadAccounting(accountingPath) if err != nil { log.Fatalf("Failed to parse %s: %s", accountingPath, err) } log.Printf("%s: %+v", accountingPath, accounting) log.Printf("Loading %s...", aniObDefPath) animated, err := data.LoadAnimatedObjectDefinitions(aniObDefPath) if err != nil { log.Fatalf("Failed to parse %s: %s", genericDataPath, err) } log.Printf("%s: %+v", aniObDefPath, animated) log.Printf("Loading %s...", genericDataPath) genericData, err := data.LoadGeneric(genericDataPath) if err != nil { log.Fatalf("Failed to parse %s: %s", genericDataPath, err) } log.Printf("%s: %+v", genericDataPath, genericData) log.Printf("Loading %s...", i18nPath) i18n, err := data.LoadI18n(i18nPath) if err != nil { log.Fatalf("Failed to parse %s: %s", i18nPath, err) } log.Printf("%s: len=%v", i18nPath, i18n.Len()) ha, err := data.LoadHasAction(hasActionPath) if err != nil { log.Fatalf("Failed to parse %s: %v", hasActionPath, err) } ha.Print() } func loadObj(objDataPath string) { // TODO: Obj/cpiece.rec isn't loaded by this. Do we need it? How do we know? log.Printf("Loading %s...", objDataPath) objects, err := data.LoadObjects(objDataPath) if err != nil { log.Fatalf("Failed to parse %s: %s", objDataPath, err) } inspect := "c_webs" inspect_obj := inspect + ".obj" log.Printf("Objects in %s:", objDataPath) for key, obj := range objects { if key != inspect_obj { continue } log.Printf( "\t%s\t%d sprites\t%d bytes", key, obj.ObjectHeader.NumSprites, obj.ObjectHeader.DataSize, ) } log.Printf("%s: %#v", inspect, objects[inspect_obj]) for i, sprite := range objects[inspect_obj].Sprites { numPixels := sprite.Width * sprite.Height log.Printf("sprite %d: w=%d h=%d sz=%d w*h=%d bits/pixel=%v", i, sprite.Width, sprite.Height, sprite.PixelSize, numPixels, float64(sprite.PixelSize*8)/float64(numPixels)) } } func loadMapsFrom(mapsPath string) { log.Printf("Loading maps from %s", mapsPath) gameMaps, err := maps.LoadGameMaps(mapsPath) if err != nil { log.Fatalf("Failed to parse %s/*.{MAP,txt} as game maps: %v", mapsPath, err) } log.Printf("Maps in %s:", mapsPath) for key, gameMap := range gameMaps { rect := gameMap.Rect() hdr := gameMap.Header fmt.Printf( " * `%s`: IsCampaignMap=%v W=%v:%v L=%v:%v SetName=%s\n", key, hdr.IsCampaignMap, rect.Min.X, rect.Max.X, rect.Min.Y, rect.Max.Y, string(hdr.SetName[:]), ) } } func loadSets(setsPath string) { log.Printf("Loading sets from %s", setsPath) mapSets, err := sets.LoadSets(setsPath) if err != nil { log.Fatalf("Failed to parse %s/*.set as map sets: %v", setsPath, err) } for key, mapSet := range mapSets { fmt.Printf(" * `%s`: surface expected=%d actual=%d\n", key, mapSet.SurfaceCount, len(mapSet.SurfacePalette)) fmt.Printf(" * `%s`: left expected=%d actual=%d\n", key, mapSet.LeftCount, len(mapSet.LeftPalette)) fmt.Printf(" * `%s`: right expected=%d actual=%d\n", key, mapSet.RightCount, len(mapSet.RightPalette)) fmt.Printf(" * `%s`: center expected=%d actual=%d\n", key, mapSet.CenterCount, len(mapSet.CenterPalette)) } } func loadMenus(menusPath string) { log.Printf("Loading menus from %s", menusPath) menus, err := menus.LoadMenus(menusPath) if err != nil { log.Fatalf("Failed to parse %s/*.mnu as menus: %v", menusPath, err) } for _, menu := range menus { fmt.Printf(" * `%s`: objects=%v fonts=%v\n", menu.Name, menu.ObjectFiles, menu.FontNames) for _, group := range menu.Groups { // TODO: display group for _, record := range group.Records { displayRecord(record, 2) } } } } func displayRecord(record *menus.Record, depth int) { content := fmt.Sprintf("id=%v type=%v sprite=%v", record.ID, record.Type, record.SpriteId) if !record.Active { content = "(" + content + ")" } fmt.Printf("%s* %s\n", strings.Repeat(" ", depth), content) } func loadFonts(fontsPath string) { log.Printf("Loading fonts from %s", fontsPath) fonts, err := fonts.LoadFonts(fontsPath) if err != nil { log.Fatalf("Failed to parse %s/*.fnt as fonts: %v", fontsPath, err) } for _, font := range fonts { fmt.Printf(" * `%s`: obj=%v entries=%v\n", font.Name, font.ObjectFile, font.Entries()) } } func loadIdx(idxPath string) { log.Printf("Loading idx from %s", idxPath) idx, err := idx.Load(idxPath) if err != nil { log.Fatalf("Failed to parse %s as idx: %v", idxPath, err) } for i, group := range idx.Groups { log.Printf("Group %2d: %4d records, start sprite is %6d", i, len(group.Records), group.Spec.SpriteIdx) } }