2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2023-10-12 18:19:22 +02:00
|
|
|
Copyright (C) 2023 the OpenMoHAA team
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// actor_machinegunner.cpp
|
|
|
|
|
|
|
|
#include "actor.h"
|
2018-08-02 15:12:07 +02:00
|
|
|
#include "weapturret.h"
|
2023-10-14 13:31:19 +02:00
|
|
|
#include "bg_local.h"
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::InitMachineGunner(GlobalFuncs_t *func)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
func->BeginState = &Actor::Begin_MachineGunner;
|
|
|
|
func->EndState = &Actor::End_MachineGunner;
|
|
|
|
func->ThinkState = &Actor::Think_MachineGunner;
|
|
|
|
func->IsState = &Actor::IsMachineGunnerState;
|
|
|
|
func->FinishedAnimation = &Actor::FinishedAnimation_MachineGunner;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 20:17:09 +02:00
|
|
|
bool Actor::IsMachineGunnerState(int state)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Begin_MachineGunner(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_csMood = STRING_ALERT;
|
|
|
|
m_csIdleMood = STRING_NERVOUS;
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
if (!m_pTurret) {
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ Actor (entnum %d, radnum %d, targetname '%s') has no turret specified\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
|
|
|
targetname.c_str()
|
|
|
|
);
|
2023-10-22 16:14:52 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Sentient *pOwner;
|
|
|
|
m_pTurret->m_bHadOwner = true;
|
|
|
|
pOwner = m_pTurret->GetOwner();
|
|
|
|
if (m_pTurret->GetOwner()) {
|
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ Actor (entnum %d, radnum %d, targetname '%s') cannot use turret (entnum %d, radnum %d, "
|
|
|
|
"targetname '%s')"
|
|
|
|
" since it is already being used by Actor (entnum %d, radnum %d, targetname '%s')\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
|
|
|
targetname.c_str(),
|
|
|
|
m_pTurret->entnum,
|
|
|
|
m_pTurret->radnum,
|
|
|
|
m_pTurret->targetname.c_str(),
|
|
|
|
m_pTurret->GetOwner()->entnum,
|
|
|
|
m_pTurret->GetOwner()->radnum,
|
|
|
|
m_pTurret->GetOwner()->targetname.c_str()
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
Holster();
|
|
|
|
|
|
|
|
m_pTurret->TurretBeginUsed(this);
|
|
|
|
TransitionState(ACTOR_STATE_MACHINE_GUNNER_READY);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
void Actor::End_MachineGunner(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!GetWeapon(WEAPON_MAIN)) {
|
|
|
|
giveItem("models/weapons/mp40.tik");
|
|
|
|
}
|
|
|
|
|
|
|
|
Unholster();
|
2024-04-28 20:39:54 +02:00
|
|
|
if (m_pTurret) {
|
|
|
|
m_pTurret->m_bHadOwner = true;
|
|
|
|
if (m_pTurret->GetOwner() == this) {
|
|
|
|
m_pTurret->TurretEndUsed();
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::ThinkHoldGun_TurretGun(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 16:14:52 +02:00
|
|
|
Vector vForward;
|
|
|
|
vec3_t new_angles;
|
|
|
|
vec3_t offset;
|
|
|
|
vec3_t newOrigin;
|
2023-10-12 18:19:22 +02:00
|
|
|
float right;
|
2023-10-22 16:14:52 +02:00
|
|
|
float heightDiff;
|
|
|
|
float machine_gunner_hands_up_stand;
|
|
|
|
float temp;
|
|
|
|
trace_t trace;
|
|
|
|
Vector end;
|
|
|
|
|
|
|
|
if (m_State != ACTOR_STATE_MACHINE_GUNNER_READY) {
|
|
|
|
DesiredAnimation(ANIM_MODE_FROZEN, STRING_ANIM_MG42_RELOAD_SCR);
|
|
|
|
m_bAnimScriptSet = false;
|
|
|
|
} else if (m_pTurret->IsFiring()) {
|
|
|
|
if (m_pTurret->aim_target == G_GetEntity(0)) {
|
|
|
|
m_bNoSurprise = true;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-22 16:14:52 +02:00
|
|
|
|
|
|
|
DesiredAnimation(ANIM_MODE_FROZEN, STRING_ANIM_MG42_SHOOT_SCR);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-22 16:14:52 +02:00
|
|
|
DesiredAnimation(ANIM_MODE_FROZEN, STRING_ANIM_MG42_IDLE_SCR);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CheckUnregister();
|
|
|
|
StopTurning();
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
VectorSet(new_angles, 0, m_pTurret->angles[1], 0);
|
|
|
|
setAngles(new_angles);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
VectorScale(m_pTurret->orientation[0], -39, offset);
|
|
|
|
VectorAdd(m_pTurret->origin, offset, newOrigin);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
if (m_State == ACTOR_STATE_MACHINE_GUNNER_RELOADING) {
|
2023-10-12 18:19:22 +02:00
|
|
|
heightDiff = 71.6f;
|
|
|
|
} else {
|
|
|
|
heightDiff = 71.8f;
|
|
|
|
}
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
newOrigin[2] -= heightDiff;
|
|
|
|
machine_gunner_hands_up_stand = origin[2] - newOrigin[2];
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
if (machine_gunner_hands_up_stand < 0) {
|
2023-10-22 16:14:52 +02:00
|
|
|
if (m_State == ACTOR_STATE_MACHINE_GUNNER_RELOADING) {
|
|
|
|
m_fCrouchWeight = 0;
|
|
|
|
|
|
|
|
temp = (origin[2] + 71.6f - m_pTurret->origin[2]) / 39.f;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (temp >= -1.0 && temp <= 1.0) {
|
2023-10-22 16:14:52 +02:00
|
|
|
m_pTurret->angles[0] = RAD2DEG(atan(temp / sqrt(temp * -temp + 1)));
|
|
|
|
m_pTurret->setAngles(m_pTurret->angles);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-10-22 16:14:52 +02:00
|
|
|
m_fCrouchWeight = machine_gunner_hands_up_stand / 17.1f;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fCrouchWeight < -1.0) {
|
|
|
|
m_fCrouchWeight = -1.0;
|
|
|
|
}
|
|
|
|
}
|
2023-10-22 16:14:52 +02:00
|
|
|
|
|
|
|
VectorScale2D(orientation[0], m_fCrouchWeight * -9.3f + 23.4f, offset);
|
|
|
|
VectorAdd2D(newOrigin, offset, newOrigin);
|
|
|
|
VectorScale2D(orientation[1], m_fCrouchWeight * 2.6f + 10.3f, offset);
|
|
|
|
VectorAdd2D(newOrigin, offset, newOrigin);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-22 16:14:52 +02:00
|
|
|
m_fCrouchWeight = machine_gunner_hands_up_stand / (heightDiff - 38.7f);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fCrouchWeight > 1.0) {
|
|
|
|
m_fCrouchWeight = 1.0;
|
|
|
|
}
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
VectorScale2D(orientation[0], m_fCrouchWeight * -3.f + 23.4f, offset);
|
|
|
|
VectorAdd2D(newOrigin, offset, newOrigin);
|
|
|
|
VectorScale2D(orientation[1], m_fCrouchWeight * -1.6f + 10.3f, offset);
|
|
|
|
VectorAdd2D(newOrigin, offset, newOrigin);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fCrouchWeight >= 0.5) {
|
|
|
|
m_csCurrentPosition = STRING_CROUCH;
|
|
|
|
} else {
|
|
|
|
m_csCurrentPosition = STRING_STAND;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateAimMotion();
|
|
|
|
UpdateAnim();
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
end[0] = newOrigin[0];
|
|
|
|
end[1] = newOrigin[1];
|
|
|
|
end[2] = newOrigin[2] - 94;
|
|
|
|
trace = G_Trace(newOrigin, MINS, MAXS, end, this, MASK_PATHSOLID, qfalse, "Actor::ThinkHoldGun_TurretGun");
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
if (trace.fraction != 1.0 && !trace.startsolid && !trace.allsolid && trace.ent) {
|
|
|
|
SafeSetOrigin(trace.endpos);
|
|
|
|
}
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
VectorClear(velocity);
|
2023-10-12 18:19:22 +02:00
|
|
|
UpdateBoneControllers();
|
|
|
|
UpdateFootsteps();
|
2023-10-12 20:17:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::Think_MachineGunner_TurretGun(void)
|
|
|
|
{
|
2023-10-22 16:14:52 +02:00
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
ThinkHoldGun_TurretGun();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (level.inttime < m_iEnemyCheckTime + 200) {
|
|
|
|
ThinkHoldGun_TurretGun();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateEnemyInternal();
|
|
|
|
|
2024-04-28 20:39:54 +02:00
|
|
|
if (m_Team == TEAM_AMERICAN) {
|
|
|
|
// Added in 2.30
|
|
|
|
ThinkHoldGun_TurretGun();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
if (m_pTurret->AI_CanTarget(G_GetEntity(0)->centroid)) {
|
|
|
|
ThinkHoldGun_TurretGun();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_pGrenade && rand() / 21474836.f <= m_fGrenadeAwareness) {
|
|
|
|
BecomeTurretGuy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!G_SightTrace(
|
|
|
|
EyePosition(),
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
static_cast<Sentient *>(G_GetEntity(0))->EyePosition(),
|
|
|
|
this,
|
|
|
|
G_GetEntity(0),
|
|
|
|
MASK_CANSEE,
|
|
|
|
qfalse,
|
|
|
|
"Actor::Think_MachineGunner"
|
|
|
|
)) {
|
|
|
|
ThinkHoldGun_TurretGun();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_IDLE) {
|
|
|
|
BecomeTurretGuy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Enemy && !(m_Enemy->flags & FL_NOTARGET) && !EnemyIsDisguised() && m_PotentialEnemies.IsEnemyConfirmed()) {
|
|
|
|
BecomeTurretGuy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Enemy && m_iCuriousTime || (m_Enemy && !EnemyIsDisguised() && !m_PotentialEnemies.IsEnemyConfirmed())) {
|
|
|
|
m_iCuriousAnimHint = 6;
|
|
|
|
BecomeTurretGuy();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThinkHoldGun_TurretGun();
|
2023-10-12 20:17:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Actor::Think_MachineGunner(void)
|
|
|
|
{
|
2023-10-22 16:14:52 +02:00
|
|
|
if (!RequireThink()) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-12 20:17:09 +02:00
|
|
|
|
2023-10-22 16:14:52 +02:00
|
|
|
if (m_pTurret && m_pTurret->GetOwner() == this && !m_bNoPlayerCollision) {
|
|
|
|
UpdateEyeOrigin();
|
|
|
|
Think_MachineGunner_TurretGun();
|
|
|
|
} else {
|
2023-10-12 20:17:09 +02:00
|
|
|
BecomeTurretGuy();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FinishedAnimation_MachineGunner(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-22 16:14:52 +02:00
|
|
|
if (!m_bAnimScriptSet && m_State == ACTOR_STATE_MACHINE_GUNNER_RELOADING) {
|
|
|
|
TransitionState(ACTOR_STATE_MACHINE_GUNNER_READY, 0);
|
2023-10-12 18:19:22 +02:00
|
|
|
Unregister(STRING_ANIMDONE);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::MachineGunner_CanSee(Entity *ent, float fov, float vision_distance)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
float delta[2];
|
|
|
|
|
|
|
|
delta[0] = ent->centroid[0] - centroid[0];
|
|
|
|
delta[1] = ent->centroid[1] - centroid[1];
|
|
|
|
if ((vision_distance <= 0.0f)
|
|
|
|
|| (delta[0] * delta[0] + delta[1] * delta[1]) <= (vision_distance * vision_distance)) {
|
|
|
|
if (gi.AreasConnected(edict->r.areanum, ent->edict->r.areanum)
|
|
|
|
&& ((fov <= 0.0f || fov >= 360.0f) || (FovCheck(delta, cos(fov * (0.5 * M_PI / 180.0)))))) {
|
|
|
|
return G_SightTrace(
|
|
|
|
centroid,
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
ent->centroid,
|
|
|
|
m_pTurret,
|
|
|
|
ent,
|
|
|
|
MASK_CANSEE,
|
|
|
|
0,
|
|
|
|
"Actor::MachineGunner_CanSee"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|