func_tracktrain: Lots of improvements across the board. Enjoy c0a0-c0a0e!

func_trackchange/autochange: Initial implementation.
This commit is contained in:
Marco Cawthorne 2024-02-13 22:51:36 -08:00
parent 7e8d1aacdb
commit 06d959ef02
Signed by: eukara
GPG key ID: CE2032F0A2882A22
20 changed files with 1599 additions and 228 deletions

View file

@ -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;

View file

@ -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

View 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);
}
}

View 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

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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
{

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);

View file

@ -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;