* Updated to ZDoom r3442:

- Added clearlinespecial, for doom.wad e3m4 line 1069.
- Allow using the parameterized compatibility options with IWAD maps.
- Fixed: Destroying a weapon that claimed it was its own sister would crash.
- Apply fix from previous commit to Doom-format maps. (Previous commit only did it for Hexen.)
- Fixed: In non-UDMF maps, projectile impact activation implies projectile cross activation as well.
- Applied a modified version of FDARI's patch to prevent giving health to dead things:
  * P_GiveBody() now takes a max parameter so that it can also do the bulk of the work AHealth::TryPickup() previously did.
  * Setting an actor's health to 0 or below with SetActorProperty will now kill the actor properly.- Added setactivation command for compatibility.cpp to fix the gear boxes on hexdd.wad, map54, which should be set for player uses activation but are not.
- Added some developer mode messages for setlinespecial and clearlinespecial.
- Fixed: Old-style ACS has the string table record offsets from the start of the object file to the strings, not from the start of the string table, so UnescapeStringTable() needs to be told where the offsets are based.

git-svn-id: http://mancubus.net/svn/hosted/gzdoom/trunk@1313 b0f79afe-0144-0410-b225-9a4edf0717df
This commit is contained in:
gez 2012-03-16 00:22:53 +00:00
parent 0b513a0098
commit 12f0af93ad
10 changed files with 181 additions and 106 deletions

View file

@ -74,7 +74,9 @@ enum
CP_END,
CP_CLEARFLAGS,
CP_SETFLAGS,
CP_SETSPECIAL
CP_SETSPECIAL,
CP_CLEARSPECIAL,
CP_SETACTIVATION
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -239,6 +241,22 @@ void ParseCompatibility()
CompatParams.Push(sc.Number);
}
}
else if (sc.Compare("clearlinespecial"))
{
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_CLEARSPECIAL);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
}
else if (sc.Compare("setactivation"))
{
if (flags.ExtCommandIndex == ~0u) flags.ExtCommandIndex = CompatParams.Size();
CompatParams.Push(CP_SETACTIVATION);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
sc.MustGetNumber();
CompatParams.Push(sc.Number);
}
else
{
sc.UnGet();
@ -268,6 +286,7 @@ void CheckCompatibility(MapData *map)
{
FMD5Holder md5;
FCompatValues *flags;
bool onlyparams = true;
// When playing Doom IWAD levels force COMPAT_SHORTTEX and COMPATF_LIGHT.
// I'm not sure if the IWAD maps actually need COMPATF_LIGHT but it certainly does not hurt.
@ -296,42 +315,50 @@ void CheckCompatibility(MapData *map)
}
else
{
map->GetChecksum(md5.Bytes);
onlyparams = false;
}
flags = BCompatMap.CheckKey(md5);
map->GetChecksum(md5.Bytes);
if (developer)
flags = BCompatMap.CheckKey(md5);
if (developer)
{
Printf("MD5 = ");
for (size_t j = 0; j < sizeof(md5.Bytes); ++j)
{
Printf("MD5 = ");
for (size_t j = 0; j < sizeof(md5.Bytes); ++j)
{
Printf("%02X", md5.Bytes[j]);
}
if (flags != NULL)
{
Printf(", cflags = %08x, cflags2 = %08x, bflags = %08x\n",
flags->CompatFlags[SLOT_COMPAT], flags->CompatFlags[SLOT_COMPAT2], flags->CompatFlags[SLOT_BCOMPAT]);
}
else
{
Printf("\n");
}
Printf("%02X", md5.Bytes[j]);
}
if (flags != NULL)
{
Printf(", cflags = %08x, cflags2 = %08x, bflags = %08x\n",
flags->CompatFlags[SLOT_COMPAT], flags->CompatFlags[SLOT_COMPAT2], flags->CompatFlags[SLOT_BCOMPAT]);
}
else
{
Printf("\n");
}
}
if (flags != NULL)
{
if (!onlyparams)
{
ii_compatflags = flags->CompatFlags[SLOT_COMPAT];
ii_compatflags2 = flags->CompatFlags[SLOT_COMPAT2];
ib_compatflags = flags->CompatFlags[SLOT_BCOMPAT];
ii_compatparams = flags->ExtCommandIndex;
}
else
ii_compatparams = flags->ExtCommandIndex;
}
else
{
if (!onlyparams)
{
ii_compatflags = 0;
ii_compatflags2 = 0;
ib_compatflags = 0;
ii_compatparams = -1;
}
ii_compatparams = -1;
}
// Reset i_compatflags
compatflags.Callback();
@ -388,6 +415,27 @@ void SetCompatibilityParams()
i+=8;
break;
}
case CP_CLEARSPECIAL:
{
if (CompatParams[i+1] < numlines)
{
line_t *line = &lines[CompatParams[i+1]];
line->special = 0;
memset(line->args, 0, sizeof(line->args));
}
i += 2;
break;
}
case CP_SETACTIVATION:
{
if (CompatParams[i+1] < numlines)
{
line_t *line = &lines[CompatParams[i+1]];
line->activation = CompatParams[i+2];
}
i += 3;
break;
}
}
}
}

View file

@ -180,34 +180,43 @@ AInventory *AAmmo::CreateTossable()
//
//---------------------------------------------------------------------------
bool P_GiveBody (AActor *actor, int num)
bool P_GiveBody (AActor *actor, int num, int max)
{
int max;
if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD))
{ // Do not heal dead things.
return false;
}
player_t *player = actor->player;
num = clamp(num, -65536, 65536); // prevent overflows for bad values
if (player != NULL)
{
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
// [MH] First step in predictable generic morph effects
if (player->morphTics)
{
if (player->MorphStyle & MORPH_FULLHEALTH)
{
if (!(player->MorphStyle & MORPH_ADDSTAMINA))
// Max is 0 by default, preserving default behavior for P_GiveBody()
// calls while supporting AHealth.
if (max <= 0)
{
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
// [MH] First step in predictable generic morph effects
if (player->morphTics)
{
if (player->MorphStyle & MORPH_FULLHEALTH)
{
max -= player->mo->stamina;
if (!(player->MorphStyle & MORPH_ADDSTAMINA))
{
max -= player->mo->stamina;
}
}
}
else // old health behaviour
{
max = MAXMORPHHEALTH;
if (player->MorphStyle & MORPH_ADDSTAMINA)
else // old health behaviour
{
max += player->mo->stamina;
max = MAXMORPHHEALTH;
if (player->MorphStyle & MORPH_ADDSTAMINA)
{
max += player->mo->stamina;
}
}
}
}
}
}
// [RH] For Strife: A negative body sets you up with a percentage
// of your full health.
if (num < 0)
@ -236,6 +245,8 @@ bool P_GiveBody (AActor *actor, int num)
}
else
{
// Parameter value for max is ignored on monsters, preserving original
// behaviour on AHealth as well as on existing calls to P_GiveBody().
max = actor->SpawnHealth();
if (num < 0)
{
@ -1475,58 +1486,16 @@ const char *AHealth::PickupMessage ()
bool AHealth::TryPickup (AActor *&other)
{
player_t *player = other->player;
int max = MaxAmount;
if (player != NULL)
PrevHealth = other->player != NULL ? other->player->health : other->health;
// P_GiveBody adds one new feature, applied only if it is possible to pick up negative health:
// Negative values are treated as positive percentages, ie Amount -100 means 100% health, ignoring max amount.
if (P_GiveBody(other, Amount, MaxAmount))
{
PrevHealth = other->player->health;
if (max == 0)
{
max = static_cast<APlayerPawn*>(other)->GetMaxHealth() + player->mo->stamina;
// [MH] First step in predictable generic morph effects
if (player->morphTics)
{
if (player->MorphStyle & MORPH_FULLHEALTH)
{
if (!(player->MorphStyle & MORPH_ADDSTAMINA))
{
max -= player->mo->stamina;
}
}
else // old health behaviour
{
max = MAXMORPHHEALTH;
if (player->MorphStyle & MORPH_ADDSTAMINA)
{
max += player->mo->stamina;
}
}
}
}
if (player->health >= max)
{
return false;
}
player->health += Amount;
if (player->health > max)
{
player->health = max;
}
player->mo->health = player->health;
GoAwayAndDie();
return true;
}
else
{
PrevHealth = INT_MAX;
if (P_GiveBody(other, Amount))
{
GoAwayAndDie ();
return true;
}
return false;
}
GoAwayAndDie ();
return true;
return false;
}
IMPLEMENT_CLASS (AHealthPickup)

View file

@ -146,11 +146,16 @@ bool AWeapon::Use (bool pickup)
void AWeapon::Destroy()
{
if (SisterWeapon != NULL)
AWeapon *sister = SisterWeapon;
if (sister != NULL)
{
// avoid recursion
SisterWeapon->SisterWeapon = NULL;
SisterWeapon->Destroy();
sister->SisterWeapon = NULL;
if (sister != this)
{ // In case we are our own sister, don't crash.
sister->Destroy();
}
}
Super::Destroy();
}

View file

@ -1169,7 +1169,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len)
{
StringTable = LittleLong(((DWORD *)Data)[1]);
StringTable += LittleLong(((DWORD *)(Data + StringTable))[0]) * 12 + 4;
UnescapeStringTable(Data + StringTable, false);
UnescapeStringTable(Data + StringTable, Data, false);
}
else
{
@ -1178,7 +1178,7 @@ FBehavior::FBehavior (int lumpnum, FileReader * fr, int len)
if (strings != NULL)
{
StringTable = DWORD(strings - Data + 8);
UnescapeStringTable(strings + 8, true);
UnescapeStringTable(strings + 8, NULL, true);
}
else
{
@ -1621,7 +1621,7 @@ void FBehavior::LoadScriptsDirectory ()
scripts.b = FindChunk(MAKE_ID('S','N','A','M'));
if (scripts.dw != NULL)
{
UnescapeStringTable(scripts.b + 8, false);
UnescapeStringTable(scripts.b + 8, NULL, false);
for (i = 0; i < NumScripts; ++i)
{
// ACC stores script names as an index into the SNAM chunk, with the first index as
@ -1688,15 +1688,23 @@ void FBehavior::UnencryptStrings ()
// FBehavior :: UnescapeStringTable
//
// Processes escape sequences for every string in a string table.
// Chunkstart points to the string table. Datastart points to the base address
// for offsets in the string table; if NULL, it will use chunkstart. If
// has_padding is true, then this is a STRL chunk with four bytes of padding
// on either side of the string count.
//
//============================================================================
void FBehavior::UnescapeStringTable(BYTE *chunkstart, bool has_padding)
void FBehavior::UnescapeStringTable(BYTE *chunkstart, BYTE *datastart, bool has_padding)
{
assert(chunkstart != NULL);
DWORD *chunk = (DWORD *)chunkstart;
if (datastart == NULL)
{
datastart = chunkstart;
}
if (!has_padding)
{
chunk[0] = LittleLong(chunk[0]);
@ -1704,7 +1712,7 @@ void FBehavior::UnescapeStringTable(BYTE *chunkstart, bool has_padding)
{
int ofs = LittleLong(chunk[1 + strnum]); // Byte swap offset, if needed.
chunk[1 + strnum] = ofs;
strbin((char *)chunk + ofs);
strbin((char *)datastart + ofs);
}
}
else
@ -1714,7 +1722,7 @@ void FBehavior::UnescapeStringTable(BYTE *chunkstart, bool has_padding)
{
int ofs = LittleLong(chunk[3 + strnum]); // Byte swap offset, if needed.
chunk[3 + strnum] = ofs;
strbin((char *)chunk + ofs);
strbin((char *)datastart + ofs);
}
}
}
@ -2866,11 +2874,21 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value)
switch (property)
{
case APROP_Health:
// Don't alter the health of dead things.
if (actor->health <= 0 || (actor->player != NULL && actor->player->playerstate == PST_DEAD))
{
break;
}
actor->health = value;
if (actor->player != NULL)
{
actor->player->health = value;
}
// If the health is set to a non-positive value, properly kill the actor.
if (value <= 0)
{
actor->Die(activator, activator);
}
break;
case APROP_Speed:
@ -5285,8 +5303,11 @@ int DLevelScript::RunScript ()
break;
case PCD_CLEARLINESPECIAL:
if (activationline)
if (activationline != NULL)
{
activationline->special = 0;
DPrintf("Cleared line special on line %d\n", activationline - lines);
}
break;
case PCD_CASEGOTO:
@ -5923,6 +5944,8 @@ int DLevelScript::RunScript ()
line->args[2] = STACK(3);
line->args[3] = STACK(2);
line->args[4] = STACK(1);
DPrintf("Set special on line %d (id %d) to %d(%d,%d,%d,%d,%d)\n",
linenum, STACK(7), specnum, arg0, STACK(4), STACK(3), STACK(2), STACK(1));
}
sp -= 7;
}

View file

@ -220,7 +220,7 @@ private:
static int STACK_ARGS SortScripts (const void *a, const void *b);
void UnencryptStrings ();
void UnescapeStringTable(BYTE *chunkstart, bool haspadding);
void UnescapeStringTable(BYTE *chunkstart, BYTE *datastart, bool haspadding);
int FindStringInChunk (DWORD *chunk, const char *varname) const;
const char *LookupString (DWORD index) const;

View file

@ -484,7 +484,7 @@ extern FBlockNode** blocklinks; // for thing chains
void P_TouchSpecialThing (AActor *special, AActor *toucher);
void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0);
void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type);
bool P_GiveBody (AActor *actor, int num);
bool P_GiveBody (AActor *actor, int num, int max=0);
bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison);
void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound);

View file

@ -2179,7 +2179,14 @@ void P_LoadLineDefs2 (MapData * map)
// convert the activation type
ld->activation = 1 << GET_SPAC(ld->flags);
if (ld->activation == SPAC_AnyCross) ld->activation = SPAC_Impact|SPAC_PCross; // this is really PTouch
if (ld->activation == SPAC_AnyCross)
{ // this is really PTouch
ld->activation = SPAC_Impact | SPAC_PCross;
}
else if (ld->activation == SPAC_Impact)
{ // In non-UMDF maps, Impact implies PCross
ld->activation = SPAC_Impact | SPAC_PCross;
}
ld->flags &= ~ML_SPAC_MASK;
}
delete[] mldf;

View file

@ -122,7 +122,14 @@ void P_TranslateLineDef (line_t *ld, maplinedef_t *mld)
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
if (ld->activation == SPAC_AnyCross)
{ // this is really PTouch
ld->activation = SPAC_Impact|SPAC_PCross;
}
else if (ld->activation == SPAC_Impact)
{ // In non-UMDF maps, Impact implies PCross
ld->activation = SPAC_Impact | SPAC_PCross;
}
ld->flags &= ~ML_SPAC_MASK;
if (passthrough && ld->activation == SPAC_Use)

View file

@ -3,5 +3,5 @@
// This file was automatically generated by the
// updaterevision tool. Do not edit by hand.
#define ZD_SVN_REVISION_STRING "3435"
#define ZD_SVN_REVISION_NUMBER 3435
#define ZD_SVN_REVISION_STRING "3442"
#define ZD_SVN_REVISION_NUMBER 3442

View file

@ -148,3 +148,19 @@ DCE862393CAAA6FF1294FB7056B53057 // UAC Ultra map07: Contains a scroller dependi
{
badangles
}
E2B5D1400279335811C1C1C0B437D9C8 // Deathknights of the Dark Citidel, map54
{
// This map has two gear boxes which are flagged for player cross
// activation instead of the proper player uses activation.
setactivation 963 2
setactivation 943 2
}
2B65CB046EA40D2E44576949381769CA // Commercial Doom e3m4
{
// This line is erroneously flagged as a door that monsters can operate.
// If they do, they block you off from half the map. Since the attached
// sector isn't a door, remove the special.
clearlinespecial 1069
}