// tilDump creates a dump directory and dumps the TIL file's squares using the // pillars constructed based on the MIN format, once for each image config // (pal). func tilDump(tilName string) (err error) { squares, err := til.Parse(tilName) if err != nil { return err } nameWithoutExt := tilName[:len(tilName)-len(path.Ext(tilName))] minName := nameWithoutExt + ".min" pillars, err := min.Parse(minName) if err != nil { return err } imgName := nameWithoutExt + ".cel" relPalPaths := imgconf.GetRelPalPaths(imgName) for _, relPalPath := range relPalPaths { conf, err := cel.GetConf(imgName, relPalPath) if err != nil { return err } var palDir string if len(relPalPaths) > 1 { dbg.Println("using pal:", relPalPath) palDir = path.Base(relPalPath) + "/" } bar, err = barcli.New(len(squares)) if err != nil { return err } levelFrames, err := cel.DecodeAll(imgName, conf) if err != nil { return err } dumpDir := path.Clean(dumpPrefix+"_squares_/"+nameWithoutExt) + "/" + palDir // prevent directory traversal if !strings.HasPrefix(dumpDir, dumpPrefix) { return fmt.Errorf("path (%s) contains no dump prefix (%s).", dumpDir, dumpPrefix) } err = os.MkdirAll(dumpDir, 0755) if err != nil { return err } err = dumpSquares(squares, pillars, levelFrames, dumpDir) if err != nil { return err } } return nil }
// Parse parses a given DUN file and stores each pillarNum at a coordinate in // the dungeon, based on the DUN format described above. // // Below is a description of how the squares are positioned on the dungeon map: // 1) Start at the coordinates colStart, rowStart. // 2) Place a square. // - Each square is two cols in width and two rows in height. // 3) Increment col with two. // 4) goto 2) dunQWidth number of times. // 5) Increment row with two. // 6) goto 2) dunQHeight number of times. // // ref: GetPillarRect (illustration of map coordinate system) // // Any additional cell data is stored afterwards using row major. func (dungeon *Dungeon) Parse(dunName string) (err error) { dunPath, err := mpq.GetPath(dunName) if err != nil { return err } fr, err := os.Open(dunPath) if err != nil { return err } defer fr.Close() var tmp [2]uint16 err = binary.Read(fr, binary.LittleEndian, &tmp) if err != nil { return err } dunQWidth := int(tmp[0]) dunQHeight := int(tmp[1]) colStart, err := dunconf.GetColStart(dunName) if err != nil { return err } rowStart, err := dunconf.GetRowStart(dunName) if err != nil { return err } nameWithoutExt, err := GetLevelName(dunName) if err != nil { return err } // squareNumsPlus1. squares, err := til.Parse(nameWithoutExt + ".til") if err != nil { return err } row := rowStart for i := 0; i < dunQHeight; i++ { col := colStart for j := 0; j < dunQWidth; j++ { var x uint16 err = binary.Read(fr, binary.LittleEndian, &x) if err != nil { return err } squareNumPlus1 := int(x) if squareNumPlus1 != 0 { square := squares[squareNumPlus1-1] dungeon[col][row]["pillarNum"] = square.PillarNumTop dungeon[col+1][row]["pillarNum"] = square.PillarNumRight dungeon[col][row+1]["pillarNum"] = square.PillarNumLeft dungeon[col+1][row+1]["pillarNum"] = square.PillarNumBottom } col += 2 } row += 2 } dunWidth := 2 * dunQWidth dunHeight := 2 * dunQHeight // TODO: Figure out what these values are used for. Items? row = rowStart for i := 0; i < dunHeight; i++ { col := colStart for j := 0; j < dunWidth; j++ { var x uint16 err = binary.Read(fr, binary.LittleEndian, &x) if err != nil { // Some DUN files only contain the pillar IDs. if err == io.EOF && i == 0 && j == 0 { return nil } return err } dungeon[col][row]["unknown"] = int(x) col++ } row++ } // dunMonsterIDs. row = rowStart for i := 0; i < dunHeight; i++ { col := colStart for j := 0; j < dunWidth; j++ { var x uint16 err = binary.Read(fr, binary.LittleEndian, &x) if err != nil { if err == io.EOF && i == 0 && j == 0 { return nil } return err } // TODO: Lookup monster idx from dunMonsterID. // ref: 4B6C98 dungeon[col][row]["dunMonsterID"] = int(x) col++ } row++ } // dunObjectIDs. row = rowStart for i := 0; i < dunHeight; i++ { col := colStart for j := 0; j < dunWidth; j++ { var x uint16 err = binary.Read(fr, binary.LittleEndian, &x) if err != nil { if err == io.EOF && i == 0 && j == 0 { return nil } return err } // TODO: Lookup object idx from dunObjectID. // ref: 4AAD28 dungeon[col][row]["dunObjectID"] = int(x) col++ } row++ } // transparencies. row = rowStart for i := 0; i < dunHeight; i++ { col := colStart for j := 0; j < dunWidth; j++ { var x uint16 err = binary.Read(fr, binary.LittleEndian, &x) if err != nil { if err == io.EOF && i == 0 && j == 0 { return nil } return err } dungeon[col][row]["transparency"] = int(x) col++ } row++ } return nil }