func_tracktrain: Lots of improvements across the board. Enjoy c0a0-c0a0e!
func_trackchange/autochange: Initial implementation.
This commit is contained in:
parent
7e8d1aacdb
commit
06d959ef02
20 changed files with 1599 additions and 228 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -55,6 +55,9 @@ Entity_EntityUpdate(float type, float new)
|
|||
NSENTITY_READENTITY(speaker, new)
|
||||
self.customphysics = Empty;
|
||||
break;
|
||||
case ENT_TRACKTRAIN:
|
||||
NSENTITY_READENTITY(func_tracktrain, new)
|
||||
break;
|
||||
case ENT_VEHICLE:
|
||||
NSENTITY_READENTITY(NSVehicle, new)
|
||||
break;
|
||||
|
|
|
@ -49,8 +49,7 @@ server/func_door_rotating.qc
|
|||
server/func_lod.qc
|
||||
server/func_train.qc
|
||||
server/func_guntarget.qc
|
||||
server/func_tracktrain.qc
|
||||
server/func_tracktraincontrols.qc
|
||||
server/func_traincontrols.qc
|
||||
server/func_tank.qc
|
||||
server/func_tankcontrols.qc
|
||||
server/func_pushable.qc
|
||||
|
@ -63,6 +62,8 @@ server/func_platrot.qc
|
|||
server/func_pendulum.qc
|
||||
server/func_vehiclecontrols.qc
|
||||
server/func_monsterclip.qc
|
||||
server/func_trackchange.qc
|
||||
server/func_trackautochange.qc
|
||||
server/light.qc
|
||||
server/logic_auto.qc
|
||||
server/logic_relay.qc
|
||||
|
|
42
src/gs-entbase/server/func_trackautochange.qc
Normal file
42
src/gs-entbase/server/func_trackautochange.qc
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
class
|
||||
func_trackautochange:func_trackchange
|
||||
{
|
||||
void func_trackautochange(void);
|
||||
|
||||
virtual void MoverFinishesMoving(void);
|
||||
};
|
||||
|
||||
void
|
||||
func_trackautochange::func_trackautochange(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
func_trackautochange::MoverFinishesMoving(void)
|
||||
{
|
||||
NSEntity ourTrain = (NSEntity)find(world, ::targetname, m_strTrainName);
|
||||
super::MoverFinishesMoving();
|
||||
|
||||
if (ourTrain) {
|
||||
ourTrain.Trigger(this, TRIG_TOGGLE);
|
||||
}
|
||||
}
|
171
src/gs-entbase/server/func_trackchange.qc
Normal file
171
src/gs-entbase/server/func_trackchange.qc
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
enumflags
|
||||
{
|
||||
FNCTRACKCHANGE_UNUSED1,
|
||||
FNCTRACKCHANGE_UNUSED2,
|
||||
FNCTRACKCHANGE_BOTTOM,
|
||||
FNCTRACKCHANGE_NOMOVE,
|
||||
FNCTRACKCHANGE_UNUSED3,
|
||||
FNCTRACKCHANGE_XAXIS,
|
||||
FNCTRACKCHANGE_YAXIS,
|
||||
};
|
||||
|
||||
/*!QUAKED func_trackchange (0 .5 .8) ? x x x BOTTOM NOMOVE x X_AXIS Y_AXIS
|
||||
# OVERVIEW
|
||||
A rotating, moving platform that will transport func_tracktrain entities between two path_track entities.
|
||||
|
||||
# KEYS
|
||||
- "targetname" : Name
|
||||
- "height" : Travel altitude in game units.
|
||||
- "rotation" : Amount of spinning rotation in degrees.
|
||||
- "train" : Name of the train to be switched.
|
||||
- "toptrack" : Name of the top track.
|
||||
- "bottomtrack" : Name of the bottom track.
|
||||
- "speed" : Movement and rotation speed in game units per second.
|
||||
|
||||
# SPAWNFLAGS
|
||||
- BOTTOM (8) : Start at the bottom track.
|
||||
- NOMOVE (16) : Only rotate, don't move.
|
||||
- X_AXIS (64) : Rotate on the X-Axis.
|
||||
- Y_AXIS (128) : Rotate on the Y-Axis.
|
||||
|
||||
# NOTES
|
||||
This version of the entity is designed for interactive trains. If you want to use them
|
||||
with automated (trigger controlled) func_tracktrain entities, use func_trackautochange.
|
||||
|
||||
# TRIVIA
|
||||
This entity was introduced in Half-Life (1998).
|
||||
*/
|
||||
class
|
||||
func_trackchange:func_platrot
|
||||
{
|
||||
public:
|
||||
void func_trackchange(void);
|
||||
|
||||
/* overrides */
|
||||
virtual void SpawnKey(string,string);
|
||||
virtual void Spawned(void);
|
||||
virtual void Save(float);
|
||||
virtual void Restore(string,string);
|
||||
virtual void MoverFinishesMoving(void);
|
||||
virtual void MoverStartsMoving(void);
|
||||
|
||||
private:
|
||||
string m_strTrainName;
|
||||
string m_strTopTrack;
|
||||
string m_strBottomTrack;
|
||||
};
|
||||
|
||||
void
|
||||
func_trackchange::func_trackchange(void)
|
||||
{
|
||||
m_strTrainName = __NULL__;
|
||||
m_strTopTrack = __NULL__;
|
||||
m_strBottomTrack = __NULL__;
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::SpawnKey(string keyName, string setValue)
|
||||
{
|
||||
switch (keyName) {
|
||||
case "train":
|
||||
m_strTrainName = ReadString(setValue);
|
||||
break;
|
||||
case "toptrack":
|
||||
m_strTopTrack = ReadString(setValue);
|
||||
break;
|
||||
case "bottomtrack":
|
||||
m_strBottomTrack = ReadString(setValue);
|
||||
break;
|
||||
default:
|
||||
super::SpawnKey(keyName, setValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::Spawned(void)
|
||||
{
|
||||
spawnflags |= 1;
|
||||
super::Spawned();
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::Save(float handle)
|
||||
{
|
||||
super::Save(handle);
|
||||
SaveString(handle, "m_strTrainName", m_strTrainName);
|
||||
SaveString(handle, "m_strTopTrack", m_strTopTrack);
|
||||
SaveString(handle, "m_strBottomTrack", m_strBottomTrack);
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::Restore(string keyName, string setValue)
|
||||
{
|
||||
switch (keyName) {
|
||||
case "m_strTrainName":
|
||||
m_strTrainName = ReadString(setValue);
|
||||
break;
|
||||
case "m_strTopTrack":
|
||||
m_strTopTrack = ReadString(setValue);
|
||||
break;
|
||||
case "m_strBottomTrack":
|
||||
m_strBottomTrack = ReadString(setValue);
|
||||
break;
|
||||
default:
|
||||
super::Restore(keyName, setValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::MoverStartsMoving(void)
|
||||
{
|
||||
NSEntity ourTrain = (NSEntity)find(world, ::targetname, m_strTrainName);
|
||||
super::MoverStartsMoving();
|
||||
|
||||
if (ourTrain) {
|
||||
ourTrain.target = __NULL__;
|
||||
ourTrain.SetVelocity(GetVelocity());
|
||||
ourTrain.SetAngularVelocity(GetAngularVelocity());
|
||||
ourTrain.ScheduleThink(ClearVelocity, 100.0f);
|
||||
print(sprintf("Changing %s to have no target\n", m_strTrainName));
|
||||
print(sprintf("%v %v\n", GetVelocity(), GetAngularVelocity()));
|
||||
} else {
|
||||
print(sprintf("No train to go with trackchange %s\n", targetname));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
func_trackchange::MoverFinishesMoving(void)
|
||||
{
|
||||
NSEntity ourTrain = (NSEntity)find(world, ::targetname, m_strTrainName);
|
||||
super::MoverFinishesMoving();
|
||||
|
||||
if (ourTrain) {
|
||||
ourTrain.ClearVelocity();
|
||||
|
||||
if (GetMoverState() == MOVER_POS1) {
|
||||
print(sprintf("Changing %s from %s to %s\n", m_strTrainName, m_strBottomTrack, m_strTopTrack));
|
||||
ourTrain.target = m_strTopTrack;
|
||||
} else {
|
||||
print(sprintf("Changing %s from %s to %s\n", m_strTrainName, m_strBottomTrack, m_strBottomTrack));
|
||||
ourTrain.target = m_strBottomTrack;
|
||||
}
|
||||
} else {
|
||||
print(sprintf("No train to go with trackchange %s\n", targetname));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -44,6 +44,8 @@ func_traincontrols::func_traincontrols(void)
|
|||
void
|
||||
func_traincontrols::Respawn(void)
|
||||
{
|
||||
InitBrushTrigger();
|
||||
ClearAngles();
|
||||
}
|
||||
SetOrigin(GetSpawnOrigin());
|
||||
SetModel(GetSpawnModel());
|
||||
SetSolid(SOLID_TRIGGER);
|
||||
SetParent(target);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -26,6 +26,9 @@ Node entities used for func_trains and func_guntargets.
|
|||
- "yaw_speed" : New yaw rotation for passing train. Currently unused.
|
||||
- "wait" : Waiting time until we go to the next node.
|
||||
|
||||
# INPUTS
|
||||
- "OnPass" : Triggered when a 'train' passes over this node.
|
||||
|
||||
# SPAWNFLAGS
|
||||
- PC_WAIT (1) : Train will stop moving once passed. Needs retrigger to progress.
|
||||
- PC_TELEPORT (2) : Train passing will immediately teleport to "target".
|
||||
|
@ -52,17 +55,26 @@ path_corner:NSPointTrigger
|
|||
public:
|
||||
void path_corner(void);
|
||||
|
||||
virtual void Spawned(void);
|
||||
virtual void Save(float);
|
||||
virtual void Restore(string,string);
|
||||
virtual void SpawnKey(string,string);
|
||||
virtual void Respawn(void);
|
||||
virtual void Trigger(entity, triggermode_t);
|
||||
virtual string GetPathTarget(void);
|
||||
virtual string GetSelfTarget(void);
|
||||
virtual path_corner GetPathTargetEntity(void);
|
||||
virtual path_corner GetSelfTargetEntity(void);
|
||||
virtual bool DisablesTrain(void);
|
||||
|
||||
virtual void PathPassTrigger(entity, triggermode_t);
|
||||
|
||||
private:
|
||||
int m_iFired;
|
||||
float m_flSpeed;
|
||||
float m_flYawSpeed;
|
||||
float m_flWait;
|
||||
string m_strOnPass;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -72,6 +84,66 @@ path_corner::path_corner(void)
|
|||
m_flSpeed = 0.0f;
|
||||
m_flYawSpeed = 0.0f;
|
||||
m_flWait = 1.0f;
|
||||
m_strOnPass = __NULL__;
|
||||
}
|
||||
|
||||
void
|
||||
path_corner::Spawned(void)
|
||||
{
|
||||
super::Spawned();
|
||||
|
||||
if (m_strOnPass)
|
||||
m_strOnPass = CreateOutput(m_strOnPass);
|
||||
}
|
||||
|
||||
string
|
||||
path_corner::GetPathTarget(void)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
bool
|
||||
path_corner::DisablesTrain(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
string
|
||||
path_corner::GetSelfTarget(void)
|
||||
{
|
||||
for (path_corner f = __NULL__; (f = (path_corner)find(f, ::classname, "path_corner"));) {
|
||||
if (f.GetPathTarget() == targetname) {
|
||||
return f.targetname;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
path_corner
|
||||
path_corner::GetPathTargetEntity(void)
|
||||
{
|
||||
string theTarget = GetPathTarget();
|
||||
|
||||
for (path_corner f = __NULL__; (f = (path_corner)find(f, ::classname, "path_corner"));) {
|
||||
if (f.targetname == theTarget) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
path_corner
|
||||
path_corner::GetSelfTargetEntity(void)
|
||||
{
|
||||
for (path_corner f = __NULL__; (f = (path_corner)find(f, ::classname, "path_corner"));) {
|
||||
if (f.GetPathTarget() == targetname) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -82,6 +154,7 @@ path_corner::Save(float handle)
|
|||
SaveFloat(handle, "m_flSpeed", m_flSpeed);
|
||||
SaveFloat(handle, "m_flYawSpeed", m_flYawSpeed);
|
||||
SaveFloat(handle, "m_flWait", m_flWait);
|
||||
SaveString(handle, "m_strOnPass", m_strOnPass);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -100,6 +173,9 @@ path_corner::Restore(string strKey, string strValue)
|
|||
case "m_flWait":
|
||||
m_flWait = ReadFloat(strValue);
|
||||
break;
|
||||
case "m_strOnPass":
|
||||
m_strOnPass = ReadString(strValue);
|
||||
break;
|
||||
default:
|
||||
super::Restore(strKey, strValue);
|
||||
}
|
||||
|
@ -121,6 +197,10 @@ path_corner::SpawnKey(string strKey, string strValue)
|
|||
case "message":
|
||||
m_strMessage = ReadString(strValue);
|
||||
break;
|
||||
/* I/O system */
|
||||
case "OnPass":
|
||||
m_strOnPass = PrepareOutput(m_strOnPass, strValue);
|
||||
break;
|
||||
default:
|
||||
super::SpawnKey(strKey, strValue);
|
||||
}
|
||||
|
@ -141,18 +221,32 @@ path_corner::Respawn(void)
|
|||
void
|
||||
path_corner::Trigger(entity act, triggermode_t state)
|
||||
{
|
||||
entity a;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
path_corner::PathPassTrigger(entity activatingEntity, triggermode_t triggerMode)
|
||||
{
|
||||
if (HasSpawnFlags(PC_FIREONCE) && m_iFired) {
|
||||
NSLog("path_corner (%s) can only fire its targets once", targetname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_strMessage)
|
||||
for (a = world; (a = find(a, ::targetname, m_strMessage));) {
|
||||
NSEntity trigger = (NSEntity)a;
|
||||
trigger.Trigger(act, state);
|
||||
m_iFired = TRUE;
|
||||
NSLog("path_corner (%s) fired its %S targets", targetname, m_strMessage);
|
||||
UseOutput(this, m_strOnPass);
|
||||
|
||||
if (!m_strMessage)
|
||||
return;
|
||||
|
||||
for (entity f = world; (f = find(f, ::targetname, m_strMessage));) {
|
||||
NSTrigger trigger = (NSTrigger)f;
|
||||
|
||||
NSLog("^2%s::^3PathPassTrigger^7:" \
|
||||
"Triggering %s `%s` from %s", \
|
||||
classname, f.classname, \
|
||||
trigger.targetname, activatingEntity.classname);
|
||||
|
||||
if (trigger.Trigger != __NULL__) {
|
||||
trigger.Trigger(activatingEntity, triggerMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -14,7 +14,15 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*!QUAKED path_track (.5 .3 0) (-8 -8 -8) (8 8 8)
|
||||
enumflags
|
||||
{
|
||||
PATHTRACK_DISABLED,
|
||||
PATHTRACK_FIREONCE,
|
||||
PATHTRACK_BRANCHREVERSE,
|
||||
PATHTRACK_DISABLETRAIN
|
||||
};
|
||||
|
||||
/*!QUAKED path_track (.5 .3 0) (-8 -8 -8) (8 8 8) DISABLED FIRE_ONCE BRANCHREVERSE DISABLETRAIN
|
||||
# OVERVIEW
|
||||
Node entities used for func_tracktrains.
|
||||
It's like a path_corner, but for tracktrains.
|
||||
|
@ -23,6 +31,22 @@ It's like a path_corner, but for tracktrains.
|
|||
- "targetname" : Name
|
||||
- "target" : Target when triggered.
|
||||
- "killtarget" : Target to kill when triggered.
|
||||
- "altpath" : When enabled, will point to this instead.
|
||||
- "netname" : Target to trigger when the train gets stopped here.
|
||||
|
||||
# INPUTS
|
||||
- "ToggleAlternatePath" : Toggles between `target` and `altpath`.
|
||||
- "EnableAlternatePath" : Next node will be the one set in `altpath`.
|
||||
- "DisableAlternatePath" : Next node will be the one set in `target`.
|
||||
- "TogglePath" : Toggles the ability to use this node.
|
||||
- "EnablePath" : Enables the ability to use this node.
|
||||
- "DisablePath" : Disables the ability to use this node.
|
||||
|
||||
# SPAWNFLAGS
|
||||
- DISABLED (1) : Start disabled.
|
||||
- FIRE_ONCE (2) : Fire pass target once.
|
||||
- BRANCHREVERSE (4) : Complicated.
|
||||
- DISABLETRAIN (8) : Disables train when it passes.
|
||||
|
||||
# TRIVIA
|
||||
This entity was introduced in Half-Life (1998).
|
||||
|
@ -31,4 +55,228 @@ This entity was introduced in Half-Life (1998).
|
|||
class
|
||||
path_track:path_corner
|
||||
{
|
||||
public:
|
||||
void path_track(void);
|
||||
|
||||
nonvirtual void PathEndTrigger(entity, triggermode_t);
|
||||
|
||||
/* overrides */
|
||||
virtual void Respawn(void);
|
||||
virtual void SpawnKey(string, string);
|
||||
virtual void Save(float);
|
||||
virtual void Restore(string,string);
|
||||
virtual void Trigger(entity, triggermode_t);
|
||||
virtual void Input(entity, string, string);
|
||||
virtual string GetPathTarget(void);
|
||||
virtual string GetSelfTarget(void);
|
||||
virtual path_corner GetPathTargetEntity(void);
|
||||
virtual path_corner GetSelfTargetEntity(void);
|
||||
virtual bool DisablesTrain(void);
|
||||
|
||||
private:
|
||||
bool m_bTrackEnabled;
|
||||
bool m_bAltPath;
|
||||
string m_strAltPath;
|
||||
string m_strEndTrigger;
|
||||
};
|
||||
|
||||
void
|
||||
path_track::path_track(void)
|
||||
{
|
||||
m_bAltPath = false;
|
||||
m_bTrackEnabled = true;
|
||||
m_strAltPath = __NULL__;
|
||||
m_strEndTrigger = __NULL__;
|
||||
}
|
||||
|
||||
void
|
||||
path_track::SpawnKey(string keyName, string setValue)
|
||||
{
|
||||
switch (keyName) {
|
||||
case "altpath":
|
||||
m_strAltPath = ReadString(setValue);
|
||||
break;
|
||||
case "netname":
|
||||
m_strEndTrigger = ReadString(setValue);
|
||||
break;
|
||||
default:
|
||||
super::SpawnKey(keyName, setValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
path_track::Respawn(void)
|
||||
{
|
||||
m_bTrackEnabled = HasSpawnFlags(PATHTRACK_DISABLED) ? false : true;
|
||||
}
|
||||
|
||||
void
|
||||
path_track::Save(float handle)
|
||||
{
|
||||
super::Save(handle);
|
||||
SaveBool(handle, "m_bAltPath", m_bAltPath);
|
||||
SaveBool(handle, "m_bTrackEnabled", m_bTrackEnabled);
|
||||
SaveString(handle, "m_strAltPath", m_strAltPath);
|
||||
SaveString(handle, "m_strEndTrigger", m_strEndTrigger);
|
||||
}
|
||||
|
||||
void
|
||||
path_track::Restore(string strKey, string strValue)
|
||||
{
|
||||
switch (strKey) {
|
||||
case "m_bAltPath":
|
||||
m_bAltPath = ReadBool(strValue);
|
||||
break;
|
||||
case "m_bTrackEnabled":
|
||||
m_bTrackEnabled = ReadBool(strValue);
|
||||
break;
|
||||
case "m_strAltPath":
|
||||
m_strAltPath = ReadString(strValue);
|
||||
break;
|
||||
case "m_strEndTrigger":
|
||||
m_strEndTrigger = ReadString(strValue);
|
||||
break;
|
||||
default:
|
||||
super::Restore(strKey, strValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
path_track::Input(entity activatingEntity, string inputName, string dataField)
|
||||
{
|
||||
switch (inputName) {
|
||||
case "ToggleAlternatePath":
|
||||
Trigger(activatingEntity, TRIG_TOGGLE);
|
||||
break;
|
||||
case "EnableAlternatePath":
|
||||
Trigger(activatingEntity, TRIG_ON);
|
||||
break;
|
||||
case "DisableAlternatePath":
|
||||
Trigger(activatingEntity, TRIG_OFF);
|
||||
break;
|
||||
case "TogglePath":
|
||||
m_bTrackEnabled ^= true;
|
||||
break;
|
||||
case "EnablePath":
|
||||
m_bTrackEnabled = true;
|
||||
break;
|
||||
case "DisablePath":
|
||||
m_bTrackEnabled = false;
|
||||
break;
|
||||
default:
|
||||
super::Input(activatingEntity, inputName, dataField);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
path_track::Trigger(entity activatingEntity, triggermode_t triggerMode)
|
||||
{
|
||||
/* no idea if this is accurate behaviour, but it should be compatible */
|
||||
if (m_strAltPath) {
|
||||
switch (triggerMode) {
|
||||
case TRIG_ON:
|
||||
m_bAltPath = true;
|
||||
break;
|
||||
case TRIG_OFF:
|
||||
m_bAltPath = false;
|
||||
break;
|
||||
default:
|
||||
m_bAltPath ^= true;
|
||||
}
|
||||
} else {
|
||||
switch (triggerMode) {
|
||||
case TRIG_ON:
|
||||
m_bTrackEnabled = true;
|
||||
break;
|
||||
case TRIG_OFF:
|
||||
m_bTrackEnabled = false;
|
||||
break;
|
||||
default:
|
||||
m_bTrackEnabled ^= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
path_track::DisablesTrain(void)
|
||||
{
|
||||
return HasSpawnFlags(PATHTRACK_DISABLETRAIN) ? true : false;
|
||||
}
|
||||
|
||||
string
|
||||
path_track::GetPathTarget(void)
|
||||
{
|
||||
string theTarget = target;
|
||||
|
||||
if (m_bTrackEnabled == false){
|
||||
return targetname;
|
||||
}
|
||||
|
||||
if (!target) {
|
||||
theTarget = targetname;
|
||||
}
|
||||
|
||||
if (!m_strAltPath) {
|
||||
return theTarget;
|
||||
}
|
||||
|
||||
return (m_bAltPath == false) ? theTarget : m_strAltPath;
|
||||
}
|
||||
|
||||
string
|
||||
path_track::GetSelfTarget(void)
|
||||
{
|
||||
for (path_track f = __NULL__; (f = (path_track)find(f, ::classname, "path_track"));) {
|
||||
if (f.GetPathTarget() == targetname) {
|
||||
return f.targetname;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
path_corner
|
||||
path_track::GetPathTargetEntity(void)
|
||||
{
|
||||
string theTarget = GetPathTarget();
|
||||
|
||||
for (path_track f = __NULL__; (f = (path_track)find(f, ::classname, "path_track"));) {
|
||||
if (f.targetname == theTarget && f.m_bTrackEnabled == true) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
path_corner
|
||||
path_track::GetSelfTargetEntity(void)
|
||||
{
|
||||
for (path_track f = __NULL__; (f = (path_track)find(f, ::classname, "path_track"));) {
|
||||
if (f.GetPathTarget() == targetname) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
return __NULL__;
|
||||
}
|
||||
|
||||
void
|
||||
path_track::PathEndTrigger(entity activatingEntity, triggermode_t triggerMode)
|
||||
{
|
||||
if (!m_strEndTrigger)
|
||||
return;
|
||||
|
||||
for (entity f = world; (f = find(f, ::targetname, m_strEndTrigger));) {
|
||||
NSTrigger trigger = (NSTrigger)f;
|
||||
|
||||
NSLog("^2%s::^3PathEndTrigger^7:" \
|
||||
"Triggering %s `%s` from %s", \
|
||||
classname, f.classname, \
|
||||
trigger.targetname, activatingEntity.classname);
|
||||
|
||||
if (trigger.Trigger != __NULL__) {
|
||||
trigger.Trigger(activatingEntity, triggerMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -142,11 +142,13 @@ trigger_auto_trigger(void)
|
|||
trigger_auto loop;
|
||||
|
||||
/* don't do it more than once */
|
||||
if (called)
|
||||
if (called) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (loop = __NULL__; (loop = (trigger_auto)find(loop, ::classname, "trigger_auto"));) {
|
||||
loop.Processing();
|
||||
loop.ScheduleThink(trigger_auto::Processing, 0.25f);
|
||||
}
|
||||
|
||||
called = true;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -222,6 +222,8 @@ trigger_changelevel::IsInside(entity ePlayer, entity eVolume)
|
|||
void
|
||||
trigger_changelevel::Change(void)
|
||||
{
|
||||
trigger_transition transitionHelper = __NULL__;
|
||||
|
||||
/* needed for logic_auto */
|
||||
cvar_set("_bsp_change_auto", "1");
|
||||
|
||||
|
@ -230,6 +232,7 @@ trigger_changelevel::Change(void)
|
|||
NSLog("^2trigger_changelevel::^3Change^7: Change to `%s`",
|
||||
m_strMap);
|
||||
parm_string = m_strChangeTarget;
|
||||
trigger_transition_pvsfallback(this);
|
||||
changelevel(m_strMap);
|
||||
return;
|
||||
}
|
||||
|
@ -247,10 +250,13 @@ trigger_changelevel::Change(void)
|
|||
}
|
||||
|
||||
if (m_strLandmark) {
|
||||
for (entity e = world; (e = find(e, ::classname, "trigger_transition"));) {
|
||||
if (e.targetname == m_strLandmark)
|
||||
if (IsInside(m_activator, e) == FALSE)
|
||||
for (entity e = world; (e = find(e, ::classname, "trigger_transition"));) {
|
||||
transitionHelper = (trigger_transition)e;
|
||||
|
||||
if (e.targetname == m_strLandmark) {
|
||||
if (IsInside(m_activator, e) == false)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,19 +265,17 @@ trigger_changelevel::Change(void)
|
|||
info_landmark lm = (info_landmark)e;
|
||||
/* found it */
|
||||
if (lm.targetname == m_strLandmark) {
|
||||
trigger_transition t;
|
||||
NSLog("^2trigger_changelevel::^3Change^7: Found landmark for %s", m_strLandmark);
|
||||
g_landmarkpos = m_activator.origin - lm.origin;
|
||||
|
||||
/* time to transition */
|
||||
t = (trigger_transition)find(world, ::targetname, m_strLandmark);
|
||||
|
||||
if (t) {
|
||||
t.SaveTransition();
|
||||
if (transitionHelper) {
|
||||
transitionHelper.SaveTransition(__NULL__, false);
|
||||
} else {
|
||||
trigger_transition_pvsfallback(this);
|
||||
}
|
||||
|
||||
changelevel(m_strMap, m_strLandmark);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +283,7 @@ trigger_changelevel::Change(void)
|
|||
void
|
||||
trigger_changelevel::Trigger(entity act, triggermode_t unused)
|
||||
{
|
||||
if (GetMaster(act) == FALSE)
|
||||
if (GetMaster(act) == false)
|
||||
return;
|
||||
|
||||
/* disable meself */
|
||||
|
@ -303,6 +307,9 @@ trigger_changelevel::Touch(entity eToucher)
|
|||
if (!(eToucher.flags & FL_CLIENT))
|
||||
return;
|
||||
|
||||
if (time < 2.0f)
|
||||
return;
|
||||
|
||||
Trigger(eToucher, TRIG_TOGGLE);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
/* overrides */
|
||||
virtual void Respawn(void);
|
||||
|
||||
nonvirtual void SaveTransition(void);
|
||||
nonvirtual void SaveTransition(entity, bool);
|
||||
nonvirtual NSEntity FindCarrierEntity(string);
|
||||
nonvirtual void LoadTransition(void);
|
||||
};
|
||||
|
@ -58,7 +58,7 @@ trigger_transition::Respawn(void)
|
|||
}
|
||||
|
||||
void
|
||||
trigger_transition::SaveTransition(void)
|
||||
trigger_transition::SaveTransition(entity pvsTest, bool usePVS)
|
||||
{
|
||||
int i = 0i;
|
||||
filestream transFile = fopen("trans.dat", FILE_WRITE);
|
||||
|
@ -69,12 +69,37 @@ trigger_transition::SaveTransition(void)
|
|||
|
||||
/* loop through all entities */
|
||||
for (NSEntity a = __NULL__; (a = (NSEntity)findfloat(a, ::identity, 1));) {
|
||||
print(sprintf("TRANSITION: %i %S %S\n", i, a.classname, a.m_strGlobalName));
|
||||
bool replicateEntity = false;
|
||||
//print(sprintf("TRANSITION: %i %S %S\n", i, a.classname, a.m_strGlobalName));
|
||||
|
||||
if (a == this)
|
||||
continue;
|
||||
/* if we're using the PVS, don't use the transition trigger as reference */
|
||||
if (usePVS == true && !a.m_strGlobalName) {
|
||||
if (checkpvs(a.origin, pvsTest) == true) {
|
||||
replicateEntity = true;
|
||||
|
||||
if (WithinBounds(a) == true) {
|
||||
/* these checks are somewhat safe assumptions. */
|
||||
if (a.classname == "player") {
|
||||
replicateEntity = false;
|
||||
}
|
||||
if (a.classname == "info_landmark") {
|
||||
replicateEntity = false;
|
||||
}
|
||||
|
||||
/* to get rid of the 'out of model slots' error */
|
||||
if (a.model == "" && solid != SOLID_NOT) {
|
||||
replicateEntity = false;
|
||||
}
|
||||
|
||||
/* one thing is verified in GoldSrc: no brushes carry over. */
|
||||
if (a.m_bIsBrush == true) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (WithinBounds(a) == true) {
|
||||
replicateEntity = true;
|
||||
}
|
||||
|
||||
if (replicateEntity == true) {
|
||||
fputs(transFile, sprintf("ENTITY \"%i\" %S\n", i, a.classname));
|
||||
fputs(transFile, "{\n");
|
||||
a.Save(transFile);
|
||||
|
@ -84,7 +109,10 @@ trigger_transition::SaveTransition(void)
|
|||
fputs(transFile, "{\n");
|
||||
a.Save(transFile);
|
||||
fputs(transFile, "}\n");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -108,7 +136,7 @@ void
|
|||
trigger_transition::LoadTransition(void)
|
||||
{
|
||||
string lineFeed;
|
||||
bool carryEntity;
|
||||
bool isNew = false;
|
||||
NSEntity carrierEntity = __NULL__;
|
||||
|
||||
filestream transFile = fopen("trans.dat", FILE_READ);
|
||||
|
@ -127,7 +155,6 @@ trigger_transition::LoadTransition(void)
|
|||
continue;
|
||||
} else if (argv(0) == "}") {
|
||||
carrierEntity.TransitionComplete();
|
||||
carryEntity = false;
|
||||
carrierEntity = __NULL__;
|
||||
continue;
|
||||
}
|
||||
|
@ -135,15 +162,18 @@ trigger_transition::LoadTransition(void)
|
|||
if (c == 3) {
|
||||
if (argv(0) == "CONTINUE") {
|
||||
carrierEntity = FindCarrierEntity(argv(2));
|
||||
carryEntity = true;
|
||||
isNew = false;
|
||||
} else if (argv(0) == "ENTITY") {
|
||||
//carrierEntity = spawn
|
||||
carryEntity = false;
|
||||
carrierEntity = EntityDef_CreateClassname(argv(2));
|
||||
isNew = true;
|
||||
}
|
||||
} else if (c == 2) { /* key value pairs */
|
||||
if (carrierEntity) {
|
||||
switch (argv(0)) {
|
||||
case "model":
|
||||
if (isNew) {
|
||||
carrierEntity.Restore(argv(0), argv(1));
|
||||
}
|
||||
case "modelindex":
|
||||
break;
|
||||
#if 0
|
||||
|
@ -161,6 +191,11 @@ trigger_transition::LoadTransition(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
fremove("trans.dat");
|
||||
}
|
||||
|
||||
void
|
||||
trigger_transition_pvsfallback(entity pvsTest)
|
||||
{
|
||||
trigger_transition::SaveTransition(pvsTest, true);
|
||||
}
|
|
@ -28,6 +28,7 @@ shared/func_illusionary.qc
|
|||
shared/func_ladder.qc
|
||||
shared/func_wall.qc
|
||||
shared/func_vehicle.qc
|
||||
server/func_tracktrain.qc
|
||||
shared/func_tankmortar.qc
|
||||
shared/trigger_camera.qc
|
||||
shared/trigger_gravity.qc
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -978,10 +978,10 @@ float
|
|||
func_vehicle::SendEntity(entity ePEnt, float flChanged)
|
||||
{
|
||||
if (!modelindex)
|
||||
return (0);
|
||||
return (false);
|
||||
|
||||
if (clienttype(ePEnt) != CLIENTTYPE_REAL)
|
||||
return (0);
|
||||
return (false);
|
||||
|
||||
WriteByte(MSG_ENTITY, ENT_VEH_BRUSH);
|
||||
WriteFloat(MSG_ENTITY, flChanged);
|
||||
|
@ -1017,6 +1017,6 @@ func_vehicle::SendEntity(entity ePEnt, float flChanged)
|
|||
SENDENTITY_COORD(maxs[2], FNCVEHNET_SOLIDMOVETYPE)
|
||||
|
||||
|
||||
return true;
|
||||
return (true);
|
||||
}
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -1467,6 +1467,10 @@ NSMonster::Physics(void)
|
|||
input_angles = angles;
|
||||
m_bTurning = false;
|
||||
|
||||
/* HACK!!! */
|
||||
if (!IsAlive)
|
||||
return;
|
||||
|
||||
/* unset the leap attack */
|
||||
if (m_bLeapAttacked == true && HasFlags(FL_ONGROUND) == true) {
|
||||
m_bLeapAttacked = false;
|
||||
|
@ -2264,7 +2268,7 @@ NSMonster::_RenderDebugViewCone(void)
|
|||
#endif
|
||||
|
||||
#ifdef SERVER
|
||||
var int autocvar_ai_alertdebug = 0;
|
||||
var bool autocvar_ai_debugAlerts = false;
|
||||
|
||||
var float g_monsteralert_timer;
|
||||
void
|
||||
|
@ -2274,8 +2278,8 @@ NSMonster_AlertEnemyAlliance(vector pos, float radius, int alliance)
|
|||
if (g_monsteralert_timer > time)
|
||||
return;
|
||||
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("AI alert from %v with radius %f and alliance %i\n", pos, radius, alliance);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("AI alert from %v with radius %f and alliance %i", pos, radius, alliance);
|
||||
|
||||
for (entity w = world; (w = nextent(w));) {
|
||||
if (w.takedamage == DAMAGE_NO)
|
||||
|
@ -2288,8 +2292,8 @@ NSMonster_AlertEnemyAlliance(vector pos, float radius, int alliance)
|
|||
|
||||
/* only target monsters */
|
||||
if (!(w.flags & FL_MONSTER)) {
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("\t%S is not a monster\n", w.classname);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("\t%S is not a monster", w.classname);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2297,27 +2301,27 @@ NSMonster_AlertEnemyAlliance(vector pos, float radius, int alliance)
|
|||
|
||||
/* they already got a target of some kind */
|
||||
if (f.m_eEnemy) {
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("\t%S already has a target\n", w.classname);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("\t%S already has a target", w.classname);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if they're our friend... ignore*/
|
||||
if (f.IsFriend(alliance)) {
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("\t%S is friend of alliance %i\n", w.classname, alliance);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("\t%S is friend of alliance %i", w.classname, alliance);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if the monster is dead... ignore */
|
||||
if (f.health <= 0) {
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("\t%S is dead, cannot be alerted\n", w.classname);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("\t%S is dead, cannot be alerted", w.classname);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (autocvar_ai_alertdebug)
|
||||
NSMonster_Log("\twe're alerting %S to go to %v\n", w.classname, pos);
|
||||
if (autocvar_ai_debugAlerts)
|
||||
NSMonster_Log("\twe're alerting %S to go to %v", w.classname, pos);
|
||||
|
||||
/* we've heard a noise. investigate the location */
|
||||
f.RouteClear();
|
||||
|
|
|
@ -275,9 +275,9 @@ NSMoverEntity::MoveAndRotateToPosition(vector vecDest, vector vecAngle, float fl
|
|||
}
|
||||
|
||||
/* schedule the movement and proceed to trigger the end after a certain time */
|
||||
MoveToRotPosition_Done(fTravelTime);
|
||||
SetVelocity(vecDifference * (1.0f / fTravelTime));
|
||||
SetAngularVelocity((vecAngleDifference * (1.0 / fTravelTime)));
|
||||
MoveToRotPosition_Done(fTravelTime);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -14,6 +14,15 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
var bool autocvar_vehicle_developer = false;
|
||||
void
|
||||
_NSVehicle_Log(string msg)
|
||||
{
|
||||
if (autocvar_vehicle_developer == true)
|
||||
print(sprintf("%f %s\n", time, msg));
|
||||
}
|
||||
#define NSVehicle_Log(...) _NSVehicle_Log(sprintf(__VA_ARGS__))
|
||||
|
||||
/** This entity class represents vehicles that are predicted across the network. */
|
||||
class NSVehicle:NSSurfacePropEntity
|
||||
{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -446,8 +446,6 @@ NSVehicle::PlayerEnter(NSClientPlayer pl)
|
|||
m_eDriverLast = m_eDriver;
|
||||
pl.vehicle = this;
|
||||
pl.flags |= FL_INVEHICLE;
|
||||
|
||||
SetSendFlags(VEHFL_CHANGED_DRIVER);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -458,6 +456,8 @@ NSVehicle::PlayerLeave(NSClientPlayer pl)
|
|||
|
||||
owner = __NULL__;
|
||||
pl.flags &= ~FL_INVEHICLE;
|
||||
pl.velocity = g_vec_null;
|
||||
setorigin_safe(pl, pl.origin);
|
||||
|
||||
if (m_iVehicleFlags & VHF_FROZEN)
|
||||
pl.flags &= ~FL_FROZEN;
|
||||
|
@ -467,6 +467,4 @@ NSVehicle::PlayerLeave(NSClientPlayer pl)
|
|||
|
||||
pl.vehicle = __NULL__;
|
||||
m_eDriver = __NULL__;
|
||||
|
||||
SetSendFlags(VEHFL_CHANGED_DRIVER);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef enum
|
|||
ENT_OLDCAMERA, /**< of type trigger_camera */
|
||||
ENT_MONITOR, /**< of type func_monitor */
|
||||
ENT_VEHICLE, /**< Reserved. */
|
||||
ENT_TRACKTRAIN, /**< of type func_tracktrain */
|
||||
ENT_VEH_BRUSH, /**< of type func_vehicle */
|
||||
ENT_VEH_TANKMORTAR, /**< of type func_tankmortar */
|
||||
ENT_VEH_4WHEEL, /**< of type prop_vehicle_driveable */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -23,5 +23,6 @@ vector Math_FixDeltaVector(vector);
|
|||
vector Math_Reflect(vector v1, vector v2);
|
||||
vector Math_RandomVector(float flyup);
|
||||
vector Math_RotateAroundPivot(vector pos, vector pivot, float degr);
|
||||
vector Math_AngleDiff(vector from, vector to);
|
||||
|
||||
vector hsv2rgb(float h, float s, float v);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2022 Vera Visions LLC.
|
||||
* Copyright (c) 2016-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
|
||||
|
@ -88,6 +88,34 @@ Math_RotateAroundPivot(vector pos, vector pivot, float degr)
|
|||
return new;
|
||||
}
|
||||
|
||||
|
||||
vector
|
||||
Math_AngleDiff(vector from, vector to)
|
||||
{
|
||||
static float Math_AngleDiff_S(float from, float to) {
|
||||
float angleDelta = from - to;
|
||||
|
||||
if (angleDelta > 180) {
|
||||
angleDelta -= 360;
|
||||
} else if (angleDelta < -180) {
|
||||
angleDelta += 360;
|
||||
}
|
||||
|
||||
return angleDelta;
|
||||
}
|
||||
|
||||
vector newAngle;
|
||||
|
||||
/* clean up input angles */
|
||||
from = Math_FixDeltaVector(from);
|
||||
to = Math_FixDeltaVector(to);
|
||||
|
||||
newAngle[0] = Math_AngleDiff_S(from[0], to[0]);
|
||||
newAngle[1] = Math_AngleDiff_S(from[1], to[1]);
|
||||
newAngle[2] = Math_AngleDiff_S(from[2], to[2]);
|
||||
return newAngle;
|
||||
}
|
||||
|
||||
vector hsv2rgb(float h, float s, float v)
|
||||
{
|
||||
float i,f,p,q,t;
|
||||
|
|
Loading…
Reference in a new issue