2019-08-31 19:18:15 -07:00
|
|
|
/*
|
2020-04-07 05:46:23 -07:00
|
|
|
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
|
2019-08-31 19:18:15 -07:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2019-03-19 12:01:24 -07:00
|
|
|
|
2020-03-30 04:51:48 -07:00
|
|
|
int
|
|
|
|
CBaseMonster::AnimIdle(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CBaseMonster::AnimWalk(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
CBaseMonster::AnimRun(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-07-26 16:19:53 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::AnimPlay(float seq)
|
|
|
|
{
|
|
|
|
/* forces a client-side update */
|
|
|
|
SendFlags |= BASEFL_CHANGED_FRAME;
|
|
|
|
|
|
|
|
SetFrame(seq);
|
|
|
|
m_flAnimTime = time + frameduration(modelindex, frame);
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::Sound(string msg)
|
2020-03-25 05:58:19 -07:00
|
|
|
{
|
2020-03-26 03:24:33 -07:00
|
|
|
sound(this, CHAN_VOICE, msg, 1.0, ATTN_NORM);
|
2020-03-25 05:58:19 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::Gib(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
|
|
|
takedamage = DAMAGE_NO;
|
2020-04-22 18:13:29 -07:00
|
|
|
FX_GibHuman(this.origin);
|
2019-03-19 12:01:24 -07:00
|
|
|
Hide();
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::IdleNoise(void)
|
2020-03-25 14:35:05 -07:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-08-03 14:39:57 -07:00
|
|
|
int
|
|
|
|
CBaseMonster::IsFriend(int al)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (m_iAlliance == MAL_ROGUE)
|
|
|
|
return FALSE;
|
|
|
|
else if (al == m_iAlliance)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
CBaseMonster::SeeFOV(void)
|
|
|
|
{
|
|
|
|
return 90;
|
|
|
|
}
|
|
|
|
|
2020-08-02 03:55:03 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::SeeThink(void)
|
|
|
|
{
|
|
|
|
if (m_eEnemy)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_flSeeTime > time)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_flSeeTime = time + 0.25f;
|
|
|
|
|
2020-08-03 14:39:57 -07:00
|
|
|
for (entity w = world; (w = findfloat(w, ::takedamage, DAMAGE_YES));) {
|
|
|
|
if (IsFriend(w.m_iAlliance))
|
|
|
|
continue;
|
2020-08-02 03:55:03 -07:00
|
|
|
|
|
|
|
if (w.health <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* first, is the potential enemy in our field of view? */
|
2020-08-03 14:39:57 -07:00
|
|
|
makevectors(v_angle);
|
2020-08-02 03:55:03 -07:00
|
|
|
vector v = normalize(w.origin - origin);
|
|
|
|
float flDot = v * v_forward;
|
|
|
|
|
2020-08-03 14:39:57 -07:00
|
|
|
if (flDot < SeeFOV()/180)
|
2020-08-02 03:55:03 -07:00
|
|
|
continue;
|
|
|
|
|
|
|
|
other = world;
|
|
|
|
traceline(origin, w.origin, MOVE_OTHERONLY, this);
|
|
|
|
|
|
|
|
if (trace_fraction == 1.0f) {
|
|
|
|
m_eEnemy = w;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-07-26 16:19:53 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::AttackThink(void)
|
|
|
|
{
|
2020-11-23 12:39:40 -08:00
|
|
|
if (m_iSequenceState != SEQUENCESTATE_NONE)
|
|
|
|
return;
|
|
|
|
|
2020-07-26 16:19:53 -07:00
|
|
|
if (m_flAttackThink > time) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-02 03:55:03 -07:00
|
|
|
/* reset */
|
2020-08-03 14:39:57 -07:00
|
|
|
if (m_eEnemy.solid == SOLID_CORPSE || (m_eEnemy && m_eEnemy.health <= 0)) {
|
2020-08-02 03:55:03 -07:00
|
|
|
m_eEnemy = __NULL__;
|
2020-08-03 14:39:57 -07:00
|
|
|
ClearRoute();
|
|
|
|
}
|
2020-07-26 16:19:53 -07:00
|
|
|
|
|
|
|
/* do we have a clear shot? */
|
|
|
|
other = world;
|
|
|
|
traceline(origin, m_eEnemy.origin, MOVE_OTHERONLY, this);
|
|
|
|
|
|
|
|
/* something is blocking us */
|
|
|
|
if (trace_fraction < 1.0f) {
|
2020-08-02 03:55:03 -07:00
|
|
|
m_iMState = MONSTER_IDLE;
|
2020-07-26 16:19:53 -07:00
|
|
|
|
|
|
|
/* FIXME: This is unreliable, but unlikely that a player ever is here */
|
|
|
|
if (m_vecLKPos != [0,0,0]) {
|
2020-08-03 14:39:57 -07:00
|
|
|
ClearRoute();
|
2020-07-26 16:19:53 -07:00
|
|
|
NewRoute(m_vecLKPos);
|
|
|
|
m_flSequenceSpeed = 140;
|
|
|
|
m_vecLKPos = [0,0,0];
|
|
|
|
}
|
|
|
|
} else {
|
2020-08-02 03:55:03 -07:00
|
|
|
m_iMState = MONSTER_AIMING;
|
2020-07-26 16:19:53 -07:00
|
|
|
|
|
|
|
/* make sure we remember the last known position. */
|
|
|
|
m_vecLKPos = m_eEnemy.origin;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_iMState == MONSTER_AIMING) {
|
2020-08-02 03:55:03 -07:00
|
|
|
int m;
|
2020-07-26 16:19:53 -07:00
|
|
|
if (vlen(origin - m_eEnemy.origin) < 96)
|
2020-08-02 03:55:03 -07:00
|
|
|
m = AttackMelee();
|
|
|
|
else {
|
|
|
|
m = AttackRanged();
|
|
|
|
|
|
|
|
/* if we don't have the desired attack mode, walk */
|
|
|
|
if (m == FALSE)
|
|
|
|
m_iMState = MONSTER_CHASING;
|
|
|
|
|
|
|
|
}
|
2020-07-26 16:19:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-02 03:55:03 -07:00
|
|
|
int
|
2020-07-26 16:19:53 -07:00
|
|
|
CBaseMonster::AttackMelee(void)
|
|
|
|
{
|
|
|
|
m_flAttackThink = time + 0.5f;
|
2020-08-02 03:55:03 -07:00
|
|
|
return FALSE;
|
2020-07-26 16:19:53 -07:00
|
|
|
}
|
|
|
|
|
2020-08-02 03:55:03 -07:00
|
|
|
int
|
2020-07-26 16:19:53 -07:00
|
|
|
CBaseMonster::AttackRanged(void)
|
|
|
|
{
|
|
|
|
m_flAttackThink = time + 0.5f;
|
2020-08-02 03:55:03 -07:00
|
|
|
return FALSE;
|
2020-07-26 16:19:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CBaseMonster::AttackDraw(void)
|
|
|
|
{
|
2020-08-03 09:49:30 -07:00
|
|
|
dprint(sprintf("^1%s::AttackDraw: Not defined!\n", classname));
|
2020-07-26 16:19:53 -07:00
|
|
|
m_flAttackThink = time + 0.5f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CBaseMonster::AttackHolster(void)
|
|
|
|
{
|
2020-08-03 09:49:30 -07:00
|
|
|
dprint(sprintf("^1%s::AttackHolster: Not defined!\n", classname));
|
2020-07-26 16:19:53 -07:00
|
|
|
m_flAttackThink = time + 0.5f;
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::ClearRoute(void)
|
2020-03-27 02:37:01 -07:00
|
|
|
{
|
|
|
|
if (m_iNodes) {
|
|
|
|
m_iNodes = 0;
|
|
|
|
memfree(m_pRoute);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::FreeState(void)
|
2020-03-29 02:21:26 -07:00
|
|
|
{
|
2020-09-10 11:24:51 -07:00
|
|
|
string to_trigger;
|
2020-03-29 02:21:26 -07:00
|
|
|
m_flSequenceEnd = 0;
|
|
|
|
m_iSequenceState = SEQUENCESTATE_NONE;
|
|
|
|
|
2020-09-10 11:24:51 -07:00
|
|
|
/* we're clearing m_strRouteEnded early, because m_strRouteEnded
|
|
|
|
might change when .Trigger is executed. It could be another scripted
|
|
|
|
sequence triggering another sequence. Hence the caching */
|
|
|
|
to_trigger = m_strRouteEnded;
|
|
|
|
m_strRouteEnded = __NULL__;
|
|
|
|
|
2020-03-29 02:21:26 -07:00
|
|
|
/* trigger when required */
|
2020-09-10 11:24:51 -07:00
|
|
|
if (to_trigger) {
|
|
|
|
for (entity f = world; (f = find(f, ::targetname, to_trigger));) {
|
2020-09-10 04:36:19 -07:00
|
|
|
CBaseTrigger trigger = (CBaseTrigger)f;
|
|
|
|
if (trigger.Trigger != __NULL__) {
|
|
|
|
trigger.Trigger(this, TRIG_TOGGLE);
|
|
|
|
}
|
2020-03-30 01:00:37 -07:00
|
|
|
}
|
|
|
|
}
|
2020-03-30 00:11:57 -07:00
|
|
|
|
2020-03-29 03:56:46 -07:00
|
|
|
if (m_iSequenceRemove) {
|
|
|
|
Hide();
|
|
|
|
}
|
2020-03-29 02:21:26 -07:00
|
|
|
}
|
|
|
|
|
2020-08-03 14:39:57 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::FreeStateMoved(void)
|
|
|
|
{
|
|
|
|
vector new_origin;
|
|
|
|
new_origin = gettaginfo(this, 0);
|
|
|
|
SetOrigin(new_origin);
|
|
|
|
FreeState();
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::CheckRoute(void)
|
2020-03-27 02:37:01 -07:00
|
|
|
{
|
|
|
|
float flDist;
|
2020-03-29 03:56:46 -07:00
|
|
|
vector evenpos;
|
2020-03-27 02:37:01 -07:00
|
|
|
|
|
|
|
if (!m_iNodes) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-29 03:56:46 -07:00
|
|
|
/* level out position/node stuff */
|
|
|
|
if (m_iCurNode < 0) {
|
|
|
|
evenpos = m_vecLastNode;
|
|
|
|
evenpos[2] = origin[2];
|
|
|
|
} else {
|
2020-04-12 06:50:42 -07:00
|
|
|
evenpos = m_pRoute[m_iCurNode].m_vecDest;
|
2020-03-29 03:56:46 -07:00
|
|
|
evenpos[2] = origin[2];
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
flDist = floor(vlen(evenpos - origin));
|
2020-03-27 02:37:01 -07:00
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
if (flDist < 8) {
|
2020-11-23 12:39:40 -08:00
|
|
|
dprint(sprintf("^2CBaseMonster::^3CheckRoute^7: " \
|
|
|
|
"%s reached node\n", this.targetname));
|
2020-03-27 02:37:01 -07:00
|
|
|
m_iCurNode--;
|
|
|
|
velocity = [0,0,0]; /* clamp friction */
|
2020-11-23 12:39:40 -08:00
|
|
|
|
|
|
|
/* we've still traveling and from this node we may be able to walk
|
|
|
|
* directly to our end-destination */
|
|
|
|
if (m_iCurNode > -1) {
|
|
|
|
tracebox(origin, mins, maxs, m_vecLastNode, MOVE_NORMAL, this);
|
|
|
|
|
|
|
|
/* can we walk directly to our target destination? */
|
|
|
|
if (trace_fraction == 1.0) {
|
|
|
|
dprint("^2CBaseMonster::^3CheckRoute^7: " \
|
|
|
|
"Walking directly to last node\n");
|
|
|
|
m_iCurNode = -1;
|
|
|
|
}
|
|
|
|
}
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
2020-07-26 16:19:53 -07:00
|
|
|
|
2020-03-29 03:56:46 -07:00
|
|
|
if (m_iCurNode < -1) {
|
|
|
|
ClearRoute();
|
2020-09-08 13:49:35 -07:00
|
|
|
dprint(sprintf("^2CBaseMonster::^3CheckRoute^7: %s reached end\n", this.targetname));
|
2020-03-29 03:56:46 -07:00
|
|
|
|
2020-03-29 02:21:26 -07:00
|
|
|
/* mark that we've ended a sequence, if we're in one and que anim */
|
|
|
|
if (m_iSequenceState == SEQUENCESTATE_ACTIVE) {
|
|
|
|
if (m_flSequenceEnd) {
|
|
|
|
float duration = frameduration(modelindex, m_flSequenceEnd);
|
|
|
|
m_iSequenceState = SEQUENCESTATE_ENDING;
|
|
|
|
think = FreeState;
|
|
|
|
nextthink = time + duration;
|
2020-09-08 13:49:35 -07:00
|
|
|
dprint(sprintf("^2CBaseMonster::^3CheckRoute^7: %s overriding anim for %f seconds (modelindex %d, frame %d)\n", this.targetname, duration, modelindex, m_flSequenceEnd));
|
2020-03-29 03:56:46 -07:00
|
|
|
} else {
|
|
|
|
/* we still need to trigger targets */
|
|
|
|
think = FreeState;
|
|
|
|
nextthink = time;
|
2020-09-08 13:49:35 -07:00
|
|
|
dprint(sprintf("^2CBaseMonster::^3CheckRoute^7: %s has no anim, finished sequence.\n", this.targetname));
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
/*if (flDist == m_flLastDist) {
|
2020-03-27 02:37:01 -07:00
|
|
|
m_flNodeGiveup += frametime;
|
|
|
|
} else {
|
2020-04-12 06:50:42 -07:00
|
|
|
m_flNodeGiveup = bound(0, m_flNodeGiveup - frametime, 1.0);
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
m_flLastDist = flDist;
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
if (m_flNodeGiveup >= 1.0f) {
|
2020-03-27 02:37:01 -07:00
|
|
|
print(sprintf("CBaseMonster::CheckNode: %s gave up route\n",
|
|
|
|
this.netname));
|
|
|
|
ClearRoute();
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::WalkRoute(void)
|
2020-03-27 02:37:01 -07:00
|
|
|
{
|
2020-07-26 16:19:53 -07:00
|
|
|
vector endangles;
|
|
|
|
|
|
|
|
/* we're busy shooting at something, don't walk */
|
|
|
|
if (m_iMState == MONSTER_AIMING) {
|
|
|
|
endangles = vectoangles(m_eEnemy.origin - origin);
|
|
|
|
|
|
|
|
/* TODO: lerp */
|
2020-08-03 14:39:57 -07:00
|
|
|
m_vecTurnAngle[1] = endangles[1];
|
|
|
|
} else if (m_iNodes && m_iMState == MONSTER_IDLE) {
|
2020-03-29 03:56:46 -07:00
|
|
|
/* we're on our last node */
|
|
|
|
if (m_iCurNode < 0) {
|
|
|
|
endangles = vectoangles(m_vecLastNode - origin);
|
|
|
|
} else {
|
2020-04-12 06:50:42 -07:00
|
|
|
endangles = vectoangles(m_pRoute[m_iCurNode].m_vecDest - origin);
|
2020-03-29 03:56:46 -07:00
|
|
|
}
|
2020-08-03 14:39:57 -07:00
|
|
|
m_vecTurnAngle[1] = endangles[1];
|
2020-03-27 02:37:01 -07:00
|
|
|
input_movevalues = [m_flSequenceSpeed, 0, 0];
|
2020-08-03 14:39:57 -07:00
|
|
|
} else if (m_iMState == MONSTER_CHASING) {
|
2020-08-02 03:55:03 -07:00
|
|
|
/* we've got 'em in our sights, just need to walk closer */
|
|
|
|
endangles = vectoangles(m_eEnemy.origin - origin);
|
2020-11-23 12:39:40 -08:00
|
|
|
input_movevalues = [m_flChaseSpeed, 0, 0];
|
2020-08-03 14:39:57 -07:00
|
|
|
m_vecTurnAngle[1] = endangles[1];
|
2020-08-28 21:22:18 -07:00
|
|
|
} else {
|
|
|
|
return;
|
2020-08-02 03:55:03 -07:00
|
|
|
}
|
2020-08-03 14:39:57 -07:00
|
|
|
|
|
|
|
/* functional */
|
|
|
|
input_angles[1] = v_angle[1] = m_vecTurnAngle[1];
|
|
|
|
|
2020-11-23 12:39:40 -08:00
|
|
|
#if 1
|
2020-08-03 14:39:57 -07:00
|
|
|
/* cosmetic */
|
|
|
|
vector new_ang;
|
|
|
|
vector old_ang;
|
|
|
|
vector tmp;
|
|
|
|
makevectors(m_vecTurnAngle);
|
|
|
|
new_ang = v_forward;
|
|
|
|
makevectors(angles);
|
2020-11-23 12:39:40 -08:00
|
|
|
old_ang = v_forward;
|
2020-08-03 14:39:57 -07:00
|
|
|
|
|
|
|
tmp[0] = Math_Lerp(old_ang[0], new_ang[0], frametime * 5);
|
|
|
|
tmp[1] = Math_Lerp(old_ang[1], new_ang[1], frametime * 5);
|
|
|
|
tmp[2] = Math_Lerp(old_ang[2], new_ang[2], frametime * 5);
|
|
|
|
angles = vectoangles(tmp);
|
2020-11-23 12:39:40 -08:00
|
|
|
#endif
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::NewRoute(vector destination)
|
2020-03-27 02:37:01 -07:00
|
|
|
{
|
|
|
|
/* engine calls this upon successfully creating a route */
|
|
|
|
static void NewRoute_RouteCB(entity ent, vector dest, int numnodes, nodeslist_t *nodelist)
|
|
|
|
{
|
|
|
|
CBaseMonster p = (CBaseMonster)ent;
|
|
|
|
p.m_iNodes = numnodes;
|
|
|
|
p.m_iCurNode = numnodes - 1;
|
|
|
|
p.m_pRoute = nodelist;
|
2020-03-30 04:51:48 -07:00
|
|
|
|
2020-09-13 09:35:12 -07:00
|
|
|
tracebox(p.origin, p.mins, p.maxs, dest, MOVE_NORMAL, this);
|
|
|
|
|
|
|
|
/* can we walk directly to our target destination? */
|
2020-03-30 04:51:48 -07:00
|
|
|
if (trace_fraction == 1.0) {
|
2020-09-13 09:35:12 -07:00
|
|
|
dprint("^2CBaseMonster::^3NewRoute^7: " \
|
|
|
|
"Walking directly to last node\n");
|
2020-03-30 04:51:48 -07:00
|
|
|
p.m_iCurNode = -1;
|
2020-09-13 09:35:12 -07:00
|
|
|
} else {
|
|
|
|
/* run through all nodes, mark the closest direct path possible */
|
|
|
|
for (int i = 0; i < p.m_iNodes; i++) {
|
|
|
|
vector vecDest = p.m_pRoute[i].m_vecDest;
|
|
|
|
tracebox(p.origin, p.mins, p.maxs, vecDest, TRUE, p);
|
|
|
|
|
|
|
|
if (trace_fraction == 1.0) {
|
|
|
|
p.m_iCurNode = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-03-30 04:51:48 -07:00
|
|
|
}
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ClearRoute();
|
|
|
|
|
|
|
|
if (!m_iNodes) {
|
|
|
|
route_calculate(this, destination, 0, NewRoute_RouteCB);
|
2020-03-29 03:56:46 -07:00
|
|
|
m_vecLastNode = destination;
|
2020-03-27 02:37:01 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 01:34:14 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::ModelEvent(float fTimeStamp, int iCode, string sData)
|
|
|
|
{
|
|
|
|
switch (iCode) {
|
|
|
|
case 1003:
|
|
|
|
for (entity f = world; (f = find(f, ::targetname, sData));) {
|
|
|
|
CBaseTrigger trigger = (CBaseTrigger)f;
|
|
|
|
if (trigger.Trigger != __NULL__) {
|
|
|
|
trigger.Trigger(this, TRIG_TOGGLE);
|
|
|
|
dprint(sprintf("^2%s^7::^3ModelEvent^7: " \
|
|
|
|
"Calling trigger '%s'\n",
|
|
|
|
classname, sData));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
/* things handled on the client-side */
|
|
|
|
case 1004:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dprint(sprintf("^3[SERVER]^7 Unknown model-event code " \
|
|
|
|
"%i with data %s\n", iCode, sData));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::Physics(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
|
|
|
input_movevalues = [0,0,0];
|
|
|
|
input_impulse = 0;
|
|
|
|
input_buttons = 0;
|
2020-08-03 14:39:57 -07:00
|
|
|
input_angles = v_angle;
|
2019-03-19 12:01:24 -07:00
|
|
|
input_timelength = frametime;
|
|
|
|
|
2020-03-29 02:21:26 -07:00
|
|
|
/* override whatever we did above with this */
|
2020-08-02 06:21:35 -07:00
|
|
|
if (m_iSequenceState == SEQUENCESTATE_ENDING) {
|
2020-08-07 05:07:38 -07:00
|
|
|
input_angles = v_angle = angles = m_vecSequenceAngle;
|
2020-04-22 14:33:18 -07:00
|
|
|
SetFrame(m_flSequenceEnd);
|
2020-04-01 07:00:00 -07:00
|
|
|
} else if (movetype == MOVETYPE_WALK) {
|
2020-11-23 12:39:40 -08:00
|
|
|
if (m_iSequenceState == SEQUENCESTATE_NONE) {
|
|
|
|
SeeThink();
|
|
|
|
AttackThink();
|
|
|
|
}
|
|
|
|
|
2020-03-29 02:21:26 -07:00
|
|
|
CheckRoute();
|
|
|
|
WalkRoute();
|
|
|
|
runstandardplayerphysics(this);
|
2020-04-22 14:33:18 -07:00
|
|
|
SetOrigin(origin);
|
2020-03-29 02:21:26 -07:00
|
|
|
IdleNoise();
|
2020-03-30 04:51:48 -07:00
|
|
|
|
|
|
|
if (style != MONSTER_DEAD) {
|
|
|
|
if (m_flAnimTime > time) {
|
|
|
|
input_movevalues = [0,0,0];
|
|
|
|
} else {
|
|
|
|
float spvel = vlen(velocity);
|
|
|
|
|
|
|
|
if (spvel < 5) {
|
2020-04-22 14:33:18 -07:00
|
|
|
SetFrame(AnimIdle());
|
2020-03-30 04:51:48 -07:00
|
|
|
} else if (spvel <= 140) {
|
2020-04-22 14:33:18 -07:00
|
|
|
SetFrame(AnimWalk());
|
2020-03-30 04:51:48 -07:00
|
|
|
} else if (spvel <= 240) {
|
2020-04-22 14:33:18 -07:00
|
|
|
SetFrame(AnimRun());
|
2020-03-30 04:51:48 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-29 02:21:26 -07:00
|
|
|
}
|
2020-03-27 02:37:01 -07:00
|
|
|
|
|
|
|
/* support for think/nextthink */
|
2020-03-30 01:40:38 -07:00
|
|
|
if (think && nextthink > 0.0f) {
|
2020-03-27 02:37:01 -07:00
|
|
|
if (nextthink < time) {
|
2020-03-30 01:00:37 -07:00
|
|
|
nextthink = 0.0f;
|
2020-03-27 02:37:01 -07:00
|
|
|
think();
|
|
|
|
}
|
|
|
|
}
|
2020-08-03 14:39:57 -07:00
|
|
|
|
|
|
|
frame1time += frametime;
|
2019-03-19 12:01:24 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::touch(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-03-30 04:51:48 -07:00
|
|
|
if (movetype != MOVETYPE_WALK) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-19 12:01:24 -07:00
|
|
|
if (other.movetype == MOVETYPE_WALK) {
|
|
|
|
velocity = normalize(other.origin - origin) * -128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::PlayerUse(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
2020-08-31 01:56:31 -07:00
|
|
|
CBaseMonster::Pain(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-07-26 16:19:53 -07:00
|
|
|
if (!m_eEnemy)
|
|
|
|
m_eEnemy = g_dmg_eAttacker;
|
2019-03-19 12:01:24 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
2020-08-31 01:56:31 -07:00
|
|
|
CBaseMonster::Death(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-04-28 08:49:32 -07:00
|
|
|
/* we were already dead before, so gib */
|
|
|
|
if (style == MONSTER_DEAD) {
|
|
|
|
Gib();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-25 14:35:05 -07:00
|
|
|
m_iFlags = 0x0;
|
2019-03-19 12:01:24 -07:00
|
|
|
|
2020-04-28 08:49:32 -07:00
|
|
|
/* if we make more than 50 damage, gib immediately */
|
2019-03-19 12:01:24 -07:00
|
|
|
if (health < -50) {
|
|
|
|
Gib();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-25 14:35:05 -07:00
|
|
|
/* make sure we're not causing any more obituaries */
|
|
|
|
flags &= ~FL_MONSTER;
|
2020-04-28 08:49:32 -07:00
|
|
|
m_iFlags = 0x0;
|
2020-03-25 14:35:05 -07:00
|
|
|
|
|
|
|
/* gibbing action */
|
2020-04-22 14:33:18 -07:00
|
|
|
SetMovetype(MOVETYPE_NONE);
|
2020-04-28 08:49:32 -07:00
|
|
|
SetSolid(SOLID_CORPSE);
|
|
|
|
health = 50 + health;
|
|
|
|
style = MONSTER_DEAD;
|
2019-03-19 12:01:24 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::Hide(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-04-22 14:33:18 -07:00
|
|
|
SetModelindex(0);
|
|
|
|
SetSolid(SOLID_NOT);
|
|
|
|
SetMovetype(MOVETYPE_NONE);
|
2019-03-19 12:01:24 -07:00
|
|
|
customphysics = __NULL__;
|
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::Respawn(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-03-25 14:35:05 -07:00
|
|
|
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
|
|
|
|
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
|
|
|
|
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
|
2020-03-25 23:02:41 -07:00
|
|
|
flags |= FL_MONSTER;
|
2019-03-19 12:01:24 -07:00
|
|
|
takedamage = DAMAGE_YES;
|
|
|
|
iBleeds = TRUE;
|
|
|
|
customphysics = Physics;
|
|
|
|
velocity = [0,0,0];
|
2020-03-25 14:35:05 -07:00
|
|
|
m_iFlags = 0x0;
|
|
|
|
SendFlags = 0xff;
|
|
|
|
style = MONSTER_IDLE;
|
|
|
|
health = base_health;
|
2020-08-03 14:39:57 -07:00
|
|
|
m_eEnemy = __NULL__;
|
2020-04-22 14:33:18 -07:00
|
|
|
|
|
|
|
SetAngles(v_angle);
|
|
|
|
SetSolid(SOLID_SLIDEBOX);
|
|
|
|
SetMovetype(MOVETYPE_WALK);
|
|
|
|
SetModel(m_oldModel);
|
|
|
|
SetSize(base_mins, base_maxs);
|
|
|
|
SetOrigin(m_oldOrigin);
|
|
|
|
|
2020-03-31 00:04:05 -07:00
|
|
|
droptofloor();
|
2019-03-19 12:01:24 -07:00
|
|
|
}
|
|
|
|
|
2020-04-12 06:50:42 -07:00
|
|
|
void
|
|
|
|
CBaseMonster::CBaseMonster(void)
|
2019-03-19 12:01:24 -07:00
|
|
|
{
|
2020-06-12 01:03:07 -07:00
|
|
|
/* FIXME: Put this somewhere else? */
|
2020-06-12 08:02:30 -07:00
|
|
|
if (!(spawnflags & MSF_MULTIPLAYER))
|
2020-06-12 01:03:07 -07:00
|
|
|
if (!(cvar("coop") == 1 || cvar("sv_playerslots") == 1)) {
|
|
|
|
remove(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-19 12:01:24 -07:00
|
|
|
CBaseEntity::CBaseEntity();
|
2020-07-26 16:19:53 -07:00
|
|
|
|
|
|
|
/* give us a 65 degree view cone */
|
|
|
|
m_flFOV = 1.0 / 65;
|
2020-11-23 12:39:40 -08:00
|
|
|
m_flChaseSpeed = 140;
|
2019-03-19 12:01:24 -07:00
|
|
|
}
|