2020-09-04 23:54:23 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016-2020 Marco Hladik <marco@icculus.org>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*QUAKED func_mortar_field (0 .5 .8) ?
|
|
|
|
"targetname" Name
|
|
|
|
"m_flSpread" Maximum spread in game-units
|
|
|
|
"m_flCount" Number of bombs dropped per strike
|
|
|
|
"m_flControl" Targeting type. 0 = random, 1 = activator, 2 = controlled
|
|
|
|
"m_iszXController" Name of the momentary_rot_button providing X-offset
|
|
|
|
"m_iszYController" Name of the momentary_rot_button providing Y-offset
|
|
|
|
|
|
|
|
Description:
|
|
|
|
This brush volume acts as mortar drop area.
|
|
|
|
When triggered, it'll drop mortar shells straight to the ground (with a bit
|
|
|
|
of spread if specified).
|
|
|
|
|
|
|
|
It can be set to three different targeting modes, 0 will pick any
|
|
|
|
random point in the volume as a drop position. 1 will target the person or
|
|
|
|
entity activating it and 2 is a more complex mode which requires two
|
|
|
|
momentary_rot_button entities to control the X and Y offset in the volume.
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
GoldSrc expects some hardcoded behaviour (sounds playing, hardcoded delay
|
|
|
|
between mortar shell drops) that I haven't implemented yet.
|
|
|
|
I'll turn those into map attribute keys so people can finally control
|
|
|
|
sound, damage, delay and so on.
|
|
|
|
|
|
|
|
Trivia:
|
|
|
|
This entity was introduced in Half-Life (1998).
|
|
|
|
*/
|
|
|
|
|
|
|
|
class func_mortar_field:CBaseTrigger
|
|
|
|
{
|
|
|
|
int m_iType;
|
|
|
|
int m_iCount;
|
|
|
|
float m_flSpread;
|
|
|
|
string m_strXController;
|
|
|
|
string m_strYController;
|
|
|
|
|
|
|
|
void(void) func_mortar_field;
|
|
|
|
|
|
|
|
virtual void(vector) Fire;
|
|
|
|
virtual void(void) FireRandom;
|
|
|
|
virtual void(entity) FireTarget;
|
|
|
|
virtual void(void) FireControlled;
|
|
|
|
virtual void(entity,int) Trigger;
|
|
|
|
virtual void(void) Respawn;
|
2020-09-08 16:56:46 -07:00
|
|
|
virtual void(string, string) SpawnKey;
|
2020-09-04 23:54:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::Fire(vector vecOrg)
|
|
|
|
{
|
|
|
|
/* the spread */
|
|
|
|
makevectors([90,0,0]);
|
|
|
|
vecOrg[0] += random(-m_flSpread, m_flSpread);
|
|
|
|
vecOrg[1] += random(-m_flSpread, m_flSpread);
|
|
|
|
|
|
|
|
/* trace from the sky downwards */
|
|
|
|
traceline(vecOrg, vecOrg + (v_forward * 4096), FALSE, this);
|
|
|
|
|
|
|
|
float dmg = 200.0f;
|
|
|
|
Damage_Radius(trace_endpos, this, dmg, dmg * 2.5f, TRUE, 0);
|
|
|
|
FX_Explosion(trace_endpos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::FireRandom(void)
|
|
|
|
{
|
|
|
|
vector vecPos;
|
|
|
|
|
|
|
|
/* get our center */
|
|
|
|
vecPos[0] = absmin[0] + (0.5f * (absmax[0] - absmin[0]));
|
|
|
|
vecPos[1] = absmin[1] + (0.5f * (absmax[1] - absmin[1]));
|
|
|
|
vecPos[2] = absmin[2] + (0.5f * (absmax[2] - absmin[2]));
|
|
|
|
|
|
|
|
/* now randomize the position in the volume */
|
|
|
|
vecPos[0] += mins[0] + (random() * size[0]);
|
|
|
|
vecPos[1] += mins[1] + (random() * size[1]);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_iCount; i++);
|
|
|
|
Fire(vecPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::FireTarget(entity act)
|
|
|
|
{
|
|
|
|
vector vecPos;
|
|
|
|
|
|
|
|
/* get our center */
|
|
|
|
vecPos[0] = absmin[0] + (0.5f * (absmax[0] - absmin[0]));
|
|
|
|
vecPos[1] = absmin[1] + (0.5f * (absmax[1] - absmin[1]));
|
|
|
|
vecPos[2] = absmin[2] + (0.5f * (absmax[2] - absmin[2]));
|
|
|
|
|
|
|
|
/* orient towards the nearest player pos, clamping by our bounds */
|
|
|
|
vecPos[0] = bound(vecPos[0] + mins[0], act.origin[0], vecPos[0] + maxs[0]);
|
|
|
|
vecPos[1] = bound(vecPos[1] + mins[1], act.origin[1], vecPos[1] + maxs[0]);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_iCount; i++);
|
|
|
|
Fire(vecPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::FireControlled(void)
|
|
|
|
{
|
|
|
|
momentary_rot_button mX;
|
|
|
|
momentary_rot_button mY;
|
|
|
|
vector vecPos;
|
|
|
|
entity f;
|
|
|
|
|
|
|
|
mX = mY = __NULL__;
|
|
|
|
|
|
|
|
for (f = world; (f = find(f, ::classname, "momentary_rot_button"));) {
|
|
|
|
momentary_rot_button l = (momentary_rot_button) f;
|
|
|
|
|
2020-09-08 13:49:35 -07:00
|
|
|
if (l.targetname == m_strXController) {
|
2020-09-04 23:54:23 -07:00
|
|
|
mX = l;
|
|
|
|
}
|
|
|
|
|
2020-09-08 13:49:35 -07:00
|
|
|
if (l.targetname == m_strYController) {
|
2020-09-04 23:54:23 -07:00
|
|
|
mY = l;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mX || !mY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* find our center */
|
|
|
|
vecPos[0] = absmin[0] + (0.5f * (absmax[0] - absmin[0]));
|
|
|
|
vecPos[1] = absmin[1] + (0.5f * (absmax[1] - absmin[1]));
|
|
|
|
vecPos[2] = absmin[2] + (0.5f * (absmax[2] - absmin[2]));
|
|
|
|
|
|
|
|
/* now offset the position to the rot_buttons */
|
|
|
|
vecPos[0] += mins[0] + (mX.m_flProgress * size[0]);
|
|
|
|
vecPos[1] += mins[1] + (mY.m_flProgress * size[1]);
|
|
|
|
|
|
|
|
for (int i = 0; i < m_iCount; i++);
|
|
|
|
Fire(vecPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::Trigger(entity act, int state)
|
|
|
|
{
|
|
|
|
switch (m_iType) {
|
|
|
|
case 0:
|
|
|
|
FireRandom();
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
FireTarget(act);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
FireControlled();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
func_mortar_field::Respawn(void)
|
|
|
|
{
|
|
|
|
SetMovetype(MOVETYPE_NONE);
|
|
|
|
SetSolid(SOLID_NOT);
|
|
|
|
SetModel(m_oldModel);
|
|
|
|
SetOrigin(m_oldOrigin);
|
2020-11-13 02:17:42 -08:00
|
|
|
|
|
|
|
#ifdef GS_RENDERFX
|
|
|
|
SetRenderMode(RM_TRIGGER);
|
|
|
|
#endif
|
2020-09-04 23:54:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-09-08 16:56:46 -07:00
|
|
|
func_mortar_field::SpawnKey(string strKey, string strValue)
|
2020-09-04 23:54:23 -07:00
|
|
|
{
|
2020-09-08 16:56:46 -07:00
|
|
|
switch (strKey) {
|
|
|
|
case "m_iszXController":
|
|
|
|
m_strXController = strValue;
|
|
|
|
break;
|
|
|
|
case "m_iszYController":
|
|
|
|
m_strYController = strValue;
|
|
|
|
break;
|
|
|
|
case "m_flControl":
|
|
|
|
m_iType = stoi(strValue);
|
|
|
|
break;
|
|
|
|
case "m_flCount":
|
|
|
|
m_iCount = stoi(strValue);
|
|
|
|
break;
|
|
|
|
case "m_flSpread":
|
|
|
|
m_flSpread = stof(strValue) / 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CBaseTrigger::SpawnKey(strKey, strValue);
|
2020-09-04 23:54:23 -07:00
|
|
|
}
|
2020-09-08 16:56:46 -07:00
|
|
|
}
|
2020-09-04 23:54:23 -07:00
|
|
|
|
2020-09-08 16:56:46 -07:00
|
|
|
void
|
|
|
|
func_mortar_field::func_mortar_field(void)
|
|
|
|
{
|
2020-09-04 23:54:23 -07:00
|
|
|
CBaseTrigger::CBaseTrigger();
|
|
|
|
}
|