This commit is contained in:
Christoph Oelckers 2014-11-08 09:40:17 +01:00
commit 48fbab819b
18 changed files with 212 additions and 49 deletions

View file

@ -345,6 +345,7 @@ enum
MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat. MF7_BUDDHA = 0x00000040, // Behaves just like the buddha cheat.
MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode. MF7_FOILBUDDHA = 0x00000080, // Similar to FOILINVUL, foils buddha mode.
MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag. MF7_DONTTHRUST = 0x00000100, // Thrusting functions do not take, and do not give thrust (damage) to actors with this flag.
MF7_ALLOWPAIN = 0x00000200, // Invulnerable or immune (via damagefactors) actors can still react to taking damage even if they don't.
// --- mobj.renderflags --- // --- mobj.renderflags ---

View file

@ -61,6 +61,7 @@ typedef enum
ga_loadlevel, ga_loadlevel,
ga_newgame, ga_newgame,
ga_newgame2, ga_newgame2,
ga_recordgame,
ga_loadgame, ga_loadgame,
ga_loadgamehidecon, ga_loadgamehidecon,
ga_loadgameplaydemo, ga_loadgameplaydemo,

View file

@ -1338,6 +1338,7 @@ CCMD (endgame)
{ {
gameaction = ga_fullconsole; gameaction = ga_fullconsole;
demosequence = -1; demosequence = -1;
G_CheckDemoStatus();
} }
} }

View file

@ -136,6 +136,8 @@ extern int consoleplayer;
// Disable save/end game? // Disable save/end game?
extern bool usergame; extern bool usergame;
extern FString newdemoname;
extern FString newdemomap;
extern bool demoplayback; extern bool demoplayback;
extern bool demorecording; extern bool demorecording;
extern int demover; extern int demover;

View file

@ -609,9 +609,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BFGSpray)
damage = defdamage; damage = defdamage;
} }
int dmgFlagPass = 0;
dmgFlagPass += (spray != NULL && (spray->flags3 & MF3_FOILINVUL)) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul wasn't working.
dmgFlagPass += (spray != NULL && (spray->flags7 & MF7_FOILBUDDHA)) ? DMG_FOILBUDDHA : 0;
thingToHit = linetarget; thingToHit = linetarget;
int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash), int newdam = P_DamageMobj (thingToHit, self->target, self->target, damage, spray != NULL? FName(spray->DamageType) : FName(NAME_BFGSplash),
spray != NULL && (spray->flags3 & MF3_FOILINVUL)? DMG_FOILINVUL : 0); dmgFlagPass);
P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target); P_TraceBleed (newdam > 0 ? newdam : damage, thingToHit, self->target);
} }
} }

View file

@ -162,6 +162,8 @@ int consoleplayer; // player taking events
int gametic; int gametic;
CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG); CVAR(Bool, demo_compress, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
FString newdemoname;
FString newdemomap;
FString demoname; FString demoname;
bool demorecording; bool demorecording;
bool demoplayback; bool demoplayback;
@ -1048,6 +1050,10 @@ void G_Ticker ()
case ga_loadlevel: case ga_loadlevel:
G_DoLoadLevel (-1, false); G_DoLoadLevel (-1, false);
break; break;
case ga_recordgame:
G_CheckDemoStatus();
G_RecordDemo(newdemoname);
G_BeginRecording(newdemomap);
case ga_newgame2: // Silence GCC (see above) case ga_newgame2: // Silence GCC (see above)
case ga_newgame: case ga_newgame:
G_DoNewGame (); G_DoNewGame ();
@ -2434,6 +2440,16 @@ void G_DeferedPlayDemo (const char *name)
CCMD (playdemo) CCMD (playdemo)
{ {
if (netgame)
{
Printf("End your current netgame first!");
return;
}
if (demorecording)
{
Printf("End your current demo first!");
return;
}
if (argv.argc() > 1) if (argv.argc() > 1)
{ {
G_DeferedPlayDemo (argv[1]); G_DeferedPlayDemo (argv[1]);

View file

@ -199,6 +199,46 @@ CCMD (map)
// //
//========================================================================== //==========================================================================
CCMD(recordmap)
{
if (netgame)
{
Printf("You cannot record a new game while in a netgame.");
return;
}
if (argv.argc() > 2)
{
try
{
if (!P_CheckMapData(argv[2]))
{
Printf("No map %s\n", argv[2]);
}
else
{
G_DeferedInitNew(argv[2]);
gameaction = ga_recordgame;
newdemoname = argv[1];
newdemomap = argv[2];
}
}
catch (CRecoverableError &error)
{
if (error.GetMessage())
Printf("%s", error.GetMessage());
}
}
else
{
Printf("Usage: recordmap <filename> <map name>\n");
}
}
//==========================================================================
//
//
//==========================================================================
CCMD (open) CCMD (open)
{ {
if (netgame) if (netgame)

View file

@ -7296,7 +7296,7 @@ scriptwait:
while (min <= max) while (min <= max)
{ {
int mid = (min + max) / 2; int mid = (min + max) / 2;
SDWORD caseval = pc[mid*2]; SDWORD caseval = LittleLong(pc[mid*2]);
if (caseval == STACK(1)) if (caseval == STACK(1))
{ {
pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1])); pc = activeBehavior->Ofs2PC (LittleLong(pc[mid*2+1]));

View file

@ -938,6 +938,10 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
FState * woundstate = NULL; FState * woundstate = NULL;
PainChanceList * pc = NULL; PainChanceList * pc = NULL;
bool justhit = false; bool justhit = false;
bool plrDontThrust = false;
bool invulpain = false;
int fakeDamage = 0;
int holdDamage = 0;
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE))) if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
{ // Shouldn't happen { // Shouldn't happen
@ -972,7 +976,14 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL))) if (inflictor == NULL || (!(inflictor->flags3 & MF3_FOILINVUL) && !(flags & DMG_FOILINVUL)))
{ {
return -1; if (target->flags7 & MF7_ALLOWPAIN)
{
invulpain = true; //This returns -1 later.
fakeDamage = damage;
goto fakepain; //The label is above the massive pile of checks.
}
else
return -1;
} }
} }
else else
@ -980,11 +991,21 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// Players are optionally excluded from getting thrust by damage. // Players are optionally excluded from getting thrust by damage.
if (static_cast<APlayerPawn *>(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL) if (static_cast<APlayerPawn *>(target)->PlayerFlags & PPF_NOTHRUSTWHENINVUL)
{ {
return -1; if (target->flags7 & MF7_ALLOWPAIN)
plrDontThrust = 1;
else
return -1;
} }
} }
} }
if ((target->flags7 & MF7_ALLOWPAIN) && (damage < TELEFRAG_DAMAGE))
{
//Intentionally do not jump to fakepain because the damage hasn't been dished out yet.
//Once it's dished out, THEN we can disregard damage factors affecting pain chances.
fakeDamage = damage;
}
if (inflictor != NULL) if (inflictor != NULL)
{ {
if (inflictor->flags5 & MF5_PIERCEARMOR) if (inflictor->flags5 & MF5_PIERCEARMOR)
@ -1010,6 +1031,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// Invulnerable, and won't wake up // Invulnerable, and won't wake up
return -1; return -1;
} }
player = target->player; player = target->player;
if (player && damage > 1 && damage < TELEFRAG_DAMAGE) if (player && damage > 1 && damage < TELEFRAG_DAMAGE)
{ {
@ -1032,10 +1054,13 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
return -1; return -1;
} }
} }
if (damage > 0)
damage = inflictor->DoSpecialDamage (target, damage, mod);
damage = inflictor->DoSpecialDamage (target, damage, mod);
if (damage == -1) if (damage == -1)
{ {
if (target->flags7 & MF7_ALLOWPAIN) //Hold off ending the function before we can deal the pain chances.
goto fakepain;
return -1; return -1;
} }
} }
@ -1058,12 +1083,15 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
int olddam = damage; int olddam = damage;
target->Inventory->ModifyDamage(olddam, mod, damage, true); target->Inventory->ModifyDamage(olddam, mod, damage, true);
if (olddam != damage && damage <= 0) if (((target->flags7 & MF7_ALLOWPAIN) && (fakeDamage <= 0)) || (olddam != damage && damage <= 0))
{ // Still allow FORCEPAIN { // Still allow FORCEPAIN and make sure we're still passing along fake damage to hit enemies for their pain states.
if (MustForcePain(target, inflictor)) if (MustForcePain(target, inflictor))
{ {
goto dopain; goto dopain;
} }
else if (target->flags7 & MF7_ALLOWPAIN)
goto fakepain;
return -1; return -1;
} }
} }
@ -1081,19 +1109,25 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
goto dopain; goto dopain;
} }
else if (target->flags7 & MF7_ALLOWPAIN)
goto fakepain;
return -1; return -1;
} }
} }
if (damage > 0)
damage = target->TakeSpecialDamage (inflictor, source, damage, mod); damage = target->TakeSpecialDamage (inflictor, source, damage, mod);
} }
if (damage == -1) if (damage == -1)
{ {
if (target->flags7 & MF7_ALLOWPAIN)
goto fakepain;
return -1; return -1;
} }
// Push the target unless the source's weapon's kickback is 0. // Push the target unless the source's weapon's kickback is 0.
// (i.e. Gauntlets/Chainsaw) // (i.e. Gauntlets/Chainsaw)
if (inflictor && inflictor != target // [RH] Not if hurting own self if (!(plrDontThrust) && inflictor && inflictor != target // [RH] Not if hurting own self
&& !(target->flags & MF_NOCLIP) && !(target->flags & MF_NOCLIP)
&& !(inflictor->flags2 & MF2_NODMGTHRUST) && !(inflictor->flags2 & MF2_NODMGTHRUST)
&& !(flags & DMG_THRUSTLESS) && !(flags & DMG_THRUSTLESS)
@ -1134,11 +1168,10 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust); fltthrust = clamp((damage * 0.125 * kickback) / target->Mass, 0., fltthrust);
} }
thrust = FLOAT2FIXED(fltthrust); thrust = FLOAT2FIXED(fltthrust);
// Don't apply ultra-small damage thrust.
// Don't apply ultra-small damage thrust if (thrust < FRACUNIT / 100)
if (thrust < FRACUNIT/100) thrust = 0; thrust = 0;
// make fall forwards sometimes // make fall forwards sometimes
if ((damage < 40) && (damage > target->health) if ((damage < 40) && (damage > target->health)
@ -1147,8 +1180,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// [RH] But only if not too fast and not flying // [RH] But only if not too fast and not flying
&& thrust < 10*FRACUNIT && thrust < 10*FRACUNIT
&& !(target->flags & MF_NOGRAVITY) && !(target->flags & MF_NOGRAVITY)
&& (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL)) && (inflictor == NULL || !(inflictor->flags5 & MF5_NOFORWARDFALL)))
)
{ {
ang += ANG180; ang += ANG180;
thrust *= 4; thrust *= 4;
@ -1215,6 +1247,12 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
(player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE)) (player->cheats & CF_GODMODE2) || (player->mo->flags5 & MF5_NODAMAGE))
//Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2. //Absolutely no hurting if NODAMAGE is involved. Same for GODMODE2.
{ // player is invulnerable, so don't hurt him { // player is invulnerable, so don't hurt him
if (player->mo->flags7 & MF7_ALLOWPAIN)
{
invulpain = true;
fakeDamage = damage;
goto fakepain;
}
return -1; return -1;
} }
@ -1232,7 +1270,8 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
{ {
// If MF6_FORCEPAIN is set, make the player enter the pain state. // If MF6_FORCEPAIN is set, make the player enter the pain state.
if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL && if (!(target->flags5 & MF5_NOPAIN) && inflictor != NULL &&
(inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS)) (inflictor->flags6 & MF6_FORCEPAIN) && !(inflictor->flags5 & MF5_PAINLESS) &&
(!(player->mo->flags2 & MF2_INVULNERABLE)))
{ {
goto dopain; goto dopain;
} }
@ -1263,7 +1302,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
// telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor, // telefrag him right? ;) (Unfortunately the damage is "absorbed" by armor,
// but telefragging should still do enough damage to kill the player) // but telefragging should still do enough damage to kill the player)
// Ignore players that are already dead. // Ignore players that are already dead.
if (((player->cheats & CF_BUDDHA2) || ((player->cheats & CF_BUDDHA) && damage < TELEFRAG_DAMAGE)) && player->playerstate != PST_DEAD) if (((player->cheats & CF_BUDDHA2) || ((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA) && damage < TELEFRAG_DAMAGE)) && player->playerstate != PST_DEAD)
{ {
// If this is a voodoo doll we need to handle the real player as well. // If this is a voodoo doll we need to handle the real player as well.
player->mo->health = target->health = player->health = 1; player->mo->health = target->health = player->health = 1;
@ -1296,7 +1335,10 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
damage = newdam; damage = newdam;
if (damage <= 0) if (damage <= 0)
{ {
return damage; if (target->flags7 & MF7_ALLOWPAIN)
goto fakepain;
else
return damage;
} }
} }
@ -1383,6 +1425,12 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
} }
} }
fakepain: //Needed so we can skip the rest of the above, but still obey the original rules.
if (target->flags7 & MF7_ALLOWPAIN && (fakeDamage != damage))
{
holdDamage = damage;
damage = fakeDamage;
}
if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) && if (!(target->flags5 & MF5_NOPAIN) && (inflictor == NULL || !(inflictor->flags5 & MF5_PAINLESS)) &&
(target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY)) (target->player != NULL || !G_SkillProperty(SKILLP_NoPain)) && !(target->flags & MF_SKULLFLY))
@ -1474,6 +1522,14 @@ dopain:
if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target))) if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target)))
target->flags |= MF_JUSTHIT; // fight back! target->flags |= MF_JUSTHIT; // fight back!
if (invulpain) //Note that this takes into account all the cheats a player has, in terms of invulnerability.
{
return -1; //NOW we return -1!
}
else if (target->flags7 & MF7_ALLOWPAIN)
{
return holdDamage;
}
return damage; return damage;
} }
@ -1688,7 +1744,7 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage,
target->health -= damage; target->health -= damage;
if (target->health <= 0) if (target->health <= 0)
{ // Death { // Death
if ((player->cheats & CF_BUDDHA && damage < TELEFRAG_DAMAGE) || (player->cheats & CF_BUDDHA2)) if ((((player->cheats & CF_BUDDHA) || (player->mo->flags7 & MF7_BUDDHA)) && damage < TELEFRAG_DAMAGE) || (player->cheats & CF_BUDDHA2))
{ // [SP] Save the player... { // [SP] Save the player...
player->health = target->health = 1; player->health = target->health = 1;
} }

View file

@ -4111,7 +4111,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
z = shootz + FixedMul(hitdist, vz); z = shootz + FixedMul(hitdist, vz);
if ((hitactor->flags & MF_NOBLOOD) || if ((hitactor->flags & MF_NOBLOOD) ||
(hitactor->flags2 & (MF2_DORMANT | MF2_INVULNERABLE))) (hitactor->flags2 & MF2_DORMANT || ((hitactor->flags2 & MF2_INVULNERABLE) && !(puffDefaults->flags3 & MF3_FOILINVUL))))
{ {
spawnpuff = (puffclass != NULL); spawnpuff = (puffclass != NULL);
} }
@ -4132,7 +4132,10 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
{ {
P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType);
} }
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, DMG_INFLICTOR_IS_PUFF); int dmgFlagPass = DMG_INFLICTOR_IS_PUFF;
dmgFlagPass += (puffDefaults->flags3 & MF3_FOILINVUL) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul check wasn't working.
dmgFlagPass += (puffDefaults->flags7 & MF7_FOILBUDDHA) ? DMG_FOILBUDDHA : 0;
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass);
if (bleed) if (bleed)
{ {
P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor); P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor);

View file

@ -1167,7 +1167,7 @@ bool AActor::Massacre ()
P_DamageMobj (this, NULL, NULL, TELEFRAG_DAMAGE, NAME_Massacre); P_DamageMobj (this, NULL, NULL, TELEFRAG_DAMAGE, NAME_Massacre);
} }
while (health != prevhealth && health > 0); //abort if the actor wasn't hurt. while (health != prevhealth && health > 0); //abort if the actor wasn't hurt.
return true; return health <= 0;
} }
return false; return false;
} }
@ -5986,7 +5986,7 @@ bool AActor::IsHostile (AActor *other)
int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype) int AActor::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{ {
if (target->player && target->player->mo == target && damage < 1000 && if (target->player && target->player->mo == target && damage < 1000 &&
(target->player->cheats & CF_GODMODE)) (target->player->cheats & CF_GODMODE || target->player->cheats & CF_GODMODE2))
{ {
return -1; return -1;
} }

View file

@ -714,6 +714,7 @@ void P_SectorDamage(int tag, int amount, FName type, const PClass *protectClass,
//============================================================================ //============================================================================
CVAR(Bool, showsecretsector, false, 0) CVAR(Bool, showsecretsector, false, 0)
CVAR(Bool, cl_showsecretmessage, true, CVAR_ARCHIVE)
void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum) void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornum)
{ {
@ -723,7 +724,7 @@ void P_GiveSecret(AActor *actor, bool printmessage, bool playsound, int sectornu
{ {
actor->player->secretcount++; actor->player->secretcount++;
} }
if (actor->CheckLocalView (consoleplayer)) if (cl_showsecretmessage && actor->CheckLocalView(consoleplayer))
{ {
if (printmessage) if (printmessage)
{ {

View file

@ -1541,11 +1541,11 @@ public:
double ulen = TVector3<double>(cp[0], cp[1], cp[2]).Length(); double ulen = TVector3<double>(cp[0], cp[1], cp[2]).Length();
// normalize the vector, it must have a length of 1 // normalize the vector, it must have a length of 1
sec->floorplane.a = FLOAT2FIXED(cp[0] / ulen); sec->ceilingplane.a = FLOAT2FIXED(cp[0] / ulen);
sec->floorplane.b = FLOAT2FIXED(cp[1] / ulen); sec->ceilingplane.b = FLOAT2FIXED(cp[1] / ulen);
sec->floorplane.c = FLOAT2FIXED(cp[2] / ulen); sec->ceilingplane.c = FLOAT2FIXED(cp[2] / ulen);
sec->floorplane.d = FLOAT2FIXED(cp[3] / ulen); sec->ceilingplane.d = FLOAT2FIXED(cp[3] / ulen);
sec->floorplane.ic = FLOAT2FIXED(ulen / cp[2]); sec->ceilingplane.ic = FLOAT2FIXED(ulen / cp[2]);
} }
if (lightcolor == -1 && fadecolor == -1 && desaturation == -1) if (lightcolor == -1 && fadecolor == -1 && desaturation == -1)

View file

@ -78,7 +78,9 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
struct PredictPos struct PredictPos
{ {
int gametic; int gametic;
FVector3 point; fixed_t x;
fixed_t y;
fixed_t z;
fixed_t pitch; fixed_t pitch;
fixed_t yaw; fixed_t yaw;
} static PredictionLerpFrom, PredictionLerpResult, PredictionLast; } static PredictionLerpFrom, PredictionLerpResult, PredictionLast;
@ -2588,7 +2590,8 @@ void P_PlayerThink (player_t *player)
{ {
if (player->mo->waterlevel < 3 || if (player->mo->waterlevel < 3 ||
(player->mo->flags2 & MF2_INVULNERABLE) || (player->mo->flags2 & MF2_INVULNERABLE) ||
(player->cheats & (CF_GODMODE | CF_NOCLIP2))) (player->cheats & (CF_GODMODE | CF_NOCLIP2)) ||
(player->cheats & CF_GODMODE2))
{ {
player->mo->ResetAirSupply (); player->mo->ResetAirSupply ();
} }
@ -2605,12 +2608,19 @@ void P_PredictionLerpReset()
PredictionLerptics = PredictionLast.gametic = PredictionLerpFrom.gametic = PredictionLerpResult.gametic = 0; PredictionLerptics = PredictionLast.gametic = PredictionLerpFrom.gametic = PredictionLerpResult.gametic = 0;
} }
bool P_LerpCalculate(FVector3 from, FVector3 to, FVector3 &result, float scale) bool P_LerpCalculate(PredictPos from, PredictPos to, PredictPos &result, float scale)
{ {
result = to - from; FVector3 vecFrom(FIXED2DBL(from.x), FIXED2DBL(from.y), FIXED2DBL(from.z));
result *= scale; FVector3 vecTo(FIXED2DBL(to.x), FIXED2DBL(to.y), FIXED2DBL(to.z));
result = result + from; FVector3 vecResult;
FVector3 delta = result - to; vecResult = vecTo - vecFrom;
vecResult *= scale;
vecResult = vecResult + vecFrom;
FVector3 delta = vecResult - vecTo;
result.x = FLOAT2FIXED(vecResult.X);
result.y = FLOAT2FIXED(vecResult.Y);
result.z = FLOAT2FIXED(vecResult.Z);
// As a fail safe, assume extrapolation is the threshold. // As a fail safe, assume extrapolation is the threshold.
return (delta.LengthSquared() > cl_predict_lerpthreshold && scale <= 1.00f); return (delta.LengthSquared() > cl_predict_lerpthreshold && scale <= 1.00f);
@ -2715,8 +2725,18 @@ void P_PredictPlayer (player_t *player)
if (CanLerp && PredictionLast.gametic > 0 && i == PredictionLast.gametic && !NoInterpolateOld) if (CanLerp && PredictionLast.gametic > 0 && i == PredictionLast.gametic && !NoInterpolateOld)
{ {
// Z is not compared as lifts will alter this with no apparent change // Z is not compared as lifts will alter this with no apparent change
DoLerp = (PredictionLast.point.X != FIXED2FLOAT(player->mo->x) || // Make lerping less picky by only testing whole units
PredictionLast.point.Y != FIXED2FLOAT(player->mo->y)); DoLerp = ((PredictionLast.x >> 16) != (player->mo->x >> 16) ||
(PredictionLast.y >> 16) != (player->mo->y >> 16));
// Aditional Debug information
if (developer && DoLerp)
{
DPrintf("Lerp! Ltic (%d) && Ptic (%d) | Lx (%d) && Px (%d) | Ly (%d) && Py (%d)\n",
PredictionLast.gametic, i,
(PredictionLast.x >> 16), (player->mo->x >> 16),
(PredictionLast.y >> 16), (player->mo->y >> 16));
}
} }
} }
@ -2733,19 +2753,19 @@ void P_PredictPlayer (player_t *player)
} }
PredictionLast.gametic = maxtic - 1; PredictionLast.gametic = maxtic - 1;
PredictionLast.point.X = FIXED2FLOAT(player->mo->x); PredictionLast.x = player->mo->x;
PredictionLast.point.Y = FIXED2FLOAT(player->mo->y); PredictionLast.y = player->mo->y;
PredictionLast.point.Z = FIXED2FLOAT(player->mo->z); PredictionLast.z = player->mo->z;
if (PredictionLerptics > 0) if (PredictionLerptics > 0)
{ {
if (PredictionLerpFrom.gametic > 0 && if (PredictionLerpFrom.gametic > 0 &&
P_LerpCalculate(PredictionLerpFrom.point, PredictionLast.point, PredictionLerpResult.point, (float)PredictionLerptics * cl_predict_lerpscale)) P_LerpCalculate(PredictionLerpFrom, PredictionLast, PredictionLerpResult, (float)PredictionLerptics * cl_predict_lerpscale))
{ {
PredictionLerptics++; PredictionLerptics++;
player->mo->x = FLOAT2FIXED(PredictionLerpResult.point.X); player->mo->x = PredictionLerpResult.x;
player->mo->y = FLOAT2FIXED(PredictionLerpResult.point.Y); player->mo->y = PredictionLerpResult.y;
player->mo->z = FLOAT2FIXED(PredictionLerpResult.point.Z); player->mo->z = PredictionLerpResult.z;
} }
else else
{ {

View file

@ -4054,6 +4054,7 @@ enum T_Flags
{ {
TF_TELEFRAG = 1, // Allow telefrag in order to teleport. TF_TELEFRAG = 1, // Allow telefrag in order to teleport.
TF_RANDOMDECIDE = 2, // Randomly fail based on health. (A_Srcr2Decide) TF_RANDOMDECIDE = 2, // Randomly fail based on health. (A_Srcr2Decide)
TF_FORCED = 4, // Forget what's in the way. TF_Telefrag takes precedence though.
}; };
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport)
@ -4103,7 +4104,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport)
fixed_t prevX = self->x; fixed_t prevX = self->x;
fixed_t prevY = self->y; fixed_t prevY = self->y;
fixed_t prevZ = self->z; fixed_t prevZ = self->z;
if (P_TeleportMove (self, spot->x, spot->y, spot->z, Flags & TF_TELEFRAG)) bool teleResult = false;
//Take precedence and cooperate with telefragging first.
if (P_TeleportMove(self, spot->x, spot->y, spot->z, Flags & TF_TELEFRAG))
teleResult = true;
if ((!(teleResult)) && (Flags & TF_FORCED))
{
//If for some reason the original move didn't work, regardless of telefrag, force it to move.
self->SetOrigin(spot->x, spot->y, spot->z);
teleResult = true;
}
if (teleResult)
{ {
ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains!
@ -4509,7 +4523,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp)
self->PrevY = self->y + reference->PrevY - reference->y; self->PrevY = self->y + reference->PrevY - reference->y;
self->PrevZ = self->z + reference->PrevZ - reference->z; self->PrevZ = self->z + reference->PrevZ - reference->z;
} }
else if (! (flags & WARPF_INTERPOLATE)) else if (!(flags & WARPF_INTERPOLATE))
{ {
self->PrevX = self->x; self->PrevX = self->x;
self->PrevY = self->y; self->PrevY = self->y;

View file

@ -245,6 +245,7 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF7, BUDDHA, AActor, flags7), DEFINE_FLAG(MF7, BUDDHA, AActor, flags7),
DEFINE_FLAG(MF7, FOILBUDDHA, AActor, flags7), DEFINE_FLAG(MF7, FOILBUDDHA, AActor, flags7),
DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7), DEFINE_FLAG(MF7, DONTTHRUST, AActor, flags7),
DEFINE_FLAG(MF7, ALLOWPAIN, AActor, flags7),
// Effect flags // Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),

View file

@ -181,7 +181,9 @@ const int FPF_AIMATANGLE = 1;
const int FPF_TRANSFERTRANSLATION = 2; const int FPF_TRANSFERTRANSLATION = 2;
// Flags for A_Teleport // Flags for A_Teleport
const int TF_TELEFRAG = 1;const int TF_RANDOMDECIDE = 2; const int TF_TELEFRAG = 1;
const int TF_RANDOMDECIDE = 2;
const int TF_FORCED = 4;
// Flags for A_WolfAttack // Flags for A_WolfAttack
const int WAF_NORANDOM = 1; const int WAF_NORANDOM = 1;
@ -326,6 +328,7 @@ Const Int WARPF_STOP = 0x80;
Const Int WARPF_TOFLOOR = 0x100; Const Int WARPF_TOFLOOR = 0x100;
Const Int WARPF_TESTONLY = 0x200; Const Int WARPF_TESTONLY = 0x200;
Const Int WAPRF_ABSOLUTEPOSITION = 0x400; Const Int WAPRF_ABSOLUTEPOSITION = 0x400;
Const Int WARPF_ABSOLUTEPOSITION = 0x400;
// flags for A_SetPitch/SetAngle // flags for A_SetPitch/SetAngle
const int SPF_FORCECLAMP = 1; const int SPF_FORCECLAMP = 1;

View file

@ -1098,6 +1098,7 @@ OptionMenu MessageOptions
Title "MESSAGES" Title "MESSAGES"
Option "Show messages", "show_messages", "OnOff" Option "Show messages", "show_messages", "OnOff"
Option "Show obituaries", "show_obituaries", "OnOff" Option "Show obituaries", "show_obituaries", "OnOff"
Option "Show secret notifications", "cl_showsecretmessage", "OnOff"
Option "Scale text in high res", "con_scaletext", "ScaleValues" Option "Scale text in high res", "con_scaletext", "ScaleValues"
Option "Minimum message level", "msg", "MessageLevels" Option "Minimum message level", "msg", "MessageLevels"
Option "Center messages", "con_centernotify", "OnOff" Option "Center messages", "con_centernotify", "OnOff"