openmohaa/code/fgame/portableturret.cpp
2024-09-19 10:52:47 +02:00

1013 lines
28 KiB
C++

/*
===========================================================================
Copyright (C) 2023 the OpenMoHAA team
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
===========================================================================
*/
#include "portableturret.h"
#include "g_spawn.h"
#include "g_phys.h"
#include "player.h"
Event EV_CarryableTurret_Drop
(
"dropturret",
EV_DEFAULT,
NULL,
NULL,
"Makes the carryable turret have itself dropped",
EV_NORMAL
);
Event EV_CarryableTurret_TurretTik
(
"turrettik",
EV_DEFAULT,
NULL,
NULL,
"Tiki of the turret to place",
EV_NORMAL
);
Event EV_CarryableTurret_Place
(
"placeturret",
EV_DEFAULT,
NULL,
NULL,
"Try to place the carryable turret",
EV_NORMAL
);
Event EV_CarryableTurret_EnablePickup
(
"_internalenablepickup",
EV_DEFAULT,
NULL,
NULL,
NULL,
EV_NORMAL
);
CLASS_DECLARATION(InventoryItem, CarryableTurret, NULL) {
{&EV_Touch, NULL },
{&EV_Item_Pickup, &CarryableTurret::EventPickup },
{&EV_CarryableTurret_Drop, &CarryableTurret::DropTurret },
{&EV_CarryableTurret_TurretTik, &CarryableTurret::EventTurretTik },
{&EV_CarryableTurret_Place, &CarryableTurret::EventPlaceTurret },
{&EV_CarryableTurret_EnablePickup, &CarryableTurret::EventEnablePickup},
{NULL, NULL }
};
CarryableTurret::CarryableTurret()
{
if (LoadingSavegame) {
return;
}
if (spawnflags & 1) {
Event *ev = new Event(EV_CarryableTurret_Place);
ev->AddInteger(1);
PostEvent(ev, EV_POSTSPAWN);
}
isPickable = true;
}
void CarryableTurret::EventPickup(Event *ev)
{
Entity *ent;
Sentient *sent;
Item *item;
Weapon *activeWeap;
if (!isPickable) {
return;
}
ent = ev->GetEntity(1);
if (!Pickupable(ent)) {
// can't be picked up by the entity
return;
}
sent = static_cast<Sentient *>(ent);
if (sent->HasItem(item_name)) {
// already in possession of the carryable turret
return;
}
item = ItemPickup(sent);
if (!item) {
// couldn't pick it up
return;
}
if (!item->GetOwner()) {
// invalid owner?!
return;
}
activeWeap = item->GetOwner()->GetActiveWeapon(WEAPON_MAIN);
if (activeWeap && activeWeap != item) {
activeWeap->DetachFromOwner();
}
// make the sentient use the carryable turret
item->GetOwner()->ChangeWeapon(static_cast<Weapon *>(item), WEAPON_MAIN);
}
qboolean CarryableTurret::Removable(void)
{
return qtrue;
}
void CarryableTurret::DetachFromOwner(void)
{
Weapon::DetachFromOwner();
PostEvent(EV_CarryableTurret_Drop, 0);
}
void CarryableTurret::AttachToHolster(weaponhand_t hand)
{
Weapon::AttachToHolster(hand);
PostEvent(EV_CarryableTurret_Drop, 0);
}
void CarryableTurret::DropTurret(Event *ev)
{
Weapon *activeWeap;
Sentient *currentOwner;
if (!owner) {
return;
}
currentOwner = owner;
activeWeap = currentOwner->GetActiveWeapon(WEAPON_MAIN);
Drop();
isPickable = false;
PostEvent(EV_CarryableTurret_EnablePickup, 1.5f);
if (activeWeap == this) {
currentOwner->edict->s.eFlags |= EF_UNARMED;
}
}
qboolean CarryableTurret::Drop(void)
{
qboolean result = Weapon::Drop();
if (result) {
spawnflags &= ~SPAWNFLAG_NOPC;
CancelEventsOfType(EV_Remove);
}
return result;
}
void CarryableTurret::EventTurretTik(Event *ev)
{
turretModel = ev->GetString(1);
}
void CarryableTurret::EventPlaceTurret(Event *ev)
{
Event *newev;
Player *ownerP;
Entity *placer;
Vector turretAngles, targetPos;
Vector forward, right, up;
Vector endpos, endpos2;
Vector start, end;
Vector mins, maxs;
trace_t trace;
float groundAngle;
bool autoPlace = false;
if (ev->NumArgs() && ev->GetInteger(1)) {
autoPlace = true;
AngleVectors(angles, forward, NULL, NULL);
mins = Vector(-32, -32, 0);
maxs = Vector(32, 32, 32);
start = origin;
end = origin - forward * 55;
trace =
G_Trace(start, mins, maxs, end, this, MASK_CARRYABLETURRET, qtrue, "CarryableTurret::EventPlaceTurret1");
if (trace.startsolid || trace.fraction < 1 || trace.ent) {
gi.DPrintf(
"~*~*~ Not enough room to auto place portable turret at (%i %i %i)\n",
(int)origin[0],
(int)origin[1],
(int)origin[2]
);
angles = Vector(-90, 0, 0);
setAngles(angles);
return;
}
mins = Vector(-16, -16, 0);
maxs = Vector(16, 16, 8);
start = origin - forward * 55;
end = start;
end[2] -= 128;
trace =
G_Trace(start, mins, maxs, end, this, MASK_CARRYABLETURRET, qtrue, "CarryableTurret::EventPlaceTurret1");
mins = Vector(-16, -16, 0);
maxs = Vector(16, 16, 95);
start = trace.endpos;
trace =
G_Trace(start, mins, maxs, end, this, MASK_CARRYABLETURRET, qtrue, "CarryableTurret::EventPlaceTurret1");
if (trace.startsolid || trace.fraction < 1) {
gi.DPrintf(
"~*~*~ Not enough room to auto place portable turret at (%i %i %i)\n",
(int)origin[0],
(int)origin[1],
(int)origin[2]
);
angles = Vector(-90, 0, 0);
setAngles(angles);
return;
}
setOrigin(start);
angles[0] = 0;
angles[2] = 0;
setAngles(angles);
placer = this;
} else {
if (!owner) {
return;
}
placer = owner;
if (!placer->groundentity) {
return;
}
if (placer->IsSubclassOfPlayer()) {
ownerP = static_cast<Player *>(placer);
if (ownerP->client->ps.pm_flags & (PMF_NO_GRAVITY | PMF_VIEW_JUMP_START | PMF_VIEW_DUCK_RUN)) {
if (level.time > next_noammo_time) {
Sound(m_NoAmmoSound);
}
next_noammo_time = FireDelay(FIRE_PRIMARY) + level.time + level.frametime;
ownerP->HUDPrint(va("%s\n", gi.LV_ConvertString("You cannot place a turret right now.")));
return;
} else if (ownerP->client->ps.pm_flags & PMF_DUCKED) {
mins = Vector(-16, -16, 0);
maxs = Vector(16, 16, 95);
start = placer->origin;
trace = G_Trace(
start, mins, maxs, end, owner, MASK_PLAYERSOLID, qtrue, "CarryableTurret::EventPlaceTurret1"
);
if (trace.startsolid || trace.fraction < 1) {
if (level.time > next_noammo_time) {
Sound(m_NoAmmoSound);
}
next_noammo_time = FireDelay(FIRE_PRIMARY) + level.time + level.frametime;
ownerP->HUDPrint(va("%s\n", gi.LV_ConvertString("Not enough room to place the turret.")));
return;
}
}
}
}
turretAngles[0] = 0;
turretAngles[1] = placer->angles[1];
turretAngles[2] = 0;
AngleVectors(turretAngles, forward, right, NULL);
targetPos = placer->origin + forward * 55 + Vector(0, 0, 65.43f);
mins = Vector(-32, -32, -16);
maxs = Vector(32, 32, 8);
trace = G_Trace(
targetPos, mins, maxs, targetPos, placer, MASK_CARRYABLETURRET, qtrue, "CarryableTurret::EventPlaceTurret1"
);
if (trace.startsolid || trace.fraction < 1 || trace.ent) {
if (level.time > next_noammo_time) {
Sound(m_NoAmmoSound);
}
next_noammo_time = FireDelay(FIRE_PRIMARY) + level.time + level.frametime;
if (autoPlace) {
gi.DPrintf("Not enough room to place the turret.\n");
} else if (placer->IsSubclassOfPlayer()) {
ownerP->HUDPrint(va("%s\n", gi.LV_ConvertString("Not enough room to place the turret.")));
}
return;
}
mins = Vector(-4, -4, 0);
maxs = Vector(4, 4, 4);
start = placer->origin + Vector(0, 0, 16) + right * 12;
end = start + Vector(0, 0, -128);
trace = G_Trace(
start, mins, maxs, end, placer, CONTENTS_FENCE | CONTENTS_SOLID, qtrue, "CarryableTurret::EventPlaceTurret2"
);
endpos = trace.endpos;
start = placer->origin + Vector(0, 0, 16) - right * 12;
end = start + Vector(0, 0, -128);
trace = G_Trace(
start, mins, maxs, end, placer, CONTENTS_FENCE | CONTENTS_SOLID, qtrue, "CarryableTurret::EventPlaceTurret2"
);
endpos2 = trace.endpos;
groundAngle = RAD2DEG(atan2(endpos[2] - endpos2[2], 12));
if (fabs(groundAngle) > 40) {
if (level.time > next_noammo_time) {
Sound(m_NoAmmoSound);
}
next_noammo_time = FireDelay(FIRE_PRIMARY) + level.time + level.frametime;
if (autoPlace) {
gi.DPrintf(
"Ground is too uneven to place the turret. (Too much ground roll to the side. Ground is at %g, limit "
"is %g)\n",
fabs(groundAngle),
40.f
);
} else if (placer->IsSubclassOfPlayer()) {
ownerP = static_cast<Player *>(placer);
ownerP->HUDPrint(va("%s", gi.LV_ConvertString("Ground is too uneven to place the turret.")));
}
return;
}
mins = Vector(-2, -2, 0);
maxs = Vector(2, 2, 4);
start = targetPos + forward * 13;
end = start + Vector(0, 0, -129.43f);
trace = G_Trace(
start, mins, maxs, end, placer, CONTENTS_FENCE | CONTENTS_SOLID, qtrue, "CarryableTurret::EventPlaceTurret2"
);
groundAngle = RAD2DEG(atan2(placer->origin[2] - trace.endpos[2], 55));
if (fabs(groundAngle) > 30) {
if (level.time > next_noammo_time) {
Sound(m_NoAmmoSound);
}
next_noammo_time = FireDelay(FIRE_PRIMARY) + level.time + level.frametime;
if (autoPlace) {
gi.DPrintf(
"Ground is too uneven to place the turret. (Too much ground pitch. Ground is at %g, limit is %g)\n",
fabs(groundAngle),
30.f
);
} else if (placer->IsSubclassOfPlayer()) {
Player *ownerP = static_cast<Player *>(placer);
ownerP->HUDPrint(va("%s", gi.LV_ConvertString("Ground is too uneven to place the turret.")));
}
return;
}
turretAngles[0] = groundAngle;
AngleVectors(turretAngles, forward, NULL, up);
targetPos = placer->origin + forward * 55 + up * 65.43f;
if (!turretModel.length()) {
gi.DPrintf("WARNING: Carryable turret item '%s' doesn't have a turrettik specified\n", model.c_str());
return;
}
ClassDef *c;
PortableTurret *ent;
SpawnArgs spawnArgs;
spawnArgs.setArg("model", turretModel);
c = spawnArgs.getClassDef();
if (!c || !checkInheritance(Entity::classinfostatic(), c)) {
gi.DPrintf(
"WARNING: Carryable turret item '%s' can't find turrettik '%s'\n", model.c_str(), turretModel.c_str()
);
return;
}
if (c != PortableTurret::classinfostatic()) {
gi.DPrintf(
"WARNING: Carryable turret item '%s' set to invalid turrettik '%s'\n", model.c_str(), turretModel.c_str()
);
return;
}
ent = static_cast<PortableTurret *>(c->newInstance());
ent->setModel(turretModel);
ent->setOrigin(placer->origin + forward * 32 + up * 65.43f);
ent->setAngles(turretAngles);
ent->ProcessInitCommands();
ent->SetGroundPitch(turretAngles[0]);
ent->SetOwnerPosition(placer->origin);
ent->CancelEventsOfType(EV_Item_DropToFloor);
if (autoPlace) {
newev = new Event(EV_Item_DropToFloor, 1);
newev->AddInteger(1);
ent->ProcessEvent(newev);
ent->setOrigin(vec_zero);
PostEvent(EV_Remove, level.frametime);
} else {
ent->ProcessEvent(EV_Item_DropToFloor);
DetachGun();
RemoveFromOwner();
setOrigin(vec_zero);
PostEvent(EV_Remove, level.frametime);
placer->velocity = vec_zero;
newev = new Event(EV_Use, 1);
newev->AddEntity(placer);
ent->ProcessEvent(newev);
}
}
void CarryableTurret::EventEnablePickup(Event *ev)
{
isPickable = true;
}
bool CarryableTurret::IsCarryableTurret() const
{
return true;
}
void CarryableTurret::Archive(Archiver& arc)
{
Weapon::Archive(arc);
arc.ArchiveString(&turretModel);
arc.ArchiveBoolean(&isPickable);
}
CLASS_DECLARATION(TurretGun, PortableTurret, NULL) {
{&EV_Item_DropToFloor, &PortableTurret::PortablePlaceTurret},
{&EV_Weapon_SetAmmoClipSize, &PortableTurret::EventSetClipSize },
{NULL, NULL }
};
PortableTurret::PortableTurret()
{
groundPitch = 0.0;
nextUsableTime = 0.0;
packingUp = 0;
mustDetach = 0;
ammo_in_clip[0] = 0;
ammo_clip_size[0] = 0;
endReloadTime = 0.0;
}
PortableTurret::~PortableTurret()
{
if (baseEntity) {
baseEntity->ProcessEvent(EV_Remove);
baseEntity = NULL;
}
TurretGun::RemoveUserCamera();
}
void PortableTurret::SetGroundPitch(float pitch)
{
groundPitch = pitch;
}
void PortableTurret::SetOwnerPosition(const Vector& pos)
{
ownerPosition = pos + Vector(0, 0, 16);
}
void PortableTurret::PortablePlaceTurret(Event *ev)
{
Vector turretAngles;
Vector forward, up;
bool attachPlayer = false;
char baseModel[1024];
PlaceTurret(ev);
if (ev->NumArgs() && ev->GetInteger(1)) {
attachPlayer = true;
}
m_fPitchUpCap += groundPitch;
m_fPitchDownCap += groundPitch;
m_fMaxIdlePitch += groundPitch;
m_pUserCamera = new Camera();
currentModel = model;
COM_StripExtension(model.c_str(), baseModel, sizeof(baseModel));
strcat(baseModel, "_setup.tik");
setupModel = CanonicalTikiName(baseModel);
turretAngles[0] = groundPitch;
turretAngles[1] = m_fStartYaw;
turretAngles[2] = 0;
AngleVectors(turretAngles, forward, NULL, up);
cameraOrigin = origin + (forward * m_vViewOffset[0]) + (up * m_vViewOffset[2]);
if (attachPlayer) {
nextUsableTime = 0;
packingUp = false;
mustDetach = false;
m_pUserCamera->setOrigin(origin);
m_pUserCamera->setAngles(angles);
m_pUserCamera->SetPositionOffset(m_vViewOffset);
MakeBaseEntity();
endReloadTime = 0;
owner = NULL;
edict->r.ownerNum = ENTITYNUM_NONE;
m_fIdlePitchSpeed = 0;
m_iIdleHitCount = 0;
m_iFiring = 0;
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
ForceIdle();
} else {
nextUsableTime = level.time + 2;
packingUp = false;
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
model = setupModel;
if (setModel()) {
ForceIdle();
P_DeleteViewModel();
mustDetach = true;
m_pUserCamera->setOrigin(cameraOrigin);
m_pUserCamera->setAngles(turretAngles);
m_pUserCamera->SetPositionOffset(vec_zero);
} else {
Com_Printf("^~^~^PortableTurret::PortablePlaceTurret: Bad model name '%s'\n", setupModel.c_str());
}
}
}
void PortableTurret::MakeBaseEntity()
{
char baseModel[1024];
Vector turretAngles;
if (!baseEntity) {
COM_StripExtension(model, baseModel, sizeof(baseModel));
strcat(baseModel, "_base.tik");
baseEntity = new Entity();
}
baseEntity->takedamage = DAMAGE_NO;
baseEntity->setModel(baseModel);
baseEntity->setMoveType(MOVETYPE_NONE);
baseEntity->setSolidType(SOLID_NOT);
baseEntity->setSize(Vector(4, 4, 4), Vector(-4, -4, -50));
baseEntity->setOrigin(origin);
turretAngles[0] = groundPitch;
turretAngles[1] = angles[1];
turretAngles[2] = 0;
baseEntity->setAngles(turretAngles);
}
void PortableTurret::EventSetClipSize(Event *ev)
{
ammo_clip_size[FIRE_PRIMARY] = ev->GetFloat(1);
ammo_in_clip[FIRE_PRIMARY] = ammo_clip_size[FIRE_PRIMARY];
}
void PortableTurret::AbortTurretSetup()
{
Sentient *currentOwner;
bool isPackingUp = packingUp;
currentOwner = owner;
nextUsableTime = 0;
packingUp = false;
P_TurretEndUsed();
m_iFiring = 0;
if (isPackingUp) {
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
model = currentModel;
if (setModel()) {
ForceIdle();
MakeBaseEntity();
} else {
Com_Printf("^~^~^PortableTurret::P_ThinkActive: Bad model name '%s'\n", currentModel.c_str());
}
} else {
Item *item;
item = currentOwner->giveItem("weapons/mg42carryable.tik");
if (item) {
item->Drop();
} else {
gi.DPrintf("couldn't spawn carryable turret for player\n");
}
RemoveUserCamera();
hideModel();
setOrigin(vec_zero);
PostEvent(EV_Remove, level.frametime);
if (baseEntity) {
baseEntity->hideModel();
baseEntity->setOrigin(vec_zero);
baseEntity->PostEvent(EV_Remove, level.frametime);
baseEntity = NULL;
}
}
}
void PortableTurret::P_UserAim(usercmd_t *cmd)
{
bool doDetach = false;
if (cmd->buttons & BUTTON_ATTACKRIGHT) {
if (!mustDetach) {
doDetach = true;
}
mustDetach = true;
} else {
mustDetach = false;
}
if (nextUsableTime > level.time) {
angles[0] = groundPitch;
angles[1] = m_fStartYaw;
setAngles(angles);
TurretGun::P_UserAim(cmd);
m_iFiring = 0;
flags |= FL_THINK;
} else if (doDetach) {
nextUsableTime = level.time + 2;
packingUp = true;
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
model = setupModel;
if (setModel()) {
SetWeaponAnim("packup");
P_DeleteViewModel();
if (baseEntity) {
baseEntity->ProcessEvent(EV_Remove);
baseEntity = NULL;
}
} else {
Com_Printf("^~^~^PortableTurret::PortablePlaceTurret: Bad model name '%s'\n", model.c_str());
}
} else {
TurretGun::P_UserAim(cmd);
}
}
void PortableTurret::P_TurretEndUsed()
{
if (nextUsableTime > level.time) {
AbortTurretSetup();
return;
}
endReloadTime = 0;
TurretGun::P_TurretEndUsed();
RemoveUserCamera();
ForceIdle();
}
void PortableTurret::P_TurretBeginUsed(Player *pEnt)
{
Event *ev;
Weapon *activeWeap;
TurretGun::P_TurretBeginUsed(pEnt);
activeWeap = pEnt->GetActiveWeapon(WEAPON_MAIN);
if (activeWeap && activeWeap->GetPutaway()) {
ev = new Event("deactivateweapon", 1);
ev->AddString("righthand");
pEnt->PostEvent(ev, 0);
}
ev = new Event("modheight", 1);
ev->AddString("stand");
pEnt->ProcessEvent(ev);
ev = new Event("moveposflags", 1);
ev->AddString("standing");
pEnt->ProcessEvent(ev);
}
void PortableTurret::P_ThinkActive()
{
Event *ev;
Weapon *activeWeap;
Entity *ent;
Player *ownerP = static_cast<Player *>(owner.Pointer());
if (!ownerP->IsZoomed()) {
ownerP->ToggleZoom(80);
}
owner->setOrigin(ownerPosition);
if (nextUsableTime != 0) {
if (nextUsableTime > level.time) {
float yawCap;
// cap the pitch
if (m_vUserViewAng[0] < m_fPitchUpCap) {
m_vUserViewAng[0] = m_fPitchUpCap;
} else if (m_vUserViewAng[0] > m_fPitchDownCap) {
m_vUserViewAng[0] = m_fPitchDownCap;
}
yawCap = AngleSubtract(m_vUserViewAng[1], m_fStartYaw);
if (yawCap > m_fMaxYawOffset) {
yawCap = m_fMaxYawOffset;
} else if (yawCap < -m_fMaxYawOffset) {
yawCap = -m_fMaxYawOffset;
}
m_vUserViewAng[1] = m_fStartYaw + yawCap;
// set the view angles
owner->SetViewAngles(m_vUserViewAng);
m_pUserCamera->setAngles(m_vUserViewAng);
return;
}
nextUsableTime = 0;
if (packingUp) {
SpawnArgs spawnArgs;
ClassDef *c;
ownerP->SetHolsteredByCode(false);
P_TurretEndUsed();
m_iFiring = 0;
spawnArgs.setArg("model", "weapons/mg42carryable.tik");
c = spawnArgs.getClassDef();
if (c && checkInheritance(Entity::classinfostatic(), c)) {
ent = static_cast<Entity *>(c->newInstance());
if (ent) {
activeWeap = ownerP->GetActiveWeapon(WEAPON_MAIN);
if (activeWeap) {
activeWeap->DetachFromOwner();
}
ent->setModel("weapons/mg42carryable.tik");
ent->setOrigin(vec_zero);
ent->ProcessInitCommands();
ev = new Event(EV_Item_Pickup, 1);
ev->AddEntity(ownerP);
ent->ProcessEvent(ev);
ent->PostEvent(EV_Remove, 0);
} else {
gi.DPrintf("couldn't spawn carryable turret for player\n");
}
// remove the carryable turret entity and the base
hideModel();
setOrigin(vec_zero);
PostEvent(EV_Remove, level.frametime);
if (baseEntity) {
baseEntity->hideModel();
baseEntity->setOrigin(vec_zero);
baseEntity->PostEvent(EV_Remove, level.frametime);
baseEntity = NULL;
}
} else {
gi.DPrintf("WARNING: couldn't spawn tiki '%s'\n", "weapons/mg42carryable.tik");
}
return;
}
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
StopWeaponAnim();
model = currentModel;
if (setModel()) {
ForceIdle();
MakeBaseEntity();
P_CreateViewModel();
ForceIdle();
} else {
Com_Printf("^~^~^PortableTurret::P_ThinkActive: Bad model name '%s'\n", currentModel.c_str());
return;
}
}
if (endReloadTime != 0) {
float yawCap;
Vector jittering;
m_iFiring = 0;
if (endReloadTime < level.time) {
ammo_in_clip[FIRE_PRIMARY] = ammo_clip_size[FIRE_PRIMARY];
endReloadTime = 0;
}
// cap the pitch
if (m_vUserViewAng[0] < m_fPitchUpCap) {
m_vUserViewAng[0] = m_fPitchUpCap;
} else if (m_vUserViewAng[0] > m_fPitchDownCap) {
m_vUserViewAng[0] = m_fPitchDownCap;
}
yawCap = AngleSubtract(m_vUserViewAng[1], m_fStartYaw);
if (yawCap > m_fMaxYawOffset) {
yawCap = m_fMaxYawOffset;
} else if (yawCap < -m_fMaxYawOffset) {
yawCap = -m_fMaxYawOffset;
}
m_vUserViewAng[1] = m_fStartYaw + yawCap;
// set the view angles
owner->SetViewAngles(m_vUserViewAng);
m_pUserCamera->setAngles(m_vUserViewAng);
} else {
if (ammo_clip_size[FIRE_PRIMARY] && ammo_in_clip[FIRE_PRIMARY] > 0) {
float yawCap;
Vector delta;
Vector targetAngles;
Vector jittering;
// cap the pitch
if (m_vUserViewAng[0] < m_fPitchUpCap) {
m_vUserViewAng[0] = m_fPitchUpCap;
} else if (m_vUserViewAng[0] > m_fPitchDownCap) {
m_vUserViewAng[0] = m_fPitchDownCap;
}
yawCap = AngleSubtract(m_vUserViewAng[1], m_fStartYaw);
if (yawCap > m_fMaxYawOffset) {
yawCap = m_fMaxYawOffset;
} else if (yawCap < -m_fMaxYawOffset) {
yawCap = -m_fMaxYawOffset;
}
m_vUserViewAng[1] = m_fStartYaw + yawCap;
// set the view angles
owner->SetViewAngles(m_vUserViewAng);
delta = owner->GunTarget() - origin;
targetAngles = delta.toAngles();
P_SetTargetAngles(targetAngles);
if (m_iFiring) {
m_iFiring = 4;
if (ReadyToFire(FIRE_PRIMARY)) {
Fire(FIRE_PRIMARY);
m_fCurrViewJitter = m_fViewJitter;
if (ammo_clip_size[FIRE_PRIMARY]) {
// decrease the ammo count
ammo_in_clip[FIRE_PRIMARY]--;
}
}
}
// apply some jitter
jittering = m_vUserViewAng;
P_ApplyFiringViewJitter(jittering);
m_pUserCamera->setOrigin(origin);
m_pUserCamera->setAngles(jittering);
m_pUserCamera->SetPositionOffset(m_vViewOffset);
ownerP->client->ps.camera_flags |= CF_CAMERA_ANGLES_TURRETMODE;
} else {
m_iFiring = 0;
endReloadTime = level.time + 1.5;
angles[0] = GetGroundPitch();
angles[1] = GetStartYaw();
setAngles(angles);
SetWeaponAnim("reload");
}
}
}
void PortableTurret::P_TurretUsed(Player *player)
{
if (player != owner) {
for (Player *p = static_cast<Player *>(findradius(NULL, centroid, 50)); p;
p = static_cast<Player *>(findradius(p, centroid, 50))) {
if (!p->IsSubclassOfPlayer()) {
continue;
}
if (p != player && !p->IsSpectator() && !p->IsDead()) {
return;
}
}
}
TurretGun::P_TurretUsed(player);
}
float PortableTurret::GetGroundPitch() const
{
return groundPitch;
}
float PortableTurret::GetStartYaw() const
{
return m_fStartYaw;
}
bool PortableTurret::IsReloading() const
{
return endReloadTime > level.time;
}
bool PortableTurret::IsSettingUp() const
{
return nextUsableTime > level.time && !packingUp;
}
bool PortableTurret::IsPackingUp() const
{
return nextUsableTime > level.time && packingUp;
}
void PortableTurret::Archive(Archiver& arc)
{
TurretGun::Archive(arc);
arc.ArchiveSafePointer(&baseEntity);
arc.ArchiveFloat(&groundPitch);
arc.ArchiveVector(&ownerPosition);
arc.ArchiveFloat(&nextUsableTime);
arc.ArchiveBoolean(&packingUp);
arc.ArchiveBoolean(&mustDetach);
arc.ArchiveString(&currentModel);
arc.ArchiveString(&setupModel);
arc.ArchiveVector(&cameraOrigin);
arc.ArchiveFloat(&endReloadTime);
}