mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 21:57:57 +03:00
2969 lines
77 KiB
C++
2969 lines
77 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2024 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 "Entities.h"
|
|
#include "g_phys.h"
|
|
#include "g_spawn.h"
|
|
#include "scriptthread.h"
|
|
#include "game.h"
|
|
#include "weapon.h"
|
|
#include "weaputils.h"
|
|
#include "actor.h"
|
|
#include "sentient.h"
|
|
#include "player.h"
|
|
|
|
Container<ProjectileTarget *> g_projectileTargets;
|
|
|
|
/*QUAKED ProjectileGenerator_Target (1.0 0.0 1.0) (-12 -12 -12) (12 12 12)
|
|
|
|
Place this target down and assign it a ProjectileGenerator ID and it will
|
|
shoot here....
|
|
|
|
Here are the params:
|
|
|
|
ID <nIdNum> (Generator ID number.)
|
|
|
|
******************************************************************************/
|
|
|
|
Event EV_PG_SetID
|
|
(
|
|
"ID",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"ID",
|
|
"Sets the ID for this projectile generator\nDefault=0:",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_SetModel
|
|
(
|
|
"Model",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"Model",
|
|
"Projectile model to use.\nDefault=models/projectiles/bazookashell.tik",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MinDuration
|
|
(
|
|
"MinDuration",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"MinDuration",
|
|
"Sets the minimum duration of the bursts (in seconds)\nDefault=3",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MaxDuration
|
|
(
|
|
"MaxDuration",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"MaxDuration",
|
|
"Sets the maximum duration of bursts(in seconds)\nDefault=3",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MinNumShots
|
|
(
|
|
"MinNumShots",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"MinNumShots",
|
|
"Sets the minimum # of shots to fire in a cycle\nDefault=1",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MaxNumShots
|
|
(
|
|
"MaxNumShots",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"MaxNumShots",
|
|
"Sets the maximum # of shots to fire in a cycle\nDefault=1",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_Cycles
|
|
(
|
|
"Cycles",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"Cycles",
|
|
"Number of cycles. 0=infinte\nDefault=0",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MinDelay
|
|
(
|
|
"MinDelay",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"MinDelay",
|
|
"Minimum time between bursts.\n",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_MaxDelay
|
|
(
|
|
"MaxDelay",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"MaxDelay",
|
|
"Maximum time between bursts\nDefault=10",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_Accuracy
|
|
(
|
|
"Accuracy",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"Accuracy",
|
|
"Accuracy 0-25 feet\nDefault=10",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_ClearTarget
|
|
(
|
|
"ClearTarget",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Pick another target...",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_BeginCycle
|
|
(
|
|
"BeginCycle",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Startup the cycle..",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_TickCycle
|
|
(
|
|
"TickCycle",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Tick the cycle..",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_EndCycle
|
|
(
|
|
"EndCycle",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"End the cycle..",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_TurnOn
|
|
(
|
|
"TurnOn",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turn On and begin the first cycle",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_TurnOff
|
|
(
|
|
"TurnOff",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Turn Off and cancel the current cycle (if any)",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_Set_FireDelay
|
|
(
|
|
"firedelay",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"fFireDelay",
|
|
"Set the minimum time between shots from the weapon",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_Initialize
|
|
(
|
|
"initialize",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Initialize object",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_Set_FireOnStartUp(
|
|
"FireOnStartUp",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
"i",
|
|
"Default=1; Set this to 0 if you don't want the PG to fire on startup.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_isDonut
|
|
(
|
|
"isdonut",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"isdonut",
|
|
"will target donut",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_arcDonut
|
|
(
|
|
"arc",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"arc",
|
|
"arc in front of the player",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_minDonut
|
|
(
|
|
"mindonut",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"mindonut",
|
|
"min extent of donut from player",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_maxDonut
|
|
(
|
|
"maxdonut",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"maxdonut",
|
|
"max extent of donut from player",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_PlayPreImpactSound
|
|
(
|
|
"playpreimpact",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Play a pre-impact sound",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_SetPreImpactSound
|
|
(
|
|
"preimpactsound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"Sound",
|
|
"Set a pre-impact sound.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_SetPreImpactSoundTime
|
|
(
|
|
"preimpactsoundtime",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"delay",
|
|
"Set the time before impact to play the preimpact sound.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_SetPreImpactSoundProbability
|
|
(
|
|
"preimpactsoundprob",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"probability",
|
|
"Set the chance for a pre-impact sound to occur.\n"
|
|
"Range: ( 0.0, 1.0 ), with 0 having no chance, and 1 always occurring.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_SetLaunchSound
|
|
(
|
|
"launchsound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"Sound",
|
|
"Set a launch sound for the projectile.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_PG_GetTargetEntity
|
|
(
|
|
"gettargetentity",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Returns entity being targeted by the projectile generator,",
|
|
EV_RETURN
|
|
);
|
|
Event EV_PG_IsTurnedOn
|
|
(
|
|
"isturnedon",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Returns whether the generator is on or off.",
|
|
EV_RETURN
|
|
);
|
|
|
|
CLASS_DECLARATION(Entity, ProjectileTarget, "ProjectileGenerator_Target") {
|
|
{&EV_PG_SetID, &ProjectileTarget::EventSetId},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
void ClearProjectileTargets()
|
|
{
|
|
g_projectileTargets.ClearObjectList();
|
|
}
|
|
|
|
ProjectileTarget::ProjectileTarget()
|
|
{
|
|
m_iID = -1;
|
|
setMoveType(MOVETYPE_NONE);
|
|
setSolidType(SOLID_NOT);
|
|
hideModel();
|
|
|
|
g_projectileTargets.AddObject(this);
|
|
}
|
|
|
|
void ProjectileTarget::EventSetId(Event *ev)
|
|
{
|
|
m_iID = ev->GetInteger(1);
|
|
}
|
|
|
|
int ProjectileTarget::GetId() const
|
|
{
|
|
return m_iID;
|
|
}
|
|
|
|
void ProjectileTarget::Archive(Archiver& arc)
|
|
{
|
|
Entity::Archive(arc);
|
|
|
|
arc.ArchiveInteger(&m_iID);
|
|
}
|
|
|
|
CLASS_DECLARATION(Animate, ProjectileGenerator, "ProjectileGenerator") {
|
|
{&EV_PG_SetID, &ProjectileGenerator::EventSetId },
|
|
{&EV_PG_SetModel, &ProjectileGenerator::SetWeaponModel },
|
|
{&EV_PG_MinDuration, &ProjectileGenerator::EventMinDuration },
|
|
{&EV_PG_MaxDuration, &ProjectileGenerator::EventMaxDuration },
|
|
{&EV_PG_Cycles, &ProjectileGenerator::EventCycles },
|
|
{&EV_PG_MinNumShots, &ProjectileGenerator::EventMinNumShots },
|
|
{&EV_PG_MaxNumShots, &ProjectileGenerator::EventMaxNumShots },
|
|
{&EV_Set_FireOnStartUp, &ProjectileGenerator::EventFireOnStartUp },
|
|
{&EV_PG_MinDelay, &ProjectileGenerator::EventMinDelay },
|
|
{&EV_PG_MaxDelay, &ProjectileGenerator::EventMaxDelay },
|
|
{&EV_PG_Accuracy, &ProjectileGenerator::EventAccuracy },
|
|
{&EV_PG_BeginCycle, &ProjectileGenerator::BeginCycle },
|
|
{&EV_TickCycle, &ProjectileGenerator::TickCycle },
|
|
{&EV_EndCycle, &ProjectileGenerator::EndCycle },
|
|
{&EV_TurnOn, &ProjectileGenerator::TurnOn },
|
|
{&EV_TurnOff, &ProjectileGenerator::TurnOff },
|
|
{&EV_Initialize, &ProjectileGenerator::OnInitialize },
|
|
{&EV_Activate, &ProjectileGenerator::TurnOn },
|
|
{&EV_SetTarget, &ProjectileGenerator::SetTarget },
|
|
{&EV_PG_SetLaunchSound, &ProjectileGenerator::EventLaunchSound },
|
|
{&EV_PG_GetTargetEntity, &ProjectileGenerator::EventGetTargetEntity},
|
|
{&EV_PG_IsTurnedOn, &ProjectileGenerator::EventIsTurnedOn },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ProjectileGenerator::ProjectileGenerator()
|
|
{
|
|
m_iId = -1;
|
|
m_fMinDuration = 1;
|
|
m_fMaxDuration = 3;
|
|
m_iCycles = 0;
|
|
m_fMinDelay = 3.0;
|
|
m_fMaxDelay = 10;
|
|
m_fAccuracy = 10;
|
|
m_iCurrentCycle = 0;
|
|
m_iMinNumShots = 1;
|
|
m_iMaxNumShots = 1;
|
|
m_fCurrentTime = 0;
|
|
m_fShotsPerSec = 0;
|
|
m_iTargetIndex = -1;
|
|
m_fLastShotTime = 0;
|
|
m_iAnimSlot = 0;
|
|
m_bIsTurnedOn = false;
|
|
m_bFireOnStartUp = true;
|
|
m_bIsDonut = false;
|
|
m_fArcDonut = 0;
|
|
m_fMinDonut = 0;
|
|
m_fMaxDonut = 0;
|
|
m_pTarget = NULL;
|
|
|
|
m_fCycleTime = 1;
|
|
setMoveType(MOVETYPE_NONE);
|
|
setSolidType(SOLID_NOT);
|
|
if (ShouldPlayFireSound()) {
|
|
if (ShouldHideModel()) {
|
|
hideModel();
|
|
edict->r.svFlags |= SVF_NOCLIENT;
|
|
}
|
|
} else {
|
|
hideModel();
|
|
}
|
|
|
|
if (!LoadingSavegame && ShouldStartOn()) {
|
|
PostEvent(EV_TurnOn, 0.1f);
|
|
}
|
|
|
|
m_pCurrent = NULL;
|
|
if (!LoadingSavegame) {
|
|
PostEvent(EV_Initialize, 0.001f);
|
|
}
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldStartOn() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_TURN_ON) ? true : false;
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldHideModel() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_HIDDEN) ? true : false;
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldPlayFireSound() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_PLAY_FIRE_SOUND) ? true : false;
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldPlayMotionSound() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_PLAY_MOTION_SOUND) ? true : false;
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldRotateYaw() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_ROTATE_YAW) ? true : false;
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldRotateRoll() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_ROTATE_ROLL) ? true : false;
|
|
}
|
|
|
|
void ProjectileGenerator::EventIsTurnedOn(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bIsTurnedOn);
|
|
}
|
|
|
|
void ProjectileGenerator::EventGetTargetEntity(Event *ev)
|
|
{
|
|
ev->AddEntity(m_pCurrent);
|
|
}
|
|
|
|
void ProjectileGenerator::EventLaunchSound(Event *ev)
|
|
{
|
|
m_sLaunchSound = ev->GetString(1);
|
|
}
|
|
|
|
void ProjectileGenerator::SetTarget(Event *ev)
|
|
{
|
|
SetTarget(ev->GetEntity(1));
|
|
}
|
|
|
|
void ProjectileGenerator::SetTarget(Entity *ent)
|
|
{
|
|
m_pTarget = ent;
|
|
}
|
|
|
|
void ProjectileGenerator::OnInitialize(Event *ev)
|
|
{
|
|
if (ShouldRotateYaw()) {
|
|
angles.setYaw(angles.yaw() + 180);
|
|
}
|
|
if (ShouldRotateRoll()) {
|
|
angles.setRoll(angles.roll() + 180);
|
|
}
|
|
}
|
|
|
|
void ProjectileGenerator::TurnOff(Event *ev)
|
|
{
|
|
CancelEventsOfType(EV_PG_BeginCycle);
|
|
CancelEventsOfType(EV_TickCycle);
|
|
m_bIsTurnedOn = false;
|
|
}
|
|
|
|
void ProjectileGenerator::TurnOn(Event *ev)
|
|
{
|
|
if (!m_bIsTurnedOn) {
|
|
CancelEventsOfType(EV_PG_BeginCycle);
|
|
CancelEventsOfType(EV_TickCycle);
|
|
SetupNextCycle();
|
|
m_bIsTurnedOn = true;
|
|
}
|
|
}
|
|
|
|
void ProjectileGenerator::SetupNextCycle()
|
|
{
|
|
float numShots;
|
|
float delay;
|
|
|
|
if (m_iCycles && m_iCurrentCycle >= m_iCycles) {
|
|
m_pCurrent = NULL;
|
|
TurnOff(NULL);
|
|
return;
|
|
}
|
|
|
|
// retrieve the target
|
|
m_pCurrent = ChooseTarget();
|
|
m_fCycleTime = G_Random(m_fMaxDuration - m_fMinDuration) + m_fMinDuration;
|
|
|
|
// get a random number of shots
|
|
numShots = m_iMinNumShots;
|
|
if (numShots < m_iMaxNumShots) {
|
|
numShots = rand() % (m_iMaxNumShots - m_iMinNumShots) + m_iMinNumShots;
|
|
}
|
|
|
|
// get a random delay
|
|
m_fShotsPerSec = numShots / m_fCycleTime;
|
|
delay = 0.01f;
|
|
if (m_bIsTurnedOn || !m_bFireOnStartUp) {
|
|
delay = G_Random(m_fMaxDelay - m_fMinDelay) + m_fMinDelay;
|
|
}
|
|
|
|
PostEvent(EV_PG_BeginCycle, delay);
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldTargetRandom() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_TARGET_RANDOM) ? true : false;
|
|
}
|
|
|
|
Entity *ProjectileGenerator::ChooseTarget()
|
|
{
|
|
int numTargets;
|
|
|
|
if (m_pTarget) {
|
|
m_vTargetOrg = GetTargetPos(m_pTarget);
|
|
return m_pTarget;
|
|
}
|
|
|
|
if (ShouldTargetPlayer()) {
|
|
Entity *target = G_FindTarget(this, "player");
|
|
if (target) {
|
|
m_vTargetOrg = GetTargetPos(target);
|
|
return target;
|
|
}
|
|
}
|
|
|
|
if (!m_projectileTargets.NumObjects()) {
|
|
GetLocalTargets();
|
|
}
|
|
|
|
numTargets = m_projectileTargets.NumObjects();
|
|
if (numTargets) {
|
|
ProjectileTarget *target;
|
|
|
|
if (ShouldTargetRandom()) {
|
|
target = m_projectileTargets.ObjectAt((rand() % numTargets) + 1);
|
|
} else {
|
|
m_iTargetIndex = (m_iTargetIndex + 1) % numTargets;
|
|
target = m_projectileTargets.ObjectAt(m_iTargetIndex + 1);
|
|
}
|
|
|
|
m_vTargetOrg = GetTargetPos(target);
|
|
return target;
|
|
}
|
|
|
|
spawnflags |= PT_SPAWNFLAG_TARGET_PLAYER;
|
|
return ChooseTarget();
|
|
}
|
|
|
|
void ProjectileGenerator::GetLocalTargets()
|
|
{
|
|
int i;
|
|
|
|
m_projectileTargets.ClearObjectList();
|
|
for (i = 1; i <= g_projectileTargets.NumObjects(); i++) {
|
|
ProjectileTarget *target = g_projectileTargets.ObjectAt(i);
|
|
if (m_iId == target->GetId()) {
|
|
m_projectileTargets.AddObject(target);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ProjectileGenerator::ShouldTargetPlayer() const
|
|
{
|
|
return (spawnflags & PT_SPAWNFLAG_TARGET_PLAYER) ? true : false;
|
|
}
|
|
|
|
Vector ProjectileGenerator::GetTargetPos(Entity *target)
|
|
{
|
|
Vector vOrg;
|
|
Vector vForward;
|
|
Vector vAngles;
|
|
float fRandDonut;
|
|
|
|
if (!target) {
|
|
return Vector(0, 0, 0);
|
|
}
|
|
|
|
vOrg = target->origin;
|
|
|
|
if (target->IsSubclassOfActor()) {
|
|
vOrg += Vector(0, 0, 36);
|
|
}
|
|
|
|
if (m_bIsDonut) {
|
|
Entity *playerTarget = G_FindTarget(this, "player");
|
|
|
|
if (playerTarget) {
|
|
vAngles = playerTarget->client->ps.viewangles;
|
|
} else {
|
|
vAngles = target->angles;
|
|
}
|
|
|
|
if (rand() & 1) {
|
|
vAngles.setYaw(vAngles[1] + m_fArcDonut / 2.0);
|
|
} else {
|
|
vAngles.setYaw(vAngles[1] - m_fArcDonut / 2.0);
|
|
}
|
|
|
|
AngleVectors(vAngles, vForward, NULL, NULL);
|
|
|
|
fRandDonut = G_Random(m_fMaxDonut - m_fMinDonut) + m_fMinDonut;
|
|
vOrg += vForward * (fRandDonut * 16);
|
|
} else {
|
|
vAngles.setYaw(G_Random(360));
|
|
AngleVectors(vAngles, vForward, NULL, NULL);
|
|
|
|
fRandDonut = G_Random(m_fAccuracy) * 16;
|
|
vOrg += vForward * fRandDonut;
|
|
}
|
|
|
|
return vOrg;
|
|
}
|
|
|
|
void ProjectileGenerator::GetMuzzlePos(Vector& pos)
|
|
{
|
|
orientation_t orient;
|
|
|
|
pos = origin;
|
|
|
|
if (GetRawTag("tag_barrel", &orient)) {
|
|
vec3_t axis[3];
|
|
int i;
|
|
|
|
AnglesToAxis(angles, axis);
|
|
for (i = 0; i < 3; i++) {
|
|
VectorMA(pos, orient.origin[i], axis[i], pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ProjectileGenerator::Fire()
|
|
{
|
|
m_fLastShotTime = level.time;
|
|
SetWeaponAnim("Fire", 0);
|
|
}
|
|
|
|
void ProjectileGenerator::TryLaunchSound()
|
|
{
|
|
if (m_sLaunchSound != "") {
|
|
Sound(m_sLaunchSound, CHAN_AUTO);
|
|
}
|
|
}
|
|
|
|
void ProjectileGenerator::SetWeaponAnim(const char *name, Event *ev)
|
|
{
|
|
int animnum = gi.Anim_NumForName(edict->tiki, name);
|
|
if (animnum == -1) {
|
|
return;
|
|
}
|
|
|
|
StopAnimating(m_iAnimSlot);
|
|
RestartAnimSlot(m_iAnimSlot);
|
|
|
|
int idleanim = gi.Anim_NumForName(edict->tiki, "idle");
|
|
|
|
edict->s.frameInfo[m_iAnimSlot].index = idleanim;
|
|
m_iAnimSlot = (m_iAnimSlot + 1) & 3;
|
|
edict->s.frameInfo[m_iAnimSlot].index = idleanim;
|
|
|
|
if (ev) {
|
|
NewAnim(animnum, ev, m_iAnimSlot);
|
|
} else {
|
|
NewAnim(animnum, m_iAnimSlot);
|
|
}
|
|
|
|
SetOnceType(m_iAnimSlot);
|
|
RestartAnimSlot(m_iAnimSlot);
|
|
}
|
|
|
|
void ProjectileGenerator::EventAccuracy(Event *ev)
|
|
{
|
|
m_fAccuracy = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMaxDelay(Event *ev)
|
|
{
|
|
m_fMaxDelay = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMinDelay(Event *ev)
|
|
{
|
|
m_fMinDelay = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventFireOnStartUp(Event *ev)
|
|
{
|
|
m_bFireOnStartUp = ev->GetBoolean(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMaxNumShots(Event *ev)
|
|
{
|
|
m_iMaxNumShots = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMinNumShots(Event *ev)
|
|
{
|
|
m_iMinNumShots = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventCycles(Event *ev)
|
|
{
|
|
m_iCycles = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMaxDuration(Event *ev)
|
|
{
|
|
m_fMaxDuration = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventMinDuration(Event *ev)
|
|
{
|
|
m_fMinDuration = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::SetWeaponModel(Event *ev)
|
|
{
|
|
setModel(ev->GetString(1));
|
|
}
|
|
|
|
void ProjectileGenerator::EventSetId(Event *ev)
|
|
{
|
|
m_iId = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator::BeginCycle(Event *ev)
|
|
{
|
|
if (!m_bIsTurnedOn) {
|
|
return;
|
|
}
|
|
|
|
if (!m_fShotsPerSec) {
|
|
SetupNextCycle();
|
|
return;
|
|
}
|
|
|
|
if (m_pCurrent) {
|
|
m_vTargetOrg = GetTargetPos(m_pCurrent);
|
|
}
|
|
|
|
m_iCurrentCycle++;
|
|
m_fCurrentTime = 0;
|
|
|
|
TickCycle(ev);
|
|
|
|
PostEvent(EV_EndCycle, m_fCycleTime);
|
|
}
|
|
|
|
void ProjectileGenerator::TickCycle(Event *ev)
|
|
{
|
|
if (!m_bIsTurnedOn) {
|
|
return;
|
|
}
|
|
|
|
m_fCurrentTime += level.frametime * m_fShotsPerSec;
|
|
if (m_fCurrentTime >= 1.f) {
|
|
float f = floor(m_fCurrentTime);
|
|
if (Attack(floor(f))) {
|
|
m_fCurrentTime -= floor(f);
|
|
}
|
|
}
|
|
|
|
PostEvent(EV_TickCycle, 0.01f);
|
|
}
|
|
|
|
void ProjectileGenerator::EndCycle(Event *ev)
|
|
{
|
|
CancelEventsOfType(EV_TickCycle);
|
|
SetupNextCycle();
|
|
}
|
|
|
|
void ProjectileGenerator::EventmaxDonut(Event *ev)
|
|
{
|
|
m_fMaxDonut = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventminDonut(Event *ev)
|
|
{
|
|
m_fMinDonut = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventarcDonut(Event *ev)
|
|
{
|
|
m_fArcDonut = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator::EventisDonut(Event *ev)
|
|
{
|
|
m_bIsDonut = ev->GetBoolean(1);
|
|
}
|
|
|
|
bool ProjectileGenerator::Attack(int count)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
void ProjectileGenerator::Archive(Archiver& arc)
|
|
{
|
|
Animate::Archive(arc);
|
|
|
|
arc.ArchiveInteger(&m_iId);
|
|
arc.ArchiveInteger(&m_iCycles);
|
|
arc.ArchiveFloat(&m_fMinDuration);
|
|
arc.ArchiveFloat(&m_fMaxDuration);
|
|
arc.ArchiveInteger(&m_iMinNumShots);
|
|
arc.ArchiveInteger(&m_iMaxNumShots);
|
|
arc.ArchiveFloat(&m_fMinDelay);
|
|
arc.ArchiveFloat(&m_fMaxDelay);
|
|
arc.ArchiveFloat(&m_fAccuracy);
|
|
arc.ArchiveInteger(&m_iCurrentCycle);
|
|
arc.ArchiveFloat(&m_fCycleTime);
|
|
arc.ArchiveFloat(&m_fShotsPerSec);
|
|
arc.ArchiveFloat(&m_fCurrentTime);
|
|
arc.ArchiveInteger(&m_iTargetIndex);
|
|
arc.ArchiveFloat(&m_fLastShotTime);
|
|
arc.ArchiveInteger(&m_iAnimSlot);
|
|
arc.ArchiveBool(&m_bIsTurnedOn);
|
|
arc.ArchiveInteger(&m_bIsDonut);
|
|
arc.ArchiveFloat(&m_fArcDonut);
|
|
arc.ArchiveFloat(&m_fMinDonut);
|
|
arc.ArchiveFloat(&m_fMaxDonut);
|
|
arc.ArchiveString(&m_sLaunchSound);
|
|
arc.ArchiveBool(&m_bFireOnStartUp);
|
|
arc.ArchiveObjectPointer((Class **)&m_pTarget);
|
|
arc.ArchiveObjectPointer((Class **)&m_pCurrent);
|
|
}
|
|
|
|
/*QUAKED ProjectileGenerator_Projectile (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) LaunchSound x TargetRandom StartOn FlipYaw FlipRoll TargetPlayer HideModel
|
|
|
|
Allows you to launch projectiles without the need for actual AI. Useful for faking large battles.
|
|
Here are the params:
|
|
|
|
ID <nIdNum>
|
|
Model <sModelName> (Defaults to bazooka weapon)
|
|
Projectile <sModelName> (Defaults to bazooka projectile)
|
|
MinDuration <nMinDur=1> (Min burst cycle duration)
|
|
MaxDuration <nMaxDur=3> (Max burst cycle duration)
|
|
Cycles <nCycles=0> (0=infinite)
|
|
MinNumShots <nMinNumShots=1> (Minimum # of shots per cycle)
|
|
MaxNumShots <nMaxNumShots=1> (Maximum # of shots per cycle)
|
|
|
|
MinDelay <nDelay=2> (min amount of time between cycles)
|
|
MaxDelay <nDelay=10> (max amount of time between cycles)
|
|
Accuracy <nAccuracy=10> (accuracy measured in feet. 0-25 feet range)
|
|
FireOnStartUp (defaults to 1. This flag tells the PG to fire immediately when turned on. Then do its delay from then on.)
|
|
|
|
IsDonut <nIsDonut=1> (indicates to use donut to calculate impact location)
|
|
Arc <nArc=#degrees) (how many degrees does the arc have)
|
|
minDonut <nMinDonut=15> (mindistance from player)
|
|
maxDonut <nMaxDonut=30> (maxdistance from player)
|
|
launchsound <sSoundName> (Defaults to no sound)
|
|
|
|
preimpactsound <sSoundName> (Defaults to no sound)
|
|
preimpactsoundtime <nTime=1.0> (Time before impact to begin preimpact sound)
|
|
preimpactsoundprob <nProb=0.0> (Chance of an impact sound being played. 0..1 range )
|
|
|
|
Here are some useful script commands:
|
|
|
|
$<generatorName> TurnOn
|
|
$<generatorName> TurnOff
|
|
$<generatorName> playpreimpact ( plays the preimpact sound immediately )
|
|
$<generatorName> gettargetentity ( return the entity that is targeted )
|
|
$<generatorName> isturnedon ( is the projectil generator turned on? )
|
|
|
|
******************************************************************************/
|
|
|
|
CLASS_DECLARATION(ProjectileGenerator, ProjectileGenerator_Projectile, "ProjectileGenerator_Projectile") {
|
|
{&EV_Weapon_SetProjectile, &ProjectileGenerator_Projectile::SetProjectileModel },
|
|
{&EV_PG_isDonut, &ProjectileGenerator_Projectile::EventisDonut },
|
|
{&EV_PG_arcDonut, &ProjectileGenerator_Projectile::EventarcDonut },
|
|
{&EV_PG_minDonut, &ProjectileGenerator_Projectile::EventminDonut },
|
|
{&EV_PG_maxDonut, &ProjectileGenerator_Projectile::EventmaxDonut },
|
|
{&EV_PG_PlayPreImpactSound, &ProjectileGenerator_Projectile::PlayPreImpactSound },
|
|
{&EV_PG_SetPreImpactSound, &ProjectileGenerator_Projectile::SetPreImpactSound },
|
|
{&EV_PG_SetPreImpactSoundTime, &ProjectileGenerator_Projectile::SetPreImpactSoundTime },
|
|
{&EV_PG_SetPreImpactSoundProbability, &ProjectileGenerator_Projectile::SetPreImpactSoundProbability},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ProjectileGenerator_Projectile::ProjectileGenerator_Projectile()
|
|
{
|
|
if (LoadingSavegame) {
|
|
return;
|
|
}
|
|
|
|
m_sProjectileModel = "models/projectiles/bazookashell.tik";
|
|
setModel("models/weapons/bazooka.tik");
|
|
m_sPreImpactSound = "";
|
|
m_fImpactSoundTime = 1;
|
|
m_fImpactSoundProbability = 0;
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::SetPreImpactSoundProbability(Event *ev)
|
|
{
|
|
m_fImpactSoundProbability = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::SetPreImpactSoundTime(Event *ev)
|
|
{
|
|
m_fImpactSoundTime = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::SetPreImpactSound(Event *ev)
|
|
{
|
|
m_sPreImpactSound = ev->GetString(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::PlayPreImpactSound(Event *ev)
|
|
{
|
|
Sound(m_sPreImpactSound, CHAN_AUTO);
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::SetProjectileModel(Event *ev)
|
|
{
|
|
m_sProjectileModel = ev->GetString(1);
|
|
}
|
|
|
|
float ProjectileGenerator_Projectile::EstimateImpactTime(
|
|
const Vector& targetOrigin, const Vector& fromOrigin, float speed
|
|
) const
|
|
{
|
|
Vector delta = fromOrigin - targetOrigin;
|
|
|
|
return delta.length() / speed;
|
|
}
|
|
|
|
bool ProjectileGenerator_Projectile::Attack(int count)
|
|
{
|
|
Projectile *proj;
|
|
static int NukePlayer = 0;
|
|
Vector dir(0, 0, 1);
|
|
float speed = 500;
|
|
|
|
Vector muzzlePos = origin;
|
|
GetMuzzlePos(muzzlePos);
|
|
|
|
if (m_pCurrent) {
|
|
m_vTargetOrg = GetTargetPos(m_pCurrent);
|
|
|
|
if (m_bIsDonut) {
|
|
Entity *playerTarget = G_FindTarget(this, "player");
|
|
|
|
if (playerTarget) {
|
|
if (playerTarget->takedamage) {
|
|
if (!Q_stricmp(targetname, "artillerykiller")) {
|
|
NukePlayer++;
|
|
}
|
|
} else {
|
|
NukePlayer = 0;
|
|
}
|
|
|
|
if (NukePlayer > 2) {
|
|
m_vTargetOrg = playerTarget->origin;
|
|
muzzlePos = playerTarget->origin;
|
|
muzzlePos[2] += 256;
|
|
NukePlayer = 0;
|
|
} else {
|
|
muzzlePos = m_vTargetOrg;
|
|
muzzlePos[2] += random() * 500.0 + 500.0;
|
|
}
|
|
} else {
|
|
muzzlePos = m_vTargetOrg;
|
|
muzzlePos[2] += 1000.0;
|
|
}
|
|
}
|
|
|
|
dir = m_vTargetOrg - muzzlePos;
|
|
dir.normalize();
|
|
|
|
Vector newAngles;
|
|
VectorToAngles(dir, newAngles);
|
|
|
|
if (ShouldRotateYaw()) {
|
|
newAngles.setYaw(newAngles.yaw() + 180);
|
|
}
|
|
|
|
if (ShouldRotateRoll()) {
|
|
newAngles.setRoll(newAngles.roll() + 180);
|
|
}
|
|
|
|
setAngles(newAngles);
|
|
} else {
|
|
AngleVectors(angles, dir, NULL, NULL);
|
|
}
|
|
|
|
Fire();
|
|
TryLaunchSound();
|
|
|
|
proj = ProjectileAttack(muzzlePos, dir, this, m_sProjectileModel, 1.0, speed);
|
|
|
|
if (proj->flags & FL_THINK) {
|
|
gi.DPrintf("Projectile used is thinking...pre-impact sound cannot be predicted.\n");
|
|
return true;
|
|
}
|
|
|
|
if (G_Random() <= m_fImpactSoundProbability && m_sPreImpactSound.length()) {
|
|
float time;
|
|
|
|
time = EstimateImpactTime(m_vTargetOrg, muzzlePos, speed);
|
|
time -= 1.0;
|
|
|
|
if (time > 0) {
|
|
PostEvent(EV_PG_PlayPreImpactSound, time);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ProjectileGenerator_Projectile::Archive(Archiver& arc)
|
|
{
|
|
ProjectileGenerator::Archive(arc);
|
|
|
|
arc.ArchiveString(&m_sProjectileModel);
|
|
arc.ArchiveString(&m_sPreImpactSound);
|
|
arc.ArchiveFloat(&m_fImpactSoundTime);
|
|
arc.ArchiveFloat(&m_fImpactSoundProbability);
|
|
}
|
|
|
|
/*QUAKED ProjectileGenerator_Gun (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) LaunchSound x TargetRandom StartOn FlipYaw FlipRoll TargetPlayer HideModel
|
|
|
|
Allows you to launch projectiles without the need for actual AI. Useful for faking large battles.
|
|
Here are the params:
|
|
|
|
ID <nIdNum>
|
|
MinDuration <nMinDur=1> (Min burst cycle duration)
|
|
MaxDuration <nMaxDur=3> (Max burst cycle duration)
|
|
Cycles <nCycles=0> (0=infinite)
|
|
MinNumShots <nMinNumShots=1> (Minimum # of shots per cycle)
|
|
MaxNumShots <nMaxNumShots=1> (Maximum # of shots per cycle)
|
|
|
|
MinDelay <nDelay=2> (min amount of time between cycles)
|
|
MaxDelay <nDelay=10> (max amount of time between cycles)
|
|
Accuracy <nAccuracy=10> (accuracy measured in feet. 0-25 feet range)
|
|
launchsound <sSoundName> (Defaults to no sound)
|
|
FireOnStartUp (defaults to 1. This flag tells the PG to fire immediately when turned on. Then do its delay from then on.)
|
|
|
|
bulletLarge <0,1,2,3> (whether to fire normal, rifle, artillery or larger bullets)
|
|
tracerSpeed <0,2> (scale factor for tracer speed)
|
|
|
|
Here are some useful script commands:
|
|
|
|
$<generatorName> TurnOn
|
|
$<generatorName> TurnOff
|
|
$<generatorName> gettargetentity ( return the entity that is targeted )
|
|
$<generatorName> isturnedon ( is the projectil generator turned on? )
|
|
|
|
******************************************************************************/
|
|
|
|
Event EV_PG_SetFakeBullets(
|
|
"fakebullets",
|
|
EV_DEFAULT,
|
|
"b",
|
|
"useFakeBullets",
|
|
"Whether or not the projectile generator should fire real bullets."
|
|
);
|
|
|
|
CLASS_DECLARATION(ProjectileGenerator, ProjectileGenerator_Gun, "ProjectileGenerator_Gun") {
|
|
{&EV_PG_SetID, &ProjectileGenerator_Gun::EventSetId },
|
|
{&EV_Weapon_SetBulletRange, &ProjectileGenerator_Gun::SetBulletRange },
|
|
{&EV_Weapon_SetBulletSpread, &ProjectileGenerator_Gun::SetBulletSpread },
|
|
{&EV_Weapon_SetTracerFrequency, &ProjectileGenerator_Gun::SetTracerFrequency },
|
|
{&EV_Weapon_SetBulletDamage, &ProjectileGenerator_Gun::SetBulletDamage },
|
|
{&EV_Weapon_SetBulletCount, &ProjectileGenerator_Gun::SetBulletCount },
|
|
{&EV_PG_SetFakeBullets, &ProjectileGenerator_Gun::SetFakeBullets },
|
|
{&EV_Weapon_SetBulletLarge, &ProjectileGenerator_Gun::SetBulletLarge },
|
|
{&EV_Weapon_SetTracerSpeed, &ProjectileGenerator_Gun::SetTracerSpeed },
|
|
{&EV_Weapon_SetBulletKnockback, &ProjectileGenerator_Gun::SetBulletKnockback },
|
|
{&EV_Weapon_SetBulletThroughWood, &ProjectileGenerator_Gun::SetBulletThroughWood },
|
|
{&EV_Weapon_SetBulletThroughMetal, &ProjectileGenerator_Gun::SetBulletThroughMetal},
|
|
{&EV_Weapon_SetMeansOfDeath, &ProjectileGenerator_Gun::SetMeansOfDeath },
|
|
{&EV_Weapon_FireDelay, &ProjectileGenerator_Gun::SetFireDelay },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ProjectileGenerator_Gun::ProjectileGenerator_Gun()
|
|
{
|
|
m_fBulletRange = 4000;
|
|
m_fBulletDamage = 40;
|
|
m_iBulletCount = 1;
|
|
m_vBulletSpread = Vector(40, 40, 0);
|
|
m_iTracerFrequency = 0;
|
|
m_iBulletLarge = 0;
|
|
m_iMeansOfDeath = MOD_BULLET;
|
|
m_fBulletThroughWood = 0;
|
|
m_fBulletThroughMetal = 0;
|
|
m_iBulletKnockback = 0;
|
|
m_iAttackCount = 0;
|
|
m_fFireDelay = 1;
|
|
m_fTracerSpeed = 1.0;
|
|
m_bFakeBullets = 0;
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetFireDelay(Event *ev)
|
|
{
|
|
m_fFireDelay = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetMeansOfDeath(Event *ev)
|
|
{
|
|
m_iMeansOfDeath = MOD_string_to_int(ev->GetString(1));
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletThroughWood(Event *ev)
|
|
{
|
|
m_fBulletThroughWood = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletThroughMetal(Event *ev)
|
|
{
|
|
m_fBulletThroughMetal = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletKnockback(Event *ev)
|
|
{
|
|
m_iBulletKnockback = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetTracerSpeed(Event *ev)
|
|
{
|
|
m_fTracerSpeed = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletLarge(Event *ev)
|
|
{
|
|
m_iBulletLarge = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetFakeBullets(Event *ev)
|
|
{
|
|
m_bFakeBullets = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletCount(Event *ev)
|
|
{
|
|
m_iBulletCount = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletDamage(Event *ev)
|
|
{
|
|
m_fBulletDamage = ev->GetFloat(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetTracerFrequency(Event *ev)
|
|
{
|
|
m_iTracerFrequency = ev->GetInteger(1);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletSpread(Event *ev)
|
|
{
|
|
m_vBulletSpread.x = ev->GetFloat(1);
|
|
m_vBulletSpread.y = ev->GetFloat(2);
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::SetBulletRange(Event *ev)
|
|
{
|
|
m_fBulletRange = ev->GetFloat(1);
|
|
}
|
|
|
|
bool ProjectileGenerator_Gun::Attack(int count)
|
|
{
|
|
Vector dir;
|
|
Vector right, up;
|
|
Vector muzzlePos;
|
|
int iTracerCount = 0;
|
|
|
|
if (ShouldPlayFireSound() && m_fLastShotTime + m_fFireDelay > level.time) {
|
|
return false;
|
|
}
|
|
|
|
GetMuzzlePos(muzzlePos);
|
|
|
|
if (m_pCurrent) {
|
|
dir = m_vTargetOrg - muzzlePos;
|
|
dir.normalize();
|
|
|
|
Vector newAngles;
|
|
VectorToAngles(dir, newAngles);
|
|
|
|
AngleVectors(newAngles, NULL, right, up);
|
|
|
|
if (ShouldRotateYaw()) {
|
|
newAngles.setYaw(newAngles.yaw() + 180);
|
|
}
|
|
|
|
if (ShouldRotateRoll()) {
|
|
newAngles.setRoll(newAngles.roll() + 180);
|
|
}
|
|
|
|
setAngles(newAngles);
|
|
} else {
|
|
AngleVectors(angles, dir, right, up);
|
|
}
|
|
|
|
int iTracerFrequency = 0;
|
|
|
|
m_iAttackCount += count;
|
|
if (!m_iTracerFrequency) {
|
|
m_iTracerFrequency = 4;
|
|
}
|
|
|
|
if (!(m_iAttackCount % m_iTracerFrequency)) {
|
|
m_iAttackCount = 0;
|
|
iTracerFrequency = count;
|
|
}
|
|
|
|
if (ShouldPlayFireSound()) {
|
|
Fire();
|
|
}
|
|
|
|
TryLaunchSound();
|
|
|
|
if (m_bFakeBullets) {
|
|
FakeBulletAttack(
|
|
muzzlePos,
|
|
muzzlePos,
|
|
dir,
|
|
right,
|
|
up,
|
|
m_fBulletRange,
|
|
m_fBulletDamage,
|
|
m_iBulletLarge,
|
|
m_vBulletSpread,
|
|
count,
|
|
this,
|
|
iTracerFrequency,
|
|
&iTracerCount,
|
|
m_fTracerSpeed
|
|
);
|
|
} else {
|
|
BulletAttack(
|
|
muzzlePos,
|
|
muzzlePos,
|
|
dir,
|
|
right,
|
|
up,
|
|
m_fBulletRange,
|
|
m_fBulletDamage,
|
|
m_iBulletLarge,
|
|
m_iBulletKnockback,
|
|
0,
|
|
m_iMeansOfDeath,
|
|
m_vBulletSpread,
|
|
count,
|
|
this,
|
|
iTracerFrequency,
|
|
&iTracerCount,
|
|
m_fBulletThroughWood,
|
|
m_fBulletThroughMetal,
|
|
NULL,
|
|
m_fTracerSpeed
|
|
);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ProjectileGenerator_Gun::TickWeaponAnim()
|
|
{
|
|
return m_fLastShotTime + m_fFireDelay < level.time;
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::TickCycle(Event *ev)
|
|
{
|
|
ProjectileGenerator::TickCycle(ev);
|
|
TickWeaponAnim();
|
|
}
|
|
|
|
void ProjectileGenerator_Gun::Archive(Archiver& arc)
|
|
{
|
|
ProjectileGenerator::Archive(arc);
|
|
|
|
arc.ArchiveFloat(&m_fBulletRange);
|
|
arc.ArchiveFloat(&m_fBulletDamage);
|
|
arc.ArchiveInteger(&m_iBulletCount);
|
|
arc.ArchiveVector(&m_vBulletSpread);
|
|
arc.ArchiveInteger(&m_iTracerFrequency);
|
|
arc.ArchiveInteger(&m_iBulletLarge);
|
|
arc.ArchiveInteger(&m_bFakeBullets);
|
|
arc.ArchiveInteger(&m_iMeansOfDeath);
|
|
arc.ArchiveFloat(&m_fBulletThroughWood);
|
|
arc.ArchiveFloat(&m_fBulletThroughMetal);
|
|
arc.ArchiveFloat(&m_iBulletKnockback);
|
|
arc.ArchiveInteger(&m_iAttackCount);
|
|
arc.ArchiveFloat(&m_fFireDelay);
|
|
arc.ArchiveFloat(&m_fTracerSpeed);
|
|
}
|
|
|
|
/*QUAKED ProjectileGenerator_Heavy (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) LaunchSound x TargetRandom StartOn FlipYaw FlipRoll TargetPlayer HideModel
|
|
|
|
Allows you to launch projectiles without the need for actual AI. Useful for faking large battles.
|
|
Here are the params:
|
|
|
|
ID <nIdNum>
|
|
Model <sModelName> (Defaults to bazooka weapon)
|
|
Projectile <sModelName> (Defaults to bazooka projectile)
|
|
MinDuration <nMinDur=1> (Min burst cycle duration)
|
|
MaxDuration <nMaxDur=3> (Max burst cycle duration)
|
|
Cycles <nCycles=0> (0=infinite)
|
|
MinNumShots <nMinNumShots=1> (Minimum # of shots per cycle)
|
|
MaxNumShots <nMaxNumShots=1> (Maximum # of shots per cycle)
|
|
|
|
MinDelay <nDelay=2> (min amount of time between cycles)
|
|
MaxDelay <nDelay=10> (max amount of time between cycles)
|
|
Accuracy <nAccuracy=10> (accuracy measured in feet. 0-25 feet range)
|
|
|
|
FireOnStartUp (defaults to 1. This flag tells the PG to fire immediately when turned on. Then do its delay from then on.)
|
|
|
|
IsDonut <nIsDonut=1> (indicates to use donut to calculate impact location)
|
|
Arc <nArc=#degrees) (how many degrees does the arc have)
|
|
minDonut <nMinDonut=15> (mindistance from player)
|
|
maxDonut <nMaxDonut=30> (maxdistance from player)
|
|
launchsound <sSoundName> (Defaults to no sound)
|
|
|
|
Here are some useful script commands:
|
|
|
|
$<generatorName> TurnOn
|
|
$<generatorName> TurnOff
|
|
$<generatorName> gettargetentity ( return the entity that is targeted )
|
|
$<generatorName> isturnedon ( is the projectil generator turned on? )
|
|
|
|
******************************************************************************/
|
|
|
|
CLASS_DECLARATION(ProjectileGenerator, ProjectileGenerator_Heavy, "ProjectileGenerator_Heavy") {
|
|
{&EV_Weapon_SetProjectile, &ProjectileGenerator_Heavy::SetProjectileModel},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ProjectileGenerator_Heavy::ProjectileGenerator_Heavy()
|
|
{
|
|
if (LoadingSavegame) {
|
|
return;
|
|
}
|
|
|
|
setModel("models/weapons/bazooka.tik");
|
|
m_sProjectileModel = "models/projectiles/bazookashell.tik";
|
|
}
|
|
|
|
void ProjectileGenerator_Heavy::SetProjectileModel(Event *ev)
|
|
{
|
|
m_sProjectileModel = ev->GetString(1);
|
|
}
|
|
|
|
bool ProjectileGenerator_Heavy::Attack(int count)
|
|
{
|
|
static int NukePlayer = 0;
|
|
Vector dir(0, 0, 1);
|
|
float speed = 500;
|
|
|
|
Vector muzzlePos = origin;
|
|
GetMuzzlePos(muzzlePos);
|
|
|
|
if (m_pCurrent) {
|
|
m_vTargetOrg = GetTargetPos(m_pCurrent);
|
|
|
|
if (m_bIsDonut) {
|
|
Entity *playerTarget = G_FindTarget(this, "player");
|
|
|
|
if (playerTarget) {
|
|
if (playerTarget->takedamage) {
|
|
if (!Q_stricmp(targetname, "artillerykiller")) {
|
|
NukePlayer++;
|
|
}
|
|
} else {
|
|
NukePlayer = 0;
|
|
}
|
|
|
|
if (NukePlayer > 2) {
|
|
m_vTargetOrg = playerTarget->origin;
|
|
muzzlePos = playerTarget->origin;
|
|
muzzlePos[2] += 256;
|
|
NukePlayer = 0;
|
|
} else {
|
|
muzzlePos = m_vTargetOrg;
|
|
muzzlePos[2] += random() * 1000.0 + 500.0;
|
|
}
|
|
} else {
|
|
muzzlePos = m_vTargetOrg;
|
|
muzzlePos[2] += 2000.0;
|
|
}
|
|
}
|
|
|
|
dir = m_vTargetOrg - muzzlePos;
|
|
dir.normalize();
|
|
|
|
Vector newAngles;
|
|
VectorToAngles(dir, newAngles);
|
|
|
|
if (ShouldRotateYaw()) {
|
|
newAngles.setYaw(newAngles.yaw() + 180);
|
|
}
|
|
|
|
if (ShouldRotateRoll()) {
|
|
newAngles.setRoll(newAngles.roll() + 180);
|
|
}
|
|
|
|
setAngles(newAngles);
|
|
} else {
|
|
AngleVectors(angles, dir, NULL, NULL);
|
|
}
|
|
|
|
TryLaunchSound();
|
|
// spawn the projectile
|
|
HeavyAttack(muzzlePos, dir, m_sProjectileModel, speed, this, NULL);
|
|
|
|
return true;
|
|
}
|
|
|
|
void ProjectileGenerator_Heavy::Archive(Archiver& arc)
|
|
{
|
|
ProjectileGenerator::Archive(arc);
|
|
|
|
arc.ArchiveString(&m_sProjectileModel);
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_explosive (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) ReplaceModel
|
|
|
|
Explosive throbbing box. Connect to the object you want to make explode.
|
|
|
|
ReplaceModel - check this if you want the destroy model to replace the model instead of doing
|
|
a model switch.
|
|
|
|
|
|
Parameters:
|
|
Model - name of pulse model (default=items/pulse_explosive.tik")
|
|
UsedModel - name of non-pulse version (default=items/explosive.tik")
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
ActivateSound - name of activation sound (default=plantbomb)
|
|
TickSound - name of 'ticking' sound (default=bombtick)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the stopwatch go (default=5 seconds)
|
|
DestroyModel - name of model to switch target to.
|
|
setthread - name of thread to call when the explosion happens...
|
|
setusethread - name of thread to call when explosive was placed.
|
|
explosionpos - vector of the position the explosion should occur
|
|
|
|
Note:
|
|
* Set stopwatchduration to 0 to prevent the explosion and stopwatch from happening.
|
|
* You may then send the Explode event to this object to make the explosion happen.
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
Event EV_DestroyModel
|
|
(
|
|
"DestroyModel",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"DestroyModel",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_UsedModel
|
|
(
|
|
"UsedModel",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"UsedModel",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ExplosionSound
|
|
(
|
|
"ExplosionSound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"ExplosionSound",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_ActivateSound
|
|
(
|
|
"ActivateSound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"ActivateSound",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_TickSound
|
|
(
|
|
"TickSound",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"TickSound",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetDamage
|
|
(
|
|
"SetDamage",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"Damage",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_Radius
|
|
(
|
|
"Radius",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"Radius",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_StopWatchDuration
|
|
(
|
|
"StopWatchDuration",
|
|
EV_DEFAULT,
|
|
"f",
|
|
"StopWatchDuration",
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetThread
|
|
(
|
|
"setthread",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"thread",
|
|
"Set the thread to execute when this object is used",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetUseThread
|
|
(
|
|
"setusethread",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"thread",
|
|
"Set the thread to execute when this object is used",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_DoExplosion
|
|
(
|
|
"Explode",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Cause the explosion to happen.",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetTriggered
|
|
(
|
|
"triggered",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"triggered",
|
|
"Set the triggered status (0 or 1)",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetExplosionEffect
|
|
(
|
|
"explosioneffect",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"effectModel",
|
|
"Set the explosion effect model",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetExplosionOffset
|
|
(
|
|
"explosionoffset",
|
|
EV_DEFAULT,
|
|
"v",
|
|
"offset",
|
|
"Set the explosion offset",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_BlowUp
|
|
(
|
|
"BlowUp",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(Animate, ThrobbingBox_Explosive, "ThrobbingBox_Explosive") {
|
|
{&EV_Use, &ThrobbingBox_Explosive::OnUse },
|
|
{&EV_BlowUp, &ThrobbingBox_Explosive::OnBlowUp },
|
|
{&EV_DestroyModel, &ThrobbingBox_Explosive::SetDestroyModel },
|
|
{&EV_UsedModel, &ThrobbingBox_Explosive::UsedModel },
|
|
{&EV_ExplosionSound, &ThrobbingBox_Explosive::ExplosionSound },
|
|
{&EV_ActivateSound, &ThrobbingBox_Explosive::ActivateSound },
|
|
{&EV_TickSound, &ThrobbingBox_Explosive::TickSound },
|
|
{&EV_SetDamage, &ThrobbingBox_Explosive::SetDamage },
|
|
{&EV_Radius, &ThrobbingBox_Explosive::SetRadius },
|
|
{&EV_StopWatchDuration, &ThrobbingBox_Explosive::SetStopWatchDuration},
|
|
{&EV_SetThread, &ThrobbingBox_Explosive::SetThread },
|
|
{&EV_SetUseThread, &ThrobbingBox_Explosive::SetUseThread },
|
|
{&EV_DoExplosion, &ThrobbingBox_Explosive::DoExplosion },
|
|
{&EV_SetTriggered, &ThrobbingBox_Explosive::SetTriggered },
|
|
{&EV_SetExplosionEffect, &ThrobbingBox_Explosive::SetExplosionEffect },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ThrobbingBox_Explosive::ThrobbingBox_Explosive()
|
|
{
|
|
if (LoadingSavegame) {
|
|
return;
|
|
}
|
|
|
|
setModel("items\\\\pulse_explosive.tik");
|
|
m_sUsedModel = "items/explosive.tik";
|
|
m_sSound = "explode_flak88";
|
|
m_sActivateSound = "plantbomb";
|
|
m_sTickSound = "bombtick";
|
|
|
|
m_bUsed = false;
|
|
m_fExplosionDamage = 300;
|
|
m_fRadius = 300;
|
|
m_fStopwatchDuration = 5;
|
|
|
|
m_sEffect = "emitters/mortar_higgins.tik";
|
|
m_vOffset = Vector(0, 0, 0);
|
|
}
|
|
|
|
bool ThrobbingBox_Explosive::ShouldDoExplosion()
|
|
{
|
|
return m_fStopwatchDuration;
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetExplosionOffset(Event *ev)
|
|
{
|
|
m_vOffset = ev->GetVector(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetExplosionEffect(Event *ev)
|
|
{
|
|
m_sEffect = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetTriggered(Event *ev)
|
|
{
|
|
m_bUsed = ev->GetInteger(1) ? true : false;
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::DoExplosion(Event *ev)
|
|
{
|
|
SpawnArgs sp;
|
|
ScriptModel *spawned;
|
|
|
|
sp.setArg("model", m_sEffect);
|
|
sp.setArg("origin", va("%f %f %f", origin.x, origin.y, origin.z));
|
|
sp.setArg("classname", "ScriptModel");
|
|
|
|
if (target.length()) {
|
|
SimpleEntity *targetEnt = G_FindTarget(NULL, target.c_str());
|
|
if (targetEnt) {
|
|
sp.setArg("origin", va("%f %f %f", targetEnt->origin.x, targetEnt->origin.y, targetEnt->origin.z));
|
|
}
|
|
}
|
|
|
|
spawned = static_cast<ScriptModel *>(sp.Spawn());
|
|
if (spawned) {
|
|
spawned->NewAnim("start");
|
|
spawned->setSolidType(SOLID_NOT);
|
|
}
|
|
|
|
RadiusDamage(origin + Vector(0, 0, 128), this, this, m_fExplosionDamage, this, MOD_EXPLOSION, m_fRadius);
|
|
|
|
Sound(m_sSound, CHAN_BODY);
|
|
|
|
m_thread.Execute(this);
|
|
PostEvent(EV_Remove, 0);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetUseThread(Event *ev)
|
|
{
|
|
if (ev->IsFromScript()) {
|
|
m_useThread.SetThread(ev->GetValue(1));
|
|
} else {
|
|
m_useThread.Set(ev->GetString(1));
|
|
}
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetThread(Event *ev)
|
|
{
|
|
if (ev->IsFromScript()) {
|
|
m_thread.SetThread(ev->GetValue(1));
|
|
} else {
|
|
m_thread.Set(ev->GetString(1));
|
|
}
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetStopWatchDuration(Event *ev)
|
|
{
|
|
m_fStopwatchDuration = ev->GetFloat(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetRadius(Event *ev)
|
|
{
|
|
m_fRadius = ev->GetFloat(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetDamage(Event *ev)
|
|
{
|
|
m_fExplosionDamage = ev->GetFloat(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::TickSound(Event *ev)
|
|
{
|
|
m_sTickSound = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::ActivateSound(Event *ev)
|
|
{
|
|
m_sActivateSound = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::ExplosionSound(Event *ev)
|
|
{
|
|
m_sSound = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::UsedModel(Event *ev)
|
|
{
|
|
m_sUsedModel = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::SetDestroyModel(Event *ev)
|
|
{
|
|
m_sDestroyedModel = ev->GetString(1);
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::OnBlowUp(Event *ev)
|
|
{
|
|
Player *player;
|
|
Entity *targetEnt;
|
|
ScriptModel *mdl;
|
|
|
|
StopLoopSound();
|
|
setSolidType(SOLID_NOT);
|
|
|
|
player = static_cast<Player *>(G_FindTarget(this, "player"));
|
|
if (player) {
|
|
// clear the player's stopwatch
|
|
player->SetStopwatch(0);
|
|
}
|
|
|
|
if (target.length() && (targetEnt = static_cast<Entity *>(G_FindTarget(NULL, target.c_str())))
|
|
&& m_sDestroyedModel.length()) {
|
|
if (spawnflags & TBE_SPAWNFLAG_DESTROYED_MODEL) {
|
|
SpawnArgs sp;
|
|
|
|
sp.setArg("model", m_sDestroyedModel.c_str());
|
|
sp.setArg("origin", va("%f %f %f", targetEnt->origin.x, targetEnt->origin.y, targetEnt->origin.z));
|
|
sp.setArg("angles", va("%f %f %f", targetEnt->angles.x, targetEnt->angles.y, targetEnt->angles.z));
|
|
sp.setArg("classname", "ScriptModel");
|
|
|
|
mdl = static_cast<ScriptModel *>(sp.Spawn());
|
|
if (mdl) {
|
|
mdl->NewAnim("start");
|
|
mdl->setSolidType(static_cast<solid_t>(targetEnt->getSolidType()));
|
|
}
|
|
|
|
if (targetEnt->IsSubclassOfVehicle()) {
|
|
Vehicle *veh = static_cast<Vehicle *>(targetEnt);
|
|
Entity *ent;
|
|
int i;
|
|
|
|
// remove all turrets
|
|
for (i = 0; i < MAX_TURRETS; i++) {
|
|
ent = veh->QueryTurretSlotEntity(i);
|
|
if (ent) {
|
|
ent->PostEvent(EV_Remove, 0);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_PASSENGERS; i++) {
|
|
ent = veh->QueryPassengerSlotEntity(i);
|
|
if (ent) {
|
|
ent->Damage(this, this, ent->health * 2.f, vec_zero, vec_zero, vec_zero, 50, 0, MOD_VEHICLE);
|
|
}
|
|
}
|
|
|
|
ent = veh->QueryDriverSlotEntity(0);
|
|
if (ent) {
|
|
ent->takedamage = DAMAGE_YES;
|
|
ent->Damage(this, this, ent->health * 2.f, vec_zero, vec_zero, vec_zero, 50, 0, MOD_VEHICLE);
|
|
}
|
|
}
|
|
|
|
targetEnt->PostEvent(EV_Remove, 0);
|
|
} else {
|
|
targetEnt->setModel(m_sDestroyedModel.c_str());
|
|
}
|
|
}
|
|
|
|
if (ShouldDoExplosion()) {
|
|
DoExplosion(NULL);
|
|
}
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::OnUse(Event *ev)
|
|
{
|
|
if (m_bUsed) {
|
|
// don't use more than once
|
|
return;
|
|
}
|
|
|
|
if (edict->s.renderfx & RF_DONTDRAW) {
|
|
// ignore if invisible
|
|
return;
|
|
}
|
|
|
|
m_bUsed = true;
|
|
|
|
setModel(m_sUsedModel);
|
|
|
|
if (m_fStopwatchDuration > 0) {
|
|
Player *player = static_cast<Player *>(G_FindTarget(this, "player"));
|
|
player->SetStopwatch(m_fStopwatchDuration, SWT_NORMAL);
|
|
LoopSound(m_sTickSound);
|
|
}
|
|
|
|
// Play the activation sound
|
|
Sound(m_sActivateSound, CHAN_BODY);
|
|
|
|
Unregister(STRING_TRIGGER);
|
|
m_useThread.Execute(this);
|
|
|
|
if (m_fStopwatchDuration > 0) {
|
|
PostEvent(EV_BlowUp, m_fStopwatchDuration);
|
|
}
|
|
}
|
|
|
|
void ThrobbingBox_Explosive::Archive(Archiver& arc)
|
|
{
|
|
Animate::Archive(arc);
|
|
|
|
arc.ArchiveString(&m_sUsedModel);
|
|
arc.ArchiveString(&m_sSound);
|
|
arc.ArchiveBool(&m_bUsed);
|
|
arc.ArchiveFloat(&m_fExplosionDamage);
|
|
arc.ArchiveFloat(&m_fRadius);
|
|
arc.ArchiveFloat(&m_fStopwatchDuration);
|
|
arc.ArchiveString(&m_sActivateSound);
|
|
arc.ArchiveString(&m_sTickSound);
|
|
arc.ArchiveString(&m_sDestroyedModel);
|
|
arc.ArchiveString(&m_sEffect);
|
|
arc.ArchiveVector(&m_vOffset);
|
|
m_thread.Archive(arc);
|
|
m_useThread.Archive(arc);
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_ExplodePlayerFlak88 (1.0 0.0 1.0) (-12 -12 -12) (12 12 12)
|
|
|
|
Explosive throbbing box. Connect to the object you want to make explode.
|
|
|
|
|
|
Parameters:
|
|
Model - name of pulse model (default=items/pulse_explosive.tik")
|
|
UsedModel - name of non-pulse version (default=items/explosive.tik")
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
ActivateSound - name of activation sound (default=plantbomb)
|
|
TickSound - name of 'ticking' sound (default=bombtick)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the stopwatch go (default=5 seconds)
|
|
setthread - name of thread to call when the explosion happens...
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_ExplodePlayerFlak88, "ThrobbingBox_ExplodePlayerFlak88") {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
ThrobbingBox_ExplodePlayerFlak88::ThrobbingBox_ExplodePlayerFlak88()
|
|
{
|
|
spawnflags |= TBE_SPAWNFLAG_DESTROYED_MODEL;
|
|
m_sDestroyedModel = "statweapons/flak88_d.tik";
|
|
m_sEffect = "fx/demodamage_flak88.tik";
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_ExplodeFlak88 (1.0 0.0 1.0) (-12 -12 -12) (12 12 12)
|
|
|
|
Explosive throbbing box. Connect to the object you want to make explode.
|
|
|
|
Parameters:
|
|
Model - name of pulse model (default=items/pulse_explosive.tik")
|
|
UsedModel - name of non-pulse version (default=items/explosive.tik")
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
ActivateSound - name of activation sound (default=plantbomb)
|
|
TickSound - name of 'ticking' sound (default=bombtick)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the stopwatch go (default=5 seconds)
|
|
setthread - name of thread to call when the explosion happens...
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_ExplodeFlak88, "ThrobbingBox_ExplodeFlak88") {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
ThrobbingBox_ExplodeFlak88::ThrobbingBox_ExplodeFlak88()
|
|
{
|
|
m_sDestroyedModel = "statweapons/flak88_d.tik";
|
|
m_sEffect = "fx/demodamage_flak88.tik";
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_ExplodeNebelwerfer (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) ReplaceModel
|
|
|
|
Explosive throbbing box. Connect to the object you want to make explode.
|
|
|
|
Parameters:
|
|
Model - name of pulse model (default=items/pulse_explosive.tik")
|
|
UsedModel - name of non-pulse version (default=items/explosive.tik")
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
ActivateSound - name of activation sound (default=plantbomb)
|
|
TickSound - name of 'ticking' sound (default=bombtick)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the stopwatch go (default=5 seconds)
|
|
setthread - name of thread to call when the explosion happens...
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_ExplodeNebelwerfer, "ThrobbingBox_ExplodeNebelwerfer") {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
ThrobbingBox_ExplodeNebelwerfer::ThrobbingBox_ExplodeNebelwerfer()
|
|
{
|
|
m_sDestroyedModel = "statweapons/nebelwerfer_d.tik";
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_ExplodePlayerNebelwerfer (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) ReplaceModel
|
|
|
|
Explosive throbbing box. Connect to the object you want to make explode.
|
|
|
|
Parameters:
|
|
Model - name of pulse model (default=items/pulse_explosive.tik")
|
|
UsedModel - name of non-pulse version (default=items/explosive.tik")
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
ActivateSound - name of activation sound (default=plantbomb)
|
|
TickSound - name of 'ticking' sound (default=bombtick)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the stopwatch go (default=5 seconds)
|
|
setthread - name of thread to call when the explosion happens...
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_ExplodePlayerNebelwerfer, "ThrobbingBox_ExplodePlayerNebelwerfer") {
|
|
{NULL, NULL}
|
|
};
|
|
|
|
ThrobbingBox_ExplodePlayerNebelwerfer::ThrobbingBox_ExplodePlayerNebelwerfer()
|
|
{
|
|
spawnflags |= TBE_SPAWNFLAG_DESTROYED_MODEL;
|
|
m_sDestroyedModel = "statweapons/nebelwerfer_d.tik";
|
|
}
|
|
|
|
/*QUAKED ThrobbingBox_Stickybomb (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) ReplaceModel WetFuse
|
|
|
|
Stickybomb throbbing box. Connect to the object you want to make explode.
|
|
When WetFuse is selected, the bomb will fizzle out and can only be destroyed by shooting it.
|
|
|
|
Parameters:
|
|
ExplosionSound - name of explosion sound (default=explode_flak88)
|
|
Damage - amount of damage to do (default=300)
|
|
radius - radius to do the damage (default=300)
|
|
stopwatchduration - how long should the fuse go (default=5 seconds)
|
|
setthread - name of thread to call when the explosion happens...
|
|
DestroyModel - name of model to switch target to.
|
|
setusethread - name of thread to call when stickybomb is placed.
|
|
|
|
---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
Event EV_StickyBombWet("stickybombwet", EV_DEFAULT, NULL, NULL, NULL);
|
|
|
|
CLASS_DECLARATION(ThrobbingBox_Explosive, ThrobbingBox_Stickybomb, "ThrobbingBox_Stickybomb") {
|
|
{&EV_Damage, &ThrobbingBox_Stickybomb::OnBlowUp },
|
|
{&EV_Use, &ThrobbingBox_Stickybomb::OnStickyBombUse},
|
|
{&EV_StickyBombWet, &ThrobbingBox_Stickybomb::OnStickyBombWet},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
ThrobbingBox_Stickybomb::ThrobbingBox_Stickybomb()
|
|
{
|
|
if (LoadingSavegame) {
|
|
return;
|
|
}
|
|
|
|
setModel("items/pulse_stickybomb.tik");
|
|
m_sUsedModel = "items/stickybomb.tik";
|
|
m_sSound = "explode_flak88";
|
|
m_sActivateSound = "stickybomb_plant";
|
|
m_sTickSound = "stickybomb_fuse";
|
|
|
|
health = 10;
|
|
m_fStopwatchStartTime = 0;
|
|
|
|
setSolidType(SOLID_BBOX);
|
|
takedamage = DAMAGE_NO;
|
|
setContents(CONTENTS_WEAPONCLIP);
|
|
}
|
|
|
|
void ThrobbingBox_Stickybomb::OnStickyBombWet(Event *ev)
|
|
{
|
|
Player *player;
|
|
|
|
CancelEventsOfType(EV_BlowUp);
|
|
NewAnim("idle_fuse_wet");
|
|
StopLoopSound();
|
|
Sound("stickybomb_fuse_out", CHAN_BODY);
|
|
|
|
player = static_cast<Player *>(G_FindTarget(this, "player"));
|
|
player->SetStopwatch(0, SWT_NORMAL);
|
|
player->SetStopwatch(m_fStopwatchDuration - (level.svsFloatTime - m_fStopwatchStartTime), SWT_FUSE_WET);
|
|
}
|
|
|
|
void ThrobbingBox_Stickybomb::OnStickyBombUse(Event *ev)
|
|
{
|
|
if (m_bUsed) {
|
|
return;
|
|
}
|
|
|
|
setSolidType(SOLID_BBOX);
|
|
setContents(CONTENTS_WEAPONCLIP);
|
|
takedamage = DAMAGE_YES;
|
|
m_bUsed = true;
|
|
|
|
setModel(m_sUsedModel);
|
|
|
|
if (m_fStopwatchDuration > 0) {
|
|
Player *player = static_cast<Player *>(G_FindTarget(this, "player"));
|
|
player->SetStopwatch(m_fStopwatchDuration, SWT_FUSE);
|
|
LoopSound(m_sTickSound);
|
|
m_fStopwatchStartTime = level.svsFloatTime;
|
|
}
|
|
|
|
// Play the activation sound
|
|
Sound(m_sActivateSound, CHAN_BODY);
|
|
|
|
Unregister(STRING_TRIGGER);
|
|
m_useThread.Execute(this);
|
|
PostEvent(EV_BlowUp, m_fStopwatchDuration);
|
|
|
|
if (spawnflags & TBE_SPAWNFLAG_MAKE_WET) {
|
|
PostEvent(EV_StickyBombWet, G_Random(m_fStopwatchDuration / 2.0) + m_fStopwatchDuration / 4.0);
|
|
}
|
|
|
|
NewAnim("idle_fuse_lit");
|
|
}
|
|
|
|
void ThrobbingBox_Stickybomb::Archive(Archiver& arc)
|
|
{
|
|
ThrobbingBox_Explosive::Archive(arc);
|
|
|
|
arc.ArchiveFloat(&m_fStopwatchStartTime);
|
|
}
|
|
|
|
/*QUAKED func_objective (1.0 0.0 1.0) (-12 -12 -12) (12 12 12) StartOn
|
|
|
|
object used to simplify placing objectives. You may optionally connect this object to the
|
|
target you want to use for the compass position....
|
|
|
|
Checkboxes:
|
|
StartOn - check this if you want this objective to be displayed when the level first loads
|
|
|
|
Parameters:
|
|
|
|
ObjectiveNbr <nObjNbr=0>
|
|
Text <sText>
|
|
|
|
Events:
|
|
TurnOn
|
|
TurnOff
|
|
Complete
|
|
Text <sNewText>
|
|
SetCurrent
|
|
|
|
//---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
Event EV_Complete
|
|
(
|
|
"Complete",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Complete this objective.",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_SetCurrent
|
|
(
|
|
"SetCurrent",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"Set this objective as current.",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_SetText
|
|
(
|
|
"Text",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"text",
|
|
"Set current text.",
|
|
EV_NORMAL
|
|
);
|
|
|
|
Event EV_SetObjectiveNbr
|
|
(
|
|
"ObjectiveNbr",
|
|
EV_DEFAULT,
|
|
"i",
|
|
"index",
|
|
"Sets the objective number.",
|
|
EV_NORMAL
|
|
);
|
|
|
|
CLASS_DECLARATION(Entity, Objective, "func_objective") {
|
|
{&EV_TurnOn, &Objective::TurnOn },
|
|
{&EV_TurnOff, &Objective::TurnOff },
|
|
{&EV_Complete, &Objective::Complete },
|
|
{&EV_SetCurrent, &Objective::SetCurrent },
|
|
{&EV_SetText, &Objective::SetText },
|
|
{&EV_SetObjectiveNbr, &Objective::SetObjectiveNbr},
|
|
{&EV_Activate, &Objective::SetCurrent },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
Objective::Objective()
|
|
{
|
|
m_iObjectiveIndex = 0;
|
|
|
|
if (LoadingSavegame) {
|
|
return;
|
|
}
|
|
|
|
if (spawnflags & OBJECTIVE_SPAWNFLAG_TURN_ON) {
|
|
PostEvent(EV_TurnOn, 0.1f);
|
|
}
|
|
}
|
|
|
|
void Objective::Archive(Archiver& arc)
|
|
{
|
|
Entity::Archive(arc);
|
|
|
|
arc.ArchiveString(&m_sText);
|
|
arc.ArchiveInteger(&m_iObjectiveIndex);
|
|
}
|
|
|
|
void Objective::TurnOn(Event *ev)
|
|
{
|
|
ScriptThread::AddObjective(m_iObjectiveIndex, OBJ_STATUS_CURRENT, m_sText, GetOrigin());
|
|
}
|
|
|
|
void Objective::TurnOff(Event *ev)
|
|
{
|
|
ScriptThread::AddObjective(m_iObjectiveIndex, OBJ_STATUS_HIDDEN, m_sText, GetOrigin());
|
|
}
|
|
|
|
void Objective::Complete(Event *ev)
|
|
{
|
|
ScriptThread::AddObjective(m_iObjectiveIndex, OBJ_STATUS_COMPLETED, m_sText, GetOrigin());
|
|
}
|
|
|
|
void Objective::SetCurrent(Event *ev)
|
|
{
|
|
ScriptThread::SetCurrentObjective(m_iObjectiveIndex, TEAM_NONE);
|
|
}
|
|
|
|
Vector Objective::GetOrigin() const
|
|
{
|
|
if (target.c_str()) {
|
|
SimpleEntity *targetEnt;
|
|
|
|
targetEnt = G_FindTarget(NULL, target.c_str());
|
|
|
|
if (targetEnt) {
|
|
return targetEnt->origin;
|
|
}
|
|
}
|
|
|
|
return origin;
|
|
}
|
|
|
|
void Objective::SetObjectiveNbr(Event *ev)
|
|
{
|
|
m_iObjectiveIndex = ev->GetInteger(1);
|
|
}
|
|
|
|
void Objective::SetText(Event *ev)
|
|
{
|
|
m_sText = ev->GetString(1);
|
|
}
|
|
|
|
int Objective::GetObjectiveIndex() const
|
|
{
|
|
return m_iObjectiveIndex;
|
|
}
|
|
|
|
/*QUAKED func_fencepost (0 1 0) ?
|
|
fencepost that can be blown up
|
|
"health" how much health the fence post should have (default 50)
|
|
//---------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
CLASS_DECLARATION(Entity, FencePost, "func_fencepost") {
|
|
{&EV_Killed, &FencePost::Killed},
|
|
{NULL, NULL }
|
|
};
|
|
|
|
FencePost::FencePost()
|
|
{
|
|
max_health = 20;
|
|
health = 20;
|
|
damage_type = MOD_AAGUN;
|
|
|
|
if (!LoadingSavegame) {
|
|
PostEvent(EV_BecomeSolid, EV_POSTSPAWN);
|
|
}
|
|
|
|
takedamage = DAMAGE_YES;
|
|
}
|
|
|
|
void FencePost::Killed(Event *ev)
|
|
{
|
|
Vector vMins, vMaxs;
|
|
Vector vStart, vEnd;
|
|
Vector vCenter;
|
|
float fHalf;
|
|
|
|
vCenter = mins - maxs;
|
|
vCenter *= 0.5;
|
|
|
|
if (size.x > size.y) {
|
|
if (size.x > size.z) {
|
|
if (size.y > size.z) {
|
|
fHalf = size.y / 2.f;
|
|
} else {
|
|
fHalf = size.z / 2.f;
|
|
}
|
|
|
|
vMins[0] = mins[0];
|
|
vMaxs[0] = maxs[0];
|
|
vMins[1] = vCenter[1];
|
|
vMaxs[1] = vCenter[1];
|
|
vMins[2] = vCenter[2];
|
|
vMaxs[2] = vCenter[2];
|
|
} else {
|
|
fHalf = size.x / 2.f;
|
|
|
|
vMins[2] = mins[2];
|
|
vMaxs[2] = maxs[2];
|
|
vMins[1] = vCenter[1];
|
|
vMaxs[1] = vCenter[1];
|
|
vMins[0] = vCenter[0];
|
|
vMaxs[0] = vCenter[0];
|
|
}
|
|
} else {
|
|
if (size.y > size.z) {
|
|
if (size.x > size.z) {
|
|
fHalf = size.x / 2.f;
|
|
} else {
|
|
fHalf = size.z / 2.f;
|
|
}
|
|
|
|
vMins[1] = mins[1];
|
|
vMaxs[1] = maxs[1];
|
|
vMins[0] = vCenter[0];
|
|
vMaxs[0] = vCenter[0];
|
|
vMins[2] = vCenter[2];
|
|
vMaxs[2] = vCenter[2];
|
|
} else {
|
|
fHalf = size.y / 2.f;
|
|
|
|
vMins[2] = mins[2];
|
|
vMaxs[2] = maxs[2];
|
|
vMins[1] = vCenter[1];
|
|
vMaxs[1] = vCenter[1];
|
|
vMins[0] = vCenter[0];
|
|
vMaxs[0] = vCenter[0];
|
|
}
|
|
}
|
|
|
|
MatrixTransformVector(vMins, orientation, vStart);
|
|
MatrixTransformVector(vMaxs, orientation, vEnd);
|
|
|
|
vStart += origin;
|
|
vEnd += origin;
|
|
|
|
if (fHalf > 255) {
|
|
fHalf = 255;
|
|
}
|
|
|
|
gi.SetBroadcastVisible(vStart, vEnd);
|
|
gi.MSG_StartCGM(CGM_FENCEPOST);
|
|
gi.MSG_WriteCoord(vStart[0]);
|
|
gi.MSG_WriteCoord(vStart[1]);
|
|
gi.MSG_WriteCoord(vStart[2]);
|
|
gi.MSG_WriteCoord(vEnd[0]);
|
|
gi.MSG_WriteCoord(vEnd[1]);
|
|
gi.MSG_WriteCoord(vEnd[2]);
|
|
gi.MSG_WriteByte((int)fHalf);
|
|
gi.MSG_WriteByte(0);
|
|
gi.MSG_EndCGM();
|
|
|
|
deadflag = DEAD_DEAD;
|
|
|
|
PostEvent(EV_Remove, 0);
|
|
}
|
|
|
|
Event EV_SetEnemyName
|
|
(
|
|
"enemyname",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"enemyname",
|
|
"",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_SetEnemyName2
|
|
(
|
|
"enemyname",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"enemyname",
|
|
"",
|
|
EV_SETTER
|
|
);
|
|
Event EV_GetEnemyName
|
|
(
|
|
"enemyname",
|
|
EV_DEFAULT,
|
|
"s",
|
|
"enemyname",
|
|
"",
|
|
EV_GETTER
|
|
);
|
|
Event EV_Sentient_GetDontDropWeapons
|
|
(
|
|
"dontdropweapons",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"dontdropweapons getter",
|
|
EV_GETTER
|
|
);
|
|
Event EV_SetDontDropHealth
|
|
(
|
|
"dontdrophealth",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"dontdrophealth setter",
|
|
EV_NORMAL
|
|
);
|
|
Event EV_GetDontDropHealth
|
|
(
|
|
"dontdrophealth",
|
|
EV_DEFAULT,
|
|
NULL,
|
|
NULL,
|
|
"dontdrophealth getter",
|
|
EV_GETTER
|
|
);
|
|
|
|
CLASS_DECLARATION(SimpleArchivedEntity, AISpawnPoint, "info_aispawnpoint") {
|
|
{&EV_Model, &AISpawnPoint::SetModel },
|
|
{&EV_GetModel, &AISpawnPoint::GetModel },
|
|
{&EV_SetHealth2, &AISpawnPoint::SetHealth },
|
|
{&EV_Entity_GetHealth, &AISpawnPoint::GetHealth },
|
|
{&EV_SetEnemyName, &AISpawnPoint::SetEnemyName },
|
|
{&EV_SetEnemyName2, &AISpawnPoint::SetEnemyName },
|
|
{&EV_GetEnemyName, &AISpawnPoint::GetEnemyName },
|
|
{&EV_Actor_SetAccuracy, &AISpawnPoint::SetAccuracy },
|
|
{&EV_Actor_GetAccuracy, &AISpawnPoint::GetAccuracy },
|
|
{&EV_Actor_SetAmmoGrenade, &AISpawnPoint::SetAmmoGrenade },
|
|
{&EV_Actor_GetAmmoGrenade, &AISpawnPoint::GetAmmoGrenade },
|
|
{&EV_Actor_SetBalconyHeight, &AISpawnPoint::SetBalconyHeight },
|
|
{&EV_Actor_GetBalconyHeight, &AISpawnPoint::GetBalconyHeight },
|
|
{&EV_Actor_SetDisguiseLevel, &AISpawnPoint::SetDisguiseLevel },
|
|
{&EV_Actor_GetDisguiseLevel, &AISpawnPoint::GetDisguiseLevel },
|
|
{&EV_Actor_SetDisguisePeriod2, &AISpawnPoint::SetDisguisePeriod },
|
|
{&EV_Actor_GetDisguisePeriod, &AISpawnPoint::GetDisguisePeriod },
|
|
{&EV_Actor_SetDisguiseRange2, &AISpawnPoint::SetDisguiseRange },
|
|
{&EV_Actor_GetDisguiseRange, &AISpawnPoint::GetDisguiseRange },
|
|
{&EV_Actor_SetEnemyShareRange2, &AISpawnPoint::SetEnemyShareRange },
|
|
{&EV_Actor_GetEnemyShareRange, &AISpawnPoint::GetEnemyShareRange },
|
|
{&EV_Actor_GetFixedLeash, &AISpawnPoint::GetFixedLeash },
|
|
{&EV_Actor_SetFixedLeash2, &AISpawnPoint::SetFixedLeash },
|
|
{&EV_Actor_SetGrenadeAwareness, &AISpawnPoint::SetGrenadeAwareness },
|
|
{&EV_Actor_GetGrenadeAwareness, &AISpawnPoint::GetGrenadeAwareness },
|
|
{&EV_Actor_SetGun, &AISpawnPoint::SetGun },
|
|
{&EV_Actor_GetGun, &AISpawnPoint::GetGun },
|
|
{&EV_Actor_GetMaxNoticeTimeScale, &AISpawnPoint::GetMaxNoticeTimeScale},
|
|
{&EV_Actor_SetMaxNoticeTimeScale, &AISpawnPoint::SetMaxNoticeTimeScale},
|
|
{&EV_Actor_GetSoundAwareness, &AISpawnPoint::GetSoundAwareness },
|
|
{&EV_Actor_SetSoundAwareness, &AISpawnPoint::SetSoundAwareness },
|
|
{&EV_Actor_SetTypeAttack, &AISpawnPoint::SetTypeAttack },
|
|
{&EV_Actor_GetTypeAttack, &AISpawnPoint::GetTypeAttack },
|
|
{&EV_Actor_SetTypeDisguise, &AISpawnPoint::SetTypeDisguise },
|
|
{&EV_Actor_GetTypeDisguise, &AISpawnPoint::GetTypeDisguise },
|
|
{&EV_Actor_SetTypeGrenade, &AISpawnPoint::SetTypeGrenade },
|
|
{&EV_Actor_GetTypeGrenade, &AISpawnPoint::GetTypeGrenade },
|
|
{&EV_Actor_SetTypeIdle, &AISpawnPoint::SetTypeIdle },
|
|
{&EV_Actor_GetTypeIdle, &AISpawnPoint::GetTypeIdle },
|
|
{&EV_Actor_SetPatrolWaitTrigger, &AISpawnPoint::SetPatrolWaitTrigger },
|
|
{&EV_Actor_GetPatrolWaitTrigger, &AISpawnPoint::GetPatrolWaitTrigger },
|
|
{&EV_Actor_SetHearing, &AISpawnPoint::SetHearing },
|
|
{&EV_Actor_GetHearing, &AISpawnPoint::GetHearing },
|
|
{&EV_Actor_GetSight, &AISpawnPoint::GetSight },
|
|
{&EV_Actor_SetSight2, &AISpawnPoint::SetSight },
|
|
{&EV_Actor_SetFov, &AISpawnPoint::SetFov },
|
|
{&EV_Actor_GetFov, &AISpawnPoint::GetFov },
|
|
{&EV_Actor_SetLeash2, &AISpawnPoint::SetLeash },
|
|
{&EV_Actor_GetLeash, &AISpawnPoint::GetLeash },
|
|
{&EV_Actor_SetMinDistance, &AISpawnPoint::SetMinDistance },
|
|
{&EV_Actor_GetMinDistance, &AISpawnPoint::GetMinDistance },
|
|
{&EV_Actor_SetMaxDistance, &AISpawnPoint::SetMaxDistance },
|
|
{&EV_Actor_GetMaxDistance, &AISpawnPoint::GetMaxDistance },
|
|
{&EV_Actor_SetInterval2, &AISpawnPoint::SetInterval },
|
|
{&EV_Actor_GetInterval, &AISpawnPoint::GetInterval },
|
|
{&EV_Sentient_DontDropWeapons, &AISpawnPoint::SetDontDropWeapons },
|
|
{&EV_Sentient_GetDontDropWeapons, &AISpawnPoint::GetDontDropWeapons },
|
|
{&EV_SetDontDropHealth, &AISpawnPoint::SetDontDropHealth },
|
|
{&EV_GetDontDropHealth, &AISpawnPoint::GetDontDropHealth },
|
|
{&EV_Actor_GetFavoriteEnemy, &AISpawnPoint::GetFavoriteEnemy },
|
|
{&EV_Actor_SetFavoriteEnemy2, &AISpawnPoint::SetFavoriteEnemy },
|
|
{&EV_Actor_SetNoSurprise2, &AISpawnPoint::SetNoSurprise },
|
|
{&EV_Actor_GetNoSurprise, &AISpawnPoint::GetNoSurprise },
|
|
{&EV_Actor_SetPatrolPath, &AISpawnPoint::SetPatrolPath },
|
|
{&EV_Actor_GetPatrolPath, &AISpawnPoint::GetPatrolPath },
|
|
{&EV_Actor_SetTurret, &AISpawnPoint::SetTurret },
|
|
{&EV_Actor_GetTurret, &AISpawnPoint::GetTurret },
|
|
{&EV_Actor_SetAlarmNode, &AISpawnPoint::SetAlarmNode },
|
|
{&EV_Actor_GetAlarmNode, &AISpawnPoint::GetAlarmNode },
|
|
{&EV_Actor_SetWeapon, &AISpawnPoint::SetWeapon },
|
|
{&EV_Actor_GetWeapon, &AISpawnPoint::GetWeapon },
|
|
{&EV_SetTarget, &AISpawnPoint::SetTarget },
|
|
{&EV_GetTarget, &AISpawnPoint::GetTarget },
|
|
{&EV_Actor_SetVoiceType, &AISpawnPoint::SetVoiceType },
|
|
{&EV_Actor_GetVoiceType, &AISpawnPoint::GetVoiceType },
|
|
{&EV_Sentient_ForceDropWeapon, &AISpawnPoint::SetForceDropWeapon },
|
|
{&EV_Sentient_GetForceDropWeapon, &AISpawnPoint::GetForceDropWeapon },
|
|
{&EV_Sentient_ForceDropHealth, &AISpawnPoint::SetForceDropHealth },
|
|
{&EV_Sentient_GetForceDropHealth, &AISpawnPoint::GetForceDropHealth },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
AISpawnPoint::AISpawnPoint()
|
|
{
|
|
m_iHealth = 100;
|
|
|
|
m_iAccuracy = 20;
|
|
m_iAmmoGrenade = 0;
|
|
m_iBalconyHeight = 128;
|
|
|
|
m_iDisguiseLevel = 1;
|
|
m_fDisguisePeriod = 30000;
|
|
m_fDisguiseRange = 256;
|
|
|
|
m_fEnemyShareRange = 0;
|
|
m_fFixedLeash = 0.0;
|
|
|
|
m_fGrenadeAwareness = 20.0;
|
|
m_fMaxNoticeTimeScale = 1;
|
|
m_fSoundAwareness = 100;
|
|
|
|
m_bPatrolWaitTrigger = false;
|
|
|
|
m_fHearing = 2048;
|
|
m_fSight = world->m_fAIVisionDistance;
|
|
m_fFov = 90;
|
|
m_fLeash = 512;
|
|
m_fMinDist = 128.0;
|
|
m_fMaxDist = 1024;
|
|
m_fInterval = 128.0;
|
|
|
|
m_bDontDropWeapons = false;
|
|
m_bDontDropHealth = false;
|
|
m_bNoSurprise = false;
|
|
m_bForceDropWeapon = false;
|
|
m_bForceDropHealth = false;
|
|
}
|
|
|
|
void AISpawnPoint::GetForceDropHealth(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bForceDropHealth);
|
|
}
|
|
|
|
void AISpawnPoint::SetForceDropHealth(Event *ev)
|
|
{
|
|
// Fixed in OPM
|
|
// This does look like a mistake on original mohaab (2.30 and 2.40)
|
|
// it should be m_bForceDropHealth.
|
|
// That's the reason why AI often don't drop weapons
|
|
//m_bForceDropWeapon = ev->GetBoolean(1);
|
|
m_bForceDropHealth = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetForceDropWeapon(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bForceDropWeapon);
|
|
}
|
|
|
|
void AISpawnPoint::SetForceDropWeapon(Event *ev)
|
|
{
|
|
m_bForceDropWeapon = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetVoiceType(Event *ev)
|
|
{
|
|
ev->AddString(m_sVoiceType);
|
|
}
|
|
|
|
void AISpawnPoint::SetVoiceType(Event *ev)
|
|
{
|
|
m_sVoiceType = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTarget(Event *ev)
|
|
{
|
|
ev->AddString(m_sTarget);
|
|
}
|
|
|
|
void AISpawnPoint::SetTarget(Event *ev)
|
|
{
|
|
m_sTarget = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetWeapon(Event *ev)
|
|
{
|
|
ev->AddString(m_sWeapon);
|
|
}
|
|
|
|
void AISpawnPoint::SetWeapon(Event *ev)
|
|
{
|
|
m_sWeapon = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetAlarmNode(Event *ev)
|
|
{
|
|
ev->AddString(m_sAlarmNode);
|
|
}
|
|
|
|
void AISpawnPoint::SetAlarmNode(Event *ev)
|
|
{
|
|
m_sAlarmNode = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTurret(Event *ev)
|
|
{
|
|
ev->AddString(m_sTurret);
|
|
}
|
|
|
|
void AISpawnPoint::SetTurret(Event *ev)
|
|
{
|
|
m_sTurret = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetPatrolPath(Event *ev)
|
|
{
|
|
ev->AddString(m_sPatrolPath);
|
|
}
|
|
|
|
void AISpawnPoint::SetPatrolPath(Event *ev)
|
|
{
|
|
m_sPatrolPath = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetNoSurprise(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bNoSurprise);
|
|
}
|
|
|
|
void AISpawnPoint::SetNoSurprise(Event *ev)
|
|
{
|
|
m_bNoSurprise = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::SetFavoriteEnemy(Event *ev)
|
|
{
|
|
m_sFavoriteEnemy = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetFavoriteEnemy(Event *ev)
|
|
{
|
|
ev->AddString(m_sFavoriteEnemy);
|
|
}
|
|
|
|
void AISpawnPoint::GetDontDropHealth(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bDontDropHealth);
|
|
}
|
|
|
|
void AISpawnPoint::SetDontDropHealth(Event *ev)
|
|
{
|
|
m_bDontDropHealth = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetDontDropWeapons(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bDontDropWeapons);
|
|
}
|
|
|
|
void AISpawnPoint::SetDontDropWeapons(Event *ev)
|
|
{
|
|
m_bDontDropWeapons = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetInterval(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fInterval);
|
|
}
|
|
|
|
void AISpawnPoint::SetInterval(Event *ev)
|
|
{
|
|
m_fInterval = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetMaxDistance(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fMaxDist);
|
|
}
|
|
|
|
void AISpawnPoint::SetMaxDistance(Event *ev)
|
|
{
|
|
m_fMaxDist = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetMinDistance(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fMinDist);
|
|
}
|
|
|
|
void AISpawnPoint::SetMinDistance(Event *ev)
|
|
{
|
|
m_fMinDist = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetLeash(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fLeash);
|
|
}
|
|
|
|
void AISpawnPoint::SetLeash(Event *ev)
|
|
{
|
|
m_fLeash = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetFov(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fFov);
|
|
}
|
|
|
|
void AISpawnPoint::SetFov(Event *ev)
|
|
{
|
|
m_fFov = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::SetSight(Event *ev)
|
|
{
|
|
m_fSight = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetSight(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fSight);
|
|
}
|
|
|
|
void AISpawnPoint::GetHearing(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fHearing);
|
|
}
|
|
|
|
void AISpawnPoint::SetHearing(Event *ev)
|
|
{
|
|
m_fHearing = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetPatrolWaitTrigger(Event *ev)
|
|
{
|
|
ev->AddInteger(m_bPatrolWaitTrigger);
|
|
}
|
|
|
|
void AISpawnPoint::SetPatrolWaitTrigger(Event *ev)
|
|
{
|
|
m_bPatrolWaitTrigger = ev->GetBoolean(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTypeIdle(Event *ev)
|
|
{
|
|
ev->AddString(m_sTypeIdle);
|
|
}
|
|
|
|
void AISpawnPoint::SetTypeIdle(Event *ev)
|
|
{
|
|
m_sTypeIdle = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTypeGrenade(Event *ev)
|
|
{
|
|
ev->AddString(m_sTypeGrenade);
|
|
}
|
|
|
|
void AISpawnPoint::SetTypeGrenade(Event *ev)
|
|
{
|
|
m_sTypeGrenade = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTypeDisguise(Event *ev)
|
|
{
|
|
ev->AddString(m_sTypeDisguise);
|
|
}
|
|
|
|
void AISpawnPoint::SetTypeDisguise(Event *ev)
|
|
{
|
|
m_sTypeDisguise = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetTypeAttack(Event *ev)
|
|
{
|
|
ev->AddString(m_sTypeAttack);
|
|
}
|
|
|
|
void AISpawnPoint::SetTypeAttack(Event *ev)
|
|
{
|
|
m_sTypeAttack = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::SetSoundAwareness(Event *ev)
|
|
{
|
|
m_fSoundAwareness = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetSoundAwareness(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fSoundAwareness);
|
|
}
|
|
|
|
void AISpawnPoint::SetMaxNoticeTimeScale(Event *ev)
|
|
{
|
|
m_fMaxNoticeTimeScale = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetMaxNoticeTimeScale(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fMaxNoticeTimeScale);
|
|
}
|
|
|
|
void AISpawnPoint::GetGun(Event *ev)
|
|
{
|
|
ev->AddString(m_sGun);
|
|
}
|
|
|
|
void AISpawnPoint::SetGun(Event *ev)
|
|
{
|
|
m_sGun = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetGrenadeAwareness(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fGrenadeAwareness);
|
|
}
|
|
|
|
void AISpawnPoint::SetGrenadeAwareness(Event *ev)
|
|
{
|
|
m_fGrenadeAwareness = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::SetFixedLeash(Event *ev)
|
|
{
|
|
m_fFixedLeash = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetFixedLeash(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fFixedLeash);
|
|
}
|
|
|
|
void AISpawnPoint::GetEnemyShareRange(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fEnemyShareRange);
|
|
}
|
|
|
|
void AISpawnPoint::SetEnemyShareRange(Event *ev)
|
|
{
|
|
m_fEnemyShareRange = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetDisguiseRange(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fDisguiseRange);
|
|
}
|
|
|
|
void AISpawnPoint::SetDisguiseRange(Event *ev)
|
|
{
|
|
m_fDisguiseRange = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetDisguisePeriod(Event *ev)
|
|
{
|
|
ev->AddFloat(m_fDisguisePeriod);
|
|
}
|
|
|
|
void AISpawnPoint::SetDisguisePeriod(Event *ev)
|
|
{
|
|
m_fDisguisePeriod = ev->GetFloat(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetDisguiseLevel(Event *ev)
|
|
{
|
|
ev->AddInteger(m_iDisguiseLevel);
|
|
}
|
|
|
|
void AISpawnPoint::SetDisguiseLevel(Event *ev)
|
|
{
|
|
m_iDisguiseLevel = ev->GetInteger(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetBalconyHeight(Event *ev)
|
|
{
|
|
ev->AddInteger(m_iBalconyHeight);
|
|
}
|
|
|
|
void AISpawnPoint::SetBalconyHeight(Event *ev)
|
|
{
|
|
m_iBalconyHeight = ev->GetInteger(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetAmmoGrenade(Event *ev)
|
|
{
|
|
ev->AddInteger(m_iAmmoGrenade);
|
|
}
|
|
|
|
void AISpawnPoint::SetAmmoGrenade(Event *ev)
|
|
{
|
|
m_iAmmoGrenade = ev->GetInteger(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetAccuracy(Event *ev)
|
|
{
|
|
ev->AddInteger(m_iAccuracy);
|
|
}
|
|
|
|
void AISpawnPoint::SetAccuracy(Event *ev)
|
|
{
|
|
m_iAccuracy = ev->GetInteger(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetEnemyName(Event *ev)
|
|
{
|
|
ev->AddString(m_sEnemyName);
|
|
}
|
|
|
|
void AISpawnPoint::SetEnemyName(Event *ev)
|
|
{
|
|
m_sEnemyName = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetHealth(Event *ev)
|
|
{
|
|
ev->AddInteger(m_iHealth);
|
|
}
|
|
|
|
void AISpawnPoint::SetHealth(Event *ev)
|
|
{
|
|
m_iHealth = ev->GetInteger(1);
|
|
}
|
|
|
|
void AISpawnPoint::GetModel(Event *ev)
|
|
{
|
|
ev->AddString(m_sModel);
|
|
}
|
|
|
|
void AISpawnPoint::SetModel(Event *ev)
|
|
{
|
|
m_sModel = ev->GetString(1);
|
|
}
|
|
|
|
void AISpawnPoint::Archive(Archiver& arc)
|
|
{
|
|
SimpleEntity::Archive(arc);
|
|
|
|
arc.ArchiveString(&m_sModel);
|
|
arc.ArchiveInteger(&m_iHealth);
|
|
arc.ArchiveString(&m_sEnemyName);
|
|
arc.ArchiveFloat(&m_iAccuracy);
|
|
arc.ArchiveInteger(&m_iAmmoGrenade);
|
|
arc.ArchiveFloat(&m_iBalconyHeight);
|
|
arc.ArchiveInteger(&m_iDisguiseLevel);
|
|
arc.ArchiveFloat(&m_fDisguisePeriod);
|
|
arc.ArchiveFloat(&m_fDisguiseRange);
|
|
arc.ArchiveFloat(&m_fEnemyShareRange);
|
|
arc.ArchiveFloat(&m_fFixedLeash);
|
|
arc.ArchiveFloat(&m_fGrenadeAwareness);
|
|
arc.ArchiveString(&m_sGun);
|
|
arc.ArchiveFloat(&m_fMaxNoticeTimeScale);
|
|
arc.ArchiveFloat(&m_fSoundAwareness);
|
|
arc.ArchiveString(&m_sTypeAttack);
|
|
arc.ArchiveString(&m_sTypeDisguise);
|
|
arc.ArchiveString(&m_sTypeGrenade);
|
|
arc.ArchiveString(&m_sTypeIdle);
|
|
arc.ArchiveBool(&m_bPatrolWaitTrigger);
|
|
arc.ArchiveFloat(&m_fHearing);
|
|
arc.ArchiveFloat(&m_fSight);
|
|
arc.ArchiveFloat(&m_fFov);
|
|
arc.ArchiveFloat(&m_fLeash);
|
|
arc.ArchiveFloat(&m_fMinDist);
|
|
arc.ArchiveFloat(&m_fMaxDist);
|
|
arc.ArchiveFloat(&m_fInterval);
|
|
arc.ArchiveBool(&m_bDontDropWeapons);
|
|
arc.ArchiveBool(&m_bDontDropHealth);
|
|
arc.ArchiveString(&m_sFavoriteEnemy);
|
|
arc.ArchiveBool(&m_bNoSurprise);
|
|
arc.ArchiveString(&m_sPatrolPath);
|
|
arc.ArchiveString(&m_sTurret);
|
|
arc.ArchiveString(&m_sAlarmNode);
|
|
arc.ArchiveString(&m_sWeapon);
|
|
arc.ArchiveString(&m_sTarget);
|
|
arc.ArchiveString(&m_sVoiceType);
|
|
arc.ArchiveBool(&m_bForceDropWeapon);
|
|
arc.ArchiveBool(&m_bForceDropHealth);
|
|
}
|