I can parse some of the data files, and extract individual frames from .obj files. I can't yet convert those frames into something viewable.
340 lines
12 KiB
Go
340 lines
12 KiB
Go
package data
|
|
|
|
type ActionPointEnum int
|
|
type SettingEnum int
|
|
type TransitionFrameEnum int
|
|
type SquadTypeEnum int // just for the multiplayer choose units menu
|
|
type VehicleTypeEnum int // just for the multiplayer choose units screen
|
|
type OptionEnum int // differs from settings in that these are defaults changeable from the UI
|
|
type SpellEnum int
|
|
type AIPriorityEnum int // FIXME: no idea what this is for
|
|
type RngRangeEnum int
|
|
|
|
// VEHICLE_WALK_TRANSITION_FRAME entries
|
|
|
|
const (
|
|
APCastSpell ActionPointEnum = 0
|
|
APWalk = 1
|
|
APRun = 2
|
|
APTurn = 3
|
|
APCrouch = 4
|
|
APStand = 5
|
|
APOpenDoor = 6
|
|
APDropItem = 7
|
|
APPickupItem = 8
|
|
APThrowItem = 9
|
|
APUseMedikit = 10
|
|
APUseScanner = 11
|
|
APJump = 12
|
|
APThrowGrenade = 13
|
|
APHalfTurn = 14
|
|
APToClearJammedWeapon = 15
|
|
APHandToHandRound = 16
|
|
APToUseSwitch = 17
|
|
APToUseKey = 18
|
|
APToBoardDisembark = 19
|
|
APWhenOnFire = 20
|
|
APWhenBroken = 21
|
|
APMax = 22
|
|
|
|
SettingOccasionalSoundPercent SettingEnum = 0
|
|
SettingOccasionalMovementSound = 1
|
|
SettingFullJumpFuel = 2
|
|
SettingMaxJumpDistance = 3
|
|
SettingFlyFramesPerCell = 4
|
|
SettingPowerArmorRating = 5
|
|
SettingTerminatorArmorRating = 6
|
|
SettingBloodThirsterArmorRating = 7
|
|
SettingDemonicArmorRating = 8
|
|
SettingPrimitiveArmorRating = 9
|
|
SettingHorrorArmorRating = 10
|
|
SettingArmorDice = 11
|
|
SettingJumpPixelsPerFrame = 12
|
|
SettingCharacterAnimationDelay = 13
|
|
SettingVehicleAnimationDelay = 14
|
|
SettingLoopingEffectsDelay = 15
|
|
SettingFireAnimationDelay = 16
|
|
SettingCharacterFireTransparency = 17
|
|
SettingMissileDrawOffset = 18 // pixels per missing piece
|
|
SettingWeaponJamPercent = 19 // to two decimal places
|
|
SettingScanFrequency = 20
|
|
SettingCoverSearchRadius = 21
|
|
SettingDialogAutoCloseTime = 22
|
|
SettingPointBlankBallisticSkillBonus = 23
|
|
SettingPointBlankRange = 24
|
|
SettingMinimumOverwatchShotPercent = 25
|
|
SettingMultipleSekectDragTolerance = 26
|
|
SettingStandingGuardPostRadius = 27
|
|
SettingMaxDemonFlyDistance = 28
|
|
SettingSpellLoopingVolume = 29 // percentage, 0 decimal places
|
|
SettingPercentOfChaosInSecondaryQuadrant = 30
|
|
SettingNumberOfRandomCrates = 31
|
|
SettingMax = 32
|
|
|
|
TFDeletedVehicle TransitionFrameEnum = 0
|
|
TFUltraRhino = 1
|
|
TFUltraPredator = 2
|
|
TFUltraLandSpeeder = 3
|
|
TFUltraDreadnought = 4
|
|
TFChaosRhino = 5
|
|
TFChaosPredator = 6
|
|
TFChaosDreadnought = 7
|
|
TFMax = 8
|
|
|
|
SquadTerminator SquadTypeEnum = 0
|
|
SquadTactical = 1
|
|
SquadAssault = 2
|
|
SquadDevastator = 3
|
|
SquadChaos = 4
|
|
SquadChaosKhorne = 5
|
|
SquadChaosTerminator = 6
|
|
SquadChaosCultise = 7
|
|
SquadLibrarian = 8
|
|
SquadTechmarine = 9
|
|
SquadApothecary = 10
|
|
SquadChaplain = 11
|
|
SquadCaptain = 12
|
|
SquadChaosLord = 13
|
|
SquadChaosChaplain = 14
|
|
SquadChaosSorcerer = 15
|
|
SauadChaosBlodThirster = 16
|
|
SquadChaosBlootLetter = 17
|
|
SquadChaosFleshHound = 18
|
|
SquadChaosLordOfChange = 19
|
|
SquadChaosFlamer = 20
|
|
SquadChaosPinkHorror = 21
|
|
SquadChaosBlueHorror = 22
|
|
SquadMax = 23
|
|
|
|
VehicleUltraRhino VehicleTypeEnum = 0
|
|
VehicleUltraPredator = 1
|
|
VehicleUltraLandSpeeder = 2
|
|
VehicleUltraDreadnought = 3
|
|
VehicleChaosRhino = 4
|
|
VehicleChaosPredator = 5
|
|
VehicleChaosDreadnought = 6
|
|
VehicleMax = 7
|
|
|
|
OptionMovies OptionEnum = 0
|
|
OptionMusic = 1
|
|
OptionCombatVoices = 2
|
|
OptionGrid = 3
|
|
OptionShowPaths = 4
|
|
OptionPointSave = 5
|
|
OptionAutoCutLevel = 6
|
|
OptionShowUnitAnimations = 7
|
|
OptionCombatResolution = 8
|
|
OptionMusicVolume = 9 // percentage, 0df
|
|
OptionSoundEffectsVolume = 10 // percentage, 0df
|
|
OptionUnitAnimationSpeed = 11 // percentage, 0df, see CHARCTER ANIMATION DELAY / VEHICLE ANIMATION DELAY for worst case value
|
|
OptionEffectAnimationSpeed = 12 // percentage, 0d, see LOOPING_EFFECTS_DELAY for worst case value
|
|
OptionMax = 13
|
|
|
|
SpellHellfire SpellEnum = 0
|
|
SpellLightningArc = 1
|
|
SpellGate = 2
|
|
SpellAssail = 3
|
|
SpellDisplacement = 4
|
|
SpellMachineCurse = 5
|
|
SpellScan = 6
|
|
SpellQuickening = 7
|
|
SpellStrengthOfMind = 8
|
|
SpellSmite = 9
|
|
SpellIronArm = 10
|
|
SpellSalamandar = 11
|
|
SpellTeleport = 12
|
|
SpellPsychicShield = 13
|
|
SpellDestroyDemon = 14
|
|
SpellHolocaust = 15
|
|
SpellScourge = 16
|
|
SpellPurge = 17
|
|
SpellAuraOfFire = 18
|
|
SpellVortex = 19
|
|
SpellStormOfWrath = 20
|
|
SpellAuraOfFortitude = 21
|
|
SpellPinkFireOfTzeentch = 22
|
|
SpellBoltOfChange = 23
|
|
SpellTzeentchFireStore = 24
|
|
SpellMax = 25
|
|
|
|
AIPrioritySpecialCharacter = 0
|
|
AIPriorityVehicle = 1
|
|
AIPriorityTerminator = 2
|
|
AIPriorityHeavyWeapon = 3
|
|
AIPriorityRegular = 4
|
|
AIPriorityCultist = 5
|
|
AIPriorityMax = 6
|
|
|
|
RngRangeVehicleHillHeight RngRangeEnum = 0
|
|
RngRangeVehicleHillWidth = 1
|
|
RngRangeVehicleHillDensity = 2
|
|
RngRangeVehicleLargeObjectDensity = 3
|
|
RngRangeVehicleSmallObjectDensity = 4
|
|
RngRangeNoVehicleHillHeight = 5
|
|
RngRangeNoVehicleHillWidth = 6
|
|
RngRangeNoVehicleHillDensity = 7
|
|
RngRangeNoVehicleLargeObjectDensity = 8
|
|
RngRangeNoVehicleSmallObjectDensity = 9
|
|
RngRangeMax = 10
|
|
|
|
// FIXME: is this really a hardcoded value?
|
|
NumCampaignScenarios = 15
|
|
)
|
|
|
|
type Generic struct {
|
|
ActionPoints map[ActionPointEnum]int
|
|
Settings map[SettingEnum]int
|
|
VehicleWalkTransitionFrames map[TransitionFrameEnum]CompassPoints
|
|
MPChooseUnitSquadLimits map[SquadTypeEnum]int
|
|
|
|
// I'm assuming this is to do with MP becauses squads are. I could be wrong.
|
|
MPChooseVehicleLimits map[VehicleTypeEnum]int
|
|
|
|
Options map[OptionEnum]int
|
|
|
|
CampaignMaps []string
|
|
CampaignEndMissionWavs []string
|
|
|
|
AICoherentForce int // Range that defnines a coherent for for the AI. No idea
|
|
AISpellDeltaPriorityWeights map[SpellEnum]int // AI delta priority weights for each spell
|
|
AIPriority map[AIPriorityEnum]int
|
|
AICommandInfiniteLoopCounterWatermark int // Messing with this can cripple the API...
|
|
|
|
RngRanges map[RngRangeEnum]Range
|
|
}
|
|
|
|
// TODO: consume these values from the file
|
|
func LoadGeneric(filename string) (*Generic, error) {
|
|
scanLines, err := fileToScanner(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out := &Generic{
|
|
ActionPoints: make(map[ActionPointEnum]int),
|
|
Settings: make(map[SettingEnum]int),
|
|
VehicleWalkTransitionFrames: make(map[TransitionFrameEnum]CompassPoints),
|
|
MPChooseUnitSquadLimits: make(map[SquadTypeEnum]int),
|
|
MPChooseVehicleLimits: make(map[VehicleTypeEnum]int),
|
|
Options: make(map[OptionEnum]int),
|
|
AISpellDeltaPriorityWeights: make(map[SpellEnum]int),
|
|
AIPriority: make(map[AIPriorityEnum]int),
|
|
RngRanges: make(map[RngRangeEnum]Range),
|
|
}
|
|
|
|
// Various action point values, first to last
|
|
for ap := ActionPointEnum(0); ap < APMax; ap++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.ActionPoints[ap] = val
|
|
}
|
|
|
|
// Other miscellaneous data fields, first to last
|
|
for setting := SettingEnum(0); setting < SettingMax; setting++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.Settings[setting] = val
|
|
}
|
|
|
|
// Vehicle walk transition frames. Whatever they are.
|
|
for tf := TransitionFrameEnum(0); tf < TFMax; tf++ {
|
|
val, err := consumeCompassPoints(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.VehicleWalkTransitionFrames[tf] = val
|
|
}
|
|
|
|
for st := SquadTypeEnum(0); st < SquadMax; st++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.MPChooseUnitSquadLimits[st] = val
|
|
}
|
|
|
|
for vt := VehicleTypeEnum(0); vt < VehicleMax; vt++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.MPChooseVehicleLimits[vt] = val
|
|
}
|
|
|
|
for op := OptionEnum(0); op < OptionMax; op++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.Options[op] = val
|
|
}
|
|
|
|
for i := 0; i < NumCampaignScenarios; i++ {
|
|
val, err := consumeString(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.CampaignMaps = append(out.CampaignMaps, val)
|
|
}
|
|
|
|
for i := 0; i < NumCampaignScenarios; i++ {
|
|
val, err := consumeString(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// FIXME: "none" is a special-case value here
|
|
out.CampaignEndMissionWavs = append(out.CampaignEndMissionWavs, val)
|
|
}
|
|
|
|
out.AICoherentForce, err = consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for sp := SpellEnum(0); sp < SpellMax; sp++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.AISpellDeltaPriorityWeights[sp] = val
|
|
}
|
|
|
|
for ai := AIPriorityEnum(0); ai < AIPriorityMax; ai++ {
|
|
val, err := consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.AIPriority[ai] = val
|
|
}
|
|
|
|
out.AICommandInfiniteLoopCounterWatermark, err = consumeInt(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for rg := RngRangeEnum(0); rg < RngRangeMax; rg++ {
|
|
val, err := consumeRange(scanLines)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out.RngRanges[rg] = val
|
|
}
|
|
|
|
return out, nil
|
|
}
|