EntityDef work on NSMonster, NSTalkMonster, NSProjectile etc.

This commit is contained in:
Marco Cawthorne 2023-06-20 21:19:00 -07:00
parent 69d1498c8b
commit 31774ce3f1
Signed by: eukara
GPG Key ID: CE2032F0A2882A22
13 changed files with 855 additions and 45 deletions

View File

@ -83,7 +83,8 @@ enum
EDEFTWEAK_EQ = 0,
EDEFTWEAK_LT,
EDEFTWEAK_GT,
EDEFTWEAK_NOT
EDEFTWEAK_NOT,
EDEFTWEAK_CONTAINS
};
typedef struct
@ -203,16 +204,19 @@ EntityDef_ReadFile(string filePath)
switch (argv(i+2)) {
case "equals":
currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 0 ", argv(i+3), ";");
break;
break;
case "less-than":
currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 1 ", argv(i+3), ";");
break;
break;
case "greater-than":
currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 2 ", argv(i+3), ";");
break;
break;
case "is-not":
currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 3 ", argv(i+3), ";");
break;
case "contains":
currentDef.tweakDefs = strcat(currentDef.tweakDefs, argv(i+1), " 4 ", argv(i+3), ";");
break;
}
inEvent = false;
@ -264,7 +268,7 @@ EntityDef_Init(void)
}
}
#if 1
#if 0
for (int i = 0i; i < g_entDefCount; i++) {
int numKeys = tokenize_console(g_entDefTable[i].spawnData);
print(sprintf("edef %i: %S\n", i, g_entDefTable[i].entClass));
@ -323,6 +327,12 @@ EntityDef_CheckCondition(int id, string keyWord, float tweakCondition, string ke
case EDEFTWEAK_NOT:
if (key == keyWord && value != keyValue)
return true;
case EDEFTWEAK_CONTAINS:
tmp1 = stof(keyValue);
tmp2 = stof(value);
if (key == keyWord && tmp2 & tmp1)
return true;
break;
}
}
@ -456,6 +466,19 @@ EntityDef_Precaches(int index)
spawnWords = tokenize_console(g_entDefTable[index].spawnData);
}
}
/* handle soundDef events */
spawnWords = tokenize(g_entDefTable[index].eventList);
for (int i = 0; i < spawnWords; i+=3) {
int testCode = stoi(argv(i+0));
string testInput = argv(i+1);
string testData = argv(i+2);
if (testInput == "StartSoundDef") {
Sound_Precache(testData);
tokenize(g_entDefTable[index].eventList);
}
}
}
NSEntity

View File

@ -358,6 +358,9 @@ public:
/** Returns either true or false depending on if this entity is facing the entity in question. */
nonvirtual bool IsFacing(entity);
/** Returns either true or false depending on if this entity is facing a position in question. */
nonvirtual bool IsFacingPosition(vector);
/** Returns the time that's passed since the entity has been spawned. */
nonvirtual float GetSpawnAge(void);

View File

@ -748,6 +748,19 @@ void NSEntity::Input( entity eAct, string strInput, string strData ) {
if ( PlayerUse )
PlayerUse();
break;
case "SpawnDef":
break;
case "SpawnProjectileDef":
if (EntityDef_HasSpawnClass(strData)) {
NSProjectile_SpawnDefAttachment(strData, this, 0);
} else {
float rangedDmg = Skill_GetDefValue(EntityDef_GetKeyValue(strData, "damage"));
TraceAttack_FireBullets(1, origin + view_ofs, rangedDmg, [0.01,0.01], 0);
}
break;
case "StartSoundDef":
StartSoundDef(strData, CHAN_VOICE, true);
break;
default:
NSTrigger::Input( eAct, strInput, strData );
}
@ -902,6 +915,13 @@ bool NSEntity::IsFacing(entity target)
return ((vecDiff * v_forward) > 0 ) ? true : false;
}
bool NSEntity::IsFacingPosition(vector targetPos)
{
vector vecDiff = normalize(targetPos - origin);
makevectors(angles);
return ((vecDiff * v_forward) > 0 ) ? true : false;
}
float
NSEntity::GetSpawnAge(void)
{

View File

@ -50,6 +50,7 @@ typedef enumflags
MONFL_CHANGED_RENDERCOLOR,
MONFL_CHANGED_RENDERAMT,
MONFL_CHANGED_RENDERMODE,
MONFL_CHANGED_HEADYAW
} nsmonster_changed_t;
/** List of supported ACT types.
@ -373,11 +374,19 @@ public:
private:
vector v_angle_net;
#ifdef CLIENT
nonvirtual void _RenderDebugViewCone();
#endif
PREDICTED_FLOAT(m_flHeadYaw)
PREDICTED_FLOAT_N(frame1time)
PREDICTED_FLOAT_N(subblendfrac)
PREDICTED_FLOAT_N(bonecontrol1)
#ifdef SERVER
entity m_eLookAt;
entity m_ssLast;
vector oldnet_velocity;
float m_flPitch;
@ -422,6 +431,70 @@ private:
/* caching variables, don't save these */
float m_actIdle;
bool m_bTurning;
float m_flIdleNext;
float _m_flMeleeAttempts;
float _m_flMeleeDelay;
float _m_flBurstCount;
bool _m_bShouldThrow;
/* save these please */
float _m_flReloadTracker;
bool m_bWeaponDrawn;
/* entityDef related */
float m_flEyeHeight;
string m_sndSight;
string m_sndIdle;
float m_flIdleMin;
float m_flIdleMax;
string m_sndFootstep;
string m_sndChatter;
string m_sndChatterCombat;
string m_sndPain;
string m_sndMeleeAttack;
string m_sndMeleeAttackHit;
string m_sndMeleeAttackMiss;
string m_sndDeath;
string m_sndThud;
/* attack definitions, if defined will fire projectiles */
string m_defSpecial1;
float m_flSpecial1Range;
string m_defSpecial2;
float m_flSpecial2Range;
string m_defRanged1;
float m_flRanged1Range;
string m_defRanged2;
float m_flRanged2Range;
/* ranged1 only */
int m_iNumProjectiles;
float m_flProjectileDelay;
float m_flProjectileSpread;
/* general */
float m_flAttackCone;
float m_flAttackAccuracy;
/* melee attack */
string m_defMelee;
float m_flMeleeRange;
string m_sndRangedAttack;
float m_flReloadCount;
float m_flReloadDelay;
string m_sndReload;
string m_sndRangedAttack2;
bool m_bWeaponStartsDrawn;
float m_flBodyOnDraw;
float m_flWalkSpeed;
float m_flRunSpeed;
nonvirtual void _LerpTurnToEnemy(void);
nonvirtual void _LerpTurnToPos(vector);

View File

@ -6,7 +6,7 @@
* 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
* 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
@ -14,6 +14,9 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var float autocvar_ai_walkSpeed = 64;
var float autocvar_ai_runSpeed = 364;
void
NSMonster::NSMonster(void)
{
@ -51,6 +54,44 @@ NSMonster::NSMonster(void)
m_flAnimTime = 0.0f;
m_flTrackingTime = 0.0f;
m_actIdle = -1;
m_flIdleNext = 0.0f;
m_flEyeHeight = 64.0f;
m_sndSight = __NULL__;
m_sndIdle = __NULL__;
m_flIdleMin = 5.0f;
m_flIdleMax = 10.0f;
m_sndFootstep = __NULL__;
m_sndChatter = __NULL__;
m_sndChatterCombat = __NULL__;
m_sndPain = __NULL__;
m_sndMeleeAttack = __NULL__;
m_sndMeleeAttackHit = __NULL__;
m_sndMeleeAttackMiss = __NULL__;
m_sndDeath = __NULL__;
m_sndThud = __NULL__;
m_defMelee = __NULL__;
m_defSpecial1 = __NULL__;
m_iNumProjectiles = 1i;
m_flProjectileDelay = 0.0f;
m_flProjectileSpread = 0.0f;
m_flAttackCone = 0.0f;
m_flAttackAccuracy = 1.0f;
m_flMeleeRange = -1;
m_defRanged1 = __NULL__;
m_defRanged2 = __NULL__;
/* invalidate all ranges. */
m_flRanged1Range =
m_flRanged2Range =
m_flSpecial1Range =
m_flSpecial2Range = -1.0f;
m_bWeaponStartsDrawn = true;
m_flWalkSpeed = autocvar_ai_walkSpeed;
m_flRunSpeed = autocvar_ai_runSpeed;
#endif
}
@ -245,7 +286,9 @@ NSMonster::Gib(void)
vector vecDir = vectoangles(GetOrigin() - g_dmg_vecLocation);
SetState(MONSTER_DEAD);
SetTakedamage(DAMAGE_NO);
FX_GibHuman(origin, vecDir, g_dmg_iDamage * 2.5f);
string breakModel = GetPropData(PROPINFO_BREAKMODEL);
BreakModel_Spawn(absmin, absmax, vecDir, g_dmg_iDamage * 2.5f, vlen(size) / 10, breakModel);
Disappear();
}
@ -257,11 +300,17 @@ NSMonster::FallNoise(void)
void
NSMonster::IdleNoise(void)
{
if (m_flIdleNext > time)
return;
StartSoundDef(m_sndIdle, CHAN_VOICE, true);
m_flIdleNext = time + random(m_flIdleMin, m_flIdleMax);
}
void
NSMonster::AlertNoise(void)
{
StartSoundDef(m_sndSight, CHAN_VOICE, true);
}
bool
@ -279,7 +328,7 @@ NSMonster::IsFriend(int al)
float
NSMonster::MeleeMaxDistance(void)
{
return 96;
return m_flMeleeRange;
}
/* Whether or not we should attempt a melee attack */
@ -302,6 +351,9 @@ NSMonster::AlertNearby(void)
return;
for (entity w = world; (w = findfloat(w, ::takedamage, DAMAGE_YES));) {
if (w.classname != classname)
continue;
if (!IsFriend(w.m_iAlliance))
continue;
@ -362,6 +414,22 @@ NSMonster_TraceAgainsTarget(NSMonster monster, NSEntity target)
void
NSMonster::SeeThink(void)
{
if (m_eLookAt) {
vector vecDelta;
makevectors( angles );
vecDelta = normalize( (m_eLookAt.origin + m_eLookAt.view_ofs) - GetEyePos() );
m_flHeadYaw = (vecDelta * v_right) * -60;
//print(sprintf("head yaw: %f %v\n", m_flHeadYaw, vecDelta));
/* this will make the actor 'aim" at the target */
{
makevectors(v_angle);
vector tmp = vectoangles(v_forward);
subblendfrac = tmp[0] / 90;
bonecontrol1 = m_flHeadYaw; /* head turning */
}
}
if (m_flAttackThink < time)
if (m_eEnemy) {
/* check if we should invalidate current enemy */
@ -371,6 +439,7 @@ NSMonster::SeeThink(void)
return;
m_flSeeTime = time + 0.25f;
m_eLookAt = m_eEnemy;
/* see if we can trace our target, if yes, update our timestamp */
if (NSMonster_TraceAgainsTarget(this, (NSEntity) m_eEnemy) == true) {
@ -391,6 +460,7 @@ NSMonster::SeeThink(void)
SetState(MONSTER_ALERT);
m_eEnemy = __NULL__;
m_eLookAt = __NULL__;
m_flSeeTime = 0;
}
@ -434,27 +504,22 @@ NSMonster::SeeThink(void)
}
}
var float autocvar_ai_stepSize = 128;
float
NSMonster::GetWalkSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_WALK));
return speed;
return m_flWalkSpeed;
}
float
NSMonster::GetChaseSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_RUN));
return speed;
return m_flRunSpeed;
}
float
NSMonster::GetRunSpeed(void)
{
float speed = autocvar_ai_stepSize / frameduration(modelindex, FramegroupForAct(ACT_RUN));
return speed;
return m_flRunSpeed;
}
float
@ -519,6 +584,9 @@ NSMonster::_LerpTurnToPos(vector turnPos)
void
NSMonster::_LerpTurnToEnemy(void)
{
vector enemyEyePos;
vector dirAim;
if (!m_eEnemy)
return;
@ -529,6 +597,11 @@ NSMonster::_LerpTurnToEnemy(void)
return;
_LerpTurnToPos(m_eEnemy.origin);
enemyEyePos = (m_eEnemy.origin + m_eEnemy.view_ofs);
dirAim = vectoangles(enemyEyePos - GetEyePos());
v_angle[0] = dirAim[0];
}
void
@ -545,7 +618,7 @@ NSMonster::AttackThink(void)
/* do we have a clear shot? */
other = world;
traceline(origin, m_eEnemy.origin, MOVE_OTHERONLY, this);
traceline(GetEyePos(), m_eEnemy.origin, MOVE_OTHERONLY, this);
/* something is blocking us */
if (trace_fraction < 1.0f) {
@ -589,13 +662,165 @@ NSMonster::AttackThink(void)
int
NSMonster::AttackMelee(void)
{
m_flAttackThink = time + 0.5f;
return (0);
float actMelee1 = FramegroupForAct(ACT_MELEE_ATTACK1);
float actMelee2 = FramegroupForAct(ACT_MELEE_ATTACK2);
if (!m_defMelee)
return (0);
_m_flMeleeDelay = Skill_GetDefValue(EntityDef_GetKeyValue(m_defMelee, "delay"));
_m_flMeleeAttempts = Skill_GetDefValue(EntityDef_GetKeyValue(m_defMelee, "attempts"));
//print(sprintf("Melee attack %S with delay %f and %d attempts\n", m_defMelee, _m_flMeleeDelay, _m_flMeleeAttempts));
static void
AttackMelee_AttackFlail(void)
{
float meleeDmg = Skill_GetDefValue(EntityDef_GetKeyValue(m_defMelee, "damage"));
float meleeWait = Skill_GetDefValue(EntityDef_GetKeyValue(m_defMelee, "wait"));
traceline(origin, m_eEnemy.origin, FALSE, this);
if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) {
StartSoundDef(m_sndMeleeAttackMiss, CHAN_WEAPON, true);
return;
}
Damage_Apply(trace_ent, this, meleeDmg, 0, 0);
StartSoundDef(m_sndMeleeAttackHit, CHAN_WEAPON, true);
_m_flMeleeAttempts--;
if (_m_flMeleeAttempts > 0)
ScheduleThink(AttackMelee_AttackFlail, _m_flMeleeDelay + meleeWait);
}
if (random() < 0.5 || actMelee2 == -1)
AnimPlay(actMelee1);
else
AnimPlay(actMelee2);
m_flAttackThink = m_flAnimTime;
StartSoundDef(m_sndMeleeAttack, CHAN_WEAPON, true);
/* functional */
ScheduleThink(AttackMelee_AttackFlail, _m_flMeleeDelay);
return (1);
}
int
NSMonster::AttackRanged(void)
{
static void AttackRanged_Throw(void)
{
for (int i = 0; i < m_iNumProjectiles; i++)
NSProjectile_SpawnDef(m_defSpecial1, this);
}
static void AttackRanged_RangedSpecial(void)
{
NSProjectile_SpawnDef(m_defRanged2, this);
}
float distToEnemy = vlen(m_eEnemy.origin - GetOrigin());
bool inSpecial1Range = (distToEnemy < m_flSpecial1Range && m_flSpecial1Range != -1.0) ? true : false;
bool inSpecial2Range = (distToEnemy < m_flSpecial2Range && m_flSpecial2Range != -1.0) ? true : false;
bool inRanged1Range = (distToEnemy < m_flRanged1Range && m_flRanged1Range != -1.0) ? true : false;
bool inRanged2Range = (distToEnemy < m_flRanged2Range && m_flRanged2Range != -1.0) ? true : false;
bool throwAnyway = false;
traceline(GetEyePos(), m_eEnemy.origin, MOVE_NORMAL, this);
if (_m_bShouldThrow == false && inSpecial1Range && m_flReloadCount)
if (_m_flReloadTracker > m_flReloadCount) {
throwAnyway = true;
_m_bShouldThrow = true;
}
/* special always first if possible */
if (throwAnyway == false && inRanged1Range && trace_ent == m_eEnemy) {
float rangedDmg = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "damage"));
float rangedDly = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "delay"));
float rangedMin = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "delay_min"));
float rangedMax = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "delay_max"));
float burstCount = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "burst"));
float burstDelay = Skill_GetDefValue(EntityDef_GetKeyValue(m_defRanged1, "burst_delay"));
float actRanged = FramegroupForAct(ACT_RANGE_ATTACK1);
float burstTime = 0.0f;
if (rangedDly <= 0.0) {
rangedDly = random(rangedMin, rangedMax);
}
/* can't shoot anything ranged anymore, need to reload. */
if (m_flReloadCount)
if (_m_flReloadTracker > m_flReloadCount) {
float actReload = FramegroupForAct(ACT_RELOAD);
_m_flReloadTracker = 0;
AnimPlay(actReload);
StartSoundDef(m_sndReload, CHAN_WEAPON, true);
_m_bShouldThrow = false;
if (m_flReloadDelay)
m_flAttackThink = time + m_flReloadDelay;
else
m_flAttackThink = time + frameduration(modelindex, actReload);
return 1;
}
AnimPlay(actRanged);
/* if we have no spawnclass, it must be a hitscan weapon */
if (EntityDef_HasSpawnClass(m_defRanged1)) {
NSProjectile_SpawnDef(m_defRanged1, this);
} else {
TraceAttack_FireBullets(1, GetEyePos(), rangedDmg, [0.01,0.01] * m_flAttackAccuracy, 0);
}
StartSoundDef(m_sndRangedAttack, CHAN_WEAPON, true);
_m_flBurstCount++;
_m_flReloadTracker++;
if (burstCount)
if (_m_flBurstCount >= burstCount) {
_m_flBurstCount = 0;
burstTime = burstDelay;
}
if (rangedDly)
m_flAttackThink = time + rangedDly + burstTime;
else
m_flAttackThink = time + frameduration(modelindex, actRanged) + burstTime;
return 1;
} else if (throwAnyway == false && inRanged2Range && trace_ent == m_eEnemy) {
float actRangedSpecial = FramegroupForAct(ACT_RANGE_ATTACK2);
AnimPlay(actRangedSpecial);
ScheduleThink(AttackRanged_RangedSpecial, 0.0f);
m_flAttackThink = time + frameduration(modelindex, actRangedSpecial);
return 1;
} else if (inSpecial1Range) {
AnimPlay(FramegroupForAct(ACT_SPECIAL_ATTACK1));
ScheduleThink(AttackRanged_Throw, m_flProjectileDelay);
if (_m_bShouldThrow)
m_flAttackThink = time + 1.0f;
else
m_flAttackThink = time + 2.5f;
return 1;
} else if (inSpecial2Range) {
AnimPlay(FramegroupForAct(ACT_SPECIAL_ATTACK2));
ScheduleThink(AttackRanged_Throw, m_flProjectileDelay);
if (_m_bShouldThrow)
m_flAttackThink = time + 1.0f;
else
m_flAttackThink = time + 2.5f;
return 1;
}
m_flAttackThink = time + 0.5f;
return (0);
}
@ -603,15 +828,20 @@ NSMonster::AttackRanged(void)
void
NSMonster::AttackDraw(void)
{
NSMonster_Log("^1%s::AttackDraw: Not defined!", classname);
m_flAttackThink = time + 0.5f;
float actDraw = FramegroupForAct(ACT_ARM);
AnimPlay(actDraw);
m_flAttackThink = time + frameduration(modelindex, actDraw);
if (m_flBodyOnDraw)
SetBody(m_flBodyOnDraw);
}
void
NSMonster::AttackHolster(void)
{
NSMonster_Log("^1%s::AttackHolster: Not defined!", classname);
m_flAttackThink = time + 0.5f;
float actHolster = FramegroupForAct(ACT_DISARM);
AnimPlay(actHolster);
m_flAttackThink = time + frameduration(modelindex, actHolster);
}
void
@ -787,8 +1017,27 @@ NSMonster::IsAlive(void)
void
NSMonster::StateChanged(monsterState_t oldState, monsterState_t newState)
{
NSMonster_Log("^2%s::^3StateChanged^7: state changed from %d to %d", \
classname, oldState, newState);
switch (newState) {
case MONSTER_AIMING:
/* we're coming from an alerted/raised state to pointing a gun. */
if (oldState == MONSTER_ALERT) {
/* only draw if it wasn't already drawn */
if (m_bWeaponDrawn == false) {
AttackDraw();
m_bWeaponDrawn = true;
}
}
break;
case MONSTER_ALERT:
if (oldState == MONSTER_AIMING) {
/* only holster if it wasn't in the initial state either */
if (m_bWeaponStartsDrawn == false) {
AttackHolster();
m_bWeaponDrawn = false;
}
}
break;
}
}
void
@ -899,8 +1148,7 @@ NSMonster::Physics(void)
}
}
m_flBaseTime = frame1time;
frame1time += frametime;
//print(sprintf("%f was %f\n", frame1time, m_flBaseTime));
processmodelevents(modelindex, frame, m_flBaseTime,
frame1time, HandleAnimEvent);
@ -912,6 +1160,7 @@ NSMonster::Touch(entity eToucher)
if (movetype != MOVETYPE_WALK)
return;
if (autocvar(pm_pushMonsters, 0))
if (eToucher.movetype == MOVETYPE_WALK) {
if (eToucher.absmin[2] < origin[2])
velocity = normalize(eToucher.origin - origin) * -128;
@ -927,6 +1176,11 @@ NSMonster::HasBeenHit(void)
void
NSMonster::Pain(void)
{
float actSmallFlinch = FramegroupForAct(ACT_SMALL_FLINCH);
float actBigFlinch = FramegroupForAct(ACT_BIG_FLINCH);
float actTwitch = FramegroupForAct(ACT_TWITCH);
float actPain = -1;
/* dead things tell nuthin */
if (IsAlive() == false)
return;
@ -951,6 +1205,42 @@ NSMonster::Pain(void)
/* alert all nearby friendlies */
AlertNearby();
switch (g_dmg_iHitBody) {
case BODY_HEAD:
actPain = FramegroupForAct(ACT_FLINCH_HEAD);
break;
case BODY_CHEST:
actPain = FramegroupForAct(ACT_FLINCH_CHEST);
break;
case BODY_STOMACH:
actPain = FramegroupForAct(ACT_FLINCH_STOMACH);
break;
case BODY_ARMLEFT:
actPain = FramegroupForAct(ACT_FLINCH_LEFTARM);
break;
case BODY_ARMRIGHT:
actPain = FramegroupForAct(ACT_FLINCH_RIGHTARM);
break;
case BODY_LEGLEFT:
actPain = FramegroupForAct(ACT_FLINCH_LEFTLEG);
break;
case BODY_LEGRIGHT:
actPain = FramegroupForAct(ACT_FLINCH_RIGHTLEG);
break;
}
/* fallback in case we do not have specialized flinches */
if (actPain == -1) {
/* for big damage pain anim, we need to take at least 1/3rd of health */
if (actBigFlinch >= 0 && g_dmg_iDamage > (base_health / 3))
actPain = actBigFlinch;
else if (actSmallFlinch >= 0)
actPain = actSmallFlinch;
}
AnimPlay(actPain);
StartSoundDef(m_sndPain, CHAN_VOICE, true);
HasBeenHit();
}
@ -981,6 +1271,19 @@ NSMonster::_Alerted(void)
void
NSMonster::Death(void)
{
static void Death_Thud(void)
{
StartSoundDef(m_sndThud, CHAN_BODY, true);
}
float actViolent = FramegroupForAct(ACT_DIEVIOLENT);
float actForward = FramegroupForAct(ACT_DIEFORWARD);
float actBackward = FramegroupForAct(ACT_DIEBACKWARD);
float actSimple = FramegroupForAct(ACT_DIESIMPLE);
float actBackshot = FramegroupForAct(ACT_DIE_BACKSHOT);
float actDeath = -1;
/* we were already dead before, so gib */
if (GetState() == MONSTER_DEAD) {
HasBeenGibbed();
@ -997,8 +1300,37 @@ NSMonster::Death(void)
return;
}
/* make sure we're not causing any more obituaries */
switch (g_dmg_iHitBody) {
case BODY_HEAD:
actDeath = FramegroupForAct(ACT_DIE_HEADSHOT);
break;
case BODY_CHEST:
actDeath = FramegroupForAct(ACT_DIE_CHESTSHOT);
break;
case BODY_STOMACH:
actDeath = FramegroupForAct(ACT_DIE_GUTSHOT);
break;
}
if (actDeath == -1) {
if (actViolent >= 0 && GetHealth() < -15) /* lots of damage */
AnimPlay(actViolent);
else if (actBackshot >= 0 && IsFacingPosition(g_dmg_vecLocation) == false)
AnimPlay(actBackshot);
else if (actForward >= 0 && IsFacingPosition(g_dmg_vecLocation) == false)
AnimPlay(actForward);
else if (actBackward >= 0 && IsFacingPosition(g_dmg_vecLocation) == true)
AnimPlay(actBackward);
else
AnimPlay(actSimple);
} else {
AnimPlay(actDeath);
}
StartSoundDef(m_sndDeath, CHAN_VOICE, true);
HasBeenKilled();
/* make sure we're not causing any more obituaries */
RemoveFlags(FL_MONSTER);
/* set the monster up for getting gibbed */
@ -1010,6 +1342,9 @@ NSMonster::Death(void)
/* monsters trigger their targets when dead */
if (GetTriggerCondition() == MTRIG_DEATH)
TriggerTargets();
/* play thud sound */
ScheduleThink(Death_Thud, frameduration(modelindex, frame) * 0.5f);
}
#if 0
@ -1047,8 +1382,15 @@ NSMonster::Respawn(void)
SetModel(GetSpawnModel());
SetSize(base_mins, base_maxs);
SetOrigin(GetSpawnOrigin());
SetEyePos([0, 0, m_flEyeHeight]);
DropToFloor();
if (m_bWeaponStartsDrawn) {
m_bWeaponDrawn = true;
} else {
m_bWeaponDrawn = false;
}
}
void
@ -1057,10 +1399,148 @@ NSMonster::SpawnKey(string strKey, string strValue)
switch (strKey) {
/* The legacy GoldSrc trigger condition system */
case "TriggerCondition":
m_iTriggerCondition = stoi(strValue);
m_iTriggerCondition = ReadInt(strValue);
break;
case "TriggerTarget":
m_strTriggerTarget = strValue;
m_strTriggerTarget = ReadString(strValue);
break;
/* entityDef related */
case "netname": /* used for obituries and debug info */
netname = ReadString(strValue);
break;
case "eye_height":
m_flEyeHeight = ReadFloat(strValue);
break;
case "snd_sight":
m_sndSight = ReadString(strValue);
break;
case "snd_idle":
m_sndIdle = ReadString(strValue);
break;
case "idle_min": /* used for idle sound timer */
m_flIdleMin = ReadFloat(strValue);
break;
case "idle_max": /* ditto */
m_flIdleMax = ReadFloat(strValue);
break;
case "snd_footstep":
m_sndFootstep = ReadString(strValue);
break;
case "snd_chatter":
m_sndChatter = ReadString(strValue);
break;
case "snd_chatter_combat":
m_sndChatterCombat = ReadString(strValue);
break;
case "snd_pain":
m_sndPain = ReadString(strValue);
break;
case "snd_death":
m_sndDeath = ReadString(strValue);
break;
case "snd_thud":
m_sndThud = ReadString(strValue);
break;
case "def_melee": /* melee attack information */
case "def_attack_melee":
m_defMelee = ReadString(strValue);
break;
case "attack_melee_range":
case "melee_range": /* Doom 3 compat */
m_flMeleeRange = ReadFloat(strValue);
break;
case "snd_melee_attack":
m_sndMeleeAttack = ReadString(strValue);
break;
case "snd_melee_attack_hit":
m_sndMeleeAttackHit = ReadString(strValue);
break;
case "snd_melee_attack_miss":
m_sndMeleeAttackMiss = ReadString(strValue);
break;
case "def_attack_ranged": /* primary ranged attack */
case "def_attack_ranged_1":
m_defRanged1 = ReadString(strValue);
break;
case "attack_ranged1_range":
case "attack_ranged_range":
case "ranged_range":
m_flRanged1Range = ReadFloat(strValue);
break;
case "def_attack_ranged_2": /* special ranged attack */
m_defRanged2 = ReadString(strValue);
break;
case "attack_ranged2_range":
case "ranged2_range":
m_flRanged2Range = ReadFloat(strValue);
break;
case "snd_ranged_attack":
m_sndRangedAttack = ReadString(strValue);
break;
case "reload_count": /* how many ranged attacks until reload */
m_flReloadCount = ReadFloat(strValue);
break;
case "reload_delay": /* time between reloads */
m_flReloadDelay = ReadFloat(strValue);
break;
case "snd_reload":
m_sndReload = ReadString(strValue);
break;
case "def_attack_special":
case "def_attack_special_1":
m_defSpecial1 = ReadString(strValue);
break;
case "attack_special1_range":
case "attack_special_range":
case "special1_range":
m_flSpecial1Range = ReadFloat(strValue);
break;
case "def_attack_special_2": /* projectile */
m_defSpecial2 = ReadString(strValue);
break;
case "attack_special2_range":
case "special2_range":
m_flSpecial2Range = ReadFloat(strValue);
break;
case "num_projectiles":
m_iNumProjectiles = ReadInt(strValue);
break;
case "projectile_spread":
m_flProjectileSpread = ReadFloat(strValue);
break;
case "projectile_delay":
m_flProjectileDelay = ReadFloat(strValue);
break;
case "attack_cone":
m_flAttackCone = ReadFloat(strValue);
break;
case "attack_accuracy": /* affects ranged accuracy */
m_flAttackAccuracy = ReadFloat(strValue);
break;
case "weapon_drawn":
m_bWeaponStartsDrawn = ReadBool(strValue);
break;
case "body_on_draw":
m_flBodyOnDraw = ReadFloat(strValue);
break;
case "speed_walk":
m_flWalkSpeed = ReadFloat(strValue);
break;
case "speed_run":
m_flRunSpeed = ReadFloat(strValue);
break;
/* compat */
case "maxs":
base_maxs = ReadVector(strValue);
break;
case "mins":
base_mins = ReadVector(strValue);
break;
case "team":
m_iAlliance = ReadInt(strValue);
break;
case "health":
base_health = Skill_GetDefValue(strValue);
break;
default:
NSSurfacePropEntity::SpawnKey(strKey, strValue);
@ -1077,6 +1557,7 @@ NSMonster::EvaluateEntity(void)
EVALUATE_VECTOR(angles, 0, MONFL_CHANGED_ANGLES_X)
EVALUATE_VECTOR(angles, 1, MONFL_CHANGED_ANGLES_Y)
EVALUATE_VECTOR(angles, 2, MONFL_CHANGED_ANGLES_Z)
EVALUATE_VECTOR(v_angle, 0, MONFL_CHANGED_ANGLES_X)
EVALUATE_FIELD(modelindex, MONFL_CHANGED_MODELINDEX)
EVALUATE_VECTOR(view_ofs, 2, MONFL_CHANGED_MODELINDEX)
EVALUATE_FIELD(solid, MONFL_CHANGED_SOLID)
@ -1103,6 +1584,9 @@ NSMonster::EvaluateEntity(void)
EVALUATE_VECTOR(m_vecRenderColor, 1, MONFL_CHANGED_RENDERCOLOR)
EVALUATE_VECTOR(m_vecRenderColor, 2, MONFL_CHANGED_RENDERCOLOR)
EVALUATE_FIELD(m_flRenderAmt, MONFL_CHANGED_RENDERAMT)
EVALUATE_FIELD(bonecontrol1, MONFL_CHANGED_HEADYAW)
EVALUATE_FIELD(subblendfrac, MONFL_CHANGED_HEADYAW)
EVALUATE_FIELD(frame1time, MONFL_CHANGED_HEADYAW)
}
/* Make sure StartFrame calls this */
@ -1126,6 +1610,7 @@ NSMonster::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_ANGLE(angles[0], MONFL_CHANGED_ANGLES_X)
SENDENTITY_ANGLE(angles[1], MONFL_CHANGED_ANGLES_Y)
SENDENTITY_ANGLE(angles[2], MONFL_CHANGED_ANGLES_Z)
SENDENTITY_ANGLE(v_angle[0], MONFL_CHANGED_ANGLES_X)
SENDENTITY_SHORT(modelindex, MONFL_CHANGED_MODELINDEX)
SENDENTITY_BYTE(view_ofs[2], MONFL_CHANGED_MODELINDEX)
SENDENTITY_BYTE(solid, MONFL_CHANGED_SOLID)
@ -1152,6 +1637,9 @@ NSMonster::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_ANGLE(m_vecRenderColor[1], MONFL_CHANGED_RENDERCOLOR)
SENDENTITY_ANGLE(m_vecRenderColor[2], MONFL_CHANGED_RENDERCOLOR)
SENDENTITY_ANGLE(m_flRenderAmt, MONFL_CHANGED_RENDERAMT)
SENDENTITY_FLOAT(bonecontrol1, MONFL_CHANGED_HEADYAW)
SENDENTITY_FLOAT(subblendfrac, MONFL_CHANGED_HEADYAW)
SENDENTITY_FLOAT(frame1time, MONFL_CHANGED_HEADYAW)
return (1);
}
@ -1202,6 +1690,7 @@ NSMonster::ReceiveEntity(float flNew, float flChanged)
READENTITY_ANGLE(angles[0], MONFL_CHANGED_ANGLES_X)
READENTITY_ANGLE(angles[1], MONFL_CHANGED_ANGLES_Y)
READENTITY_ANGLE(angles[2], MONFL_CHANGED_ANGLES_Z)
READENTITY_ANGLE(v_angle[0], MONFL_CHANGED_ANGLES_X)
READENTITY_SHORT(modelindex, MONFL_CHANGED_MODELINDEX)
READENTITY_BYTE(view_ofs[2], MONFL_CHANGED_MODELINDEX)
READENTITY_BYTE(solid, MONFL_CHANGED_SOLID)
@ -1228,16 +1717,17 @@ NSMonster::ReceiveEntity(float flNew, float flChanged)
READENTITY_ANGLE(m_vecRenderColor[1], MONFL_CHANGED_RENDERCOLOR)
READENTITY_ANGLE(m_vecRenderColor[2], MONFL_CHANGED_RENDERCOLOR)
READENTITY_ANGLE(m_flRenderAmt, MONFL_CHANGED_RENDERAMT)
READENTITY_FLOAT(bonecontrol1, MONFL_CHANGED_HEADYAW)
READENTITY_FLOAT(subblendfrac, MONFL_CHANGED_HEADYAW)
READENTITY_FLOAT(frame1time, MONFL_CHANGED_HEADYAW)
if (scale == 0.0)
scale = 1.0f;
if (flChanged & MONFL_CHANGED_FRAME)
frame1time = 0.0f;
if (flChanged & MONFL_CHANGED_SIZE)
setsize(this, mins * scale, maxs * scale);
if (flChanged & MONFL_CHANGED_BODY)
setcustomskin(this, "", sprintf("geomset 0 %i\ngeomset 1 %i\n", m_iBody, m_iBody));
_UpdateGeomset();
setorigin(this, origin);
}

View File

@ -136,4 +136,9 @@ public:
#ifdef CLIENT
void NSProjectile_ReadEntity(bool);
#endif
#ifdef SERVER
void NSProjectile_SpawnDef(string entityDef, NSEntity theOwner)
void NSProjectile_SpawnDefAttachment(string entityDef, NSEntity theOwner, int attachmentID)
#endif

View File

@ -503,4 +503,33 @@ NSProjectile_ReadEntity(bool new)
fl = readfloat();
rend.ReceiveEntity(new, fl);
}
#endif
#ifdef SERVER
void
NSProjectile_SpawnDef(string entityDef, NSEntity theOwner)
{
entity oldself = self;
NSProjectile rocket = spawn(NSProjectile);
rocket.owner = theOwner;
self = rocket;
EntityDef_SpawnClassname(entityDef);
self = oldself;
rocket.Launch(theOwner.GetOrigin() + theOwner.view_ofs, theOwner.GetAngles(), 0.0f, 0.0f, 0.0f);
}
void
NSProjectile_SpawnDefAttachment(string entityDef, NSEntity theOwner, int attachmentID)
{
entity oldself = self;
float skeletonIndex = skel_create(theOwner.modelindex);
vector attachmentPos = gettaginfo(theOwner, skel_get_numbones(skeletonIndex) + attachmentID);
skel_delete(skeletonIndex);
NSProjectile rocket = spawn(NSProjectile);
rocket.owner = theOwner;
self = rocket;
EntityDef_SpawnClassname(entityDef);
self = oldself;
rocket.Launch(attachmentPos, theOwner.GetAngles(), 0.0f, 0.0f, 0.0f);
}
#endif

View File

@ -45,7 +45,14 @@ void NSRenderableEntity::RendererRestarted( void ) {
void NSRenderableEntity::_UpdateGeomset(void)
{
setcustomskin(this, "", sprintf("geomset 0 %i\ngeomset 1 %i\n", m_iBody, m_iBody));
int firstBody = (m_iBody & 0x0F);
int secondBody = ((m_iBody >> 4) & 0x0F);
//print(sprintf("%i body 1: %i body 2: %i\n", m_iBody , firstBody, secondBody));
setcustomskin(this, "",
sprintf("geomset 0 %i\ngeomset 1 %i\ngeomset 2 %i\n", secondBody, firstBody, secondBody)
);
}
#endif
@ -276,7 +283,7 @@ NSRenderableEntity::ReceiveEntity(float flNew, float flChanged)
if (flChanged & RDENT_CHANGED_SIZE)
setsize(this, mins * scale, maxs * scale);
if (flChanged & RDENT_CHANGED_BODY)
setcustomskin(this, "", sprintf("geomset 0 %i\ngeomset 1 %i\n", m_iBody, m_iBody));
_UpdateGeomset();
setorigin(this, origin);
}
@ -541,9 +548,6 @@ NSRenderableEntity::predraw(void)
angles[1] -= frametime * 120.0;
}
if (serverkeyfloat(SERVERKEY_PAUSESTATE) != 1)
frame1time += frametime;
processmodelevents(modelindex, frame, m_flBaseTime,
frame1time, HandleAnimEvent);
@ -775,6 +779,8 @@ NSRenderableEntity::HandleAnimEvent(float flTimeStamp, int iCode, string strData
tokenize(m_strModelEventCB); /* ensure argv() is 'rewound'... */
}
}
//print(sprintf("Received: %f %i %S\n", flTimeStamp, iCode, strData));
#else
NSLog("Unknown model event: %f %i %S", flTimeStamp, iCode, strData);
#endif

View File

@ -24,6 +24,10 @@ public:
void NSSquadMonster(void);
#ifdef SERVER
/* overrides */
virtual void Spawned(void);
virtual void SpawnKey(string, string);
/** Overridable: Called when this NPC became squad leader. */
virtual void HasBecomeSquadLeader(void);
/** Overridable: Called when this NPC joined a squad. */
@ -51,6 +55,8 @@ public:
#ifdef SERVER
private:
int m_iSquadLeaderBody;
bool m_bStartAsLeader;
bool m_inSquad;
NSSquadMonster m_eSquadLeader;

View File

@ -20,6 +20,7 @@ NSSquadMonster::NSSquadMonster(void)
#ifdef SERVER
m_inSquad = false;
m_eSquadLeader = __NULL__;
m_bStartAsLeader = false;
for (int i = 0; i < NSSQUADMONSTER_MAXMEMBERS; i++) {
m_eSquadMembers[i] = __NULL__;
@ -28,6 +29,39 @@ NSSquadMonster::NSSquadMonster(void)
}
#ifdef SERVER
void
NSSquadMonster::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "squad_leader":
m_bStartAsLeader = ReadBool(strValue);
break;
case "squad_leader_body":
m_iSquadLeaderBody = ReadInt(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
NSSquadMonster::Spawned(void)
{
static void AttachToNearBySquad(void) {
FindSquadNearMe(1024);
}
super::Spawned();
/* unless specified manually, make up who becomes squad member */
if (m_bStartAsLeader) {
m_eSquadLeader = this;
m_inSquad = true;
} else {
ScheduleThink(AttachToNearBySquad, 0.5f);
}
}
void
NSSquadMonster::HasBecomeSquadLeader(void)
{
@ -97,6 +131,7 @@ NSSquadMonster::AddToSquad(NSSquadMonster addMember)
startMember = this;
m_inSquad = true;
print(sprintf("%s (%d) became squad leader\n", classname, num_for_edict(this)));
SetBody(GetBody() | m_iSquadLeaderBody);
HasBecomeSquadLeader();
}

View File

@ -602,6 +602,10 @@ NSSurfacePropEntity::SpawnKey(string strKey, string strValue)
case "materialdata":
SetSurfaceData(strValue);
break;
/* entityDef */
case "blood_color":
m_vecBloodColor = ReadVector(strValue);
break;
/* Input/Output system */
#ifdef SERVER
case "OnBreak":

View File

@ -98,6 +98,8 @@ public:
virtual void TalkFollow(void);
/** Called when they tell the player that they'll stop following. */
virtual void TalkStopFollow(void);
/** Called when they tell the player they won't follow you. */
virtual void TalkDenyFollow(void);
#endif
#ifdef CLIENT
@ -127,7 +129,7 @@ private:
float m_flTraceTime;
float m_flFollowSpeedChanged;
float m_flFollowSpeed;
bool m_bFollowOnUse;
/* sentences identifiers */
string m_talkAnswer; /* random answer to whenever a question is asked */
@ -153,6 +155,7 @@ private:
string m_talkUnfollow; /* when the player asks us to stop following */
string m_talkFollow; /* whenever player asks the NPC to follow */
string m_talkStopFollow; /* we have to stop following */
string m_talkDenyFollow; /* deny the follow request. */
virtual void _Alerted(void);
#endif

View File

@ -49,6 +49,8 @@ NSTalkMonster::NSTalkMonster(void)
m_talkUnfollow = __NULL__;
m_talkFollow = __NULL__;
m_talkStopFollow = __NULL__;
m_talkDenyFollow = __NULL__;
m_bFollowOnUse = false;
#else
m_flSentenceTime = 0.0f;
m_pSentenceQue = __NULL__;
@ -300,13 +302,13 @@ NSTalkMonster::TalkPlayerGreet(void)
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
if (VisibleVec(p.origin + p.view_ofs) == false)
continue;
}
Sentence(m_talkPlayerGreet);
m_flNextSentence = time + 10.0;
m_iFlags |= MONSTER_METPLAYER;
m_eLookAt = p;
break;
}
}
@ -485,6 +487,17 @@ NSTalkMonster::TalkStopFollow(void)
m_flNextSentence = time + 10.0;
}
void
NSTalkMonster::TalkDenyFollow(void)
{
if (m_iSequenceState != SEQUENCESTATE_NONE)
return;
Sentence(m_talkDenyFollow);
m_flNextSentence = time + 10.0;
}
void
NSTalkMonster::FollowPlayer(void)
{
@ -506,7 +519,7 @@ NSTalkMonster::FollowPlayer(void)
/* Give up after 1024 units */
if (flPlayerDist > 1024) {
m_eFollowing = world;
} else if (flPlayerDist > 64) {
} else if (flPlayerDist > 128) {
/* we only allow speed changes every second, avoid jitter */
if (m_flFollowSpeedChanged < time) {
float flNextSpeed = GetChaseSpeed();
@ -605,6 +618,7 @@ NSTalkMonster::RunAI(void)
FollowChain();
if (m_eFollowing != world) {
m_eLookAt = m_eFollowing;
FollowPlayer();
} else if (m_iFlags & MONSTER_FEAR) {
PanicFrame();
@ -623,6 +637,11 @@ NSTalkMonster::Respawn(void)
super::Respawn();
m_eFollowing = world;
m_eFollowingChain = world;
PlayerUse = OnPlayerUse;
if (m_bFollowOnUse) {
m_iFlags |= MONSTER_CANFOLLOW;
}
}
void
@ -632,8 +651,10 @@ NSTalkMonster::OnPlayerUse(void)
return;
/* can't press use any non-allies */
if (!(m_iFlags & MONSTER_CANFOLLOW))
if (!(m_iFlags & MONSTER_CANFOLLOW)) {
TalkDenyFollow();
return;
}
if ((m_eFollowing == world)) {
if (!(m_iFlags & MONSTER_USED)) {
@ -660,6 +681,77 @@ NSTalkMonster::SpawnKey(string strKey, string strValue)
case "UseSentence":
m_talkFollow = strcat("!", strValue);
break;
/* entityDef */
case "talk_answer":
m_talkAnswer = ReadString(strValue);
break;
case "talk_ask":
m_talkAsk = ReadString(strValue);
break;
case "talk_ally_shot":
m_talkAllyShot = ReadString(strValue);
break;
case "talk_greet":
m_talkGreet = ReadString(strValue);
break;
case "talk_idle":
m_talkIdle = ReadString(strValue);
break;
case "talk_panic":
m_talkPanic = ReadString(strValue);
break;
case "talk_hearing":
m_talkHearing = ReadString(strValue);
break;
case "talk_smelling":
m_talkSmelling = ReadString(strValue);
break;
case "talk_stare":
m_talkStare = ReadString(strValue);
break;
case "talk_survived":
m_talkSurvived = ReadString(strValue);
break;
case "talk_wounded":
m_talkWounded = ReadString(strValue);
break;
case "talk_alert":
m_talkAlert = ReadString(strValue);
break;
case "talk_player_ask":
m_talkPlayerAsk = ReadString(strValue);
break;
case "talk_player_greet":
m_talkPlayerGreet = ReadString(strValue);
break;
case "talk_player_idle":
m_talkPlayerIdle = ReadString(strValue);
break;
case "talk_player_wounded1":
m_talkPlayerWounded1 = ReadString(strValue);
break;
case "talk_player_wounded2":
m_talkPlayerWounded2 = ReadString(strValue);
break;
case "talk_player_wounded3":
m_talkPlayerWounded3 = ReadString(strValue);
break;
case "talk_unfollow":
m_talkUnfollow = ReadString(strValue);
break;
case "talk_follow":
m_talkFollow = ReadString(strValue);
break;
case "talk_stop_follow":
m_talkStopFollow = ReadString(strValue);
break;
case "talk_deny_follow":
m_talkDenyFollow = ReadString(strValue);
break;
case "follow_on_use":
m_bFollowOnUse = ReadBool(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
break;
@ -686,6 +778,7 @@ NSTalkMonster::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_ANGLE(angles[0], MONFL_CHANGED_ANGLES_X)
SENDENTITY_ANGLE(angles[1], MONFL_CHANGED_ANGLES_Y)
SENDENTITY_ANGLE(angles[2], MONFL_CHANGED_ANGLES_Z)
SENDENTITY_FLOAT(v_angle[0], MONFL_CHANGED_ANGLES_X)
SENDENTITY_SHORT(modelindex, MONFL_CHANGED_MODELINDEX)
SENDENTITY_BYTE(view_ofs[2], MONFL_CHANGED_MODELINDEX)
SENDENTITY_BYTE(solid, MONFL_CHANGED_SOLID)
@ -712,6 +805,7 @@ NSTalkMonster::SendEntity(entity ePEnt, float flChanged)
SENDENTITY_ANGLE(m_vecRenderColor[1], MONFL_CHANGED_RENDERCOLOR)
SENDENTITY_ANGLE(m_vecRenderColor[2], MONFL_CHANGED_RENDERCOLOR)
SENDENTITY_ANGLE(m_flRenderAmt, MONFL_CHANGED_RENDERAMT)
SENDENTITY_FLOAT(m_flHeadYaw, MONFL_CHANGED_HEADYAW)
return (1);
}
@ -844,6 +938,23 @@ NSTalkMonster::predraw(void)
m_bWasPaused = true;
}
bonecontrol2 = autocvar(bonecontrol2, 0);
bonecontrol3 = autocvar(bonecontrol3, 0);
bonecontrol4 = autocvar(bonecontrol4, 0);
/* this will make the actor 'aim" at the target */
{
makevectors(v_angle);
vector tmp = vectoangles(v_forward);
subblendfrac = tmp[0] / 90;
bonecontrol1 = m_flHeadYaw; /* head turning */
}
//print(sprintf("yaw: %f %f\n", subblendfrac, v_angle[0]));
subblend2frac = autocvar(subblend2frac, 0);
basesubblendfrac = autocvar(basesubblendfrac, 0);
basesubblend2frac = autocvar(basesubblend2frac, 0);
addentity(this);
_RenderDebugViewCone();
@ -864,6 +975,7 @@ NSTalkMonster::ReceiveEntity(float flNew, float flChanged)
READENTITY_ANGLE(angles[0], MONFL_CHANGED_ANGLES_X)
READENTITY_ANGLE(angles[1], MONFL_CHANGED_ANGLES_Y)
READENTITY_ANGLE(angles[2], MONFL_CHANGED_ANGLES_Z)
READENTITY_FLOAT(v_angle[0], MONFL_CHANGED_ANGLES_X)
READENTITY_SHORT(modelindex, MONFL_CHANGED_MODELINDEX)
READENTITY_BYTE(view_ofs[2], MONFL_CHANGED_MODELINDEX)
READENTITY_BYTE(solid, MONFL_CHANGED_SOLID)
@ -890,6 +1002,7 @@ NSTalkMonster::ReceiveEntity(float flNew, float flChanged)
READENTITY_ANGLE(m_vecRenderColor[1], MONFL_CHANGED_RENDERCOLOR)
READENTITY_ANGLE(m_vecRenderColor[2], MONFL_CHANGED_RENDERCOLOR)
READENTITY_ANGLE(m_flRenderAmt, MONFL_CHANGED_RENDERAMT)
READENTITY_FLOAT(m_flHeadYaw, MONFL_CHANGED_HEADYAW)
if (scale == 0.0)
scale = 1.0f;
@ -899,7 +1012,7 @@ NSTalkMonster::ReceiveEntity(float flNew, float flChanged)
if (flChanged & MONFL_CHANGED_SIZE)
setsize(this, mins * scale, maxs * scale);
if (flChanged & MONFL_CHANGED_BODY)
setcustomskin(this, "", sprintf("geomset 0 %i\ngeomset 1 %i\n", m_iBody, m_iBody));
_UpdateGeomset();
setorigin(this, origin);
}