nuclide/Source/gs-entbase/server/func_door_rotating.cpp

350 lines
7 KiB
C++

/***
*
* Copyright (c) 2016-2019 Marco 'eukara' Hladik. All rights reserved.
*
* See the file LICENSE attached with the sources for usage details.
*
****/
#define SF_ROT_OPEN 1
#define SF_ROT_BACKWARDS 2
#define SF_ROT_PASSABLE 8
#define SF_ROT_ONEWAY 16
#define SF_ROT_TOGGLE 32
#define SF_ROT_ZAXIS 64
#define SF_ROT_XAXIS 128
#define SF_ROT_USE 256
#define SF_DOOR_NOMONSTERS 512
#define SF_DOOR_SILENT 0x80000000i
class func_door_rotating:CBaseTrigger
{
int m_iMoveSnd;
int m_iStopSnd;
int m_iDamage;
int m_iLocked;
float m_flDistance;
float m_flSpeed;
float m_flLip;
float m_iState;
float m_flNextAction;
float m_flWait;
float m_flDelay;
vector m_vecDest;
vector m_vecPos1;
vector m_vecPos2;
vector m_vecMoveDir;
virtual void() m_pMove = 0;
void() func_door_rotating;
virtual void() Respawn;
virtual void() Precache;
virtual void() Arrived;
virtual void() Returned;
virtual void() RotateBack;
virtual void() RotateAway;
virtual void() Trigger;
virtual void() Use;
virtual void() Touch;
virtual void() Blocked;
virtual void() SetMovementDirection;
virtual void(vector angle, void() func) RotateToDestination;
virtual void() RotateToDestination_End;
};
void func_door_rotating::Precache(void)
{
if (m_iMoveSnd > 0 && m_iMoveSnd <= 10) {
precache_sound(sprintf("doors/doormove%i.wav", m_iMoveSnd));
} else {
precache_sound("common/null.wav");
}
if (m_iStopSnd > 0 && m_iStopSnd <= 8) {
precache_sound(sprintf("doors/doorstop%i.wav", m_iStopSnd));
} else {
precache_sound("common/null.wav");
}
}
void func_door_rotating::Arrived(void)
{
m_iState = STATE_RAISED;
if (m_iStopSnd > 0 && m_iStopSnd <= 8) {
sound(this, CHAN_VOICE, sprintf("doors/doorstop%i.wav", m_iStopSnd), 1.0, ATTN_NORM);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0, ATTN_NORM);
}
if (!(spawnflags & SF_ROT_USE)) {
touch = Touch;
}
if (m_flWait < 0) {
return;
}
think = RotateBack;
nextthink = (ltime + m_flWait);
}
void func_door_rotating::Returned(void)
{
if (!(spawnflags & SF_ROT_USE)) {
touch = Touch;
}
m_iState = STATE_LOWERED;
}
void func_door_rotating::RotateBack(void)
{
if (m_iMoveSnd > 0 && m_iMoveSnd <= 10) {
sound(this, CHAN_VOICE, sprintf("doors/doormove%i.wav", m_iMoveSnd), 1.0, ATTN_NORM);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0, ATTN_NORM);
}
if (!(spawnflags & SF_ROT_USE)) {
touch = __NULL__;
}
m_iState = STATE_DOWN;
RotateToDestination(m_vecPos1, Returned);
}
void func_door_rotating::RotateAway(void)
{
float fDirection = 1.0;
if (m_iState == STATE_UP) {
return;
}
if (m_iMoveSnd > 0 && m_iMoveSnd <= 10) {
sound(this, CHAN_VOICE, sprintf("doors/doormove%i.wav", m_iMoveSnd), 1.0, ATTN_NORM);
} else {
sound(this, CHAN_VOICE, "common/null.wav", 1.0, ATTN_NORM);
}
if (m_iState == STATE_RAISED) {
nextthink = (ltime + m_flWait);
return;
}
m_iState = STATE_UP;
if (!(spawnflags & SF_ROT_ONEWAY)) {
/* One way doors only work on the Y axis */
if (!(spawnflags & SF_ROT_ZAXIS || spawnflags & SF_ROT_XAXIS)) {
vector vDifference = eActivator.origin - origin;
vector vAngles = eActivator.angles;
vAngles[0] = vAngles[2] = 0;
makevectors(vAngles);
vector vNext = (eActivator.origin + (v_forward * 10)) - origin;
if (((vDifference[0] * vNext[1]) - (vDifference[1] * vNext[0])) < 0) {
fDirection = -1.0f;
}
}
}
RotateToDestination(m_vecPos2 * fDirection, Arrived);
}
void func_door_rotating::Trigger(void)
{
if (m_flNextAction > time) {
return;
}
m_flNextAction = time + m_flWait;
if ((m_iState == STATE_UP) || (m_iState == STATE_RAISED)) {
RotateBack();
return;
}
RotateAway();
if (m_flDelay) {
#ifdef GS_DEVELOPER
print(sprintf("func_door_rotating: Delayed trigger of `%s`\n", m_strTarget));
#endif
CBaseTrigger::UseTargets_Delay(m_flDelay);
} else {
#ifdef GS_DEVELOPER
print(sprintf("func_door_rotating: Normal trigger of `%s`\n", m_strTarget));
#endif
CBaseTrigger::UseTargets();
}
}
void func_door_rotating::Use(void)
{
eActivator.gflags &= ~GF_USE_RELEASED;
Trigger();
}
void func_door_rotating::Touch(void)
{
if (spawnflags & SF_ROT_USE) {
return;
}
if (m_iLocked) {
return;
}
if (other.movetype == MOVETYPE_WALK) {
if (other.absmin[2] <= maxs[2] - 2) {
eActivator = other;
Trigger();
}
}
touch = __NULL__;
}
void func_door_rotating::Blocked(void)
{
if (m_iDamage) {
Damage_Apply(other, this, m_iDamage, other.origin, FALSE);
}
if (m_flWait >= 0) {
if (m_iState == STATE_DOWN) {
RotateAway();
} else {
RotateBack();
}
}
}
void func_door_rotating::SetMovementDirection(void)
{
if (spawnflags & SF_ROT_ZAXIS) {
m_vecMoveDir = [0,0,1];
} else if (spawnflags & SF_ROT_XAXIS) {
m_vecMoveDir = [1,0,0];
} else {
m_vecMoveDir = [0,1,0];
}
if (spawnflags & SF_ROT_BACKWARDS) {
m_vecMoveDir *= 1;
}
}
void func_door_rotating::RotateToDestination_End(void)
{
angles = m_vecDest;
avelocity = [0,0,0];
nextthink = -1;
m_pMove();
}
void func_door_rotating::RotateToDestination(vector vDestinationAngle, void() func)
{
vector vecAngleDifference;
float flTravelLength, flTravelTime;
if (!m_flSpeed) {
objerror("No speed defined for moving entity! Will not divide by zero.");
}
vecAngleDifference = (vDestinationAngle - angles);
flTravelLength = vlen(vecAngleDifference);
flTravelTime = (flTravelLength / m_flSpeed);
avelocity = (vecAngleDifference * (1 / flTravelTime));
m_vecDest = vDestinationAngle;
m_pMove = func;
think = RotateToDestination_End;
nextthink = (ltime + flTravelTime);
}
void func_door_rotating::Respawn(void)
{
func_door_rotating::SetMovementDirection();
if (!m_flSpeed) {
m_flSpeed = 100;
}
if (!m_flLip) {
m_flLip = 90;
}
if (!m_flDelay) {
m_flDelay = 4;
}
if (!m_flDistance) {
m_flDistance = 90;
}
solid = SOLID_BSP;
movetype = MOVETYPE_PUSH;
setorigin(this, m_oldOrigin);
setmodel(this, m_oldModel);
think = __NULL__;
nextthink = -1;
m_pMove = 0;
avelocity = [0,0,0];
blocked = Blocked;
if (spawnflags & SF_ROT_USE) {
touch = __NULL__;
PlayerUse = Use;
} else {
touch = Touch;
PlayerUse = __NULL__;
}
m_iState = STATE_LOWERED;
m_vecPos1 = m_oldAngle;
m_vecPos2 = m_oldAngle + m_vecMoveDir * m_flDistance;
if (spawnflags & SF_ROT_OPEN) {
vector vTemp = m_vecPos2;
m_vecPos2 = m_vecPos1;
m_vecPos1 = vTemp;
m_vecMoveDir = m_vecMoveDir * -1;
}
if (m_strTargetName) {
m_iLocked = TRUE;
}
angles = m_vecPos1;
}
void func_door_rotating::func_door_rotating(void)
{
for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) {
switch (argv(i)) {
case "speed":
m_flSpeed = stof(argv(i+1));
break;
case "lip":
m_flLip = stof(argv(i+1));
break;
case "movesnd":
m_iMoveSnd = stoi(argv(i+1));
break;
case "stopsnd":
m_iStopSnd = stoi(argv(i+1));
break;
case "distance":
m_flDistance = stof(argv(i+1));
break;
case "delay":
m_flDelay = stof(argv(i+1));
break;
case "dmg":
m_iDamage = stoi(argv(i+1));
break;
default:
break;
}
}
func_door_rotating::Precache();
CBaseEntity::CBaseEntity();
func_door_rotating::Respawn();
}