226 lines
6.8 KiB
Go
226 lines
6.8 KiB
Go
package data
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/emef/bitfield"
|
|
|
|
"code.ur.gs/lupine/ordoor/internal/util/asciiscan"
|
|
)
|
|
|
|
// AnimAction represents an animation that is stored in WarHammer.ani
|
|
type AnimAction int
|
|
|
|
// CharacterType represents one of the different types of character in the game.
|
|
//
|
|
// TODO: can we load the list of character types anywhere or is it hardcoded in
|
|
// the original too?
|
|
type CharacterType int
|
|
|
|
const (
|
|
AnimActionNone AnimAction = 0
|
|
AnimActionAnim AnimAction = 1
|
|
AnimActionWalk AnimAction = 2
|
|
AnimActionExplosion AnimAction = 3
|
|
AnimActionProjectile AnimAction = 4
|
|
AnimActionSmoke AnimAction = 5
|
|
AnimActionStandingShoot AnimAction = 6
|
|
AnimActionStandingDeath AnimAction = 7
|
|
AnimActionPain AnimAction = 8
|
|
AnimActionSpellFx1 AnimAction = 9
|
|
AnimActionSpellFx2 AnimAction = 10
|
|
AnimActionSpellFx3 AnimAction = 11
|
|
AnimActionSpellFx4 AnimAction = 12
|
|
AnimActionSpellFx5 AnimAction = 13
|
|
AnimActionRun AnimAction = 14
|
|
AnimActionCrouch AnimAction = 15
|
|
AnimActionStand AnimAction = 16
|
|
AnimActionStandingRead AnimAction = 17
|
|
AnimActionStandingUnready AnimAction = 18
|
|
AnimActionCrouchingReady AnimAction = 19
|
|
AnimActionCrouchingUnready AnimAction = 20
|
|
AnimActionCrouchingShoot AnimAction = 21
|
|
AnimActionStandingGrenade AnimAction = 22
|
|
AnimActionCrouchingGrenade AnimAction = 23
|
|
AnimActionDrawMelee AnimAction = 24
|
|
AnimActionSlash AnimAction = 25
|
|
AnimActionStab AnimAction = 26
|
|
AnimActionBlown AnimAction = 27
|
|
AnimActionCrouchingDeath AnimAction = 28
|
|
AnimActionJump AnimAction = 29
|
|
AnimActionHeal AnimAction = 30
|
|
AnimActionTechWork AnimAction = 31
|
|
AnimActionCast AnimAction = 32
|
|
AnimActionShoot AnimAction = 33
|
|
AnimActionDeath AnimAction = 34
|
|
AnimActionFromWarp AnimAction = 35
|
|
|
|
AnimActionStart = AnimActionNone
|
|
AnimActionEnd = AnimActionFromWarp
|
|
AnimActionCount = AnimActionEnd - AnimActionStart + 1
|
|
|
|
// FIXME: indexed from 1, very annoying
|
|
CharacterTypeTactical CharacterType = 1
|
|
CharacterTypeAssault CharacterType = 2
|
|
CharacterTypeDevastator CharacterType = 3
|
|
CharacterTypeTerminator CharacterType = 4
|
|
CharacterTypeApothecary CharacterType = 5
|
|
CharacterTypeTechmarine CharacterType = 6
|
|
CharacterTypeChaplain CharacterType = 7
|
|
CharacterTypeLibrarian CharacterType = 8
|
|
CharacterTypeCaptain CharacterType = 9
|
|
CharacterTypeChaosMarine CharacterType = 10
|
|
CharacterTypeChaosLord CharacterType = 11
|
|
CharacterTypeChaosChaplain CharacterType = 12
|
|
CharacterTypeChaosSorcerer CharacterType = 13
|
|
CharacterTypeChaosTerminator CharacterType = 14
|
|
CharacterTypeKhorneBerserker CharacterType = 15
|
|
CharacterTypeBloodThirster CharacterType = 16
|
|
CharacterTypeBloodLetter CharacterType = 17
|
|
CharacterTypeFleshHound CharacterType = 18
|
|
CharacterTypeLordOfChange CharacterType = 19
|
|
CharacterTypeFlamer CharacterType = 20
|
|
CharacterTypePinkHorror CharacterType = 21
|
|
CharacterTypeBlueHorror CharacterType = 22
|
|
CharacterTypeChaosCultist CharacterType = 23
|
|
|
|
CharacterTypeStart = CharacterTypeTactical
|
|
CharacterTypeEnd = CharacterTypeChaosCultist
|
|
CharacterTypeCount = CharacterTypeEnd - CharacterTypeStart + 1
|
|
)
|
|
|
|
// HasAction tells us whether a character has an animation or not.
|
|
type HasAction struct {
|
|
bits bitfield.BitField
|
|
}
|
|
|
|
var (
|
|
cTypes = map[CharacterType]string{
|
|
CharacterTypeTactical: "Tactical",
|
|
CharacterTypeAssault: "Assault",
|
|
CharacterTypeDevastator: "Devastator",
|
|
CharacterTypeTerminator: "Terminator",
|
|
CharacterTypeApothecary: "Apothecary",
|
|
CharacterTypeTechmarine: "Techmarine",
|
|
CharacterTypeChaplain: "Chaplain",
|
|
CharacterTypeLibrarian: "Librarian",
|
|
CharacterTypeCaptain: "Captain",
|
|
CharacterTypeChaosMarine: "Chaos Marine",
|
|
CharacterTypeChaosLord: "Chaos Lord",
|
|
CharacterTypeChaosChaplain: "Chaos Chaplain",
|
|
CharacterTypeChaosSorcerer: "Chaos Sorcerer",
|
|
CharacterTypeChaosTerminator: "Chaos Terminator",
|
|
CharacterTypeKhorneBerserker: "Knorne Berserker",
|
|
CharacterTypeBloodThirster: "Bloodthirster",
|
|
CharacterTypeBloodLetter: "Bloodletter",
|
|
CharacterTypeFleshHound: "Flesh Hound",
|
|
CharacterTypeLordOfChange: "Lord of Change",
|
|
CharacterTypeFlamer: "Flamer",
|
|
CharacterTypePinkHorror: "Pink Horror",
|
|
CharacterTypeBlueHorror: "Blue Horror",
|
|
CharacterTypeChaosCultist: "Cultist",
|
|
}
|
|
)
|
|
|
|
func (c CharacterType) String() string {
|
|
if str, ok := cTypes[c]; ok {
|
|
return str
|
|
}
|
|
|
|
return "Unknown Character"
|
|
}
|
|
|
|
func LoadHasAction(filename string) (*HasAction, error) {
|
|
scanner, err := asciiscan.New(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer scanner.Close()
|
|
|
|
out := &HasAction{
|
|
bits: bitfield.New(int(CharacterTypeCount) * int(AnimActionCount)),
|
|
}
|
|
|
|
// Reuse this for every loop
|
|
var actions [AnimActionCount]bool
|
|
ptrs := make([]*bool, len(actions))
|
|
for i, _ := range actions {
|
|
ptrs[i] = &actions[i]
|
|
}
|
|
|
|
for c := CharacterTypeStart; c <= CharacterTypeEnd; c++ {
|
|
if err := scanner.ConsumeBoolPtrs(ptrs...); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for j, value := range actions {
|
|
a := AnimActionStart + AnimAction(j)
|
|
|
|
out.set(c, a, value)
|
|
}
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func (h *HasAction) Check(c CharacterType, a AnimAction) bool {
|
|
return h.bits.Test(h.offset(c, a))
|
|
}
|
|
|
|
func (h *HasAction) offset(c CharacterType, a AnimAction) uint32 {
|
|
// Best to view this as a 2D array with CharacterTypeCount * AnimActionCount elements
|
|
i := uint32(c - CharacterTypeStart)
|
|
j := uint32(a - AnimActionStart)
|
|
|
|
return (i * uint32(AnimActionCount)) + j
|
|
}
|
|
|
|
func (h *HasAction) set(c CharacterType, a AnimAction, value bool) {
|
|
if value {
|
|
h.bits.Set(h.offset(c, a))
|
|
} else {
|
|
h.bits.Clear(h.offset(c, a))
|
|
}
|
|
}
|
|
|
|
// Actions returns the list of animations that a character type has
|
|
func (h *HasAction) Actions(c CharacterType) []AnimAction {
|
|
var out []AnimAction
|
|
|
|
for j := AnimActionStart; j < AnimActionCount; j++ {
|
|
if h.Check(c, j) {
|
|
out = append(out, j)
|
|
}
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
// FIXME: Too slow
|
|
func (h *HasAction) Index(c CharacterType, requestedAction AnimAction) int {
|
|
for i, action := range h.Actions(c) {
|
|
if action == requestedAction {
|
|
return i
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
func (h *HasAction) Print() {
|
|
fmt.Println(" Tac Ass Dev Term Apo Tech Chp Lib Cpt CMar CLrd CChp CSrc CTrm Kbz BTh BL FHnd LoC Flm PHr BHr Cult")
|
|
for a := AnimActionStart; a <= AnimActionEnd; a++ {
|
|
fmt.Printf("%.2d", int(a))
|
|
for c := CharacterTypeStart; c <= CharacterTypeEnd; c++ {
|
|
if h.Check(c, a) {
|
|
fmt.Print(" x ")
|
|
} else {
|
|
fmt.Print(" ")
|
|
}
|
|
}
|
|
|
|
fmt.Println("")
|
|
}
|
|
}
|