Skip to content

Latest commit

 

History

History
625 lines (547 loc) · 36.8 KB

developer_spec.md

File metadata and controls

625 lines (547 loc) · 36.8 KB

MBF21 Developer Spec v1.4

The contents of this file are aimed at developers, with links to relevant code and extra technical details. MBF21 supports the full spec of boom & mbf, plus the following.

Sectors

Instant death sector special

  • Implementation
  • Bit 12 (4096) turns on "alternate damage meaning" for bit 5 & 6:
Dec Bit 6-5 Description
0 00 Kills a player unless they have a rad suit or invulnerability
32 01 Kills a player
64 10 Kills all players and exits the map (normal exit)
96 11 Kills all players and exits the map (secret exit)

Kill monsters sector special

  • PR
  • Bit 13 turns on "kill monsters" flag for sectors - kills grounded monsters.

Lines

Block land monsters line flag

  • PR
  • Uses bit 12 (4096).

Block players line flag

Line scroll special variants

  • PR
  • Scroll like special 255, but also apply the scroll to all other linedefs which share the same tag.
  • The scrolling speed is divided by 8 to give more fine-grained control.
  • 1024 is without control sector / acceleration.
  • 1025 uses control sector.
  • 1026 uses control sector + acceleration.

Things

Dehacked Thing Groups

Infighting
  • Add Infighting group = N in Thing definition.
  • N is a nonnegative integer.
  • Things with the same value of N will not target each other after taking damage.
Projectile
  • Add Projectile group = M in Thing definition.
  • M is an integer.
  • Things with the same value of M will not deal projectile damage to each other.
  • A negative value of M means that species has no projectile immunity, even to other things in the same species.
Splash
  • Add Splash group = S in Thing definition.
  • S is a nonnegative integer.
  • If an explosion (or other splash damage source) has the same splash group as the target, it will not deal damage.
Examples
Thing 12 (Imp)
Projectile group = -1
Splash group = 0

Thing 16 (Baron of Hell)
Projectile group = 2

Thing 18 (Hell Knight)
Infighting group = 1
Projectile group = 1

Thing 21 (Arachnotron)
Infighting group = 1
Projectile group = 2

Thing 31 (Barrel)
Splash group = 0

In this example:

  • Imp projectiles now damage other Imps (and they will infight with their own kind).
  • Barons and Arachnotrons are in the same projectile group: their projectiles will no longer damage each other.
  • Barons and Hell Knights are not in the same projectile group: their projectiles will now damage each other, leading to infighting.
  • Hell Knights and Arachnotrons are in the same infighting group: they will not infight with each other, despite taking damage from each other's projectiles.
  • Imps and Barrels are in the same splash group: barrels no longer deal splash damage to imps.
  • Note that the group numbers are separate - being in infighting group 1 doesn't mean you are in projectile group 1.

New Thing Flags

  • commit
  • Add MBF21 Bits = X in the Thing definition.
  • The format is the same as the existing Bits field.
  • Example: MBF21 Bits = LOGRAV+DMGIGNORED+MAP07BOSS1.
  • The value can also be given as a number (sum of the individual flag values below).
  • Implementations match between DSDA-Doom and Eternity Engine for labeled flags.
DSDA-Doom Eternity Engine Value Description
MF2_LOGRAV MF2_LOGRAV 0x00001 Lower gravity (1/8)
MF2_SHORTMRANGE MF2_SHORTMRANGE 0x00002 Short missile range (archvile)
MF2_DMGIGNORED MF3_DMGIGNORED 0x00004 Other things ignore its attacks (archvile)
MF2_NORADIUSDMG MF4_NORADIUSDMG 0x00008 Doesn't take splash damage (cyberdemon, mastermind)
MF2_FORCERADIUSDMG MF4_FORCERADIUSDMG 0x00010 Thing causes splash damage even if the target shouldn't
MF2_HIGHERMPROB MF2_HIGHERMPROB 0x00020 Higher missile attack probability (cyberdemon)
MF2_RANGEHALF MF2_RANGEHALF 0x00040 Use half distance for missile attack probability (cyberdemon, mastermind, revenant, lost soul)
MF2_NOTHRESHOLD MF3_NOTHRESHOLD 0x00080 Has no targeting threshold (archvile)
MF2_LONGMELEE MF2_LONGMELEE 0x00100 Has long melee range (revenant)
MF2_BOSS MF2_BOSS 0x00200 Full volume see / death sound & splash immunity (from heretic)
MF2_MAP07BOSS1 MF2_MAP07BOSS1 0x00400 Tag 666 "boss" on doom 2 map 7 (mancubus)
MF2_MAP07BOSS2 MF2_MAP07BOSS2 0x00800 Tag 667 "boss" on doom 2 map 7 (arachnotron)
MF2_E1M8BOSS MF2_E1M8BOSS 0x01000 E1M8 boss (baron)
MF2_E2M8BOSS MF2_E2M8BOSS 0x02000 E2M8 boss (cyberdemon)
MF2_E3M8BOSS MF2_E3M8BOSS 0x04000 E3M8 boss (mastermind)
MF2_E4M6BOSS MF2_E4M6BOSS 0x08000 E4M6 boss (cyberdemon)
MF2_E4M8BOSS MF2_E4M8BOSS 0x10000 E4M8 boss (mastermind)
MF2_RIP MF3_RIP 0x20000 Ripper projectile (does not disappear on impact)
MF2_FULLVOLSOUNDS 0x40000 Full volume see / death sounds (cyberdemon, mastermind)

Rip sound

  • commit
  • When set, this is the sound that plays for ripper projectiles when they rip through something.
  • Add Rip sound = X in the Thing definition.
  • X is the sound index, as seen in other sound fields.

Fast speed

  • PR, commit
  • Sets the thing speed for skill 5 / -fast.
  • Add Fast speed = X in the Thing definition.
  • X has the same units as the normal Speed field.

Melee range

  • PR
  • Sets the range at which a monster will initiate a melee attack.
  • Also affects the range for vanilla melee attack codepointers, e.g. A_SargAttack, A_TroopAttack, etc.
    • Similarly, adjusting the player mobj's melee range will adjust the range of A_Punch and A_Saw
  • Add Melee range = X in the Thing definition.
  • X is in fixed point, like the Radius and Height fields

Weapons

Weapon Flags

  • PR
  • Add MBF21 Bits = X in the Weapon definition.
  • The format is the same as the existing thing Bits field.
  • Example: MBF21 Bits = SILENT+NOAUTOFIRE.
  • The value can also be given as a number (sum of the individual flag values below).
Name Value Description
NOTHRUST 0x001 Doesn't thrust things
SILENT 0x002 Weapon is silent
NOAUTOFIRE 0x004 Weapon won't autofire when swapped to
FLEEMELEE 0x008 Monsters consider it a melee weapon
AUTOSWITCHFROM 0x010 Can be switched away from when ammo is picked up
NOAUTOSWITCHTO 0x020 Cannot be switched to when ammo is picked up

MBF21 defaults:

Weapon Flags
Fist FLEEMELEE+AUTOSWITCHFROM+NOAUTOSWITCHTO
Pistol AUTOSWITCHFROM
Shotgun
Chaingun
Rocket Launcher NOAUTOFIRE
Plasma Rifle
BFG NOAUTOFIRE
Chainsaw NOTHRUST+FLEEMELEE+NOAUTOSWITCHTO
Super Shotgun

Ammo pickup weapon autoswitch changes

  • PR
  • Weapon autoswitch on ammo pickup now accounts for the ammo per shot of a weapon, as well as the NOAUTOSWITCHTO and AUTOSWITCHFROM weapon flags, allowing more accuracy and customization of this behaviour.
  • If the current weapon is enabled for AUTOSWITCHFROM and the player picks up ammo for a different weapon, autoswitch will occur for the highest ranking weapon (by index) matching these conditions:
    • player has the weapon
    • weapon is not flagged with NOAUTOSWITCHTO
    • weapon uses the ammo that was picked up
    • player did not have enough ammo to fire the weapon before
    • player now has enough ammo to fire the weapon

New DEHACKED "Ammo per shot" Weapon field

  • PR
  • Add Ammo per shot = X in the Weapon definition.
  • Value must be a nonnegative integer.
  • Tools should assume this value is undefined for all vanilla weapons (i.e. always write it to the patch if the user specifies any valid value)
  • Weapons WITH this field set will use the ammo-per-shot value when:
    • Checking if there is enough ammo before firing
    • Determining if the weapon has ammo during weapon auto-switch
    • Deciding how much ammo to subtract in native Doom weapon attack pointers
      • Exceptions: A_Saw and A_Punch will never attempt to subtract ammo.
    • The amount param is zero for certain new MBF21 DEHACKED codepointers (see below).
  • Weapons WITHOUT this field set will use vanilla Doom semantics for all above behaviors.
  • For backwards-compatibility, setting the BFG cells/shot misc field will also set the BFG weapon's Ammo per shot field (but not vice-versa).

Frames

Frame Flags

  • PR
  • Add MBF21 Bits = X in the Frame definition.
  • The format is the same as the existing thing Bits field.
  • Example: MBF21 Bits = SKILL5FAST.
  • The value can also be given as a number (sum of the individual flag values below).
Name Value Description
SKILL5FAST 0x001 Tics halve on nightmare skill (demon)

New "Args" fields for DEHACKED states

  • PR
  • Defines 8 new integer fields in the state table for use as codepointer arguments
  • Args are defined in dehacked by adding Args1 = X, Args2 = X... up to Args8 = X in the State definition.
  • Default value for each arg is determined by the frame's codepointer. For ease of implementation, DEHACKED tools may wish to simply pass through any args that are explicitly set by the user (i.e. assume the default value is undefined).
  • For future-proofing, if args are defined on a state than its action pointer expects (e.g. defining Args3 on a state that uses A_WeaponSound), an error must be thrown on startup.

New DEHACKED Codepointers

  • PR, PR, PR, PR, PR, PR
  • All new MBF21 pointers use the new "Args" fields for params, rather than misc1/misc2 fields
  • Arg fields are listed in order in the docs below, e.g. for A_SpawnObject, type is Args1, angle is Args2, etc.
  • Although all args are integers internally, there are effectively the following types of args:
    • int: An integer. 'Nuff said.
    • uint: An unsigned integer. Must be greater than or equal to zero.
    • fixed A fixed-point number.
      • For user-friendliness, a suggested convention for MBF21-supporting DEHACKED tools is to convert numbers with decimal points to their fixed-point representation when saving the patch (e.g. "1.0" gets saved as "65536"), so this doesn't get super-ugly on the user side of life.
    • The reference implementation of these codepointers in dsda-doom is designed to be as easy to implement as possible for Boom-derived sourceports. Though some modification of internal functions is needed for certain codepointers, the changes are minimally invasive and should not require mounds of refactoring.
Actor pointers
  • A_SpawnObject(type, angle, x_ofs, y_ofs, z_ofs, x_vel, y_vel, z_vel)

    • Generic actor spawn function.
    • Args:
      • type (uint): Type (dehnum) of actor to spawn
      • angle (fixed): Angle (degrees), relative to calling actor's angle
      • x_ofs (fixed): X (forward/back) spawn position offset
      • y_ofs (fixed): Y (left/right) spawn position offset
      • z_ofs (fixed): Z (up/down) spawn position offset
      • x_vel (fixed): X (forward/back) velocity
      • y_vel (fixed): Y (left/right) velocity
      • z_vel (fixed): Z (up/down) velocity
    • Notes:
      • If the spawnee is a missile, the tracer and target pointers are set as follows:
        • If spawner is also a missile, tracer and target are copied to spawnee
        • Otherwise, spawnee's target is set to the spawner and tracer is set to the spawner's target.
  • A_MonsterProjectile(type, angle, pitch, hoffset, voffset)

    • Generic monster projectile attack.
    • Args:
      • type (uint): Type (dehnum) of actor to spawn
      • angle (fixed): Angle (degrees), relative to calling actor's angle
      • pitch (fixed): Pitch (degrees), relative to calling actor's pitch
      • hoffset (fixed): Horizontal spawn offset, relative to calling actor's angle
      • voffset (fixed): Vertical spawn offset, relative to actor's default projectile fire height
    • Notes:
      • The spawned projectile's tracer pointer is always set to the spawner's target, for generic seeker missile support.
      • For demo-compatible ports, the pitch arg must use the same approximated slope calculation that Doom's monster aim / autoaim uses (finetangent table) & only adjust the projectile's z-velocity, rather than calculate true 3D pitch.
  • A_MonsterBulletAttack(hspread, vspread, numbullets, damagebase, damagedice)

    • Generic monster bullet attack.
    • Args:
      • hspread (fixed): Horizontal spread (degrees, in fixed point)
      • vspread (fixed): Vertical spread (degrees, in fixed point)
      • numbullets (uint): Number of bullets to fire; if not set, defaults to 1
      • damagebase (uint): Base damage of attack; if not set, defaults to 3
      • damagedice (uint): Attack damage random multiplier; if not set, defaults to 5
    • Notes:
      • Damage formula is: damage = (damagebase * random(1, damagedice))
      • Damage arg defaults are identical to Doom's monster bullet attack damage values.
      • For demo-compatible ports, the vspread arg must use the same approximated slope calculation that Doom's monster aim / autoaim uses (finetangent table), rather than calculate true 3D pitch.
  • A_MonsterMeleeAttack(damagebase, damagedice, sound, range)

    • Generic monster melee attack.
    • Args:
      • damagebase (uint): Base damage of attack; if not set, defaults to 3
      • damagedice (uint): Attack damage random multiplier; if not set, defaults to 8
      • sound (uint): Sound to play if attack hits
      • range (fixed): Attack range; if not set, defaults to calling actor's melee range property
    • Notes:
      • Damage formula is: damage = (damagebase * random(1, damagedice))
  • A_RadiusDamage(damage, radius)

    • Generic explosion.
    • Args:
      • damage (uint): Max explosion damge
      • radius (uint): Explosion radius, in map units
  • A_NoiseAlert

    • Alerts monsters within sound-travel distance of the calling actor's target.
    • No Args.
  • A_HealChase(state, sound)

    • Generic A_VileChase. Chases the player and resurrects any corpses with a Raise state when bumping into them.
    • Args:
      • state (uint): State to jump to on the calling actor when resurrecting a corpse
      • sound (uint): Sound to play when resurrecting a corpse
  • A_SeekTracer(threshold, maxturnangle)

    • Generic seeker missile function.
    • Args:
      • threshold (fixed): If angle to target is lower than this, missile will 'snap' directly to face the target
      • maxturnangle (fixed): Maximum angle a missile will turn towards the target if angle is above the threshold
    • Notes:
      • When using this function, keep in mind that seek 'strength' also depends on how often this function is called -- e.g. calling A_SeekTracer every tic will result in a much more aggressive seek than calling it every 4 tics, even if the args are the same
      • This function uses Heretic's seeker missile logic (P_SeekerMissile), rather than Doom's, with the following changes:
        • The actor's tracer pointer is used as the seek target, rather than Heretic's special1 field
        • On the z-axis, the missile will seek towards the vertical centerpoint of the seek target, rather than the bottom (resulting in much friendly behavior when seeking toward enemies on high ledges).
        • Z-axis seeking will always be attempted, rather than use Heretic's behavior of skipping the Z-axis adjustment if the missile's z position falls between the actor's top/bottom z positions.
  • A_FindTracer(fov, rangeblocks)

    • Searches for a valid tracer (seek target), if the calling actor doesn't already have one. Particularly useful for player missiles.
    • Args:
      • fov (fixed): Field-of-view, relative to calling actor's angle, to search for targets in. If zero, the search will occur in all directions.
      • rangeblocks (uint): Distance to search, in map blocks (128 units); if not set, defaults to 10.
    • Notes:
      • This function will no-op if the calling actor already has a tracer. To forcibly re-acquire a new tracer, call A_ClearTracer first.
      • This function uses a variant of Hexen's blockmap search algorithm (P_RoughMonsterSearch), with the rules for picking a valid target defined as follows (in order of evaluation):
        • Actors without the SHOOTABLE flag are skipped
        • The projectile's owner (target) is skipped
        • Actors on the same "team" are skipped (e.g. MF_FRIEND actors will not pick players or fellow MF_FRIENDs), with a few exceptions:
          • If actors are infighting (i.e. candidate actor is projectile owner's target), actor will not be skipped
          • Players will not be skipped in deathmatch
            • This rule is to work around a weird quirk in MBF (namely, that players have MF_FRIEND set even in DM); ports with a robust "team" implementation may wish to adjust or append to this logic to take player team into account.
        • If the fov arg is nonzero, actors outside of an fov-degree cone, relative to the missile's angle, are skipped
        • Actors not in line-of-sight of the missile are skipped
  • A_ClearTracer

    • Clears the calling actor's tracer (seek target) field.
    • No Args.
  • A_JumpIfHealthBelow(state, health)

    • Jumps to a state if caller's health is below the specified threshold.
    • Args:
      • state (uint): State to jump to
      • health (int): Health to check
    • Notes:
      • The jump will only occur if health is BELOW the given value -- e.g. A_JumpIfHealthBelow(420, 69) will jump to state 420 if health is 68 or lower.
  • A_JumpIfTargetInSight(state)

    • Jumps to a state if caller's target is in line-of-sight.
    • Args:
      • state (uint): State to jump to
      • fov (fixed): Field-of-view, relative to calling actor's angle, to check for target in. If zero, the check will occur in all directions.
  • A_JumpIfTargetCloser(state, distance)

    • Jumps to a state if caller's target is closer than the specified distance.
    • Args:
      • state (uint): State to jump to
      • distance (fixed): Distance threshold, in map units
    • Notes:
      • For demo-compatible ports, this function must the same approximate distance check as other functions in the game (P_AproxDistance).
      • The jump will only occur if distance is BELOW the given value -- e.g. A_JumpIfTargetCloser(420, 69.0) will jump to state 420 if distance is 68.0 or lower.
  • A_JumpIfTracerInSight(state)

    • Jumps to a state if caller's tracer (seek target) is in line-of-sight.
    • Args:
      • state (uint): State to jump to
      • fov (fixed): Field-of-view, relative to calling actor's angle, to check for tracer in. If zero, the check will occur in all directions.
  • A_JumpIfTracerCloser(state, distance)

    • Jumps to a state if caller's tracer (seek target) is closer than the specified distance.
    • Args:
      • state (uint): State to jump to
      • distance (fixed): Distance threshold, in map units
    • Notes:
      • For demo-compatible ports, this function must the same approximate distance check as other functions in the game (P_AproxDistance).
      • The jump will only occur if distance is BELOW the given value -- e.g. A_JumpIfTracerCloser(420, 69.0) will jump to state 420 if distance is 68.0 or lower.
  • A_JumpIfFlagsSet(state, flags, flags2)

    • Jumps to a state if caller has the specified thing flags set.
    • Args:
      • state (uint): State to jump to.
      • flags (int): Standard actor flag(s) to check
      • flags2 (int): MBF21 actor flag(s) to check
    • Notes:
      • If multiple flags are specified in a field, jump will only occur if all the flags are set (e.g. AND comparison, not OR)
  • A_AddFlags(flags, flags2)

    • Adds the specified thing flags to the caller.
    • Args:
      • flags (int): Standard actor flag(s) to add
      • flags2 (int): MBF21 actor flag(s) to add
  • A_RemoveFlags(flags, flags2)

    • Removes the specified thing flags from the caller.
    • Args:
      • flags (int): Standard actor flag(s) to remove
      • flags2 (int): MBF21 actor flag(s) to remove
Weapon pointers
  • A_WeaponProjectile(type, angle, pitch, hoffset, voffset)

    • Generic weapon projectile attack.
    • Args:
      • type (uint): Type (dehnum) of actor to spawn
      • angle (fixed): Angle (degrees), relative to player's angle
      • pitch (fixed): Pitch (degrees), relative to player's pitch
      • hoffset (fixed): Horizontal spawn offset, relative to player's angle
      • voffset (fixed): Vertical spawn offset, relative to player's default projectile fire height
    • Notes:
      • Unlike native Doom attack codepointers, this function will not consume ammo, trigger the Flash state, or play a sound.
      • The spawned projectile's tracer pointer is set to the player's autoaim target, if available.
      • For demo-compatible ports, the pitch arg must use the same approximated slope calculation that Doom's monster aim / autoaim uses (finetangent table) & only adjust the projectile's z-velocity, rather than calculate true 3D pitch.
  • A_WeaponBulletAttack(hspread, vspread, numbullets, damagebase, damagedice)

    • Generic weapon bullet attack.
    • Args:
      • hspread (fixed): Horizontal spread (degrees, in fixed point)
      • vspread (fixed): Vertical spread (degrees, in fixed point)
      • numbullets (uint): Number of bullets to fire; if not set, defaults to 1
      • damagebase (uint): Base damage of attack; if not set, defaults to 5
      • damagedice (uint): Attack damage random multiplier; if not set, defaults to 3
    • Notes:
      • Unlike native Doom attack codepointers, this function will not consume ammo, trigger the Flash state, or play a sound.
      • Damage formula is: damage = (damagebase * random(1, damagedice))
      • Damage arg defaults are identical to Doom's weapon bullet attack damage values.
        • Note that these defaults are intentionally different for weapons vs monsters (5d3 vs 3d5) -- yup, Doom did it this way. :P
      • For demo-compatible ports, the vspread arg must use the same approximated slope calculation that Doom's monster aim / autoaim uses (finetangent table), rather than calculate true 3D pitch.
  • A_WeaponMeleeAttack(damagebase, damagedice, zerkfactor, sound, range)

    • Generic weapon melee attack.
    • Args:
      • damagebase (uint): Base damage of attack; if not set, defaults to 2
      • damagedice (uint): Attack damage random multiplier; if not set, defaults to 10
      • zerkfactor (fixed): Berserk damage multiplier; if not set, defaults to 1.0
      • sound (uint): Sound index to play if attack hits
      • range (fixed): Attack range; if not set, defaults to player mobj's melee range property
    • Notes:
      • Damage formula is: damage = (damagebase * random(1, damagedice)); this is then multiplied by zerkfactor if the player has Berserk.
  • A_WeaponSound(sound, fullvol)

    • Generic playsound for weapons.
    • Args:
      • sound (uint): Sound index to play.
      • fullvol (int): If nonzero, play this sound at full volume across the entire map.
  • A_WeaponJump(state, chance)

    • Random state jump for weapons.
    • Args:
      • state (uint): State index to jump to.
      • chance (int): Chance out of 256 to perform the jump. 0 (or below) never jumps, 256 (or higher) always jumps.
  • A_ConsumeAmmo(amount)

    • Subtracts ammo from the currently-selected weapon's ammo pool.
    • Args:
      • amount (int): Amount of ammo to subtract. If zero, will default to the current weapon's ammopershot value.
    • Notes:
      • This function will not reduce ammo below zero.
      • This function will no-op if the current weapon uses the am_noammo ("None"/"Infinite") ammotype.
      • If amount is negative, ammo will be added to the ammo pool instead.
  • A_CheckAmmo(state, amount)

    • Jumps to state if ammo is below amount.
    • Args:
      • state (uint): State index to jump to.
      • amount (uint): Amount of ammo to check. If zero, will default to the current weapon's ammopershot value.
    • Notes:
      • The jump will only occur if ammo is BELOW the given value -- e.g. A_CheckAmmo(420, 69) will jump to state 420 if ammo is 68 or lower.
      • This function will no-op if the current weapon uses the am_noammo ("None"/"Infinite") ammotype.
  • A_RefireTo(state, noammocheck)

    • Jumps to state if the fire button is currently being pressed and the weapon has enough ammo to fire.
    • Args:
      • state (uint): State index to jump to.
      • noammocheck (int): If nonzero, skip the ammo check.
  • A_GunFlashTo(state, nothirdperson)

    • Generic weapon muzzle flash.
    • Args:
      • state (uint): State index to set the flash psprite to.
      • nothirdperson (int): If nonzero, do not change the 3rd-person player sprite to the player muzzleflash state.
  • A_WeaponAlert

    • Alerts monsters within sound-travel distance of the player's presence. Useful for weapons with the WPF_SILENT flag set.
    • No Args.

Miscellaneous

New comp flags

  • comp_ledgeblock: commit
    • Ledges block ground enemies
    • Exception: movement due to scrolling / pushers / pullers disables comp_ledgeblock for the next xy movement: commit
  • comp_friendlyspawn: PR
    • When on: A_Spawn new thing inherits friend flag from source thing.
    • When off: A_Spawn new thing keeps its default friend flag.
  • comp_voodooscroller: PR
    • When on: voodoo dolls on slow scrollers move too slowly
    • When off: voodoo dolls move the same speed as the floor
  • comp_reservedlineflag: commit, commit
    • When on: the line flag 0x0800 clears extended flags (flags &= 0x01ff).
    • When off: the line flag 0x0800 means nothing.

Summary of comp flags since mbf in pr+ and changes:

Name Index Default Description
comp_moveblock- 19 0 Large negative displacements are mishandled
comp_respawn* 20 0 Creatures with no spawnpoint respawn at (0,0)
comp_sound- 21 0 Assorted sound errors
comp_666- 22 0 Buggy pre-udoom boss checks
comp_soul* 23 0 Lost souls do not bounce
comp_maskedanim- 24 0 Two-sided midtextures don't animate
comp_ouchface- 25 0 Buggy vanilla ouchface code
comp_maxhealth- 26 0 Max health in deh only applies to potions
comp_translucency- 27 0 Disable some predefined translucency
comp_ledgeblock 28 1 Ledges block ground enemies
comp_friendlyspawn 29 1 A_Spawn new thing inherits friendliness
comp_voodooscroller 30 0 Voodoo dolls on slow scrollers move too slowly
comp_reservedlineflag 31 1 Line flag 0x0800 clears extended flags
  • Comp options marked with a - have been deoptionalized in mbf21 (forced to 0). Many of these have nothing to do with demo compatibility - others are simple bug fixes.
  • Comp options marked with a * are already implemented in EE.

Option default changes

  • comp_pursuit: 1 (was 0)

Demo format / header

  • MBF21 occupies complevel 21.
  • Demo version is 221.
  • longtics are enabled while recording.
  • Old option entries removed:
    • variable_friction (always 1)
    • allow_pushers (always 1)
    • demo_insurance (always 0)
    • obsolete / empty bytes
  • New option entries:
    • New comp options from above
    • Size of comp option list
      • This could be used to add comp options later without adding a complevel
      • When reading a demo that has a size larger than what you expect, abort
  • Header options block:
Key Bytes
monsters_remember 1
weapon_recoil 1
player_bobbing 1
respawnparm 1
fastparm 1
nomonsters 1
rngseed 4
monster_infighting 1
dogs 1
distfriend 2
monster_backing 1
monster_avoid_hazards 1
monster_friction 1
help_friends 1
dog_jumping 1
monkeys 1
comp list size (23+) 1
comp_telefrag 1
comp_dropoff 1
comp_vile 1
comp_pain 1
comp_skull 1
comp_blazing 1
comp_doorlight 1
comp_model 1
comp_god 1
comp_falloff 1
comp_floors 1
comp_skymap 1
comp_pursuit 1
comp_doorstuck 1
comp_staylift 1
comp_zombie 1
comp_stairs 1
comp_infcheat 1
comp_zerotags 1
comp_respawn 1
comp_soul 1
comp_ledgeblock 1
comp_friendlyspawn 1
comp_voodooscroller 1
comp_reservedlineflag 1
  • The comp list size is variable - take care when reading demos.
    • If the comp list size is <24, then comp_voodooscroller equals 1.
    • If the comp list size is <25, then comp_reservedlineflag equals 0.

Fixes / adjustments since mbf

  • Fix 3 key door bug
    • Already fixed in pr+ / EE.
    • code
  • Fix T_VerticalDoor mistake
    • Already fixed in pr+ / EE.
    • code
  • Fix buggy comp_stairs implementation
    • Already fixed in pr+ / EE.
    • code and code
  • P_CreateSecNodeList global tmthing fix
    • Already fixed in pr+ / EE.
    • code
  • A_CheckReload downstate
    • Already fixed in pr+ / EE.
    • code
  • Fix P_DivlineSide bug
    • Already fixed in pr+ / EE.
    • code
  • P_InterceptVector precision / overflow fix
    • Already fixed in pr+ / EE.
    • code
  • Fix generalized crusher walkover lines
    • Already fixed in EE, but not in pr+.
    • commit
  • Fix blockmap issue seen in btsx e2 Map 20
    • Already fixed in EE, but not in pr+.
    • commit
  • Fix missing dropoff condition
    • Already fixed in pr+, but not in EE.
    • code
    • EE
  • P_KillMobj thinker updates
    • Changed in pr+, reverted for mbf21.
    • commit
  • A_Mushroom changes
    • Changed in pr+, reverted for mbf21.
    • commit
  • Fix negative ammo counts
  • Fix weapon autoswitch not taking DEHACKED ammotype changes into account

Important Notes

  • The default ammopershot value for fist / chainsaw is 1 (matters for backwards compatibility).
  • Depending on how your port has modified spawning code, you may have a lingering bug related to the validcount variable. Basically, in vanilla doom, this variable is incremented in the wrong position in P_CheckPosition. The explanation for why this is a problem is complicated, but ripper projectiles (and possibly other cases) will expose this bug and cause desyncs. If your port strives for demo compatibility, I recommend adding an extra validcount increment in P_CheckPosition before running the P_BlockLinesIterator, as was done in dsda-doom (wrap it in a compatibility check for mbf21 if necessary): code. Without that fix, vanilla heretic demos go out of sync, and the same will be true for mbf21 demos with certain dehacked features in play. A port like crispy doom wouldn't be affected because it hasn't modified the spawn code in a way that introduces the bugged validcount. Ports like pr+ and ee do have this problem, for example.