func_door/func_door_rotating: Fixes to behaviour when Blocked.

This commit is contained in:
Marco Cawthorne 2025-02-24 17:20:43 -08:00
parent 9fd8b6d218
commit b82d068065
2 changed files with 79 additions and 46 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,12 +17,12 @@
enumflags {
SF_MOV_OPEN,
SF_MOV_RESERVED1,
SF_MOV_UNLINK, /* TODO: implement this */
SF_MOV_RESERVED2, /* was UNLINK in Quake. Removed in HL */
SF_MOV_PASSABLE,
SF_MOV_RESERVED2,
SF_MOV_TOGGLE,
SF_MOV_RESERVED3,
SF_MOV_TOGGLE,
SF_MOV_RESERVED4,
SF_MOV_RESERVED5,
SF_MOV_USE
};
@ -50,17 +50,18 @@ axis. It is often used for primitive elevators as well.
- "forceclosed": Will make sure the door will not bounce back when something is blocking it
# SPAWNFLAGS
- SF_MOV_OPEN : Swaps the positions between raised and lowered state.
- SF_MOV_UNLINK : Currently unimplemented.
- SF_MOV_PASSABLE : Don't test against any collision with this door.
- SF_MOV_TOGGLE : Door cannot be opened by physical means, only by a trigger.
- SF_MOV_USE : Players can press the "use" button/key to activate this door.
- SF_MOV_OPEN (1) : Swaps the positions between raised and lowered state.
- SF_MOV_PASSABLE (8) : Don't test against any collision with this door.
- SF_MOV_TOGGLE (32) : Door cannot be opened by physical means, only by a trigger.
- SF_MOV_USE (256): Players can press the "use" button/key to activate this door.
# NOTES
The keys "movesnd" and "stopsnd" are obsolete. Their values point towards
the samples doors/doormoveX.wav and doors/doorstopX.wav respectively, where
X is the integer value set in "movesnd" and "stopsnd".
Previous documents referred to the SF_MOV_UNLINK (4) flag, which was a left-over from Quake.
# TRIVIA
This entity was introduced in Quake (1996).
@ -88,6 +89,11 @@ public:
virtual void MoverStartsMoving(void);
virtual void MoverFinishesMoving(void);
nonvirtual void EnableTouchActivation(void);
nonvirtual void DisableTouchActivation(void);
nonvirtual void Lock(void);
nonvirtual void Unlock(void);
private:
string targetClose;
float m_flSpeed;
@ -112,8 +118,34 @@ private:
int m_waterType;
string m_strFullyClosed;
float m_preventTouch;
};
void
func_door::EnableTouchActivation(void)
{
m_bCanTouch = true;
}
void
func_door::DisableTouchActivation(void)
{
m_bCanTouch = false;
}
void
func_door::Lock(void)
{
m_bLocked = true;
}
void
func_door::Unlock(void)
{
m_bLocked = false;
}
void
func_door::func_door(void)
{
@ -345,13 +377,15 @@ func_door::Respawn(void)
}
/* this is a terrible hack */
if (m_flWait == 0)
if (m_flWait == 0) {
m_flWait = 0.01f;
}
if (HasSpawnFlags(SF_MOV_PASSABLE))
if (HasSpawnFlags(SF_MOV_PASSABLE)) {
SetSolid(SOLID_NOT);
else
} else {
SetSolid(SOLID_BSP);
}
SetMovetype(MOVETYPE_PUSH);
AddFlags(FL_FINDABLE_NONSOLID);
@ -377,16 +411,16 @@ func_door::Respawn(void)
m_iValue = 0;
if (spawnflags & SF_MOV_USE)
if (HasSpawnFlags(SF_MOV_USE) || HasSpawnFlags(SF_MOV_TOGGLE)) {
m_bCanTouch = false;
else
} else {
m_bCanTouch = true;
}
if (HasSpawnFlags(SF_MOV_OPEN)) {
SetOrigin(GetMoverPosition2());
SetMoverPosition2(GetMoverPosition1());
SetMoverPosition1(GetOrigin());
m_iValue = 1;
_PortalOpen();
} else {
@ -396,8 +430,8 @@ func_door::Respawn(void)
if (HasTargetname()) {
m_bCanTouch = false;
if (m_strLockedSfx != __NULL__) {
m_bLocked = true;
if (STRING_SET(m_strLockedSfx)) {
Lock();
}
}
}
@ -423,8 +457,9 @@ func_door::Input(entity eAct, string strInput, string strData)
void
func_door::PlayerUse(void)
{
if (!HasSpawnFlags(SF_MOV_USE))
if (!HasSpawnFlags(SF_MOV_USE)) {
return;
}
eActivator.RemoveVFlags(VFL_USE_RELEASED);
Trigger(eActivator, TRIG_TOGGLE);
@ -514,10 +549,6 @@ func_door::Trigger(entity act, triggermode_t triggerstate)
return;
}
if (m_flWait == -1 && GetMoverState() == MOVER_POS2) {
return;
}
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
@ -546,6 +577,10 @@ func_door::Trigger(entity act, triggermode_t triggerstate)
void
func_door::Touch(entity eToucher)
{
if (m_preventTouch > GetTime()) {
return;
}
/* locked sound plays only when touched. still need another check in Trigger()
to see if it's locked in case it gets trigger targeted */
if (m_bLocked || !GetMaster(eToucher)) {
@ -564,14 +599,6 @@ func_door::Touch(entity eToucher)
return;
}
if (HasSpawnFlags(SF_MOV_USE) == true) {
return;
}
if (HasSpawnFlags(SF_MOV_TOGGLE) == true) {
return;
}
if (eToucher.movetype == MOVETYPE_WALK) {
/* only trigger if we're not above the door. */
if (eToucher.absmin[2] <= maxs[2] - 2) {
@ -583,19 +610,20 @@ func_door::Touch(entity eToucher)
void
func_door::Blocked(entity eBlocker)
{
if (m_iDamage) {
if (m_iDamage != 0i) {
vector center = WorldSpaceCenter();
vector dmgDir = dirFromTarget(center, eBlocker.origin);
ncDict damageDecl = spawn(ncDict);
damageDecl.AddKey("damage", itos(m_iDamage));
m_bCanTouch = false;
combat.Damage(eBlocker, this, eBlocker, damageDecl.GetDeclBody(), center, dmgDir, eBlocker.origin);
remove(damageDecl);
m_preventTouch = GetTime() + 0.5f;
}
if (!m_bForceClosed)
if (m_flWait >= 0) {
MoveToReverse(m_flSpeed);
if (m_bForceClosed == false) {
if (m_flWait >= 0) {
MoveToReverse(m_flSpeed);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2025 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -112,6 +112,8 @@ private:
bool m_bLocked;
bool m_bCanTouch;
vector m_vecTurnDir;
float m_flNextTrigger;
float m_preventTouch;
};
void
@ -248,7 +250,7 @@ func_door_rotating::Respawn(void)
m_vecTurnDir = [0,1,0];
}
if (spawnflags & SF_ROT_USE) {
if (HasSpawnFlags(SF_ROT_USE) || HasSpawnFlags(SF_ROT_TOGGLE)) {
m_bCanTouch = false;
} else {
m_bCanTouch = true;
@ -445,14 +447,17 @@ func_door_rotating::Trigger(entity act, triggermode_t state)
return;
}
if (m_flWait == -1 && GetMoverState() == MOVER_POS2) {
return;
}
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
if (m_flNextTrigger > time) {
if (HasSpawnFlags(SF_ROT_TOGGLE) == false) {
return;
}
}
m_flNextTrigger = time + m_flWait;
eActivator = (ncEntity)act;
/* this door can swing both ways */
@ -499,6 +504,10 @@ func_door_rotating::Use(void)
void
func_door_rotating::Touch(entity eToucher)
{
if (m_preventTouch > GetTime()) {
return;
}
/* locked sound plays only when touched. still need another check in Trigger()
to see if it's locked in case it gets trigger targeted */
if (m_bLocked || !GetMaster(eToucher)) {
@ -517,10 +526,6 @@ func_door_rotating::Touch(entity eToucher)
return;
}
if (HasSpawnFlags(SF_ROT_USE)) {
return;
}
if (eToucher.movetype == MOVETYPE_WALK) {
Trigger(eToucher, TRIG_TOGGLE);
}
@ -534,7 +539,7 @@ func_door_rotating::Blocked(entity eBlocker)
vector dmgDir = dirFromTarget(center, eBlocker.origin);
ncDict damageDecl = spawn(ncDict);
damageDecl.AddKey("damage", itos(m_iDamage));
m_bCanTouch = false;
m_preventTouch = GetTime() + 0.5f;
combat.Damage(eBlocker, this, eBlocker, damageDecl.GetDeclBody(), center, dmgDir, eBlocker.origin);
remove(damageDecl);
}