Compare commits

..

5 commits

24 changed files with 632 additions and 457 deletions

View file

@ -4,7 +4,6 @@
#define CSQC
#define CLIENT
#define NEW_INVENTORY
#includelist
/* first the engine, then nuclide headers for client/shared */

View file

@ -15,6 +15,7 @@
*/
#include "gamerules.h"
#include "items.h"
// stubs for spawning
void info_player_deathmatch(void)

32
base/src/server/items.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2016-2022 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.
*/
/* PICKUP ITEMS */
class item_pickup:NSRenderableEntity
{
int m_bFloating;
int m_iClip;
int m_iWasDropped;
int id;
void item_pickup(void);
virtual void Spawned(void);
virtual void Touch(entity);
virtual void SetItem(int i);
virtual void Respawn(void);
virtual void SetFloating(int);
virtual void PickupRespawn(void);
};

92
base/src/server/items.qc Normal file
View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 2016-2022 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.
*/
void item_pickup::Touch(entity eToucher)
{
if (eToucher.classname != "player") {
return;
}
/* don't remove if AddItem fails */
if (Weapons_AddItem((player)eToucher, id, m_iClip) == FALSE) {
return;
}
Logging_Pickup(eToucher, this, __NULL__);
Sound_Play(other, CHAN_ITEM, "weapon.pickup");
UseTargets(eToucher, TRIG_TOGGLE, m_flDelay);
if (real_owner || m_iWasDropped == 1 || cvar("sv_playerslots") == 1) {
Destroy();
} else {
Disappear();
ScheduleThink(PickupRespawn, 30.0f);
}
}
void item_pickup::SetItem(int i)
{
id = i;
m_oldModel = Weapons_GetWorldmodel(id);
SetModel(GetSpawnModel());
SetSize([-16,-16,0], [16,16,16]);
}
void item_pickup::SetFloating(int i)
{
m_bFloating = rint(bound(0, m_bFloating, 1));
}
void
item_pickup::PickupRespawn(void)
{
Respawn();
Sound_Play(this, CHAN_ITEM, "item.respawn");
}
void item_pickup::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetOrigin(GetSpawnOrigin());
botinfo = BOTINFO_WEAPON;
/* At some points, the item id might not yet be set */
if (GetSpawnModel()) {
SetModel(GetSpawnModel());
}
SetSize([-16,-16,0], [16,16,16]);
ReleaseThink();
if (!m_bFloating) {
DropToFloor();
SetMovetype(MOVETYPE_TOSS);
}
}
void
item_pickup::Spawned(void)
{
super::Spawned();
Sound_Precache("item.respawn");
Sound_Precache("weapon.pickup");
}
void item_pickup::item_pickup(void)
{
}

View file

@ -4,7 +4,6 @@
#define QWSSQC
#define SERVER
#define NEW_INVENTORY
#includelist
/* engine, then nuclide headers & functions */
@ -27,6 +26,7 @@ gamerules.qc
gamerules_singleplayer.qc
gamerules_multiplayer.qc
modelevent.qc
items.qc
/* global server/shared code */
../../../src/server/include.src

40
base/src/shared/flags.h Normal file
View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2016-2022 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.
*/
/* game flags */
#define GF_SEMI_TOGGLED (int)(1<<0)
#define GF_FLASHLIGHT (int)(1<<1)
#define GF_UNUSED3 (int)(1<<2)
#define GF_UNUSED4 (int)(1<<3)
#define GF_UNUSED5 (int)(1<<4)
#define GF_UNUSED6 (int)(1<<5)
#define GF_UNUSED7 (int)(1<<6)
#define GF_UNUSED8 (int)(1<<7)
#define GF_UNUSED9 (int)(1<<8)
#define GF_UNUSED10 (int)(1<<9)
#define GF_UNUSED11 (int)(1<<10)
#define GF_UNUSED12 (int)(1<<11)
#define GF_UNUSED13 (int)(1<<12)
#define GF_UNUSED14 (int)(1<<14)
#define GF_UNUSED15 (int)(1<<16)
#define GF_UNUSED16 (int)(1<<13)
#define GF_UNUSED17 (int)(1<<17)
#define GF_UNUSED18 (int)(1<<18)
#define GF_UNUSED19 (int)(1<<19)
#define GF_UNUSED20 (int)(1<<20)
#define GF_UNUSED21 (int)(1<<21)
#define GF_UNUSED22 (int)(1<<22)
#define GF_UNUSED23 (int)(1<<23)

View file

@ -1,5 +1,8 @@
#includelist
player.qc
weapon_common.h
weapons.h
flags.h
fx_explosion.qc
fx_spark.qc
fx_blood.qc
@ -8,4 +11,6 @@ fx_corpse.qc
fx_gibhuman.qc
fx_impact.qc
TestWeapon.qc
weapons.qc
weapon_common.qc
#endlist

20
base/src/shared/weapons.h Normal file
View file

@ -0,0 +1,20 @@
/*
* 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.
*/
enum
{
WEAPON_NONE
};

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
weapon_t w_null = {};
weapon_t g_weapons[] = {
w_null
};

View file

@ -124,7 +124,7 @@ NSTraceAttack::_ApplyDamage(void)
/* the location _could_ be more accurate... */
if (m_eMultiTarget.CanBleed() == true) {
FX_Blood(trace_endpos, [0.5,0,0]);
FX_Blood(trace_endpos, m_eMultiTarget.GetBloodColor());
}
trace_surface_id = m_iMultiBody;

View file

@ -322,7 +322,7 @@ public:
/** Returns if the entity is visible from a given position and a field of view of 90 degrees. */
nonvirtual bool VisibleVec(vector);
/** Returns a normalized value of how far away the target is from the entity's view direction. 1 means dead-center. 0 means it's behind.*/
nonvirtual bool DistanceFromYaw(entity);
nonvirtual bool DistanceFromYaw(vector);
/** Returns if the entity has any spawnflags set. */
nonvirtual bool HasSpawnFlags(float);
/** Returns if the entity is aligned to the ground. */

View file

@ -99,7 +99,7 @@ bool NSEntity::VisibleVec( vector org ) {
bool NSEntity::Visible( entity ent ) {
/* is it in our field of view? */
if ( DistanceFromYaw(ent) > 0.3f ) {
if ( DistanceFromYaw(ent.origin) > 0.3f ) {
traceline( origin, ent.origin, MOVE_NORMAL, this );
if ( trace_fraction == 1.0f || trace_ent == ent ) {
print( sprintf( "%s can see %s\n", classname, ent.classname ) );
@ -110,12 +110,12 @@ bool NSEntity::Visible( entity ent ) {
return ( false );
}
bool NSEntity::DistanceFromYaw( entity ent ) {
bool NSEntity::DistanceFromYaw( vector targetPos ) {
vector flDelta;
float flFoV;
makevectors( angles );
flDelta = normalize( ent.origin - origin );
flDelta = normalize( targetPos - origin );
return flDelta * v_forward;
}

View file

@ -331,12 +331,16 @@ public:
nonvirtual bool InSequence(void);
/* animation cycles */
/** Overridable: Called when we need to play a fresh idle framegroup. */
/** DEPRECATED, Overridable: Called when we need to play a fresh idle framegroup. */
virtual int AnimIdle(void);
/** Overridable: Called when we need to play a fresh walking framegroup. */
/** DEPRECATED, Overridable: Called when we need to play a fresh walking framegroup. */
virtual int AnimWalk(void);
/** Overridable: Called when we need to play a fresh running framegroup. */
/** DEPRECATED, Overridable: Called when we need to play a fresh running framegroup. */
virtual int AnimRun(void);
/** Overridable: Returns which framegroup to play for a given ACT. */
virtual float FramegroupForAct(float);
/** Call to play an ACT on the given NSMonster. */
nonvirtual void ActPlay(float);
/** Call to play a single animation onto it, which cannot be interrupted by movement. */
virtual void AnimPlay(float);
/** Internal use only. Run every frame to update animation parameters. */
@ -417,8 +421,11 @@ private:
/* caching variables, don't save these */
float m_actIdle;
bool m_bTurning;
nonvirtual void _LerpTurnToEnemy(void);
nonvirtual void _LerpTurnToPos(vector);
nonvirtual void _LerpTurnToYaw(vector);
virtual void _Alerted(void);
#endif
};

View file

@ -188,19 +188,33 @@ NSMonster::Restore(string strKey, string strValue)
int
NSMonster::AnimIdle(void)
{
return frameforaction(modelindex, ACT_IDLE);
return FramegroupForAct(ACT_IDLE);
}
int
NSMonster::AnimWalk(void)
{
return frameforaction(modelindex, ACT_WALK);
return FramegroupForAct(ACT_WALK);
}
int
NSMonster::AnimRun(void)
{
return frameforaction(modelindex, ACT_RUN);
float runAnim = FramegroupForAct(ACT_RUN);
return (runAnim == -1) ? AnimWalk() : runAnim;
}
float
NSMonster::FramegroupForAct(float actName)
{
float frameGroup = frameforaction(modelindex, actName);
return frameGroup;
}
void
NSMonster::ActPlay(float actName)
{
AnimPlay(FramegroupForAct(actName));
}
void
@ -425,21 +439,21 @@ var float autocvar_ai_stepSize = 128;
float
NSMonster::GetWalkSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, AnimWalk());
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_WALK));
return speed;
}
float
NSMonster::GetChaseSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, AnimRun());
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_RUN));
return speed;
}
float
NSMonster::GetRunSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, AnimRun());
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_RUN));
return speed;
}
@ -453,20 +467,27 @@ NSMonster::GetYawSpeed(void)
}
void
NSMonster::_LerpTurnToEnemy(void)
NSMonster::_LerpTurnToYaw(vector turnYaw)
{
/* only continue if we're in one of the three states. */
if (GetState() != MONSTER_AIMING)
if (GetState() != MONSTER_CHASING)
if (GetState() != MONSTER_FOLLOWING)
return;
if (!m_eEnemy)
return;
float turnSpeed = GetYawSpeed();
vector vecWishAngle = vectoangles(m_eEnemy.origin - origin);
float yawDiff = anglesub(vecWishAngle[1], v_angle[1]);
vector vecWishAngle = turnYaw;
float yawDiff = anglesub(turnYaw[1], v_angle[1]);
if (fabs(yawDiff) > 90) {
velocity = g_vec_null;
input_movevalues = g_vec_null;
if (m_bTurning == false)
if (yawDiff < 0) {
SetFrame(FramegroupForAct(ACT_TURN_RIGHT));
} else {
SetFrame(FramegroupForAct(ACT_TURN_LEFT));
}
m_bTurning = true;
} else {
m_bTurning = false;
}
/* min/max out the diff */
if (yawDiff > 0) {
@ -487,6 +508,29 @@ NSMonster::_LerpTurnToEnemy(void)
angles[1] = input_angles[1] = v_angle[1] = vecWishAngle[1];
}
void
NSMonster::_LerpTurnToPos(vector turnPos)
{
vector vecWishAngle = vectoangles(turnPos - origin);
_LerpTurnToYaw(vecWishAngle);
}
void
NSMonster::_LerpTurnToEnemy(void)
{
if (!m_eEnemy)
return;
/* only continue if we're in one of the three states. */
if (GetState() != MONSTER_AIMING)
if (GetState() != MONSTER_CHASING)
if (GetState() != MONSTER_FOLLOWING)
return;
_LerpTurnToPos(m_eEnemy.origin);
}
void
NSMonster::AttackThink(void)
{
@ -662,29 +706,7 @@ NSMonster::WalkRoute(void)
return;
/* yaw interpolation */
{
float turnSpeed = GetYawSpeed();
vector vecWishAngle = input_angles;
float yawDiff = anglesub(vecWishAngle[1], v_angle[1]);
/* min/max out the diff */
if (yawDiff > 0) {
v_angle[1] += turnSpeed * frametime;
if (v_angle[1] > vecWishAngle[1])
v_angle[1] = vecWishAngle[1];
} else if (yawDiff < 0) {
v_angle[1] -= turnSpeed * frametime;
if (v_angle[1] < vecWishAngle[1])
v_angle[1] = vecWishAngle[1];
}
/* fix angles */
makevectors(v_angle);
vecWishAngle = vectoangles( v_forward );
angles[1] = input_angles[1] = v_angle[1] = vecWishAngle[1];
}
_LerpTurnToYaw(input_angles);
}
void
@ -699,6 +721,9 @@ NSMonster::AnimationUpdate(void)
if (GetState() == MONSTER_AIMING)
return;
if (m_bTurning)
return;
float spvel = vlen(velocity);
float midspeed = GetWalkSpeed() + ((GetRunSpeed() - GetWalkSpeed()) * 0.5f);
@ -813,6 +838,7 @@ NSMonster::Physics(void)
input_buttons = 0;
input_timelength = frametime;
input_angles = angles;
m_bTurning = false;
/* when stuck in a sequence, forget enemies, combat stance */
if (GetSequenceState() != SEQUENCESTATE_NONE) {

View file

@ -0,0 +1,60 @@
/*
* 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.
*/
#define NSSQUADMONSTER_MAXMEMBERS 5
/** NSSquadMonster based NPCs are able to communicate strategies together. */
class
NSSquadMonster:NSMonster
{
public:
void NSSquadMonster(void);
#ifdef SERVER
/** Overridable: Called when this NPC became squad leader. */
virtual void HasBecomeSquadLeader(void);
/** Overridable: Called when this NPC joined a squad. */
virtual void HasJoinedSquad(void);
/** Returns true/false if they're in a squad. */
nonvirtual bool InSquad(void);
/** Returns whether or not they're the squad leader. */
nonvirtual bool IsSquadLeader(void);
/** Returns the leader of their squad. Invalid if none. */
nonvirtual NSSquadMonster GetSquadLeader(void);
/** Will find and attach to a Squad in the specified radius. */
nonvirtual void FindSquadNearMe(float);
/** Will add the specified NPC to this entity's current squad. */
nonvirtual void AddToSquad(NSSquadMonster);
/** Will remove the specified NPC from this entity's current squad. Can be called on self. */
nonvirtual void RemoveFromSquad(NSSquadMonster);
/** Returns the nearest available member of its squad. */
nonvirtual NSSquadMonster GetNearestSquadMember(void);
/** Returns the farthest available member of its squad. */
nonvirtual NSSquadMonster GetFarthestSquadMember(void);
#endif
#ifdef SERVER
private:
bool m_inSquad;
NSSquadMonster m_eSquadLeader;
/* stored only in the squad leader's memory */
NSSquadMonster m_eSquadMembers[NSSQUADMONSTER_MAXMEMBERS];
#endif
};

View file

@ -0,0 +1,216 @@
/*
* 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.
*/
void
NSSquadMonster::NSSquadMonster(void)
{
#ifdef SERVER
m_inSquad = false;
m_eSquadLeader = __NULL__;
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
m_eSquadMembers[i] = __NULL__;
}
#endif
}
#ifdef SERVER
void
NSSquadMonster::HasBecomeSquadLeader(void)
{
/* implemented by sub-class */
}
void
NSSquadMonster::HasJoinedSquad(void)
{
/* implemented by sub-class */
}
bool
NSSquadMonster::InSquad(void)
{
return m_inSquad;
}
bool
NSSquadMonster::IsSquadLeader(void)
{
if (m_eSquadLeader == this)
return true;
return false;
}
NSSquadMonster
NSSquadMonster::GetSquadLeader(void)
{
return m_eSquadLeader;
}
void
NSSquadMonster::FindSquadNearMe(float searchRadius)
{
entity searchResult = findradius(GetOrigin(), searchRadius);
while (searchResult) {
/* found someone just like us */
if (searchResult != this)
if (searchResult.classname == classname) {
NSSquadMonster squadMember = (NSSquadMonster)searchResult;
/* we found someone, they may not be in a squad (that's ok!)
as they will then create one. */
squadMember.AddToSquad(this);
return;
}
/* advance the chain. */
searchResult = searchResult.chain;
}
}
void
NSSquadMonster::AddToSquad(NSSquadMonster addMember)
{
NSSquadMonster startMember = __NULL__;
if (!addMember)
return;
/* no start? this monster just became a squad leader */
if (InSquad() == false) {
m_eSquadLeader = this;
startMember = this;
m_inSquad = true;
print(sprintf("%s (%d) became squad leader\n", classname, num_for_edict(this)));
HasBecomeSquadLeader();
}
startMember = GetSquadLeader();
/* fit the member into the nearest slot */
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
if (startMember.m_eSquadMembers[i] == __NULL__) {
startMember.m_eSquadMembers[i] = addMember;
addMember.m_eSquadLeader = startMember;
addMember.m_inSquad = true;
addMember.HasJoinedSquad();
print(sprintf("%s (%d) added to squad, member %i\n", classname, num_for_edict(this), i));
return;
}
}
}
void
NSSquadMonster::RemoveFromSquad(NSSquadMonster toRemove)
{
NSSquadMonster startMember = __NULL__;
/* don't bother if not in squad. */
if (InSquad() == false)
return;
if (!toRemove)
return;
startMember = GetSquadLeader();
/* fit the member into the nearest slot */
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
if (startMember.m_eSquadMembers[i] == toRemove) {
startMember.m_eSquadMembers[i] = __NULL__;
toRemove.m_eSquadLeader = __NULL__;
toRemove.m_inSquad = false;
return;
}
}
}
NSSquadMonster
NSSquadMonster::GetNearestSquadMember(void)
{
NSSquadMonster member = __NULL__;
NSSquadMonster nearestMember = __NULL__;
float dist = 0.0f;
float nearestDist = 99999.0f;
NSSquadMonster startMember;
if (InSquad() == false)
return __NULL__;
/* only leaders have the member list */
startMember = GetSquadLeader();
/* iterate through members... */
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
member = startMember.m_eSquadMembers[i];
/* don't recognize self, ever */
if (member == __NULL__ || member == this)
continue;
/* check the distance from us to a valid member */
member = startMember.m_eSquadMembers[i];
dist = vlen(member.GetOrigin() - GetOrigin());
/* found one */
if (dist < nearestDist) {
nearestDist = dist;
nearestMember = member;
}
}
return nearestMember;
}
NSSquadMonster
NSSquadMonster::GetFarthestSquadMember(void)
{
NSSquadMonster member = __NULL__;
NSSquadMonster farthestMember = __NULL__;
float dist = 0.0f;
float farthestDist = 0.0f;
NSSquadMonster startMember;
if (InSquad() == false)
return __NULL__;
/* only leaders have the member list */
startMember = GetSquadLeader();
/* iterate through members... */
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
member = startMember.m_eSquadMembers[i];
/* don't recognize self, ever */
if (member == __NULL__ || member == this)
continue;
/* check the distance from us to a valid member */
member = startMember.m_eSquadMembers[i];
dist = vlen(member.GetOrigin() - GetOrigin());
/* found one */
if (dist > farthestDist) {
farthestDist = dist;
farthestMember = member;
}
}
return farthestMember;
}
#endif

View file

@ -47,37 +47,6 @@ typedef enumflags
It can take damage and can handle variously different types of impact. */
class NSSurfacePropEntity:NSRenderableEntity
{
private:
float m_flBurnNext;
PREDICTED_FLOAT(armor)
PREDICTED_FLOAT_N(health)
#ifdef SERVER
/* fire/burning */
entity m_eBurner;
int m_iBurnWeapon;
float m_flBurnTime;
float m_flBurnDmgTime; /* for whenever they touch a hot flame */
/* I/O */
string m_strOnBreak;
/* life, death */
float m_oldHealth;
/* Surface/PropKit */
int m_iMaterial;
string m_strSurfData;
int m_iPropData;
string m_strPropData;
float m_flDeathTime;
nonvirtual void _SurfaceDataFinish(void);
nonvirtual void _PropDataFinish(void);
#endif
public:
void NSSurfacePropEntity(void);
@ -154,6 +123,11 @@ public:
nonvirtual void SetPropData(string);
/** Returns how many seconds have passed since we died. Will return -1 if not applicable. */
nonvirtual float TimeSinceDeath(void);
/** Sets the colour of the blood of this entity. */
nonvirtual void SetBloodColor(vector);
/** Returns the blood color of this entity. */
nonvirtual vector GetBloodColor(void);
#endif
#ifdef CLIENT
@ -164,8 +138,41 @@ public:
/* misc 'being' methods */
/** Returns the absolute world position of where the eyes are located. */
nonvirtual vector GetEyePos(void);
/** Sets the relative position of the eyes */
/** Sets the relative position of the eyes. */
nonvirtual void SetEyePos(vector);
private:
float m_flBurnNext;
PREDICTED_FLOAT(armor)
PREDICTED_FLOAT_N(health)
#ifdef SERVER
/* fire/burning */
entity m_eBurner;
int m_iBurnWeapon;
float m_flBurnTime;
float m_flBurnDmgTime; /* for whenever they touch a hot flame */
/* I/O */
string m_strOnBreak;
/* life, death */
float m_oldHealth;
vector m_vecBloodColor;
/* Surface/PropKit */
int m_iMaterial;
string m_strSurfData;
int m_iPropData;
string m_strPropData;
float m_flDeathTime;
nonvirtual void _SurfaceDataFinish(void);
nonvirtual void _PropDataFinish(void);
#endif
};
#ifdef CLIENT

View file

@ -30,6 +30,7 @@ NSSurfacePropEntity::NSSurfacePropEntity(void)
m_oldHealth = 0;
m_strSurfData = __NULL__;
m_strPropData = __NULL__;
m_vecBloodColor = [0.5, 0, 0];
#endif
}
@ -63,6 +64,17 @@ NSSurfacePropEntity::Spawned(void)
/* networking */
#ifdef SERVER
void
NSSurfacePropEntity::SetBloodColor(vector newColor)
{
m_vecBloodColor = newColor;
}
vector
NSSurfacePropEntity::GetBloodColor(void)
{
return m_vecBloodColor;
}
bool
NSSurfacePropEntity::IsAlive(void)

View file

@ -34,7 +34,7 @@ information and can speak more complicated dialogue.
They also can communicate with other NSTalkMonster based entities.
*/
class NSTalkMonster:NSMonster
class NSTalkMonster:NSSquadMonster
{
public:
void NSTalkMonster(void);

View file

@ -490,9 +490,10 @@ NSTalkMonster::FollowPlayer(void)
{
float flPlayerDist;
input_angles = vectoangles(m_eFollowingChain.origin - origin);
input_angles[0] = 0;
input_angles[1] = Math_FixDelta(input_angles[1]);
input_angles[2] = 0;
input_angles[0] = 0;
input_angles[1] = Math_FixDelta(input_angles[1]);
input_angles[2] = 0;
_LerpTurnToYaw(input_angles[1]);
/* for best results, we want to ignore the Z plane
this avoids the problem of a follower spinning
@ -521,7 +522,8 @@ NSTalkMonster::FollowPlayer(void)
}
}
input_movevalues[0] = m_flFollowSpeed;
if (DistanceFromYaw(vecParent) > 0.9f)
input_movevalues[0] = m_flFollowSpeed;
other = world;
traceline(origin, m_eFollowingChain.origin, MOVE_OTHERONLY, this);
@ -532,6 +534,7 @@ NSTalkMonster::FollowPlayer(void)
input_angles[0] = 0;
input_angles[1] = Math_FixDelta(input_angles[1]);
input_angles[2] = 0;
_LerpTurnToYaw(input_angles[1]);
} else {
m_vecLastUserPos = m_eFollowingChain.origin;
}
@ -617,7 +620,7 @@ NSTalkMonster::RunAI(void)
void
NSTalkMonster::Respawn(void)
{
NSMonster::Respawn();
super::Respawn();
m_eFollowing = world;
m_eFollowingChain = world;
}
@ -658,7 +661,7 @@ NSTalkMonster::SpawnKey(string strKey, string strValue)
m_talkFollow = strcat("!", strValue);
break;
default:
NSMonster::SpawnKey(strKey, strValue);
super::SpawnKey(strKey, strValue);
break;
}
}

View file

@ -1,119 +0,0 @@
#ifndef MAX_WEAPONS
#define MAX_WEAPONS 32
#endif
/** This class represents inventory items and weapons that you can directly interact with.
Trouble that's standing in the way of this taking off:
Level changes currently only support client entities from setting up
changelevel parameters. There is parm_string that we *could* use to
store weapon entity information in, but this will grow massively.
For the time being, we need to use the legacy system if we want to support
singleplayer.
*/
class
NSWeapon:NSRenderableEntity
{
private:
entity m_owner;
string m_strName; /* Full character name */
int m_iSlot;
int m_iSlotPos;
bool m_bAllowDropping;
int m_iWeight;
/* generic info */
int m_iClip1;
int m_iClip2;
float m_flPrimaryNext;
float m_flSecondaryNext;
float m_flLastFired;
public:
void NSWeapon(void);
/* inspired by GMOD API https://wiki.facepunch.com/gmod/Weapon */
/** Returns the model used to attach to players that wield this weapon */
virtual string GetPlayerModel(void);
/** Returns the model used to display in-world representations of this weapon. */
virtual string GetWorldModel(void);
/** Returns the name used in printed text for this weapon */
virtual string GetPrintName(void);
/** Returns if this weapon is allowed to be dropped. */
virtual bool AllowDropping(void);
/** Returns the framegroup used for the top-half of a player when aiming this weapon. */
virtual int GetPlayerAnim(void);
/** Returns a formatted obituary message.
Should contain two %s parameters, the first is the attacker and the second is the target. */
virtual string GetObituaryMessage(void);
/** Returns the weapon type. Check weapontype_t for details. */
virtual int GetType(void);
/** Returns primary attack clip */
virtual int GetClip1(void);
/** Returns secondary attack clip */
virtual int GetClip2(void);
/** Returns primary max clip size */
virtual int GetMaxClip1(void);
/** Returns secondary max clip size */
virtual int GetMaxClip2(void);
/** Returns the next time the primary mode can fire */
virtual float GetNextPrimaryFire(void);
/** Returns the next time the secondary mode can fire */
virtual float GetNextSecondaryFire(void);
/** Returns the slot/HUD category the weapon belongs in. */
virtual int GetSlot(void);
/** Returns the position the weapon belongs in of the slot specified in GetSlot() */
virtual int GetSlotPos(void);
/** Returns the 'weight', used for deciding what the next best weapon to switch to is. */
virtual int GetWeight(void);
/** Returns absolute time at which the weapon was last fired */
virtual float LastFireTime(void);
/** Sets the primary ammo clip count */
virtual void SetClip1(int);
/** Sets the secondary ammo clip count */
virtual void SetClip2(int);
/** Returns whether the weapon allows to being switched from when a better weighted weapon is picked up */
virtual bool AllowsAutoSwitchFrom(void);
/** Returns whether the weapon allows to being switched to when a better weighted weapon is picked up */
virtual bool AllowsAutoSwitchTo(void);
/** Returns if the weapon is empty, with no reserve ammonition */
virtual bool IsEmpty(void);
/** Returns if the weapon has ammo left in it. */
virtual bool HasAmmo(void);
/* calls */
/** Called to reload resources utilized by this weapon. */
virtual void Precache(void);
/** Called when the weapon was switched to from another. */
virtual void Draw(void);
/** Called right before switching to a new weapon. */
virtual void Holster(void);
/** Called whenever the command +attack is called by a client. */
virtual void Primary(void);
/** Called whenever the command +attack2 is called by a client. */
virtual void Secondary(void);
/** Called whenever the command +reload is called by a client. */
virtual void Reload(void);
/** Called whenever the no weapon command is called by a client. */
virtual void Release(void);
#ifdef CLIENT
/** Called before 3D world rendering is performed. */
virtual void ClientPredraw(void);
/** Called after 3D world rendering is performed. */
virtual void ClientPostdraw(void);
virtual void ReceiveEntity(float, float);
#endif
#ifdef SERVER
virtual float SendEntity(entity, float);
virtual void Touch(entity);
virtual void Respawn(void);
#endif
};

View file

@ -1,246 +0,0 @@
void
NSWeapon::NSWeapon(void)
{
}
/* calls */
void
NSWeapon::Precache(void)
{
}
void
NSWeapon::Draw(void)
{
}
void
NSWeapon::Holster(void)
{
}
void
NSWeapon::Primary(void)
{
}
void
NSWeapon::Secondary(void)
{
}
void
NSWeapon::Reload(void)
{
}
void
NSWeapon::Release(void)
{
}
#ifdef CLIENT
void
NSWeapon::ClientPredraw(void)
{
}
void
NSWeapon::ClientPostdraw(void)
{
}
void
NSWeapon::ReceiveEntity(float new, float flChanged)
{
}
#endif
#ifdef SERVER
float
NSWeapon::SendEntity(entity ePEnt, float flChanged)
{
/* if we have a model, assume we're a pickup */
if (modelindex) {
return super::SendEntity(ePEnt, flChanged);
}
/* don't network to anyone but the owner */
if (ePEnt != owner) {
return (false);
}
#if 0
WriteByte(MSG_ENTITY, ENT_WEAPON);
WriteFloat(MSG_ENTITY, flChanged);
WriteInt(MSG_ENTITY, m_iSlot);
WriteInt(MSG_ENTITY, m_iSlotPos);
WriteByte(MSG_ENTITY, m_bAllowDropping);
WriteInt(MSG_ENTITY, m_iWeight);
WriteInt(MSG_ENTITY, m_iClip1);
WriteInt(MSG_ENTITY, m_iClip2);
WriteFloat(MSG_ENTITY, m_flPrimaryNext);
WriteFloat(MSG_ENTITY, m_flSecondaryNext);
WriteFloat(MSG_ENTITY, m_flLastFired);
#endif
return (true);
}
void
NSWeapon::Touch(entity eToucher)
{
Hide();
SetSolid(SOLID_NOT);
}
void
NSWeapon::Respawn(void)
{
/* the weapons gets placed in-world */
SetModel(GetWorldModel());
SetSolid(SOLID_TRIGGER);
SetOrigin(GetSpawnOrigin());
}
#endif
/* get */
string
NSWeapon::GetPlayerModel(void)
{
return "models/error.vvm";
}
string
NSWeapon::GetWorldModel(void)
{
return "models/error.vvm";
}
string
NSWeapon::GetPrintName(void)
{
return m_strName;
}
int
NSWeapon::GetSlot(void)
{
return m_iSlot;
}
int
NSWeapon::GetSlotPos(void)
{
return m_iSlotPos;
}
bool
NSWeapon::AllowDropping(void)
{
return false;
}
int
NSWeapon::GetWeight(void)
{
return 0;
}
int
NSWeapon::GetPlayerAnim(void)
{
return 0;
}
bool
NSWeapon::IsEmpty(void)
{
return false;
}
string
NSWeapon::GetObituaryMessage(void)
{
return "%s killed %s with Unknown";
}
int
NSWeapon::GetType(void)
{
return 0;
}
int
NSWeapon::GetClip1(void)
{
return 0;
}
int
NSWeapon::GetClip2(void)
{
return 0;
}
int
NSWeapon::GetMaxClip1(void)
{
return 0;
}
int
NSWeapon::GetMaxClip2(void)
{
return 0;
}
float
NSWeapon::GetNextPrimaryFire(void)
{
return m_flPrimaryNext;
}
float
NSWeapon::GetNextSecondaryFire(void)
{
return m_flSecondaryNext;
}
float
NSWeapon::LastFireTime(void)
{
return m_flLastFired;
}
void
NSWeapon::SetClip1(int new_clip)
{
m_iClip1 = new_clip;
}
void
NSWeapon::SetClip2(int new_clip)
{
m_iClip1 = new_clip;
}
bool
NSWeapon::AllowsAutoSwitchFrom(void)
{
return true;
}
bool
NSWeapon::AllowsAutoSwitchTo(void)
{
return true;
}
bool
NSWeapon::HasAmmo(void)
{
return false;
}

View file

@ -62,6 +62,7 @@ string __fullspawndata;
#include "NSPointTrigger.h"
#include "NSNavAI.h"
#include "NSMonster.h"
#include "NSSquadMonster.h"
#include "NSTalkMonster.h"
#include "NSProjectile.h"
#include "NSItem.h"
@ -71,7 +72,6 @@ string __fullspawndata;
#include "../xr/defs.h"
#include "NSClient.h"
#include "NSClientSpectator.h"
#include "NSWeapon.h"
#include "NSClientPlayer.h"
#include "NSVehicle.h"

View file

@ -10,10 +10,10 @@ NSMoverEntity.qc
NSPhysicsEntity.qc
NSBrushTrigger.qc
NSPointTrigger.qc
NSWeapon.qc
NSVehicle.qc
NSNavAI.qc
NSMonster.qc
NSSquadMonster.qc
NSTalkMonster.qc
NSProjectile.qc
NSItem.qc