document 'Physics' group, related to external-simulator physics

def > decls/def
sound/*.sndshd > decls/sound/*.sndshd
efx/ > decls/efx
NSWeapon: add "snd_fireStart", "snd_fireStop", "snd_fireLoop"
NSWeapon: add "view_geomset" to FireInfo
NSWeapon: add "knockbackRelease" to FireInfo
NSWeapon: add "altMode" toggle
NSWeapon: "actLoop" decoupled from "actFireStart"
NSWeapon: fireRate inherited from model if not set
NSWeapon: query all sequences from FireInfo
NSWeapon privatize weapon state
solidify more def documentation across the board
NSWeapon add "chargeTime" key
rework state machine in NSWeapon
reload timing separation in NSWeapon
add overheatLength, overheatPerShot to NSWeapon
This commit is contained in:
Marco Cawthorne 2024-08-11 13:39:51 -07:00
parent 21b68d1938
commit e4ab1bd671
Signed by: eukara
GPG key ID: CE2032F0A2882A22
23 changed files with 401 additions and 164 deletions

View file

@ -50,9 +50,9 @@ This works only with the OpenAL sound backend.
- 20 - Big room style #1.
- 21 - Big room style #2.
- 22 - Big room style #3.
- 23 - Small concrete room.
- 24 - Medium concrete room.
- 25 - Large concrete room.
- 23 - Small cavern.
- 24 - Medium cavern.
- 25 - Large cavern.
- 26 - Weirdo preset #1.
- 27 - Weirdo preset #2.
- 28 - Weirdo preset #3.

View file

@ -30,6 +30,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup brushentity
@ingroup physics
*/
class
func_physbox:NSPhysicsEntity

View file

@ -40,6 +40,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_ballsocket:NSPhysicsConstraint

View file

@ -40,6 +40,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_constraint:NSPhysicsConstraint

View file

@ -34,6 +34,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_constraintsystem:NSPhysicsConstraint

View file

@ -40,6 +40,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_convert:NSPhysicsConstraint

View file

@ -43,6 +43,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_hinge:NSPhysicsConstraint

View file

@ -36,6 +36,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_keepupright:NSPhysicsConstraint

View file

@ -40,6 +40,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
phys_slideconstraint:NSPhysicsConstraint

View file

@ -51,6 +51,7 @@ This entity was introduced in Half-Life 2 (2004).
@ingroup server
@ingroup pointentity
@ingroup physics
*/
class
prop_physics:NSPhysicsEntity

View file

@ -248,6 +248,10 @@ NSClientPlayer::ProcessInput(void)
return;
}
m_activeWeapon.velocity = velocity;
m_activeWeapon.origin = origin;
m_activeWeapon.Relink();
/* weapon system */
if (input_buttons & INPUT_SECONDARY) {
m_activeWeapon._SecondaryAttack();
@ -487,7 +491,7 @@ NSClientPlayer::UpdateAliveCam(void)
{
vector cam_pos = GetEyePos();
#if defined(VALVE) || defined(CSTRIKE) || defined(GEARBOX) || defined(TFC)
#if defined(VALVE) || defined(CSTRIKE) || defined(GEARBOX) || defined(TFC) || defined(REWOLF)
//view_angles = Camera_RunBob(view_angles);
//view_angles = Camera_StrafeRoll(view_angles);
cam_pos += CalculateLean(view_angles);

View file

@ -1259,7 +1259,6 @@ void
NSEntity::StopSound(float channel, bool broadcast)
{
if (broadcast) {
sound(this, channel, "common/null.wav", 1.0f, ATTN_NORM, 100, SOUNDFLAG_FOLLOW, 0 );
Sound_Stop(this, channel);
} else {
#ifdef SERVER

View file

@ -14,6 +14,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var bool autocvar_ai_enable = true;
var bool autocvar_ai_debugLogic = false;
void
_NSMonster_Log(string className, string functionName, float edictNum, string warnMessage)

View file

@ -1437,9 +1437,14 @@ NSMonster::Physics(void)
input_angles = angles;
m_bTurning = false;
/* HACK!!! */
if (!IsAlive)
if (autocvar_ai_enable == false) {
return;
}
/* HACK!!! */
if (!IsAlive()) {
return;
}
/* editors like Hammer like putting 'sequence' into spawndata
of monsters. so only ever force the animation when flagged as dead */

View file

@ -28,8 +28,9 @@ NSActor::NSActor(void)
_m_flRouteGiveUp = 0.0f;
#endif
for (int i = 0; i < MAX_AMMO_TYPES; i++)
for (int i = 0; i < MAX_AMMO_TYPES; i++) {
m_iAmmoTypes[i] = 0;
}
}
bool
@ -144,8 +145,9 @@ NSActor::Restore(string strKey, string strValue)
void
NSActor::RestoreComplete(void)
{
if (m_iNodes <= 0i)
if (m_iNodes <= 0i) {
return;
}
/* re-plot our route */
RouteToPosition(m_vecLastNode);
@ -189,8 +191,9 @@ NSActor::CheckRoute(void)
return;
}
if (!m_iNodes)
if (!m_iNodes) {
return;
}
if (_m_flRouteGiveUp < time) {
float distanceToLastFrame = distanceSquared(_m_vecRoutePrev, origin);
@ -704,7 +707,6 @@ NSActor::GiveItem(string itemName)
m_itemList._AddedCallback();
//NSLog("First Item %S", m_itemList.classname);
/* TODO: Replace this with a 'SwitchBest' type function? */
/* we have no active weapon, and this is our pick */
if (!m_activeWeapon) {
SwitchToExactWeapon((NSWeapon)m_itemList);
@ -743,8 +745,6 @@ NSActor::GiveItem(string itemName)
newItem._AddedCallback();
}
/* TODO: Replace this with a 'SwitchBest' type function? */
/* we have no active weapon, and this is our pick */
if (!m_activeWeapon) {
SwitchToBestWeapon(false);
}
@ -1002,5 +1002,4 @@ NSActor_ListInventory(NSActor targetEntity)
itemEntry = (NSItem)itemEntry.chain;
i += 1i;
}
}

View file

@ -30,6 +30,7 @@ If you want to create an easy 'weld' type connection, a ballsocket or even a rop
type connection - this class is what you need.
@ingroup baseclass
@ingroup physics
*/
class
NSPhysicsConstraint:NSEntity

View file

@ -35,14 +35,6 @@ var bool autocvar_r_showPhysicsInfo = false;
.float damp_angular;
.float jointgroup;
enum
{
PHYSM_BOX,
PHYSM_SPHERE,
PHYSM_CAPSULE,
PHYSM_TRIMESH,
PHYSM_CYLINDER
};
enumflags
{
@ -75,15 +67,40 @@ typedef enumflags
PHYENT_CHANGED_RENDERMODE,
} nsphyricsentity_changed_t;
/** This entity class represents physically-simulated entities.
/** @defgroup physics Physics Simulator
@brief Anything involving a more advanced physics simulator.
Gameplay features such as movement and projectiles don't usually
tend to be complex because you want consistent behaviour.
All objects that are handled by an external physics simulator tend
to be more physically accurate, but less predictable -
reserved for effects or function where realistic motion
is paramount. This section covers these types of entities and how to
control them.
The physics simulator used is controlled by the engine and may be
subject to change.
subject to change at any given time. Currently we're targeting ODE.
@{
*/
enum
{
PHYSM_BOX,
PHYSM_SPHERE,
PHYSM_CAPSULE,
PHYSM_TRIMESH,
PHYSM_CYLINDER
};
/** This entity class represents physically-simulated entities.
Units of mass is defined in kilograms, a standard unit of measurement.
You will find the API to be mostly compatible of that offered by Garry's Mod.
@ingroup baseclass
@ingroup physics
*/
class NSPhysicsEntity:NSSurfacePropEntity
{
@ -218,4 +235,6 @@ private:
#endif
};
noref .bool isPhysics;
noref .bool isPhysics;
/** @} */ // end of pmove

View file

@ -747,7 +747,7 @@ NSSoundScape::LoadFromEFX(string efxFile)
return (false);
}
fh = fopen(strcat("efx/", efxFile, ".efx"), FILE_READ);
fh = fopen(strcat("decls/efx/", efxFile, ".efx"), FILE_READ);
if (fh < 0) {
EntError("Unable to load EFX file %S", efxFile);
@ -856,37 +856,43 @@ EFX_UpdateListener(NSView playerView)
vector camPos = playerView.GetCameraOrigin();
vector camAngle = playerView.GetCameraAngle();
NSSoundScape bestScape = __NULL__;
float bestDistance = 999999.0f;
if (lastScape) {
SetListener(camPos, anglesToForward(camAngle), anglesToRight(camAngle), anglesToUp(camAngle), 12);
// printf("%s: %v: %v; %v\n", lastScape.classname, lastScape.origin, camPos, camAngle);
makevectors(camAngle);
SetListener(camPos, v_forward, v_right, v_up, 12);
} else {
SetListener(camPos, anglesToForward(camAngle), anglesToRight(camAngle), anglesToUp(camAngle), 0);
//printf("%v; %v\n", camPos, camAngle);
makevectors(camAngle);
SetListener(camPos, v_forward, v_right, v_up, 0);
}
if (autocvar_s_al_use_reverb == false) {
return;
}
float bestdist = 999999;
for (entity e = world; (e = find(e, classname, "NSSoundScape"));) {
float deltaPos;
NSSoundScape scape = (NSSoundScape)e;
/* don't get blocked by entities */
other = world;
traceline(scape.origin, camPos, MOVE_OTHERONLY, scape);
traceline(scape.GetOrigin(), camPos, MOVE_OTHERONLY, scape);
/* collided */
if (trace_fraction < 1.0f) {
continue;
}
float dist = vlen(e.origin - camPos);
if (dist > scape.m_radius) {
/* max-radius check */
deltaPos = length(scape.GetOrigin() - camPos);
if ((deltaPos > scape.GetRadius()) || (deltaPos > bestDistance)) {
continue;
}
if (dist > bestdist) {
continue;
}
bestdist = dist;
bestDistance = deltaPos;
bestScape = scape;
}

View file

@ -46,7 +46,8 @@ typedef enum
WEAPONSTATE_RELOAD_END,
WEAPONSTATE_CHARGING,
WEAPONSTATE_FIRELOOP,
WEAPONSTATE_RELEASED
WEAPONSTATE_RELEASED,
WEAPONSTATE_OVERHEATED
} nsweapon_state_t;
string nsweapon_state_s[] =
@ -57,7 +58,8 @@ string nsweapon_state_s[] =
"WEAPONSTATE_RELOAD_END",
"WEAPONSTATE_CHARGING",
"WEAPONSTATE_FIRELOOP",
"WEAPONSTATE_RELEASED"
"WEAPONSTATE_RELEASED",
"WEAPONSTATE_OVERHEATED"
};
typedef enum
@ -66,6 +68,8 @@ typedef enum
WEPEVENT_RELOADED
} nsweapon_event_t;
#define CHAN_LOOP 5
/*! \brief This entity class represents weapon based items. */
/*!QUAKED NSWeapon (0 0.8 0.8) (-16 -16 0) (16 16 72)
# OVERVIEW
@ -73,6 +77,18 @@ This entity class represents weapon based items.
It is based on NSItem. The only difference is that the attack
related keys get forwarded only to items of this class.
## FireInfo
Weapon firing events are split into optional decl titled 'FireInfo'
that are queried for implemented attack types.
The "def_fireInfo" key points to the decl containing the primary-attack
FireInfo. If that doesn't exist, the keys that would be queried from
there are read from the main decl. This goes for any key that is not
present in a FireInfo.
The "def_altFireInfo" key points to the decl containing the secondary-attack
FireInfo. If that does not exist, secondary attacks are not possible.
# KEYS
- "targetname" : Name
@ -90,11 +106,11 @@ related keys get forwarded only to items of this class.
- "continuousSmoke" : whether the particle effect is continous
- "clipSizeDefault" : CUSTOM: Default clip size on pickup.
## Attack related keys
## FireInfo related keys
- "def_onFire" : Def to spawn when the weapon is fired.
- "def_onRelease" : Def to spawn when the weapon has been released.
## Ammo management related keys
### Ammo management related keys
- "ammoType" : name of the ammo type def entry which the weapon uses
- "ammoRequired" : set to 1 if we require ammo.
- "ammoPerShot" : Amount of ammo to deduct per successful shot.
@ -107,7 +123,43 @@ for delivering a lethal charge to other enemies.
### Overheating weapons
Overheating of the weapon is done when both keys are set.
- "overheatLength" : Time in which it takes for the weapon to cool down.
- "overheatPerShot" : Time added against "overheat_length" when a shot is fired.
- "overheatPerShot" : Time added against "overheatLength" when a shot is fired.
### Mode switching
- "altMode" : When 1, then secondary-attack will toggle between "def_fireInfo" and "def_altFireInfo" on primary-attack.
### Act overrides
Activities are used to decide which animation gets played and which actions are available for this object. If a model does not define them, you can override them here.
This system is SUBJECT to change. It may be removed altogether when FTEQW adds a proper
activity override format for existing models.
- "actIdle" : Sequences to play when idle.
- "actIdleEmpty" : Sequences to play when idle and with an empty clip.
- "actDraw" : Sequences to play when drawing the weapon.
- "actDrawEmpty" : Sequences to play when drawing the empty weapon.
- "actHolster" : Sequences to play when holstering the weapon.
- "actHolsterEmpty" : Sequences to play when holstering the empty weapon.
- "actFire" : Sequences to play when "def_onFire" fires.
- "actFireLast" : Sequences to play when firing the last shot in the weapon.
- "actFireEmpty" : Sequences to play when failing to fire the weapon.
- "actReload" : Sequences to play when reloading the weapon.
- "actReloadEmpty" : Sequences to play when reloading the empty weapon.
- "actReloadStart" : When set will play sequences for the start of a shotgun-style reload.
- "actReloadEnd" : Like "actReloadStart" but for the end of the shotgun-style reload.
- "actDelay" : Sequence to play while the weapon is charging (see "chargeTime")
- "actLoop" : Sequence to play while the weapon is still charging, or in a firing-loop.
- "actDetonate" : Sequences to play when "detonateOnFire" is triggered.
- "actMeleeMiss" : Sequences to play when the melee attack fails.
- "actMeleeHit" : Sequences to play when the melee attack hits.
- "actFireStart" : Sequences to play at the start of a loop/charge attack.
- "actFireStop" : Sequences to play at the end of a loop/charge attack.
- "actRelease" : Sequences to play when "def_onRelease" fires.
### Misc keys
- "reloadTime" : Time in seconds between the start/end of a reload.
- "detonateOnFire" : When set, will detonate all entities of specified classname.
- "punchAngle" : Weapon punchangle to be applied to the camera when shooting "def_onFire".
- "fireRate" : Firing rate between shots.
- "semiAuto" : If not set to "1", the weapon will be fully automatic.
@ingroup baseclass
*/
@ -165,7 +217,6 @@ public:
nonvirtual void PlaySound(string, bool);
/* state */
nonvirtual void SetWeaponState(nsweapon_state_t);
nonvirtual nsweapon_state_t GetWeaponState(void);
virtual void SetAttackNext(float);
@ -203,6 +254,8 @@ public:
nonvirtual void Attack(string);
private:
/** Internal use Sets/overrides the weapon state. Subclasses track your own state! */
nonvirtual void _SetWeaponState(nsweapon_state_t);
/** Called to signal that the owner switched to this weapon. */
nonvirtual void _SwitchedToCallback(void);
/** Called to signal that the owner switched from this weapon. */
@ -213,6 +266,7 @@ private:
nonvirtual void _WeaponStoppedFiring(void);
nonvirtual void _PrimaryAttack(void);
nonvirtual void _SecondaryAttack(void);
nonvirtual void _SwitchedWeaponMode(void);
#ifdef SERVER
nonvirtual void _ReloadFinished(void);
@ -254,12 +308,14 @@ private:
float m_jointTrailWorld;
float m_jointTrailView;
float m_flSpeedMod;
bool m_bAltModeSwitch;
/* cached fireInfo */
string m_fiDetonateOnFire;
float m_fiMeleeRange;
vector m_fiPunchAngle;
string m_fiSndFire;
string m_fiSndRelease;
string m_fiSndEmpty;
int m_fiAmmoType;
int m_fiAmmoPerShot;
@ -272,6 +328,14 @@ private:
string m_fiSndFireLoop;
float m_flReloadSpeed;
float m_fiChargeTime;
bool m_bHasLoop;
string m_fiSndFireStart;
string m_fiSndFireStop;
string m_fiSndFireLoop;
/* overheating */
float m_fiOverheatLength;
float m_fiOverheatPoints;
NETWORKED_INT(m_iClip)
NETWORKED_INT(m_iClipSize)
@ -282,6 +346,7 @@ private:
NETWORKED_FLOAT(m_flFireRate)
NETWORKED_FLOAT(m_dState)
NETWORKED_BOOL(m_bFiring)
NETWORKED_BOOL(m_flOverheating)
};
/* Helper functions for plugins, the rest of the codebase etc.

View file

@ -65,7 +65,7 @@ NSWeapon::RemovedFromInventory(void)
}
void
NSWeapon::SetWeaponState(nsweapon_state_t newState)
NSWeapon::_SetWeaponState(nsweapon_state_t newState)
{
if (m_dState == newState) {
return;
@ -87,12 +87,14 @@ NSWeapon::GetWeaponState(void)
void
NSWeapon::UpdateFireInfoCache(void)
{
string viewGeomset;
string ammoPerShot = GetSubDefString(m_strLastFireInfo, "ammoPerShot");
string reloadSpeed = GetSubDefString(m_strLastFireInfo, "reloadTime");
m_fiDetonateOnFire = GetSubDefString(m_strLastFireInfo, "detonateOnFire");
m_fiMeleeRange = GetSubDefFloat(m_strLastFireInfo, "melee_distance");
m_fiPunchAngle = GetSubDefVector(m_strLastFireInfo, "punchAngle");
m_fiSndFire = GetSubDefString(m_strLastFireInfo, "snd_fire");
m_fiSndRelease = GetSubDefString(m_strLastFireInfo, "snd_release");
m_fiSndEmpty = GetSubDefString(m_strLastFireInfo, "snd_empty");
m_fiAmmoType = ammoNumForName(GetSubDefString(m_strLastFireInfo, "ammoType"));
m_fiAmmoRequired = GetSubDefBool(m_strLastFireInfo, "ammoRequired");
@ -104,6 +106,20 @@ NSWeapon::UpdateFireInfoCache(void)
m_fiOnRelease = GetSubDefString(m_strLastFireInfo, "def_onRelease");
m_fiChargeTime = GetSubDefFloat(m_strLastFireInfo, "chargeTime");
m_fiOverheatPoints = GetSubDefFloat(m_strLastFireInfo, "overheatPerShot");
m_fiSndFireStart = GetSubDefString(m_strLastFireInfo, "snd_fireStart");
m_fiSndFireStop = GetSubDefString(m_strLastFireInfo, "snd_fireStop");
m_fiSndFireLoop = GetSubDefString(m_strLastFireInfo, "snd_fireLoop");
/* only check if it's present. */
m_bHasLoop = GetSubDefBool(m_strLastFireInfo, "actLoop");
/* keep the last valid value (don't 0.0f it) to prevent overlay dropouts. */
if (m_fiOverheatPoints) {
m_fiOverheatLength = GetSubDefFloat(m_strLastFireInfo, "overheatLength");
}
/* when -1.0 we'll pull it from the animation. */
if (reloadSpeed != "") {
m_flReloadSpeed = stof(reloadSpeed);
@ -111,6 +127,18 @@ NSWeapon::UpdateFireInfoCache(void)
m_flReloadSpeed = -1.0f;
}
#ifdef CLIENT
viewGeomset = GetSubDefString(m_strLastFireInfo, "view_geomset");
if (viewGeomset) {
setcustomskin(pSeat->m_eViewModel, "", viewGeomset);
setcustomskin(pSeat->m_eViewModelL, "", viewGeomset);
} else {
setcustomskin(pSeat->m_eViewModel, "", "");
setcustomskin(pSeat->m_eViewModelL, "", "");
}
#endif
#if 0
NSError("Switched FireInfo to %S", m_strLastFireInfo);
NSError("m_fiAmmoType: %i", m_fiAmmoRequired);
@ -337,6 +365,7 @@ NSWeapon::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_ENTITY(owner, WEAPONFL_CHANGED_CHAIN)
SENDENTITY_BYTE(m_dState, WEAPONFL_CHANGED_STATE)
SENDENTITY_BYTE(m_bFiring, WEAPONFL_CHANGED_STATE)
SENDENTITY_FLOAT(m_flOverheating, WEAPONFL_CHANGED_STATE)
} else {
/* the item is in the inventory */
}
@ -385,6 +414,7 @@ NSWeapon::EvaluateEntity(void)
EVALUATE_FIELD(owner, WEAPONFL_CHANGED_CHAIN)
EVALUATE_FIELD(m_dState, WEAPONFL_CHANGED_STATE)
EVALUATE_FIELD(m_bFiring, WEAPONFL_CHANGED_STATE)
EVALUATE_FIELD(m_flOverheating, WEAPONFL_CHANGED_STATE)
}
#endif
@ -392,8 +422,9 @@ NSWeapon::EvaluateEntity(void)
void
NSWeapon::ClientFX(bool isThirdperson)
{
if (m_bFiring == false)
if (m_bFiring == false) {
return;
}
vector src;
vector endpos;
@ -456,6 +487,7 @@ NSWeapon::ReceiveEntity(float flNew, float flChanged)
READENTITY_ENTNUM(owner_entnum, WEAPONFL_CHANGED_CHAIN)
READENTITY_BYTE(m_dState, WEAPONFL_CHANGED_STATE)
READENTITY_BYTE(m_bFiring, WEAPONFL_CHANGED_STATE)
READENTITY_FLOAT(m_flOverheating, WEAPONFL_CHANGED_STATE)
}
if (flChanged & WEAPONFL_CHANGED_MODELINDEX) {
@ -502,6 +534,7 @@ NSWeapon::PredictPreFrame(void)
SAVE_STATE(m_flFireRate)
SAVE_STATE(m_dState)
SAVE_STATE(m_bFiring)
SAVE_STATE(m_flOverheating)
}
void
@ -516,6 +549,7 @@ NSWeapon::PredictPostFrame(void)
ROLL_BACK(m_flFireRate)
ROLL_BACK(m_dState)
ROLL_BACK(m_bFiring)
ROLL_BACK(m_flOverheating)
}
#endif
@ -548,10 +582,6 @@ NSWeapon::_CacheWeaponDefVariables(void)
/* may be defined in either fireInfo or weaponDef */
ammoRequired = GetSubDefString(m_primaryFireInfo, "ammoRequired");
if (!ammoRequired) {
ammoRequired = GetDefString("ammoRequired");
}
m_bAmmoRequired = stof(ammoRequired);
m_primaryAmmoType = ammoNumForName(firstType);
@ -566,6 +596,8 @@ NSWeapon::_CacheWeaponDefVariables(void)
m_viewModel = getmodelindex(GetDefString("model_view"));
m_worldModel = getmodelindex(GetDefString("model"));
m_bAltModeSwitch = GetDefBool("altMode");
/* gettagindex takes the silliest of parameters to determine which model to query */
string jointTrailWorld = GetDefString("joint_world_trail");
string jointTrailView = GetDefString("joint_view_trail");
@ -602,7 +634,7 @@ NSWeapon::_SwitchedToCallback(void)
void
NSWeapon::_SwitchedFromCallback(void)
{
printf("Switched from %S\n", classname);
//printf("Switched from %S\n", classname);
Holster();
}
@ -624,22 +656,12 @@ NSWeapon::Draw(void)
float drawAnimation = 0;
float drawTime;
if (!m_iMode) {
if (m_iClipSize > 0 && m_iClip == 0) {
drawAnimation = GetDefAct("actDrawEmpty");
}
if (m_iClipSize > 0 && m_iClip == 0) {
drawAnimation = GetSubDefAct(m_strLastFireInfo, "actDrawEmpty");
}
if (!drawAnimation) {
drawAnimation = GetDefAct("actDraw");
}
} else {
if (m_iClipSize > 0 && m_iClip == 0) {
drawAnimation = GetDefAct("actAltDrawEmpty");
}
if (!drawAnimation) {
drawAnimation = GetDefAct("actAltDraw");
}
if (!drawAnimation) {
drawAnimation = GetSubDefAct(m_strLastFireInfo, "actDraw");
}
drawTime = frameduration(m_viewModel, drawAnimation);
@ -719,7 +741,13 @@ NSWeapon::FiredWeaponAttack(string fireInfo)
{
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
ourOwner.AttackByDef(fireInfo, false);
SetWeaponState(WEAPONSTATE_IDLE);
_SetWeaponState(WEAPONSTATE_IDLE);
/* knockback */
{
float weaponKnockBack = GetSubDefFloat(fireInfo, "knockback");
ourOwner.AddVelocity(anglesToForward(ourOwner.v_angle) * -weaponKnockBack);
}
/* prevent release from firing it again */
if (m_bPowerAmmo) {
@ -732,7 +760,14 @@ NSWeapon::ReleasedWeaponAttack(string fireInfo)
{
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
ourOwner.AttackByDef(fireInfo, true);
SetWeaponState(WEAPONSTATE_RELEASED);
/* knockback */
{
float weaponKnockBack = GetSubDefFloat(fireInfo, "knockbackRelease");
ourOwner.AddVelocity(anglesToForward(ourOwner.v_angle) * -weaponKnockBack);
}
_SetWeaponState(WEAPONSTATE_RELEASED);
}
void
@ -746,6 +781,8 @@ NSWeapon::Attack(string fireInfo)
ourOwner.gflags |= GF_SEMI_TOGGLED;
}
SwitchFireInfo(fireInfo);
/* no real attack, detonate named satchels, pipe bombs, etc. */
if (m_fiDetonateOnFire != __NULL__) {
if (DetonateDef(m_fiDetonateOnFire) == true) {
@ -856,7 +893,7 @@ NSWeapon::Attack(string fireInfo)
/* mark as charging, play loop anim in Idle() next */
SetIdleNext(frameduration(m_viewModel, shotAnim));
SetWeaponFrame(shotAnim);
SetWeaponState(WEAPONSTATE_CHARGING);
_SetWeaponState(WEAPONSTATE_CHARGING);
return;
}
}
@ -865,38 +902,61 @@ NSWeapon::Attack(string fireInfo)
#ifdef SERVER
v_angle = input_angles;
ourOwner.StartSoundDef(m_fiSndFire, CHAN_WEAPON, true);
if (m_fiSndFire) {
ourOwner.StartSoundDef(m_fiSndFire, CHAN_WEAPON, true);
}
#endif
FiredWeaponAttack(fireInfo);
if (m_iClipSize > 0 && m_iClip == 0)
shotAnim = GetSubDefAct(fireInfo, "actFireLast");
if (m_bHasLoop == false) {
if (m_iClipSize > 0 && m_iClip == 0) {
shotAnim = GetSubDefAct(fireInfo, "actFireLast");
}
if (!shotAnim)
shotAnim = GetSubDefAct(fireInfo, "actFire");
if (!shotAnim) {
shotAnim = GetSubDefAct(fireInfo, "actFire");
}
#ifdef CLIENT
View_SetMuzzleflash(m_muzzleModelIndex);
View_SetMuzzleflash(m_muzzleModelIndex);
#endif
SetWeaponFrame(shotAnim);
{
float weaponKnockBack = GetSubDefFloat(fireInfo, "knockback");
ourOwner.AddVelocity(anglesToForward(ourOwner.v_angle) * -weaponKnockBack);
SetWeaponFrame(shotAnim);
SetIdleNext(frameduration(m_viewModel, shotAnim));
} else {
_SetWeaponState(WEAPONSTATE_FIRELOOP);
Idle();
}
/* build up heat */
if (m_fiOverheatLength > 0.0f && m_fiOverheatPoints > 0.0f) {
m_flOverheating += m_fiOverheatPoints;
#ifdef SERVER
//printf("%f (%f)\n", m_flOverheating, (m_flOverheating / m_fiOverheatLength));
#endif
if (m_flOverheating >= m_fiOverheatLength) {
_SetWeaponState(WEAPONSTATE_OVERHEATED);
}
}
float animTime = frameduration(m_viewModel, shotAnim);
if (m_fiFireRate) {
SetAttackNext(m_fiFireRate);
} else {
SetAttackNext(animTime);
}
SetAttackNext(m_fiFireRate);
SetIdleNext(frameduration(m_viewModel, shotAnim));
//EntLog("Primary Attack! Firing rate: %f", GetDefFloat("fireRate"));
m_bFiring = true;
}
void
NSWeapon::_PrimaryAttack(void)
{
SwitchFireInfo(m_primaryFireInfo);
_WeaponStartedFiring();
PrimaryAttack();
}
@ -904,11 +964,28 @@ NSWeapon::_PrimaryAttack(void)
void
NSWeapon::_SecondaryAttack(void)
{
SwitchFireInfo(m_secondaryFireInfo);
_WeaponStartedFiring();
SecondaryAttack();
}
void
NSWeapon::_SwitchedWeaponMode(void)
{
float animMode;
if (m_iMode) {
animMode = GetSubDefAct(m_strLastFireInfo, "actModeOn");
SwitchFireInfo(m_secondaryFireInfo);
} else {
SwitchFireInfo(m_primaryFireInfo);
animMode = GetSubDefAct(m_strLastFireInfo, "actModeOff");
}
SetWeaponFrame(animMode);
SetAttackNext(frameduration(m_viewModel, animMode));
SetIdleNext(frameduration(m_viewModel, animMode));
}
void
NSWeapon::PlaySound(string soundDef, bool clientOnly)
{
@ -925,28 +1002,14 @@ NSWeapon::PlaySound(string soundDef, bool clientOnly)
#endif
}
void
NSWeapon::PrimaryAttack(void)
{
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
if (CanFire() == false) {
if (!(ourOwner.gflags & GF_SEMI_TOGGLED)) {
Release();
}
return;
}
Attack(m_primaryFireInfo);
}
void
NSWeapon::Idle(void)
{
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
float idleAnim = 0;
m_flOverheating = max(0.0f, m_flOverheating - input_timelength);
if (CanIdle() == false) {
return;
}
@ -954,18 +1017,18 @@ NSWeapon::Idle(void)
/* handle shotgun style reloads */
switch (m_dState) {
case WEAPONSTATE_RELOAD_START:
idleAnim = GetDefAct("actReloadStart");
SetWeaponState(WEAPONSTATE_RELOAD);
idleAnim = GetSubDefAct(m_strLastFireInfo, "actReloadStart");
_SetWeaponState(WEAPONSTATE_RELOAD);
PlaySound(GetDefString("snd_reload_start"), false);
break;
case WEAPONSTATE_RELOAD:
float reloadTime;
idleAnim = GetDefAct("actReload");
idleAnim = GetSubDefAct(m_strLastFireInfo, "actReload");
m_iClip++;
ourOwner.UseAmmo(m_primaryAmmoType, 1);
if (HasReserveAmmo() == false || m_iClip >= m_iClipSize) {
SetWeaponState(WEAPONSTATE_RELOAD_END);
_SetWeaponState(WEAPONSTATE_RELOAD_END);
}
#ifdef SERVER
@ -983,54 +1046,81 @@ NSWeapon::Idle(void)
return;
break;
case WEAPONSTATE_RELOAD_END:
idleAnim = GetDefAct("actReloadEnd");
SetWeaponState(WEAPONSTATE_IDLE);
idleAnim = GetSubDefAct(m_strLastFireInfo, "actReloadEnd");
_SetWeaponState(WEAPONSTATE_IDLE);
#ifdef SERVER
PlaySound(GetDefString("snd_reload_end"), false);
#endif
break;
case WEAPONSTATE_FIRELOOP:
idleAnim = GetDefAct("actLoop");
idleAnim = GetSubDefAct(m_strLastFireInfo, "actLoop");
break;
case WEAPONSTATE_CHARGING:
idleAnim = GetDefAct("actLoop");
idleAnim = GetSubDefAct(m_strLastFireInfo, "actLoop");
break;
case WEAPONSTATE_RELEASED:
//breakpoint();
idleAnim = GetDefAct("actRelease");
SetWeaponState(WEAPONSTATE_IDLE);
idleAnim = GetSubDefAct(m_strLastFireInfo, "actRelease");
_SetWeaponState(WEAPONSTATE_IDLE);
break;
case WEAPONSTATE_OVERHEATED:
/* prevent fire for the next N seconds */
_SetWeaponState(WEAPONSTATE_IDLE);
SetAttackNext(m_fiOverheatLength);
SetReloadNext(0.1f);
break;
case WEAPONSTATE_IDLE:
default:
if (!m_iMode) {
if (m_iClipSize > 0 && m_iClip == 0) {
idleAnim = GetDefAct("actIdleEmpty");
if (m_iClipSize > 0 && m_iClip == 0) {
idleAnim = GetSubDefAct(m_strLastFireInfo, "actIdleEmpty");
/* this will mess with us otherwise */
if (!idleAnim)
return;
}
/* this will mess with us otherwise */
if (!idleAnim)
idleAnim = GetDefAct("actIdle");
} else {
if (m_iClipSize > 0 && m_iClip == 0) {
idleAnim = GetDefAct("actAltIdleEmpty");
/* this will mess with us otherwise */
if (!idleAnim)
return;
}
if (!idleAnim)
idleAnim = GetDefAct("actAltIdle");
return;
}
if (!idleAnim)
idleAnim = GetSubDefAct(m_strLastFireInfo, "actIdle");
}
SetWeaponFrame(idleAnim);
SetIdleNext(frameduration(m_viewModel, idleAnim));
}
void
NSWeapon::PrimaryAttack(void)
{
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
if (CanFire() == false) {
if (!(ourOwner.gflags & GF_SEMI_TOGGLED)) {
Idle();
return;
}
if (m_bHasLoop) {
Release();
} else {
Idle();
}
return;
}
if (m_bAltModeSwitch == true) {
if (CanFire() == false) {
return;
}
}
if (m_iMode) {
Attack(m_secondaryFireInfo);
return;
}
Attack(m_primaryFireInfo);
}
void
NSWeapon::SecondaryAttack(void)
{
@ -1040,8 +1130,9 @@ NSWeapon::SecondaryAttack(void)
/* zoom takes priority */
if (m_flZoomFOV > 0.0f) {
if (CanFire() == false)
if (CanFire() == false) {
return;
}
ourOwner = (NSClientPlayer)GetOwner();
ourOwner.viewzoom = (ourOwner.viewzoom == 1.0) ? m_flZoomFOV : 1.0;
@ -1056,8 +1147,20 @@ NSWeapon::SecondaryAttack(void)
ourOwner.gflags |= GF_SEMI_TOGGLED;
return;
} else if (m_bAltModeSwitch == true) {
if (CanFire() == false) {
Idle();
return;
}
m_iMode = 1 - m_iMode;
SetAttackNext(1.0);
SetIdleNext(1.0f);
_SwitchedWeaponMode();
return;
}
/* no fire info? don't even bother then */
if (m_secondaryFireInfo == "") {
Release();
@ -1106,7 +1209,7 @@ NSWeapon::Reload(void)
if (m_dState >= WEAPONSTATE_RELOAD_START && m_dState <= WEAPONSTATE_RELOAD_END) {
return;
}
reloadStartAct = GetDefAct("actReloadStart");
reloadStartAct = GetSubDefAct(m_strLastFireInfo, "actReloadStart");
/* we cannot reload this weapon by principle. */
if (!m_iClipSize) {
@ -1114,6 +1217,7 @@ NSWeapon::Reload(void)
}
if (CanReload() == false) {
Idle();
return;
}
@ -1121,6 +1225,7 @@ NSWeapon::Reload(void)
ammoTypeID = ammoNumForName(ammoType);
if (m_iClip == m_iClipSize) {
Idle();
return;
}
@ -1131,27 +1236,17 @@ NSWeapon::Reload(void)
/* we have a start-reload, so this is a shotgun styled weapon reload */
if (reloadStartAct) {
SetWeaponState(WEAPONSTATE_RELOAD_START);
_SetWeaponState(WEAPONSTATE_RELOAD_START);
Release();
return;
}
if (!m_iMode) {
if (m_iClipSize > 0 && m_iClip == 0) {
reloadAnimation = GetDefAct("actReloadEmpty");
}
if (m_iClipSize > 0 && m_iClip == 0) {
reloadAnimation = GetSubDefAct(m_strLastFireInfo, "actReloadEmpty");
}
if (!reloadAnimation) {
reloadAnimation = GetDefAct("actReload");
}
} else {
if (m_iClipSize > 0 && m_iClip == 0) {
reloadAnimation = GetDefAct("actAltReloadEmpty");
}
if (!reloadAnimation) {
reloadAnimation = GetDefAct("actAltReload");
}
if (!reloadAnimation) {
reloadAnimation = GetSubDefAct(m_strLastFireInfo, "actReload");
}
if (m_flReloadSpeed == -1.0f) {
@ -1204,14 +1299,24 @@ NSWeapon::_WeaponStartedFiring(void)
float actFireStart = GetSubDefAct(m_strLastFireInfo, "actFireStart");
#ifdef SERVER
printf("actFireStart %d %S\n", actFireStart, m_strLastFireInfo);
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
if (m_fiSndFireStart) {
ourOwner.StartSoundDef(m_fiSndFireStart, CHAN_WEAPON, true);
}
if (m_fiSndFireLoop) {
//ourOwner.StartSoundDef(m_fiSndFireLoop, CHAN_LOOP, true);
}
//printf("actFireStart %d %S\n", actFireStart, m_strLastFireInfo);
#endif
if (actFireStart) {
SetWeaponFrame(actFireStart);
SetAttackNext(frameduration(m_viewModel, actFireStart));
SetIdleNext(frameduration(m_viewModel, actFireStart));
SetWeaponState(WEAPONSTATE_FIRELOOP);
_SetWeaponState(WEAPONSTATE_FIRELOOP);
}
WeaponStartedFiring();
@ -1223,6 +1328,7 @@ NSWeapon::_WeaponStartedFiring(void)
void
NSWeapon::_WeaponStoppedFiring(void)
{
if (m_bHasLoop == false)
if (CanFire() == false) {
return;
}
@ -1231,15 +1337,11 @@ NSWeapon::_WeaponStoppedFiring(void)
if (owner.vv_flags & VFL_FIRING) {
float actFireStop = GetSubDefAct(m_strLastFireInfo, "actFireStop");
#ifdef SERVER
printf("actFireStop %d %S\n", actFireStop, m_strLastFireInfo);
#endif
if (actFireStop) {
SetWeaponFrame(actFireStop);
SetAttackNext(frameduration(m_viewModel, actFireStop));
SetIdleNext(frameduration(m_viewModel, actFireStop));
SetWeaponState(WEAPONSTATE_RELEASED);
_SetWeaponState(WEAPONSTATE_RELEASED);
}
WeaponStoppedFiring();
@ -1272,12 +1374,11 @@ NSWeapon::Release(void)
ourOwner.gflags &= ~GF_SEMI_TOGGLED;
if (m_fiWillRelease) {
/* TODO: should be from the previous fireinfo */
string defThrown = GetSubDefString(m_strLastFireInfo, "def_thrown");
string defPlant = GetSubDefString(m_strLastFireInfo, "def_plant");
/* delayed shot release */
idleAnim = GetDefAct("actRelease");
idleAnim = GetSubDefAct(m_strLastFireInfo, "actRelease");
/* aimed at attached to whatever we're looking at */
if (defPlant != "") {
@ -1292,13 +1393,16 @@ NSWeapon::Release(void)
}
}
if (m_fiSndRelease) {
ourOwner.StartSoundDef(m_fiSndRelease, CHAN_WEAPON, true);
}
ReleasedWeaponAttack(m_strLastFireInfo);
m_fiWillRelease = false;
SetWeaponFrame(idleAnim);
SetAttackNext(1.0f);
SetIdleNext(1.0f);
ourOwner.vv_flags &= ~VFL_PRIMEDFUSE;
ourOwner.vv_flags |= VFL_REDRAW;
return;
}
@ -1310,13 +1414,33 @@ NSWeapon::Release(void)
}
#endif
/* already in a reload? */
if (!(m_dState >= WEAPONSTATE_RELOAD_START && m_dState <= WEAPONSTATE_RELOAD_END)) {
_SetWeaponState(WEAPONSTATE_IDLE);
}
#ifdef SERVER
if (m_bFiring == true) {
NSClientPlayer ourOwner = (NSClientPlayer)GetOwner();
if (m_fiSndFireStop) {
ourOwner.StartSoundDef(m_fiSndFireStop, CHAN_WEAPON, true);
}
ourOwner.StopSound(CHAN_LOOP, true);
//printf("actFireStop %d %S\n", actFireStop, m_strLastFireInfo);
}
#endif
m_bFiring = false;
#if 0
if (ourOwner.vv_flags & VFL_REDRAW) {
Draw();
ourOwner.vv_flags &= ~VFL_REDRAW;
return;
}
#endif
Idle();
}
@ -1419,6 +1543,11 @@ NSWeapon::CanFire(void)
return (false);
}
/* sanity check */
if (GetWeaponState() == WEAPONSTATE_OVERHEATED) {
return (false);
}
if (ourOwner.gflags & GF_SEMI_TOGGLED) {
return (false);
}

View file

@ -176,7 +176,7 @@ EntityDef_Init(void)
g_entDefInclude = "";
pm = search_begin("def/*.def", TRUE, TRUE);
pm = search_begin("decls/def/*.def", TRUE, TRUE);
for (int i = 0; i < search_getsize(pm); i++) {
EntityDef_ReadFile(search_getfilename(pm, i));
}
@ -188,7 +188,7 @@ EntityDef_Init(void)
int includeCount = tokenizebyseparator(g_entDefInclude, ";");
for (int i = 0; i < (includeCount-1); i++) {
string fileName = strcat("def/", argv(i));
string fileName = strcat("decls/def/", argv(i));
EntityDef_ReadFile(fileName);
includeCount = tokenizebyseparator(g_entDefInclude, ";");
}

View file

@ -216,7 +216,7 @@ void Sound_Speak(entity targetEntity, string sentencesEntry);
#endif
/** Stops sounds on a given channel, on a target entity. */
void Sound_Stop(entity target, int chan);
void Sound_Stop(entity target, float chan);
void Sound_DebugList();

View file

@ -422,7 +422,7 @@ Sound_Precache(string shader)
g_sounds[index].pitch_min = g_sounds[index].pitch_max = 100;
g_sounds[index].offset = 0;
sh = search_begin("sound/*.sndshd", TRUE, TRUE);
sh = search_begin("decls/sound/*.sndshd", TRUE, TRUE);
for (int i = 0; i < search_getsize(sh); i++) {
fh = fopen(search_getfilename(sh, i), FILE_READ);
@ -565,7 +565,7 @@ Sound_DistancePos(vector pos, string shader)
}
void
Sound_Stop(entity target, int chan)
Sound_Stop(entity target, float chan)
{
sound(target, chan, "common/null.wav", 1.0f, ATTN_NORM, 100, SOUNDFLAG_FOLLOW, 0 );
}