2006-02-24 04:48:15 +00:00
|
|
|
/*
|
|
|
|
** p_xlat.cpp
|
|
|
|
** Translate old Doom format maps to the Hexen format
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
** Copyright 1998-2005 Randy Heit
|
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
** The linedef translations are read from a WAD lump (DOOMX or HERETICX),
|
|
|
|
** so most of this file's behavior can be easily customized without
|
|
|
|
** recompiling.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "doomtype.h"
|
|
|
|
#include "g_level.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "doomdata.h"
|
|
|
|
#include "r_data.h"
|
|
|
|
#include "m_swap.h"
|
|
|
|
#include "p_spec.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "a_sharedglobal.h"
|
|
|
|
#include "gi.h"
|
|
|
|
#include "w_wad.h"
|
|
|
|
|
|
|
|
// define names for the TriggerType field of the general linedefs
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
WalkOnce,
|
|
|
|
WalkMany,
|
|
|
|
SwitchOnce,
|
|
|
|
SwitchMany,
|
|
|
|
GunOnce,
|
|
|
|
GunMany,
|
|
|
|
PushOnce,
|
|
|
|
PushMany,
|
|
|
|
} triggertype_e;
|
|
|
|
|
|
|
|
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld)
|
|
|
|
{
|
|
|
|
static FMemLump tlatebase;
|
|
|
|
const BYTE *tlate;
|
|
|
|
short special = LittleShort(mld->special);
|
|
|
|
short tag = LittleShort(mld->tag);
|
|
|
|
DWORD flags = LittleShort(mld->flags);
|
|
|
|
BOOL passthrough;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (flags & ML_TRANSLUCENT_STRIFE)
|
|
|
|
{
|
|
|
|
ld->alpha = 255*3/4;
|
|
|
|
}
|
|
|
|
if (gameinfo.gametype == GAME_Strife)
|
|
|
|
{
|
|
|
|
// It might be useful to make these usable by all games.
|
|
|
|
// Unfortunately, there aren't enough flag bits left to do that,
|
|
|
|
// so they're Strife-only.
|
|
|
|
if (flags & ML_RAILING_STRIFE)
|
|
|
|
{
|
|
|
|
flags |= ML_RAILING;
|
|
|
|
}
|
|
|
|
if (flags & ML_BLOCK_FLOATERS_STRIFE)
|
|
|
|
{
|
|
|
|
flags |= ML_BLOCK_FLOATERS;
|
|
|
|
}
|
|
|
|
passthrough = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-05-17 02:19:20 +00:00
|
|
|
if (gameinfo.gametype == GAME_Doom)
|
|
|
|
{
|
|
|
|
if (flags & ML_RESERVED_ETERNITY)
|
|
|
|
{
|
|
|
|
flags &= 0x1FF;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
passthrough = (flags & ML_PASSUSE_BOOM);
|
|
|
|
}
|
|
|
|
flags = flags & 0xFFFF01FF; // Ignore flags unknown to DOOM
|
|
|
|
|
|
|
|
// For purposes of maintaining BOOM compatibility, each
|
|
|
|
// line also needs to have its ID set to the same as its tag.
|
|
|
|
// An external conversion program would need to do this more
|
|
|
|
// intelligently.
|
|
|
|
ld->id = tag;
|
|
|
|
|
|
|
|
// 0 specials are never translated.
|
|
|
|
if (special == 0)
|
|
|
|
{
|
|
|
|
ld->special = 0;
|
|
|
|
ld->flags = flags;
|
|
|
|
ld->args[0] = mld->tag;
|
|
|
|
memset (ld->args+1, 0, sizeof(ld->args)-sizeof(ld->args[0]));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tlatebase.GetMem() == NULL)
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype == GAME_Doom)
|
|
|
|
{
|
|
|
|
tlatebase = Wads.ReadLump ("DOOMX");
|
|
|
|
}
|
|
|
|
else if (gameinfo.gametype == GAME_Strife)
|
|
|
|
{
|
|
|
|
tlatebase = Wads.ReadLump ("STRIFEX");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tlatebase = Wads.ReadLump ("HERETICX");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tlate = (const BYTE *)tlatebase.GetMem();
|
|
|
|
|
|
|
|
// Check if this is a regular linetype
|
|
|
|
if (tlate[0] == 'N' && tlate[1] == 'O' && tlate[2] == 'R' && tlate[3] == 'M')
|
|
|
|
{
|
|
|
|
int count = (tlate[4] << 8) | tlate[5];
|
|
|
|
tlate += 6;
|
|
|
|
while (count)
|
|
|
|
{
|
|
|
|
int low = (tlate[0] << 8) | tlate[1];
|
|
|
|
int high = (tlate[2] << 8) | tlate[3];
|
|
|
|
tlate += 4;
|
|
|
|
if (special >= low && special <= high)
|
|
|
|
{ // found it, so use the LUT
|
|
|
|
const BYTE *specialmap = tlate + (special - low) * 7;
|
|
|
|
|
|
|
|
ld->flags = flags | ((specialmap[0] & 0x1f) << 9);
|
|
|
|
|
|
|
|
if (passthrough && (GET_SPAC(ld->flags) == SPAC_USE))
|
|
|
|
{
|
|
|
|
ld->flags &= ~ML_SPAC_MASK;
|
|
|
|
ld->flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT;
|
|
|
|
}
|
|
|
|
ld->special = specialmap[1];
|
|
|
|
ld->args[0] = specialmap[2];
|
|
|
|
ld->args[1] = specialmap[3];
|
|
|
|
ld->args[2] = specialmap[4];
|
|
|
|
ld->args[3] = specialmap[5];
|
|
|
|
ld->args[4] = specialmap[6];
|
|
|
|
switch (specialmap[0] & 0xe0)
|
|
|
|
{
|
|
|
|
case 7<<5: // First two arguments are tags
|
|
|
|
ld->args[1] = tag;
|
|
|
|
case 1<<5: case 6<<5: // First argument is a tag
|
|
|
|
ld->args[0] = tag;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2<<5: // Second argument is a tag
|
|
|
|
ld->args[1] = tag;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3<<5: // Third argument is a tag
|
|
|
|
ld->args[2] = tag;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4<<5: // Fourth argument is a tag
|
|
|
|
ld->args[3] = tag;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5<<5: // Fifth argument is a tag
|
|
|
|
ld->args[4] = tag;
|
|
|
|
break;
|
|
|
|
}
|
- Fixed: ActorFlagSetOrReset() wasn't receiving the + or - character from
ParseActorProperties().
- Fixed: The decorate FindFlag() function returned flags from ActorFlags
instead of the passed flags set.
- Fixed: The CHT_CHAINSAW, CHT_POWER, CHT_HEALTH, and CHT_RESSURECT needed
NULL player->mo checks.
- Fixed: The "give all" command didn't give the backpack in Doom, and it
must give the backpack before giving ammo.
- Fixed: P_SetPsprite() must not call the action function if the player is
not attached to an actor. This can happen, for instance, if the level is
destroyed while the player is holding a powered-up Phoenix Rod. As part
of its EndPowerup() function, it sets the psprite to the regular version,
but the player actor has already been destroyed.
- Fixed: FinishThingdef() needs to check for valid names, because weapons
could have inherited valid pointers from their superclass.
- Fixed: fuglyname didn't work.
- Fixed: Redefining $ambient sounds leaked memory.
- Added Jim's crashcatcher.c fix for better shell support.
- VC7.1 seems to have no trouble distinguishing between passing a (const
TypeInfo *) reference to operator<< and the generic, templated (object *)
version, so a few places that can benefit from it now use it. I believe
VC6 had problems with this, which is why I didn't do it all along. The
function's implementation was also moved out of dobject.cpp and into
farchive.cpp.
- Fixed: UnpackPixels() unpacked all chunks in a byte, which is wrong for the
last byte in a row if the image width is not an even multiple of the number
pixels per byte.
- Fixed: P_TranslateLineDef() should only clear monster activation for secret
useable lines, not crossable lines.
- Fixed: Some leftover P_IsHostile() calls still needed to be rewritten.
- Fixed: AWeaponHolder::Serialize() wrote the class type in all circumstances.
SVN r20 (trunk)
2006-03-14 06:11:39 +00:00
|
|
|
if ((ld->flags & ML_SECRET) && (GET_SPAC(ld->flags) == SPAC_USE || GET_SPAC(ld->flags) == SPAC_USETHROUGH))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
ld->flags &= ~ML_MONSTERSCANACTIVATE;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
tlate += (high - low + 1) * 7;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if this is a BOOM generalized linetype
|
|
|
|
if (tlate[0] == 'B' && tlate[1] == 'O' && tlate[2] == 'O' && tlate[3] == 'M')
|
|
|
|
{
|
|
|
|
int count = (tlate[4] << 8) | tlate[5];
|
|
|
|
tlate += 6;
|
|
|
|
|
|
|
|
// BOOM translators are stored on disk as:
|
|
|
|
//
|
|
|
|
// WORD <first linetype in range>
|
|
|
|
// WORD <last linetype in range>
|
|
|
|
// BYTE <new special>
|
|
|
|
// repeat [BYTE op BYTES parms]
|
|
|
|
//
|
|
|
|
// op consists of some bits:
|
|
|
|
//
|
|
|
|
// 76543210
|
|
|
|
// ||||||++-- Dest is arg[(op&3)+1] (arg[0] is always tag)
|
|
|
|
// |||||+---- 0 = store, 1 = or with existing value
|
|
|
|
// ||||+----- 0 = this is normal, 1 = x-op in next byte
|
|
|
|
// ++++------ # of elements in list, or 0 to always use a constant value
|
|
|
|
//
|
|
|
|
// If a constant value is used, parms is a single byte containing that value.
|
|
|
|
// Otherwise, parms has the format:
|
|
|
|
//
|
|
|
|
// WORD <value to AND with linetype>
|
|
|
|
// repeat [WORD <if result is this> BYTE <use this>]
|
|
|
|
//
|
|
|
|
// These x-ops are defined:
|
|
|
|
//
|
|
|
|
// 0 = end of this BOOM translator
|
|
|
|
// 1 = dest is flags
|
|
|
|
|
|
|
|
while (count)
|
|
|
|
{
|
|
|
|
int low = (tlate[0] << 8) | tlate[1];
|
|
|
|
int high = (tlate[2] << 8) | tlate[3];
|
|
|
|
tlate += 4;
|
|
|
|
|
|
|
|
DWORD oflags = flags;
|
|
|
|
|
|
|
|
// Assume we found it and translate
|
|
|
|
switch (special & 0x0007)
|
|
|
|
{
|
|
|
|
case WalkMany:
|
|
|
|
flags |= ML_REPEAT_SPECIAL;
|
|
|
|
case WalkOnce:
|
|
|
|
flags |= SPAC_CROSS << ML_SPAC_SHIFT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SwitchMany:
|
|
|
|
case PushMany:
|
|
|
|
flags |= ML_REPEAT_SPECIAL;
|
|
|
|
case SwitchOnce:
|
|
|
|
case PushOnce:
|
|
|
|
if (passthrough)
|
|
|
|
flags |= SPAC_USETHROUGH << ML_SPAC_SHIFT;
|
|
|
|
else
|
|
|
|
flags |= SPAC_USE << ML_SPAC_SHIFT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GunMany:
|
|
|
|
flags |= ML_REPEAT_SPECIAL;
|
|
|
|
case GunOnce:
|
|
|
|
flags |= SPAC_IMPACT << ML_SPAC_SHIFT;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ld->args[0] = tag;
|
|
|
|
ld->args[1] = ld->args[2] = ld->args[3] = ld->args[4] = 0;
|
|
|
|
|
|
|
|
ld->special = *tlate++;
|
|
|
|
for (;;)
|
|
|
|
{
|
2006-04-16 13:29:50 +00:00
|
|
|
int *destp;
|
|
|
|
int flagtemp;
|
2006-02-24 04:48:15 +00:00
|
|
|
BYTE op = *tlate++;
|
|
|
|
BYTE dest;
|
|
|
|
BYTE val = 0; // quiet, GCC
|
|
|
|
bool found;
|
|
|
|
int lsize;
|
|
|
|
|
|
|
|
dest = op & 3;
|
|
|
|
if (op & 8)
|
|
|
|
{
|
|
|
|
BYTE xop = *tlate++;
|
|
|
|
if (xop == 0)
|
|
|
|
break;
|
|
|
|
else if (xop == 1)
|
|
|
|
dest = 4;
|
|
|
|
}
|
|
|
|
if (dest < 4)
|
|
|
|
{
|
|
|
|
destp = &ld->args[dest+1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-04-16 13:29:50 +00:00
|
|
|
flagtemp = ((flags >> 9) & 0x3f);
|
2006-02-24 04:48:15 +00:00
|
|
|
destp = &flagtemp;
|
|
|
|
}
|
|
|
|
lsize = op >> 4;
|
|
|
|
if (lsize == 0)
|
|
|
|
{
|
|
|
|
val = *tlate++;
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
WORD mask = (tlate[0] << 8) | tlate[1];
|
|
|
|
tlate += 2;
|
|
|
|
found = false;
|
|
|
|
for (i = 0; i < lsize; i++)
|
|
|
|
{
|
|
|
|
WORD filter = (tlate[0] << 8) | tlate[1];
|
|
|
|
if ((special & mask) == filter)
|
|
|
|
{
|
|
|
|
val = tlate[2];
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
tlate += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
if (op & 4)
|
|
|
|
{
|
|
|
|
*destp |= val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*destp = val;
|
|
|
|
}
|
|
|
|
if (dest == 4)
|
|
|
|
{
|
|
|
|
flags = (flags & ~0x7e00) | (flagtemp << 9);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (special >= low && special <= high)
|
|
|
|
{ // Really found it, so we're done
|
|
|
|
// We treat push triggers like switch triggers with zero tags.
|
|
|
|
if ((special & 7) == PushMany || (special & 7) == PushOnce)
|
|
|
|
{
|
|
|
|
if (ld->special == Generic_Door)
|
|
|
|
{
|
|
|
|
ld->args[2] |= 128;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ld->args[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ld->flags = flags;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = oflags;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't know what to do, so 0 it
|
|
|
|
ld->special = 0;
|
|
|
|
ld->flags = flags;
|
|
|
|
memset (ld->args, 0, sizeof(ld->args));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that ZDoom again gives the option of using Doom's original teleport
|
|
|
|
// behavior, only teleport dests in a sector with a 0 tag need to be
|
|
|
|
// given a TID. And since Doom format maps don't have TIDs, we can safely
|
|
|
|
// give them TID 1.
|
|
|
|
|
|
|
|
void P_TranslateTeleportThings ()
|
|
|
|
{
|
|
|
|
ATeleportDest *dest;
|
|
|
|
TThinkerIterator<ATeleportDest> iterator;
|
|
|
|
bool foundSomething = false;
|
|
|
|
|
|
|
|
while ( (dest = iterator.Next()) )
|
|
|
|
{
|
|
|
|
if (dest->Sector->tag == 0)
|
|
|
|
{
|
|
|
|
dest->tid = 1;
|
|
|
|
dest->AddToHash ();
|
|
|
|
foundSomething = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (foundSomething)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < numlines; ++i)
|
|
|
|
{
|
|
|
|
if (lines[i].special == Teleport)
|
|
|
|
{
|
|
|
|
if (lines[i].args[1] == 0)
|
|
|
|
{
|
|
|
|
lines[i].args[0] = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (lines[i].special == Teleport_NoFog)
|
|
|
|
{
|
|
|
|
if (lines[i].args[2] == 0)
|
|
|
|
{
|
|
|
|
lines[i].args[0] = 1;
|
|
|
|
}
|
|
|
|
}
|
2006-04-11 08:36:23 +00:00
|
|
|
else if (lines[i].special == Teleport_ZombieChanger)
|
|
|
|
{
|
|
|
|
if (lines[i].args[2] == 0)
|
|
|
|
{
|
|
|
|
lines[i].args[0] = 1;
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int P_TranslateSectorSpecial (int special)
|
|
|
|
{
|
|
|
|
int high;
|
|
|
|
|
|
|
|
// Allow any supported sector special by or-ing 0x8000 to it in Doom format maps
|
|
|
|
// That's for those who like to mess around with existing maps. ;)
|
|
|
|
if (special & 0x8000)
|
|
|
|
{
|
|
|
|
return special & 0x7fff;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (special == 9)
|
|
|
|
{
|
|
|
|
return SECRET_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gameinfo.gametype == GAME_Doom || gameinfo.gametype == GAME_Strife)
|
|
|
|
{
|
|
|
|
// This supports phased lighting with specials 21-24
|
|
|
|
high = (special & 0xfe0) << 3;
|
|
|
|
special &= 0x1f;
|
|
|
|
if (special < 21)
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype == GAME_Strife)
|
|
|
|
{
|
|
|
|
if (special == 4 || special == 5 || special == 15 || special == 16 || special == 18)
|
|
|
|
{
|
|
|
|
return high | (special + 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (level.flags & LEVEL_CAVERNS_OF_DARKNESS)
|
|
|
|
{
|
|
|
|
// CoD uses 18 as an instant death sector type and 19 for healing the player
|
|
|
|
if (special == 18) return high | Damage_InstantDeath;
|
|
|
|
if (special == 19) return high | Sector_Heal;
|
|
|
|
}
|
|
|
|
return high | (special + 64);
|
|
|
|
}
|
|
|
|
else if (special < 40)
|
|
|
|
{
|
|
|
|
return high | (special - 20);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
high = (special & 0xfc0) << 3;
|
|
|
|
special &= 0x3f;
|
|
|
|
if (special == 5)
|
|
|
|
{
|
|
|
|
return high | dDamage_LavaWimpy;
|
|
|
|
}
|
|
|
|
else if (special == 16)
|
|
|
|
{
|
|
|
|
return high | dDamage_LavaHefty;
|
|
|
|
}
|
|
|
|
else if (special == 4)
|
|
|
|
{
|
|
|
|
return high | dScroll_EastLavaDamage;
|
|
|
|
}
|
|
|
|
else if (special < 20)
|
|
|
|
{
|
|
|
|
return high | (special + 64);
|
|
|
|
}
|
|
|
|
else if (special < 40)
|
|
|
|
{
|
|
|
|
return high | (special + 205);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return high | special;
|
|
|
|
}
|