- Added a StartConversation special that allows automatic activation of Strife

dialogs.
- Added Thing_Raise special that allows Arch-Vile like resurrections from scripts
  or DECORATE states.
- Added a RadiusDamageFactor property for actors. This replaces the hard coded
  factor of 0.25 for Hexen's players.
- Added new SpawnProjectile function to ACS. It's the same as Thing_Projectile2
  but the projectile is specified by name, not spawn ID.
- Added MAPINFO option to set the compatibility flags. If this is done these
  explicit settings will take precedence over the compatflags CVAR.

SVN r164 (trunk)
This commit is contained in:
Christoph Oelckers 2006-06-03 12:30:11 +00:00
parent 4325fb8993
commit 15681d0588
32 changed files with 472 additions and 260 deletions

View file

@ -1,3 +1,15 @@
June 3, 2006 (Changes by Graf Zahl)
- Added a StartConversation special that allows automatic activation of Strife
dialogs.
- Added Thing_Raise special that allows Arch-Vile like resurrections from scripts
or DECORATE states.
- Added a RadiusDamageFactor property for actors. This replaces the hard coded
factor of 0.25 for Hexen's players.
- Added new SpawnProjectile function to ACS. It's the same as Thing_Projectile2
but the projectile is specified by name, not spawn ID.
- Added MAPINFO option to set the compatibility flags. If this is done these
explicit settings will take precedence over the compatflags CVAR.
May 31, 2006 May 31, 2006
- Merged in recent ZDBSP fixes: - Merged in recent ZDBSP fixes:
- Added code to explicitly handle outputting overlapping segs when - Added code to explicitly handle outputting overlapping segs when
@ -14,7 +26,6 @@ May 31, 2006
- Enabled reference optimization and COMDAT folding in the linker for a slightly - Enabled reference optimization and COMDAT folding in the linker for a slightly
smaller executable. smaller executable.
May 31, 2006 (Changes by Graf Zahl) May 31, 2006 (Changes by Graf Zahl)
- Fixed: Ammo items dropped by monsters that have a default amount of 1 didn't - Fixed: Ammo items dropped by monsters that have a default amount of 1 didn't
contain any ammo at all. contain any ammo at all.

View file

@ -403,6 +403,7 @@ enum
AMETA_WoundHealth, // health needed to enter wound state AMETA_WoundHealth, // health needed to enter wound state
AMETA_PoisonDamage, // Amount of poison damage AMETA_PoisonDamage, // Amount of poison damage
AMETA_FastSpeed, // Speed in fast mode AMETA_FastSpeed, // Speed in fast mode
AMETA_RDFactor, // Radius damage factor
}; };
// Map Object definition. // Map Object definition.

View file

@ -372,7 +372,14 @@ CVAR (Flag, sv_barrelrespawn, dmflags2, DF2_BARRELS_RESPAWN);
// //
//========================================================================== //==========================================================================
CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO); int i_compatflags; // internal compatflags composed from the compatflags CVAR and MAPINFO settings
CUSTOM_CVAR (Int, compatflags, 0, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
if (level.info == NULL) i_compatflags = self;
else i_compatflags = (self & ~level.info->compatmask) | (level.info->compatflags & level.info->compatmask);
}
CVAR (Flag, compat_shortTex, compatflags, COMPATF_SHORTTEX); CVAR (Flag, compat_shortTex, compatflags, COMPATF_SHORTTEX);
CVAR (Flag, compat_stairs, compatflags, COMPATF_STAIRINDEX); CVAR (Flag, compat_stairs, compatflags, COMPATF_STAIRINDEX);
CVAR (Flag, compat_limitpain, compatflags, COMPATF_LIMITPAIN); CVAR (Flag, compat_limitpain, compatflags, COMPATF_LIMITPAIN);

View file

@ -309,5 +309,6 @@ EXTERN_CVAR (Int, dmflags);
EXTERN_CVAR (Int, dmflags2); // [BC] EXTERN_CVAR (Int, dmflags2); // [BC]
EXTERN_CVAR (Int, compatflags); EXTERN_CVAR (Int, compatflags);
extern int i_compatflags;
#endif #endif

View file

@ -132,7 +132,7 @@ void A_PainShootSkull (AActor *self, angle_t angle)
} }
// [RH] make this optional // [RH] make this optional
if (compatflags & COMPATF_LIMITPAIN) if (i_compatflags & COMPATF_LIMITPAIN)
{ {
// count total number of skulls currently on the level // count total number of skulls currently on the level
// if there are already 20 skulls on the level, don't spit another one // if there are already 20 skulls on the level, don't spit another one

View file

@ -91,6 +91,7 @@ IMPLEMENT_ACTOR (AClericPlayer, Hexen, -1, 0)
PROP_RadiusFixed (16) PROP_RadiusFixed (16)
PROP_HeightFixed (64) PROP_HeightFixed (64)
PROP_SpeedFixed (1) PROP_SpeedFixed (1)
PROP_RadiusdamageFactor(FRACUNIT/4)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY) PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY)
PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL) PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL)
PROP_Flags3 (MF3_NOBLOCKMONST) PROP_Flags3 (MF3_NOBLOCKMONST)
@ -193,19 +194,19 @@ bool AClericWeapon::TryPickup (AActor *toucher)
// somebody wants to use these weapons with either of those games. // somebody wants to use these weapons with either of those games.
if (toucher->IsKindOf (RUNTIME_CLASS(AFighterPlayer)) || if (toucher->IsKindOf (RUNTIME_CLASS(AFighterPlayer)) ||
toucher->IsKindOf (RUNTIME_CLASS(AMagePlayer))) toucher->IsKindOf (RUNTIME_CLASS(AMagePlayer)))
{ // Wrong class, but try to pick up for mana { // Wrong class, but try to pick up for mana
if (ShouldStay()) if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay { // Can't pick up weapons for other classes in coop netplay
return false; return false;
} }
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1)); bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2)); gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome) if (gaveSome)
{ {
GoAwayAndDie (); GoAwayAndDie ();
} }
return gaveSome; return gaveSome;
} }
return Super::TryPickup (toucher); return Super::TryPickup (toucher);
} }

View file

@ -89,6 +89,7 @@ IMPLEMENT_ACTOR (AFighterPlayer, Hexen, -1, 0)
PROP_Mass (100) PROP_Mass (100)
PROP_PainChance (255) PROP_PainChance (255)
PROP_SpeedFixed (1) PROP_SpeedFixed (1)
PROP_RadiusdamageFactor(FRACUNIT/4)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY) PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY)
PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL) PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL)
PROP_Flags3 (MF3_NOBLOCKMONST) PROP_Flags3 (MF3_NOBLOCKMONST)
@ -384,8 +385,8 @@ bool AFighterPlayer::DoHealingRadius (APlayerPawn *other)
gotSome = true; gotSome = true;
} }
} }
if (gotSome) if (gotSome)
{ {
S_Sound (other, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM); S_Sound (other, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM);
return true; return true;
} }
@ -402,19 +403,19 @@ bool AFighterWeapon::TryPickup (AActor *toucher)
// somebody wants to use these weapons with either of those games. // somebody wants to use these weapons with either of those games.
if (toucher->IsKindOf (RUNTIME_CLASS(AClericPlayer)) || if (toucher->IsKindOf (RUNTIME_CLASS(AClericPlayer)) ||
toucher->IsKindOf (RUNTIME_CLASS(AMagePlayer))) toucher->IsKindOf (RUNTIME_CLASS(AMagePlayer)))
{ // Wrong class, but try to pick up for mana { // Wrong class, but try to pick up for mana
if (ShouldStay()) if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay { // Can't pick up weapons for other classes in coop netplay
return false; return false;
} }
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1)); bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2)); gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome) if (gaveSome)
{ {
GoAwayAndDie (); GoAwayAndDie ();
} }
return gaveSome; return gaveSome;
} }
return Super::TryPickup (toucher); return Super::TryPickup (toucher);
} }

View file

@ -88,6 +88,7 @@ IMPLEMENT_ACTOR (AMagePlayer, Hexen, -1, 0)
PROP_RadiusFixed (16) PROP_RadiusFixed (16)
PROP_HeightFixed (64) PROP_HeightFixed (64)
PROP_SpeedFixed (1) PROP_SpeedFixed (1)
PROP_RadiusdamageFactor(FRACUNIT/4)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY) PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPOFF|MF_PICKUP|MF_NOTDMATCH|MF_FRIENDLY)
PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL) PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_SLIDE|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL)
PROP_Flags3 (MF3_NOBLOCKMONST) PROP_Flags3 (MF3_NOBLOCKMONST)
@ -162,14 +163,14 @@ fixed_t AMagePlayer::GetJumpZ ()
// Radius mana boost // Radius mana boost
bool AMagePlayer::DoHealingRadius (APlayerPawn *other) bool AMagePlayer::DoHealingRadius (APlayerPawn *other)
{ {
int amount = 50 + (pr_manaradius() % 50); int amount = 50 + (pr_manaradius() % 50);
if (GiveAmmo (RUNTIME_CLASS(AMana1), amount) || if (GiveAmmo (RUNTIME_CLASS(AMana1), amount) ||
GiveAmmo (RUNTIME_CLASS(AMana2), amount)) GiveAmmo (RUNTIME_CLASS(AMana2), amount))
{ {
S_Sound (other, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM); S_Sound (other, CHAN_AUTO, "MysticIncant", 1, ATTN_NORM);
return true; return true;
} }
return false; return false;
} }
@ -199,19 +200,19 @@ bool AMageWeapon::TryPickup (AActor *toucher)
// somebody wants to use these weapons with either of those games. // somebody wants to use these weapons with either of those games.
if (toucher->IsKindOf (RUNTIME_CLASS(AFighterPlayer)) || if (toucher->IsKindOf (RUNTIME_CLASS(AFighterPlayer)) ||
toucher->IsKindOf (RUNTIME_CLASS(AClericPlayer))) toucher->IsKindOf (RUNTIME_CLASS(AClericPlayer)))
{ // Wrong class, but try to pick up for mana { // Wrong class, but try to pick up for mana
if (ShouldStay()) if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay { // Can't pick up weapons for other classes in coop netplay
return false; return false;
} }
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1)); bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2)); gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome) if (gaveSome)
{ {
GoAwayAndDie (); GoAwayAndDie ();
} }
return gaveSome; return gaveSome;
} }
return Super::TryPickup (toucher); return Super::TryPickup (toucher);
} }

View file

@ -247,6 +247,19 @@ static const char *MapInfoMapLevel[] =
"allowcrouch", "allowcrouch",
"nocrouch", "nocrouch",
"pausemusicinmenus", "pausemusicinmenus",
"compat_shorttex",
"compat_stairs",
"compat_limitpain",
"compat_nopassover",
"compat_notossdrops",
"compat_useblocking",
"compat_nodoorlight",
"compat_ravenscroll",
"compat_soundtarget",
"compat_dehhealth",
"compat_trace",
"compat_dropoff",
NULL NULL
}; };
@ -270,7 +283,8 @@ enum EMIType
MITYPE_RELLIGHT, MITYPE_RELLIGHT,
MITYPE_CLRBYTES, MITYPE_CLRBYTES,
MITYPE_REDIRECT, MITYPE_REDIRECT,
MITYPE_SPECIALACTION MITYPE_SPECIALACTION,
MITYPE_COMPATFLAG,
}; };
struct MapInfoHandler struct MapInfoHandler
@ -363,6 +377,18 @@ MapHandlers[] =
{ MITYPE_SCFLAGS, LEVEL_CROUCH_YES, ~LEVEL_CROUCH_NO }, { MITYPE_SCFLAGS, LEVEL_CROUCH_YES, ~LEVEL_CROUCH_NO },
{ MITYPE_SCFLAGS, LEVEL_CROUCH_NO, ~LEVEL_CROUCH_YES }, { MITYPE_SCFLAGS, LEVEL_CROUCH_NO, ~LEVEL_CROUCH_YES },
{ MITYPE_SCFLAGS, LEVEL_PAUSE_MUSIC_IN_MENUS, 0 }, { MITYPE_SCFLAGS, LEVEL_PAUSE_MUSIC_IN_MENUS, 0 },
{ MITYPE_COMPATFLAG, COMPATF_SHORTTEX},
{ MITYPE_COMPATFLAG, COMPATF_STAIRINDEX},
{ MITYPE_COMPATFLAG, COMPATF_LIMITPAIN},
{ MITYPE_COMPATFLAG, COMPATF_NO_PASSMOBJ},
{ MITYPE_COMPATFLAG, COMPATF_NOTOSSDROPS},
{ MITYPE_COMPATFLAG, COMPATF_USEBLOCKING},
{ MITYPE_COMPATFLAG, COMPATF_NODOORLIGHT},
{ MITYPE_COMPATFLAG, COMPATF_RAVENSCROLL},
{ MITYPE_COMPATFLAG, COMPATF_SOUNDTARGET},
{ MITYPE_COMPATFLAG, COMPATF_DEHHEALTH},
{ MITYPE_COMPATFLAG, COMPATF_TRACE},
{ MITYPE_COMPATFLAG, COMPATF_DROPOFF},
}; };
static const char *MapInfoClusterLevel[] = static const char *MapInfoClusterLevel[] =
@ -976,6 +1002,16 @@ static void ParseMapInfoLower (MapInfoHandler *handlers,
SC_SetCMode(false); SC_SetCMode(false);
} }
break; break;
case MITYPE_COMPATFLAG:
SC_MustGetNumber();
if (levelinfo != NULL)
{
if (sc_Number) levelinfo->compatflags |= (DWORD)handler->data1;
else levelinfo->compatflags &= ~ (DWORD)handler->data1;
levelinfo->compatmask |= (DWORD)handler->data1;
}
break;
} }
} }
if (levelinfo) if (levelinfo)
@ -2157,6 +2193,8 @@ void G_InitLevelLocals ()
dmflags = (dmflags & ~clear) | set; dmflags = (dmflags & ~clear) | set;
compatflags.Callback();
NormalLight.ChangeFade (level.fadeto); NormalLight.ChangeFade (level.fadeto);
if (level.Scrolls != NULL) if (level.Scrolls != NULL)

View file

@ -134,6 +134,7 @@ struct level_info_s
char *level_name; char *level_name;
char fadetable[9]; char fadetable[9];
SBYTE WallVertLight, WallHorizLight; SBYTE WallVertLight, WallHorizLight;
// TheDefaultLevelInfo initializes everything above this line.
int musicorder; int musicorder;
FCompressedMemFile *snapshot; FCompressedMemFile *snapshot;
DWORD snapshotVer; DWORD snapshotVer;
@ -149,6 +150,8 @@ struct level_info_s
float aircontrol; float aircontrol;
int WarpTrans; int WarpTrans;
int airsupply; int airsupply;
DWORD compatflags;
DWORD compatmask;
// Redirection: If any player is carrying the specified item, then // Redirection: If any player is carrying the specified item, then
// you go to the RedirectMap instead of this one. // you go to the RedirectMap instead of this one.

View file

@ -180,7 +180,7 @@ bool P_GiveBody (AActor *actor, int num)
if (player != NULL) if (player != NULL)
{ {
max = ((compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina; max = ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina;
if (player->morphTics) if (player->morphTics)
{ {
max = MAXMORPHHEALTH; max = MAXMORPHHEALTH;
@ -1484,9 +1484,9 @@ void ABasicArmor::Tick ()
case GAME_Strife: case GAME_Strife:
Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "I_ARM2" : "I_ARM1", FTexture::TEX_Any); Icon = TexMan.CheckForTexture (SavePercent == FRACUNIT/3 ? "I_ARM2" : "I_ARM1", FTexture::TEX_Any);
break; break;
default: default:
break; break;
} }
} }
@ -1768,7 +1768,7 @@ bool AHealth::TryPickup (AActor *other)
{ {
if (max == 0) if (max == 0)
{ {
max = ((compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina; max = ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth) + player->stamina;
if (player->morphTics) if (player->morphTics)
{ {
max = MAXMORPHHEALTH; max = MAXMORPHHEALTH;

View file

@ -282,6 +282,7 @@ enum
ADEF_BounceFactor, ADEF_BounceFactor,
ADEF_BounceCount, ADEF_BounceCount,
ADEF_FloatSpeed, ADEF_FloatSpeed,
ADEF_RDFactor,
ADEF_SpawnState, ADEF_SpawnState,
ADEF_SeeState, ADEF_SeeState,

View file

@ -216,6 +216,7 @@ static void ApplyActorDefault (int defnum, const char *datastr, int dataint)
case ADEF_MaxStepHeight: actor->MaxStepHeight = dataint; break; case ADEF_MaxStepHeight: actor->MaxStepHeight = dataint; break;
case ADEF_BounceFactor: actor->bouncefactor = dataint; break; case ADEF_BounceFactor: actor->bouncefactor = dataint; break;
case ADEF_BounceCount: actor->bouncecount = dataint; break; case ADEF_BounceCount: actor->bouncecount = dataint; break;
case ADEF_RDFactor: sgClass->Meta.SetMetaFixed (AMETA_RDFactor, dataint); break;
case ADEF_SpawnState: actor->SpawnState = datastate; break; case ADEF_SpawnState: actor->SpawnState = datastate; break;
case ADEF_SeeState: actor->SeeState = datastate; break; case ADEF_SeeState: actor->SeeState = datastate; break;
@ -273,7 +274,7 @@ static void ApplyActorDefault (int defnum, const char *datastr, int dataint)
case ADEF_Ammo_BackpackAmount: ammo->BackpackAmount = dataint; break; case ADEF_Ammo_BackpackAmount: ammo->BackpackAmount = dataint; break;
case ADEF_Ammo_BackpackMaxAmount:ammo->BackpackMaxAmount = dataint; break; case ADEF_Ammo_BackpackMaxAmount:ammo->BackpackMaxAmount = dataint; break;
case ADEF_Ammo_DropAmount: sgClass->Meta.SetMetaInt (AIMETA_DropAmount, dataint); case ADEF_Ammo_DropAmount: sgClass->Meta.SetMetaInt (AIMETA_DropAmount, dataint); break;
case ADEF_Weapon_Flags: weapon->WeaponFlags = dataint; break; case ADEF_Weapon_Flags: weapon->WeaponFlags = dataint; break;
case ADEF_Weapon_FlagsSet: weapon->WeaponFlags |= dataint; break; case ADEF_Weapon_FlagsSet: weapon->WeaponFlags |= dataint; break;

View file

@ -252,6 +252,7 @@ public:
#define PROP_MaxStepHeight(x) ADD_FIXD_PROP(ADEF_MaxStepHeight,x) #define PROP_MaxStepHeight(x) ADD_FIXD_PROP(ADEF_MaxStepHeight,x)
#define PROP_BounceFactor(x) ADD_LONG_PROP(ADEF_BounceFactor,x) #define PROP_BounceFactor(x) ADD_LONG_PROP(ADEF_BounceFactor,x)
#define PROP_BounceCount(x) ADD_LONG_PROP(ADEF_BounceCount,x) #define PROP_BounceCount(x) ADD_LONG_PROP(ADEF_BounceCount,x)
#define PROP_RadiusdamageFactor(x) ADD_LONG_PROP(ADEF_RDFactor,x)
#define PROP_SpawnState(x) ADD_BYTE_PROP(ADEF_SpawnState,x) #define PROP_SpawnState(x) ADD_BYTE_PROP(ADEF_SpawnState,x)
#define PROP_SeeState(x) ADD_BYTE_PROP(ADEF_SeeState,x) #define PROP_SeeState(x) ADD_BYTE_PROP(ADEF_SeeState,x)

View file

@ -282,21 +282,21 @@ static oldmenu_t HereticMainDef =
// //
// HEXEN "NEW GAME" MENU // HEXEN "NEW GAME" MENU
// //
static oldmenuitem_t ClassItems[] = static oldmenuitem_t ClassItems[] =
{ {
{ 1,1, 'f', "FIGHTER", SCClass }, { 1,1, 'f', "FIGHTER", SCClass },
{ 1,1, 'c', "CLERIC", SCClass }, { 1,1, 'c', "CLERIC", SCClass },
{ 1,1, 'm', "MAGE", SCClass }, { 1,1, 'm', "MAGE", SCClass },
{ 1,1, 'r', "RANDOM", SCClass } // [RH] { 1,1, 'r', "RANDOM", SCClass } // [RH]
}; };
static oldmenu_t ClassMenu = static oldmenu_t ClassMenu =
{ {
4, ClassItems, 4, ClassItems,
DrawClassMenu, DrawClassMenu,
66, 58, 66, 58,
0 0
}; };
// //
// EPISODE SELECT // EPISODE SELECT
@ -388,23 +388,23 @@ static oldmenu_t HereticSkillMenu =
// //
// HEXEN SKILL SELECT // HEXEN SKILL SELECT
// //
static oldmenuitem_t HexenSkillItems[] = static oldmenuitem_t HexenSkillItems[] =
{ {
{ 1,1, '1', NULL, M_ChooseSkill }, { 1,1, '1', NULL, M_ChooseSkill },
{ 1,1, '2', NULL, M_ChooseSkill }, { 1,1, '2', NULL, M_ChooseSkill },
{ 1,1, '3', NULL, M_ChooseSkill }, { 1,1, '3', NULL, M_ChooseSkill },
{ 1,1, '4', NULL, M_ChooseSkill }, { 1,1, '4', NULL, M_ChooseSkill },
{ 1,1, '5', NULL, M_ChooseSkill } { 1,1, '5', NULL, M_ChooseSkill }
}; };
static oldmenu_t HexenSkillMenu = static oldmenu_t HexenSkillMenu =
{ {
5, HexenSkillItems, 5, HexenSkillItems,
DrawHexenSkillMenu, DrawHexenSkillMenu,
120, 44, 120, 44,
2 2
}; };
// //
// [RH] Player Setup Menu // [RH] Player Setup Menu
@ -1525,53 +1525,53 @@ void M_NewGame(int choice)
} }
} }
//========================================================================== //==========================================================================
// //
// DrawClassMenu // DrawClassMenu
// //
//========================================================================== //==========================================================================
static void DrawClassMenu(void) static void DrawClassMenu(void)
{ {
char name[9]; char name[9];
int classnum; int classnum;
static const char boxLumpName[3][7] = static const char boxLumpName[3][7] =
{ {
"M_FBOX", "M_FBOX",
"M_CBOX", "M_CBOX",
"M_MBOX" "M_MBOX"
}; };
static const char walkLumpName[3][10] = static const char walkLumpName[3][10] =
{ {
"M_FWALK%d", "M_FWALK%d",
"M_CWALK%d", "M_CWALK%d",
"M_MWALK%d" "M_MWALK%d"
}; };
screen->DrawText (CR_UNTRANSLATED, 34, 24, "CHOOSE CLASS:", DTA_Clean, true, TAG_DONE); screen->DrawText (CR_UNTRANSLATED, 34, 24, "CHOOSE CLASS:", DTA_Clean, true, TAG_DONE);
classnum = itemOn; classnum = itemOn;
if (classnum > 2) if (classnum > 2)
{ {
classnum = (MenuTime>>2) % 3; classnum = (MenuTime>>2) % 3;
} }
screen->DrawTexture (TexMan[boxLumpName[classnum]], 174, 8, DTA_Clean, true, TAG_DONE); screen->DrawTexture (TexMan[boxLumpName[classnum]], 174, 8, DTA_Clean, true, TAG_DONE);
sprintf (name, walkLumpName[classnum], ((MenuTime >> 3) & 3) + 1); sprintf (name, walkLumpName[classnum], ((MenuTime >> 3) & 3) + 1);
screen->DrawTexture (TexMan[name], 174+24, 8+12, DTA_Clean, true, TAG_DONE); screen->DrawTexture (TexMan[name], 174+24, 8+12, DTA_Clean, true, TAG_DONE);
} }
//---------------------------------------------------------------------------
//
// PROC DrawSkillMenu
//
//---------------------------------------------------------------------------
static void DrawHexenSkillMenu()
{
screen->DrawText (CR_UNTRANSLATED, 74, 16, "CHOOSE SKILL LEVEL:", DTA_Clean, true, TAG_DONE);
}
//---------------------------------------------------------------------------
//
// PROC DrawSkillMenu
//
//---------------------------------------------------------------------------
static void DrawHexenSkillMenu()
{
screen->DrawText (CR_UNTRANSLATED, 74, 16, "CHOOSE SKILL LEVEL:", DTA_Clean, true, TAG_DONE);
}
// //
// M_Episode // M_Episode
@ -1645,70 +1645,70 @@ void M_Episode (int choice)
M_SetupNextMenu (&HereticSkillMenu); M_SetupNextMenu (&HereticSkillMenu);
} }
//========================================================================== //==========================================================================
// //
// SCClass // SCClass
// //
//========================================================================== //==========================================================================
static void SCClass (int option) static void SCClass (int option)
{ {
if (netgame) if (netgame)
{ {
M_StartMessage (GStrings("NEWGAME"), NULL, false); M_StartMessage (GStrings("NEWGAME"), NULL, false);
return; return;
} }
MenuPClass = option < 3 ? option : -1; MenuPClass = option < 3 ? option : -1;
switch (MenuPClass) switch (MenuPClass)
{ {
case 0/*PCLASS_FIGHTER*/: case 0/*PCLASS_FIGHTER*/:
HexenSkillMenu.x = 120; HexenSkillMenu.x = 120;
HexenSkillItems[0].name = "SQUIRE"; HexenSkillItems[0].name = "SQUIRE";
HexenSkillItems[1].name = "KNIGHT"; HexenSkillItems[1].name = "KNIGHT";
HexenSkillItems[2].name = "WARRIOR"; HexenSkillItems[2].name = "WARRIOR";
HexenSkillItems[3].name = "BERSERKER"; HexenSkillItems[3].name = "BERSERKER";
HexenSkillItems[4].name = "TITAN"; HexenSkillItems[4].name = "TITAN";
break; break;
case 1/*PCLASS_CLERIC*/: case 1/*PCLASS_CLERIC*/:
HexenSkillMenu.x = 116; HexenSkillMenu.x = 116;
HexenSkillItems[0].name = "ALTAR BOY"; HexenSkillItems[0].name = "ALTAR BOY";
HexenSkillItems[1].name = "ACOLYTE"; HexenSkillItems[1].name = "ACOLYTE";
HexenSkillItems[2].name = "PRIEST"; HexenSkillItems[2].name = "PRIEST";
HexenSkillItems[3].name = "CARDINAL"; HexenSkillItems[3].name = "CARDINAL";
HexenSkillItems[4].name = "POPE"; HexenSkillItems[4].name = "POPE";
break; break;
case 2/*PCLASS_MAGE*/: case 2/*PCLASS_MAGE*/:
HexenSkillMenu.x = 112; HexenSkillMenu.x = 112;
HexenSkillItems[0].name = "APPRENTICE"; HexenSkillItems[0].name = "APPRENTICE";
HexenSkillItems[1].name = "ENCHANTER"; HexenSkillItems[1].name = "ENCHANTER";
HexenSkillItems[2].name = "SORCERER"; HexenSkillItems[2].name = "SORCERER";
HexenSkillItems[3].name = "WARLOCK"; HexenSkillItems[3].name = "WARLOCK";
HexenSkillItems[4].name = "ARCHMAGE"; HexenSkillItems[4].name = "ARCHMAGE";
break; break;
case -1/*random*/: // [RH] case -1/*random*/: // [RH]
// Since Hexen is "Heretic 2", use the Heretic skill // Since Hexen is "Heretic 2", use the Heretic skill
// names when not playing as a specific class. // names when not playing as a specific class.
HexenSkillMenu.x = HereticSkillMenu.x; HexenSkillMenu.x = HereticSkillMenu.x;
HexenSkillItems[0].name = HereticSkillItems[0].name; HexenSkillItems[0].name = HereticSkillItems[0].name;
HexenSkillItems[1].name = HereticSkillItems[1].name; HexenSkillItems[1].name = HereticSkillItems[1].name;
HexenSkillItems[2].name = HereticSkillItems[2].name; HexenSkillItems[2].name = HereticSkillItems[2].name;
HexenSkillItems[3].name = HereticSkillItems[3].name; HexenSkillItems[3].name = HereticSkillItems[3].name;
HexenSkillItems[4].name = HereticSkillItems[4].name; HexenSkillItems[4].name = HereticSkillItems[4].name;
break; break;
} }
if (EpiDef.numitems > 1) if (EpiDef.numitems > 1)
{ {
M_SetupNextMenu (&EpiDef); M_SetupNextMenu (&EpiDef);
} }
else if (!EpisodeNoSkill[0]) else if (!EpisodeNoSkill[0])
{ {
M_SetupNextMenu (&HexenSkillMenu); M_SetupNextMenu (&HexenSkillMenu);
} }
else else
{ {
M_ChooseSkill(2); M_ChooseSkill(2);
} }
} }
void M_Options (int choice) void M_Options (int choice)

View file

@ -4294,7 +4294,14 @@ int DLevelScript::RunScript ()
// Like Thing_Projectile(Gravity) specials, but you can give the // Like Thing_Projectile(Gravity) specials, but you can give the
// projectile a TID. // projectile a TID.
// Thing_Projectile2 (tid, type, angle, speed, vspeed, gravity, newtid); // Thing_Projectile2 (tid, type, angle, speed, vspeed, gravity, newtid);
P_Thing_Projectile (STACK(7), STACK(6), ((angle_t)(STACK(5)<<24)), P_Thing_Projectile (STACK(7), STACK(6), NULL, ((angle_t)(STACK(5)<<24)),
STACK(4)<<(FRACBITS-3), STACK(3)<<(FRACBITS-3), 0, NULL, STACK(2), STACK(1), false);
sp -= 7;
break;
case PCD_SPAWNPROJECTILE:
// Same, but takes an actor name instead of a spawn ID.
P_Thing_Projectile (STACK(7), 0, FBehavior::StaticLookupString (STACK(6)), ((angle_t)(STACK(5)<<24)),
STACK(4)<<(FRACBITS-3), STACK(3)<<(FRACBITS-3), 0, NULL, STACK(2), STACK(1), false); STACK(4)<<(FRACBITS-3), STACK(3)<<(FRACBITS-3), 0, NULL, STACK(2), STACK(1), false);
sp -= 7; sp -= 7;
break; break;

View file

@ -478,6 +478,10 @@ public:
PCD_PRINTWORLDCHARARRAY, PCD_PRINTWORLDCHARARRAY,
PCD_PRINTGLOBALCHARARRAY, // [JB] end of new p-codes PCD_PRINTGLOBALCHARARRAY, // [JB] end of new p-codes
PCD_SETACTORANGLE, // [GRB] PCD_SETACTORANGLE, // [GRB]
PCD_GRABINPUT, // Unused but acc defines them
PCD_SETMOUSEPOINTER, // "
PCD_MOVEMOUSEPOINTER, // "
PCD_SPAWNPROJECTILE,
PCODE_COMMAND_COUNT PCODE_COMMAND_COUNT
}; };

View file

@ -84,6 +84,7 @@ static FStrifeDialogueNode *CurNode, *PrevNode;
static brokenlines_t *DialogueLines; static brokenlines_t *DialogueLines;
static AActor *ConversationNPC, *ConversationPC; static AActor *ConversationNPC, *ConversationPC;
static angle_t ConversationNPCAngle; static angle_t ConversationNPCAngle;
static bool ConversationFaceTalker;
#define NUM_RANDOM_LINES 10 #define NUM_RANDOM_LINES 10
#define NUM_RANDOM_GOODBYES 3 #define NUM_RANDOM_GOODBYES 3
@ -601,7 +602,7 @@ CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE)
// //
//============================================================================ //============================================================================
void P_StartConversation (AActor *npc, AActor *pc) void P_StartConversation (AActor *npc, AActor *pc, bool facetalker)
{ {
FStrifeDialogueReply *reply; FStrifeDialogueReply *reply;
menuitem_t item; menuitem_t item;
@ -629,9 +630,13 @@ void P_StartConversation (AActor *npc, AActor *pc)
{ {
npc->target = pc; npc->target = pc;
} }
ConversationFaceTalker = facetalker;
ConversationNPCAngle = npc->angle; ConversationNPCAngle = npc->angle;
A_FaceTarget (npc); if (facetalker)
pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y); {
A_FaceTarget (npc);
pc->angle = R_PointToAngle2 (pc->x, pc->y, npc->x, npc->y);
}
// Check if we should jump to another node // Check if we should jump to another node
while (CurNode->ItemCheck[0] != NULL) while (CurNode->ItemCheck[0] != NULL)
@ -742,7 +747,7 @@ void P_ResumeConversation ()
{ {
if (ConversationPC != NULL && ConversationNPC != NULL) if (ConversationPC != NULL && ConversationNPC != NULL)
{ {
P_StartConversation (ConversationNPC, ConversationPC); P_StartConversation (ConversationNPC, ConversationPC, ConversationFaceTalker);
} }
} }
@ -962,7 +967,7 @@ static void PickConversationReply ()
ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1]; ConversationNPC->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
if (gameaction != ga_slideshow) if (gameaction != ga_slideshow)
{ {
P_StartConversation (ConversationNPC, players[consoleplayer].mo); P_StartConversation (ConversationNPC, players[consoleplayer].mo, ConversationFaceTalker);
return; return;
} }
else else

View file

@ -59,7 +59,7 @@ extern const PClass *StrifeTypes[999];
void P_LoadStrifeConversations (const char *mapname); void P_LoadStrifeConversations (const char *mapname);
void P_FreeStrifeConversations (); void P_FreeStrifeConversations ();
void P_StartConversation (AActor *npc, AActor *pc); void P_StartConversation (AActor *npc, AActor *pc, bool facetalker);
void P_ResumeConversation (); void P_ResumeConversation ();
#endif #endif

View file

@ -302,7 +302,7 @@ DDoor::DDoor (sector_t *sec, EVlDoor type, fixed_t speed, int delay, int lightTa
vertex_t *spot; vertex_t *spot;
fixed_t height; fixed_t height;
if (compatflags & COMPATF_NODOORLIGHT) if (i_compatflags & COMPATF_NODOORLIGHT)
{ {
m_LightTag = 0; m_LightTag = 0;
} }
@ -779,7 +779,7 @@ bool EV_SlidingDoor (line_t *line, AActor *actor, int tag, int speed, int delay)
} }
while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0)
{ {
sec = &sectors[secnum]; sec = &sectors[secnum];
if (sec->ceilingdata != NULL) if (sec->ceilingdata != NULL)
{ {

View file

@ -775,7 +775,7 @@ void P_NewChaseDir(AActor * actor)
if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight && if (actor->floorz - actor->dropoffz > actor->MaxDropOffHeight &&
actor->z <= actor->floorz && !(actor->flags & MF_DROPOFF) && actor->z <= actor->floorz && !(actor->flags & MF_DROPOFF) &&
!(actor->flags2 & MF2_ONMOBJ) && !(actor->flags2 & MF2_ONMOBJ) &&
!(actor->flags & MF_FLOAT) && !(compatflags & COMPATF_DROPOFF)) !(actor->flags & MF_FLOAT) && !(i_compatflags & COMPATF_DROPOFF))
{ {
a.thing = actor; a.thing = actor;
a.deltax = a.deltay = 0; a.deltax = a.deltay = 0;
@ -1537,7 +1537,7 @@ void A_Look (AActor *actor)
} }
else else
{ {
targ = (compatflags & COMPATF_SOUNDTARGET)? actor->Sector->SoundTarget : actor->LastHeard; targ = (i_compatflags & COMPATF_SOUNDTARGET)? actor->Sector->SoundTarget : actor->LastHeard;
// [RH] If the soundtarget is dead, don't chase it // [RH] If the soundtarget is dead, don't chase it
if (targ != NULL && targ->health <= 0) if (targ != NULL && targ->health <= 0)
@ -2195,7 +2195,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int special, int cha
fixed_t spawnz; fixed_t spawnz;
spawnz = source->z; spawnz = source->z;
if (!(compatflags & COMPATF_NOTOSSDROPS)) if (!(i_compatflags & COMPATF_NOTOSSDROPS))
{ {
int style = sv_dropstyle; int style = sv_dropstyle;
if (style==0) style= (gameinfo.gametype == GAME_Strife)? 2:1; if (style==0) style= (gameinfo.gametype == GAME_Strife)? 2:1;
@ -2235,7 +2235,7 @@ AInventory *P_DropItem (AActor *source, const PClass *type, int special, int cha
return NULL; return NULL;
} }
} }
if (!(compatflags & COMPATF_NOTOSSDROPS)) if (!(i_compatflags & COMPATF_NOTOSSDROPS))
{ {
P_TossItem (mo); P_TossItem (mo);
} }

View file

@ -698,7 +698,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
persteptime = FixedDiv (stairsize, speed) >> FRACBITS; persteptime = FixedDiv (stairsize, speed) >> FRACBITS;
int (* FindSector) (int tag, int start) = int (* FindSector) (int tag, int start) =
(compatflags & COMPATF_STAIRINDEX)? P_FindSectorFromTagLinear : P_FindSectorFromTag; (i_compatflags & COMPATF_STAIRINDEX)? P_FindSectorFromTagLinear : P_FindSectorFromTag;
// check if a manual trigger, if so do just the sector on the backside // check if a manual trigger, if so do just the sector on the backside
if (tag == 0) if (tag == 0)
@ -862,7 +862,7 @@ manual_stair:
{ {
return rtn; return rtn;
} }
if (!(compatflags & COMPATF_STAIRINDEX)) if (!(i_compatflags & COMPATF_STAIRINDEX))
{ {
secnum = osecnum; //jff 3/4/98 restore loop index secnum = osecnum; //jff 3/4/98 restore loop index
} }

View file

@ -50,6 +50,7 @@
#include "a_keys.h" #include "a_keys.h"
#include "gi.h" #include "gi.h"
#include "m_random.h" #include "m_random.h"
#include "p_conversation.h"
#include "a_strifeglobal.h" #include "a_strifeglobal.h"
#define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \ #define FUNC(a) static int a (line_t *ln, AActor *it, bool backSide, \
@ -1107,14 +1108,14 @@ FUNC(LS_Thing_Damage)
FUNC(LS_Thing_Projectile) FUNC(LS_Thing_Projectile)
// Thing_Projectile (tid, type, angle, speed, vspeed) // Thing_Projectile (tid, type, angle, speed, vspeed)
{ {
return P_Thing_Projectile (arg0, arg1, BYTEANGLE(arg2), arg3<<(FRACBITS-3), return P_Thing_Projectile (arg0, arg1, NULL, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
arg4<<(FRACBITS-3), 0, NULL, 0, 0, false); arg4<<(FRACBITS-3), 0, NULL, 0, 0, false);
} }
FUNC(LS_Thing_ProjectileGravity) FUNC(LS_Thing_ProjectileGravity)
// Thing_ProjectileGravity (tid, type, angle, speed, vspeed) // Thing_ProjectileGravity (tid, type, angle, speed, vspeed)
{ {
return P_Thing_Projectile (arg0, arg1, BYTEANGLE(arg2), arg3<<(FRACBITS-3), return P_Thing_Projectile (arg0, arg1, NULL, BYTEANGLE(arg2), arg3<<(FRACBITS-3),
arg4<<(FRACBITS-3), 0, NULL, 1, 0, false); arg4<<(FRACBITS-3), 0, NULL, 1, 0, false);
} }
@ -1284,13 +1285,13 @@ FUNC(LS_Thing_Hate)
FUNC(LS_Thing_ProjectileAimed) FUNC(LS_Thing_ProjectileAimed)
// Thing_ProjectileAimed (tid, type, speed, target, newtid) // Thing_ProjectileAimed (tid, type, speed, target, newtid)
{ {
return P_Thing_Projectile (arg0, arg1, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, false); return P_Thing_Projectile (arg0, arg1, NULL, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, false);
} }
FUNC(LS_Thing_ProjectileIntercept) FUNC(LS_Thing_ProjectileIntercept)
// Thing_ProjectileIntercept (tid, type, speed, target, newtid) // Thing_ProjectileIntercept (tid, type, speed, target, newtid)
{ {
return P_Thing_Projectile (arg0, arg1, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, true); return P_Thing_Projectile (arg0, arg1, NULL, 0, arg2<<(FRACBITS-3), 0, arg3, it, 0, arg4, true);
} }
// [BC] added newtid for next two // [BC] added newtid for next two
@ -1312,6 +1313,81 @@ FUNC(LS_Thing_SpawnFacing)
return P_Thing_Spawn (arg0, arg1, ANGLE_MAX, arg2 ? false : true, arg3); return P_Thing_Spawn (arg0, arg1, ANGLE_MAX, arg2 ? false : true, arg3);
} }
static bool DoThingRaise(AActor * thing)
{
if (thing == NULL)
return false; // not valid
if (!(thing->flags & MF_CORPSE) )
return true; // not a corpse
if (thing->tics != -1)
return true; // not lying still yet
if (thing->RaiseState == NULL)
return true; // monster doesn't have a raise state
AActor *info = thing->GetDefault ();
thing->momx = thing->momy = 0;
// [RH] Check against real height and radius
fixed_t oldheight = thing->height;
fixed_t oldradius = thing->radius;
int oldflags = thing->flags;
thing->flags |= MF_SOLID;
thing->height = info->height; // [RH] Use real height
thing->radius = info->radius; // [RH] Use real radius
if (!P_CheckPosition (thing, thing->x, thing->y))
{
thing->flags = oldflags;
thing->radius = oldradius;
thing->height = oldheight;
return false;
}
S_Sound (thing, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
thing->SetState (info->RaiseState);
thing->flags = info->flags;
thing->flags2 = info->flags2;
thing->flags3 = info->flags3;
thing->flags4 = info->flags4;
thing->health = info->health;
thing->target = NULL;
thing->lastenemy = NULL;
// [RH] If it's a monster, it gets to count as another kill
if (thing->CountsAsKill())
{
level.total_monsters++;
}
return true;
}
FUNC(LS_Thing_Raise)
// Thing_Raise(tid)
{
AActor * target;
bool ok = false;
if (arg0==0)
{
ok = DoThingRaise (it);
}
else
{
TActorIterator<AActor> iterator (arg0);
while ( (target = iterator.Next ()) )
{
ok |= DoThingRaise(target);
}
}
return ok;
}
FUNC(LS_Thing_SetGoal) FUNC(LS_Thing_SetGoal)
// Thing_SetGoal (tid, goal, delay, chasegoal) // Thing_SetGoal (tid, goal, delay, chasegoal)
{ {
@ -2555,6 +2631,40 @@ FUNC(LS_GlassBreak)
return false; return false;
} }
FUNC(LS_StartConversation)
// StartConversation (tid, facetalker)
{
FActorIterator iterator (arg0);
AActor *target = iterator.Next();
// Only living players are allowed to start conversations
if (it == NULL || it->player == NULL || it->player->mo != it || it->health<=0)
{
return false;
}
// Dead things can't talk.
if (target->health <= 0)
{
return false;
}
// Fighting things don't talk either.
if (target->flags4 & MF4_INCOMBAT)
{
return false;
}
if (target->Conversation != NULL)
{
// Give the NPC a chance to play a brief animation
target->ConversationAnimation (0);
P_StartConversation (target, it, !!arg1);
return true;
}
return false;
}
lnSpecFunc LineSpecials[256] = lnSpecFunc LineSpecials[256] =
{ {
LS_NOP, LS_NOP,
@ -2574,8 +2684,8 @@ lnSpecFunc LineSpecials[256] =
LS_Door_Animated, LS_Door_Animated,
LS_Autosave, LS_Autosave,
LS_NOP, // Transfer_WallLight LS_NOP, // Transfer_WallLight
LS_NOP, // 17 LS_Thing_Raise,
LS_NOP, // 18 LS_StartConversation,
LS_NOP, // 19 LS_NOP, // 19
LS_Floor_LowerByValue, LS_Floor_LowerByValue,
LS_Floor_LowerToLowest, LS_Floor_LowerToLowest,

View file

@ -57,6 +57,8 @@ typedef enum {
Autosave = 15, // [RH] Save the game *now* Autosave = 15, // [RH] Save the game *now*
Transfer_WallLight = 16, Transfer_WallLight = 16,
Thing_Raise = 17,
StartConversation = 18,
Floor_LowerByValue = 20, Floor_LowerByValue = 20,
Floor_LowerToLowest = 21, Floor_LowerToLowest = 21,

View file

@ -126,7 +126,7 @@ void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz);
extern const PClass *SpawnableThings[MAX_SPAWNABLES]; extern const PClass *SpawnableThings[MAX_SPAWNABLES];
bool P_Thing_Spawn (int tid, int type, angle_t angle, bool fog, int newtid); bool P_Thing_Spawn (int tid, int type, angle_t angle, bool fog, int newtid);
bool P_Thing_Projectile (int tid, int type, angle_t angle, bool P_Thing_Projectile (int tid, int type, const char * type_name, angle_t angle,
fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid,
bool leadTarget); bool leadTarget);
bool P_Thing_Move (int tid, int mapspot, bool fog); bool P_Thing_Move (int tid, int mapspot, bool fog);

View file

@ -834,7 +834,7 @@ BOOL PIT_CheckThing (AActor *thing)
} }
BlockingMobj = thing; BlockingMobj = thing;
topz = thing->z + thing->height; topz = thing->z + thing->height;
if (!(compatflags & COMPATF_NO_PASSMOBJ) && !(tmthing->flags & (MF_FLOAT|MF_MISSILE|MF_SKULLFLY|MF_NOGRAVITY)) && if (!(i_compatflags & COMPATF_NO_PASSMOBJ) && !(tmthing->flags & (MF_FLOAT|MF_MISSILE|MF_SKULLFLY|MF_NOGRAVITY)) &&
(thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE)) (thing->flags & MF_SOLID) && (thing->flags4 & MF4_ACTLIKEBRIDGE))
{ {
// [RH] Let monsters walk on actors as well as floors // [RH] Let monsters walk on actors as well as floors
@ -856,7 +856,7 @@ BOOL PIT_CheckThing (AActor *thing)
} }
// [RH] If the other thing is a bridge, then treat the moving thing as if it had MF2_PASSMOBJ, so // [RH] If the other thing is a bridge, then treat the moving thing as if it had MF2_PASSMOBJ, so
// you can use a scrolling floor to move scenery items underneath a bridge. // you can use a scrolling floor to move scenery items underneath a bridge.
if ((tmthing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(compatflags & COMPATF_NO_PASSMOBJ)) if ((tmthing->flags2 & MF2_PASSMOBJ || thing->flags4 & MF4_ACTLIKEBRIDGE) && !(i_compatflags & COMPATF_NO_PASSMOBJ))
{ // check if a mobj passed over/under another object { // check if a mobj passed over/under another object
if (tmthing->flags3 & thing->flags3 & MF3_DONTOVERLAP) if (tmthing->flags3 & thing->flags3 & MF3_DONTOVERLAP)
{ // Some things prefer not to overlap each other, if possible { // Some things prefer not to overlap each other, if possible
@ -1329,7 +1329,7 @@ BOOL P_CheckPosition (AActor *thing, fixed_t x, fixed_t y)
// other things in the blocks and see if we hit something that is // other things in the blocks and see if we hit something that is
// definitely blocking. Otherwise, we need to check the lines, or we // definitely blocking. Otherwise, we need to check the lines, or we
// could end up stuck inside a wall. // could end up stuck inside a wall.
if (BlockingMobj == NULL || (compatflags & COMPATF_NO_PASSMOBJ)) if (BlockingMobj == NULL || (i_compatflags & COMPATF_NO_PASSMOBJ))
{ // Thing slammed into something; don't let it move now. { // Thing slammed into something; don't let it move now.
thing->height = realheight; thing->height = realheight;
return false; return false;
@ -1593,7 +1593,7 @@ BOOL P_TryMove (AActor *thing, fixed_t x, fixed_t y,
goto pushline; goto pushline;
} }
} }
if (!(tmthing->flags2 & MF2_PASSMOBJ) || (compatflags & COMPATF_NO_PASSMOBJ)) if (!(tmthing->flags2 & MF2_PASSMOBJ) || (i_compatflags & COMPATF_NO_PASSMOBJ))
{ {
thing->z = oldz; thing->z = oldz;
return false; return false;
@ -3159,7 +3159,7 @@ BOOL PTR_UseTraverse (intercept_t *in)
{ {
// Give the NPC a chance to play a brief animation // Give the NPC a chance to play a brief animation
in->d.thing->ConversationAnimation (0); in->d.thing->ConversationAnimation (0);
P_StartConversation (in->d.thing, usething); P_StartConversation (in->d.thing, usething, true);
return false; return false;
} }
return true; return true;
@ -3189,7 +3189,7 @@ blocked:
trace.y + FixedMul (trace.dy, in->frac)); trace.y + FixedMul (trace.dy, in->frac));
} }
if (openrange <= 0 || if (openrange <= 0 ||
(in->d.line->special != 0 && (compatflags & COMPATF_USEBLOCKING))) (in->d.line->special != 0 && (i_compatflags & COMPATF_USEBLOCKING)))
{ {
// [RH] Give sector a chance to intercept the use // [RH] Give sector a chance to intercept the use
@ -3233,7 +3233,7 @@ blocked:
//[RH] And now I've changed it again. If the line is of type //[RH] And now I've changed it again. If the line is of type
// SPAC_USE, then it eats the use. Everything else passes // SPAC_USE, then it eats the use. Everything else passes
// it through, including SPAC_USETHROUGH. // it through, including SPAC_USETHROUGH.
if (compatflags & COMPATF_USEBLOCKING) if (i_compatflags & COMPATF_USEBLOCKING)
{ {
return GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH; return GET_SPAC(in->d.line->flags) == SPAC_USETHROUGH;
} }
@ -3508,10 +3508,8 @@ BOOL PIT_RadiusAttack (AActor *thing)
{ {
points = points * splashfactor; points = points * splashfactor;
} }
if (thing->player && gameinfo.gametype == GAME_Hexen) points *= thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT)/(float)FRACUNIT;
{
points = points * 0.25f;
}
if (points > 0.f && P_CheckSight (thing, bombspot, 1)) if (points > 0.f && P_CheckSight (thing, bombspot, 1))
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
float momz; float momz;
@ -3569,12 +3567,13 @@ BOOL PIT_RadiusAttack (AActor *thing)
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
int damage = Scale (bombdamage, bombdistance-dist, bombdistance); int damage = Scale (bombdamage, bombdistance-dist, bombdistance);
damage = (int)((float)damage * splashfactor); damage = (int)((float)damage * splashfactor);
if (thing->player && gameinfo.gametype == GAME_Hexen)
damage = Scale(damage, thing->GetClass()->Meta.GetMetaFixed(AMETA_RDFactor, FRACUNIT), FRACUNIT);
if (damage > 0)
{ {
damage >>= 2; P_DamageMobj (thing, bombspot, bombsource, damage, bombmod);
P_TraceBleed (damage, thing, bombspot);
} }
P_DamageMobj (thing, bombspot, bombsource, damage, bombmod);
P_TraceBleed (damage, thing, bombspot);
} }
} }
return true; return true;

View file

@ -1313,7 +1313,7 @@ void P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
// that large thrusts can't propel an actor through a wall, because wall // that large thrusts can't propel an actor through a wall, because wall
// running depends on the player's original movement continuing even after // running depends on the player's original movement continuing even after
// it gets blocked. // it gets blocked.
if (mo->player != NULL && (compatflags & COMPATF_WALLRUN) || (mo->waterlevel >= 1) || if (mo->player != NULL && (i_compatflags & COMPATF_WALLRUN) || (mo->waterlevel >= 1) ||
(mo->player != NULL && mo->player->crouchfactor < FRACUNIT*3/4)) (mo->player != NULL && mo->player->crouchfactor < FRACUNIT*3/4))
{ {
// preserve the direction instead of clamping x and y independently. // preserve the direction instead of clamping x and y independently.
@ -1456,7 +1456,7 @@ void P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
{ {
mo->momz = WATER_JUMP_SPEED; mo->momz = WATER_JUMP_SPEED;
} }
if (player && (compatflags & COMPATF_WALLRUN)) if (player && (i_compatflags & COMPATF_WALLRUN))
{ {
// [RH] Here is the key to wall running: The move is clipped using its full speed. // [RH] Here is the key to wall running: The move is clipped using its full speed.
// If the move is done a second time (because it was too fast for one move), it // If the move is done a second time (because it was too fast for one move), it
@ -1474,7 +1474,7 @@ void P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly)
} }
else else
{ {
if (!player || !(compatflags & COMPATF_WALLRUN)) if (!player || !(i_compatflags & COMPATF_WALLRUN))
{ {
xmove = mo->momx; xmove = mo->momx;
ymove = mo->momy; ymove = mo->momy;
@ -2595,7 +2595,7 @@ void AActor::Tick ()
scrolltype <= Scroll_SouthWest_Fast) scrolltype <= Scroll_SouthWest_Fast)
{ // Hexen scroll special { // Hexen scroll special
scrolltype -= Scroll_North_Slow; scrolltype -= Scroll_North_Slow;
if (compatflags&COMPATF_RAVENSCROLL) if (i_compatflags&COMPATF_RAVENSCROLL)
{ {
angle_t fineangle = HexenScrollDirs[scrolltype / 3] * 32; angle_t fineangle = HexenScrollDirs[scrolltype / 3] * 32;
fixed_t carryspeed = DivScale32 (HexenSpeedMuls[scrolltype % 3], 32*CARRYFACTOR); fixed_t carryspeed = DivScale32 (HexenSpeedMuls[scrolltype % 3], 32*CARRYFACTOR);
@ -2615,7 +2615,7 @@ void AActor::Tick ()
scrolltype -= Carry_East5; scrolltype -= Carry_East5;
byte dir = HereticScrollDirs[scrolltype / 5]; byte dir = HereticScrollDirs[scrolltype / 5];
fixed_t carryspeed = DivScale32 (HereticSpeedMuls[scrolltype % 5], 32*CARRYFACTOR); fixed_t carryspeed = DivScale32 (HereticSpeedMuls[scrolltype % 5], 32*CARRYFACTOR);
if (scrolltype<=Carry_East35 && !(compatflags&COMPATF_RAVENSCROLL)) if (scrolltype<=Carry_East35 && !(i_compatflags&COMPATF_RAVENSCROLL))
{ {
// Use speeds that actually match the scrolling textures! // Use speeds that actually match the scrolling textures!
carryspeed = (1 << ((scrolltype%5) + FRACBITS-1)); carryspeed = (1 << ((scrolltype%5) + FRACBITS-1));
@ -2625,7 +2625,7 @@ void AActor::Tick ()
} }
else if (scrolltype == dScroll_EastLavaDamage) else if (scrolltype == dScroll_EastLavaDamage)
{ // Special Heretic scroll special { // Special Heretic scroll special
if (compatflags&COMPATF_RAVENSCROLL) if (i_compatflags&COMPATF_RAVENSCROLL)
{ {
scrollx += DivScale32 (28, 32*CARRYFACTOR); scrollx += DivScale32 (28, 32*CARRYFACTOR);
} }
@ -2762,7 +2762,7 @@ void AActor::Tick ()
(z - FloatBobOffsets[(FloatBobPhase + level.maptime) & 63] != floorz) (z - FloatBobOffsets[(FloatBobPhase + level.maptime) & 63] != floorz)
))) )))
{ // Handle Z momentum and gravity { // Handle Z momentum and gravity
if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(compatflags & COMPATF_NO_PASSMOBJ)) if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(i_compatflags & COMPATF_NO_PASSMOBJ))
{ {
if (!(onmo = P_CheckOnmobj (this))) if (!(onmo = P_CheckOnmobj (this)))
{ {

View file

@ -451,7 +451,7 @@ fixed_t sector_t::FindHighestCeilingSurrounding (vertex_t **v) const
static inline void CheckShortestTex (int texnum, fixed_t &minsize) static inline void CheckShortestTex (int texnum, fixed_t &minsize)
{ {
if (texnum > 0 || (texnum == 0 && (compatflags & COMPATF_SHORTTEX))) if (texnum > 0 || (texnum == 0 && (i_compatflags & COMPATF_SHORTTEX)))
{ {
FTexture *tex = TexMan[texnum]; FTexture *tex = TexMan[texnum];
int yscale = tex->ScaleY ? tex->ScaleY : 8; int yscale = tex->ScaleY ? tex->ScaleY : 8;

View file

@ -150,7 +150,7 @@ bool P_Thing_Move (int tid, int mapspot, bool fog)
return false; return false;
} }
bool P_Thing_Projectile (int tid, int type, angle_t angle, bool P_Thing_Projectile (int tid, int type, const char * type_name, angle_t angle,
fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid,
bool leadTarget) bool leadTarget)
{ {
@ -161,11 +161,19 @@ bool P_Thing_Projectile (int tid, int type, angle_t angle,
float fspeed = float(speed); float fspeed = float(speed);
int defflags3; int defflags3;
if (type >= MAX_SPAWNABLES) if (type_name == NULL)
return false; {
if (type >= MAX_SPAWNABLES)
return false;
if ((kind = SpawnableThings[type]) == NULL) if ((kind = SpawnableThings[type]) == NULL)
return false; return false;
}
else
{
if ((kind = PClass::FindClass(type_name)) == NULL)
return false;
}
defflags3 = GetDefaultByType (kind)->flags3; defflags3 = GetDefaultByType (kind)->flags3;
if ((defflags3 & MF3_ISMONSTER) && (dmflags & DF_NO_MONSTERS)) if ((defflags3 & MF3_ISMONSTER) && (dmflags & DF_NO_MONSTERS))

View file

@ -171,7 +171,7 @@ static BOOL PTR_TraceIterator (intercept_t *in)
// For backwards compatibility: Ignore lines with the same sector on both sides. // For backwards compatibility: Ignore lines with the same sector on both sides.
// This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 needs it. // This is the way Doom.exe did it and some WADs (e.g. Alien Vendetta MAP15 needs it.
if (compatflags & COMPATF_TRACE) if (i_compatflags & COMPATF_TRACE)
{ {
return true; return true;
} }

View file

@ -624,13 +624,13 @@ static void S_StartSound (fixed_t *pt, AActor *mover, int channel,
{ {
pt = NULL; pt = NULL;
} }
if (compatflags & COMPATF_MAGICSILENCE) if (i_compatflags & COMPATF_MAGICSILENCE)
{ // For people who just can't play without a silent BFG. { // For people who just can't play without a silent BFG.
channel = 1; channel = 1;
} }
else else
{ {
if ((channel & CHAN_MAYBE_LOCAL) && (compatflags & COMPATF_SILENTPICKUP)) if ((channel & CHAN_MAYBE_LOCAL) && (i_compatflags & COMPATF_SILENTPICKUP))
{ {
if (mover != 0 && mover != players[consoleplayer].camera) if (mover != 0 && mover != players[consoleplayer].camera)
{ {
@ -1108,7 +1108,7 @@ void S_StopSound (fixed_t *pt, int channel)
{ {
if (Channel[i].sfxinfo && if (Channel[i].sfxinfo &&
((pt == NULL && Channel[i].pt == &Channel[i].x) || Channel[i].pt == pt) && ((pt == NULL && Channel[i].pt == &Channel[i].x) || Channel[i].pt == pt) &&
((compatflags & COMPATF_MAGICSILENCE) || Channel[i].entchannel == channel)) ((i_compatflags & COMPATF_MAGICSILENCE) || Channel[i].entchannel == channel))
{ {
S_StopChannel (i); S_StopChannel (i);
} }
@ -1208,7 +1208,7 @@ bool S_IsActorPlayingSomething (AActor *actor, int channel)
{ {
int i; int i;
if (compatflags & COMPATF_MAGICSILENCE) if (i_compatflags & COMPATF_MAGICSILENCE)
{ {
channel = 0; channel = 0;
} }

View file

@ -2954,6 +2954,15 @@ static void ActorFastSpeed (AActor *defaults, Baggage &bag)
bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, fixed_t(sc_Float*FRACUNIT)); bag.Info->Class->Meta.SetMetaFixed (AMETA_FastSpeed, fixed_t(sc_Float*FRACUNIT));
} }
//==========================================================================
//
//==========================================================================
static void ActorRadiusDamageFactor (AActor *defaults, Baggage &bag)
{
SC_MustGetFloat();
bag.Info->Class->Meta.SetMetaFixed (AMETA_RDFactor, fixed_t(sc_Float*FRACUNIT));
}
//========================================================================== //==========================================================================
// //
//========================================================================== //==========================================================================
@ -3572,6 +3581,7 @@ static const ActorProps props[] =
{ "projectile", ActorProjectile, RUNTIME_CLASS(AActor) }, { "projectile", ActorProjectile, RUNTIME_CLASS(AActor) },
{ "puzzleitem.number", (apf)PuzzleitemNumber, RUNTIME_CLASS(APuzzleItem) }, { "puzzleitem.number", (apf)PuzzleitemNumber, RUNTIME_CLASS(APuzzleItem) },
{ "radius", ActorRadius, RUNTIME_CLASS(AActor) }, { "radius", ActorRadius, RUNTIME_CLASS(AActor) },
{ "radiusdamagefactor", ActorRadiusDamageFactor, RUNTIME_CLASS(AActor) },
{ "raise", ActorRaiseState, RUNTIME_CLASS(AActor) }, { "raise", ActorRaiseState, RUNTIME_CLASS(AActor) },
{ "reactiontime", ActorReactionTime, RUNTIME_CLASS(AActor) }, { "reactiontime", ActorReactionTime, RUNTIME_CLASS(AActor) },
{ "renderstyle", ActorRenderStyle, RUNTIME_CLASS(AActor) }, { "renderstyle", ActorRenderStyle, RUNTIME_CLASS(AActor) },