Add NSMoverEntity, a class that handles moving, pushing entity classes such as func_door and the like.

This commit is contained in:
Marco Cawthorne 2023-03-13 15:26:35 -07:00
parent 719f85210d
commit c7709bb2d5
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
8 changed files with 696 additions and 657 deletions

View File

@ -27,14 +27,6 @@ enumflags
SF_BTT_TOUCH_ONLY
};
enum
{
STATE_RAISED,
STATE_LOWERED,
STATE_UP,
STATE_DOWN
};
enum
{
FRAME_OFF,
@ -79,18 +71,14 @@ original position.
This entity was introduced in Quake (1996).
*/
class
func_button:NSSurfacePropEntity
func_button:NSMoverEntity
{
int m_iState;
moverState_t m_moverState;
float m_flSpeed;
float m_flLip;
float m_flNextTrigger;
float m_flWait;
float m_flDelay;
vector m_vecPos1;
vector m_vecPos2;
vector m_vecDest;
vector m_vecMoveDir;
string m_strSndPressed;
string m_strSndUnpressed;
@ -111,32 +99,24 @@ public:
virtual void SpawnKey(string,string);
virtual void Spawned(void);
virtual void Respawn(void);
virtual void Arrived(void);
virtual void Returned(void);
virtual void MoveBack(void);
virtual void MoveAway(void);
virtual void Touch(entity);
virtual void Blocked(entity);
virtual void Trigger(entity, triggermode_t);
virtual void DeathTrigger(void);
virtual void PlayerUse(void);
virtual void SetMovementDirection(void);
virtual void MoveToDestination(vector, void(void));
virtual void MoverStartsMoving(void);
virtual void MoverFinishesMoving(void);
};
void
func_button::func_button(void)
{
m_iState = 0i;
m_flSpeed = 0.0f;
m_flLip = 0.0f;
m_flNextTrigger = 0.0f;
m_flWait = 4.0f;
m_flDelay = 0.0f;
m_vecPos1 = [0.0f, 0.0f, 0.0f];
m_vecPos2 = [0.0f, 0.0f, 0.0f];
m_vecDest = [0.0f, 0.0f, 0.0f];
m_vecMoveDir = [0.0f, 0.0f, 0.0f];
m_strSndPressed = __NULL__;
m_strSndUnpressed = __NULL__;
m_bCanTouch = false;
@ -151,16 +131,11 @@ void
func_button::Save(float handle)
{
super::Save(handle);
SaveInt(handle, "m_iState", m_iState);
SaveFloat(handle, "m_flSpeed", m_flSpeed);
SaveFloat(handle, "m_flLip", m_flLip);
SaveFloat(handle, "m_flNextTrigger", m_flNextTrigger);
SaveFloat(handle, "m_flWait", m_flWait);
SaveFloat(handle, "m_flDelay", m_flDelay);
SaveVector(handle, "m_vecPos1", m_vecPos1);
SaveVector(handle, "m_vecPos2", m_vecPos2);
SaveVector(handle, "m_vecDest", m_vecDest);
SaveVector(handle, "m_vecMoveDir", m_vecMoveDir);
SaveString(handle, "m_strSndPressed", m_strSndPressed);
SaveString(handle, "m_strSndUnpressed", m_strSndUnpressed);
SaveString(handle, "m_strOnPressed", m_strOnPressed);
@ -175,9 +150,6 @@ void
func_button::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_iState":
m_iState = ReadInt(strValue);
break;
case "m_flSpeed":
m_flSpeed = ReadFloat(strValue);
break;
@ -193,18 +165,6 @@ func_button::Restore(string strKey, string strValue)
case "m_flDelay":
m_flDelay = ReadFloat(strValue);
break;
case "m_vecPos1":
m_vecPos1 = ReadVector(strValue);
break;
case "m_vecPos2":
m_vecPos2 = ReadVector(strValue);
break;
case "m_vecDest":
m_vecDest = ReadVector(strValue);
break;
case "m_vecMoveDir":
m_vecMoveDir = ReadVector(strValue);
break;
case "m_strSndPressed":
m_strSndPressed = ReadString(strValue);
break;
@ -306,10 +266,6 @@ func_button::Spawned(void)
void
func_button::Respawn(void)
{
RestoreAngles();
SetMovementDirection();
ClearAngles();
SetSolid(SOLID_BSP);
SetMovetype(MOVETYPE_PUSH);
SetOrigin(GetSpawnOrigin());
@ -319,6 +275,11 @@ func_button::Respawn(void)
ReleaseThink();
SetHealth(GetSpawnHealth());
RestoreAngles();
SetPosition1(GetSpawnOrigin());
SetPosition2(GetDirectionalPosition(GetSpawnAngles(), m_flLip));
ClearAngles();
if (health > 0) {
takedamage = DAMAGE_YES;
Death = DeathTrigger;
@ -328,86 +289,47 @@ func_button::Respawn(void)
m_flSpeed = 100;
}
m_vecPos1 = GetSpawnOrigin();
if (HasSpawnFlags(SF_BTT_NOMOVE)) {
m_vecPos2 = m_vecPos1;
} else {
m_vecPos2 = (m_vecPos1 + m_vecMoveDir * (fabs(m_vecMoveDir * size) - m_flLip));
SetPosition2(GetPosition1());
}
m_iValue = 0;
m_iState = STATE_LOWERED;
}
void
func_button::Arrived(void)
func_button::MoverFinishesMoving(void)
{
SetOrigin(m_vecDest);
ClearVelocity();
ReleaseThink();
m_bCanTouch = true;
UseOutput(this, m_strOnIn);
m_iState = STATE_RAISED;
if (HasSpawnFlags(SF_BTT_TOGGLE) == true) {
return;
static void MoveBack(void) {
MoveToPosition(GetPosition1(), m_flSpeed);
}
if (m_flWait != -1) {
if (GetMoverState() == MOVER_POS1) {
UseOutput(this, m_strOnOut);
SetFrame(FRAME_OFF);
} else if (GetMoverState() == MOVER_POS2) {
UseOutput(this, m_strOnIn);
ScheduleThink(MoveBack, m_flWait);
}
}
void
func_button::Returned(void)
{
UseOutput(this, m_strOnOut);
SetOrigin(m_vecDest);
ClearVelocity();
ReleaseThink();
SetFrame(FRAME_OFF);
m_bCanTouch = true;
m_iState = STATE_LOWERED;
}
void
func_button::MoveBack(void)
{
m_bCanTouch = false;
m_iState = STATE_DOWN;
m_iValue = 0;
if (m_strSndUnpressed) {
Sound_Play(this, CHAN_VOICE, m_strSndUnpressed);
}
if (m_vecPos2 != m_vecPos1) {
MoveToDestination (m_vecPos1, Returned);
} else {
Returned();
}
}
void
func_button::MoveAway(void)
func_button::MoverStartsMoving(void)
{
if (m_iState == STATE_UP) {
return;
}
m_bCanTouch = false;
m_iState = STATE_UP;
if (m_vecPos2 != m_vecPos1) {
MoveToDestination(m_vecPos2, Arrived);
} else {
Arrived();
}
m_iValue = 1;
SetFrame(FRAME_ON);
if (GetMoverState() == MOVER_1TO2) {
m_iValue = 1;
SetFrame(FRAME_ON);
} else if (GetMoverState() == MOVER_2TO1) {
m_iValue = 0;
if (m_strSndUnpressed) {
Sound_Play(this, CHAN_VOICE, m_strSndUnpressed);
}
}
}
/* TODO: Handle state */
@ -425,9 +347,9 @@ func_button::Trigger(entity act, triggermode_t state)
m_flNextTrigger = time + m_flWait;
if ((m_iState == STATE_UP) || (m_iState == STATE_RAISED)){
if ((m_moverState == MOVER_1TO2) || (m_moverState == MOVER_POS2)){
if (m_flWait != -1) {
MoveBack();
MoveToPosition(GetPosition1(), m_flSpeed);
}
return;
}
@ -435,8 +357,7 @@ func_button::Trigger(entity act, triggermode_t state)
if (m_strSndPressed)
Sound_Play(this, CHAN_VOICE, m_strSndPressed);
MoveAway();
MoveToPosition(GetPosition2(), m_flSpeed);
UseOutput(act, m_strOnPressed);
UseTargets(act, TRIG_TOGGLE, m_flDelay);
@ -480,55 +401,6 @@ void
func_button::Blocked(entity eBlocker)
{
if (m_flWait >= 0) {
if (m_iState == STATE_DOWN) {
MoveAway();
} else {
MoveBack();
}
MoveToReverse(m_flSpeed);
}
}
void
func_button::SetMovementDirection(void)
{
if (GetSpawnAngles() == [0,-1,0]) {
m_vecMoveDir = [0,0,1];
} else if (GetSpawnAngles() == [0,-2,0]) {
m_vecMoveDir = [0,0,-1];
} else {
makevectors(GetSpawnAngles());
m_vecMoveDir = v_forward;
}
}
void
func_button::MoveToDestination(vector vecDest, void(void) func)
{
vector vecDifference;
float flTravel, fTravelTime;
if (!m_flSpeed) {
objerror("No speed defined for moving entity! Will not divide by zero.");
}
m_vecDest = vecDest;
if (vecDest == origin) {
ClearVelocity();
ScheduleThink(func, 0.0f);
return;
}
vecDifference = (vecDest - origin);
flTravel = vlen(vecDifference);
fTravelTime = (flTravel / m_flSpeed);
if (fTravelTime < 0.1) {
ClearVelocity();
ScheduleThink(func, 0.0f);
return;
}
ScheduleThink(func, fTravelTime);
SetVelocity(vecDifference * (1 / fTravelTime));
}
}

View File

@ -26,14 +26,6 @@ enumflags {
SF_MOV_USE
};
enum
{
DOORSTATE_RAISED,
DOORSTATE_LOWERED,
DOORSTATE_UP,
DOORSTATE_DOWN
};
/*!QUAKED func_door (0 .5 .8) ? SF_MOV_OPEN x SF_MOV_UNLINK SF_MOV_PASSABLE x SF_MOV_TOGGLE x x SF_MOV_USE
# OVERVIEW
This sliding door entity has the ability to slide forth and back on any
@ -72,21 +64,13 @@ X is the integer value set in "movesnd" and "stopsnd".
This entity was introduced in Quake (1996).
*/
class
func_door:NSRenderableEntity
func_door:NSMoverEntity
{
public:
void func_door(void);
virtual void Spawned(void);
virtual void PortalOpen(void);
virtual void PortalClose(void);
virtual void SetMovementDirection(void);
virtual void MoveToDestination(vector, void(void) func);
virtual void MoveAway(void);
virtual void MoveBack(void);
virtual void Arrived(void);
virtual void Returned(void);
virtual void Respawn(void);
virtual void Trigger(entity, triggermode_t);
virtual void Blocked(entity);
@ -97,21 +81,18 @@ public:
virtual void SpawnKey(string, string);
virtual void Input(entity, string, string);
virtual void MoverStartsMoving(void);
virtual void MoverFinishesMoving(void);
private:
string targetClose;
vector m_vecPos1;
vector m_vecPos2;
vector m_vecDest;
vector m_vecMoveDir;
float m_flSpeed;
float m_flLip;
float m_iState;
float m_flNextTrigger;
float m_flWait;
float m_flDelay;
float m_flLip;
int m_iDamage;
int m_iLocked;
int m_iPortalState;
int m_iForceClosed;
bool m_iCanTouch;
@ -128,21 +109,13 @@ private:
void
func_door::func_door(void)
{
m_vecPos1 =
m_vecPos2 =
m_vecDest =
m_vecMoveDir = [0,0,0];
m_flSpeed =
m_flLip =
m_iState =
m_flNextTrigger =
m_flWait =
m_flDelay = 0.0f;
m_iDamage =
m_iLocked =
m_iPortalState =
m_iForceClosed = 0;
m_iCanTouch = false;
@ -163,14 +136,7 @@ func_door::Save(float handle)
{
super::Save(handle);
SaveVector(handle, "m_vecPos1", m_vecPos1);
SaveVector(handle, "m_vecPos2", m_vecPos2);
SaveVector(handle, "m_vecDest", m_vecDest);
SaveVector(handle, "m_vecMoveDir", m_vecMoveDir);
SaveFloat(handle, "m_flSpeed", m_flSpeed);
SaveFloat(handle, "m_flLip", m_flLip);
SaveFloat(handle, "m_iState", m_iState);
SaveFloat(handle, "m_flNextTrigger", m_flNextTrigger);
SaveFloat(handle, "m_flWait", m_flWait);
SaveFloat(handle, "m_flDelay", m_flDelay);
@ -178,7 +144,6 @@ func_door::Save(float handle)
SaveInt(handle, "m_iDamage", m_iDamage);
SaveInt(handle, "m_iLocked", m_iLocked);
SaveInt(handle, "m_iPortalState", m_iPortalState);
SaveInt(handle, "m_iForceClosed", m_iForceClosed);
SaveString(handle, "m_strLockedSfx", m_strLockedSfx);
@ -194,28 +159,9 @@ void
func_door::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_vecPos1":
m_vecPos1 = ReadVector(strValue);
break;
case "m_vecPos2":
m_vecPos2 = ReadVector(strValue);
break;
case "m_vecDest":
m_vecDest = ReadVector(strValue);
break;
case "m_vecMoveDir":
m_vecMoveDir = ReadVector(strValue);
break;
case "m_flSpeed":
m_flSpeed = ReadFloat(strValue);
break;
case "m_flLip":
m_flLip = ReadFloat(strValue);
break;
case "m_iState":
m_iState = ReadFloat(strValue);
break;
case "m_flNextTrigger":
m_flNextTrigger = ReadFloat(strValue);
break;
@ -235,9 +181,6 @@ func_door::Restore(string strKey, string strValue)
case "m_iLocked":
m_iLocked = ReadInt(strValue);
break;
case "m_iPortalState":
m_iPortalState = ReadInt(strValue);
break;
case "m_iForceClosed":
m_iForceClosed = ReadInt(strValue);
break;
@ -355,20 +298,10 @@ func_door::Spawned(void)
void
func_door::Respawn(void)
{
/* reset */
m_vecPos1 = [0,0,0];
m_vecPos2 = [0,0,0];
m_vecDest = [0,0,0];
m_vecMoveDir = [0,0,0];
/* this is a terrible hack */
if (m_flWait == 0)
m_flWait = 0.01f;
RestoreAngles();
SetMovementDirection();
ClearAngles();
if (HasSpawnFlags(SF_MOV_PASSABLE))
SetSolid(SOLID_NOT);
else
@ -380,6 +313,11 @@ func_door::Respawn(void)
AddFlags(FL_FINDABLE_NONSOLID);
ReleaseThink();
RestoreAngles();
SetPosition1(GetSpawnOrigin());
SetPosition2(GetDirectionalPosition(GetSpawnAngles(), m_flLip));
ClearAngles();
/* FIXME: Is this correct? */
if (m_flWait == -1) {
spawnflags |= SF_MOV_TOGGLE;
@ -394,9 +332,6 @@ func_door::Respawn(void)
}
m_iValue = 0;
m_iState = DOORSTATE_LOWERED;
m_vecPos1 = GetSpawnOrigin();
m_vecPos2 = (m_vecPos1 + m_vecMoveDir * (fabs(m_vecMoveDir * size) - m_flLip));
if (spawnflags & SF_MOV_USE)
m_iCanTouch = false;
@ -405,12 +340,13 @@ func_door::Respawn(void)
if (HasSpawnFlags(SF_MOV_OPEN)) {
SetOrigin(m_vecPos2);
m_vecPos2 = m_vecPos1;
m_vecPos1 = origin;
SetPosition2(GetPosition1());
SetPosition1(GetOrigin());
m_iValue = 1;
PortalOpen();
_PortalOpen();
} else {
PortalClose();
_PortalClose();
}
if (targetname) {
@ -436,28 +372,6 @@ func_door::Input(entity eAct, string strInput, string strData)
}
}
void
func_door::PortalOpen(void)
{
if (m_iPortalState == 1)
return;
m_iPortalState = 1;
setorigin(this, origin);
openportal(this, AREAPORTAL_OPEN);
}
void
func_door::PortalClose(void)
{
if (m_iPortalState == 0)
return;
m_iPortalState = 0;
setorigin(this, origin);
openportal(this, AREAPORTAL_CLOSED);
}
void
func_door::PlayerUse(void)
{
@ -469,94 +383,75 @@ func_door::PlayerUse(void)
}
void
func_door::Arrived(void)
func_door::MoverFinishesMoving(void)
{
SetOrigin(m_vecDest);
ClearVelocity();
ReleaseThink();
m_iState = DOORSTATE_RAISED;
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
static void MoveBack(void) {
MoveToPosition(GetPosition1(), m_flSpeed);
}
if (m_strSndMove)
sound(this, CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM);
if ((m_flWait < 0.0f) || HasSpawnFlags(SF_MOV_TOGGLE) == true)
return;
ScheduleThink(MoveBack, m_flWait);
}
void
func_door::Returned(void)
{
SetOrigin(m_vecDest);
ClearVelocity();
ReleaseThink();
if (targetClose)
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
/* we arrived at our starting position within the map */
if (GetMoverState() == MOVER_POS1) {
if (targetClose)
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
}
}
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
sound(this, CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM);
} else if (GetMoverState() == MOVER_POS2) {
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
sound(this, CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM);
if ((m_flWait < 0.0f) || HasSpawnFlags(SF_MOV_TOGGLE) == true)
return;
ScheduleThink(MoveBack, m_flWait);
}
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
sound(this, CHAN_WEAPON, "common/null.wav", 1.0f, ATTN_NORM);
m_iState = DOORSTATE_LOWERED;
PortalClose();
}
void
func_door::MoveBack(void)
func_door::MoverStartsMoving(void)
{
if (m_strSndClose) {
Sound_Play(this, CHAN_VOICE, m_strSndClose);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
if (GetMoverState() == MOVER_1TO2) {
if (m_strSndOpen) {
Sound_Play(this, CHAN_VOICE, m_strSndOpen);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
Sound_Play(this, CHAN_WEAPON, m_strSndMove);
m_iValue = 1;
} else if (GetMoverState() == MOVER_2TO1) {
if (m_strSndClose) {
Sound_Play(this, CHAN_VOICE, m_strSndClose);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
Sound_Play(this, CHAN_WEAPON, m_strSndMove);
m_iValue = 0;
}
if (m_strSndMove)
Sound_Play(this, CHAN_WEAPON, m_strSndMove);
m_iValue = 0;
m_iState = DOORSTATE_DOWN;
MoveToDestination(m_vecPos1, Returned);
}
void
func_door::MoveAway(void)
{
if (m_iState == DOORSTATE_UP) {
return;
}
if (m_strSndOpen) {
Sound_Play(this, CHAN_VOICE, m_strSndOpen);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (m_strSndMove)
Sound_Play(this, CHAN_WEAPON, m_strSndMove);
m_iValue = 1;
m_iState = DOORSTATE_UP;
MoveToDestination(m_vecPos2, Arrived);
PortalOpen();
}
void
@ -573,20 +468,16 @@ func_door::Trigger(entity act, triggermode_t triggerstate)
m_flNextTrigger = time + m_flWait;
/* only trigger stuff once we are done moving */
if ((m_iState == DOORSTATE_RAISED) || (m_iState == DOORSTATE_LOWERED)) {
if ((GetMoverState() == MOVER_POS1) || (GetMoverState() == MOVER_POS2)) {
UseTargets(act, TRIG_TOGGLE, m_flDelay);
}
if (triggerstate == TRIG_OFF) {
MoveBack();
MoveToPosition(GetPosition1(), m_flSpeed);
} else if (triggerstate == TRIG_ON) {
MoveAway();
MoveToPosition(GetPosition2(), m_flSpeed);
} else {
if ((m_iState == DOORSTATE_UP) || (m_iState == DOORSTATE_RAISED)){
MoveBack();
} else {
MoveAway();
}
MoveToReverse(m_flSpeed);
}
}
@ -627,61 +518,10 @@ func_door::Blocked(entity eBlocker)
if (!m_iForceClosed)
if (m_flWait >= 0) {
if (m_iState == DOORSTATE_DOWN) {
MoveAway();
} else {
MoveBack();
}
MoveToReverse(m_flSpeed);
}
}
void
func_door::SetMovementDirection(void)
{
if (GetSpawnAngles() == [0,-1,0]) {
m_vecMoveDir = [0,0,1];
} else if (GetSpawnAngles() == [0,-2,0]) {
m_vecMoveDir = [0,0,-1];
} else {
makevectors(GetSpawnAngles());
m_vecMoveDir = v_forward;
}
}
void
func_door::MoveToDestination(vector vecDest, void(void) func)
{
vector vecDifference;
float flTravel;
float fTravelTime;
if (!m_flSpeed) {
objerror("func_door: No speed defined!");
return;
}
m_vecDest = vecDest;
if (vecDest == origin) {
ScheduleThink(func, 0.1f);
ClearVelocity();
return;
}
vecDifference = (vecDest - origin);
flTravel = vlen(vecDifference);
fTravelTime = (flTravel / m_flSpeed);
if (fTravelTime < 0.1) {
ScheduleThink(func, 0.1f);
ClearVelocity();
return;
}
ScheduleThink(func, fTravelTime);
SetVelocity(vecDifference * (1.0f / fTravelTime));
}
void
func_water(void)
{

View File

@ -68,8 +68,30 @@ Please include an origin brush so that a pivot point will be defined.
This entity was introduced in Quake II (1997).
*/
class
func_door_rotating:NSRenderableEntity
func_door_rotating:NSMoverEntity
{
public:
void func_door_rotating(void);
/* overrides */
virtual void Spawned(void);
virtual void SpawnKey(string,string);
virtual void Save(float);
virtual void Restore(string,string);
virtual void Use(void);
virtual void Touch(entity);
virtual void Blocked(entity);
virtual void Respawn(void);
virtual void MoverStartsMoving(void);
virtual void MoverFinishesMoving(void);
virtual void Trigger(entity, triggermode_t);
#ifdef GS_PHYSICS
nonvirtual void Unhinge(void);
#endif
private:
string targetClose;
string m_strSndStop;
string m_strSndOpen;
@ -78,43 +100,13 @@ func_door_rotating:NSRenderableEntity
float m_flSoundWait;
float m_flDistance;
float m_flSpeed;
float m_iState;
float m_flNextAction;
float m_flWait;
float m_flDelay;
int m_iPortalState;
int m_iDamage;
int m_iLocked;
vector m_vecDest;
vector m_vecPos1;
vector m_vecPos2;
vector m_vecMoveDir;
bool m_iCanTouch;
public:
void func_door_rotating(void);
virtual void Save(float);
virtual void Restore(string,string);
virtual void Spawned(void);
virtual void PortalOpen(void);
virtual void PortalClose(void);
virtual void Respawn(void);
virtual void Arrived(void);
virtual void Returned(void);
virtual void Back(void);
virtual void Away(void);
virtual void Trigger(entity, triggermode_t);
virtual void Use(void);
virtual void Touch(entity);
virtual void Blocked(entity);
virtual void SetMovementDirection(void);
virtual void SpawnKey(string,string);
virtual void RotToDest(vector angle, void(void) func);
#ifdef GS_PHYSICS
virtual void Unhinge(void);
#endif
bool m_bCanTouch;
vector m_vecTurnDir;
};
void
@ -130,16 +122,11 @@ func_door_rotating::func_door_rotating(void)
m_iLocked = 0i;
m_flDistance = 90.0f;
m_flSpeed = 100.0f;
m_iState = 0i;
m_flNextAction = 0.0f;
m_flWait = 0.0f;
m_flDelay = 4.0f;
m_vecDest = [0.0f, 0.0f, 0.0f];
m_vecPos1 = [0.0f, 0.0f, 0.0f];
m_vecPos2 = [0,0,0];
m_vecMoveDir = [0.0f, 0.0f, 0.0f];
m_iPortalState = 0i;
m_iCanTouch = false;
m_bCanTouch = false;
m_vecTurnDir = g_vec_null;
}
void
@ -154,18 +141,13 @@ func_door_rotating::Save(float handle)
SaveFloat(handle, "m_flSoundWait", m_flSoundWait);
SaveFloat(handle, "m_flDistance", m_flDistance);
SaveFloat(handle, "m_flSpeed", m_flSpeed);
SaveFloat(handle, "m_iState", m_iState);
SaveFloat(handle, "m_flNextAction", m_flNextAction);
SaveFloat(handle, "m_flWait", m_flWait);
SaveFloat(handle, "m_flDelay", m_flDelay);
SaveInt(handle, "m_iPortalState", m_iPortalState);
SaveInt(handle, "m_iDamage", m_iDamage);
SaveInt(handle, "m_iLocked", m_iLocked);
SaveVector(handle, "m_vecDest", m_vecDest);
SaveVector(handle, "m_vecPos1", m_vecPos1);
SaveVector(handle, "m_vecPos2", m_vecPos2);
SaveVector(handle, "m_vecMoveDir", m_vecMoveDir);
SaveBool(handle, "m_iCanTouch", m_iCanTouch);
SaveBool(handle, "m_bCanTouch", m_bCanTouch);
SaveVector(handle, "m_vecTurnDir", m_vecTurnDir);
}
void
@ -196,9 +178,6 @@ func_door_rotating::Restore(string strKey, string strValue)
case "m_flSpeed":
m_flSpeed = ReadFloat(strValue);
break;
case "m_iState":
m_iState = ReadInt(strValue);
break;
case "m_flNextAction":
m_flNextAction = ReadFloat(strValue);
break;
@ -208,29 +187,17 @@ func_door_rotating::Restore(string strKey, string strValue)
case "m_flDelay":
m_flDelay = ReadFloat(strValue);
break;
case "m_iPortalState":
m_iPortalState = ReadInt(strValue);
break;
case "m_iDamage":
m_iDamage = ReadInt(strValue);
break;
case "m_iLocked":
m_iLocked = ReadInt(strValue);
break;
case "m_vecDest":
m_vecDest = ReadVector(strValue);
case "m_bCanTouch":
m_bCanTouch = ReadInt(strValue);
break;
case "m_vecPos1":
m_vecPos1 = ReadVector(strValue);
break;
case "m_vecPos2":
m_vecPos2 = ReadVector(strValue);
break;
case "m_vecMoveDir":
m_vecMoveDir = ReadVector(strValue);
break;
case "m_iCanTouch":
m_iCanTouch = ReadInt(strValue);
case "m_vecTurnDir":
m_vecTurnDir = ReadVector(strValue);
break;
default:
super::Restore(strKey, strValue);
@ -255,10 +222,6 @@ func_door_rotating::Spawned(void)
void
func_door_rotating::Respawn(void)
{
RestoreAngles();
SetMovementDirection();
ClearAngles();
#ifdef GS_PHYSICS
SetTakedamage(DAMAGE_YES);
SetHealth(100);
@ -272,14 +235,24 @@ func_door_rotating::Respawn(void)
ClearVelocity();
ReleaseThink();
if (spawnflags & SF_ROT_USE)
m_iCanTouch = false;
else
m_iCanTouch = true;
if (HasSpawnFlags(SF_ROT_ZAXIS)) {
m_vecTurnDir = [0,0,1];
} else if (HasSpawnFlags(SF_ROT_XAXIS)) {
m_vecTurnDir = [1,0,0];
} else {
m_vecTurnDir = [0,1,0];
}
if (spawnflags & SF_ROT_USE) {
m_bCanTouch = false;
} else {
m_bCanTouch = true;
}
/* this is a terrible hack */
if (m_flWait == 0)
if (m_flWait == 0) {
m_flWait = 0.01f;
}
if (HasSpawnFlags(SF_ROT_USE)) {
PlayerUse = Use;
@ -287,26 +260,22 @@ func_door_rotating::Respawn(void)
PlayerUse = __NULL__;
}
m_vecPos1 = GetSpawnAngles();
SetPosition1(GetSpawnAngles());
RestoreAngles();
if (HasSpawnFlags(SF_ROT_BACKWARDS)) {
m_vecPos2 = GetSpawnAngles() + m_vecMoveDir * -m_flDistance;
SetPosition2(GetDirectionalRotation(m_vecTurnDir, -m_flDistance));
} else {
m_vecPos2 = GetSpawnAngles() + m_vecMoveDir * m_flDistance;
SetPosition2(GetDirectionalRotation(m_vecTurnDir, m_flDistance));
}
ClearAngles();
if (HasSpawnFlags(SF_ROT_OPEN)) {
vector vTemp = m_vecPos2;
m_vecPos2 = m_vecPos1;
m_vecPos1 = vTemp;
m_vecMoveDir = m_vecMoveDir * -1;
PortalOpen();
} else {
PortalClose();
vector vTemp = GetPosition2();
SetPosition2(GetPosition1());
SetPosition1(vTemp);
}
m_iState = STATE_LOWERED;
if (HasSpawnFlags(SF_ROT_PASSABLE)) {
SetSolid(SOLID_NOT);
}
@ -315,7 +284,7 @@ func_door_rotating::Respawn(void)
m_iLocked = TRUE;
}
SetAngles(m_vecPos1);
SetAngles(GetPosition1());
}
void
@ -326,9 +295,6 @@ func_door_rotating::SpawnKey(string strKey, string strValue)
case "speed":
m_flSpeed = stof(strValue);
break;
/*case "lip":
m_flDistance = stof(strValue);
break;*/
case "snd_open":
m_strSndOpen = strValue;
break;
@ -344,11 +310,11 @@ func_door_rotating::SpawnKey(string strKey, string strValue)
break;
/* GoldSrc compat */
case "movesnd":
x = stoi(strValue);
x = stoi(strValue); /* sanitize */
m_strSndOpen = m_strSndClose = sprintf("func_door_rotating.move_%i", x);
break;
case "stopsnd":
x = stoi(strValue);
x = stoi(strValue); /* sanitize */
m_strSndStop = sprintf("func_door_rotating.stop_%i", x);
break;
case "distance":
@ -364,7 +330,7 @@ func_door_rotating::SpawnKey(string strKey, string strValue)
targetClose = strValue;
break;
case "locked_sound":
x = stoi(strValue);
x = stoi(strValue); /* sanitize */
m_strLockedSfx = sprintf("func_button.hlsfx_%i", x+1i);
break;
default:
@ -372,34 +338,13 @@ func_door_rotating::SpawnKey(string strKey, string strValue)
}
}
void
func_door_rotating::PortalOpen(void)
{
if (m_iPortalState == 1)
return;
m_iPortalState = 1;
setorigin(this, origin);
openportal(this, AREAPORTAL_OPEN);
}
void
func_door_rotating::PortalClose(void)
{
if (m_iPortalState == 0)
return;
m_iPortalState = 0;
setorigin(this, origin);
openportal(this, AREAPORTAL_CLOSED);
}
#ifdef GS_PHYSICS
void
func_door_rotating::Unhinge(void)
{
SetTakedamage(DAMAGE_NO);
ReleaseThink();
m_iCanTouch = false;
m_bCanTouch = false;
SetSolid(SOLID_PHYSICS_BOX);
SetMovetype(MOVETYPE_PHYSICS);
physics_enable(this, TRUE);
@ -407,102 +352,60 @@ func_door_rotating::Unhinge(void)
#endif
void
func_door_rotating::Arrived(void)
func_door_rotating::MoverFinishesMoving(void)
{
SetAngles(m_vecDest);
SetAngularVelocity([0,0,0]);
ReleaseThink();
m_iState = STATE_RAISED;
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
static void RotateBack(void) {
RotateToPosition(GetPosition1(), m_flSpeed);
}
if ((m_flWait < 0.0f) || HasSpawnFlags(SF_ROT_TOGGLE) == true)
return;
ScheduleThink(Back, m_flWait);
}
void
func_door_rotating::Returned(void)
{
SetAngles(m_vecDest);
SetAngularVelocity([0,0,0]);
ReleaseThink();
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if (targetClose)
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
}
}
m_iState = STATE_LOWERED;
PortalClose();
}
void
func_door_rotating::Back(void)
{
if (!HasSpawnFlags(SF_DOOR_SILENT)) {
if (m_strSndClose) {
Sound_Play(this, CHAN_VOICE, m_strSndClose);
if (GetMoverState() == MOVER_POS1) {
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
}
m_iState = STATE_DOWN;
RotToDest(m_vecPos1, Returned);
}
void
func_door_rotating::Away(void)
{
float fDirection = 1.0;
if (m_iState == STATE_UP) {
return;
}
if (!HasSpawnFlags(SF_DOOR_SILENT)) {
if (m_strSndOpen) {
Sound_Play(this, CHAN_VOICE, m_strSndOpen);
if (targetClose)
for (entity f = world; (f = find(f, ::targetname, targetClose));) {
NSEntity trigger = (NSEntity)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
}
}
} else if (GetMoverState() == MOVER_POS2) {
if (m_strSndStop) {
Sound_Play(this, CHAN_VOICE, m_strSndStop);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
if ((m_flWait < 0.0f) || HasSpawnFlags(SF_ROT_TOGGLE) == true)
return;
ScheduleThink(RotateBack, m_flWait);
}
}
m_iState = STATE_UP;
if (!HasSpawnFlags(SF_ROT_ONEWAY)) {
/* One way doors only work on the Y axis */
if (!HasSpawnFlags(SF_ROT_ZAXIS) || HasSpawnFlags(SF_ROT_XAXIS)) {
/* get the door facing dir */
vector door_dir = vectoangles(WorldSpaceCenter() - origin);
makevectors(door_dir);
float flDir = dotproduct(origin - eActivator.origin, v_right);
if (flDir > 0) {
fDirection = -1.0f;
void
func_door_rotating::MoverStartsMoving(void)
{
if (GetMoverState() == MOVER_2TO1) {
if (!HasSpawnFlags(SF_DOOR_SILENT)) {
if (m_strSndClose) {
Sound_Play(this, CHAN_VOICE, m_strSndClose);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
}
} else if (GetMoverState() == MOVER_1TO2) {
if (!HasSpawnFlags(SF_DOOR_SILENT)) {
if (m_strSndOpen) {
Sound_Play(this, CHAN_VOICE, m_strSndOpen);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0f, ATTN_NORM);
}
}
}
RotToDest(m_vecPos2 * fDirection, Arrived);
PortalOpen();
}
void
@ -511,24 +414,38 @@ func_door_rotating::Trigger(entity act, triggermode_t state)
if (GetMaster() == FALSE) {
return;
}
if (m_flNextAction > time) {
return;
}
m_flNextAction = time + m_flWait;
eActivator = act;
/* this door can swing both ways */
if (!HasSpawnFlags(SF_ROT_ONEWAY)) {
/* One way doors only work on the Y axis */
if (!HasSpawnFlags(SF_ROT_ZAXIS) || HasSpawnFlags(SF_ROT_XAXIS)) {
float flDirection = 1.0;
/* get the door facing dir */
vector door_dir = vectoangles(WorldSpaceCenter() - origin);
makevectors(door_dir);
float flDir = dotproduct(origin - act.origin, v_right);
if (flDir > 0) {
flDirection = -1.0f;
}
SetPosition2(GetDirectionalRotation(m_vecTurnDir, m_flDistance * flDirection));
}
}
if (state == TRIG_TOGGLE) {
if ((m_iState == STATE_UP) || (m_iState == STATE_RAISED)) {
Back();
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_POS2)) {
RotateToPosition(GetPosition1(), m_flSpeed);
return;
} else {
Away();
RotateToPosition(GetPosition2(), m_flSpeed);
}
} else if (state == TRIG_OFF) {
Back();
RotateToPosition(GetPosition1(), m_flSpeed);
} else if (state == TRIG_ON) {
Away();
RotateToPosition(GetPosition2(), m_flSpeed);
}
UseTargets(act, TRIG_TOGGLE, m_flDelay);
@ -544,8 +461,9 @@ func_door_rotating::Use(void)
void
func_door_rotating::Touch(entity eToucher)
{
if (m_iCanTouch == false)
if (m_bCanTouch == false) {
return;
}
if (m_iLocked || !GetMaster()) {
if (m_flSoundWait < time)
@ -559,7 +477,7 @@ func_door_rotating::Touch(entity eToucher)
return;
}
if ((m_iState == STATE_UP) || (m_iState == STATE_DOWN)) {
if ((GetMoverState() == MOVER_1TO2) || (GetMoverState() == MOVER_2TO1)) {
return;
}
@ -576,48 +494,6 @@ func_door_rotating::Blocked(entity eBlocker)
}
if (m_flWait >= 0) {
if (m_iState == STATE_DOWN) {
Away();
} else {
Back();
}
}
}
void
func_door_rotating::SetMovementDirection(void)
{
if (HasSpawnFlags(SF_ROT_ZAXIS)) {
m_vecMoveDir = [0,0,1];
} else if (HasSpawnFlags(SF_ROT_XAXIS)) {
m_vecMoveDir = [1,0,0];
} else {
m_vecMoveDir = [0,1,0];
}
}
void
func_door_rotating::RotToDest(vector vDestAngle, void(void) func)
{
vector vecAngleDifference;
float flTravelLength, flTravelTime;
if (!m_flSpeed) {
NSLog("^1func_door_rotating::^3RotToDest^7: No speed defined for %s!", targetname);
Respawn();
return;
}
vecAngleDifference = (vDestAngle - angles);
flTravelLength = vlen(vecAngleDifference);
flTravelTime = (flTravelLength / m_flSpeed);
/* Avoid NAN hack */
if (flTravelTime <= 0.0f) {
ScheduleThink(func, 0.0f);
} else {
avelocity = (vecAngleDifference * (1 / flTravelTime));
m_vecDest = vDestAngle;
ScheduleThink(func, flTravelTime);
RotateToReverse(m_flSpeed);
}
}

View File

@ -83,9 +83,6 @@
WriteEntity(MSG_ENTITY, field);\
}
#define AREAPORTAL_CLOSED 0
#define AREAPORTAL_OPEN 1
var bool g_isloading = false;
var bool autocvar_mp_flashlight = true;

110
src/shared/NSMoverEntity.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2023 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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/** The state the NSMoverEntity is in. */
typedef enum
{
MOVER_POS1, /**< At the initial starting position. */
MOVER_POS2, /**< At the final destination. */
MOVER_1TO2, /**< On its way to the final destination. */
MOVER_2TO1 /**< on its way back to the starting position. */
} moverState_t;
/** The movement type of the NSMoverEntity. */
typedef enum
{
MOVERTYPE_TRANSFORM, /**< Moves in a linear fashion. */
MOVERTYPE_ROTATE, /**< Rotates in a linear fashion. */
} moverType_t;
#define AREAPORTAL_CLOSED 0
#define AREAPORTAL_OPEN 1
/** NSMoverEntity is responsible for handling movement functions of
mainly brush-based entities that move and push other entities around
the game world. Your sub-class will define the type of movement and
the two positions within the entity will traverse - and then do so
at your request. */
class
NSMoverEntity:NSSurfacePropEntity
{
public:
void NSMoverEntity(void);
/** Returns a directional position from the current one. */
nonvirtual vector GetDirectionalPosition(vector, float);
/** Returns a directional angle from the current one. */
nonvirtual vector GetDirectionalRotation(vector, float);
/** Set the movement state. */
nonvirtual void SetMoverState(moverState_t);
/** Returns the movement state. */
nonvirtual moverState_t GetMoverState(void);
/** Set the movement type. */
nonvirtual void SetMoverType(moverType_t);
/** Returns the movement type. */
nonvirtual moverType_t GetMoverType(void);
/** Sets the initial starting position. */
nonvirtual void SetPosition1(vector);
/** Returns the starting position. */
nonvirtual vector GetPosition1(void);
/** Sets the final destination. */
nonvirtual void SetPosition2(vector);
/** Returns the final destination. */
nonvirtual vector GetPosition2(void);
/** Moves this entity to the specified position. */
nonvirtual void MoveToPosition(vector, float);
/** Rotates this entity to the desired angle. */
nonvirtual void RotateToPosition(vector, float);
/** Moves to the reverse state. If a mover is at pos1, it'll go to pos2, etc. */
nonvirtual void MoveToReverse(float);
/** Rotates to the reversed state. */
nonvirtual void RotateToReverse(float);
/** Returns if the NSMoverEntity is currently moving. */
nonvirtual bool IsMoving(void);
/** Overridable: Called when the mover starts moving from its position to another. */
virtual void MoverStartsMoving(void);
/** Overridable: Called when the mover completes its movement to a destination. */
virtual void MoverFinishesMoving(void);
/* overrides */
#ifdef SERVER
virtual void Save(float);
virtual void Restore(string, string);
#endif
private:
vector m_vecPos1;
vector m_vecPos2;
moverState_t m_moverState;
moverType_t m_moverType;
int m_iPortalState;
nonvirtual void _PortalOpen(void);
nonvirtual void _PortalClose(void);
nonvirtual void _ArrivedAtPosition1(void);
nonvirtual void _ArrivedAtPosition2(void);
nonvirtual void _RotatedToPosition1(void);
nonvirtual void _RotatedToPosition2(void);
nonvirtual void _BeginMoving(void);
};

342
src/shared/NSMoverEntity.qc Normal file
View File

@ -0,0 +1,342 @@
void
NSMoverEntity::NSMoverEntity(void)
{
m_vecPos1 = g_vec_null;
m_vecPos2 = g_vec_null;
m_moverState = MOVER_POS1;
m_moverType = MOVERTYPE_TRANSFORM;
m_iPortalState = 0i;
}
#ifdef SERVER
void
NSMoverEntity::Save(float handle)
{
super::Save(handle);
SaveVector(handle, "m_vecPos1", m_vecPos1);
SaveVector(handle, "m_vecPos2", m_vecPos2);
SaveFloat(handle, "m_moverState", m_moverState);
SaveFloat(handle, "m_moverType", m_moverType);
SaveInt(handle, "m_iPortalState", m_iPortalState);
}
void
NSMoverEntity::Restore(string strKey, string strValue)
{
switch (strKey) {
case "m_vecPos1":
m_vecPos1 = ReadVector(strValue);
break;
case "m_vecPos2":
m_vecPos2 = ReadVector(strValue);
break;
case "m_moverState":
m_moverState = ReadFloat(strValue);
break;
case "m_moverType":
m_moverType = ReadFloat(strValue);
break;
case "m_iPortalState":
m_iPortalState = ReadInt(strValue);
break;
default:
super::Restore(strKey, strValue);
}
}
#endif
vector
NSMoverEntity::GetDirectionalPosition(vector vecAngle, float flLip)
{
vector vecMoveDir = g_vec_null;
vector vecPos = g_vec_null;
/* editor angle */
if (vecAngle == [0,-1,0]) {
vecMoveDir = [0,0,1];
} else if (vecAngle == [0,-2,0]) {
vecMoveDir = [0,0,-1];
} else {
/* manually specified angle */
makevectors(vecAngle);
vecMoveDir = v_forward;
}
vecPos = (GetOrigin() + vecMoveDir * (fabs(vecMoveDir * size) - flLip));
return vecPos;
}
vector
NSMoverEntity::GetDirectionalRotation(vector normalizedAngle, float travelDistance)
{
vector vecMoveDir = normalizedAngle;
return (GetAngles() + vecMoveDir * travelDistance);
}
void
NSMoverEntity::SetMoverState(moverState_t val)
{
m_moverState = val;
}
moverState_t
NSMoverEntity::GetMoverState(void)
{
return m_moverState;
}
void
NSMoverEntity::SetMoverType(moverType_t val)
{
m_moverType = val;
}
moverType_t
NSMoverEntity::GetMoverType(void)
{
return m_moverType;
}
void
NSMoverEntity::SetPosition1(vector val)
{
m_vecPos1 = val;
}
vector
NSMoverEntity::GetPosition1(void)
{
return m_vecPos1;
}
void
NSMoverEntity::SetPosition2(vector val)
{
m_vecPos2 = val;
}
vector
NSMoverEntity::GetPosition2(void)
{
return m_vecPos2;
}
void
NSMoverEntity::MoveToPosition(vector vecDest, float flSpeed)
{
vector vecDifference;
float flTravel;
float fTravelTime;
/* selects which end method to trigger based on state. */
static void MoveToPosition_Done(float travelTime) {
if (m_moverState == MOVER_1TO2) {
ScheduleThink(_ArrivedAtPosition2, travelTime);
} else if (m_moverState == MOVER_2TO1) {
ScheduleThink(_ArrivedAtPosition1, travelTime);
}
MoverStartsMoving();
_PortalOpen();
}
/* selects which end positition to set based on state */
static void MoveToPosition_SetDest(vector vecDest) {
if (m_moverState == MOVER_POS2) {
m_vecPos1 = vecDest;
m_moverState = MOVER_2TO1;
} else {
m_moverState = MOVER_1TO2;
m_vecPos2 = vecDest;
}
}
/* abort if no speed is defined whatsoever */
if (!flSpeed) {
objerror("NSMoverEntity::MoveToPosition: No speed defined!");
return;
}
/* set the appropriate attribute */
MoveToPosition_SetDest(vecDest);
/* if we're already there, don't bother and trigger it right now. */
if (vecDest == GetOrigin()) {
MoveToPosition_Done(0.0f);
ClearVelocity();
return;
}
/* calculate travel distance and time */
vecDifference = (vecDest - GetOrigin());
flTravel = vlen(vecDifference);
fTravelTime = (flTravel / flSpeed);
/* schedule the movement and proceed to trigger the end after a certain time */
MoveToPosition_Done(fTravelTime);
SetVelocity(vecDifference * (1.0f / fTravelTime));
}
void
NSMoverEntity::MoveToReverse(float flSpeed)
{
if ((GetMoverState() == MOVER_POS2) || (GetMoverState() == MOVER_1TO2)){
MoveToPosition(GetPosition1(), flSpeed);
} else {
MoveToPosition(GetPosition2(), flSpeed);
}
}
void
NSMoverEntity::RotateToPosition(vector vDestAngle, float flSpeed)
{
vector vecAngleDifference;
float flTravelLength, flTravelTime;
static void RotateToPosition_Done(float travelTime) {
if (m_moverState == MOVER_1TO2) {
ScheduleThink(_RotatedToPosition2, travelTime);
} else if (m_moverState == MOVER_2TO1) {
ScheduleThink(_RotatedToPosition1, travelTime);
}
MoverStartsMoving();
_PortalOpen();
}
static void RotateToPosition_SetDest(vector vecDest) {
if (m_moverState == MOVER_POS2) {
m_vecPos1 = vecDest;
m_moverState = MOVER_2TO1;
} else {
m_moverState = MOVER_1TO2;
m_vecPos2 = vecDest;
}
}
if (!flSpeed) {
NSLog("NSMoverEntity::RotateToPosition: No speed defined!");
Respawn();
return;
}
RotateToPosition_SetDest(vDestAngle);
vecAngleDifference = (vDestAngle - angles);
flTravelLength = vlen(vecAngleDifference);
flTravelTime = (flTravelLength / flSpeed);
/* Avoid NAN hack */
if (flTravelTime <= 0.0f) {
if (m_moverState == MOVER_1TO2) {
_RotatedToPosition2();
} else if (m_moverState == MOVER_2TO1) {
_RotatedToPosition1();
}
} else {
SetAngularVelocity((vecAngleDifference * (1 / flTravelTime)));
RotateToPosition_Done(flTravelTime);
}
}
void
NSMoverEntity::RotateToReverse(float flSpeed)
{
if ((GetMoverState() == MOVER_POS2) || (GetMoverState() == MOVER_1TO2)){
RotateToPosition(GetPosition1(), flSpeed);
} else {
RotateToPosition(GetPosition2(), flSpeed);
}
}
bool
NSMoverEntity::IsMoving(void)
{
switch (GetMoverState()) {
case MOVER_POS1:
case MOVER_POS2:
return false;
break;
default:
return true;
}
}
void
NSMoverEntity::_PortalOpen(void)
{
if (m_iPortalState == 1)
return;
m_iPortalState = 1;
setorigin(this, origin);
openportal(this, AREAPORTAL_OPEN);
}
void
NSMoverEntity::_PortalClose(void)
{
if (m_iPortalState == 0)
return;
m_iPortalState = 0;
setorigin(this, origin);
openportal(this, AREAPORTAL_CLOSED);
}
void
NSMoverEntity::_ArrivedAtPosition1(void)
{
SetOrigin(m_vecPos1);
ClearVelocity();
ReleaseThink();
m_moverState = MOVER_POS1;
_PortalClose();
MoverFinishesMoving();
}
void
NSMoverEntity::_ArrivedAtPosition2(void)
{
SetOrigin(m_vecPos2);
ClearVelocity();
ReleaseThink();
m_moverState = MOVER_POS2;
MoverFinishesMoving();
}
void
NSMoverEntity::_RotatedToPosition1(void)
{
SetAngles(m_vecPos1);
ClearVelocity();
ReleaseThink();
m_moverState = MOVER_POS1;
_PortalClose();
MoverFinishesMoving();
}
void
NSMoverEntity::_RotatedToPosition2(void)
{
SetAngles(m_vecPos2);
ClearVelocity();
ReleaseThink();
m_moverState = MOVER_POS2;
MoverFinishesMoving();
}
void
NSMoverEntity::_BeginMoving(void)
{
}
void
NSMoverEntity::MoverStartsMoving(void)
{
}
void
NSMoverEntity::MoverFinishesMoving(void)
{
}

View File

@ -52,6 +52,7 @@ string __fullspawndata;
#include "NSTimer.h"
#include "NSRenderableEntity.h"
#include "NSSurfacePropEntity.h"
#include "NSMoverEntity.h"
#include "NSPhysicsEntity.h"
#include "NSBrushTrigger.h"
#include "NSPointTrigger.h"

View File

@ -6,6 +6,7 @@ NSEntity.qc
NSTimer.qc
NSRenderableEntity.qc
NSSurfacePropEntity.qc
NSMoverEntity.qc
NSPhysicsEntity.qc
NSBrushTrigger.qc
NSPointTrigger.qc