package assetstore import ( "fmt" "code.ur.gs/lupine/ordoor/internal/data" "code.ur.gs/lupine/ordoor/internal/idx" ) type Animation struct { Frames []*Sprite } func (a *AssetStore) AnimationsIndex() (*idx.Idx, error) { if a.idx != nil { return a.idx, nil } filename, err := a.lookup("WarHammer", "idx", "Idx") if err != nil { return nil, err } idx, err := idx.Load(filename) if err != nil { return nil, err } a.idx = idx return idx, nil } func (a *AssetStore) AnimationsObject() (*Object, error) { if a.aniObj != nil { return a.aniObj, nil } filename, err := a.lookup("WarHammer", "ani", "Anim") if err != nil { return nil, err } obj, err := a.ObjectByPath(filename) if err != nil { return nil, err } a.aniObj = obj return obj, nil } func (a *AssetStore) Animation(groupIdx int, recId int, compass int) (*Animation, error) { realIdx, err := a.AnimationsIndex() if err != nil { return nil, err } // FIXME: are we using the right value if we need to make this change? if compass == 0 { compass = 8 } obj, err := a.AnimationsObject() if err != nil { return nil, err } group := realIdx.Groups[groupIdx] if group.Spec.Count == 0 { return &Animation{}, nil } var det *idx.Detail for i, rec := range group.Records { if /*int(rec.ActionID) == int(action) && */ int(rec.Compass) == compass { det = &group.Details[i] } } if det == nil { return nil, fmt.Errorf("Couldn't find anim (%v %v %v)", groupIdx, recId, compass) } first := int(group.Spec.SpriteIdx) + int(det.FirstSprite) last := int(group.Spec.SpriteIdx) + int(det.LastSprite) count := last - first + 1 sprites, err := obj.Sprites(first, count) if err != nil { return nil, err } return &Animation{Frames: sprites}, nil } func (a *AssetStore) CharacterAnimation(ctype data.CharacterType, action data.AnimAction, compass int) (*Animation, error) { ha, err := a.HasAction() if err != nil { return nil, err } if !ha.Check(ctype, action) { return nil, fmt.Errorf("character %s: animation %s: not available", ctype, action) } // FIXME: we still need to be able to go from CTYPE to GROUP. In particular, // squad leaders seem to be a modification on top of a previous group, which // is a bit awkward. For now, hardcode it. How are captain modifiers stored? group, ok := map[data.CharacterType]int{ data.CharacterTypeTactical: 1, // Has captain data.CharacterTypeAssault: 3, // Has captain data.CharacterTypeDevastator: 5, data.CharacterTypeTerminator: 6, // Has captain data.CharacterTypeApothecary: 8, data.CharacterTypeTechmarine: 9, data.CharacterTypeChaplain: 10, data.CharacterTypeLibrarian: 11, data.CharacterTypeCaptain: 12, data.CharacterTypeChaosMarine: 13, data.CharacterTypeChaosLord: 14, data.CharacterTypeChaosChaplain: 15, data.CharacterTypeChaosSorcerer: 16, data.CharacterTypeChaosTerminator: 17, data.CharacterTypeKhorneBerserker: 18, data.CharacterTypeBloodThirster: 19, // This is a rotating thing? data.CharacterTypeBloodLetter: 20, data.CharacterTypeFleshHound: 21, data.CharacterTypeLordOfChange: 22, // Another rotating thing? data.CharacterTypeFlamer: 23, data.CharacterTypePinkHorror: 24, data.CharacterTypeBlueHorror: 25, data.CharacterTypeChaosCultist: 26, }[ctype] if !ok { return nil, fmt.Errorf("Unknown character type: %s", ctype) } return a.Animation(group, int(action), compass) }