WEAPON_SLAM: rough but mostly functional implementation

This commit is contained in:
Marco Cawthorne 2023-09-25 16:09:58 -07:00
parent b7941fb3dc
commit 6c9a29060c
Signed by: eukara
GPG key ID: CE2032F0A2882A22
5 changed files with 352 additions and 97 deletions

View file

@ -308,7 +308,7 @@ HUD_DrawHealth(void)
HUD_DrawNums(pl.health, pos + [40, 0], pSeatLocal->m_flHealthAlpha, g_hud_color);
} else {
drawsubpic(
pos + [-72,-14],
pos + [0,-14],
[48,16],
g_hud7_spr,
[spr_health[0], spr_health[1]],

View file

@ -51,5 +51,5 @@ ClientGame_RendererRestart(string rstr)
MUZZLE_SMALL = (int)getmodelindex("sprites/muzzleflash2.spr");
MUZZLE_WEIRD = (int)getmodelindex("sprites/muzzleflash3.spr");
BEAM_TRIPMINE = particleeffectnum("weapon_tripmine.beam");
BEAM_TRIPMINE = particleeffectnum("weapon_slam.beam");
}

View file

@ -281,11 +281,4 @@ weapon_t w_ar2 =
.isempty = w_ar2_isempty,
.type = w_ar2_type,
.hudpic = w_ar2_hudpic
};
#ifdef CLIENT
void w_tripmine_parse(void)
{
}
#endif
};

View file

@ -14,21 +14,212 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* MONSTER_TRIPMINE SEGMENT
*
* Because not being able to place it around levels would be boring.
* Some maps, such as subtransit and a few singleplayer chapters have this. */
#ifdef SERVER
class monster_tripmine:NSMonster
{
int m_iDist;
void(void) monster_tripmine;
virtual float(entity, float) SendEntity;
virtual void(int) Trip;
virtual void(void) Damaged;
virtual void(void) Ready;
virtual void(void) Respawn;
};
float
monster_tripmine::SendEntity(entity pvsent, float flags)
{
WriteByte(MSG_ENTITY, ENT_TRIPMINE);
WriteCoord(MSG_ENTITY, origin[0]);
WriteCoord(MSG_ENTITY, origin[1]);
WriteCoord(MSG_ENTITY, origin[2]);
WriteCoord(MSG_ENTITY, angles[0]);
WriteCoord(MSG_ENTITY, angles[1]);
WriteCoord(MSG_ENTITY, angles[2]);
WriteByte(MSG_ENTITY, health);
WriteShort(MSG_ENTITY, modelindex);
return (1);
}
void
monster_tripmine::Trip(int walkthrough)
{
float dmg;
if (!walkthrough) {
real_owner = g_dmg_eAttacker;
}
/* This is to prevent infinite loops in Damage_Radius */
Death =
Pain = __NULL__;
takedamage = DAMAGE_NO;
dmg = Skill_GetValue("plr_tripmine", 150);
pointparticles(particleeffectnum("fx_explosion.main"), origin, [0,0,0], 1);
Damage_Radius(origin, real_owner, dmg, dmg * 2.5f, TRUE, WEAPON_SLAM);
Sound_Play(self, CHAN_VOICE, "fx.explosion");
Destroy();
}
void
monster_tripmine::Damaged(void)
{
Trip(0);
}
void
monster_tripmine::Ready(void)
{
makevectors(angles);
traceline(origin, origin + v_forward * 2048, FALSE, this);
SetSolid(SOLID_BBOX);
/* first time we're marked as ready, we play a sound and set the distance */
if (!health) {
SendFlags = -1;
health = 1;
Death =
Pain = Damaged;
takedamage = DAMAGE_YES;
m_iDist = (int)trace_plane_dist;
Sound_Play(this, CHAN_WEAPON, "weapon_tripmine.activate");
}
if ((int)trace_plane_dist != m_iDist) {
Trip(1);
}
nextthink = time;
}
void
monster_tripmine::Respawn(void)
{
SetModel("models/weapons/w_slam.mdl");
SetSolid(SOLID_NOT);
SetMovetype(MOVETYPE_NONE);
SetSize([-8,-8,-8], [8,8,8]);
SetOrigin(origin);
SendFlags = 1; /* force update */
/* ready in 4 seconds flat */
think = Ready;
/* fast beam */
if (spawnflags & 1) {
nextthink = time;
} else {
nextthink = time + 4.0f;
}
}
void
monster_tripmine::monster_tripmine(void)
{
Respawn();
}
#else
class csitem_tripmine
{
int m_iActive;
void(void) csitem_tripmine;
virtual float(void) predraw;
};
float csitem_tripmine::predraw(void)
{
if (m_iActive) {
makevectors(angles);
traceline(origin, origin + v_forward * 8196, FALSE, this);
trailparticles(BEAM_TRIPMINE, this, origin, trace_endpos);
}
addentity(this);
return PREDRAW_NEXT;
}
void
csitem_tripmine::csitem_tripmine(void)
{
solid = SOLID_BBOX;
movetype = MOVETYPE_NONE;
drawmask = MASK_ENGINE;
m_iActive = FALSE;
}
void w_tripmine_parse(void)
{
csitem_tripmine tm = (csitem_tripmine)self;
spawnfunc_csitem_tripmine();
tm.origin[0] = readcoord();
tm.origin[1] = readcoord();
tm.origin[2] = readcoord();
tm.angles[0] = readcoord();
tm.angles[1] = readcoord();
tm.angles[2] = readcoord();
tm.m_iActive = readbyte();
tm.modelindex = readshort();
setorigin(tm, tm.origin);
setsize(tm, [-8,-8,-8], [8,8,8]);
}
#endif
enum
{
SLAM_IDLE,
SLAM_FIDGET,
SLAM_DRAW,
SLAM_THROW
SLAM_IDLE, // 3.36
SLAM_IDLE_NOHAND, // 3.36
SLAM_THROW, // 0.50
SLAM_DRAWHAND, // 0.83
SLAM_THROW_NOHAND, // 0.50
SLAM_WAVE, // 0.83
SLAM_DRAW, // 1.00
SLAM_DRAW_NOHAND, // 1.00
SLAM_PLACE, // 1.36
SLAM_DETONATE, // 1.36
SLAM_PLACE_ONEHAND, // 1.36
SLAM_PLACE_NOHAND, // 1.36
SLAM_DETONATOR_DRAW, // 1.00
SLAM_DETONATOR_IDLE, // 3.36
SLAM_DETONATOR_BOOM, // 0.70
SLAM_DETONATOR_THROWDRAW, // 1.00
SLAM_DETONATOR_HOLSTER, // 0.43
SLAM_TRIPMINE_IDLE, // 3.36
SLAM_TRIPMINE_DRAW, // 0.86
SLAM_TRIPMINE_TOTHROW, // 1.70
SLAM_TRIPMINE_STARTATTACH, // 0.26
SLAM_TRIPMINE_ENDATTACH, // 0.63
/* hopefully unused */
SLAM_STICKWALL_IDLE, // 1.36
SLAM_STICKWALL_IDLE_NOHAND, // 1.36
SLAM_STICKWALL_STARTATTACH, // 0.20
SLAM_STICKWALL_ENDATTACH, // 0.63
SLAM_STICKWALL_TOTHROW, // 1.00
SLAM_STICKWALL_TOTHROW_NOHAND, // 1.00
};
enum
{
RADIO_IDLE,
RADIO_FIDGET,
RADIO_DRAW,
RADIO_USE,
RADIO_HOLSTER
SLAMSTATE_NONE,
SLAMSTATE_RAISEDETONATOR,
SLAMSTATE_LOWERDETONATOR,
SLAMSTATE_GOTOTRIPMINE,
SLAMSTATE_TRIPMINE,
SLAMSTATE_LEAVETRIPMINE,
SLAMSTATE_ENDATTACH,
SLAMSTATE_GOTOTRIPDRAW
};
#ifdef SERVER
@ -101,14 +292,26 @@ w_slam_pickup(player pl, int new, int startammo)
void
w_slam_draw(player pl)
{
if (pl.satchel_chg > 0) {
Weapons_SetModel("models/v_slam_radio.mdl");
Weapons_ViewAnimation(pl, RADIO_DRAW);
Weapons_SetModel("models/weapons/v_slam.mdl");
if (pl.mode_tempstate == SLAMSTATE_TRIPMINE) {
Weapons_ViewAnimation(pl, SLAM_TRIPMINE_DRAW);
} else {
Weapons_SetModel("models/weapons/v_slam.mdl");
Weapons_ViewAnimation(pl, SLAM_DRAW);
if (pl.satchel_chg) {
if (pl.ammo_satchel)
Weapons_ViewAnimation(pl, SLAM_DETONATOR_THROWDRAW);
else
Weapons_ViewAnimation(pl, SLAM_DETONATOR_DRAW);
} else {
if (pl.ammo_satchel)
Weapons_ViewAnimation(pl, SLAM_DRAW_NOHAND);
else
Weapons_ViewAnimation(pl, SLAM_DRAWHAND);
}
}
pl.w_idle_next = 0.9f;
}
void
@ -125,84 +328,77 @@ w_slam_primary(player pl)
}
/* Ammo check */
if (pl.satchel_chg <= 0 && pl.ammo_satchel <= 0) {
if (pl.ammo_satchel <= 0) {
return;
}
if (pl.satchel_chg <= 0) {
Weapons_ViewAnimation(pl, RADIO_DRAW);
} else {
Weapons_ViewAnimation(pl, RADIO_USE);
}
if (pl.mode_tempstate == SLAMSTATE_TRIPMINE) {
#ifdef SERVER
/* if we don't have any slams placed yet, place one */
if (!pl.satchel_chg) {
NSProjectile_SpawnDef("projectile_slam", pl);
pl.satchel_chg++;
pl.ammo_satchel--;
pl.mode_tempstate = 1; /* mark us as having deployed something */
vector src = Weapons_GetCameraPos(pl);
Weapons_MakeVectors(pl);
traceline(src, src + v_forward * 64, FALSE, pl);
vector ang = vectoangles(trace_plane_normal);
monster_tripmine mine = spawn(monster_tripmine, real_owner: pl, angles: ang, spawnflags: MSF_MULTIPLAYER);
mine.health = 0;
mine.SetOrigin(trace_endpos + (trace_plane_normal * 8));
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTSQUEAK, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTSQUEAK, 0.5f);
} else {
/* detonate all we have */
s_slam_detonate(pl);
pl.satchel_chg = 0;
/* no slams left to place? just get rid of this thing */
if (pl.ammo_satchel <= 0) {
Weapons_RemoveItem(pl, WEAPON_SLAM);
}
}
#else
Weapons_SetModel("models/v_slam_radio.mdl");
/* same thing as the SERVER ifdef above... */
if (!pl.satchel_chg) {
pl.satchel_chg++;
pl.ammo_satchel--;
} else {
pl.satchel_chg = 0;
}
Sound_Play(pl, CHAN_WEAPON, "weapon_tripmine.deploy");
Sound_Play(mine, CHAN_WEAPON, "weapon_tripmine.charge");
#endif
Weapons_ViewAnimation(pl, SLAM_TRIPMINE_STARTATTACH);
pl.mode_tempstate = SLAMSTATE_ENDATTACH;
pl.w_attack_next =
pl.w_idle_next = 0.20f;
pl.ammo_satchel--;
if (pl.ammo_satchel <= 0 && pl.satchel_chg <= 0) {
#ifdef SERVER
Weapons_RemoveItem(pl, WEAPON_SLAM);
#endif
}
} else {
if (pl.satchel_chg)
Weapons_ViewAnimation(pl, SLAM_THROW);
else {
Weapons_ViewAnimation(pl, SLAM_THROW_NOHAND);
pl.mode_tempstate = SLAMSTATE_RAISEDETONATOR;
}
#ifdef SERVER
NSProjectile_SpawnDef("projectile_slam", pl);
#endif
pl.satchel_chg++;
pl.ammo_satchel--;
pl.w_attack_next =
pl.w_idle_next = 0.50f;
}
pl.w_attack_next = 1.0f;
pl.w_idle_next = 1.0f;
}
void
w_slam_secondary(player pl)
{
if (pl.w_attack_next) {
if (pl.satchel_chg <= 0)
return;
}
/* Ammo check */
if (pl.ammo_satchel <= 0) {
return;
Weapons_ViewAnimation(pl, SLAM_DETONATOR_BOOM);
pl.w_attack_next =
pl.w_idle_next = 0.7f;
} else {
Weapons_ViewAnimation(pl, SLAM_DETONATE);
pl.w_attack_next =
pl.w_idle_next = 1.36f;
}
Weapons_SetModel("models/v_slam_radio.mdl");
Weapons_ViewAnimation(pl, RADIO_DRAW);
#ifdef SERVER
NSProjectile_SpawnDef("projectile_slam", pl);
s_slam_detonate(pl);
#endif
if (pl.flags & FL_CROUCHING)
Animation_PlayerTop(pl, ANIM_CR_SHOOTSQUEAK, 0.41f);
else
Animation_PlayerTop(pl, ANIM_SHOOTSQUEAK, 0.5f);
pl.mode_tempstate = 0;
pl.satchel_chg = 0;
pl.satchel_chg++;
pl.ammo_satchel--;
pl.mode_tempstate = 1; /* mark us as having deployed something */
pl.w_attack_next = 1.0f;
pl.w_idle_next = 0.5f;
}
void
@ -214,25 +410,65 @@ w_slam_reload(player pl)
void
w_slam_release(player pl)
{
if (pl.w_attack_next > 0.0) {
return;
}
/* we're in either slam or tripmine mode */
if (pl.mode_tempstate == SLAMSTATE_NONE || pl.mode_tempstate == SLAMSTATE_TRIPMINE) {
Weapons_MakeVectors(pl);
vector src = pl.origin + pl.view_ofs;
traceline(src, src + (v_forward * 64), FALSE, pl);
if (trace_fraction >= 1.0 && pl.mode_tempstate == SLAMSTATE_TRIPMINE) {
pl.mode_tempstate = SLAMSTATE_LEAVETRIPMINE;
} else if (trace_fraction < 1.0 && pl.mode_tempstate == SLAMSTATE_NONE) {
pl.mode_tempstate = SLAMSTATE_GOTOTRIPMINE;
}
}
if (pl.w_idle_next > 0.0) {
return;
}
/* keep track of the model via tempstates */
if (pl.satchel_chg < 1i && pl.mode_tempstate != 0) {
pl.mode_tempstate = 0;
Weapons_SetModel("models/v_slam.mdl");
Weapons_ViewAnimation(pl, SLAM_DRAW);
pl.w_idle_next = 15.0f;
return;
}
if (pl.satchel_chg <= 0) {
Weapons_ViewAnimation(pl, SLAM_FIDGET);
if (pl.mode_tempstate == SLAMSTATE_RAISEDETONATOR) {
w_slam_draw(pl);
pl.mode_tempstate = SLAMSTATE_NONE;
} else if (pl.mode_tempstate == SLAMSTATE_GOTOTRIPMINE) {
Weapons_ViewAnimation(pl, SLAM_PLACE);
pl.w_idle_next = 1.30;
pl.mode_tempstate = SLAMSTATE_TRIPMINE;
} else if (pl.mode_tempstate == SLAMSTATE_LEAVETRIPMINE) {
Weapons_ViewAnimation(pl, SLAM_TRIPMINE_TOTHROW);
pl.w_idle_next = 1.68;
pl.mode_tempstate = SLAMSTATE_NONE;
} else if (pl.mode_tempstate == SLAMSTATE_ENDATTACH ) {
Weapons_ViewAnimation(pl, SLAM_TRIPMINE_ENDATTACH);
pl.w_idle_next = 0.6f;
pl.mode_tempstate = SLAMSTATE_GOTOTRIPDRAW;
} else if (pl.mode_tempstate == SLAMSTATE_TRIPMINE) {
Weapons_ViewAnimation(pl, SLAM_TRIPMINE_IDLE);
} else if (pl.mode_tempstate == SLAMSTATE_GOTOTRIPDRAW ) {
pl.mode_tempstate = SLAMSTATE_TRIPMINE;
w_slam_draw(pl);
} else {
Weapons_ViewAnimation(pl, RADIO_FIDGET);
if (pl.satchel_chg) {
if (pl.ammo_satchel)
Weapons_ViewAnimation(pl, SLAM_IDLE);
else
Weapons_ViewAnimation(pl, SLAM_DETONATOR_IDLE);
} else {
if (pl.ammo_satchel) {
Weapons_ViewAnimation(pl, SLAM_IDLE_NOHAND);
} else {
#ifdef SERVER
Weapons_RemoveItem(pl, WEAPON_SLAM);
#endif
}
}
//pl.w_idle_next = 3.36f;
}
pl.w_idle_next = 15.0f;
}
float
@ -246,8 +482,6 @@ w_slam_hud(player pl)
{
#ifdef CLIENT
HUD_DrawAmmo2();
vector aicon_pos = g_hudmins + [g_hudres[0] - 48, g_hudres[1] - 42];
drawsubpic(aicon_pos, [24,24], g_hud7_spr, [72/256,96/128], [24/256, 24/128], g_hud_color, pSeatLocal->m_flAmmo2Alpha, DRAWFLAG_ADDITIVE);
#endif
}

View file

@ -11,4 +11,32 @@ entityDef weapon_slam
"inv_item" "$WEAPON_SLAM"
"snd_acquire" "weapon.pickup"
"snd_respawn" "item.respawn"
}
entityDef projectile_slam
{
"spawnclass" "NSProjectile"
"model" "models/weapons/w_slam.mdl"
"velocity" "274 0 0"
"angular_velocity" "0 400 0"
"friction" "0.8"
"gravity" "0.5"
"bounce" "1"
"frame" "1"
"mins" "-1 -1 -4"
"maxs" "1 1 4"
"snd_bounce" "weapon_satchel.bounce"
"inherit_velocity" "1"
"def_splash_damage" "damage_satchelExplosion"
"model_detonate" "fx_explosion.main"
"snd_explode" "fx.explosion"
}
entityDef damage_satchelExplosion
{
"damage" "skill:plr_satchel"
"radius" "375"
}