add marathon 1 data loaders
parent
49253773a6
commit
17a882cb20
115
MarathonData.md
115
MarathonData.md
|
@ -380,14 +380,14 @@ Map tags:
|
||||||
| `LITE` | Array of Light |
|
| `LITE` | Array of Light |
|
||||||
| `NOTE` | Array of Annotation |
|
| `NOTE` | Array of Annotation |
|
||||||
| `OBJS` | Array of Object |
|
| `OBJS` | Array of Object |
|
||||||
| `påth` | Not analyzed (guardpaths) (å is $8C) |
|
|
||||||
| `plac` | Array of Object Frequency |
|
| `plac` | Array of Object Frequency |
|
||||||
| `door` | No test data (extra door data) |
|
|
||||||
| `plat` | Array of Platform Data |
|
| `plat` | Array of Platform Data |
|
||||||
| `medi` | Array of Media Data |
|
| `medi` | Array of Media Data |
|
||||||
| `ambi` | Array of Ambient Sound |
|
| `ambi` | Array of Ambient Sound |
|
||||||
| `bonk` | Array of Random Sound |
|
| `bonk` | Array of Random Sound |
|
||||||
| `term` | Array of Terminal |
|
| `term` | Array of Terminal |
|
||||||
|
| `påth` | Unused, supposed to be guardpaths (å is $8C) |
|
||||||
|
| `door` | Unused, supposed to be extra door data |
|
||||||
|
|
||||||
Map files can be identified by the `Minf` chunk.
|
Map files can be identified by the `Minf` chunk.
|
||||||
|
|
||||||
|
@ -395,7 +395,8 @@ Maps will always have either a `PNTS` or `EPNT` chunk, depending on what the
|
||||||
map (and editor) use. `PNTS` are plain and have no more information than the
|
map (and editor) use. `PNTS` are plain and have no more information than the
|
||||||
actual position, while `EPNT` can be loaded directly into memory by the engine.
|
actual position, while `EPNT` can be loaded directly into memory by the engine.
|
||||||
`EPNT` also tells the engine that the map is preprocessed and that `iidx` and
|
`EPNT` also tells the engine that the map is preprocessed and that `iidx` and
|
||||||
`PLAT` chunks also exist.
|
`PLAT` chunks also exist. With `DataVersion` as `DataM1`, the format must
|
||||||
|
always be preprocessed.
|
||||||
|
|
||||||
Physics tags:
|
Physics tags:
|
||||||
|
|
||||||
|
@ -416,7 +417,7 @@ Image tags:
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ---- | ----------- |
|
| ---- | ----------- |
|
||||||
| `PICT` | Picture Resource |
|
| `PICT` | Picture Resource |
|
||||||
| `clut` | Unused? |
|
| `clut` | Banished to the shadow realm |
|
||||||
|
|
||||||
Images can be identified by the `PICT` chunk.
|
Images can be identified by the `PICT` chunk.
|
||||||
|
|
||||||
|
@ -427,7 +428,6 @@ Save file tags:
|
||||||
| `plyr` | Not analyzed (saved player data) |
|
| `plyr` | Not analyzed (saved player data) |
|
||||||
| `dwol` | Not analyzed (saved dynamic world data) |
|
| `dwol` | Not analyzed (saved dynamic world data) |
|
||||||
| `mobj` | Not analyzed (saved object data) |
|
| `mobj` | Not analyzed (saved object data) |
|
||||||
| `door` | Not analyzed (saved door data) |
|
|
||||||
| `iidx` | Not analyzed (saved map indices) |
|
| `iidx` | Not analyzed (saved map indices) |
|
||||||
| `alin` | Not analyzed (saved automap lines) |
|
| `alin` | Not analyzed (saved automap lines) |
|
||||||
| `apol` | Not analyzed (saved automap polygons) |
|
| `apol` | Not analyzed (saved automap polygons) |
|
||||||
|
@ -607,8 +607,8 @@ Light Function is 14 bytes.
|
||||||
| `Type` | `u16` | `0` |
|
| `Type` | `u16` | `0` |
|
||||||
| `Period` | `u16` | `2` |
|
| `Period` | `u16` | `2` |
|
||||||
| `DeltaPeriod` | `u16` | `4` |
|
| `DeltaPeriod` | `u16` | `4` |
|
||||||
| `Value` | `u16` | `6` |
|
| `Value` | `fixed` | `6` |
|
||||||
| `DeltaValue` | `u16` | `10` |
|
| `DeltaValue` | `fixed` | `10` |
|
||||||
|
|
||||||
- `Type` is a Light Function enumeration.
|
- `Type` is a Light Function enumeration.
|
||||||
|
|
||||||
|
@ -701,14 +701,16 @@ Side is 64 bytes. One possibly textured side of a line segment.
|
||||||
- `Type` is a Side Type enumeration.
|
- `Type` is a Side Type enumeration.
|
||||||
- `Flags` is a Side Flags bit field.
|
- `Flags` is a Side Flags bit field.
|
||||||
- `TexPri`, `TexSec` and `TexTra` are Side Texture structures representing the
|
- `TexPri`, `TexSec` and `TexTra` are Side Texture structures representing the
|
||||||
primary, secondary and transparent (middle) textures.
|
primary, secondary and transparent (middle) textures. Middle textures are not
|
||||||
|
supported if `DataVersion` is `DataM1` and so `TexTra` must be set to none.
|
||||||
- `ExTopL`, `ExTopR`, `ExBotL` and `ExBotR` are Point structures representing
|
- `ExTopL`, `ExTopR`, `ExBotL` and `ExBotR` are Point structures representing
|
||||||
the collision bounding rectangle.
|
the collision bounding rectangle.
|
||||||
- `PanelType` is a control panel preset number.
|
- `PanelType` is a control panel preset number.
|
||||||
- `PanelPerm` is the permutation for this control panel (if any.)
|
- `PanelPerm` is the permutation for this control panel (if any.)
|
||||||
- `XferPri`, `XferSec` and `XferTra` are Transfer Mode enumerations for each
|
- `XferPri`, `XferSec` and `XferTra` are Transfer Mode enumerations for each
|
||||||
respective texture.
|
respective texture.
|
||||||
- `Shade` is the ambient shading used primarily for visual contrast.
|
- `Shade` is the ambient shading used primarily for visual contrast. If
|
||||||
|
`DataVersion` is `DataM1`, this must be set to 0.
|
||||||
|
|
||||||
### Polygon ###
|
### Polygon ###
|
||||||
|
|
||||||
|
@ -718,6 +720,8 @@ yourself and the map compiler will not help you with this process. (It is a
|
||||||
planned feature of Maraiah to allow the user to draw polygons of arbitrary
|
planned feature of Maraiah to allow the user to draw polygons of arbitrary
|
||||||
shape and automatically split them.)
|
shape and automatically split them.)
|
||||||
|
|
||||||
|
Note that `u16opt`s not available with `DataM1` must be set to none.
|
||||||
|
|
||||||
| Name | Type | Offset |
|
| Name | Type | Offset |
|
||||||
| ---- | ---- | ------ |
|
| ---- | ---- | ------ |
|
||||||
| `Type` | `u16` | `0` |
|
| `Type` | `u16` | `0` |
|
||||||
|
@ -744,6 +748,11 @@ shape and automatically split them.)
|
||||||
| `NeighborNum` | `u16` | `86` |
|
| `NeighborNum` | `u16` | `86` |
|
||||||
| `Center` | `struct` | `88` |
|
| `Center` | `struct` | `88` |
|
||||||
| `SideArray` | `u16[8]` | `92` |
|
| `SideArray` | `u16[8]` | `92` |
|
||||||
|
|
||||||
|
If `DataVersion` is not `DataM1`:
|
||||||
|
|
||||||
|
| Name | Type | Offset |
|
||||||
|
| ---- | ---- | ------ |
|
||||||
| `OrigFlr` | `struct` | `108` |
|
| `OrigFlr` | `struct` | `108` |
|
||||||
| `OrigCei` | `struct` | `112` |
|
| `OrigCei` | `struct` | `112` |
|
||||||
| `Media` | `u16opt` | `116` |
|
| `Media` | `u16opt` | `116` |
|
||||||
|
@ -752,7 +761,8 @@ shape and automatically split them.)
|
||||||
| `SoundAmbient` | `u16opt` | `122` |
|
| `SoundAmbient` | `u16opt` | `122` |
|
||||||
| `SoundRandom` | `u16opt` | `124` |
|
| `SoundRandom` | `u16opt` | `124` |
|
||||||
|
|
||||||
- `Type` is a Polygon Type enumeration.
|
- `Type` is a Polygon Type enumeration, unless `DataVersion` is `DataM1`, where
|
||||||
|
it is instead an Old Polygon Type enumeration.
|
||||||
- `Flags` is a Polygon Flags bit field.
|
- `Flags` is a Polygon Flags bit field.
|
||||||
- `Area` is the power-of-two area of the polygon.
|
- `Area` is the power-of-two area of the polygon.
|
||||||
- `ObjectFst` must be `65535`.
|
- `ObjectFst` must be `65535`.
|
||||||
|
@ -762,7 +772,7 @@ shape and automatically split them.)
|
||||||
|
|
||||||
### Light ###
|
### Light ###
|
||||||
|
|
||||||
Light is 100 bytes.
|
Light is 100 bytes. If `DataVersion` is `DataM1` this is an Old Light.
|
||||||
|
|
||||||
| Name | Type | Offset |
|
| Name | Type | Offset |
|
||||||
| ---- | ---- | ------ |
|
| ---- | ---- | ------ |
|
||||||
|
@ -782,6 +792,37 @@ Light is 100 bytes.
|
||||||
- `ActivPri`, `ActivSec` and `ActivMid` are Light Function structures.
|
- `ActivPri`, `ActivSec` and `ActivMid` are Light Function structures.
|
||||||
- `InactPri`, `InactSec` and `InactMid` are Light Function structures.
|
- `InactPri`, `InactSec` and `InactMid` are Light Function structures.
|
||||||
|
|
||||||
|
### Old Light ###
|
||||||
|
|
||||||
|
Old Light is 32 bytes. The old lighting system not only sucked, but there was
|
||||||
|
no Media system, so it was even more useless as it couldn't be used as a
|
||||||
|
controller for liquids. So, because of these issues, the new lighting system
|
||||||
|
was put in place, but it was incompatible data-wise because it had too many
|
||||||
|
extensions.
|
||||||
|
|
||||||
|
|
||||||
|
| Name | Type | Offset |
|
||||||
|
| ---- | ---- | ------ |
|
||||||
|
| `Type` | `u16` | `2` |
|
||||||
|
| `Mode` | `u16` | `4` |
|
||||||
|
| `Phase` | `u16` | `6` |
|
||||||
|
| `ValueMin` | `fixed` | `8` |
|
||||||
|
| `ValueMax` | `fixed` | `12` |
|
||||||
|
| `Period` | `u16` | `16` |
|
||||||
|
| `ValueCur` | `fixed` | `18` |
|
||||||
|
|
||||||
|
- `Type` is an Old Light Type enumeration. To create a new light from this, you
|
||||||
|
will need to write a lookup table which imitates each light type in the new
|
||||||
|
lighting system. This table is tedious to write, so please reference either
|
||||||
|
Aleph One or Maraiah for a full table of translations.
|
||||||
|
- `Mode` is an Old Light Mode enumeration.
|
||||||
|
- `Phase` is ignored in Aleph One.
|
||||||
|
- If `Type` is `Strobe`, you must set each resulting `Period` to this
|
||||||
|
definition's `Period` divided by 4 plus one. Otherwise, `Period` is ignored.
|
||||||
|
- For each of the new definition's functions, if the intensity of it is more
|
||||||
|
than 0, it should be set to `ValueMax`, otherwise `ValueMin`.
|
||||||
|
- `ValueCur` is ignored in Aleph One.
|
||||||
|
|
||||||
### Map Annotation ###
|
### Map Annotation ###
|
||||||
|
|
||||||
Map Annotation is 72 bytes.
|
Map Annotation is 72 bytes.
|
||||||
|
@ -928,7 +969,8 @@ such as media (liquid) presets.
|
||||||
- `Name` is the level name, intended to be 65 bytes, but one padding byte is
|
- `Name` is the level name, intended to be 65 bytes, but one padding byte is
|
||||||
left over, so the real length is 66.
|
left over, so the real length is 66.
|
||||||
- `EntryFlags` is an Entry Point Flags bit field. It is unknown why this is 32
|
- `EntryFlags` is an Entry Point Flags bit field. It is unknown why this is 32
|
||||||
bits wide when it could fit in even 8 bits.
|
bits wide when it could fit in even 8 bits. If `DataVersion` is `DataM1` and
|
||||||
|
this is `0`, this implies the value is `Solo`.
|
||||||
|
|
||||||
## Terminal ##
|
## Terminal ##
|
||||||
|
|
||||||
|
@ -1716,6 +1758,27 @@ exit upon reading them.
|
||||||
| `MustExplore` | `17` | Must be entered for Exploration | None |
|
| `MustExplore` | `17` | Must be entered for Exploration | None |
|
||||||
| `AutoExit` | `18` | Teleports to next level if success | None |
|
| `AutoExit` | `18` | Teleports to next level if success | None |
|
||||||
|
|
||||||
|
### Old Polygon Type ###
|
||||||
|
|
||||||
|
| Name | Value | Description | Permutation |
|
||||||
|
| ---- | ----- | ----------- | ----------- |
|
||||||
|
| `Normal` | `0` | Normal, no effects | None |
|
||||||
|
| `ImpassItem` | `1` | Items may not pass | None |
|
||||||
|
| `ImpassMons` | `2` | Monsters may not pass | None |
|
||||||
|
| `MinorOuch` | `3` | Damages the player a little | None |
|
||||||
|
| `MajorOuch` | `4` | Damages the player a lot | Team |
|
||||||
|
| `Platform` | `5` | Platform | Plat index |
|
||||||
|
| `TrigLightOn` | `6` | Triggers light on | Light index |
|
||||||
|
| `TrigPlatOn` | `7` | Triggers platform on | Plat index |
|
||||||
|
| `TrigLightOff` | `8` | Triggers light off | Poly index |
|
||||||
|
| `TrigPlatOff` | `9` | Triggers platform off | Poly index |
|
||||||
|
| `Teleporter` | `10` | Teleports to polygon centroid | Poly index |
|
||||||
|
| `Glue` | `11` | Slows the player down | None |
|
||||||
|
| `GlueTrigger` | `12` | TODO | TODO |
|
||||||
|
| `SuperGlue` | `13` | Slows the player down a lot | None |
|
||||||
|
| `MustExplore` | `14` | Must be entered for Exploration | None |
|
||||||
|
| `AutoExit` | `15` | Teleports to next level if success | None |
|
||||||
|
|
||||||
### Control Panel Type ###
|
### Control Panel Type ###
|
||||||
|
|
||||||
This is used internally for each control panel preset and determines the
|
This is used internally for each control panel preset and determines the
|
||||||
|
@ -1793,6 +1856,32 @@ Marathon 2 itself acknowledges how redundant this enumeration is.
|
||||||
| `Strobe` | `1` | Strobe light |
|
| `Strobe` | `1` | Strobe light |
|
||||||
| `Media` | `2` | Media light |
|
| `Media` | `2` | Media light |
|
||||||
|
|
||||||
|
### Old Light Type ###
|
||||||
|
|
||||||
|
| Name | Value |
|
||||||
|
| ---- | ----- |
|
||||||
|
| `Normal` | `0` |
|
||||||
|
| `Rheostat` | `1` |
|
||||||
|
| `Flourescent` | `2` |
|
||||||
|
| `Strobe` | `3` |
|
||||||
|
| `Flickers` | `4` |
|
||||||
|
| `Pulsates` | `5` |
|
||||||
|
| `Annoying` | `6` |
|
||||||
|
| `EnergyEfficient` | `7` |
|
||||||
|
|
||||||
|
### Old Light Mode ###
|
||||||
|
|
||||||
|
| Name | Value |
|
||||||
|
| ---- | ----- |
|
||||||
|
| `TurningOn` | `0` |
|
||||||
|
| `Active` | `1` |
|
||||||
|
| `TurningOff` | `2` |
|
||||||
|
| `Inactive` | `3` |
|
||||||
|
| `Toggle` | `4` |
|
||||||
|
|
||||||
|
- `TurningOn` and `Active` mean the new light created from this should have the
|
||||||
|
`InitActive` flag. Others do not mean anything.
|
||||||
|
|
||||||
### Wad Version ###
|
### Wad Version ###
|
||||||
|
|
||||||
Used to determine how the engine loads the Wad file.
|
Used to determine how the engine loads the Wad file.
|
||||||
|
@ -2005,6 +2094,8 @@ relative to the point's lines
|
||||||
|
|
||||||
### Side Flags ###
|
### Side Flags ###
|
||||||
|
|
||||||
|
If `DataVersion` is `DataM1`, then `ItemOpt` must be set by the client.
|
||||||
|
|
||||||
| Name | Bit |
|
| Name | Bit |
|
||||||
| ---- | --- |
|
| ---- | --- |
|
||||||
| `Status` | `0` |
|
| `Status` | `0` |
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Binary data conversion utilities.
|
//! Binary data conversion utilities.
|
||||||
|
|
||||||
use crate::durandal::err::*;
|
use crate::durandal::{err::*, text::mac_roman_conv};
|
||||||
use std::{fmt, num::NonZeroU16};
|
use std::{fmt, num::NonZeroU16};
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -79,7 +79,7 @@ macro_rules! _durandal_read_impl {
|
||||||
let $nam = $b[$n] as i8;
|
let $nam = $b[$n] as i8;
|
||||||
};
|
};
|
||||||
($_:ident $b:ident $nam:ident Ident $n:expr) => {
|
($_:ident $b:ident $nam:ident Ident $n:expr) => {
|
||||||
let $nam = [$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]];
|
let $nam = Ident([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]);
|
||||||
};
|
};
|
||||||
($_:ident $b:ident $nam:ident $f:ident $n:expr) => {
|
($_:ident $b:ident $nam:ident $f:ident $n:expr) => {
|
||||||
let $nam = $f(&$b[$n])?;
|
let $nam = $f(&$b[$n])?;
|
||||||
|
@ -155,7 +155,7 @@ macro_rules! read_data {
|
||||||
/// Creates an `Ident` from a slice.
|
/// Creates an `Ident` from a slice.
|
||||||
///
|
///
|
||||||
/// `b` must be at least 4 bytes, or a panic will occur.
|
/// `b` must be at least 4 bytes, or a panic will occur.
|
||||||
pub fn ident(b: &[u8]) -> Ident {[b[0], b[1], b[2], b[3]]}
|
pub fn ident(b: &[u8]) -> Ident {Ident([b[0], b[1], b[2], b[3]])}
|
||||||
|
|
||||||
/// Applies `u32::from_be_bytes` to a slice.
|
/// Applies `u32::from_be_bytes` to a slice.
|
||||||
///
|
///
|
||||||
|
@ -232,6 +232,9 @@ pub fn rd_ofstable<T, F>(b: &[u8],
|
||||||
|
|
||||||
impl OptU16
|
impl OptU16
|
||||||
{
|
{
|
||||||
|
/// Creates an `OptU16` representing `None`.
|
||||||
|
pub const fn none() -> Self {OptU16(None)}
|
||||||
|
|
||||||
/// Creates an `OptU16` from a `u16`.
|
/// Creates an `OptU16` from a `u16`.
|
||||||
pub fn from_repr(n: u16) -> Self
|
pub fn from_repr(n: u16) -> Self
|
||||||
{
|
{
|
||||||
|
@ -272,8 +275,17 @@ impl fmt::Debug for OptU16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Ident
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "\"{}\"", mac_roman_conv(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A four-character-code identifier.
|
/// A four-character-code identifier.
|
||||||
pub type Ident = [u8; 4];
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Ident(pub [u8; 4]);
|
||||||
|
|
||||||
/// An object identified by a `u16` which may be `u16::max_value()` to
|
/// An object identified by a `u16` which may be `u16::max_value()` to
|
||||||
/// represent a nulled value.
|
/// represent a nulled value.
|
||||||
|
|
|
@ -19,6 +19,7 @@ macro_rules! c_enum
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
$(#[$outer])*
|
$(#[$outer])*
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
$V enum $E
|
$V enum $E
|
||||||
{
|
{
|
||||||
$($Enum,)+
|
$($Enum,)+
|
||||||
|
|
|
@ -9,7 +9,7 @@ macro_rules! define_fixed_type {
|
||||||
struct $Type:ident ($IT:ident) : $UT:ident, $LT:ident, $FracBits:expr;
|
struct $Type:ident ($IT:ident) : $UT:ident, $LT:ident, $FracBits:expr;
|
||||||
) => {
|
) => {
|
||||||
$(#[$outer])*
|
$(#[$outer])*
|
||||||
#[derive(Clone, PartialEq, serde::Serialize)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, serde::Serialize)]
|
||||||
pub struct $Type($IT);
|
pub struct $Type($IT);
|
||||||
|
|
||||||
impl $Type
|
impl $Type
|
||||||
|
@ -25,6 +25,13 @@ macro_rules! define_fixed_type {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn from_bits(bits: $UT) -> Self {$Type(bits as $IT)}
|
pub const fn from_bits(bits: $UT) -> Self {$Type(bits as $IT)}
|
||||||
|
|
||||||
|
/// Creates a value of this type with the integral portion `n`.
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_int(n: $LT) -> Self
|
||||||
|
{
|
||||||
|
$Type(n as ($IT) << Self::FRACBITS)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the raw bit pattern.
|
/// Returns the raw bit pattern.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_bits(&self) -> $UT {self.0 as $UT}
|
pub fn to_bits(&self) -> $UT {self.0 as $UT}
|
||||||
|
@ -71,7 +78,7 @@ macro_rules! define_fixed_type {
|
||||||
impl From<$LT> for $Type
|
impl From<$LT> for $Type
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(n: $LT) -> Self {$Type($IT::from(n) << Self::FRACBITS)}
|
fn from(n: $LT) -> Self {$Type::from_int(n)}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Add for $Type
|
impl ops::Add for $Type
|
||||||
|
|
|
@ -4,27 +4,6 @@ use crate::{durandal::{bin::*, err::*, fixed::*, text::mac_roman_conv},
|
||||||
marathon::xfer::TransferMode};
|
marathon::xfer::TransferMode};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
/// Reads a `Minf` chunk.
|
|
||||||
pub fn read_minf(b: &[u8]) -> ResultS<Minf>
|
|
||||||
{
|
|
||||||
read_data! {
|
|
||||||
88, BE in b =>
|
|
||||||
env_code = u16[0];
|
|
||||||
physi_id = u16[2];
|
|
||||||
music_id = u16[4];
|
|
||||||
missi_flags = u16[6];
|
|
||||||
envir_flags = u16[8];
|
|
||||||
level_name = mac_roman_conv[18..84] nt;
|
|
||||||
entry_flags = u32[84];
|
|
||||||
}
|
|
||||||
|
|
||||||
let missi_flags = flag_ok!(MsnFlags, missi_flags)?;
|
|
||||||
let envir_flags = flag_ok!(EnvFlags, envir_flags)?;
|
|
||||||
let entry_flags = flag_ok!(EntFlags, entry_flags)?;
|
|
||||||
Ok(Minf{env_code, physi_id, music_id, missi_flags, envir_flags, entry_flags,
|
|
||||||
level_name})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads a `LightFunc` object.
|
/// Reads a `LightFunc` object.
|
||||||
pub fn read_lightfunc(b: &[u8]) -> ResultS<LightFunc>
|
pub fn read_lightfunc(b: &[u8]) -> ResultS<LightFunc>
|
||||||
{
|
{
|
||||||
|
@ -33,8 +12,8 @@ pub fn read_lightfunc(b: &[u8]) -> ResultS<LightFunc>
|
||||||
ftype = u16[0];
|
ftype = u16[0];
|
||||||
prd_nrm = u16[2];
|
prd_nrm = u16[2];
|
||||||
prd_dta = u16[4];
|
prd_dta = u16[4];
|
||||||
val_nrm = u16[6];
|
val_nrm = Fixed[6];
|
||||||
val_dta = u16[10];
|
val_dta = Fixed[10];
|
||||||
}
|
}
|
||||||
|
|
||||||
let ftype = LightFuncType::from_repr(ftype)?;
|
let ftype = LightFuncType::from_repr(ftype)?;
|
||||||
|
@ -66,6 +45,30 @@ pub fn read_point(b: &[u8]) -> ResultS<Point>
|
||||||
Ok(Point{x, y})
|
Ok(Point{x, y})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a `Minf` chunk.
|
||||||
|
pub fn read_minf(b: &[u8]) -> ResultS<Minf>
|
||||||
|
{
|
||||||
|
read_data! {
|
||||||
|
88, BE in b =>
|
||||||
|
env_code = u16[0];
|
||||||
|
physi_id = u16[2];
|
||||||
|
music_id = u16[4];
|
||||||
|
missi_flags = u16[6];
|
||||||
|
envir_flags = u16[8];
|
||||||
|
level_name = mac_roman_conv[18..84] nt;
|
||||||
|
entry_flags = u32[84];
|
||||||
|
}
|
||||||
|
|
||||||
|
let missi_flags = flag_ok!(MsnFlags, missi_flags)?;
|
||||||
|
let envir_flags = flag_ok!(EnvFlags, envir_flags)?;
|
||||||
|
let entry_flags = flag_ok!(EntFlags, entry_flags)?;
|
||||||
|
Ok(Minf{env_code, physi_id, music_id, missi_flags, envir_flags, entry_flags,
|
||||||
|
level_name})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads an `iidx` chunk.
|
||||||
|
pub fn read_iidx(b: &[u8]) -> ResultS<(u16, usize)> {Ok((u16b(b), 2))}
|
||||||
|
|
||||||
/// Reads an `EPNT` chunk.
|
/// Reads an `EPNT` chunk.
|
||||||
pub fn read_epnt(b: &[u8]) -> ResultS<(Point, usize)>
|
pub fn read_epnt(b: &[u8]) -> ResultS<(Point, usize)>
|
||||||
{
|
{
|
||||||
|
@ -130,6 +133,18 @@ pub fn read_sids(b: &[u8]) -> ResultS<(Side, usize)>
|
||||||
xfer_pri, xfer_sec, xfer_tra, shade}, 64))
|
xfer_pri, xfer_sec, xfer_tra, shade}, 64))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an old `SIDS` chunk.
|
||||||
|
pub fn read_old_sids(b: &[u8]) -> ResultS<(Side, usize)>
|
||||||
|
{
|
||||||
|
let (mut side, siz) = read_sids(b)?;
|
||||||
|
|
||||||
|
side.tex_tra.tex_id = OptU16::none();
|
||||||
|
side.shade = Fixed::from_int(0);
|
||||||
|
side.flags.insert(SideFlags::ItemOpt);
|
||||||
|
|
||||||
|
Ok((side, siz))
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a `POLY` chunk.
|
/// Reads a `POLY` chunk.
|
||||||
pub fn read_poly(b: &[u8]) -> ResultS<(Polygon, usize)>
|
pub fn read_poly(b: &[u8]) -> ResultS<(Polygon, usize)>
|
||||||
{
|
{
|
||||||
|
@ -163,6 +178,31 @@ pub fn read_poly(b: &[u8]) -> ResultS<(Polygon, usize)>
|
||||||
snd_ind, snd_amb, snd_rnd}, 128))
|
snd_ind, snd_amb, snd_rnd}, 128))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an old `POLY` chunk.
|
||||||
|
pub fn read_old_poly(b: &[u8]) -> ResultS<(Polygon, usize)>
|
||||||
|
{
|
||||||
|
let (mut poly, siz) = read_poly(b)?;
|
||||||
|
|
||||||
|
poly.ptype = match poly.ptype {
|
||||||
|
PolyType::Hill => PolyType::OuchMinor,
|
||||||
|
PolyType::Base => PolyType::OuchMajor,
|
||||||
|
PolyType::ZoneBorder => PolyType::Glue,
|
||||||
|
PolyType::Goal => PolyType::GlueTrigger,
|
||||||
|
PolyType::TrigMonsVis => PolyType::GlueSuper,
|
||||||
|
PolyType::TrigMonsInv => PolyType::MustExplore,
|
||||||
|
PolyType::TrigMonsDual => PolyType::AutoExit,
|
||||||
|
ptype => ptype,
|
||||||
|
};
|
||||||
|
|
||||||
|
poly.ori_flr = Point{x: Unit::from_int(0), y: Unit::from_int(0)};
|
||||||
|
poly.ori_cei = Point{x: Unit::from_int(0), y: Unit::from_int(0)};
|
||||||
|
poly.med_ind = OptU16::none();
|
||||||
|
poly.snd_amb = OptU16::none();
|
||||||
|
poly.snd_rnd = OptU16::none();
|
||||||
|
|
||||||
|
Ok((poly, siz))
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a `LITE` chunk.
|
/// Reads a `LITE` chunk.
|
||||||
pub fn read_lite(b: &[u8]) -> ResultS<(Light, usize)>
|
pub fn read_lite(b: &[u8]) -> ResultS<(Light, usize)>
|
||||||
{
|
{
|
||||||
|
@ -187,6 +227,49 @@ pub fn read_lite(b: &[u8]) -> ResultS<(Light, usize)>
|
||||||
ina_mid, tag}, 100))
|
ina_mid, tag}, 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an old `LITE` chunk.
|
||||||
|
pub fn read_old_lite(b: &[u8]) -> ResultS<(Light, usize)>
|
||||||
|
{
|
||||||
|
read_data! {
|
||||||
|
32, BE in b =>
|
||||||
|
ltype = u16[2] as usize;
|
||||||
|
mode = u16[4];
|
||||||
|
phase = i16[6];
|
||||||
|
min = Fixed[8];
|
||||||
|
max = Fixed[12];
|
||||||
|
prd = u16[16];
|
||||||
|
}
|
||||||
|
|
||||||
|
if OLD_LIGHT_DEFINITIONS.len() < ltype {
|
||||||
|
bail!("bad old light type");
|
||||||
|
}
|
||||||
|
|
||||||
|
let lite = &OLD_LIGHT_DEFINITIONS[ltype];
|
||||||
|
let on = mode == 0 || mode == 1;
|
||||||
|
let strobe = ltype == 3;
|
||||||
|
let flags = if on {lite.flags | LightFlags::InitActive} else {lite.flags};
|
||||||
|
|
||||||
|
// modify each old light function accordingly
|
||||||
|
let old_lfun = move |func: &LightFunc| -> LightFunc {
|
||||||
|
LightFunc{ftype: func.ftype,
|
||||||
|
prd_nrm: if strobe {prd / 4 + 1} else {func.prd_nrm},
|
||||||
|
prd_dta: func.prd_dta,
|
||||||
|
val_nrm: if func.val_nrm > Fixed::from_int(0) {max} else {min},
|
||||||
|
val_dta: func.val_dta}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((Light{ltype: lite.ltype,
|
||||||
|
flags,
|
||||||
|
phase,
|
||||||
|
act_pri: old_lfun(&lite.act_pri),
|
||||||
|
act_sec: old_lfun(&lite.act_sec),
|
||||||
|
act_mid: old_lfun(&lite.act_mid),
|
||||||
|
ina_pri: old_lfun(&lite.ina_pri),
|
||||||
|
ina_sec: old_lfun(&lite.ina_sec),
|
||||||
|
ina_mid: old_lfun(&lite.ina_mid),
|
||||||
|
tag: 0}, 32))
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads an `OBJS` chunk.
|
/// Reads an `OBJS` chunk.
|
||||||
pub fn read_objs(b: &[u8]) -> ResultS<(Object, usize)>
|
pub fn read_objs(b: &[u8]) -> ResultS<(Object, usize)>
|
||||||
{
|
{
|
||||||
|
@ -399,8 +482,8 @@ pub struct LightFunc
|
||||||
pub ftype: LightFuncType,
|
pub ftype: LightFuncType,
|
||||||
pub prd_nrm: u16,
|
pub prd_nrm: u16,
|
||||||
pub prd_dta: u16,
|
pub prd_dta: u16,
|
||||||
pub val_nrm: u16,
|
pub val_nrm: Fixed,
|
||||||
pub val_dta: u16,
|
pub val_dta: Fixed,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A dynamic polygon light.
|
/// A dynamic polygon light.
|
||||||
|
@ -710,6 +793,11 @@ c_enum! {
|
||||||
16 => TrigItems,
|
16 => TrigItems,
|
||||||
17 => MustExplore,
|
17 => MustExplore,
|
||||||
18 => AutoExit,
|
18 => AutoExit,
|
||||||
|
19 => OuchMinor,
|
||||||
|
20 => OuchMajor,
|
||||||
|
21 => Glue,
|
||||||
|
22 => GlueTrigger,
|
||||||
|
23 => GlueSuper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,6 +810,8 @@ c_enum! {
|
||||||
1 => Linear,
|
1 => Linear,
|
||||||
2 => Smooth,
|
2 => Smooth,
|
||||||
3 => Flicker,
|
3 => Flicker,
|
||||||
|
4 => Random,
|
||||||
|
5 => Fluorescent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,4 +846,296 @@ impl std::fmt::Debug for Point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const TICKS_PER_SECOND: u16 = 30;
|
||||||
|
|
||||||
|
const OLD_LIGHT_DEFINITIONS: [Light; 8] = [
|
||||||
|
// Normal
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Rheostat
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 3,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 3,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Flourescent
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Fluorescent,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 3,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Strobe
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Flicker
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Flicker,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 3,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Pulsate
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2 - 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2 - 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2 - 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Smooth,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Annoying
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Random,
|
||||||
|
prd_nrm: 2,
|
||||||
|
prd_dta: 1,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Random,
|
||||||
|
prd_nrm: 1,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
|
||||||
|
// Energy Efficient
|
||||||
|
Light{ltype: LightType::Normal,
|
||||||
|
flags: LightFlags::SlaveValue,
|
||||||
|
phase: 0,
|
||||||
|
act_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
act_mid: LightFunc{ftype: LightFuncType::Linear,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(1),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_pri: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_sec: LightFunc{ftype: LightFuncType::Constant,
|
||||||
|
prd_nrm: TICKS_PER_SECOND,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
ina_mid: LightFunc{ftype: LightFuncType::Linear,
|
||||||
|
prd_nrm: TICKS_PER_SECOND * 2,
|
||||||
|
prd_dta: 0,
|
||||||
|
val_nrm: Fixed::from_int(0),
|
||||||
|
val_dta: Fixed::from_int(0)},
|
||||||
|
tag: 0},
|
||||||
|
];
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -95,7 +95,7 @@ pub fn read_sounds(b: &[u8]) -> ResultS<Vec<SoundTable>>
|
||||||
snd_num = u16[10] as usize;
|
snd_num = u16[10] as usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if version != 1 || magic != *b"snd2" {
|
if version != 1 || magic.0 != *b"snd2" {
|
||||||
bail!("bad sound header");
|
bail!("bad sound header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,16 @@ use crate::marathon::{map, phy, pict, trm};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
/// Reads all chunks in an entry.
|
/// Reads all chunks in an entry.
|
||||||
pub fn read_chunks(b: &[u8], siz_cnk: usize) -> ResultS<Vec<Chunk>>
|
pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize)
|
||||||
|
-> ResultS<Vec<Chunk>>
|
||||||
{
|
{
|
||||||
let mut chunks = Vec::new();
|
let mut chunks = Vec::new();
|
||||||
let mut p = 0;
|
let mut p = 0;
|
||||||
|
|
||||||
|
let map_read_sides = if old_dat {map::read_old_sids} else {map::read_sids};
|
||||||
|
let map_read_polys = if old_dat {map::read_old_poly} else {map::read_poly};
|
||||||
|
let map_read_light = if old_dat {map::read_old_lite} else {map::read_lite};
|
||||||
|
|
||||||
while p < b.len() {
|
while p < b.len() {
|
||||||
read_data! {
|
read_data! {
|
||||||
p + siz_cnk, BE in b =>
|
p + siz_cnk, BE in b =>
|
||||||
|
@ -21,16 +26,17 @@ pub fn read_chunks(b: &[u8], siz_cnk: usize) -> ResultS<Vec<Chunk>>
|
||||||
let end = beg + size;
|
let end = beg + size;
|
||||||
let data = &b[beg..end];
|
let data = &b[beg..end];
|
||||||
|
|
||||||
let chunk = match &iden {
|
chunks.push(match &iden.0 {
|
||||||
b"PICT" => Chunk::Pict(pict::load_pict(data)?),
|
b"PICT" => Chunk::Pict(pict::load_pict(data)?),
|
||||||
b"Minf" => Chunk::Minf(map::read_minf(data)?),
|
b"Minf" => Chunk::Minf(map::read_minf(data)?),
|
||||||
|
b"iidx" => Chunk::Iidx(rd_array(data, map::read_iidx)?),
|
||||||
b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?),
|
b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?),
|
||||||
b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?),
|
b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?),
|
||||||
b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?),
|
b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?),
|
||||||
b"SIDS" => Chunk::Sids(rd_array(data, map::read_sids)?),
|
b"SIDS" => Chunk::Sids(rd_array(data, map_read_sides)?),
|
||||||
b"POLY" => Chunk::Poly(rd_array(data, map::read_poly)?),
|
b"POLY" => Chunk::Poly(rd_array(data, map_read_polys)?),
|
||||||
b"LITE" => Chunk::Lite(rd_array(data, map::read_lite)?),
|
|
||||||
b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?),
|
b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?),
|
||||||
|
b"LITE" => Chunk::Lite(rd_array(data, map_read_light)?),
|
||||||
b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?),
|
b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?),
|
||||||
b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?),
|
b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?),
|
||||||
b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?),
|
b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?),
|
||||||
|
@ -44,9 +50,7 @@ pub fn read_chunks(b: &[u8], siz_cnk: usize) -> ResultS<Vec<Chunk>>
|
||||||
b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?),
|
b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?),
|
||||||
b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?),
|
b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?),
|
||||||
_ => Chunk::Data{iden, data: data.to_vec()},
|
_ => Chunk::Data{iden, data: data.to_vec()},
|
||||||
};
|
});
|
||||||
|
|
||||||
chunks.push(chunk);
|
|
||||||
|
|
||||||
p = end;
|
p = end;
|
||||||
}
|
}
|
||||||
|
@ -56,7 +60,8 @@ pub fn read_chunks(b: &[u8], siz_cnk: usize) -> ResultS<Vec<Chunk>>
|
||||||
|
|
||||||
/// Reads all entries in a `Wad`.
|
/// Reads all entries in a `Wad`.
|
||||||
pub fn read_entries(b: &[u8],
|
pub fn read_entries(b: &[u8],
|
||||||
is_old: bool,
|
old_wad: bool,
|
||||||
|
old_dat: bool,
|
||||||
siz_app: usize,
|
siz_app: usize,
|
||||||
siz_ent: usize,
|
siz_ent: usize,
|
||||||
siz_cnk: usize)
|
siz_cnk: usize)
|
||||||
|
@ -79,9 +84,9 @@ pub fn read_entries(b: &[u8],
|
||||||
index = u16[p + 8];
|
index = u16[p + 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = if is_old {i as u16} else {index};
|
let index = if old_wad {i as u16} else {index};
|
||||||
|
|
||||||
let chunks = read_chunks(&b[offset..offset + size], siz_cnk)?;
|
let chunks = read_chunks(&b[offset..offset + size], old_dat, siz_cnk)?;
|
||||||
let appdata = b[p..p + siz_app].to_vec();
|
let appdata = b[p..p + siz_app].to_vec();
|
||||||
|
|
||||||
entries.insert(index, Entry{chunks, appdata});
|
entries.insert(index, Entry{chunks, appdata});
|
||||||
|
@ -107,25 +112,26 @@ pub fn read_wad(b: &[u8]) -> ResultS<Wad>
|
||||||
|
|
||||||
let ver_wad = Ver::from_repr(ver_wad)?;
|
let ver_wad = Ver::from_repr(ver_wad)?;
|
||||||
|
|
||||||
let is_old = match ver_wad {
|
let old_wad = match ver_wad {
|
||||||
Ver::Base => true,
|
Ver::Base => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
let old_dat = ver_dat == 0;
|
||||||
|
|
||||||
let siz_ent = if is_old {8 } else {10};
|
let siz_ent = if old_wad {8 } else {10};
|
||||||
let siz_cnk = if is_old {12} else {16};
|
let siz_cnk = if old_wad {12} else {16};
|
||||||
|
|
||||||
if siz_ent != siz_went {
|
if !old_wad && siz_ent != siz_went {
|
||||||
bail!("invalid entry size");
|
bail!("invalid entry size");
|
||||||
}
|
}
|
||||||
|
|
||||||
if siz_cnk != siz_wcnk {
|
if !old_wad && siz_cnk != siz_wcnk {
|
||||||
bail!("invalid chunk size");
|
bail!("invalid chunk size");
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries = read_entries(b, is_old, siz_app, siz_ent, siz_cnk)?;
|
let entries = read_entries(b, old_wad, old_dat, siz_app, siz_ent, siz_cnk)?;
|
||||||
|
|
||||||
Ok(Wad{head: WadHeader{ver_wad, ver_dat, siz_app, name}, entries})
|
Ok(Wad{head: WadHeader{ver_wad, old_dat, siz_app, name}, entries})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Any kind of chunk in an `Entry`.
|
/// Any kind of chunk in an `Entry`.
|
||||||
|
@ -134,6 +140,7 @@ pub enum Chunk
|
||||||
{
|
{
|
||||||
Pict(image::Image8),
|
Pict(image::Image8),
|
||||||
Minf(map::Minf),
|
Minf(map::Minf),
|
||||||
|
Iidx(Vec<u16>),
|
||||||
Pnts(Vec<map::Point>),
|
Pnts(Vec<map::Point>),
|
||||||
Lins(Vec<map::Line>),
|
Lins(Vec<map::Line>),
|
||||||
Sids(Vec<map::Side>),
|
Sids(Vec<map::Side>),
|
||||||
|
@ -168,7 +175,7 @@ pub struct Entry
|
||||||
pub struct WadHeader
|
pub struct WadHeader
|
||||||
{
|
{
|
||||||
pub ver_wad: Ver,
|
pub ver_wad: Ver,
|
||||||
pub ver_dat: u16,
|
pub old_dat: bool,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub siz_app: usize,
|
pub siz_app: usize,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue