qzdoom/src/p_xlat.cpp

361 lines
8.9 KiB
C++
Raw Normal View History

/*
** p_xlat.cpp
** Translate old Doom format maps to the Hexen format
**
**---------------------------------------------------------------------------
** Copyright 1998-2007 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.
**---------------------------------------------------------------------------
**
*/
#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"
#include "sc_man.h"
#include "cmdlib.h"
#include "xlat/xlat.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)
{
unsigned short special = (unsigned short) LittleShort(mld->special);
short tag = LittleShort(mld->tag);
DWORD flags = LittleShort(mld->flags);
INTBOOL passthrough;
if (flags & ML_TRANSLUCENT_STRIFE)
{
ld->Alpha = FRACUNIT*3/4;
}
if (gameinfo.gametype == GAME_Strife)
{
if (flags & ML_RAILING_STRIFE)
{
flags |= ML_RAILING;
}
if (flags & ML_BLOCK_FLOATERS_STRIFE)
{
flags |= ML_BLOCK_FLOATERS;
}
passthrough = 0;
}
else
{
if (gameinfo.gametype & GAME_DoomChex)
{
if (flags & ML_RESERVED_ETERNITY)
{
flags &= 0x1FF;
}
}
- VC++ doesn't seem to like the TArray serializer so I added a workaround to be able to save the 3dMidtex attachment info. - Fixed: The TArray serializer needs to be declared as a friend of TArray in order to be able to access its fields. - Since there are no backwards compatibility issues due to savegame version bumping I closed all gaps in the level flag set. - Bumped min. Savegame version and Netgame version for 3dMidtex related changes. - Changed Jump and Crouch DMFlags into 3-way switches: 0: map default, 1: off, 2: on. Since I needed new bits the rest of the DMFlag bit values had to be changed as a result. - fixed: PTR_SlideTraverse didn't check ML_BLOCKMONSTERS for sliding actors without MF3_NOBLOCKMONST. - Added MAPINFO commands 'checkswitchrange' and 'nocheckswitchrange' that can enable or disable switch range checking globally per map. - Changed ML_3DMIDTEX to force ML_CHECKSWITCHRANGE. - Added a ML_CHECKSWITCHRANGE flag which allows checking whether the player can actually reach the switch he wants to use. - Made DActiveButton::EWhere global so that I can use it outside thr DActiveButton class. March 17, 2008 (Changes by Graf Zahl) - Changed P_LineOpening to pass its result in a struct instead of global variables. - Added Eternity's 3DMIDTEX feature (no Eternity code used though.) It should be feature complete with the exception of the ML_BLOCKMONSTERS flag handling. That particular part of Eternity's implementation is sub-optimal because it hijacks an existing flag and doesn't seem to make much sense to me. Maybe I'll implement it as a separate flag later. SVN r810 (trunk)
2008-03-18 18:18:18 +00:00
if (flags & ML_3DMIDTEX_ETERNITY)
{
flags |= ML_3DMIDTEX;
}
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;
}
FLineTrans *linetrans = NULL;
if (special < SimpleLineTranslations.Size()) linetrans = &SimpleLineTranslations[special];
if (linetrans != NULL && linetrans->special != 0)
{
ld->special = linetrans->special;
ld->args[0] = linetrans->args[0];
ld->args[1] = linetrans->args[1];
ld->args[2] = linetrans->args[2];
ld->args[3] = linetrans->args[3];
ld->args[4] = linetrans->args[4];
ld->flags = flags | ((linetrans->flags & 0x1f) << 9);
if (linetrans->flags & 0x20) ld->flags |= ML_FIRSTSIDEONLY;
ld->activation = 1 << GET_SPAC(ld->flags);
if (ld->activation == SPAC_AnyCross) ld->activation = SPAC_Impact|SPAC_PCross; // this is really PTouch
ld->flags &= ~ML_SPAC_MASK;
if (passthrough && ld->activation == SPAC_Use)
{
ld->activation = SPAC_UseThrough;
}
switch (linetrans->flags & LINETRANS_TAGMASK)
{
case LINETRANS_HAS2TAGS: // First two arguments are tags
ld->args[1] = tag;
case LINETRANS_HASTAGAT1: // First argument is a tag
ld->args[0] = tag;
break;
case LINETRANS_HASTAGAT2: // Second argument is a tag
ld->args[1] = tag;
break;
case LINETRANS_HASTAGAT3: // Third argument is a tag
ld->args[2] = tag;
break;
case LINETRANS_HASTAGAT4: // Fourth argument is a tag
ld->args[3] = tag;
break;
case LINETRANS_HASTAGAT5: // Fifth argument is a tag
ld->args[4] = tag;
break;
}
if ((ld->flags & ML_SECRET) && ld->activation & (SPAC_Use|SPAC_UseThrough))
{
ld->flags &= ~ML_MONSTERSCANACTIVATE;
}
return;
}
for(int i=0;i<NumBoomish;i++)
{
FBoomTranslator *b = &Boomish[i];
if (special >= b->FirstLinetype && special <= b->LastLinetype)
{
ld->special = b->NewSpecial;
switch (special & 0x0007)
{
case WalkMany:
flags |= ML_REPEAT_SPECIAL;
case WalkOnce:
ld->activation = SPAC_Cross;
break;
case SwitchMany:
case PushMany:
flags |= ML_REPEAT_SPECIAL;
case SwitchOnce:
case PushOnce:
if (passthrough)
ld->activation = SPAC_UseThrough;
else
ld->activation = SPAC_Use;
break;
case GunMany:
flags |= ML_REPEAT_SPECIAL;
case GunOnce:
ld->activation = SPAC_Impact;
break;
}
ld->args[0] = tag;
ld->args[1] = ld->args[2] = ld->args[3] = ld->args[4] = 0;
for(unsigned j=0; j < b->Args.Size(); j++)
{
FBoomArg *arg = &b->Args[j];
2006-04-16 13:29:50 +00:00
int *destp;
int flagtemp;
BYTE val = 0; // quiet, GCC
bool found;
if (arg->ArgNum < 4)
{
destp = &ld->args[arg->ArgNum+1];
}
else
{
2006-04-16 13:29:50 +00:00
flagtemp = ((flags >> 9) & 0x3f);
destp = &flagtemp;
}
if (arg->ListSize == 0)
{
val = arg->ConstantValue;
found = true;
}
else
{
found = false;
for (int k = 0; k < arg->ListSize; k++)
{
if ((special & arg->AndValue) == arg->ResultFilter[k])
{
val = arg->ResultValue[k];
found = true;
}
}
}
if (found)
{
if (arg->bOrExisting)
{
*destp |= val;
}
else
{
*destp = val;
}
if (arg->ArgNum == 4)
{
flags = (flags & ~0x7e00) | (flagtemp << 9);
}
}
}
// 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;
if (flags & ML_MONSTERSCANACTIVATE && ld->activation == SPAC_Cross)
{
// In Boom anything can activate such a line so set the proper type here.
ld->activation = SPAC_AnyCross;
}
return;
}
}
// 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 ()
{
AActor *dest;
TThinkerIterator<AActor> iterator(NAME_TeleportDest);
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[1] == 0)
2006-04-11 08:36:23 +00:00
{
lines[i].args[0] = 1;
}
}
}
}
}
int P_TranslateSectorSpecial (int special)
{
int mask = 0;
for(int i = SectorMasks.Size()-1; i>=0; i--)
{
int newmask = special & SectorMasks[i].mask;
if (newmask)
{
special &= ~newmask;
if (SectorMasks[i].op == 1) newmask <<= SectorMasks[i].shift;
else if (SectorMasks[i].op == -1) newmask >>= SectorMasks[i].shift;
else if (SectorMasks[i].op == 0 && SectorMasks[i].shift ==1) newmask = 0;
mask |= newmask;
}
}
if ((unsigned)special < SectorTranslations.Size())
{
if (SectorTranslations[special].bitmask_allowed && mask) special = 0;
else special = SectorTranslations[special].newtype;
}
return special | mask;
}