mirror of
https://github.com/id-Software/quake2-rerelease-dll.git
synced 2026-05-14 03:49:09 +02:00
Update 1 changes
This commit is contained in:
@@ -254,7 +254,8 @@ enum player_stat_t
|
||||
STAT_SELECTED_ITEM_NAME,
|
||||
// [Paril-KEX]
|
||||
STAT_HEALTH_BARS, // two health bar values; 7 bits for value, 1 bit for active
|
||||
// if active,
|
||||
// [Paril-KEX]
|
||||
STAT_ACTIVE_WEAPON,
|
||||
|
||||
// don't use; just for verification
|
||||
STAT_LAST
|
||||
|
||||
@@ -149,3 +149,40 @@ int32_t Bot_GetItemID( const char * classname ) {
|
||||
|
||||
return Item_Invalid;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Edict_ForceLookAtPoint
|
||||
================
|
||||
*/
|
||||
void Edict_ForceLookAtPoint( edict_t * edict, gvec3_cref_t point ) {
|
||||
vec3_t viewOrigin = edict->s.origin;
|
||||
if ( edict->client != nullptr ) {
|
||||
viewOrigin += edict->client->ps.viewoffset;
|
||||
}
|
||||
|
||||
const vec3_t ideal = ( point - viewOrigin ).normalized();
|
||||
|
||||
vec3_t viewAngles = vectoangles( ideal );
|
||||
if ( viewAngles.x < -180.0f ) {
|
||||
viewAngles.x = anglemod( viewAngles.x + 360.0f );
|
||||
}
|
||||
|
||||
if ( edict->client != nullptr ) {
|
||||
edict->client->ps.pmove.delta_angles = ( viewAngles - edict->client->resp.cmd_angles );
|
||||
edict->client->ps.viewangles = {};
|
||||
edict->client->v_angle = {};
|
||||
edict->s.angles = {};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Bot_PickedUpItem
|
||||
|
||||
Check if the given bot has picked up the given item or not.
|
||||
================
|
||||
*/
|
||||
bool Bot_PickedUpItem( edict_t * bot, edict_t * item ) {
|
||||
return item->item_picked_up_by[ ( bot->s.number - 1 ) ];
|
||||
}
|
||||
@@ -6,4 +6,6 @@
|
||||
void Bot_SetWeapon( edict_t * bot, const int weaponIndex, const bool instantSwitch );
|
||||
void Bot_TriggerEdict( edict_t * bot, edict_t * edict );
|
||||
int32_t Bot_GetItemID( const char * classname );
|
||||
void Bot_UseItem( edict_t * bot, const int32_t itemID );
|
||||
void Bot_UseItem( edict_t * bot, const int32_t itemID );
|
||||
void Edict_ForceLookAtPoint( edict_t * edict, gvec3_cref_t point );
|
||||
bool Bot_PickedUpItem( edict_t * bot, edict_t * item );
|
||||
|
||||
@@ -248,9 +248,6 @@ void Item_UpdateState( edict_t * item ) {
|
||||
}
|
||||
}
|
||||
|
||||
// track who has picked us up so far...
|
||||
item->sv.pickedup_list = item->item_picked_up_by;
|
||||
|
||||
const item_id_t itemID = item->item->id;
|
||||
if ( itemID == IT_FLAG1 || itemID == IT_FLAG2 ) {
|
||||
item->sv.ent_flags |= SVFL_IS_OBJECTIVE;
|
||||
@@ -529,4 +526,4 @@ const edict_t * FindActorUnderCrosshair( const edict_t * player ) {
|
||||
}
|
||||
|
||||
return traceEnt;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,7 +1050,7 @@ static void CG_ExecuteLayoutString (const char *s, vrect_t hud_vrect, vrect_t hu
|
||||
width = 3;
|
||||
value = ps->stats[STAT_AMMO];
|
||||
|
||||
int32_t min_ammo = cgi.CL_GetWarnAmmoCount(ps->stats[STAT_ACTIVE_WHEEL_WEAPON]);
|
||||
int32_t min_ammo = cgi.CL_GetWarnAmmoCount(ps->stats[STAT_ACTIVE_WEAPON]);
|
||||
|
||||
if (!min_ammo)
|
||||
min_ammo = 5; // back compat
|
||||
@@ -1702,7 +1702,6 @@ static void CG_DrawInventory(const player_state_t *ps, const std::array<int16_t,
|
||||
else
|
||||
{
|
||||
const char *string = G_Fmt("{}", inventory[item]).data();
|
||||
vec2_t strSz = cgi.SCR_MeasureFontString(string, scale);
|
||||
cgi.SCR_DrawFontString(string, x + (216 * scale) - (16 * scale), y - (font_y_offset * scale), scale, (item == selected) ? alt_color : rgba_white, true, text_align_t::RIGHT);
|
||||
|
||||
string = cgi.Localize(cgi.get_configstring(CS_ITEMS + item), nullptr, 0);
|
||||
|
||||
+31
-1
@@ -783,6 +783,8 @@ THINK(CTFDropFlagThink) (edict_t *ent) -> void
|
||||
gi.LocBroadcast_Print(PRINT_HIGH, "$g_flag_returned",
|
||||
CTFTeamName(CTF_TEAM2));
|
||||
}
|
||||
|
||||
gi.sound(ent, CHAN_RELIABLE | CHAN_NO_PHS_ADD | CHAN_AUX, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
|
||||
}
|
||||
|
||||
// Called from PlayerDie, to drop the flag from a dying player
|
||||
@@ -1087,6 +1089,20 @@ void SetCTFStats(edict_t *ent)
|
||||
p1 = imageindex_i_ctf1t;
|
||||
break;
|
||||
}
|
||||
|
||||
// [Paril-KEX] make sure there is a dropped version on the map somewhere
|
||||
if (p1 == imageindex_i_ctf1d)
|
||||
{
|
||||
e = G_FindByString<&edict_t::classname>(e, "item_flag_team1");
|
||||
|
||||
if (e == nullptr)
|
||||
{
|
||||
CTFResetFlag(CTF_TEAM1);
|
||||
gi.LocBroadcast_Print(PRINT_HIGH, "$g_flag_returned",
|
||||
CTFTeamName(CTF_TEAM1));
|
||||
gi.sound(ent, CHAN_RELIABLE | CHAN_NO_PHS_ADD | CHAN_AUX, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e->spawnflags.has(SPAWNFLAG_ITEM_DROPPED))
|
||||
p1 = imageindex_i_ctf1d; // must be dropped
|
||||
@@ -1108,6 +1124,20 @@ void SetCTFStats(edict_t *ent)
|
||||
p2 = imageindex_i_ctf2t;
|
||||
break;
|
||||
}
|
||||
|
||||
// [Paril-KEX] make sure there is a dropped version on the map somewhere
|
||||
if (p2 == imageindex_i_ctf2d)
|
||||
{
|
||||
e = G_FindByString<&edict_t::classname>(e, "item_flag_team2");
|
||||
|
||||
if (e == nullptr)
|
||||
{
|
||||
CTFResetFlag(CTF_TEAM2);
|
||||
gi.LocBroadcast_Print(PRINT_HIGH, "$g_flag_returned",
|
||||
CTFTeamName(CTF_TEAM2));
|
||||
gi.sound(ent, CHAN_RELIABLE | CHAN_NO_PHS_ADD | CHAN_AUX, gi.soundindex("ctf/flagret.wav"), 1, ATTN_NONE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e->spawnflags.has(SPAWNFLAG_ITEM_DROPPED))
|
||||
p2 = imageindex_i_ctf2d; // must be dropped
|
||||
@@ -2960,7 +2990,7 @@ bool CTFStartClient(edict_t *ent)
|
||||
|
||||
void CTFObserver(edict_t *ent)
|
||||
{
|
||||
if (!G_TeamplayEnabled())
|
||||
if (!G_TeamplayEnabled() || g_teamplay_force_join->integer)
|
||||
return;
|
||||
|
||||
// start as 'observer'
|
||||
|
||||
+67
-28
@@ -93,7 +93,8 @@ void ai_stand(edict_t *self, float dist)
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
// [Paril-KEX] check if we've been pushed out of our point_combat
|
||||
if (self->movetarget)
|
||||
if (!(self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND) &&
|
||||
self->movetarget && self->movetarget->classname && !strcmp(self->movetarget->classname, "point_combat"))
|
||||
{
|
||||
if (!boxes_intersect(self->absmin, self->absmax, self->movetarget->absmin, self->movetarget->absmax))
|
||||
{
|
||||
@@ -105,7 +106,7 @@ void ai_stand(edict_t *self, float dist)
|
||||
}
|
||||
}
|
||||
|
||||
if (self->enemy)
|
||||
if (self->enemy && !(self->enemy->classname && !strcmp(self->enemy->classname, "player_noise")))
|
||||
{
|
||||
v = self->enemy->s.origin - self->s.origin;
|
||||
self->ideal_yaw = vectoyaw(v);
|
||||
@@ -453,6 +454,12 @@ bool infront(edict_t *self, edict_t *other)
|
||||
vec = other->s.origin - self->s.origin;
|
||||
vec.normalize();
|
||||
dot = vec.dot(forward);
|
||||
|
||||
// [Paril-KEX] if we're an ambush monster, reduce our cone of
|
||||
// vision to not ruin surprises, unless we already had an enemy.
|
||||
if (self->spawnflags.has(SPAWNFLAG_MONSTER_AMBUSH) && !self->monsterinfo.trail_time && !self->enemy)
|
||||
return dot > 0.15f;
|
||||
|
||||
return dot > -0.30f;
|
||||
}
|
||||
|
||||
@@ -730,7 +737,31 @@ bool FindTarget(edict_t *self)
|
||||
return false;
|
||||
|
||||
if (client == self->enemy)
|
||||
return true; // JDC false;
|
||||
{
|
||||
bool skip_found = true;
|
||||
|
||||
// [Paril-KEX] slight special behavior if we are currently going to a sound
|
||||
// and we hear a new one; because player noises are re-used, this can leave
|
||||
// us with the "same" enemy even though it's a different noise.
|
||||
if (heardit && (self->monsterinfo.aiflags & AI_SOUND_TARGET))
|
||||
{
|
||||
vec3_t temp = client->s.origin - self->s.origin;
|
||||
self->ideal_yaw = vectoyaw(temp);
|
||||
|
||||
if (!FacingIdeal(self))
|
||||
skip_found = false;
|
||||
else if (!SV_CloseEnough(self, client, 8.f))
|
||||
skip_found = false;
|
||||
|
||||
if (!skip_found && (self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND))
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
|
||||
}
|
||||
}
|
||||
|
||||
if (skip_found)
|
||||
return true; // JDC false;
|
||||
}
|
||||
|
||||
// ROGUE - hintpath coop fix
|
||||
if ((self->monsterinfo.aiflags & AI_HINT_PATH) && coop->integer)
|
||||
@@ -873,7 +904,8 @@ bool FacingIdeal(edict_t *self)
|
||||
|
||||
//=============================================================================
|
||||
|
||||
MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
// [Paril-KEX] split this out so we can use it for the other bosses
|
||||
bool M_CheckAttack_Base(edict_t *self, float stand_ground_chance, float melee_chance, float near_chance, float mid_chance, float far_chance, float strafe_scalar)
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
float chance;
|
||||
@@ -903,7 +935,7 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self,
|
||||
MASK_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
MASK_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -938,7 +970,7 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
// make sure we're not going to shoot a monster
|
||||
tr = gi.traceline(spot1, self->monsterinfo.blind_fire_target, self,
|
||||
CONTENTS_MONSTER);
|
||||
CONTENTS_MONSTER);
|
||||
if (tr.allsolid || tr.startsolid || ((tr.fraction < 1.0f) && (tr.ent != self->enemy)))
|
||||
return false;
|
||||
|
||||
@@ -982,28 +1014,29 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (enemy_range > RANGE_MID)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.7f;
|
||||
chance = stand_ground_chance;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.4f;
|
||||
chance = melee_chance;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.25f;
|
||||
chance = near_chance;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MID)
|
||||
{
|
||||
chance = mid_chance;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.06f;
|
||||
chance = far_chance;
|
||||
}
|
||||
|
||||
// PGM - go ahead and shoot every time if it's a info_notnull
|
||||
if ((frandom() < chance) || (!self->enemy->client && self->enemy->solid == SOLID_NOT))
|
||||
if ((!self->enemy->client && self->enemy->solid == SOLID_NOT) || (frandom() < chance))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
self->monsterinfo.attack_finished = level.time;
|
||||
@@ -1018,6 +1051,7 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
// originally, just 0.3
|
||||
float strafe_chance;
|
||||
|
||||
if (!(strcmp(self->classname, "monster_daedalus")))
|
||||
strafe_chance = 0.8f;
|
||||
else
|
||||
@@ -1026,16 +1060,21 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
// if enemy is tesla, never strafe
|
||||
if ((self->enemy) && (self->enemy->classname) && (!strcmp(self->enemy->classname, "tesla_mine")))
|
||||
strafe_chance = 0;
|
||||
else
|
||||
strafe_chance *= strafe_scalar;
|
||||
|
||||
monster_attack_state_t new_state = AS_STRAIGHT;
|
||||
|
||||
if (frandom() < strafe_chance)
|
||||
new_state = AS_SLIDING;
|
||||
|
||||
if (new_state != self->monsterinfo.attack_state)
|
||||
if (strafe_chance)
|
||||
{
|
||||
self->monsterinfo.strafe_check_time = level.time + random_time(1_sec, 3_sec);
|
||||
self->monsterinfo.attack_state = new_state;
|
||||
monster_attack_state_t new_state = AS_STRAIGHT;
|
||||
|
||||
if (frandom() < strafe_chance)
|
||||
new_state = AS_SLIDING;
|
||||
|
||||
if (new_state != self->monsterinfo.attack_state)
|
||||
{
|
||||
self->monsterinfo.strafe_check_time = level.time + random_time(1_sec, 3_sec);
|
||||
self->monsterinfo.attack_state = new_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1051,6 +1090,11 @@ MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
return false;
|
||||
}
|
||||
|
||||
MONSTERINFO_CHECKATTACK(M_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
return M_CheckAttack_Base(self, 0.7f, 0.4f, 0.25f, 0.06f, 0.f, 1.0f);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
ai_run_melee
|
||||
@@ -1222,12 +1266,7 @@ bool ai_checkattack(edict_t *self, float dist)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->monsterinfo.aiflags & AI_BRUTAL)
|
||||
{
|
||||
if (self->enemy->health <= self->enemy->gib_health)
|
||||
hesDeadJim = true;
|
||||
}
|
||||
else
|
||||
if (!(self->monsterinfo.aiflags & AI_BRUTAL))
|
||||
{
|
||||
if (self->enemy->health <= 0)
|
||||
hesDeadJim = true;
|
||||
|
||||
+30
-18
@@ -3,7 +3,7 @@
|
||||
#include "g_local.h"
|
||||
#include "m_player.h"
|
||||
|
||||
void SelectNextItem(edict_t *ent, item_flags_t itflags)
|
||||
void SelectNextItem(edict_t *ent, item_flags_t itflags, bool menu = true)
|
||||
{
|
||||
gclient_t *cl;
|
||||
item_id_t i, index;
|
||||
@@ -12,12 +12,12 @@ void SelectNextItem(edict_t *ent, item_flags_t itflags)
|
||||
cl = ent->client;
|
||||
|
||||
// ZOID
|
||||
if (cl->menu)
|
||||
if (menu && cl->menu)
|
||||
{
|
||||
PMenu_Next(ent);
|
||||
return;
|
||||
}
|
||||
else if (cl->chase_target)
|
||||
else if (menu && cl->chase_target)
|
||||
{
|
||||
ChaseNext(ent);
|
||||
return;
|
||||
@@ -96,7 +96,7 @@ void ValidateSelectedItem(edict_t *ent)
|
||||
if (cl->pers.inventory[cl->pers.selected_item])
|
||||
return; // valid
|
||||
|
||||
SelectNextItem(ent, IF_ANY);
|
||||
SelectNextItem(ent, IF_ANY, false);
|
||||
}
|
||||
|
||||
//=================================================================================
|
||||
@@ -456,7 +456,7 @@ void Cmd_Spawn_f(edict_t *ent)
|
||||
if (other->inuse)
|
||||
gi.linkentity(other);
|
||||
|
||||
if (other->svflags & SVF_MONSTER)
|
||||
if ((other->svflags & SVF_MONSTER) && other->think)
|
||||
other->think(other);
|
||||
}
|
||||
|
||||
@@ -490,6 +490,19 @@ void Cmd_Teleport_f(edict_t *ent)
|
||||
ent->s.origin[0] = (float) atof(gi.argv(1));
|
||||
ent->s.origin[1] = (float) atof(gi.argv(2));
|
||||
ent->s.origin[2] = (float) atof(gi.argv(3));
|
||||
|
||||
if (gi.argc() >= 4)
|
||||
{
|
||||
float pitch = (float) atof(gi.argv(4));
|
||||
float yaw = (float) atof(gi.argv(5));
|
||||
float roll = (float) atof(gi.argv(6));
|
||||
vec3_t ang { pitch, yaw, roll };
|
||||
|
||||
ent->client->ps.pmove.delta_angles = ( ang - ent->client->resp.cmd_angles );
|
||||
ent->client->ps.viewangles = {};
|
||||
ent->client->v_angle = {};
|
||||
}
|
||||
|
||||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
@@ -660,10 +673,16 @@ void Cmd_Drop_f(edict_t *ent)
|
||||
return;
|
||||
|
||||
// ZOID--special case for tech powerups
|
||||
if (Q_strcasecmp(gi.args(), "tech") == 0 && (it = CTFWhat_Tech(ent)) != nullptr)
|
||||
if (Q_strcasecmp(gi.args(), "tech") == 0)
|
||||
{
|
||||
it->drop(ent, it);
|
||||
ValidateSelectedItem(ent);
|
||||
it = CTFWhat_Tech(ent);
|
||||
|
||||
if (it)
|
||||
{
|
||||
it->drop(ent, it);
|
||||
ValidateSelectedItem(ent);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// ZOID
|
||||
@@ -1033,7 +1052,7 @@ void Cmd_Where_f( edict_t * ent ) {
|
||||
const vec3_t & origin = ent->s.origin;
|
||||
|
||||
std::string location;
|
||||
fmt::format_to( std::back_inserter( location ), FMT_STRING( "{:.1f} {:.1f} {:.1f}\n" ), origin[ 0 ], origin[ 1 ], origin[ 2 ] );
|
||||
fmt::format_to( std::back_inserter( location ), FMT_STRING( "{:.1f} {:.1f} {:.1f} {:.1f} {:.1f} {:.1f}\n" ), origin[ 0 ], origin[ 1 ], origin[ 2 ], ent->client->ps.viewangles[0], ent->client->ps.viewangles[1], ent->client->ps.viewangles[2] );
|
||||
gi.LocClient_Print( ent, PRINT_HIGH, "Location: {}\n", location.c_str() );
|
||||
gi.SendToClipBoard( location.c_str() );
|
||||
}
|
||||
@@ -1212,9 +1231,7 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
if (do_animate)
|
||||
ent->client->anim_priority = ANIM_WAVE;
|
||||
|
||||
constexpr float NOTIFY_DISTANCE = 256.f;
|
||||
bool notified_anybody = false;
|
||||
const char *self_notify_msg = nullptr, *other_notify_msg = nullptr, *other_notify_none_msg = nullptr;
|
||||
const char *other_notify_msg = nullptr, *other_notify_none_msg = nullptr;
|
||||
|
||||
vec3_t start, dir;
|
||||
P_ProjectSource(ent, ent->client->v_angle, { 0, 0, 0 }, start, dir);
|
||||
@@ -1245,7 +1262,6 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
switch (i)
|
||||
{
|
||||
case GESTURE_FLIP_OFF:
|
||||
self_notify_msg = "$g_flipoff";
|
||||
other_notify_msg = "$g_flipoff_other";
|
||||
other_notify_none_msg = "$g_flipoff_none";
|
||||
if (do_animate)
|
||||
@@ -1255,7 +1271,6 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
}
|
||||
break;
|
||||
case GESTURE_SALUTE:
|
||||
self_notify_msg = "$g_salute";
|
||||
other_notify_msg = "$g_salute_other";
|
||||
other_notify_none_msg = "$g_salute_none";
|
||||
if (do_animate)
|
||||
@@ -1265,7 +1280,6 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
}
|
||||
break;
|
||||
case GESTURE_TAUNT:
|
||||
self_notify_msg = "$g_taunt";
|
||||
other_notify_msg = "$g_taunt_other";
|
||||
other_notify_none_msg = "$g_taunt_none";
|
||||
if (do_animate)
|
||||
@@ -1275,7 +1289,6 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
}
|
||||
break;
|
||||
case GESTURE_WAVE:
|
||||
self_notify_msg = "$g_wave";
|
||||
other_notify_msg = "$g_wave_other";
|
||||
other_notify_none_msg = "$g_wave_none";
|
||||
if (do_animate)
|
||||
@@ -1286,7 +1299,6 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
break;
|
||||
case GESTURE_POINT:
|
||||
default:
|
||||
self_notify_msg = "$g_point";
|
||||
other_notify_msg = "$g_point_other";
|
||||
other_notify_none_msg = "$g_point_none";
|
||||
if (do_animate)
|
||||
@@ -1336,7 +1348,7 @@ void Cmd_Wave_f(edict_t *ent)
|
||||
gi.WriteShort(POI_PING + (ent->s.number - 1));
|
||||
gi.WriteShort(5000);
|
||||
gi.WritePosition(tr.endpos);
|
||||
gi.WriteShort(gi.imageindex("loc_ping"));
|
||||
gi.WriteShort(level.pic_ping);
|
||||
gi.WriteByte(208);
|
||||
gi.WriteByte(POI_FLAG_NONE);
|
||||
gi.unicast(player, false);
|
||||
|
||||
+126
-20
@@ -112,7 +112,27 @@ THINK(Move_Begin) (edict_t *ent) -> void
|
||||
ent->think = Move_Final;
|
||||
}
|
||||
|
||||
void Think_AccelMove_New(edict_t *ent);
|
||||
void Think_AccelMove(edict_t *ent);
|
||||
bool Think_AccelMove_MoveInfo(moveinfo_t *moveinfo);
|
||||
|
||||
constexpr float AccelerationDistance(float target, float rate)
|
||||
{
|
||||
return (target * ((target / rate) + 1) / 2);
|
||||
}
|
||||
|
||||
inline void Move_Regular(edict_t *ent, const vec3_t &dest, void(*endfunc)(edict_t *self))
|
||||
{
|
||||
if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
|
||||
{
|
||||
Move_Begin(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->nextthink = level.time + FRAME_TIME_S;
|
||||
ent->think = Move_Begin;
|
||||
}
|
||||
}
|
||||
|
||||
void Move_Calc(edict_t *ent, const vec3_t &dest, void(*endfunc)(edict_t *self))
|
||||
{
|
||||
@@ -124,25 +144,101 @@ void Move_Calc(edict_t *ent, const vec3_t &dest, void(*endfunc)(edict_t *self))
|
||||
|
||||
if (ent->moveinfo.speed == ent->moveinfo.accel && ent->moveinfo.speed == ent->moveinfo.decel)
|
||||
{
|
||||
if (level.current_entity == ((ent->flags & FL_TEAMSLAVE) ? ent->teammaster : ent))
|
||||
{
|
||||
Move_Begin(ent);
|
||||
}
|
||||
else
|
||||
{
|
||||
ent->nextthink = level.time + FRAME_TIME_S;
|
||||
ent->think = Move_Begin;
|
||||
}
|
||||
Move_Regular(ent, dest, endfunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// accelerative
|
||||
ent->moveinfo.current_speed = 0;
|
||||
ent->think = Think_AccelMove;
|
||||
|
||||
if (gi.tick_rate == 10)
|
||||
ent->think = Think_AccelMove;
|
||||
else
|
||||
{
|
||||
// [Paril-KEX] rewritten to work better at higher tickrates
|
||||
ent->moveinfo.curve_frame = 0;
|
||||
ent->moveinfo.num_subframes = (0.1f / gi.frame_time_s) - 1;
|
||||
|
||||
float total_dist = ent->moveinfo.remaining_distance;
|
||||
|
||||
std::vector<float> distances;
|
||||
|
||||
if (ent->moveinfo.num_subframes)
|
||||
{
|
||||
distances.push_back(0);
|
||||
ent->moveinfo.curve_frame = 1;
|
||||
}
|
||||
else
|
||||
ent->moveinfo.curve_frame = 0;
|
||||
|
||||
// simulate 10hz movement
|
||||
while (ent->moveinfo.remaining_distance)
|
||||
{
|
||||
if (!Think_AccelMove_MoveInfo(&ent->moveinfo))
|
||||
break;
|
||||
|
||||
ent->moveinfo.remaining_distance -= ent->moveinfo.current_speed;
|
||||
distances.push_back(total_dist - ent->moveinfo.remaining_distance);
|
||||
}
|
||||
|
||||
if (ent->moveinfo.num_subframes)
|
||||
distances.push_back(total_dist);
|
||||
|
||||
ent->moveinfo.subframe = 0;
|
||||
ent->moveinfo.curve_ref = ent->s.origin;
|
||||
ent->moveinfo.curve_positions = make_savable_memory<float, TAG_LEVEL>(distances.size());
|
||||
std::copy(distances.begin(), distances.end(), ent->moveinfo.curve_positions.ptr);
|
||||
|
||||
ent->moveinfo.num_frames_done = 0;
|
||||
|
||||
ent->think = Think_AccelMove_New;
|
||||
}
|
||||
|
||||
ent->nextthink = level.time + FRAME_TIME_S;
|
||||
}
|
||||
}
|
||||
|
||||
THINK(Think_AccelMove_New) (edict_t *ent) -> void
|
||||
{
|
||||
float t = 0.f;
|
||||
float target_dist;
|
||||
|
||||
if (ent->moveinfo.num_subframes)
|
||||
{
|
||||
if (ent->moveinfo.subframe == ent->moveinfo.num_subframes + 1)
|
||||
{
|
||||
ent->moveinfo.subframe = 0;
|
||||
ent->moveinfo.curve_frame++;
|
||||
|
||||
if (ent->moveinfo.curve_frame == ent->moveinfo.curve_positions.count)
|
||||
{
|
||||
Move_Final(ent);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
t = (ent->moveinfo.subframe + 1) / ((float) ent->moveinfo.num_subframes + 1);
|
||||
|
||||
target_dist = lerp(ent->moveinfo.curve_positions[ent->moveinfo.curve_frame - 1], ent->moveinfo.curve_positions[ent->moveinfo.curve_frame], t);
|
||||
ent->moveinfo.subframe++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ent->moveinfo.curve_frame == ent->moveinfo.curve_positions.count)
|
||||
{
|
||||
Move_Final(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
target_dist = ent->moveinfo.curve_positions[ent->moveinfo.curve_frame++];
|
||||
}
|
||||
|
||||
ent->moveinfo.num_frames_done++;
|
||||
vec3_t target_pos = ent->moveinfo.curve_ref + (ent->moveinfo.dir * target_dist);
|
||||
ent->velocity = (target_pos - ent->s.origin) * (1.f / gi.frame_time_s);
|
||||
ent->nextthink = level.time + FRAME_TIME_S;
|
||||
}
|
||||
|
||||
//
|
||||
// Support routines for angular movement (changes in angle using avelocity)
|
||||
//
|
||||
@@ -269,11 +365,6 @@ The team has completed a frame of movement, so
|
||||
change the speed for the next frame
|
||||
==============
|
||||
*/
|
||||
constexpr float AccelerationDistance(float target, float rate)
|
||||
{
|
||||
return (target * ((target / rate) + 1) / 2);
|
||||
}
|
||||
|
||||
void plat_CalcAcceleratedMove(moveinfo_t *moveinfo)
|
||||
{
|
||||
float accel_dist;
|
||||
@@ -382,6 +473,18 @@ void plat_Accelerate(moveinfo_t *moveinfo)
|
||||
return;
|
||||
}
|
||||
|
||||
bool Think_AccelMove_MoveInfo (moveinfo_t *moveinfo)
|
||||
{
|
||||
if (moveinfo->current_speed == 0) // starting or blocked
|
||||
plat_CalcAcceleratedMove(moveinfo);
|
||||
|
||||
plat_Accelerate(moveinfo);
|
||||
|
||||
// will the entire move complete on next frame?
|
||||
return moveinfo->remaining_distance > moveinfo->current_speed;
|
||||
}
|
||||
|
||||
// Paril: old acceleration code; this is here only to support old save games.
|
||||
THINK(Think_AccelMove) (edict_t *ent) -> void
|
||||
{
|
||||
// [Paril-KEX] calculate distance dynamically
|
||||
@@ -390,12 +493,13 @@ THINK(Think_AccelMove) (edict_t *ent) -> void
|
||||
else
|
||||
ent->moveinfo.remaining_distance = (ent->moveinfo.end_origin - ent->s.origin).length();
|
||||
|
||||
if (ent->moveinfo.current_speed == 0) // starting or blocked
|
||||
plat_CalcAcceleratedMove(&ent->moveinfo);
|
||||
|
||||
plat_Accelerate(&ent->moveinfo);
|
||||
|
||||
// will the entire move complete on next frame?
|
||||
if (!Think_AccelMove_MoveInfo(&ent->moveinfo))
|
||||
{
|
||||
Move_Final(ent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->moveinfo.remaining_distance <= ent->moveinfo.current_speed)
|
||||
{
|
||||
Move_Final(ent);
|
||||
@@ -2233,6 +2337,8 @@ void train_resume(edict_t *self)
|
||||
dest -= vec3_t{1.f, 1.f, 1.f};
|
||||
}
|
||||
|
||||
self->s.sound = self->moveinfo.sound_middle;
|
||||
|
||||
self->moveinfo.state = STATE_TOP;
|
||||
self->moveinfo.start_origin = self->s.origin;
|
||||
self->moveinfo.end_origin = dest;
|
||||
|
||||
+53
-17
@@ -137,6 +137,9 @@ THINK(DoRespawn) (edict_t *ent) -> void
|
||||
else
|
||||
{
|
||||
// ZOID
|
||||
ent->svflags |= SVF_NOCLIENT;
|
||||
ent->solid = SOLID_NOT;
|
||||
gi.linkentity(ent);
|
||||
|
||||
for (count = 0, ent = master; ent; ent = ent->chain, count++)
|
||||
;
|
||||
@@ -243,7 +246,7 @@ bool Pickup_Powerup(edict_t *ent, edict_t *other)
|
||||
|
||||
if (deathmatch->integer)
|
||||
{
|
||||
if (!(ent->spawnflags & SPAWNFLAG_ITEM_DROPPED))
|
||||
if (!(ent->spawnflags & SPAWNFLAG_ITEM_DROPPED) && !is_dropped_from_death)
|
||||
SetRespawn(ent, gtime_t::from_sec(ent->item->quantity));
|
||||
}
|
||||
|
||||
@@ -307,7 +310,7 @@ void G_CheckPowerArmor(edict_t *ent)
|
||||
if (!ent->client->pers.inventory[IT_AMMO_CELLS])
|
||||
has_enough_cells = false;
|
||||
else if (ent->client->pers.autoshield >= AUTO_SHIELD_AUTO)
|
||||
has_enough_cells = !(ent->flags & FL_WANTS_POWER_ARMOR) || ent->client->pers.inventory[IT_AMMO_CELLS] > ent->client->pers.autoshield;
|
||||
has_enough_cells = (ent->flags & FL_WANTS_POWER_ARMOR) && ent->client->pers.inventory[IT_AMMO_CELLS] > ent->client->pers.autoshield;
|
||||
else
|
||||
has_enough_cells = true;
|
||||
|
||||
@@ -612,6 +615,10 @@ bool Pickup_Ammo(edict_t *ent, edict_t *other)
|
||||
|
||||
void Drop_Ammo(edict_t *ent, gitem_t *item)
|
||||
{
|
||||
// [Paril-KEX]
|
||||
if (G_CheckInfiniteAmmo(item))
|
||||
return;
|
||||
|
||||
item_id_t index = item->id;
|
||||
edict_t *dropped = Drop_Item(ent, item);
|
||||
dropped->spawnflags |= SPAWNFLAG_ITEM_DROPPED_PLAYER;
|
||||
@@ -638,7 +645,11 @@ void Drop_Ammo(edict_t *ent, gitem_t *item)
|
||||
|
||||
THINK(MegaHealth_think) (edict_t *self) -> void
|
||||
{
|
||||
if (self->owner->health > self->owner->max_health)
|
||||
if (self->owner->health > self->owner->max_health
|
||||
//ZOID
|
||||
&& !CTFHasRegeneration(self->owner)
|
||||
//ZOID
|
||||
)
|
||||
{
|
||||
self->nextthink = level.time + 1_sec;
|
||||
self->owner->health -= 1;
|
||||
@@ -668,13 +679,22 @@ bool Pickup_Health(edict_t *ent, edict_t *other)
|
||||
|
||||
other->health += count;
|
||||
|
||||
//ZOID
|
||||
if (ctf->integer && other->health > 250 && count > 25)
|
||||
other->health = 250;
|
||||
//ZOID
|
||||
|
||||
if (!(health_flags & HEALTH_IGNORE_MAX))
|
||||
{
|
||||
if (other->health > other->max_health)
|
||||
other->health = other->max_health;
|
||||
}
|
||||
|
||||
if (ent->item->tag & HEALTH_TIMED)
|
||||
if ((ent->item->tag & HEALTH_TIMED)
|
||||
//ZOID
|
||||
&& !CTFHasRegeneration(other)
|
||||
//ZOID
|
||||
)
|
||||
{
|
||||
if (!deathmatch->integer)
|
||||
{
|
||||
@@ -735,6 +755,9 @@ bool Pickup_Armor(edict_t *ent, edict_t *other)
|
||||
|
||||
old_armor_index = ArmorIndex(other);
|
||||
|
||||
// [Paril-KEX] for g_start_items
|
||||
int32_t base_count = ent->count ? ent->count : newinfo ? newinfo->base_count : 0;
|
||||
|
||||
// handle armor shards specially
|
||||
if (ent->item->id == IT_ARMOR_SHARD)
|
||||
{
|
||||
@@ -743,11 +766,10 @@ bool Pickup_Armor(edict_t *ent, edict_t *other)
|
||||
else
|
||||
other->client->pers.inventory[old_armor_index] += 2;
|
||||
}
|
||||
|
||||
// if player has no armor, just use it
|
||||
else if (!old_armor_index)
|
||||
{
|
||||
other->client->pers.inventory[ent->item->id] = newinfo->base_count;
|
||||
other->client->pers.inventory[ent->item->id] = base_count;
|
||||
}
|
||||
|
||||
// use the better armor
|
||||
@@ -766,7 +788,7 @@ bool Pickup_Armor(edict_t *ent, edict_t *other)
|
||||
// calc new armor values
|
||||
salvage = oldinfo->normal_protection / newinfo->normal_protection;
|
||||
salvagecount = (int) (salvage * other->client->pers.inventory[old_armor_index]);
|
||||
newcount = newinfo->base_count + salvagecount;
|
||||
newcount = base_count + salvagecount;
|
||||
if (newcount > newinfo->max_count)
|
||||
newcount = newinfo->max_count;
|
||||
|
||||
@@ -780,7 +802,7 @@ bool Pickup_Armor(edict_t *ent, edict_t *other)
|
||||
{
|
||||
// calc new armor values
|
||||
salvage = newinfo->normal_protection / oldinfo->normal_protection;
|
||||
salvagecount = (int) (salvage * newinfo->base_count);
|
||||
salvagecount = (int) (salvage * base_count);
|
||||
newcount = other->client->pers.inventory[old_armor_index] + salvagecount;
|
||||
if (newcount > oldinfo->max_count)
|
||||
newcount = oldinfo->max_count;
|
||||
@@ -1291,7 +1313,9 @@ void SpawnItem(edict_t *ent, gitem_t *item)
|
||||
{
|
||||
if (item->pickup == Pickup_Armor || item->pickup == Pickup_PowerArmor ||
|
||||
item->pickup == Pickup_Powerup || item->pickup == Pickup_Sphere || item->pickup == Pickup_Doppleganger ||
|
||||
(item->flags & IF_HEALTH) || (item->flags & IF_AMMO) || item->pickup == Pickup_Weapon || item->pickup == Pickup_Pack)
|
||||
(item->flags & IF_HEALTH) || (item->flags & IF_AMMO) || item->pickup == Pickup_Weapon || item->pickup == Pickup_Pack ||
|
||||
item->id == IT_ITEM_BANDOLIER || item->id == IT_ITEM_PACK ||
|
||||
item->id == IT_AMMO_NUKE)
|
||||
{
|
||||
G_FreeEdict(ent);
|
||||
return;
|
||||
@@ -2970,7 +2994,10 @@ gives +1 to maximum health
|
||||
/* use_name */ "Bandolier",
|
||||
/* pickup_name */ "$item_bandolier",
|
||||
/* pickup_name_definite */ "$item_bandolier_def",
|
||||
/* quantity */ 60
|
||||
/* quantity */ 60,
|
||||
/* ammo */ IT_NULL,
|
||||
/* chain */ IT_NULL,
|
||||
/* flags */ IF_POWERUP
|
||||
},
|
||||
|
||||
/*QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
|
||||
@@ -2991,6 +3018,9 @@ gives +1 to maximum health
|
||||
/* pickup_name */ "$item_ammo_pack",
|
||||
/* pickup_name_definite */ "$item_ammo_pack_def",
|
||||
/* quantity */ 180,
|
||||
/* ammo */ IT_NULL,
|
||||
/* chain */ IT_NULL,
|
||||
/* flags */ IF_POWERUP
|
||||
},
|
||||
|
||||
|
||||
@@ -3931,14 +3961,20 @@ void InitItems()
|
||||
if (!P_UseCoopInstancedItems() && (it.flags & IF_STAY_COOP))
|
||||
it.drop = nullptr;
|
||||
}
|
||||
else if (deathmatch->integer)
|
||||
{
|
||||
if (g_dm_weapons_stay->integer && it.drop == Drop_Weapon)
|
||||
it.drop = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [Paril-KEX]
|
||||
inline bool G_CanDropItem(const gitem_t &item)
|
||||
{
|
||||
if (!item.drop)
|
||||
return false;
|
||||
else if ((item.flags & IF_WEAPON) && !(item.flags & IF_AMMO) && deathmatch->integer && g_dm_weapons_stay->integer)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SetItemNames
|
||||
@@ -3988,7 +4024,7 @@ void SetItemNames()
|
||||
(itemlist[i].flags & IF_POWERUP_WHEEL) ? 1 : 0,
|
||||
itemlist[i].sort_id,
|
||||
itemlist[i].quantity_warn,
|
||||
itemlist[i].drop != nullptr ? 1 : 0
|
||||
G_CanDropItem(itemlist[i]) ? 1 : 0
|
||||
).data());
|
||||
itemlist[i].weapon_wheel_index = cs_index;
|
||||
cs_index++;
|
||||
@@ -4010,7 +4046,7 @@ void SetItemNames()
|
||||
gi.imageindex(itemlist[i].icon),
|
||||
(itemlist[i].flags & IF_POWERUP_ONOFF) ? 1 : 0,
|
||||
itemlist[i].sort_id,
|
||||
itemlist[i].drop != nullptr ? 1 : 0,
|
||||
G_CanDropItem(itemlist[i]) ? 1 : 0,
|
||||
itemlist[i].ammo ? GetItemByIndex(itemlist[i].ammo)->ammo_wheel_index : -1
|
||||
).data());
|
||||
itemlist[i].powerup_wheel_index = cs_index;
|
||||
|
||||
+154
-5
@@ -1177,6 +1177,7 @@ struct level_locals_t
|
||||
bool respawn_intermission; // only set once for respawning players
|
||||
|
||||
int32_t pic_health;
|
||||
int32_t pic_ping;
|
||||
|
||||
int32_t total_secrets;
|
||||
int32_t found_secrets;
|
||||
@@ -1257,6 +1258,8 @@ struct shadow_light_temp_t
|
||||
const char *lightstyletarget = nullptr;
|
||||
};
|
||||
|
||||
void G_LoadShadowLights();
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
// spawn_temp_t is only used to hold entity field values that
|
||||
@@ -1341,6 +1344,82 @@ DEFINE_DATA_FUNC(moveinfo_blocked, MOVEINFO_BLOCKED, void, edict_t *self, edict_
|
||||
#define MOVEINFO_BLOCKED(n) \
|
||||
SAVE_DATA_FUNC(n, MOVEINFO_BLOCKED, void, edict_t *self, edict_t *other)
|
||||
|
||||
// a struct that can store type-safe allocations
|
||||
// of a fixed amount of data. it self-destructs when
|
||||
// re-assigned. TODO: because edicts are still kind of
|
||||
// managed like C memory, the destructor may not be
|
||||
// called for a freed entity if this is stored as a member.
|
||||
template<typename T, int32_t tag>
|
||||
struct savable_allocated_memory_t
|
||||
{
|
||||
T *ptr;
|
||||
size_t count;
|
||||
|
||||
constexpr savable_allocated_memory_t(T *ptr, size_t count) :
|
||||
ptr(ptr),
|
||||
count(count)
|
||||
{
|
||||
}
|
||||
|
||||
inline ~savable_allocated_memory_t()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
// no copy
|
||||
constexpr savable_allocated_memory_t(const savable_allocated_memory_t &) = delete;
|
||||
constexpr savable_allocated_memory_t &operator=(const savable_allocated_memory_t &) = delete;
|
||||
|
||||
// free move
|
||||
constexpr savable_allocated_memory_t(savable_allocated_memory_t &&move)
|
||||
{
|
||||
ptr = move.ptr;
|
||||
count = move.count;
|
||||
|
||||
move.ptr = nullptr;
|
||||
move.count = 0;
|
||||
}
|
||||
|
||||
constexpr savable_allocated_memory_t &operator=(savable_allocated_memory_t &&move)
|
||||
{
|
||||
ptr = move.ptr;
|
||||
count = move.count;
|
||||
|
||||
move.ptr = nullptr;
|
||||
move.count = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void release()
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
gi.TagFree(ptr);
|
||||
count = 0;
|
||||
ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr explicit operator T *() { return ptr; }
|
||||
constexpr explicit operator const T *() const { return ptr; }
|
||||
|
||||
constexpr std::add_lvalue_reference_t<T> operator[](const size_t index) { return ptr[index]; }
|
||||
constexpr const std::add_lvalue_reference_t<T> operator[](const size_t index) const { return ptr[index]; }
|
||||
|
||||
constexpr size_t size() const { return count * sizeof(T); }
|
||||
constexpr operator bool() const { return !!ptr; }
|
||||
};
|
||||
|
||||
template<typename T, int32_t tag>
|
||||
inline savable_allocated_memory_t<T, tag> make_savable_memory(size_t count)
|
||||
{
|
||||
if (!count)
|
||||
return { nullptr, 0 };
|
||||
|
||||
return { reinterpret_cast<T *>(gi.TagMalloc(sizeof(T) * count, tag)), count };
|
||||
}
|
||||
|
||||
struct moveinfo_t
|
||||
{
|
||||
// fixed data
|
||||
@@ -1372,6 +1451,13 @@ struct moveinfo_t
|
||||
float decel_distance;
|
||||
save_moveinfo_endfunc_t endfunc;
|
||||
save_moveinfo_blocked_t blocked;
|
||||
|
||||
// [Paril-KEX] new accel state
|
||||
vec3_t curve_ref;
|
||||
savable_allocated_memory_t<float, TAG_LEVEL> curve_positions;
|
||||
size_t curve_frame;
|
||||
uint8_t subframe, num_subframes;
|
||||
size_t num_frames_done;
|
||||
};
|
||||
|
||||
struct mframe_t
|
||||
@@ -1693,9 +1779,6 @@ extern level_locals_t level;
|
||||
extern game_export_t globals;
|
||||
extern spawn_temp_t st;
|
||||
|
||||
extern int sm_meat_index;
|
||||
extern int snd_fry;
|
||||
|
||||
extern edict_t *g_edicts;
|
||||
|
||||
#include <random>
|
||||
@@ -2223,7 +2306,8 @@ void HuntTarget(edict_t *self, bool animate_state = true);
|
||||
bool infront(edict_t *self, edict_t *other);
|
||||
bool visible(edict_t *self, edict_t *other, bool through_glass = true);
|
||||
bool FacingIdeal(edict_t *self);
|
||||
|
||||
// [Paril-KEX] generic function
|
||||
bool M_CheckAttack_Base(edict_t *self, float stand_ground_chance, float melee_chance, float near_chance, float mid_chance, float far_chance, float strafe_scalar);
|
||||
|
||||
//
|
||||
// g_weapon.c
|
||||
@@ -2731,6 +2815,9 @@ constexpr gtime_t LADDER_SOUND_TIME = 300_ms;
|
||||
// time after damage that we can't respawn on a player for
|
||||
constexpr gtime_t COOP_DAMAGE_RESPAWN_TIME = 2000_ms;
|
||||
|
||||
// time after firing that we can't respawn on a player for
|
||||
constexpr gtime_t COOP_DAMAGE_FIRING_TIME = 2500_ms;
|
||||
|
||||
// this structure is cleared on each PutClientInServer(),
|
||||
// except for 'client->pers'
|
||||
struct gclient_t
|
||||
@@ -2917,6 +3004,8 @@ struct gclient_t
|
||||
height_fog_t heightfog;
|
||||
|
||||
gtime_t last_attacker_time;
|
||||
// saved - for coop; last time we were in a firing state
|
||||
gtime_t last_firing_time;
|
||||
};
|
||||
|
||||
// ==========================================
|
||||
@@ -3497,4 +3586,64 @@ inline void pierce_args_t::restore()
|
||||
}
|
||||
|
||||
num_pierced = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// [Paril-KEX] these are to fix a legacy bug with cached indices
|
||||
// in save games. these can *only* be static/globals!
|
||||
template<auto T>
|
||||
struct cached_assetindex
|
||||
{
|
||||
static cached_assetindex<T> *head;
|
||||
|
||||
const char *name;
|
||||
int32_t index = 0;
|
||||
cached_assetindex *next = nullptr;
|
||||
|
||||
inline cached_assetindex()
|
||||
{
|
||||
next = head;
|
||||
cached_assetindex<T>::head = this;
|
||||
}
|
||||
constexpr operator int32_t() const { return index; }
|
||||
|
||||
// assigned from spawn functions
|
||||
inline void assign(const char *name) { this->name = name; index = (gi.*T)(name); }
|
||||
// cleared before SpawnEntities
|
||||
constexpr void clear() { index = 0; }
|
||||
// re-find the index for the given cached entry, if we were cached
|
||||
// by the regular map load
|
||||
inline void reset() { if (index) index = (gi.*T)(this->name); }
|
||||
|
||||
static void reset_all()
|
||||
{
|
||||
auto asset = head;
|
||||
|
||||
while (asset)
|
||||
{
|
||||
asset->reset();
|
||||
asset = asset->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_all()
|
||||
{
|
||||
auto asset = head;
|
||||
|
||||
while (asset)
|
||||
{
|
||||
asset->clear();
|
||||
asset = asset->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
using cached_soundindex = cached_assetindex<&local_game_import_t::soundindex>;
|
||||
using cached_modelindex = cached_assetindex<&local_game_import_t::modelindex>;
|
||||
using cached_imageindex = cached_assetindex<&local_game_import_t::imageindex>;
|
||||
|
||||
template<> cached_soundindex *cached_soundindex::head;
|
||||
template<> cached_modelindex *cached_modelindex::head;
|
||||
template<> cached_imageindex *cached_imageindex::head;
|
||||
|
||||
extern cached_modelindex sm_meat_index;
|
||||
extern cached_soundindex snd_fry;
|
||||
@@ -22,8 +22,8 @@ local_game_import_t gi;
|
||||
game_export_t globals;
|
||||
spawn_temp_t st;
|
||||
|
||||
int sm_meat_index;
|
||||
int snd_fry;
|
||||
cached_modelindex sm_meat_index;
|
||||
cached_soundindex snd_fry;
|
||||
|
||||
edict_t *g_edicts;
|
||||
|
||||
@@ -333,7 +333,7 @@ void InitGame()
|
||||
g_friendly_fire = gi.cvar("g_friendly_fire", "0", CVAR_NOFLAGS);
|
||||
g_dm_force_respawn = gi.cvar("g_dm_force_respawn", "0", CVAR_NOFLAGS);
|
||||
g_dm_force_respawn_time = gi.cvar("g_dm_force_respawn_time", "0", CVAR_NOFLAGS);
|
||||
g_dm_spawn_farthest = gi.cvar("g_dm_spawn_farthest", "0", CVAR_NOFLAGS);
|
||||
g_dm_spawn_farthest = gi.cvar("g_dm_spawn_farthest", "1", CVAR_NOFLAGS);
|
||||
g_no_armor = gi.cvar("g_no_armor", "0", CVAR_NOFLAGS);
|
||||
g_dm_allow_exit = gi.cvar("g_dm_allow_exit", "0", CVAR_NOFLAGS);
|
||||
g_infinite_ammo = gi.cvar("g_infinite_ammo", "0", CVAR_LATCH);
|
||||
@@ -446,6 +446,9 @@ Q2GAME_API game_export_t *GetGameAPI(game_import_t *import)
|
||||
globals.Bot_TriggerEdict = Bot_TriggerEdict;
|
||||
globals.Bot_GetItemID = Bot_GetItemID;
|
||||
globals.Bot_UseItem = Bot_UseItem;
|
||||
globals.Edict_ForceLookAtPoint = Edict_ForceLookAtPoint;
|
||||
globals.Bot_PickedUpItem = Bot_PickedUpItem;
|
||||
|
||||
globals.Entity_IsVisibleToPlayer = Entity_IsVisibleToPlayer;
|
||||
globals.GetShadowLightData = GetShadowLightData;
|
||||
|
||||
|
||||
@@ -508,6 +508,7 @@ USE(light_use) (edict_t *self, edict_t *other, edict_t *activator) -> void
|
||||
// [Sam-KEX] For keeping track of shadow light parameters and setting them up on
|
||||
// the server side.
|
||||
|
||||
// TODO move to level_locals_t
|
||||
struct shadow_light_info_t
|
||||
{
|
||||
int entity_number;
|
||||
@@ -568,6 +569,57 @@ void setup_shadow_lights()
|
||||
shadowlightinfo[i].shadowlight.conedirection[2]).data());
|
||||
}
|
||||
}
|
||||
|
||||
// fix an oversight in shadow light code that causes
|
||||
// lights to be ordered wrong on return levels
|
||||
// if the spawn functions are changed.
|
||||
// this will work without changing the save/load code.
|
||||
void G_LoadShadowLights()
|
||||
{
|
||||
for (size_t i = 0; i < level.shadow_light_count; i++)
|
||||
{
|
||||
const char *cstr = gi.get_configstring(CS_SHADOWLIGHTS + i);
|
||||
const char *token = COM_ParseEx(&cstr, ";");
|
||||
|
||||
if (token && *token)
|
||||
{
|
||||
shadowlightinfo[i].entity_number = atoi(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.lighttype = (shadow_light_type_t) atoi(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.radius = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.resolution = atoi(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.intensity = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.fade_start = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.fade_end = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.lightstyle = atoi(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.coneangle = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.conedirection[0] = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.conedirection[1] = atof(token);
|
||||
|
||||
token = COM_ParseEx(&cstr, ";");
|
||||
shadowlightinfo[i].shadowlight.conedirection[2] = atof(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
static void setup_dynamic_light(edict_t* self)
|
||||
|
||||
+22
-2
@@ -791,6 +791,26 @@ void monster_dead(edict_t *self)
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
infront
|
||||
|
||||
returns 1 if the entity is in front (in sight) of self
|
||||
=============
|
||||
*/
|
||||
static bool projectile_infront(edict_t *self, edict_t *other)
|
||||
{
|
||||
vec3_t vec;
|
||||
float dot;
|
||||
vec3_t forward;
|
||||
|
||||
AngleVectors(self->s.angles, forward, nullptr, nullptr);
|
||||
vec = other->s.origin - self->s.origin;
|
||||
vec.normalize();
|
||||
dot = vec.dot(forward);
|
||||
return dot > 0.35f;
|
||||
}
|
||||
|
||||
static BoxEdictsResult_t M_CheckDodge_BoxEdictsFilter(edict_t *ent, void *data)
|
||||
{
|
||||
edict_t *self = (edict_t *) data;
|
||||
@@ -804,7 +824,7 @@ static BoxEdictsResult_t M_CheckDodge_BoxEdictsFilter(edict_t *ent, void *data)
|
||||
return BoxEdictsResult_t::Skip;
|
||||
|
||||
// projectile is behind us, we can't see it
|
||||
if (!infront(self, ent))
|
||||
if (!projectile_infront(self, ent))
|
||||
return BoxEdictsResult_t::Skip;
|
||||
|
||||
// will it hit us within 1 second? gives us enough time to dodge
|
||||
@@ -1065,7 +1085,7 @@ USE(monster_triggered_spawn_use) (edict_t *self, edict_t *other, edict_t *activa
|
||||
// we have a one frame delay here so we don't telefrag the guy who activated us
|
||||
self->think = monster_triggered_spawn;
|
||||
self->nextthink = level.time + FRAME_TIME_S;
|
||||
if (activator->client && !(self->hackflags & HACKFLAG_END_CUTSCENE))
|
||||
if (activator && activator->client && !(self->hackflags & HACKFLAG_END_CUTSCENE))
|
||||
self->enemy = activator;
|
||||
self->use = monster_use;
|
||||
|
||||
|
||||
@@ -450,13 +450,6 @@ retry:
|
||||
|
||||
if (!obstacle->inuse)
|
||||
goto retry;
|
||||
|
||||
// the move failed, bump all nextthink times and back out moves
|
||||
for (mv = ent; mv; mv = mv->teamchain)
|
||||
{
|
||||
if (mv->nextthink > 0_ms)
|
||||
mv->nextthink += FRAME_TIME_S;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -849,7 +842,11 @@ void SV_Physics_Step(edict_t *ent)
|
||||
ent->gravity = 1.0;
|
||||
// ========
|
||||
|
||||
G_TouchTriggers(ent);
|
||||
// [Paril-KEX] this is something N64 does to avoid doors opening
|
||||
// at the start of a level, which triggers some monsters to spawn.
|
||||
if (!level.is_n64 || level.time > FRAME_TIME_S)
|
||||
G_TouchTriggers(ent);
|
||||
|
||||
if (!ent->inuse)
|
||||
return;
|
||||
|
||||
|
||||
+148
-12
@@ -205,7 +205,8 @@ enum save_type_id_t
|
||||
ST_TIME, // serialized as milliseconds
|
||||
ST_DATA, // serialized as name of data ptr from global list; `tag` = list tag
|
||||
ST_INVENTORY, // serialized as classname => number key/value pairs
|
||||
ST_REINFORCEMENTS // serialized as array of data
|
||||
ST_REINFORCEMENTS, // serialized as array of data
|
||||
ST_SAVABLE_DYNAMIC // serialized similar to ST_FIXED_ARRAY but includes count
|
||||
};
|
||||
|
||||
struct save_struct_t;
|
||||
@@ -495,6 +496,21 @@ struct save_type_deducer<std::array<T, N>>
|
||||
}
|
||||
};
|
||||
|
||||
// savable_allocated_memory_t
|
||||
template<typename T, int32_t Tag>
|
||||
struct save_type_deducer<savable_allocated_memory_t<T, Tag>>
|
||||
{
|
||||
static constexpr save_field_t get_save_type(const char *name, size_t offset)
|
||||
{
|
||||
auto type = save_type_deducer<std::remove_extent_t<T>>::get_save_type(nullptr, 0).type;
|
||||
|
||||
if (type.id <= ST_BOOL || type.id >= ST_DOUBLE)
|
||||
return { name, offset, { ST_SAVABLE_DYNAMIC, ST_INVALID, Tag, []() { return save_type_deducer<std::remove_extent_t<T>>::get_save_type(nullptr, 0).type; } } };
|
||||
|
||||
return { name, offset, { ST_SAVABLE_DYNAMIC, type.id, Tag } };
|
||||
}
|
||||
};
|
||||
|
||||
// save_data_ref<T>
|
||||
template<typename T, size_t Tag>
|
||||
struct save_type_deducer<save_data_t<T, Tag>>
|
||||
@@ -681,6 +697,7 @@ SAVE_STRUCT_START
|
||||
FIELD_AUTO(intermission_angle),
|
||||
|
||||
// pic_health is set by worldspawn
|
||||
// pic_ping is set by worldspawn
|
||||
|
||||
FIELD_AUTO(total_secrets),
|
||||
FIELD_AUTO(found_secrets),
|
||||
@@ -910,6 +927,8 @@ SAVE_STRUCT_START
|
||||
FIELD_AUTO(sound_entity_time),
|
||||
FIELD_AUTO(sound2_entity),
|
||||
FIELD_AUTO(sound2_entity_time),
|
||||
|
||||
FIELD_AUTO(last_firing_time),
|
||||
SAVE_STRUCT_END
|
||||
#undef DECLARE_SAVE_STRUCT
|
||||
// clang-format on
|
||||
@@ -1107,6 +1126,13 @@ SAVE_STRUCT_START
|
||||
FIELD_AUTO(moveinfo.endfunc),
|
||||
FIELD_AUTO(moveinfo.blocked),
|
||||
|
||||
FIELD_AUTO(moveinfo.curve_ref),
|
||||
FIELD_AUTO(moveinfo.curve_positions),
|
||||
FIELD_AUTO(moveinfo.curve_frame),
|
||||
FIELD_AUTO(moveinfo.subframe),
|
||||
FIELD_AUTO(moveinfo.num_subframes),
|
||||
FIELD_AUTO(moveinfo.num_frames_done),
|
||||
|
||||
// monsterinfo_t
|
||||
FIELD_AUTO(monsterinfo.active_move),
|
||||
FIELD_AUTO(monsterinfo.next_move),
|
||||
@@ -1281,7 +1307,7 @@ SAVE_STRUCT_END
|
||||
#undef DECLARE_SAVE_STRUCT
|
||||
// clang-format on
|
||||
|
||||
size_t get_simple_type_size(save_type_id_t id)
|
||||
inline size_t get_simple_type_size(save_type_id_t id, bool fatal = true)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
@@ -1309,8 +1335,12 @@ size_t get_simple_type_size(save_type_id_t id)
|
||||
return sizeof(size_t);
|
||||
case ST_ITEM_INDEX:
|
||||
return sizeof(uint32_t);
|
||||
case ST_SAVABLE_DYNAMIC:
|
||||
return sizeof(savable_allocated_memory_t<void *, 0>);
|
||||
default:
|
||||
gi.Com_ErrorFmt("Can't calculate static size for type ID {}", (int32_t) id);
|
||||
if (fatal)
|
||||
gi.Com_ErrorFmt("Can't calculate static size for type ID {}", (int32_t) id);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1319,8 +1349,8 @@ size_t get_simple_type_size(save_type_id_t id)
|
||||
size_t get_complex_type_size(const save_type_t &type)
|
||||
{
|
||||
// these are simple types
|
||||
if ((type.id >= ST_BOOL && type.id <= ST_DOUBLE) || (type.id >= ST_ENTITY && type.id <= ST_TIME))
|
||||
return get_simple_type_size(type.id);
|
||||
if (auto simple = get_simple_type_size(type.id, false))
|
||||
return simple;
|
||||
|
||||
switch (type.id)
|
||||
{
|
||||
@@ -1448,7 +1478,7 @@ void read_save_type_json(const Json::Value &json, void *data, const save_type_t
|
||||
else if (json.asInt() < INT8_MIN || json.asInt() > INT8_MAX)
|
||||
json_print_error(field, "int8 out of range", false);
|
||||
else
|
||||
*((int8_t *) data) = json.isInt();
|
||||
*((int8_t *) data) = json.asInt();
|
||||
return;
|
||||
case ST_INT16:
|
||||
if (!json.isInt())
|
||||
@@ -1622,6 +1652,40 @@ void read_save_type_json(const Json::Value &json, void *data, const save_type_t
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
case ST_SAVABLE_DYNAMIC:
|
||||
if (!json.isArray())
|
||||
json_print_error(field, "expected array", false);
|
||||
else
|
||||
{
|
||||
savable_allocated_memory_t<void, 0> *savptr = (savable_allocated_memory_t<void, 0> *) data;
|
||||
size_t element_size;
|
||||
save_type_t element_type;
|
||||
|
||||
if (type->type_resolver)
|
||||
{
|
||||
element_type = type->type_resolver();
|
||||
element_size = get_complex_type_size(element_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
element_size = get_simple_type_size((save_type_id_t) type->tag);
|
||||
element_type = { (save_type_id_t) type->tag };
|
||||
}
|
||||
|
||||
savptr->count = json.size();
|
||||
savptr->ptr = gi.TagMalloc(element_size * savptr->count, type->count);
|
||||
|
||||
byte *out_element = (byte *) savptr->ptr;
|
||||
|
||||
for (Json::Value::ArrayIndex i = 0; i < savptr->count; i++, out_element += element_size)
|
||||
{
|
||||
const Json::Value &v = json[i];
|
||||
read_save_type_json(v, out_element, &element_type,
|
||||
fmt::format("[{}]", i).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
case ST_BITSET:
|
||||
type->read(data, json, field);
|
||||
@@ -2005,7 +2069,62 @@ bool write_save_type_json(const void *data, const save_type_t *type, bool null_f
|
||||
v.append(std::move(value));
|
||||
}
|
||||
|
||||
output = v;
|
||||
output = std::move(v);
|
||||
return true;
|
||||
}
|
||||
case ST_SAVABLE_DYNAMIC: {
|
||||
const savable_allocated_memory_t<void, 0> *savptr = (const savable_allocated_memory_t<void, 0> *) data;
|
||||
size_t i;
|
||||
size_t element_size;
|
||||
save_type_t element_type;
|
||||
|
||||
if (type->type_resolver)
|
||||
{
|
||||
element_type = type->type_resolver();
|
||||
element_size = get_complex_type_size(element_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
element_size = get_simple_type_size((save_type_id_t) type->tag);
|
||||
element_type = { (save_type_id_t) type->tag };
|
||||
}
|
||||
|
||||
const uint8_t *element = (const uint8_t *) savptr->ptr;
|
||||
|
||||
if (null_for_empty)
|
||||
{
|
||||
if (type->is_empty)
|
||||
{
|
||||
if (type->is_empty(data))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < savptr->count; i++, element += element_size)
|
||||
{
|
||||
Json::Value value;
|
||||
bool valid_value = write_save_type_json(element, &element_type, !element_type.never_empty, value);
|
||||
|
||||
if (valid_value)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == savptr->count)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
element = (const uint8_t *) savptr->ptr;
|
||||
Json::Value v(Json::arrayValue);
|
||||
|
||||
for (i = 0; i < savptr->count; i++, element += element_size)
|
||||
{
|
||||
Json::Value value;
|
||||
write_save_type_json(element, &element_type, false, value);
|
||||
v.append(std::move(value));
|
||||
}
|
||||
|
||||
output = std::move(v);
|
||||
return true;
|
||||
}
|
||||
case ST_BITSET:
|
||||
@@ -2020,7 +2139,7 @@ bool write_save_type_json(const void *data, const save_type_t *type, bool null_f
|
||||
if (null_for_empty && (!valid_value || !obj.size()))
|
||||
return false;
|
||||
|
||||
output = obj;
|
||||
output = std::move(obj);
|
||||
return true;
|
||||
}
|
||||
case ST_ENTITY: {
|
||||
@@ -2134,7 +2253,7 @@ bool write_save_type_json(const void *data, const save_type_t *type, bool null_f
|
||||
if (null_for_empty && inventory.empty())
|
||||
return false;
|
||||
|
||||
output = inventory;
|
||||
output = std::move(inventory);
|
||||
return true;
|
||||
}
|
||||
case ST_REINFORCEMENTS: {
|
||||
@@ -2165,7 +2284,7 @@ bool write_save_type_json(const void *data, const save_type_t *type, bool null_f
|
||||
reinforcements[i] = obj;
|
||||
}
|
||||
|
||||
output = reinforcements;
|
||||
output = std::move(reinforcements);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
@@ -2194,7 +2313,7 @@ bool write_save_struct_json(const void *data, const save_struct_t *structure, bo
|
||||
if (null_for_empty && obj.empty())
|
||||
return false;
|
||||
|
||||
output = obj;
|
||||
output = std::move(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2458,6 +2577,13 @@ void ReadLevelJson(const char *jsonString)
|
||||
}
|
||||
|
||||
G_PrecacheInventoryItems();
|
||||
|
||||
// clear cached indices
|
||||
cached_soundindex::reset_all();
|
||||
cached_modelindex::reset_all();
|
||||
cached_imageindex::reset_all();
|
||||
|
||||
G_LoadShadowLights();
|
||||
}
|
||||
|
||||
// [Paril-KEX]
|
||||
@@ -2468,6 +2594,16 @@ bool G_CanSave()
|
||||
gi.LocClient_Print(&g_edicts[1], PRINT_CENTER, "$g_no_save_dead");
|
||||
return false;
|
||||
}
|
||||
// don't allow saving during cameras/intermissions as this
|
||||
// causes the game to act weird when these are loaded
|
||||
else if (level.intermissiontime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ template<> cached_soundindex *cached_soundindex::head = nullptr;
|
||||
/*static*/ template<> cached_modelindex *cached_modelindex::head = nullptr;
|
||||
/*static*/ template<> cached_imageindex *cached_imageindex::head = nullptr;
|
||||
+14
-4
@@ -1144,6 +1144,11 @@ parsing textual entity definitions out of an ent file.
|
||||
*/
|
||||
void SpawnEntities(const char *mapname, const char *entities, const char *spawnpoint)
|
||||
{
|
||||
// clear cached indices
|
||||
cached_soundindex::clear_all();
|
||||
cached_modelindex::clear_all();
|
||||
cached_imageindex::clear_all();
|
||||
|
||||
edict_t *ent;
|
||||
int inhibit;
|
||||
const char *com_token;
|
||||
@@ -1509,7 +1514,7 @@ void SP_worldspawn(edict_t *ent)
|
||||
|
||||
gi.configstring(CS_MAXCLIENTS, G_Fmt("{}", game.maxclients).data());
|
||||
|
||||
if (level.is_n64)
|
||||
if (level.is_n64 && !deathmatch->integer)
|
||||
{
|
||||
gi.configstring(CONFIG_N64_PHYSICS, "1");
|
||||
pm_config.n64_physics = true;
|
||||
@@ -1544,7 +1549,7 @@ void SP_worldspawn(edict_t *ent)
|
||||
gi.cvar_set("sv_gravity", st.gravity);
|
||||
}
|
||||
|
||||
snd_fry = gi.soundindex("player/fry.wav"); // standing in lava / slime
|
||||
snd_fry.assign("player/fry.wav"); // standing in lava / slime
|
||||
|
||||
PrecacheItem(GetItemByIndex(IT_ITEM_COMPASS));
|
||||
PrecacheItem(GetItemByIndex(IT_WEAPON_BLASTER));
|
||||
@@ -1583,6 +1588,7 @@ void SP_worldspawn(edict_t *ent)
|
||||
gi.soundindex("*pain75_2.wav");
|
||||
gi.soundindex("*pain100_1.wav");
|
||||
gi.soundindex("*pain100_2.wav");
|
||||
gi.soundindex("*drown1.wav"); // [Paril-KEX]
|
||||
|
||||
// sexed models
|
||||
for (auto &item : itemlist)
|
||||
@@ -1624,6 +1630,10 @@ void SP_worldspawn(edict_t *ent)
|
||||
gi.soundindex("player/u_breath1.wav");
|
||||
gi.soundindex("player/u_breath2.wav");
|
||||
|
||||
gi.soundindex("player/wade1.wav");
|
||||
gi.soundindex("player/wade2.wav");
|
||||
gi.soundindex("player/wade3.wav");
|
||||
|
||||
gi.soundindex("items/pkup.wav"); // bonus item pickup
|
||||
gi.soundindex("world/land.wav"); // landing thud
|
||||
gi.soundindex("misc/h2ohit1.wav"); // landing splash
|
||||
@@ -1637,7 +1647,7 @@ void SP_worldspawn(edict_t *ent)
|
||||
|
||||
gi.soundindex("infantry/inflies1.wav");
|
||||
|
||||
sm_meat_index = gi.modelindex("models/objects/gibs/sm_meat/tris.md2");
|
||||
sm_meat_index.assign("models/objects/gibs/sm_meat/tris.md2");
|
||||
gi.modelindex("models/objects/gibs/arm/tris.md2");
|
||||
gi.modelindex("models/objects/gibs/bone/tris.md2");
|
||||
gi.modelindex("models/objects/gibs/bone2/tris.md2");
|
||||
@@ -1646,7 +1656,7 @@ void SP_worldspawn(edict_t *ent)
|
||||
gi.modelindex("models/objects/gibs/head2/tris.md2");
|
||||
gi.modelindex("models/objects/gibs/sm_metal/tris.md2");
|
||||
|
||||
gi.imageindex("loc_ping");
|
||||
level.pic_ping = gi.imageindex("loc_ping");
|
||||
|
||||
//
|
||||
// Setup light animation tables. 'a' is total darkness, 'z' is doublebright.
|
||||
|
||||
@@ -1327,7 +1327,15 @@ USE(use_target_camera) (edict_t *self, edict_t *other, edict_t *activator) -> vo
|
||||
|
||||
// respawn any dead clients
|
||||
if (client->health <= 0)
|
||||
{
|
||||
// give us our max health back since it will reset
|
||||
// to pers.health; in instanced items we'd lose the items
|
||||
// we touched so we always want to respawn with our max.
|
||||
if (P_UseCoopInstancedItems())
|
||||
client->client->pers.health = client->client->pers.max_health = client->max_health;
|
||||
|
||||
respawn(client);
|
||||
}
|
||||
|
||||
MoveClientToIntermission(client);
|
||||
}
|
||||
@@ -1606,6 +1614,9 @@ static float distance_to_poi(vec3_t start, vec3_t end)
|
||||
if (gi.GetPathToGoal(request, info))
|
||||
return info.pathDistSqr;
|
||||
|
||||
if (info.returnCode == PathReturnCode::NoNavAvailable)
|
||||
return (end - start).lengthSquared();
|
||||
|
||||
return std::numeric_limits<float>::infinity();
|
||||
}
|
||||
|
||||
@@ -1699,6 +1710,13 @@ USE(target_poi_use) (edict_t *ent, edict_t *other, edict_t *activator) -> void
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
// copy over POI stage value
|
||||
if (ent->count)
|
||||
{
|
||||
if (level.current_poi_stage <= ent->count)
|
||||
level.current_poi_stage = ent->count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+17
-17
@@ -480,7 +480,7 @@ constexpr spawnflags_t SPAWNFLAG_PUSH_START_OFF = 0x08_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_PUSH_CLIP = 0x10_spawnflag;
|
||||
// PGM
|
||||
|
||||
static int windsound;
|
||||
static cached_soundindex windsound;
|
||||
|
||||
TOUCH(trigger_push_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
|
||||
{
|
||||
@@ -601,7 +601,7 @@ void SP_trigger_push(edict_t *self)
|
||||
{
|
||||
InitTrigger(self);
|
||||
if (!(self->spawnflags & SPAWNFLAG_PUSH_SILENT))
|
||||
windsound = gi.soundindex("misc/windfly.wav");
|
||||
windsound.assign("misc/windfly.wav");
|
||||
self->touch = trigger_push_touch;
|
||||
|
||||
// RAFAEL
|
||||
@@ -1054,11 +1054,11 @@ TOUCH(trigger_fog_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool
|
||||
if (self->spawnflags.has(SPAWNFLAG_FOG_AFFECT_FOG))
|
||||
{
|
||||
other->client->pers.wanted_fog = {
|
||||
lerp(fog_value_storage->fog.density, fog_value_storage->fog.density_off, dist),
|
||||
lerp(fog_value_storage->fog.color[0], fog_value_storage->fog.color_off[0], dist),
|
||||
lerp(fog_value_storage->fog.color[1], fog_value_storage->fog.color_off[1], dist),
|
||||
lerp(fog_value_storage->fog.color[2], fog_value_storage->fog.color_off[2], dist),
|
||||
lerp(fog_value_storage->fog.sky_factor, fog_value_storage->fog.sky_factor_off, dist)
|
||||
lerp(fog_value_storage->fog.density_off, fog_value_storage->fog.density, dist),
|
||||
lerp(fog_value_storage->fog.color_off[0], fog_value_storage->fog.color[0], dist),
|
||||
lerp(fog_value_storage->fog.color_off[1], fog_value_storage->fog.color[1], dist),
|
||||
lerp(fog_value_storage->fog.color_off[2], fog_value_storage->fog.color[2], dist),
|
||||
lerp(fog_value_storage->fog.sky_factor_off, fog_value_storage->fog.sky_factor, dist)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1066,19 +1066,19 @@ TOUCH(trigger_fog_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool
|
||||
{
|
||||
other->client->pers.wanted_heightfog = {
|
||||
{
|
||||
lerp(fog_value_storage->heightfog.start_color[0], fog_value_storage->heightfog.start_color_off[0], dist),
|
||||
lerp(fog_value_storage->heightfog.start_color[1], fog_value_storage->heightfog.start_color_off[1], dist),
|
||||
lerp(fog_value_storage->heightfog.start_color[2], fog_value_storage->heightfog.start_color_off[2], dist),
|
||||
lerp(fog_value_storage->heightfog.start_dist, fog_value_storage->heightfog.start_dist_off, dist)
|
||||
lerp(fog_value_storage->heightfog.start_color_off[0], fog_value_storage->heightfog.start_color[0], dist),
|
||||
lerp(fog_value_storage->heightfog.start_color_off[1], fog_value_storage->heightfog.start_color[1], dist),
|
||||
lerp(fog_value_storage->heightfog.start_color_off[2], fog_value_storage->heightfog.start_color[2], dist),
|
||||
lerp(fog_value_storage->heightfog.start_dist_off, fog_value_storage->heightfog.start_dist, dist)
|
||||
},
|
||||
{
|
||||
lerp(fog_value_storage->heightfog.end_color[0], fog_value_storage->heightfog.end_color_off[0], dist),
|
||||
lerp(fog_value_storage->heightfog.end_color[1], fog_value_storage->heightfog.end_color_off[1], dist),
|
||||
lerp(fog_value_storage->heightfog.end_color[2], fog_value_storage->heightfog.end_color_off[2], dist),
|
||||
lerp(fog_value_storage->heightfog.end_dist, fog_value_storage->heightfog.end_dist_off, dist)
|
||||
lerp(fog_value_storage->heightfog.end_color_off[0], fog_value_storage->heightfog.end_color[0], dist),
|
||||
lerp(fog_value_storage->heightfog.end_color_off[1], fog_value_storage->heightfog.end_color[1], dist),
|
||||
lerp(fog_value_storage->heightfog.end_color_off[2], fog_value_storage->heightfog.end_color[2], dist),
|
||||
lerp(fog_value_storage->heightfog.end_dist_off, fog_value_storage->heightfog.end_dist, dist)
|
||||
},
|
||||
lerp(fog_value_storage->heightfog.falloff, fog_value_storage->heightfog.falloff_off, dist),
|
||||
lerp(fog_value_storage->heightfog.density, fog_value_storage->heightfog.density_off, dist)
|
||||
lerp(fog_value_storage->heightfog.falloff_off, fog_value_storage->heightfog.falloff, dist),
|
||||
lerp(fog_value_storage->heightfog.density_off, fog_value_storage->heightfog.density, dist)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+20
-4
@@ -447,8 +447,13 @@ void G_TouchTriggers(edict_t *ent)
|
||||
// to see if we need to collide against them
|
||||
void G_TouchProjectiles(edict_t *ent, vec3_t previous_origin)
|
||||
{
|
||||
struct skipped_projectile
|
||||
{
|
||||
edict_t *projectile;
|
||||
int32_t spawn_count;
|
||||
};
|
||||
// a bit ugly, but we'll store projectiles we are ignoring here.
|
||||
static std::vector<edict_t *> skipped;
|
||||
static std::vector<skipped_projectile> skipped;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -462,7 +467,7 @@ void G_TouchProjectiles(edict_t *ent, vec3_t previous_origin)
|
||||
// always skip this projectile since certain conditions may cause the projectile
|
||||
// to not disappear immediately
|
||||
tr.ent->svflags &= ~SVF_PROJECTILE;
|
||||
skipped.push_back(tr.ent);
|
||||
skipped.push_back({ tr.ent, tr.ent->spawn_count });
|
||||
|
||||
// if we're both players and it's coop, allow the projectile to "pass" through
|
||||
if (ent->client && tr.ent->owner && tr.ent->owner->client && !G_ShouldPlayersCollide(true))
|
||||
@@ -472,7 +477,8 @@ void G_TouchProjectiles(edict_t *ent, vec3_t previous_origin)
|
||||
}
|
||||
|
||||
for (auto &skip : skipped)
|
||||
skip->svflags |= SVF_PROJECTILE;
|
||||
if (skip.projectile->inuse && skip.projectile->spawn_count == skip.spawn_count)
|
||||
skip.projectile->svflags |= SVF_PROJECTILE;
|
||||
|
||||
skipped.clear();
|
||||
}
|
||||
@@ -526,7 +532,7 @@ bool KillBox(edict_t *ent, bool from_spawning, mod_id_t mod, bool bsp_clipping)
|
||||
|
||||
if (hit == ent)
|
||||
continue;
|
||||
else if (!hit->inuse || !hit->takedamage || !hit->solid || hit->solid == SOLID_TRIGGER)
|
||||
else if (!hit->inuse || !hit->takedamage || !hit->solid || hit->solid == SOLID_TRIGGER || hit->solid == SOLID_BSP)
|
||||
continue;
|
||||
else if (hit->client && !(mask & CONTENTS_PLAYER))
|
||||
continue;
|
||||
@@ -539,6 +545,16 @@ bool KillBox(edict_t *ent, bool from_spawning, mod_id_t mod, bool bsp_clipping)
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Paril-KEX] don't allow telefragging of friends in coop.
|
||||
// the player that is about to be telefragged will have collision
|
||||
// disabled until another time.
|
||||
if (ent->client && hit->client && coop->integer)
|
||||
{
|
||||
hit->clipmask &= ~CONTENTS_PLAYER;
|
||||
ent->clipmask &= ~CONTENTS_PLAYER;
|
||||
continue;
|
||||
}
|
||||
|
||||
T_Damage(hit, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION, mod);
|
||||
}
|
||||
|
||||
|
||||
@@ -863,7 +863,7 @@ void fire_rail(edict_t *self, const vec3_t &start, const vec3_t &aimdir, int dam
|
||||
if (binary_positional_search(org, start, args.tr.endpos, gi.inPHS, 3))
|
||||
{
|
||||
gi.WriteByte(svc_temp_entity);
|
||||
gi.WriteByte(g_instagib->integer ? TE_RAILTRAIL2 : TE_RAILTRAIL);
|
||||
gi.WriteByte((deathmatch->integer && g_instagib->integer) ? TE_RAILTRAIL2 : TE_RAILTRAIL);
|
||||
gi.WritePosition(start);
|
||||
gi.WritePosition(args.tr.endpos);
|
||||
gi.unicast(player, false, unicast_key);
|
||||
|
||||
+9
-7
@@ -110,7 +110,7 @@ constexpr bit_t<n> bit_v = 1ull << n;
|
||||
|
||||
// game.h -- game dll information visible to server
|
||||
// PARIL_NEW_API - value likely not used by any other Q2-esque engine in the wild
|
||||
constexpr int32_t GAME_API_VERSION = 2022;
|
||||
constexpr int32_t GAME_API_VERSION = 2023;
|
||||
constexpr int32_t CGAME_API_VERSION = 2022;
|
||||
|
||||
// forward declarations
|
||||
@@ -238,6 +238,7 @@ enum contents_t : uint32_t
|
||||
|
||||
// remaining contents are non-visible, and don't eat brushes
|
||||
|
||||
CONTENTS_NO_WATERJUMP = bit_v<13>, // [Paril-KEX] this brush cannot be waterjumped out of
|
||||
CONTENTS_PROJECTILECLIP = bit_v<14>, // [Paril-KEX] projectiles will collide with this
|
||||
|
||||
CONTENTS_AREAPORTAL = bit_v<15>,
|
||||
@@ -504,6 +505,7 @@ struct pmove_t
|
||||
gvec4_t screen_blend;
|
||||
refdef_flags_t rdflags; // merged with rdflags from server
|
||||
bool jump_sound; // play jump sound
|
||||
bool step_clip; // we clipped on top of an object from below
|
||||
float impact_delta; // impact delta, for falling damage
|
||||
};
|
||||
|
||||
@@ -1740,8 +1742,6 @@ enum sv_ent_flags_t : uint64_t {
|
||||
};
|
||||
MAKE_ENUM_BITFLAGS( sv_ent_flags_t );
|
||||
|
||||
#include <bitset>
|
||||
|
||||
static constexpr int Max_Armor_Types = 3;
|
||||
|
||||
struct armorInfo_t {
|
||||
@@ -1780,7 +1780,6 @@ struct sv_entity_t {
|
||||
char netname[ MAX_NETNAME ];
|
||||
int32_t inventory[ MAX_ITEMS ] = { 0 };
|
||||
armorInfo_t armor_info[ Max_Armor_Types ];
|
||||
std::bitset<MAX_CLIENTS> pickedup_list;
|
||||
};
|
||||
|
||||
#ifndef GAME_INCLUDE
|
||||
@@ -2005,9 +2004,10 @@ struct game_import_t
|
||||
void (*Draw_Bounds)(gvec3_cref_t mins, gvec3_cref_t maxs, const rgba_t &color, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_Sphere)(gvec3_cref_t origin, const float radius, const rgba_t &color, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_OrientedWorldText)(gvec3_cref_t origin, const char * text, const rgba_t &color, const float size, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_StaticWorldText )(gvec3_cref_t origin, gvec3_cref_t angles, const char * text, const rgba_t & color, const float size, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_StaticWorldText)(gvec3_cref_t origin, gvec3_cref_t angles, const char * text, const rgba_t & color, const float size, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_Cylinder)(gvec3_cref_t origin, const float halfHeight, const float radius, const rgba_t &color, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_Ray)(gvec3_cref_t origin, gvec3_cref_t direction, const float length, const float size, const rgba_t &color, const float lifeTime, const bool depthTest);
|
||||
void (*Draw_Arrow)(gvec3_cref_t start, gvec3_cref_t end, const float size, const rgba_t & lineColor, const rgba_t & arrowColor, const float lifeTime, const bool depthTest);
|
||||
|
||||
// scoreboard
|
||||
void (*ReportMatchDetails_Multicast)(bool is_end);
|
||||
@@ -2139,6 +2139,8 @@ struct game_export_t
|
||||
void (*Bot_TriggerEdict)(edict_t * botEdict, edict_t * edict);
|
||||
void (*Bot_UseItem)(edict_t * botEdict, const int32_t itemID);
|
||||
int32_t (*Bot_GetItemID)(const char * classname);
|
||||
void (*Edict_ForceLookAtPoint)(edict_t * edict, gvec3_cref_t point);
|
||||
bool (*Bot_PickedUpItem )(edict_t * botEdict, edict_t * itemEdict);
|
||||
|
||||
// [KEX]: Checks entity visibility instancing
|
||||
bool (*Entity_IsVisibleToPlayer)(edict_t* ent, edict_t* player);
|
||||
@@ -2167,7 +2169,7 @@ struct cg_server_data_t
|
||||
std::array<int16_t, MAX_ITEMS> inventory;
|
||||
};
|
||||
|
||||
constexpr int32_t PROTOCOL_VERSION_3XX = 34;
|
||||
constexpr int32_t PROTOCOL_VERSION_3XX = 34;
|
||||
constexpr int32_t PROTOCOL_VERSION_DEMOS = 2022;
|
||||
constexpr int32_t PROTOCOL_VERSION = 2023;
|
||||
|
||||
@@ -2260,7 +2262,7 @@ struct cgame_export_t
|
||||
int apiversion;
|
||||
|
||||
// the init/shutdown functions will be called between levels/connections
|
||||
// (cgame does not run in menus)
|
||||
// and when the client initially loads.
|
||||
void (*Init)();
|
||||
void (*Shutdown)();
|
||||
|
||||
|
||||
+13
-13
@@ -12,9 +12,9 @@ TANK
|
||||
#include "m_arachnid.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_death;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
MONSTERINFO_SIGHT(arachnid_sight) (edict_t *self, edict_t *other) -> void
|
||||
{
|
||||
@@ -51,7 +51,7 @@ MONSTERINFO_STAND(arachnid_stand) (edict_t *self) -> void
|
||||
// walk
|
||||
//
|
||||
|
||||
static int sound_step;
|
||||
static cached_soundindex sound_step;
|
||||
|
||||
void arachnid_footstep(edict_t *self)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ PAIN(arachnid_pain) (edict_t *self, edict_t *other, float kick, int damage, cons
|
||||
M_SetAnimation(self, &arachnid_move_pain2);
|
||||
}
|
||||
|
||||
static int sound_charge;
|
||||
static cached_soundindex sound_charge;
|
||||
|
||||
void arachnid_charge_rail(edict_t *self)
|
||||
{
|
||||
@@ -229,7 +229,7 @@ mframe_t arachnid_frames_attack_up1[] = {
|
||||
};
|
||||
MMOVE_T(arachnid_attack_up1) = { FRAME_rails_up1, FRAME_rails_up16, arachnid_frames_attack_up1, arachnid_run };
|
||||
|
||||
static int sound_melee, sound_melee_hit;
|
||||
static cached_soundindex sound_melee, sound_melee_hit;
|
||||
|
||||
void arachnid_melee_charge(edict_t *self)
|
||||
{
|
||||
@@ -348,13 +348,13 @@ void SP_monster_arachnid(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_step = gi.soundindex("insane/insane11.wav");
|
||||
sound_charge = gi.soundindex("gladiator/railgun.wav");
|
||||
sound_melee = gi.soundindex("gladiator/melee3.wav");
|
||||
sound_melee_hit = gi.soundindex("gladiator/melee2.wav");
|
||||
sound_pain = gi.soundindex("arachnid/pain.wav");
|
||||
sound_death = gi.soundindex("arachnid/death.wav");
|
||||
sound_sight = gi.soundindex("arachnid/sight.wav");
|
||||
sound_step.assign("insane/insane11.wav");
|
||||
sound_charge.assign("gladiator/railgun.wav");
|
||||
sound_melee.assign("gladiator/melee3.wav");
|
||||
sound_melee_hit.assign("gladiator/melee2.wav");
|
||||
sound_pain.assign("arachnid/pain.wav");
|
||||
sound_death.assign("arachnid/death.wav");
|
||||
sound_sight.assign("arachnid/sight.wav");
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/arachnid/tris.md2");
|
||||
self->mins = { -48, -48, -20 };
|
||||
|
||||
+43
-29
@@ -13,15 +13,16 @@ BERSERK
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_BERSERK_NOJUMPING = 8_spawnflag;
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_die;
|
||||
static int sound_idle;
|
||||
static int sound_idle2;
|
||||
static int sound_punch;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_thud;
|
||||
static int sound_jump;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_idle2;
|
||||
static cached_soundindex sound_punch;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_thud;
|
||||
static cached_soundindex sound_explod;
|
||||
static cached_soundindex sound_jump;
|
||||
|
||||
MONSTERINFO_SIGHT(berserk_sight) (edict_t *self, edict_t *other) -> void
|
||||
{
|
||||
@@ -215,7 +216,7 @@ void T_SlamRadiusDamage(vec3_t point, edict_t *inflictor, edict_t *attacker, flo
|
||||
vec3_t v;
|
||||
vec3_t dir;
|
||||
|
||||
while ((ent = findradius(ent, inflictor->s.origin, radius)) != nullptr)
|
||||
while ((ent = findradius(ent, inflictor->s.origin, radius * 2.f)) != nullptr)
|
||||
{
|
||||
if (ent == ignore)
|
||||
continue;
|
||||
@@ -223,18 +224,29 @@ void T_SlamRadiusDamage(vec3_t point, edict_t *inflictor, edict_t *attacker, flo
|
||||
continue;
|
||||
if (!CanDamage(ent, inflictor))
|
||||
continue;
|
||||
// don't hit players in mid air
|
||||
if (ent->client && !ent->groundentity)
|
||||
continue;
|
||||
|
||||
v = closest_point_to_box(point, ent->s.origin + ent->mins, ent->s.origin + ent->maxs) - point;
|
||||
points = damage - 0.5f * v.length();
|
||||
if (ent == attacker)
|
||||
points = points * 0.5f;
|
||||
points = max(1.f, points);
|
||||
|
||||
// calculate contribution amount
|
||||
float amount = min(1.f, 1.f - (v.length() / radius));
|
||||
|
||||
// too far away
|
||||
if (amount <= 0.f)
|
||||
continue;
|
||||
|
||||
amount *= amount;
|
||||
|
||||
// damage & kick are exponentially scaled
|
||||
points = max(1.f, damage * amount);
|
||||
|
||||
dir = (ent->s.origin - point).normalized();
|
||||
|
||||
// keep the point at their feet so they always get knocked up
|
||||
point[2] = ent->absmin[2];
|
||||
T_Damage(ent, inflictor, attacker, dir, point, dir, (int) points, (int) kick,
|
||||
T_Damage(ent, inflictor, attacker, dir, point, dir, (int) points, (int) (kick * amount),
|
||||
DAMAGE_RADIUS, mod);
|
||||
|
||||
if (ent->client)
|
||||
@@ -245,6 +257,7 @@ void T_SlamRadiusDamage(vec3_t point, edict_t *inflictor, edict_t *attacker, flo
|
||||
static void berserk_attack_slam(edict_t *self)
|
||||
{
|
||||
gi.sound(self, CHAN_WEAPON, sound_thud, 1, ATTN_NORM, 0);
|
||||
gi.sound(self, CHAN_AUTO, sound_explod, 0.75f, ATTN_NORM, 0);
|
||||
gi.WriteByte(svc_temp_entity);
|
||||
gi.WriteByte(TE_BERSERK_SLAM);
|
||||
vec3_t f, r, start;
|
||||
@@ -258,7 +271,7 @@ static void berserk_attack_slam(edict_t *self)
|
||||
self->velocity = {};
|
||||
self->flags |= FL_KILL_VELOCITY;
|
||||
|
||||
T_SlamRadiusDamage(tr.endpos, self, self, 35, 150.f, self, 275, MOD_UNKNOWN);
|
||||
T_SlamRadiusDamage(tr.endpos, self, self, 8, 300.f, self, 165, MOD_UNKNOWN);
|
||||
}
|
||||
|
||||
TOUCH(berserk_jump_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool other_touching_self) -> void
|
||||
@@ -309,7 +322,6 @@ void berserk_jump_takeoff(edict_t *self)
|
||||
self->monsterinfo.aiflags |= AI_DUCKED;
|
||||
self->monsterinfo.attack_finished = level.time + 3_sec;
|
||||
self->touch = berserk_jump_touch;
|
||||
gi.sound(self, CHAN_WEAPON, sound_jump, 1, ATTN_NORM, 0);
|
||||
berserk_high_gravity(self);
|
||||
}
|
||||
|
||||
@@ -332,15 +344,15 @@ void berserk_check_landing(edict_t *self)
|
||||
}
|
||||
|
||||
if (level.time > self->monsterinfo.attack_finished)
|
||||
self->monsterinfo.nextframe = FRAME_slam2;
|
||||
self->monsterinfo.nextframe = FRAME_slam3;
|
||||
else
|
||||
self->monsterinfo.nextframe = FRAME_slam5;
|
||||
}
|
||||
|
||||
mframe_t berserk_frames_attack_strike[] = {
|
||||
{ ai_charge },
|
||||
{ ai_charge, 0, berserk_jump_takeoff },
|
||||
{ ai_move, 0, berserk_high_gravity },
|
||||
{ ai_charge },
|
||||
{ ai_move, 0, berserk_jump_takeoff },
|
||||
{ ai_move, 0, berserk_high_gravity },
|
||||
{ ai_move, 0, berserk_check_landing },
|
||||
{ ai_move, 0, monster_footstep },
|
||||
@@ -440,6 +452,7 @@ MONSTERINFO_ATTACK(berserk_attack) (edict_t *self) -> void
|
||||
{
|
||||
M_SetAnimation(self, &berserk_move_attack_strike);
|
||||
// don't do this for a while, otherwise we just keep doing it
|
||||
gi.sound(self, CHAN_WEAPON, sound_jump, 1, ATTN_NORM, 0);
|
||||
self->timestamp = level.time + 5_sec;
|
||||
}
|
||||
else if (self->monsterinfo.active_move == &berserk_move_run1 && (range_to(self, self->enemy) <= RANGE_NEAR))
|
||||
@@ -763,15 +776,16 @@ void SP_monster_berserk(edict_t *self)
|
||||
}
|
||||
|
||||
// pre-caches
|
||||
sound_pain = gi.soundindex("berserk/berpain2.wav");
|
||||
sound_die = gi.soundindex("berserk/berdeth2.wav");
|
||||
sound_idle = gi.soundindex("berserk/beridle1.wav");
|
||||
sound_idle2 = gi.soundindex("berserk/idle.wav");
|
||||
sound_punch = gi.soundindex("berserk/attack.wav");
|
||||
sound_search = gi.soundindex("berserk/bersrch1.wav");
|
||||
sound_sight = gi.soundindex("berserk/sight.wav");
|
||||
sound_thud = gi.soundindex("mutant/thud1.wav");
|
||||
sound_jump = gi.soundindex("berserk/jump.wav");
|
||||
sound_pain.assign("berserk/berpain2.wav");
|
||||
sound_die.assign("berserk/berdeth2.wav");
|
||||
sound_idle.assign("berserk/beridle1.wav");
|
||||
sound_idle2.assign("berserk/idle.wav");
|
||||
sound_punch.assign("berserk/attack.wav");
|
||||
sound_search.assign("berserk/bersrch1.wav");
|
||||
sound_sight.assign("berserk/sight.wav");
|
||||
sound_thud.assign("mutant/thud1.wav");
|
||||
sound_explod.assign("world/explod2.wav");
|
||||
sound_jump.assign("berserk/jump.wav");
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/berserk/tris.md2");
|
||||
|
||||
|
||||
+12
-95
@@ -17,11 +17,11 @@ constexpr spawnflags_t SPAWNFLAG_BOSS2_N64 = 8_spawnflag;
|
||||
|
||||
bool infront(edict_t *self, edict_t *other);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_death;
|
||||
static int sound_search1;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_search1;
|
||||
|
||||
MONSTERINFO_SEARCH(boss2_search) (edict_t *self) -> void
|
||||
{
|
||||
@@ -607,93 +607,10 @@ DIE(boss2_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage
|
||||
M_SetAnimation(self, &boss2_move_death);
|
||||
}
|
||||
|
||||
// [Paril-KEX] use generic function
|
||||
MONSTERINFO_CHECKATTACK(Boss2_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
float enemy_yaw;
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_PLAYER | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
{
|
||||
// PGM - we want them to go ahead and shoot at info_notnulls if they can.
|
||||
if (self->enemy->solid != SOLID_NOT || tr.fraction < 1.0f) // PGM
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
// melee attack
|
||||
if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
if (self->monsterinfo.melee)
|
||||
self->monsterinfo.attack_state = AS_MELEE;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// missile attack
|
||||
if (!self->monsterinfo.attack)
|
||||
return false;
|
||||
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (enemy_range > RANGE_MID)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
|
||||
// PGM - go ahead and shoot every time if it's a info_notnull
|
||||
if ((frandom() < chance) || (self->enemy->solid == SOLID_NOT))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
self->monsterinfo.attack_finished = level.time + random_time(2_sec);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->flags & FL_FLY)
|
||||
{
|
||||
if (frandom() < 0.3f)
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.8f, 0.8f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
/*QUAKED monster_boss2 (1 .5 0) (-56 -56 0) (56 56 80) Ambush Trigger_Spawn Sight Hyperblaster
|
||||
@@ -705,11 +622,11 @@ void SP_monster_boss2(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("bosshovr/bhvpain1.wav");
|
||||
sound_pain2 = gi.soundindex("bosshovr/bhvpain2.wav");
|
||||
sound_pain3 = gi.soundindex("bosshovr/bhvpain3.wav");
|
||||
sound_death = gi.soundindex("bosshovr/bhvdeth1.wav");
|
||||
sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav");
|
||||
sound_pain1.assign("bosshovr/bhvpain1.wav");
|
||||
sound_pain2.assign("bosshovr/bhvpain2.wav");
|
||||
sound_pain3.assign("bosshovr/bhvpain3.wav");
|
||||
sound_death.assign("bosshovr/bhvdeth1.wav");
|
||||
sound_search1.assign("bosshovr/bhvunqv1.wav");
|
||||
|
||||
gi.soundindex("tank/rocket.wav");
|
||||
|
||||
|
||||
+33
-111
@@ -14,20 +14,20 @@ jorg
|
||||
|
||||
void SP_monster_makron(edict_t *self);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_idle;
|
||||
static int sound_death;
|
||||
static int sound_search1;
|
||||
static int sound_search2;
|
||||
static int sound_search3;
|
||||
static int sound_attack1, sound_attack1_loop, sound_attack1_end;
|
||||
static int sound_attack2, sound_bfg_fire;
|
||||
static int sound_firegun;
|
||||
static int sound_step_left;
|
||||
static int sound_step_right;
|
||||
static int sound_death_hit;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_search1;
|
||||
static cached_soundindex sound_search2;
|
||||
static cached_soundindex sound_search3;
|
||||
static cached_soundindex sound_attack1, sound_attack1_loop, sound_attack1_end;
|
||||
static cached_soundindex sound_attack2, sound_bfg_fire;
|
||||
static cached_soundindex sound_firegun;
|
||||
static cached_soundindex sound_step_left;
|
||||
static cached_soundindex sound_step_right;
|
||||
static cached_soundindex sound_death_hit;
|
||||
|
||||
void MakronToss(edict_t *self);
|
||||
|
||||
@@ -559,88 +559,10 @@ DIE(jorg_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage,
|
||||
M_SetAnimation(self, &jorg_move_death);
|
||||
}
|
||||
|
||||
// [Paril-KEX] use generic function
|
||||
MONSTERINFO_CHECKATTACK(Jorg_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
float enemy_yaw;
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
return false;
|
||||
}
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
// melee attack
|
||||
if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
if (self->monsterinfo.melee)
|
||||
self->monsterinfo.attack_state = AS_MELEE;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// missile attack
|
||||
if (!self->monsterinfo.attack)
|
||||
return false;
|
||||
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (enemy_range > RANGE_MID)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.2f;
|
||||
}
|
||||
|
||||
if (frandom() < chance)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
self->monsterinfo.attack_finished = level.time + random_time(2_sec);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->flags & FL_FLY)
|
||||
{
|
||||
if (frandom() < 0.3f)
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.4f, 0.2f, 0.0f, 0.f);
|
||||
}
|
||||
|
||||
void MakronPrecache();
|
||||
@@ -654,23 +576,23 @@ void SP_monster_jorg(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("boss3/bs3pain1.wav");
|
||||
sound_pain2 = gi.soundindex("boss3/bs3pain2.wav");
|
||||
sound_pain3 = gi.soundindex("boss3/bs3pain3.wav");
|
||||
sound_death = gi.soundindex("boss3/bs3deth1.wav");
|
||||
sound_attack1 = gi.soundindex("boss3/bs3atck1.wav");
|
||||
sound_attack1_loop = gi.soundindex("boss3/bs3atck1_loop.wav");
|
||||
sound_attack1_end = gi.soundindex("boss3/bs3atck1_end.wav");
|
||||
sound_attack2 = gi.soundindex("boss3/bs3atck2.wav");
|
||||
sound_search1 = gi.soundindex("boss3/bs3srch1.wav");
|
||||
sound_search2 = gi.soundindex("boss3/bs3srch2.wav");
|
||||
sound_search3 = gi.soundindex("boss3/bs3srch3.wav");
|
||||
sound_idle = gi.soundindex("boss3/bs3idle1.wav");
|
||||
sound_step_left = gi.soundindex("boss3/step1.wav");
|
||||
sound_step_right = gi.soundindex("boss3/step2.wav");
|
||||
sound_firegun = gi.soundindex("boss3/xfire.wav");
|
||||
sound_death_hit = gi.soundindex("boss3/d_hit.wav");
|
||||
sound_bfg_fire = gi.soundindex("makron/bfg_fire.wav");
|
||||
sound_pain1.assign("boss3/bs3pain1.wav");
|
||||
sound_pain2.assign("boss3/bs3pain2.wav");
|
||||
sound_pain3.assign("boss3/bs3pain3.wav");
|
||||
sound_death.assign("boss3/bs3deth1.wav");
|
||||
sound_attack1.assign("boss3/bs3atck1.wav");
|
||||
sound_attack1_loop.assign("boss3/bs3atck1_loop.wav");
|
||||
sound_attack1_end.assign("boss3/bs3atck1_end.wav");
|
||||
sound_attack2.assign("boss3/bs3atck2.wav");
|
||||
sound_search1.assign("boss3/bs3srch1.wav");
|
||||
sound_search2.assign("boss3/bs3srch2.wav");
|
||||
sound_search3.assign("boss3/bs3srch3.wav");
|
||||
sound_idle.assign("boss3/bs3idle1.wav");
|
||||
sound_step_left.assign("boss3/step1.wav");
|
||||
sound_step_right.assign("boss3/step2.wav");
|
||||
sound_firegun.assign("boss3/xfire.wav");
|
||||
sound_death_hit.assign("boss3/d_hit.wav");
|
||||
sound_bfg_fire.assign("makron/bfg_fire.wav");
|
||||
|
||||
MakronPrecache();
|
||||
|
||||
|
||||
+30
-108
@@ -20,20 +20,20 @@ void makron_step_right(edict_t *self);
|
||||
void makronBFG(edict_t *self);
|
||||
void makron_dead(edict_t *self);
|
||||
|
||||
static int sound_pain4;
|
||||
static int sound_pain5;
|
||||
static int sound_pain6;
|
||||
static int sound_death;
|
||||
static int sound_step_left;
|
||||
static int sound_step_right;
|
||||
static int sound_attack_bfg;
|
||||
static int sound_brainsplorch;
|
||||
static int sound_prerailgun;
|
||||
static int sound_popup;
|
||||
static int sound_taunt1;
|
||||
static int sound_taunt2;
|
||||
static int sound_taunt3;
|
||||
static int sound_hit;
|
||||
static cached_soundindex sound_pain4;
|
||||
static cached_soundindex sound_pain5;
|
||||
static cached_soundindex sound_pain6;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_step_left;
|
||||
static cached_soundindex sound_step_right;
|
||||
static cached_soundindex sound_attack_bfg;
|
||||
static cached_soundindex sound_brainsplorch;
|
||||
static cached_soundindex sound_prerailgun;
|
||||
static cached_soundindex sound_popup;
|
||||
static cached_soundindex sound_taunt1;
|
||||
static cached_soundindex sound_taunt2;
|
||||
static cached_soundindex sound_taunt3;
|
||||
static cached_soundindex sound_hit;
|
||||
|
||||
void makron_taunt(edict_t *self)
|
||||
{
|
||||
@@ -692,88 +692,10 @@ DIE(makron_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damag
|
||||
self->maxs = { 60, 60, 48 };
|
||||
}
|
||||
|
||||
// [Paril-KEX] use generic function
|
||||
MONSTERINFO_CHECKATTACK(Makron_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
float enemy_yaw;
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_PLAYER | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
return false;
|
||||
}
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
// melee attack
|
||||
if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
if (self->monsterinfo.melee)
|
||||
self->monsterinfo.attack_state = AS_MELEE;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// missile attack
|
||||
if (!self->monsterinfo.attack)
|
||||
return false;
|
||||
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (enemy_range > RANGE_MID)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.2f;
|
||||
}
|
||||
|
||||
if (frandom() < chance)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
self->monsterinfo.attack_finished = level.time + random_time(2_sec);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->flags & FL_FLY)
|
||||
{
|
||||
if (frandom() < 0.3f)
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.4f, 0.2f, 0.0f, 0.f);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -782,20 +704,20 @@ MONSTERINFO_CHECKATTACK(Makron_CheckAttack) (edict_t *self) -> bool
|
||||
|
||||
void MakronPrecache()
|
||||
{
|
||||
sound_pain4 = gi.soundindex("makron/pain3.wav");
|
||||
sound_pain5 = gi.soundindex("makron/pain2.wav");
|
||||
sound_pain6 = gi.soundindex("makron/pain1.wav");
|
||||
sound_death = gi.soundindex("makron/death.wav");
|
||||
sound_step_left = gi.soundindex("makron/step1.wav");
|
||||
sound_step_right = gi.soundindex("makron/step2.wav");
|
||||
sound_attack_bfg = gi.soundindex("makron/bfg_fire.wav");
|
||||
sound_brainsplorch = gi.soundindex("makron/brain1.wav");
|
||||
sound_prerailgun = gi.soundindex("makron/rail_up.wav");
|
||||
sound_popup = gi.soundindex("makron/popup.wav");
|
||||
sound_taunt1 = gi.soundindex("makron/voice4.wav");
|
||||
sound_taunt2 = gi.soundindex("makron/voice3.wav");
|
||||
sound_taunt3 = gi.soundindex("makron/voice.wav");
|
||||
sound_hit = gi.soundindex("makron/bhit.wav");
|
||||
sound_pain4.assign("makron/pain3.wav");
|
||||
sound_pain5.assign("makron/pain2.wav");
|
||||
sound_pain6.assign("makron/pain1.wav");
|
||||
sound_death.assign("makron/death.wav");
|
||||
sound_step_left.assign("makron/step1.wav");
|
||||
sound_step_right.assign("makron/step2.wav");
|
||||
sound_attack_bfg.assign("makron/bfg_fire.wav");
|
||||
sound_brainsplorch.assign("makron/brain1.wav");
|
||||
sound_prerailgun.assign("makron/rail_up.wav");
|
||||
sound_popup.assign("makron/popup.wav");
|
||||
sound_taunt1.assign("makron/voice4.wav");
|
||||
sound_taunt2.assign("makron/voice3.wav");
|
||||
sound_taunt3.assign("makron/voice.wav");
|
||||
sound_hit.assign("makron/bhit.wav");
|
||||
|
||||
gi.modelindex("models/monsters/boss3/rider/tris.md2");
|
||||
}
|
||||
|
||||
+32
-34
@@ -11,20 +11,20 @@ brain
|
||||
#include "g_local.h"
|
||||
#include "m_brain.h"
|
||||
|
||||
static int sound_chest_open;
|
||||
static int sound_tentacles_extend;
|
||||
static int sound_tentacles_retract;
|
||||
static int sound_death;
|
||||
static int sound_idle1;
|
||||
static int sound_idle2;
|
||||
static int sound_idle3;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_melee1;
|
||||
static int sound_melee2;
|
||||
static int sound_melee3;
|
||||
static cached_soundindex sound_chest_open;
|
||||
static cached_soundindex sound_tentacles_extend;
|
||||
static cached_soundindex sound_tentacles_retract;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_idle1;
|
||||
static cached_soundindex sound_idle2;
|
||||
static cached_soundindex sound_idle3;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_melee1;
|
||||
static cached_soundindex sound_melee2;
|
||||
static cached_soundindex sound_melee3;
|
||||
|
||||
MONSTERINFO_SIGHT(brain_sight) (edict_t *self, edict_t *other) -> void
|
||||
{
|
||||
@@ -321,11 +321,9 @@ mframe_t brain_frames_attack1[] = {
|
||||
};
|
||||
MMOVE_T(brain_move_attack1) = { FRAME_attak101, FRAME_attak118, brain_frames_attack1, brain_run };
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_BRAIN_TENTACLES_HIT = 65536_spawnflag;
|
||||
|
||||
void brain_chest_open(edict_t *self)
|
||||
{
|
||||
self->spawnflags &= ~SPAWNFLAG_BRAIN_TENTACLES_HIT;
|
||||
self->count = 0;
|
||||
self->monsterinfo.power_armor_type = IT_NULL;
|
||||
gi.sound(self, CHAN_BODY, sound_chest_open, 1, ATTN_NORM, 0);
|
||||
}
|
||||
@@ -334,7 +332,7 @@ void brain_tentacle_attack(edict_t *self)
|
||||
{
|
||||
vec3_t aim = { MELEE_DISTANCE, 0, 8 };
|
||||
if (fire_hit(self, aim, irandom(10, 15), -600))
|
||||
self->spawnflags |= SPAWNFLAG_BRAIN_TENTACLES_HIT;
|
||||
self->count = 1;
|
||||
else
|
||||
self->monsterinfo.melee_debounce_time = level.time + 3_sec;
|
||||
gi.sound(self, CHAN_WEAPON, sound_tentacles_retract, 1, ATTN_NORM, 0);
|
||||
@@ -343,9 +341,9 @@ void brain_tentacle_attack(edict_t *self)
|
||||
void brain_chest_closed(edict_t *self)
|
||||
{
|
||||
self->monsterinfo.power_armor_type = IT_ITEM_POWER_SCREEN;
|
||||
if (self->spawnflags.has(SPAWNFLAG_BRAIN_TENTACLES_HIT))
|
||||
if (self->count)
|
||||
{
|
||||
self->spawnflags &= ~SPAWNFLAG_BRAIN_TENTACLES_HIT;
|
||||
self->count = 0;
|
||||
M_SetAnimation(self, &brain_move_attack1);
|
||||
}
|
||||
}
|
||||
@@ -731,20 +729,20 @@ void SP_monster_brain(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_chest_open = gi.soundindex("brain/brnatck1.wav");
|
||||
sound_tentacles_extend = gi.soundindex("brain/brnatck2.wav");
|
||||
sound_tentacles_retract = gi.soundindex("brain/brnatck3.wav");
|
||||
sound_death = gi.soundindex("brain/brndeth1.wav");
|
||||
sound_idle1 = gi.soundindex("brain/brnidle1.wav");
|
||||
sound_idle2 = gi.soundindex("brain/brnidle2.wav");
|
||||
sound_idle3 = gi.soundindex("brain/brnlens1.wav");
|
||||
sound_pain1 = gi.soundindex("brain/brnpain1.wav");
|
||||
sound_pain2 = gi.soundindex("brain/brnpain2.wav");
|
||||
sound_sight = gi.soundindex("brain/brnsght1.wav");
|
||||
sound_search = gi.soundindex("brain/brnsrch1.wav");
|
||||
sound_melee1 = gi.soundindex("brain/melee1.wav");
|
||||
sound_melee2 = gi.soundindex("brain/melee2.wav");
|
||||
sound_melee3 = gi.soundindex("brain/melee3.wav");
|
||||
sound_chest_open.assign("brain/brnatck1.wav");
|
||||
sound_tentacles_extend.assign("brain/brnatck2.wav");
|
||||
sound_tentacles_retract.assign("brain/brnatck3.wav");
|
||||
sound_death.assign("brain/brndeth1.wav");
|
||||
sound_idle1.assign("brain/brnidle1.wav");
|
||||
sound_idle2.assign("brain/brnidle2.wav");
|
||||
sound_idle3.assign("brain/brnlens1.wav");
|
||||
sound_pain1.assign("brain/brnpain1.wav");
|
||||
sound_pain2.assign("brain/brnpain2.wav");
|
||||
sound_sight.assign("brain/brnsght1.wav");
|
||||
sound_search.assign("brain/brnsrch1.wav");
|
||||
sound_melee1.assign("brain/melee1.wav");
|
||||
sound_melee2.assign("brain/melee2.wav");
|
||||
sound_melee3.assign("brain/melee3.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
+30
-30
@@ -18,21 +18,21 @@ void chick_reslash(edict_t *self);
|
||||
void chick_rerocket(edict_t *self);
|
||||
void chick_attack1(edict_t *self);
|
||||
|
||||
static int sound_missile_prelaunch;
|
||||
static int sound_missile_launch;
|
||||
static int sound_melee_swing;
|
||||
static int sound_melee_hit;
|
||||
static int sound_missile_reload;
|
||||
static int sound_death1;
|
||||
static int sound_death2;
|
||||
static int sound_fall_down;
|
||||
static int sound_idle1;
|
||||
static int sound_idle2;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static cached_soundindex sound_missile_prelaunch;
|
||||
static cached_soundindex sound_missile_launch;
|
||||
static cached_soundindex sound_melee_swing;
|
||||
static cached_soundindex sound_melee_hit;
|
||||
static cached_soundindex sound_missile_reload;
|
||||
static cached_soundindex sound_death1;
|
||||
static cached_soundindex sound_death2;
|
||||
static cached_soundindex sound_fall_down;
|
||||
static cached_soundindex sound_idle1;
|
||||
static cached_soundindex sound_idle2;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
|
||||
void ChickMoan(edict_t *self)
|
||||
{
|
||||
@@ -795,21 +795,21 @@ void SP_monster_chick(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_missile_prelaunch = gi.soundindex("chick/chkatck1.wav");
|
||||
sound_missile_launch = gi.soundindex("chick/chkatck2.wav");
|
||||
sound_melee_swing = gi.soundindex("chick/chkatck3.wav");
|
||||
sound_melee_hit = gi.soundindex("chick/chkatck4.wav");
|
||||
sound_missile_reload = gi.soundindex("chick/chkatck5.wav");
|
||||
sound_death1 = gi.soundindex("chick/chkdeth1.wav");
|
||||
sound_death2 = gi.soundindex("chick/chkdeth2.wav");
|
||||
sound_fall_down = gi.soundindex("chick/chkfall1.wav");
|
||||
sound_idle1 = gi.soundindex("chick/chkidle1.wav");
|
||||
sound_idle2 = gi.soundindex("chick/chkidle2.wav");
|
||||
sound_pain1 = gi.soundindex("chick/chkpain1.wav");
|
||||
sound_pain2 = gi.soundindex("chick/chkpain2.wav");
|
||||
sound_pain3 = gi.soundindex("chick/chkpain3.wav");
|
||||
sound_sight = gi.soundindex("chick/chksght1.wav");
|
||||
sound_search = gi.soundindex("chick/chksrch1.wav");
|
||||
sound_missile_prelaunch.assign("chick/chkatck1.wav");
|
||||
sound_missile_launch.assign("chick/chkatck2.wav");
|
||||
sound_melee_swing.assign("chick/chkatck3.wav");
|
||||
sound_melee_hit.assign("chick/chkatck4.wav");
|
||||
sound_missile_reload.assign("chick/chkatck5.wav");
|
||||
sound_death1.assign("chick/chkdeth1.wav");
|
||||
sound_death2.assign("chick/chkdeth2.wav");
|
||||
sound_fall_down.assign("chick/chkfall1.wav");
|
||||
sound_idle1.assign("chick/chkidle1.wav");
|
||||
sound_idle2.assign("chick/chkidle2.wav");
|
||||
sound_pain1.assign("chick/chkpain1.wav");
|
||||
sound_pain2.assign("chick/chkpain2.wav");
|
||||
sound_pain3.assign("chick/chkpain3.wav");
|
||||
sound_sight.assign("chick/chksght1.wav");
|
||||
sound_search.assign("chick/chksrch1.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
+16
-16
@@ -11,14 +11,14 @@ FLIPPER
|
||||
#include "g_local.h"
|
||||
#include "m_flipper.h"
|
||||
|
||||
static int sound_chomp;
|
||||
static int sound_attack;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_death;
|
||||
static int sound_idle;
|
||||
static int sound_search;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_chomp;
|
||||
static cached_soundindex sound_attack;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
mframe_t flipper_frames_stand[] = {
|
||||
{ ai_stand }
|
||||
@@ -343,14 +343,14 @@ void SP_monster_flipper(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("flipper/flppain1.wav");
|
||||
sound_pain2 = gi.soundindex("flipper/flppain2.wav");
|
||||
sound_death = gi.soundindex("flipper/flpdeth1.wav");
|
||||
sound_chomp = gi.soundindex("flipper/flpatck1.wav");
|
||||
sound_attack = gi.soundindex("flipper/flpatck2.wav");
|
||||
sound_idle = gi.soundindex("flipper/flpidle1.wav");
|
||||
sound_search = gi.soundindex("flipper/flpsrch1.wav");
|
||||
sound_sight = gi.soundindex("flipper/flpsght1.wav");
|
||||
sound_pain1.assign("flipper/flppain1.wav");
|
||||
sound_pain2.assign("flipper/flppain2.wav");
|
||||
sound_death.assign("flipper/flpdeth1.wav");
|
||||
sound_chomp.assign("flipper/flpatck1.wav");
|
||||
sound_attack.assign("flipper/flpatck2.wav");
|
||||
sound_idle.assign("flipper/flpidle1.wav");
|
||||
sound_search.assign("flipper/flpsrch1.wav");
|
||||
sound_sight.assign("flipper/flpsght1.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
+14
-14
@@ -12,13 +12,13 @@ floater
|
||||
#include "m_float.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_attack2;
|
||||
static int sound_attack3;
|
||||
static int sound_death1;
|
||||
static int sound_idle;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_attack2;
|
||||
static cached_soundindex sound_attack3;
|
||||
static cached_soundindex sound_death1;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
MONSTERINFO_SIGHT(floater_sight) (edict_t *self, edict_t *other) -> void
|
||||
{
|
||||
@@ -658,13 +658,13 @@ void SP_monster_floater(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_attack2 = gi.soundindex("floater/fltatck2.wav");
|
||||
sound_attack3 = gi.soundindex("floater/fltatck3.wav");
|
||||
sound_death1 = gi.soundindex("floater/fltdeth1.wav");
|
||||
sound_idle = gi.soundindex("floater/fltidle1.wav");
|
||||
sound_pain1 = gi.soundindex("floater/fltpain1.wav");
|
||||
sound_pain2 = gi.soundindex("floater/fltpain2.wav");
|
||||
sound_sight = gi.soundindex("floater/fltsght1.wav");
|
||||
sound_attack2.assign("floater/fltatck2.wav");
|
||||
sound_attack3.assign("floater/fltatck3.wav");
|
||||
sound_death1.assign("floater/fltdeth1.wav");
|
||||
sound_idle.assign("floater/fltidle1.wav");
|
||||
sound_pain1.assign("floater/fltpain1.wav");
|
||||
sound_pain2.assign("floater/fltpain2.wav");
|
||||
sound_sight.assign("floater/fltsght1.wav");
|
||||
|
||||
gi.soundindex("floater/fltatck1.wav");
|
||||
|
||||
|
||||
+14
-14
@@ -12,13 +12,13 @@ flyer
|
||||
#include "m_flyer.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_sight;
|
||||
static int sound_idle;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_slash;
|
||||
static int sound_sproing;
|
||||
static int sound_die;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_slash;
|
||||
static cached_soundindex sound_sproing;
|
||||
static cached_soundindex sound_die;
|
||||
|
||||
void flyer_check_melee(edict_t *self);
|
||||
void flyer_loop_melee(edict_t *self);
|
||||
@@ -704,13 +704,13 @@ void SP_monster_flyer(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_sight = gi.soundindex("flyer/flysght1.wav");
|
||||
sound_idle = gi.soundindex("flyer/flysrch1.wav");
|
||||
sound_pain1 = gi.soundindex("flyer/flypain1.wav");
|
||||
sound_pain2 = gi.soundindex("flyer/flypain2.wav");
|
||||
sound_slash = gi.soundindex("flyer/flyatck2.wav");
|
||||
sound_sproing = gi.soundindex("flyer/flyatck1.wav");
|
||||
sound_die = gi.soundindex("flyer/flydeth1.wav");
|
||||
sound_sight.assign("flyer/flysght1.wav");
|
||||
sound_idle.assign("flyer/flysrch1.wav");
|
||||
sound_pain1.assign("flyer/flypain1.wav");
|
||||
sound_pain2.assign("flyer/flypain2.wav");
|
||||
sound_slash.assign("flyer/flyatck2.wav");
|
||||
sound_sproing.assign("flyer/flyatck1.wav");
|
||||
sound_die.assign("flyer/flydeth1.wav");
|
||||
|
||||
gi.soundindex("flyer/flyatck3.wav");
|
||||
|
||||
|
||||
+24
-24
@@ -12,18 +12,18 @@ GLADIATOR
|
||||
#include "m_gladiator.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_die;
|
||||
static int sound_die2;
|
||||
static int sound_gun;
|
||||
static int sound_gunb;
|
||||
static int sound_cleaver_swing;
|
||||
static int sound_cleaver_hit;
|
||||
static int sound_cleaver_miss;
|
||||
static int sound_idle;
|
||||
static int sound_search;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_die2;
|
||||
static cached_soundindex sound_gun;
|
||||
static cached_soundindex sound_gunb;
|
||||
static cached_soundindex sound_cleaver_swing;
|
||||
static cached_soundindex sound_cleaver_hit;
|
||||
static cached_soundindex sound_cleaver_miss;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
MONSTERINFO_IDLE(gladiator_idle) (edict_t *self) -> void
|
||||
{
|
||||
@@ -397,16 +397,16 @@ void SP_monster_gladiator(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("gladiator/pain.wav");
|
||||
sound_pain2 = gi.soundindex("gladiator/gldpain2.wav");
|
||||
sound_die = gi.soundindex("gladiator/glddeth2.wav");
|
||||
sound_die2 = gi.soundindex("gladiator/death.wav");
|
||||
sound_cleaver_swing = gi.soundindex("gladiator/melee1.wav");
|
||||
sound_cleaver_hit = gi.soundindex("gladiator/melee2.wav");
|
||||
sound_cleaver_miss = gi.soundindex("gladiator/melee3.wav");
|
||||
sound_idle = gi.soundindex("gladiator/gldidle1.wav");
|
||||
sound_search = gi.soundindex("gladiator/gldsrch1.wav");
|
||||
sound_sight = gi.soundindex("gladiator/sight.wav");
|
||||
sound_pain1.assign("gladiator/pain.wav");
|
||||
sound_pain2.assign("gladiator/gldpain2.wav");
|
||||
sound_die.assign("gladiator/glddeth2.wav");
|
||||
sound_die2.assign("gladiator/death.wav");
|
||||
sound_cleaver_swing.assign("gladiator/melee1.wav");
|
||||
sound_cleaver_hit.assign("gladiator/melee2.wav");
|
||||
sound_cleaver_miss.assign("gladiator/melee3.wav");
|
||||
sound_idle.assign("gladiator/gldidle1.wav");
|
||||
sound_search.assign("gladiator/gldsrch1.wav");
|
||||
sound_sight.assign("gladiator/sight.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
@@ -421,7 +421,7 @@ void SP_monster_gladiator(edict_t *self)
|
||||
// RAFAEL
|
||||
if (strcmp(self->classname, "monster_gladb") == 0)
|
||||
{
|
||||
sound_gunb = gi.soundindex("weapons/plasshot.wav");
|
||||
sound_gunb.assign("weapons/plasshot.wav");
|
||||
|
||||
self->health = 250 * st.health_multiplier;
|
||||
self->mass = 350;
|
||||
@@ -440,7 +440,7 @@ void SP_monster_gladiator(edict_t *self)
|
||||
else
|
||||
{
|
||||
// RAFAEL
|
||||
sound_gun = gi.soundindex("gladiator/railgun.wav");
|
||||
sound_gun.assign("gladiator/railgun.wav");
|
||||
|
||||
self->health = 400 * st.health_multiplier;
|
||||
self->mass = 400;
|
||||
|
||||
@@ -81,7 +81,7 @@ MONSTERINFO_STAND(guardian_stand) (edict_t *self) -> void
|
||||
// walk
|
||||
//
|
||||
|
||||
static int sound_step;
|
||||
static cached_soundindex sound_step;
|
||||
|
||||
void guardian_footstep(edict_t *self)
|
||||
{
|
||||
@@ -213,8 +213,8 @@ void guardian_atk1_finish(edict_t *self)
|
||||
self->monsterinfo.weapon_sound = 0;
|
||||
}
|
||||
|
||||
static int sound_charge;
|
||||
static int sound_spin_loop;
|
||||
static cached_soundindex sound_charge;
|
||||
static cached_soundindex sound_spin_loop;
|
||||
|
||||
void guardian_atk1_charge(edict_t *self)
|
||||
{
|
||||
@@ -292,7 +292,7 @@ void guardian_atk2_out(edict_t *self)
|
||||
M_SetAnimation(self, &guardian_move_atk2_out);
|
||||
}
|
||||
|
||||
static int sound_laser;
|
||||
static cached_soundindex sound_laser;
|
||||
|
||||
constexpr vec3_t laser_positions[] = {
|
||||
{ 125.0f, -70.f, 60.f },
|
||||
@@ -487,10 +487,10 @@ void SP_monster_guardian(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_step = gi.soundindex("zortemp/step.wav");
|
||||
sound_charge = gi.soundindex("weapons/hyprbu1a.wav");
|
||||
sound_spin_loop = gi.soundindex("weapons/hyprbl1a.wav");
|
||||
sound_laser = gi.soundindex("weapons/laser2.wav");
|
||||
sound_step.assign("zortemp/step.wav");
|
||||
sound_charge.assign("weapons/hyprbu1a.wav");
|
||||
sound_spin_loop.assign("weapons/hyprbl1a.wav");
|
||||
sound_laser.assign("weapons/laser2.wav");
|
||||
|
||||
for (auto &gib : gibs)
|
||||
gi.modelindex(gib);
|
||||
|
||||
+15
-15
@@ -14,13 +14,13 @@ GUNNER
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_GUNCMDR_NOJUMPING = 8_spawnflag;
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_pain2;
|
||||
static int sound_death;
|
||||
static int sound_idle;
|
||||
static int sound_open;
|
||||
static int sound_search;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_open;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
void guncmdr_idlesound(edict_t *self)
|
||||
{
|
||||
@@ -1326,7 +1326,7 @@ MONSTERINFO_DUCK(guncmdr_duck) (edict_t *self, gtime_t eta) -> bool
|
||||
|
||||
if ((self->monsterinfo.active_move == &guncmdr_move_fire_chain_dodge_left) ||
|
||||
(self->monsterinfo.active_move == &guncmdr_move_fire_chain_dodge_right) ||
|
||||
(self->monsterinfo.active_move == &guncmdr_move_attack_grenade_back_dodge_right) ||
|
||||
(self->monsterinfo.active_move == &guncmdr_move_attack_grenade_back_dodge_left) ||
|
||||
(self->monsterinfo.active_move == &guncmdr_move_attack_grenade_back_dodge_right) ||
|
||||
(self->monsterinfo.active_move == &guncmdr_move_attack_mortar_dodge))
|
||||
{
|
||||
@@ -1404,13 +1404,13 @@ void SP_monster_guncmdr(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_death = gi.soundindex("guncmdr/gcdrdeath1.wav");
|
||||
sound_pain = gi.soundindex("guncmdr/gcdrpain2.wav");
|
||||
sound_pain2 = gi.soundindex("guncmdr/gcdrpain1.wav");
|
||||
sound_idle = gi.soundindex("guncmdr/gcdridle1.wav");
|
||||
sound_open = gi.soundindex("guncmdr/gcdratck1.wav");
|
||||
sound_search = gi.soundindex("guncmdr/gcdrsrch1.wav");
|
||||
sound_sight = gi.soundindex("guncmdr/sight1.wav");
|
||||
sound_death.assign("guncmdr/gcdrdeath1.wav");
|
||||
sound_pain.assign("guncmdr/gcdrpain2.wav");
|
||||
sound_pain2.assign("guncmdr/gcdrpain1.wav");
|
||||
sound_idle.assign("guncmdr/gcdridle1.wav");
|
||||
sound_open.assign("guncmdr/gcdratck1.wav");
|
||||
sound_search.assign("guncmdr/gcdrsrch1.wav");
|
||||
sound_sight.assign("guncmdr/sight1.wav");
|
||||
|
||||
gi.soundindex("guncmdr/gcdratck2.wav");
|
||||
gi.soundindex("guncmdr/gcdratck3.wav");
|
||||
|
||||
+14
-14
@@ -12,13 +12,13 @@ GUNNER
|
||||
#include "m_gunner.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_pain2;
|
||||
static int sound_death;
|
||||
static int sound_idle;
|
||||
static int sound_open;
|
||||
static int sound_search;
|
||||
static int sound_sight;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_open;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_sight;
|
||||
|
||||
void gunner_idlesound(edict_t *self)
|
||||
{
|
||||
@@ -858,13 +858,13 @@ void SP_monster_gunner(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_death = gi.soundindex("gunner/death1.wav");
|
||||
sound_pain = gi.soundindex("gunner/gunpain2.wav");
|
||||
sound_pain2 = gi.soundindex("gunner/gunpain1.wav");
|
||||
sound_idle = gi.soundindex("gunner/gunidle1.wav");
|
||||
sound_open = gi.soundindex("gunner/gunatck1.wav");
|
||||
sound_search = gi.soundindex("gunner/gunsrch1.wav");
|
||||
sound_sight = gi.soundindex("gunner/sight1.wav");
|
||||
sound_death.assign("gunner/death1.wav");
|
||||
sound_pain.assign("gunner/gunpain2.wav");
|
||||
sound_pain2.assign("gunner/gunpain1.wav");
|
||||
sound_idle.assign("gunner/gunidle1.wav");
|
||||
sound_open.assign("gunner/gunatck1.wav");
|
||||
sound_search.assign("gunner/gunsrch1.wav");
|
||||
sound_sight.assign("gunner/sight1.wav");
|
||||
|
||||
gi.soundindex("gunner/gunatck2.wav");
|
||||
gi.soundindex("gunner/gunatck3.wav");
|
||||
|
||||
+28
-28
@@ -12,23 +12,23 @@ hover
|
||||
#include "m_hover.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_death1;
|
||||
static int sound_death2;
|
||||
static int sound_sight;
|
||||
static int sound_search1;
|
||||
static int sound_search2;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_death1;
|
||||
static cached_soundindex sound_death2;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search1;
|
||||
static cached_soundindex sound_search2;
|
||||
|
||||
// ROGUE
|
||||
// daedalus sounds
|
||||
static int daed_sound_pain1;
|
||||
static int daed_sound_pain2;
|
||||
static int daed_sound_death1;
|
||||
static int daed_sound_death2;
|
||||
static int daed_sound_sight;
|
||||
static int daed_sound_search1;
|
||||
static int daed_sound_search2;
|
||||
static cached_soundindex daed_sound_pain1;
|
||||
static cached_soundindex daed_sound_pain2;
|
||||
static cached_soundindex daed_sound_death1;
|
||||
static cached_soundindex daed_sound_death2;
|
||||
static cached_soundindex daed_sound_sight;
|
||||
static cached_soundindex daed_sound_search1;
|
||||
static cached_soundindex daed_sound_search2;
|
||||
// ROGUE
|
||||
|
||||
MONSTERINFO_SIGHT(hover_sight) (edict_t *self, edict_t *other) -> void
|
||||
@@ -619,26 +619,26 @@ void SP_monster_hover(edict_t *self)
|
||||
self->monsterinfo.power_armor_power = 100;
|
||||
// PMM - daedalus sounds
|
||||
self->monsterinfo.engine_sound = gi.soundindex("daedalus/daedidle1.wav");
|
||||
daed_sound_pain1 = gi.soundindex("daedalus/daedpain1.wav");
|
||||
daed_sound_pain2 = gi.soundindex("daedalus/daedpain2.wav");
|
||||
daed_sound_death1 = gi.soundindex("daedalus/daeddeth1.wav");
|
||||
daed_sound_death2 = gi.soundindex("daedalus/daeddeth2.wav");
|
||||
daed_sound_sight = gi.soundindex("daedalus/daedsght1.wav");
|
||||
daed_sound_search1 = gi.soundindex("daedalus/daedsrch1.wav");
|
||||
daed_sound_search2 = gi.soundindex("daedalus/daedsrch2.wav");
|
||||
daed_sound_pain1.assign("daedalus/daedpain1.wav");
|
||||
daed_sound_pain2.assign("daedalus/daedpain2.wav");
|
||||
daed_sound_death1.assign("daedalus/daeddeth1.wav");
|
||||
daed_sound_death2.assign("daedalus/daeddeth2.wav");
|
||||
daed_sound_sight.assign("daedalus/daedsght1.wav");
|
||||
daed_sound_search1.assign("daedalus/daedsrch1.wav");
|
||||
daed_sound_search2.assign("daedalus/daedsrch2.wav");
|
||||
gi.soundindex("tank/tnkatck3.wav");
|
||||
// pmm
|
||||
}
|
||||
else
|
||||
{
|
||||
self->yaw_speed = 18;
|
||||
sound_pain1 = gi.soundindex("hover/hovpain1.wav");
|
||||
sound_pain2 = gi.soundindex("hover/hovpain2.wav");
|
||||
sound_death1 = gi.soundindex("hover/hovdeth1.wav");
|
||||
sound_death2 = gi.soundindex("hover/hovdeth2.wav");
|
||||
sound_sight = gi.soundindex("hover/hovsght1.wav");
|
||||
sound_search1 = gi.soundindex("hover/hovsrch1.wav");
|
||||
sound_search2 = gi.soundindex("hover/hovsrch2.wav");
|
||||
sound_pain1.assign("hover/hovpain1.wav");
|
||||
sound_pain2.assign("hover/hovpain2.wav");
|
||||
sound_death1.assign("hover/hovdeth1.wav");
|
||||
sound_death2.assign("hover/hovdeth2.wav");
|
||||
sound_sight.assign("hover/hovsght1.wav");
|
||||
sound_search1.assign("hover/hovsrch1.wav");
|
||||
sound_search2.assign("hover/hovsrch2.wav");
|
||||
gi.soundindex("hover/hovatck1.wav");
|
||||
|
||||
self->monsterinfo.engine_sound = gi.soundindex("hover/hovidle1.wav");
|
||||
|
||||
+22
-22
@@ -14,18 +14,18 @@ INFANTRY
|
||||
|
||||
void InfantryMachineGun(edict_t *self);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_die1;
|
||||
static int sound_die2;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_die1;
|
||||
static cached_soundindex sound_die2;
|
||||
|
||||
static int sound_gunshot;
|
||||
static int sound_weapon_cock;
|
||||
static int sound_punch_swing;
|
||||
static int sound_punch_hit;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_idle;
|
||||
static cached_soundindex sound_gunshot;
|
||||
static cached_soundindex sound_weapon_cock;
|
||||
static cached_soundindex sound_punch_swing;
|
||||
static cached_soundindex sound_punch_hit;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_idle;
|
||||
|
||||
// range at which we'll try to initiate a run-attack to close distance
|
||||
constexpr float RANGE_RUN_ATTACK = RANGE_NEAR * 0.75f;
|
||||
@@ -848,19 +848,19 @@ MONSTERINFO_SIDESTEP(infantry_sidestep) (edict_t *self) -> bool
|
||||
|
||||
void InfantryPrecache()
|
||||
{
|
||||
sound_pain1 = gi.soundindex("infantry/infpain1.wav");
|
||||
sound_pain2 = gi.soundindex("infantry/infpain2.wav");
|
||||
sound_die1 = gi.soundindex("infantry/infdeth1.wav");
|
||||
sound_die2 = gi.soundindex("infantry/infdeth2.wav");
|
||||
sound_pain1.assign("infantry/infpain1.wav");
|
||||
sound_pain2.assign("infantry/infpain2.wav");
|
||||
sound_die1.assign("infantry/infdeth1.wav");
|
||||
sound_die2.assign("infantry/infdeth2.wav");
|
||||
|
||||
sound_gunshot = gi.soundindex("infantry/infatck1.wav");
|
||||
sound_weapon_cock = gi.soundindex("infantry/infatck3.wav");
|
||||
sound_punch_swing = gi.soundindex("infantry/infatck2.wav");
|
||||
sound_punch_hit = gi.soundindex("infantry/melee2.wav");
|
||||
sound_gunshot.assign("infantry/infatck1.wav");
|
||||
sound_weapon_cock.assign("infantry/infatck3.wav");
|
||||
sound_punch_swing.assign("infantry/infatck2.wav");
|
||||
sound_punch_hit.assign("infantry/melee2.wav");
|
||||
|
||||
sound_sight = gi.soundindex("infantry/infsght1.wav");
|
||||
sound_search = gi.soundindex("infantry/infsrch1.wav");
|
||||
sound_idle = gi.soundindex("infantry/infidle1.wav");
|
||||
sound_sight.assign("infantry/infsght1.wav");
|
||||
sound_search.assign("infantry/infsrch1.wav");
|
||||
sound_idle.assign("infantry/infidle1.wav");
|
||||
}
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_INFANTRY_NOJUMPING = 8_spawnflag;
|
||||
|
||||
+15
-15
@@ -17,10 +17,10 @@ constexpr spawnflags_t SPAWNFLAG_INSANE_STAND_GROUND = 16_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_INSANE_ALWAYS_STAND = 32_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_INSANE_QUIET = 64_spawnflag;
|
||||
|
||||
static int sound_fist;
|
||||
static int sound_shake;
|
||||
static int sound_moan;
|
||||
static int sound_scream[8];
|
||||
static cached_soundindex sound_fist;
|
||||
static cached_soundindex sound_shake;
|
||||
static cached_soundindex sound_moan;
|
||||
static cached_soundindex sound_scream[8];
|
||||
|
||||
void insane_fist(edict_t *self)
|
||||
{
|
||||
@@ -627,19 +627,19 @@ void SP_misc_insane(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_fist = gi.soundindex("insane/insane11.wav");
|
||||
sound_fist.assign("insane/insane11.wav");
|
||||
if (!self->spawnflags.has(SPAWNFLAG_INSANE_QUIET))
|
||||
{
|
||||
sound_shake = gi.soundindex("insane/insane5.wav");
|
||||
sound_moan = gi.soundindex("insane/insane7.wav");
|
||||
sound_scream[0] = gi.soundindex("insane/insane1.wav");
|
||||
sound_scream[1] = gi.soundindex("insane/insane2.wav");
|
||||
sound_scream[2] = gi.soundindex("insane/insane3.wav");
|
||||
sound_scream[3] = gi.soundindex("insane/insane4.wav");
|
||||
sound_scream[4] = gi.soundindex("insane/insane6.wav");
|
||||
sound_scream[5] = gi.soundindex("insane/insane8.wav");
|
||||
sound_scream[6] = gi.soundindex("insane/insane9.wav");
|
||||
sound_scream[7] = gi.soundindex("insane/insane10.wav");
|
||||
sound_shake.assign("insane/insane5.wav");
|
||||
sound_moan.assign("insane/insane7.wav");
|
||||
sound_scream[0].assign("insane/insane1.wav");
|
||||
sound_scream[1].assign("insane/insane2.wav");
|
||||
sound_scream[2].assign("insane/insane3.wav");
|
||||
sound_scream[3].assign("insane/insane4.wav");
|
||||
sound_scream[4].assign("insane/insane6.wav");
|
||||
sound_scream[5].assign("insane/insane8.wav");
|
||||
sound_scream[6].assign("insane/insane9.wav");
|
||||
sound_scream[7].assign("insane/insane10.wav");
|
||||
}
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
|
||||
+69
-85
@@ -29,29 +29,29 @@ bool FindTarget(edict_t *self);
|
||||
void FoundTarget(edict_t *self);
|
||||
void ED_CallSpawn(edict_t *ent);
|
||||
|
||||
static int sound_idle1;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_die;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_hook_launch;
|
||||
static int sound_hook_hit;
|
||||
static int sound_hook_heal;
|
||||
static int sound_hook_retract;
|
||||
static cached_soundindex sound_idle1;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_hook_launch;
|
||||
static cached_soundindex sound_hook_hit;
|
||||
static cached_soundindex sound_hook_heal;
|
||||
static cached_soundindex sound_hook_retract;
|
||||
|
||||
// PMM - commander sounds
|
||||
static int commander_sound_idle1;
|
||||
static int commander_sound_pain1;
|
||||
static int commander_sound_pain2;
|
||||
static int commander_sound_die;
|
||||
static int commander_sound_sight;
|
||||
static int commander_sound_search;
|
||||
static int commander_sound_hook_launch;
|
||||
static int commander_sound_hook_hit;
|
||||
static int commander_sound_hook_heal;
|
||||
static int commander_sound_hook_retract;
|
||||
static int commander_sound_spawn;
|
||||
static cached_soundindex commander_sound_idle1;
|
||||
static cached_soundindex commander_sound_pain1;
|
||||
static cached_soundindex commander_sound_pain2;
|
||||
static cached_soundindex commander_sound_die;
|
||||
static cached_soundindex commander_sound_sight;
|
||||
static cached_soundindex commander_sound_search;
|
||||
static cached_soundindex commander_sound_hook_launch;
|
||||
static cached_soundindex commander_sound_hook_hit;
|
||||
static cached_soundindex commander_sound_hook_heal;
|
||||
static cached_soundindex commander_sound_hook_retract;
|
||||
static cached_soundindex commander_sound_spawn;
|
||||
|
||||
constexpr const char *default_reinforcements = "monster_soldier_light 1;monster_soldier 2;monster_soldier_ss 2;monster_infantry 3;monster_gunner 4;monster_medic 5;monster_gladiator 6";
|
||||
constexpr int32_t default_monster_slots_base = 3;
|
||||
@@ -199,30 +199,34 @@ void abortHeal(edict_t *self, bool change_frame, bool gib, bool mark)
|
||||
int hurt;
|
||||
constexpr vec3_t pain_normal = { 0, 0, 1 };
|
||||
|
||||
cleanupHealTarget(self->enemy);
|
||||
|
||||
// gib em!
|
||||
if ((mark) && (self->enemy) && (self->enemy->inuse))
|
||||
if (self->enemy && self->enemy->inuse)
|
||||
{
|
||||
// if the first badMedic slot is filled by a medic, skip it and use the second one
|
||||
if ((self->enemy->monsterinfo.badMedic1) && (self->enemy->monsterinfo.badMedic1->inuse) && (!strncmp(self->enemy->monsterinfo.badMedic1->classname, "monster_medic", 13)))
|
||||
{
|
||||
self->enemy->monsterinfo.badMedic2 = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->enemy->monsterinfo.badMedic1 = self;
|
||||
}
|
||||
}
|
||||
if ((gib) && (self->enemy) && (self->enemy->inuse))
|
||||
{
|
||||
if (self->enemy->gib_health)
|
||||
hurt = -self->enemy->gib_health;
|
||||
else
|
||||
hurt = 500;
|
||||
cleanupHealTarget(self->enemy);
|
||||
|
||||
T_Damage(self->enemy, self, self, vec3_origin, self->enemy->s.origin,
|
||||
pain_normal, hurt, 0, DAMAGE_NONE, MOD_UNKNOWN);
|
||||
// gib em!
|
||||
if (mark)
|
||||
{
|
||||
// if the first badMedic slot is filled by a medic, skip it and use the second one
|
||||
if ((self->enemy->monsterinfo.badMedic1) && (self->enemy->monsterinfo.badMedic1->inuse) && (!strncmp(self->enemy->monsterinfo.badMedic1->classname, "monster_medic", 13)))
|
||||
{
|
||||
self->enemy->monsterinfo.badMedic2 = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
self->enemy->monsterinfo.badMedic1 = self;
|
||||
}
|
||||
}
|
||||
|
||||
if (gib)
|
||||
{
|
||||
if (self->enemy->gib_health)
|
||||
hurt = -self->enemy->gib_health;
|
||||
else
|
||||
hurt = 500;
|
||||
|
||||
T_Damage(self->enemy, self, self, vec3_origin, self->enemy->s.origin,
|
||||
pain_normal, hurt, 0, DAMAGE_NONE, MOD_UNKNOWN);
|
||||
}
|
||||
}
|
||||
// clean up self
|
||||
|
||||
@@ -632,21 +636,6 @@ void medic_fire_blaster(edict_t *self)
|
||||
}
|
||||
else
|
||||
{
|
||||
static constexpr vec3_t hb_offsets[] = {
|
||||
{ 33.0f, 12.5f, 15.0f },
|
||||
{ 32.4f, 11.2f, 15.0f },
|
||||
{ 35.6f, 7.4f, 15.0f },
|
||||
{ 34.0f, 4.1f, 15.0f },
|
||||
{ 36.6f, 1.0f, 15.0f },
|
||||
{ 34.7f, -1.9f, 15.0f },
|
||||
{ 36.6f, -0.5f, 15.0f },
|
||||
{ 34.2f, 2.8f, 15.0f },
|
||||
{ 36.5f, 3.8f, 15.0f },
|
||||
{ 33.5f, 6.9f, 15.0f },
|
||||
{ 32.7f, 9.9f, 15.0f },
|
||||
{ 34.5f, 11.0f, 15.0f }
|
||||
};
|
||||
|
||||
effect = (self->s.frame % 4) ? EF_NONE : EF_HYPERBLASTER;
|
||||
mz = static_cast<monster_muzzleflash_id_t>(((self->mass > 400) ? MZ2_MEDIC_HYPERBLASTER2_1 : MZ2_MEDIC_HYPERBLASTER1_1) + (self->s.frame - FRAME_attack19));
|
||||
}
|
||||
@@ -1232,10 +1221,8 @@ void medic_spawngrows(edict_t *self)
|
||||
{
|
||||
offset = reinforcement_position[count];
|
||||
|
||||
if (self->s.scale)
|
||||
offset *= self->s.scale;
|
||||
|
||||
startpoint = M_ProjectFlashSource(self, offset, f, r);
|
||||
|
||||
// a little off the ground
|
||||
startpoint[2] += 10 * (self->s.scale ? self->s.scale : 1.0f);
|
||||
|
||||
@@ -1277,9 +1264,6 @@ void medic_finish_spawn(edict_t *self)
|
||||
auto &reinforcement = self->monsterinfo.reinforcements.reinforcements[self->monsterinfo.chosen_reinforcements[count]];
|
||||
offset = reinforcement_position[count];
|
||||
|
||||
if (self->s.scale)
|
||||
offset *= self->s.scale;
|
||||
|
||||
startpoint = M_ProjectFlashSource(self, offset, f, r);
|
||||
|
||||
// a little off the ground
|
||||
@@ -1595,17 +1579,17 @@ void SP_monster_medic(edict_t *self)
|
||||
self->s.skinnum = 2;
|
||||
|
||||
// commander sounds
|
||||
commander_sound_idle1 = gi.soundindex("medic_commander/medidle.wav");
|
||||
commander_sound_pain1 = gi.soundindex("medic_commander/medpain1.wav");
|
||||
commander_sound_pain2 = gi.soundindex("medic_commander/medpain2.wav");
|
||||
commander_sound_die = gi.soundindex("medic_commander/meddeth.wav");
|
||||
commander_sound_sight = gi.soundindex("medic_commander/medsght.wav");
|
||||
commander_sound_search = gi.soundindex("medic_commander/medsrch.wav");
|
||||
commander_sound_hook_launch = gi.soundindex("medic_commander/medatck2c.wav");
|
||||
commander_sound_hook_hit = gi.soundindex("medic_commander/medatck3a.wav");
|
||||
commander_sound_hook_heal = gi.soundindex("medic_commander/medatck4a.wav");
|
||||
commander_sound_hook_retract = gi.soundindex("medic_commander/medatck5a.wav");
|
||||
commander_sound_spawn = gi.soundindex("medic_commander/monsterspawn1.wav");
|
||||
commander_sound_idle1.assign("medic_commander/medidle.wav");
|
||||
commander_sound_pain1.assign("medic_commander/medpain1.wav");
|
||||
commander_sound_pain2.assign("medic_commander/medpain2.wav");
|
||||
commander_sound_die.assign("medic_commander/meddeth.wav");
|
||||
commander_sound_sight.assign("medic_commander/medsght.wav");
|
||||
commander_sound_search.assign("medic_commander/medsrch.wav");
|
||||
commander_sound_hook_launch.assign("medic_commander/medatck2c.wav");
|
||||
commander_sound_hook_hit.assign("medic_commander/medatck3a.wav");
|
||||
commander_sound_hook_heal.assign("medic_commander/medatck4a.wav");
|
||||
commander_sound_hook_retract.assign("medic_commander/medatck5a.wav");
|
||||
commander_sound_spawn.assign("medic_commander/monsterspawn1.wav");
|
||||
gi.soundindex("tank/tnkatck3.wav");
|
||||
|
||||
const char *reinforcements = default_reinforcements;
|
||||
@@ -1625,16 +1609,16 @@ void SP_monster_medic(edict_t *self)
|
||||
}
|
||||
else
|
||||
{
|
||||
sound_idle1 = gi.soundindex("medic/idle.wav");
|
||||
sound_pain1 = gi.soundindex("medic/medpain1.wav");
|
||||
sound_pain2 = gi.soundindex("medic/medpain2.wav");
|
||||
sound_die = gi.soundindex("medic/meddeth1.wav");
|
||||
sound_sight = gi.soundindex("medic/medsght1.wav");
|
||||
sound_search = gi.soundindex("medic/medsrch1.wav");
|
||||
sound_hook_launch = gi.soundindex("medic/medatck2.wav");
|
||||
sound_hook_hit = gi.soundindex("medic/medatck3.wav");
|
||||
sound_hook_heal = gi.soundindex("medic/medatck4.wav");
|
||||
sound_hook_retract = gi.soundindex("medic/medatck5.wav");
|
||||
sound_idle1.assign("medic/idle.wav");
|
||||
sound_pain1.assign("medic/medpain1.wav");
|
||||
sound_pain2.assign("medic/medpain2.wav");
|
||||
sound_die.assign("medic/meddeth1.wav");
|
||||
sound_sight.assign("medic/medsght1.wav");
|
||||
sound_search.assign("medic/medsrch1.wav");
|
||||
sound_hook_launch.assign("medic/medatck2.wav");
|
||||
sound_hook_hit.assign("medic/medatck3.wav");
|
||||
sound_hook_heal.assign("medic/medatck4.wav");
|
||||
sound_hook_retract.assign("medic/medatck5.wav");
|
||||
gi.soundindex("medic/medatck1.wav");
|
||||
|
||||
self->s.skinnum = 0;
|
||||
|
||||
@@ -656,7 +656,7 @@ bool SV_movestep(edict_t *ent, vec3_t move, bool relink)
|
||||
float stepsize;
|
||||
|
||||
// push down from a step height above the wished position
|
||||
if (ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP))
|
||||
if (ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP) && ent->health > 0)
|
||||
stepsize = 64.f;
|
||||
else if (!(ent->monsterinfo.aiflags & AI_NOSTEP))
|
||||
stepsize = STEPSIZE;
|
||||
@@ -741,7 +741,8 @@ bool SV_movestep(edict_t *ent, vec3_t move, bool relink)
|
||||
ent->groundentity = nullptr;
|
||||
return true;
|
||||
}
|
||||
else if (!ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP))
|
||||
// [Paril-KEX] allow dead monsters to "fall" off of edges in their death animation
|
||||
else if (!ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP) && ent->health > 0)
|
||||
return false; // walked off an edge
|
||||
}
|
||||
|
||||
@@ -831,7 +832,7 @@ bool SV_movestep(edict_t *ent, vec3_t move, bool relink)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP))
|
||||
if (ent->spawnflags.has(SPAWNFLAG_MONSTER_SUPER_STEP) && ent->health > 0)
|
||||
{
|
||||
if (!ent->groundentity || ent->groundentity->solid == SOLID_BSP)
|
||||
{
|
||||
@@ -867,7 +868,11 @@ bool SV_movestep(edict_t *ent, vec3_t move, bool relink)
|
||||
if (relink)
|
||||
{
|
||||
gi.linkentity(ent);
|
||||
G_TouchTriggers(ent);
|
||||
|
||||
// [Paril-KEX] this is something N64 does to avoid doors opening
|
||||
// at the start of a level, which triggers some monsters to spawn.
|
||||
if (!level.is_n64 || level.time > FRAME_TIME_S)
|
||||
G_TouchTriggers(ent);
|
||||
}
|
||||
|
||||
if (stepped)
|
||||
|
||||
+62
-59
@@ -13,19 +13,19 @@ mutant
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_MUTANT_NOJUMPING = 8_spawnflag;
|
||||
|
||||
static int sound_swing;
|
||||
static int sound_hit;
|
||||
static int sound_hit2;
|
||||
static int sound_death;
|
||||
static int sound_idle;
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_step1;
|
||||
static int sound_step2;
|
||||
static int sound_step3;
|
||||
static int sound_thud;
|
||||
static cached_soundindex sound_swing;
|
||||
static cached_soundindex sound_hit;
|
||||
static cached_soundindex sound_hit2;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_step1;
|
||||
static cached_soundindex sound_step2;
|
||||
static cached_soundindex sound_step3;
|
||||
static cached_soundindex sound_thud;
|
||||
|
||||
//
|
||||
// SOUNDS
|
||||
@@ -286,7 +286,8 @@ TOUCH(mutant_jump_touch) (edict_t *self, edict_t *other, const trace_t &tr, bool
|
||||
|
||||
if (self->style == 1 && other->takedamage)
|
||||
{
|
||||
if (self->velocity.length() > 400)
|
||||
// [Paril-KEX] only if we're actually moving fast enough to hurt
|
||||
if (self->velocity.length() > 30)
|
||||
{
|
||||
vec3_t point;
|
||||
vec3_t normal;
|
||||
@@ -321,8 +322,8 @@ void mutant_jump_takeoff(edict_t *self)
|
||||
gi.sound(self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
|
||||
AngleVectors(self->s.angles, forward, nullptr, nullptr);
|
||||
self->s.origin[2] += 1;
|
||||
self->velocity = forward * 400;
|
||||
self->velocity[2] = 150;
|
||||
self->velocity = forward * 425;
|
||||
self->velocity[2] = 160;
|
||||
self->groundentity = nullptr;
|
||||
self->monsterinfo.aiflags |= AI_DUCKED;
|
||||
self->monsterinfo.attack_finished = level.time + 3_sec;
|
||||
@@ -506,15 +507,6 @@ MONSTERINFO_SETSKIN(mutant_setskin) (edict_t *self) -> void
|
||||
// DEATH
|
||||
//
|
||||
|
||||
// FIXME: expanded dead box a bit, but rotation of dead body
|
||||
// means it'll never always fit unless you move the whole box based on angle
|
||||
void mutant_dead(edict_t *self)
|
||||
{
|
||||
self->mins = { 0, -48, -24 };
|
||||
self->maxs = { 64, 16, -8 };
|
||||
monster_dead(self);
|
||||
}
|
||||
|
||||
void mutant_shrink(edict_t *self)
|
||||
{
|
||||
self->maxs[2] = 0;
|
||||
@@ -522,32 +514,43 @@ void mutant_shrink(edict_t *self)
|
||||
gi.linkentity(self);
|
||||
}
|
||||
|
||||
// [Paril-KEX]
|
||||
static void ai_move_slide_right(edict_t *self, float dist)
|
||||
{
|
||||
M_walkmove(self, self->s.angles[YAW] + 90, dist);
|
||||
}
|
||||
|
||||
static void ai_move_slide_left(edict_t *self, float dist)
|
||||
{
|
||||
M_walkmove(self, self->s.angles[YAW] - 90, dist);
|
||||
}
|
||||
|
||||
mframe_t mutant_frames_death1[] = {
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move, 0, mutant_shrink },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move }
|
||||
{ ai_move_slide_right },
|
||||
{ ai_move_slide_right },
|
||||
{ ai_move_slide_right },
|
||||
{ ai_move_slide_right, 2 },
|
||||
{ ai_move_slide_right, 5 },
|
||||
{ ai_move_slide_right, 7, mutant_shrink },
|
||||
{ ai_move_slide_right, 6 },
|
||||
{ ai_move_slide_right, 2 },
|
||||
{ ai_move_slide_right }
|
||||
};
|
||||
MMOVE_T(mutant_move_death1) = { FRAME_death101, FRAME_death109, mutant_frames_death1, mutant_dead };
|
||||
MMOVE_T(mutant_move_death1) = { FRAME_death101, FRAME_death109, mutant_frames_death1, monster_dead };
|
||||
|
||||
mframe_t mutant_frames_death2[] = {
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move, 0, mutant_shrink },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move },
|
||||
{ ai_move }
|
||||
{ ai_move_slide_left },
|
||||
{ ai_move_slide_left },
|
||||
{ ai_move_slide_left },
|
||||
{ ai_move_slide_left, 1 },
|
||||
{ ai_move_slide_left, 3, mutant_shrink },
|
||||
{ ai_move_slide_left, 6 },
|
||||
{ ai_move_slide_left, 8 },
|
||||
{ ai_move_slide_left, 5 },
|
||||
{ ai_move_slide_left, 2 },
|
||||
{ ai_move_slide_left }
|
||||
};
|
||||
MMOVE_T(mutant_move_death2) = { FRAME_death201, FRAME_death210, mutant_frames_death2, mutant_dead };
|
||||
MMOVE_T(mutant_move_death2) = { FRAME_death201, FRAME_death210, mutant_frames_death2, monster_dead };
|
||||
|
||||
DIE(mutant_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t &point, const mod_t &mod) -> void
|
||||
{
|
||||
@@ -676,19 +679,19 @@ void SP_monster_mutant(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_swing = gi.soundindex("mutant/mutatck1.wav");
|
||||
sound_hit = gi.soundindex("mutant/mutatck2.wav");
|
||||
sound_hit2 = gi.soundindex("mutant/mutatck3.wav");
|
||||
sound_death = gi.soundindex("mutant/mutdeth1.wav");
|
||||
sound_idle = gi.soundindex("mutant/mutidle1.wav");
|
||||
sound_pain1 = gi.soundindex("mutant/mutpain1.wav");
|
||||
sound_pain2 = gi.soundindex("mutant/mutpain2.wav");
|
||||
sound_sight = gi.soundindex("mutant/mutsght1.wav");
|
||||
sound_search = gi.soundindex("mutant/mutsrch1.wav");
|
||||
sound_step1 = gi.soundindex("mutant/step1.wav");
|
||||
sound_step2 = gi.soundindex("mutant/step2.wav");
|
||||
sound_step3 = gi.soundindex("mutant/step3.wav");
|
||||
sound_thud = gi.soundindex("mutant/thud1.wav");
|
||||
sound_swing.assign("mutant/mutatck1.wav");
|
||||
sound_hit.assign("mutant/mutatck2.wav");
|
||||
sound_hit2.assign("mutant/mutatck3.wav");
|
||||
sound_death.assign("mutant/mutdeth1.wav");
|
||||
sound_idle.assign("mutant/mutidle1.wav");
|
||||
sound_pain1.assign("mutant/mutpain1.wav");
|
||||
sound_pain2.assign("mutant/mutpain2.wav");
|
||||
sound_sight.assign("mutant/mutsght1.wav");
|
||||
sound_search.assign("mutant/mutsrch1.wav");
|
||||
sound_step1.assign("mutant/step1.wav");
|
||||
sound_step2.assign("mutant/step2.wav");
|
||||
sound_step3.assign("mutant/step3.wav");
|
||||
sound_thud.assign("mutant/thud1.wav");
|
||||
|
||||
self->monsterinfo.aiflags |= AI_STINKY;
|
||||
|
||||
|
||||
+22
-22
@@ -15,17 +15,17 @@ constexpr float g_athena_parasite_miss_chance = 0.1f;
|
||||
constexpr float g_athena_parasite_proboscis_speed = 1250;
|
||||
constexpr float g_athena_parasite_proboscis_retract_modifier = 2.0f;
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_die;
|
||||
static int sound_launch;
|
||||
static int sound_impact;
|
||||
static int sound_suck;
|
||||
static int sound_reelin;
|
||||
static int sound_sight;
|
||||
static int sound_tap;
|
||||
static int sound_scratch;
|
||||
static int sound_search;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_launch;
|
||||
static cached_soundindex sound_impact;
|
||||
static cached_soundindex sound_suck;
|
||||
static cached_soundindex sound_reelin;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_tap;
|
||||
static cached_soundindex sound_scratch;
|
||||
static cached_soundindex sound_search;
|
||||
|
||||
void parasite_stand(edict_t *self);
|
||||
void parasite_start_run(edict_t *self);
|
||||
@@ -909,17 +909,17 @@ void SP_monster_parasite(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("parasite/parpain1.wav");
|
||||
sound_pain2 = gi.soundindex("parasite/parpain2.wav");
|
||||
sound_die = gi.soundindex("parasite/pardeth1.wav");
|
||||
sound_launch = gi.soundindex("parasite/paratck1.wav");
|
||||
sound_impact = gi.soundindex("parasite/paratck2.wav");
|
||||
sound_suck = gi.soundindex("parasite/paratck3.wav");
|
||||
sound_reelin = gi.soundindex("parasite/paratck4.wav");
|
||||
sound_sight = gi.soundindex("parasite/parsght1.wav");
|
||||
sound_tap = gi.soundindex("parasite/paridle1.wav");
|
||||
sound_scratch = gi.soundindex("parasite/paridle2.wav");
|
||||
sound_search = gi.soundindex("parasite/parsrch1.wav");
|
||||
sound_pain1.assign("parasite/parpain1.wav");
|
||||
sound_pain2.assign("parasite/parpain2.wav");
|
||||
sound_die.assign("parasite/pardeth1.wav");
|
||||
sound_launch.assign("parasite/paratck1.wav");
|
||||
sound_impact.assign("parasite/paratck2.wav");
|
||||
sound_suck.assign("parasite/paratck3.wav");
|
||||
sound_reelin.assign("parasite/paratck4.wav");
|
||||
sound_sight.assign("parasite/parsght1.wav");
|
||||
sound_tap.assign("parasite/paridle1.wav");
|
||||
sound_scratch.assign("parasite/paridle2.wav");
|
||||
sound_search.assign("parasite/parsrch1.wav");
|
||||
|
||||
gi.modelindex("models/monsters/parasite/tip/tris.md2");
|
||||
gi.modelindex("models/monsters/parasite/segment/tris.md2");
|
||||
|
||||
+18
-18
@@ -12,15 +12,15 @@ SHAMBLER
|
||||
#include "m_shambler.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_idle;
|
||||
static int sound_die;
|
||||
static int sound_sight;
|
||||
static int sound_windup;
|
||||
static int sound_melee1;
|
||||
static int sound_melee2;
|
||||
static int sound_smack;
|
||||
static int sound_boom;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_windup;
|
||||
static cached_soundindex sound_melee1;
|
||||
static cached_soundindex sound_melee2;
|
||||
static cached_soundindex sound_smack;
|
||||
static cached_soundindex sound_boom;
|
||||
|
||||
//
|
||||
// misc
|
||||
@@ -558,15 +558,15 @@ void SP_monster_shambler(edict_t* self)
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
gi.modelindex("models/proj/lightning/tris.md2");
|
||||
sound_pain = gi.soundindex("shambler/shurt2.wav");
|
||||
sound_idle = gi.soundindex("shambler/sidle.wav");
|
||||
sound_die = gi.soundindex("shambler/sdeath.wav");
|
||||
sound_windup = gi.soundindex("shambler/sattck1.wav");
|
||||
sound_melee1 = gi.soundindex("shambler/melee1.wav");
|
||||
sound_melee2 = gi.soundindex("shambler/melee2.wav");
|
||||
sound_sight = gi.soundindex("shambler/ssight.wav");
|
||||
sound_smack = gi.soundindex("shambler/smack.wav");
|
||||
sound_boom = gi.soundindex("shambler/sboom.wav");
|
||||
sound_pain.assign("shambler/shurt2.wav");
|
||||
sound_idle.assign("shambler/sidle.wav");
|
||||
sound_die.assign("shambler/sdeath.wav");
|
||||
sound_windup.assign("shambler/sattck1.wav");
|
||||
sound_melee1.assign("shambler/melee1.wav");
|
||||
sound_melee2.assign("shambler/melee2.wav");
|
||||
sound_sight.assign("shambler/ssight.wav");
|
||||
sound_smack.assign("shambler/smack.wav");
|
||||
sound_boom.assign("shambler/sboom.wav");
|
||||
|
||||
self->health = 600 * st.health_multiplier;
|
||||
self->gib_health = -60;
|
||||
|
||||
+33
-26
@@ -12,16 +12,16 @@ SOLDIER
|
||||
#include "m_soldier.h"
|
||||
#include "m_flash.h"
|
||||
|
||||
static int sound_idle;
|
||||
static int sound_sight1;
|
||||
static int sound_sight2;
|
||||
static int sound_pain_light;
|
||||
static int sound_pain;
|
||||
static int sound_pain_ss;
|
||||
static int sound_death_light;
|
||||
static int sound_death;
|
||||
static int sound_death_ss;
|
||||
static int sound_cock;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_sight1;
|
||||
static cached_soundindex sound_sight2;
|
||||
static cached_soundindex sound_pain_light;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_pain_ss;
|
||||
static cached_soundindex sound_death_light;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_death_ss;
|
||||
static cached_soundindex sound_cock;
|
||||
|
||||
void soldier_start_charge(edict_t *self)
|
||||
{
|
||||
@@ -648,6 +648,13 @@ void soldier_fire_xatrix(edict_t *self, int flash_number, bool angle_limited)
|
||||
}
|
||||
else
|
||||
{
|
||||
// [Paril-KEX] no enemy = no fire
|
||||
if ((!self->enemy) || (!self->enemy->inuse))
|
||||
{
|
||||
self->monsterinfo.aiflags &= ~AI_HOLD_FRAME;
|
||||
return;
|
||||
}
|
||||
|
||||
// PMM
|
||||
if (self->monsterinfo.attack_state == AS_BLIND)
|
||||
end = self->monsterinfo.blind_fire_target;
|
||||
@@ -1838,10 +1845,10 @@ void SP_monster_soldier_x(edict_t *self)
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
sound_idle = gi.soundindex("soldier/solidle1.wav");
|
||||
sound_sight1 = gi.soundindex("soldier/solsght1.wav");
|
||||
sound_sight2 = gi.soundindex("soldier/solsrch1.wav");
|
||||
sound_cock = gi.soundindex("infantry/infatck3.wav");
|
||||
sound_idle.assign("soldier/solidle1.wav");
|
||||
sound_sight1.assign("soldier/solsght1.wav");
|
||||
sound_sight2.assign("soldier/solsrch1.wav");
|
||||
sound_cock.assign("infantry/infatck3.wav");
|
||||
|
||||
gi.modelindex("models/monsters/soldier/gibs/head.md2");
|
||||
gi.modelindex("models/monsters/soldier/gibs/gun.md2");
|
||||
@@ -1897,8 +1904,8 @@ void SP_monster_soldier_light(edict_t *self)
|
||||
|
||||
SP_monster_soldier_x(self);
|
||||
|
||||
sound_pain_light = gi.soundindex("soldier/solpain2.wav");
|
||||
sound_death_light = gi.soundindex("soldier/soldeth2.wav");
|
||||
sound_pain_light.assign("soldier/solpain2.wav");
|
||||
sound_death_light.assign("soldier/soldeth2.wav");
|
||||
gi.modelindex("models/objects/laser/tris.md2");
|
||||
gi.soundindex("misc/lasfly.wav");
|
||||
gi.soundindex("soldier/solatck2.wav");
|
||||
@@ -1923,8 +1930,8 @@ void SP_monster_soldier(edict_t *self)
|
||||
|
||||
SP_monster_soldier_x(self);
|
||||
|
||||
sound_pain = gi.soundindex("soldier/solpain1.wav");
|
||||
sound_death = gi.soundindex("soldier/soldeth1.wav");
|
||||
sound_pain.assign("soldier/solpain1.wav");
|
||||
sound_death.assign("soldier/soldeth1.wav");
|
||||
gi.soundindex("soldier/solatck1.wav");
|
||||
|
||||
self->s.skinnum = 2;
|
||||
@@ -1944,8 +1951,8 @@ void SP_monster_soldier_ss(edict_t *self)
|
||||
|
||||
SP_monster_soldier_x(self);
|
||||
|
||||
sound_pain_ss = gi.soundindex("soldier/solpain3.wav");
|
||||
sound_death_ss = gi.soundindex("soldier/soldeth3.wav");
|
||||
sound_pain_ss.assign("soldier/solpain3.wav");
|
||||
sound_death_ss.assign("soldier/soldeth3.wav");
|
||||
gi.soundindex("soldier/solatck3.wav");
|
||||
|
||||
self->s.skinnum = 4;
|
||||
@@ -1975,8 +1982,8 @@ void SP_monster_soldier_ripper(edict_t *self)
|
||||
|
||||
SP_monster_soldier_h(self);
|
||||
|
||||
sound_pain_light = gi.soundindex("soldier/solpain2.wav");
|
||||
sound_death_light = gi.soundindex("soldier/soldeth2.wav");
|
||||
sound_pain_light.assign("soldier/solpain2.wav");
|
||||
sound_death_light.assign("soldier/soldeth2.wav");
|
||||
|
||||
gi.modelindex("models/objects/boomrang/tris.md2");
|
||||
gi.soundindex("misc/lasfly.wav");
|
||||
@@ -2003,8 +2010,8 @@ void SP_monster_soldier_hypergun(edict_t *self)
|
||||
SP_monster_soldier_h(self);
|
||||
|
||||
gi.modelindex("models/objects/laser/tris.md2");
|
||||
sound_pain = gi.soundindex("soldier/solpain1.wav");
|
||||
sound_death = gi.soundindex("soldier/soldeth1.wav");
|
||||
sound_pain.assign("soldier/solpain1.wav");
|
||||
sound_death.assign("soldier/soldeth1.wav");
|
||||
gi.soundindex("soldier/solatck1.wav");
|
||||
gi.soundindex("weapons/hyprbd1a.wav");
|
||||
gi.soundindex("weapons/hyprbl1a.wav");
|
||||
@@ -2029,8 +2036,8 @@ void SP_monster_soldier_lasergun(edict_t *self)
|
||||
|
||||
SP_monster_soldier_h(self);
|
||||
|
||||
sound_pain_ss = gi.soundindex("soldier/solpain3.wav");
|
||||
sound_death_ss = gi.soundindex("soldier/soldeth3.wav");
|
||||
sound_pain_ss.assign("soldier/solpain3.wav");
|
||||
sound_death_ss.assign("soldier/soldeth3.wav");
|
||||
gi.soundindex("soldier/solatck3.wav");
|
||||
|
||||
self->s.skinnum = 10;
|
||||
|
||||
+14
-14
@@ -16,14 +16,14 @@ constexpr spawnflags_t SPAWNFLAG_SUPERTANK_POWERSHIELD = 8_spawnflag;
|
||||
// n64
|
||||
constexpr spawnflags_t SPAWNFLAG_SUPERTANK_LONG_DEATH = 16_spawnflag;
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_death;
|
||||
static int sound_search1;
|
||||
static int sound_search2;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_search1;
|
||||
static cached_soundindex sound_search2;
|
||||
|
||||
static int tread_sound;
|
||||
static cached_soundindex tread_sound;
|
||||
|
||||
void TreadSound(edict_t *self)
|
||||
{
|
||||
@@ -640,14 +640,14 @@ void SP_monster_supertank(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("bosstank/btkpain1.wav");
|
||||
sound_pain2 = gi.soundindex("bosstank/btkpain2.wav");
|
||||
sound_pain3 = gi.soundindex("bosstank/btkpain3.wav");
|
||||
sound_death = gi.soundindex("bosstank/btkdeth1.wav");
|
||||
sound_search1 = gi.soundindex("bosstank/btkunqv1.wav");
|
||||
sound_search2 = gi.soundindex("bosstank/btkunqv2.wav");
|
||||
sound_pain1.assign("bosstank/btkpain1.wav");
|
||||
sound_pain2.assign("bosstank/btkpain2.wav");
|
||||
sound_pain3.assign("bosstank/btkpain3.wav");
|
||||
sound_death.assign("bosstank/btkdeth1.wav");
|
||||
sound_search1.assign("bosstank/btkunqv1.wav");
|
||||
sound_search2.assign("bosstank/btkunqv2.wav");
|
||||
|
||||
tread_sound = gi.soundindex("bosstank/btkengn1.wav");
|
||||
tread_sound.assign("bosstank/btkengn1.wav");
|
||||
|
||||
gi.soundindex("gunner/gunatck3.wav");
|
||||
gi.soundindex("infantry/infatck1.wav");
|
||||
|
||||
+20
-18
@@ -16,14 +16,14 @@ void tank_refire_rocket(edict_t *self);
|
||||
void tank_doattack_rocket(edict_t *self);
|
||||
void tank_reattack_blaster(edict_t *self);
|
||||
|
||||
static int sound_thud;
|
||||
static int sound_pain, sound_pain2;
|
||||
static int sound_idle;
|
||||
static int sound_die;
|
||||
static int sound_step;
|
||||
static int sound_sight;
|
||||
static int sound_windup;
|
||||
static int sound_strike;
|
||||
static cached_soundindex sound_thud;
|
||||
static cached_soundindex sound_pain, sound_pain2;
|
||||
static cached_soundindex sound_idle;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_step;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_windup;
|
||||
static cached_soundindex sound_strike;
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_TANK_COMMANDER_GUARDIAN = 8_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_TANK_COMMANDER_HEAT_SEEKING = 16_spawnflag;
|
||||
@@ -612,7 +612,9 @@ void tank_reattack_blaster(edict_t *self)
|
||||
void tank_poststrike(edict_t *self)
|
||||
{
|
||||
self->enemy = nullptr;
|
||||
tank_run(self);
|
||||
// [Paril-KEX]
|
||||
self->monsterinfo.pausetime = HOLD_FOREVER;
|
||||
self->monsterinfo.stand(self);
|
||||
}
|
||||
|
||||
mframe_t tank_frames_attack_strike[] = {
|
||||
@@ -1041,13 +1043,13 @@ void SP_monster_tank(edict_t *self)
|
||||
gi.modelindex("models/monsters/tank/gibs/foot.md2");
|
||||
gi.modelindex("models/monsters/tank/gibs/thigh.md2");
|
||||
|
||||
sound_thud = gi.soundindex("tank/tnkdeth2.wav");
|
||||
sound_idle = gi.soundindex("tank/tnkidle1.wav");
|
||||
sound_die = gi.soundindex("tank/death.wav");
|
||||
sound_step = gi.soundindex("tank/step.wav");
|
||||
sound_windup = gi.soundindex("tank/tnkatck4.wav");
|
||||
sound_strike = gi.soundindex("tank/tnkatck5.wav");
|
||||
sound_sight = gi.soundindex("tank/sight1.wav");
|
||||
sound_thud.assign("tank/tnkdeth2.wav");
|
||||
sound_idle.assign("tank/tnkidle1.wav");
|
||||
sound_die.assign("tank/death.wav");
|
||||
sound_step.assign("tank/step.wav");
|
||||
sound_windup.assign("tank/tnkatck4.wav");
|
||||
sound_strike.assign("tank/tnkatck5.wav");
|
||||
sound_sight.assign("tank/sight1.wav");
|
||||
|
||||
gi.soundindex("tank/tnkatck1.wav");
|
||||
gi.soundindex("tank/tnkatk2a.wav");
|
||||
@@ -1062,13 +1064,13 @@ void SP_monster_tank(edict_t *self)
|
||||
self->health = 1000 * st.health_multiplier;
|
||||
self->gib_health = -225;
|
||||
self->count = 1;
|
||||
sound_pain2 = gi.soundindex("tank/pain.wav");
|
||||
sound_pain2.assign("tank/pain.wav");
|
||||
}
|
||||
else
|
||||
{
|
||||
self->health = 750 * st.health_multiplier;
|
||||
self->gib_health = -200;
|
||||
sound_pain = gi.soundindex("tank/tnkpain2.wav");
|
||||
sound_pain.assign("tank/tnkpain2.wav");
|
||||
}
|
||||
|
||||
self->monsterinfo.scale = MODEL_SCALE;
|
||||
|
||||
+90
-30
@@ -858,14 +858,14 @@ void InitClientPersistant(edict_t *ent, gclient_t *client)
|
||||
client->pers.max_ammo[AMMO_TESLA] = 5;
|
||||
// ROGUE
|
||||
|
||||
if (!g_instagib->integer)
|
||||
if (!deathmatch->integer || !g_instagib->integer)
|
||||
client->pers.inventory[IT_WEAPON_BLASTER] = 1;
|
||||
|
||||
// [Kex]
|
||||
// start items!
|
||||
if (*g_start_items->string)
|
||||
Player_GiveStartItems(ent, g_start_items->string);
|
||||
else if (g_instagib->integer)
|
||||
else if (deathmatch->integer && g_instagib->integer)
|
||||
{
|
||||
client->pers.inventory[IT_WEAPON_RAILGUN] = 1;
|
||||
client->pers.inventory[IT_AMMO_SLUGS] = 99;
|
||||
@@ -924,11 +924,6 @@ void InitClientResp(gclient_t *client)
|
||||
|
||||
client->resp.entertime = level.time;
|
||||
client->resp.coop_respawn = client->pers;
|
||||
|
||||
// ZOID
|
||||
if (G_TeamplayEnabled() && client->pers.connected && client->resp.ctf_team < CTF_TEAM1)
|
||||
CTFAssignTeam(client);
|
||||
// ZOID
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1051,7 +1046,9 @@ select_spawn_result_t SelectDeathmatchSpawnPoint(bool farthest, bool force_spawn
|
||||
if (spawn_points.size() == 0)
|
||||
{
|
||||
spot = G_FindByString<&edict_t::classname>(nullptr, "info_player_start");
|
||||
spawn_points.push_back({ spot, PlayersRangeFromSpot(spot) });
|
||||
|
||||
if (spot)
|
||||
spawn_points.push_back({ spot, PlayersRangeFromSpot(spot) });
|
||||
|
||||
// map is malformed
|
||||
if (spawn_points.size() == 0)
|
||||
@@ -1231,30 +1228,46 @@ static edict_t *SelectSingleSpawnPoint(edict_t *ent)
|
||||
}
|
||||
|
||||
// [Paril-KEX]
|
||||
static edict_t *G_UnsafeSpawnPosition(vec3_t spot)
|
||||
static edict_t *G_UnsafeSpawnPosition(vec3_t spot, bool check_players)
|
||||
{
|
||||
trace_t tr = gi.trace(spot, PLAYER_MINS, PLAYER_MAXS, spot, nullptr, MASK_PLAYERSOLID);
|
||||
contents_t mask = MASK_PLAYERSOLID;
|
||||
|
||||
if (!check_players)
|
||||
mask &= ~CONTENTS_PLAYER;
|
||||
|
||||
trace_t tr = gi.trace(spot, PLAYER_MINS, PLAYER_MAXS, spot, nullptr, mask);
|
||||
|
||||
// sometimes the spot is too close to the ground, give it a bit of slack
|
||||
if (tr.startsolid && !tr.ent->client)
|
||||
{
|
||||
spot[2] += 1;
|
||||
tr = gi.trace(spot, PLAYER_MINS, PLAYER_MAXS, spot, nullptr, MASK_PLAYERSOLID);
|
||||
tr = gi.trace(spot, PLAYER_MINS, PLAYER_MAXS, spot, nullptr, mask);
|
||||
}
|
||||
|
||||
// no idea why this happens in some maps..
|
||||
if (tr.startsolid && !tr.ent->client)
|
||||
return tr.ent;
|
||||
{
|
||||
// try a nudge
|
||||
if (G_FixStuckObject_Generic(spot, PLAYER_MINS, PLAYER_MAXS, [mask] (const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end) {
|
||||
return gi.trace(start, mins, maxs, end, nullptr, mask);
|
||||
}) == stuck_result_t::NO_GOOD_POSITION)
|
||||
return tr.ent; // what do we do here...?
|
||||
|
||||
trace_t tr = gi.trace(spot, PLAYER_MINS, PLAYER_MAXS, spot, nullptr, mask);
|
||||
|
||||
if (tr.startsolid && !tr.ent->client)
|
||||
return tr.ent; // what do we do here...?
|
||||
}
|
||||
|
||||
if (tr.fraction == 1.f)
|
||||
return nullptr;
|
||||
else if (tr.ent->client)
|
||||
else if (check_players && tr.ent && tr.ent->client)
|
||||
return tr.ent;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
edict_t *SelectCoopSpawnPoint(edict_t *ent, bool force_spawn)
|
||||
edict_t *SelectCoopSpawnPoint(edict_t *ent, bool force_spawn, bool check_players)
|
||||
{
|
||||
edict_t *spot = nullptr;
|
||||
const char *target;
|
||||
@@ -1268,7 +1281,7 @@ edict_t *SelectCoopSpawnPoint(edict_t *ent, bool force_spawn)
|
||||
// try the main spawn point first
|
||||
spot = SelectSingleSpawnPoint(ent);
|
||||
|
||||
if (spot && !G_UnsafeSpawnPosition(spot->s.origin))
|
||||
if (spot && !G_UnsafeSpawnPosition(spot->s.origin, check_players))
|
||||
return spot;
|
||||
|
||||
spot = nullptr;
|
||||
@@ -1289,7 +1302,7 @@ edict_t *SelectCoopSpawnPoint(edict_t *ent, bool force_spawn)
|
||||
{ // this is a coop spawn point for one of the clients here
|
||||
num_valid_spots++;
|
||||
|
||||
if (!G_UnsafeSpawnPosition(spot->s.origin))
|
||||
if (!G_UnsafeSpawnPosition(spot->s.origin, check_players))
|
||||
return spot; // this is it
|
||||
}
|
||||
}
|
||||
@@ -1314,7 +1327,7 @@ edict_t *SelectCoopSpawnPoint(edict_t *ent, bool force_spawn)
|
||||
// this is a coop spawn point for one of the clients here
|
||||
num_valid_spots++;
|
||||
|
||||
if (!G_UnsafeSpawnPosition(spot->s.origin))
|
||||
if (!G_UnsafeSpawnPosition(spot->s.origin, check_players))
|
||||
return spot; // this is it
|
||||
}
|
||||
}
|
||||
@@ -1392,7 +1405,7 @@ bool TryLandmarkSpawn(edict_t* ent, vec3_t& origin, vec3_t& angles)
|
||||
// sometimes, landmark spawns can cause slight inconsistencies in collision;
|
||||
// we'll do a bit of tracing to make sure the bbox is clear
|
||||
if (G_FixStuckObject_Generic(origin, PLAYER_MINS, PLAYER_MAXS, [ent] (const vec3_t &start, const vec3_t &mins, const vec3_t &maxs, const vec3_t &end) {
|
||||
return gi.trace(start, mins, maxs, end, ent, MASK_PLAYERSOLID);
|
||||
return gi.trace(start, mins, maxs, end, ent, MASK_PLAYERSOLID & ~CONTENTS_PLAYER);
|
||||
}) == stuck_result_t::NO_GOOD_POSITION)
|
||||
{
|
||||
origin = old_origin;
|
||||
@@ -1451,11 +1464,26 @@ bool SelectSpawnPoint(edict_t *ent, vec3_t &origin, vec3_t &angles, bool force_s
|
||||
|
||||
if (coop->integer)
|
||||
{
|
||||
spot = SelectCoopSpawnPoint(ent, force_spawn);
|
||||
spot = SelectCoopSpawnPoint(ent, force_spawn, true);
|
||||
|
||||
if (!spot)
|
||||
spot = SelectCoopSpawnPoint(ent, force_spawn, false);
|
||||
|
||||
// no open spot yet
|
||||
if (!spot)
|
||||
{
|
||||
// in worst case scenario in coop during intermission, just spawn us at intermission
|
||||
// spot. this only happens for a single frame, and won't break
|
||||
// anything if they come back.
|
||||
if (level.intermissiontime)
|
||||
{
|
||||
origin = level.intermission_origin;
|
||||
angles = level.intermission_angle;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2227,15 +2255,20 @@ void PutClientInServer(edict_t *ent)
|
||||
{
|
||||
if (coop->integer)
|
||||
{
|
||||
if (edict_t *collision = G_UnsafeSpawnPosition(ent->s.origin); collision && collision->client)
|
||||
edict_t *collision = G_UnsafeSpawnPosition(ent->s.origin, true);
|
||||
|
||||
if (collision)
|
||||
{
|
||||
// link us early so that the other player sees us there
|
||||
gi.linkentity(ent);
|
||||
|
||||
// we spawned in somebody else, so we're going to change their spawn position
|
||||
bool lm = false;
|
||||
SelectSpawnPoint(collision, spawn_origin, spawn_angles, true, lm);
|
||||
PutClientOnSpawnPoint(collision, spawn_origin, spawn_angles);
|
||||
if (collision->client)
|
||||
{
|
||||
// we spawned in somebody else, so we're going to change their spawn position
|
||||
bool lm = false;
|
||||
SelectSpawnPoint(collision, spawn_origin, spawn_angles, true, lm);
|
||||
PutClientOnSpawnPoint(collision, spawn_origin, spawn_angles);
|
||||
}
|
||||
// else, no choice but to accept where ever we spawned :(
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2285,6 +2318,11 @@ void ClientBeginDeathmatch(edict_t *ent)
|
||||
|
||||
InitClientResp(ent->client);
|
||||
|
||||
// ZOID
|
||||
if (G_TeamplayEnabled() && ent->client->resp.ctf_team < CTF_TEAM1)
|
||||
CTFAssignTeam(ent->client);
|
||||
// ZOID
|
||||
|
||||
// PGM
|
||||
if (gamerules->integer && DMGame.ClientBegin)
|
||||
{
|
||||
@@ -2433,6 +2471,9 @@ void ClientBegin(edict_t *ent)
|
||||
ent->client->awaiting_respawn = false;
|
||||
ent->client->respawn_timeout = 0_ms;
|
||||
|
||||
// [Paril-KEX] we're always connected by this point...
|
||||
ent->client->pers.connected = true;
|
||||
|
||||
if (deathmatch->integer)
|
||||
{
|
||||
ClientBeginDeathmatch(ent);
|
||||
@@ -2732,7 +2773,7 @@ inline edict_t *ClientChooseSlot_Coop(const char *userinfo, const char *social_i
|
||||
// make sure we have a known default
|
||||
matches[i].slot->svflags |= SVF_PLAYER;
|
||||
|
||||
matches[i].slot->sv.init = true;
|
||||
matches[i].slot->sv.init = false;
|
||||
matches[i].slot->classname = "player";
|
||||
matches[i].slot->client->pers.connected = true;
|
||||
matches[i].slot->client->pers.spawned = true;
|
||||
@@ -2872,6 +2913,9 @@ bool ClientConnect(edict_t *ent, char *userinfo, const char *social_id, bool isB
|
||||
}
|
||||
|
||||
ent->client->pers.connected = true;
|
||||
|
||||
// [Paril-KEX] force a state update
|
||||
ent->sv.init = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3190,7 +3234,9 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd)
|
||||
client->ps.pmove.pm_type = PM_NORMAL;
|
||||
|
||||
// [Paril-KEX]
|
||||
if (!G_ShouldPlayersCollide(false))
|
||||
if (!G_ShouldPlayersCollide(false) ||
|
||||
(coop->integer && !(ent->clipmask & CONTENTS_PLAYER)) // if player collision is on and we're temporarily ghostly...
|
||||
)
|
||||
client->ps.pmove.pm_flags |= PMF_IGNORE_PLAYER_COLLISION;
|
||||
else
|
||||
client->ps.pmove.pm_flags &= ~PMF_IGNORE_PLAYER_COLLISION;
|
||||
@@ -3248,7 +3294,8 @@ void ClientThink(edict_t *ent, usercmd_t *ucmd)
|
||||
|
||||
if (pm.s.pm_flags & PMF_ON_LADDER)
|
||||
{
|
||||
if (client->last_ladder_sound < level.time)
|
||||
if (!deathmatch->integer &&
|
||||
client->last_ladder_sound < level.time)
|
||||
{
|
||||
ent->s.event = EV_LADDER_STEP;
|
||||
client->last_ladder_sound = level.time + LADDER_SOUND_TIME;
|
||||
@@ -3407,12 +3454,15 @@ inline bool G_MonstersSearchingFor(edict_t *player)
|
||||
{
|
||||
for (auto ent : active_monsters())
|
||||
{
|
||||
// check for *any* player target
|
||||
if (player == nullptr && ent->enemy && !ent->enemy->client)
|
||||
continue;
|
||||
// they're not targeting us, so who cares
|
||||
if (ent->enemy != player)
|
||||
else if (player != nullptr && ent->enemy != player)
|
||||
continue;
|
||||
|
||||
// they lost sight of us
|
||||
if (ent->monsterinfo.aiflags & AI_LOST_SIGHT && level.time > ent->monsterinfo.trail_time + 5_sec)
|
||||
if ((ent->monsterinfo.aiflags & AI_LOST_SIGHT) && level.time > ent->monsterinfo.trail_time + 5_sec)
|
||||
continue;
|
||||
|
||||
// no sir
|
||||
@@ -3524,6 +3574,8 @@ inline bool G_FindRespawnSpot(edict_t *player, vec3_t &spot)
|
||||
// respawn target & position
|
||||
inline std::tuple<edict_t *, vec3_t> G_FindSquadRespawnTarget()
|
||||
{
|
||||
bool monsters_searching_for_anybody = G_MonstersSearchingFor(nullptr);
|
||||
|
||||
for (auto player : active_players())
|
||||
{
|
||||
// no dead players
|
||||
@@ -3545,6 +3597,14 @@ inline std::tuple<edict_t *, vec3_t> G_FindSquadRespawnTarget()
|
||||
continue;
|
||||
}
|
||||
|
||||
// check firing state; if any enemies are mad at any players,
|
||||
// don't respawn until everybody has cooled down
|
||||
if (monsters_searching_for_anybody && player->client->last_firing_time >= level.time)
|
||||
{
|
||||
player->client->coop_respawn_state = COOP_RESPAWN_IN_COMBAT;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check positioning; we must be on world ground
|
||||
if (player->groundentity != world)
|
||||
{
|
||||
|
||||
+11
-1
@@ -279,6 +279,8 @@ void BeginIntermission(edict_t *targ)
|
||||
|
||||
game.autosaved = false;
|
||||
|
||||
level.intermissiontime = level.time;
|
||||
|
||||
// respawn any dead clients
|
||||
for (uint32_t i = 0; i < game.maxclients; i++)
|
||||
{
|
||||
@@ -286,10 +288,17 @@ void BeginIntermission(edict_t *targ)
|
||||
if (!client->inuse)
|
||||
continue;
|
||||
if (client->health <= 0)
|
||||
{
|
||||
// give us our max health back since it will reset
|
||||
// to pers.health; in instanced items we'd lose the items
|
||||
// we touched so we always want to respawn with our max.
|
||||
if (P_UseCoopInstancedItems())
|
||||
client->client->pers.health = client->client->pers.max_health = client->max_health;
|
||||
|
||||
respawn(client);
|
||||
}
|
||||
}
|
||||
|
||||
level.intermissiontime = level.time;
|
||||
level.intermission_server_frame = gi.ServerFrame();
|
||||
level.changemap = targ->map;
|
||||
level.intermission_clear = targ->spawnflags.has(SPAWNFLAG_CHANGELEVEL_CLEAR_INVENTORY);
|
||||
@@ -754,6 +763,7 @@ void G_SetStats(edict_t *ent)
|
||||
ent->client->ps.stats[STAT_ACTIVE_WHEEL_WEAPON] = (ent->client->newweapon ? ent->client->newweapon->weapon_wheel_index :
|
||||
ent->client->pers.weapon ? ent->client->pers.weapon->weapon_wheel_index :
|
||||
-1);
|
||||
ent->client->ps.stats[STAT_ACTIVE_WEAPON] = ent->client->pers.weapon ? ent->client->pers.weapon->weapon_wheel_index : -1;
|
||||
|
||||
//
|
||||
// ammo
|
||||
|
||||
+31
-18
@@ -479,10 +479,27 @@ void PM_StepSlideMove()
|
||||
// push down the final amount
|
||||
down = pml.origin;
|
||||
down[2] -= stepSize;
|
||||
|
||||
// [Paril-KEX] jitspoe suggestion for stair clip fix; store
|
||||
// the old down position, and pick a better spot for downwards
|
||||
// trace if the start origin's Z position is lower than the down end pt.
|
||||
vec3_t original_down = down;
|
||||
|
||||
if (start_o[2] < down[2])
|
||||
down[2] = start_o[2] - 1.f;
|
||||
|
||||
trace = PM_Trace(pml.origin, pm->mins, pm->maxs, down);
|
||||
if (!trace.allsolid)
|
||||
{
|
||||
pml.origin = trace.endpos;
|
||||
// [Paril-KEX] from above, do the proper trace now
|
||||
trace_t real_trace = PM_Trace(pml.origin, pm->mins, pm->maxs, original_down);
|
||||
pml.origin = real_trace.endpos;
|
||||
|
||||
// only an upwards jump is a stair clip
|
||||
if (pml.velocity.z > 0.f)
|
||||
{
|
||||
pm->step_clip = true;
|
||||
}
|
||||
}
|
||||
|
||||
up = pml.origin;
|
||||
@@ -496,7 +513,9 @@ void PM_StepSlideMove()
|
||||
pml.origin = down_o;
|
||||
pml.velocity = down_v;
|
||||
}
|
||||
else if (pm->s.pm_flags & PMF_ON_GROUND)
|
||||
// [Paril-KEX] NB: this line being commented is crucial for ramp-jumps to work.
|
||||
// thanks to Jitspoe for pointing this one out.
|
||||
else// if (pm->s.pm_flags & PMF_ON_GROUND)
|
||||
//!! Special case
|
||||
// if we were walking along a plane, then we need to copy the Z over
|
||||
pml.velocity[2] = down_v[2];
|
||||
@@ -1012,7 +1031,12 @@ void PM_CatagorizePosition()
|
||||
pm->s.pm_time = 64;
|
||||
}
|
||||
|
||||
PM_ClipVelocity(pml.velocity, pm->groundplane.normal, pml.velocity, 1.01f);
|
||||
// [Paril-KEX] calculate impact delta; this also fixes triple jumping
|
||||
vec3_t clipped_velocity;
|
||||
PM_ClipVelocity(pml.velocity, pm->groundplane.normal, clipped_velocity, 1.01f);
|
||||
|
||||
pm->impact_delta = pml.start_velocity[2] - clipped_velocity[2];
|
||||
|
||||
pm->s.pm_flags |= PMF_ON_GROUND;
|
||||
|
||||
if (pm_config.n64_physics || (pm->s.pm_flags & PMF_DUCKED))
|
||||
@@ -1073,15 +1097,6 @@ void PM_CheckJump()
|
||||
|
||||
float jump_height = 270.f;
|
||||
|
||||
// [Paril-KEX]
|
||||
if (pm->s.pm_flags & PMF_TIME_TRICK)
|
||||
{
|
||||
pm->s.pm_flags &= ~PMF_TIME_TRICK;
|
||||
pm->s.pm_time = 0;
|
||||
|
||||
jump_height *= 1.40f;
|
||||
}
|
||||
|
||||
pml.velocity[2] += jump_height;
|
||||
if (pml.velocity[2] < jump_height)
|
||||
pml.velocity[2] = jump_height;
|
||||
@@ -1125,6 +1140,9 @@ void PM_CheckSpecialMovement()
|
||||
|
||||
if (pm->waterlevel != WATER_WAIST)
|
||||
return;
|
||||
// [Paril-KEX]
|
||||
else if (pm->watertype & CONTENTS_NO_WATERJUMP)
|
||||
return;
|
||||
|
||||
// quick check that something is even blocking us forward
|
||||
trace = PM_Trace(pml.origin, pm->mins, pm->maxs, pml.origin + (flatforward * 40), MASK_SOLID);
|
||||
@@ -1561,6 +1579,7 @@ void Pmove(pmove_t *pmove)
|
||||
pm->screen_blend = {};
|
||||
pm->rdflags = RDF_NONE;
|
||||
pm->jump_sound = false;
|
||||
pm->step_clip = false;
|
||||
pm->impact_delta = 0;
|
||||
|
||||
// clear all pmove local vars
|
||||
@@ -1621,8 +1640,6 @@ void Pmove(pmove_t *pmove)
|
||||
if (PM_CheckDuck())
|
||||
PM_CatagorizePosition();
|
||||
|
||||
bool was_on_ground = !!pm->groundentity;
|
||||
|
||||
if (pm->s.pm_type == PM_DEAD)
|
||||
PM_DeadMove();
|
||||
|
||||
@@ -1680,10 +1697,6 @@ void Pmove(pmove_t *pmove)
|
||||
// set groundentity, watertype, and waterlevel for final spot
|
||||
PM_CatagorizePosition();
|
||||
|
||||
// impact
|
||||
if (pm->groundentity && !was_on_ground)
|
||||
pm->impact_delta = pml.start_velocity[2] - pml.velocity[2];
|
||||
|
||||
// trick jump
|
||||
if (pm->s.pm_flags & PMF_TIME_TRICK)
|
||||
PM_CheckJump();
|
||||
|
||||
+58
-28
@@ -323,7 +323,7 @@ void SV_CalcViewOffset(edict_t *ent)
|
||||
}
|
||||
ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
|
||||
}
|
||||
else
|
||||
else if (!ent->client->pers.bob_skip && !SkipViewModifiers())
|
||||
{
|
||||
// add angles based on weapon kick
|
||||
angles = P_CurrentKickAngles(ent);
|
||||
@@ -416,29 +416,29 @@ void SV_CalcViewOffset(edict_t *ent)
|
||||
v = {};
|
||||
|
||||
// add fall height
|
||||
|
||||
if (ent->client->fall_time > level.time)
|
||||
{
|
||||
// [Paril-KEX] 100ms of slack is added to account for
|
||||
// visual difference in higher tickrates
|
||||
gtime_t diff = ent->client->fall_time - level.time;
|
||||
|
||||
// slack time remaining
|
||||
if (DAMAGE_TIME_SLACK())
|
||||
{
|
||||
if (diff > FALL_TIME() - DAMAGE_TIME_SLACK())
|
||||
ratio = (FALL_TIME() - diff).seconds() / DAMAGE_TIME_SLACK().seconds();
|
||||
else
|
||||
ratio = diff.seconds() / (FALL_TIME() - DAMAGE_TIME_SLACK()).seconds();
|
||||
}
|
||||
else
|
||||
ratio = diff.seconds() / (FALL_TIME() - DAMAGE_TIME_SLACK()).seconds();
|
||||
v[2] -= ratio * ent->client->fall_value * 0.4f;
|
||||
}
|
||||
|
||||
// add bob height
|
||||
if (!ent->client->pers.bob_skip && !SkipViewModifiers())
|
||||
{
|
||||
if (ent->client->fall_time > level.time)
|
||||
{
|
||||
// [Paril-KEX] 100ms of slack is added to account for
|
||||
// visual difference in higher tickrates
|
||||
gtime_t diff = ent->client->fall_time - level.time;
|
||||
|
||||
// slack time remaining
|
||||
if (DAMAGE_TIME_SLACK())
|
||||
{
|
||||
if (diff > FALL_TIME() - DAMAGE_TIME_SLACK())
|
||||
ratio = (FALL_TIME() - diff).seconds() / DAMAGE_TIME_SLACK().seconds();
|
||||
else
|
||||
ratio = diff.seconds() / (FALL_TIME() - DAMAGE_TIME_SLACK()).seconds();
|
||||
}
|
||||
else
|
||||
ratio = diff.seconds() / (FALL_TIME() - DAMAGE_TIME_SLACK()).seconds();
|
||||
v[2] -= ratio * ent->client->fall_value * 0.4f;
|
||||
}
|
||||
|
||||
// add bob height
|
||||
bob = bobfracsin * xyspeed * bob_up->value;
|
||||
if (bob > 6)
|
||||
bob = 6;
|
||||
@@ -447,9 +447,9 @@ void SV_CalcViewOffset(edict_t *ent)
|
||||
}
|
||||
|
||||
// add kick offset
|
||||
|
||||
|
||||
v += P_CurrentKickOrigin(ent);
|
||||
if (!ent->client->pers.bob_skip && !SkipViewModifiers())
|
||||
v += P_CurrentKickOrigin(ent);
|
||||
|
||||
// absolutely bound offsets
|
||||
// so the view can never be outside the player box
|
||||
@@ -532,6 +532,9 @@ void SV_CalcGunOffset(edict_t *ent)
|
||||
else if (d < 0)
|
||||
d = min(0.f, d + gi.frame_time_ms * reduction_factor);
|
||||
}
|
||||
|
||||
// [Paril-KEX] cl_rollhack
|
||||
ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
|
||||
}
|
||||
// ROGUE
|
||||
else
|
||||
@@ -790,7 +793,7 @@ void P_WorldEffects()
|
||||
|
||||
// play a gurp sound instead of a normal pain sound
|
||||
if (current_player->health <= current_player->dmg)
|
||||
gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
|
||||
gi.sound(current_player, CHAN_VOICE, gi.soundindex("*drown1.wav"), 1, ATTN_NORM, 0); // [Paril-KEX]
|
||||
else if (brandom())
|
||||
gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
|
||||
else
|
||||
@@ -802,12 +805,11 @@ void P_WorldEffects()
|
||||
}
|
||||
}
|
||||
// Paril: almost-drowning sounds
|
||||
// FIXME use better sound + precache in worldspawn
|
||||
else if (current_player->air_finished <= level.time + 3_sec)
|
||||
{
|
||||
if (current_player->client->next_drown_time < level.time)
|
||||
{
|
||||
gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/wade1.wav"), 1, ATTN_NORM, 0);
|
||||
gi.sound(current_player, CHAN_VOICE, gi.soundindex(fmt::format("player/wade{}.wav", 1 + ((int32_t) level.time.seconds() % 3)).c_str()), 1, ATTN_NORM, 0);
|
||||
current_player->client->next_drown_time = level.time + 1_sec;
|
||||
}
|
||||
}
|
||||
@@ -998,7 +1000,8 @@ void G_SetClientEvent(edict_t *ent)
|
||||
|
||||
if (ent->client->ps.pmove.pm_flags & PMF_ON_LADDER)
|
||||
{
|
||||
if (current_client->last_ladder_sound < level.time &&
|
||||
if (!deathmatch->integer &&
|
||||
current_client->last_ladder_sound < level.time &&
|
||||
(current_client->last_ladder_pos - ent->s.origin).length() > 48.f)
|
||||
{
|
||||
ent->s.event = EV_LADDER_STEP;
|
||||
@@ -1416,7 +1419,8 @@ void ClientEndServerFrame(edict_t *ent)
|
||||
|
||||
ent->s.angles[YAW] = ent->client->v_angle[YAW];
|
||||
ent->s.angles[ROLL] = 0;
|
||||
ent->s.angles[ROLL] = SV_CalcRoll(ent->s.angles, ent->velocity) * 4;
|
||||
// [Paril-KEX] cl_rollhack
|
||||
ent->s.angles[ROLL] = -SV_CalcRoll(ent->s.angles, ent->velocity) * 4;
|
||||
|
||||
//
|
||||
// calculate speed and cycle to be used for
|
||||
@@ -1524,4 +1528,30 @@ void ClientEndServerFrame(edict_t *ent)
|
||||
G_SaveLagCompensation(ent);
|
||||
|
||||
Compass_Update(ent, false);
|
||||
|
||||
// [Paril-KEX] in coop, if player collision is enabled and
|
||||
// we are currently in no-player-collision mode, check if
|
||||
// it's safe.
|
||||
if (coop->integer && G_ShouldPlayersCollide(false) && !(ent->clipmask & CONTENTS_PLAYER) && ent->takedamage)
|
||||
{
|
||||
bool clipped_player = false;
|
||||
|
||||
for (auto player : active_players())
|
||||
{
|
||||
if (player == ent)
|
||||
continue;
|
||||
|
||||
trace_t clip = gi.clip(player, ent->s.origin, ent->mins, ent->maxs, ent->s.origin, CONTENTS_MONSTER | CONTENTS_PLAYER);
|
||||
|
||||
if (clip.startsolid || clip.allsolid)
|
||||
{
|
||||
clipped_player = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// safe!
|
||||
if (!clipped_player)
|
||||
ent->clipmask |= CONTENTS_PLAYER;
|
||||
}
|
||||
}
|
||||
+26
-8
@@ -27,7 +27,7 @@ bool G_CheckInfiniteAmmo(gitem_t *item)
|
||||
if (item->flags & IF_NO_INFINITE_AMMO)
|
||||
return false;
|
||||
|
||||
return g_infinite_ammo->integer || g_instagib->integer;
|
||||
return g_infinite_ammo->integer || (deathmatch->integer && g_instagib->integer);
|
||||
}
|
||||
|
||||
//========
|
||||
@@ -456,7 +456,7 @@ void G_RemoveAmmo(edict_t *ent)
|
||||
// [Paril-KEX] get time per animation frame
|
||||
inline gtime_t Weapon_AnimationTime(edict_t *ent)
|
||||
{
|
||||
if (g_quick_weapon_switch->integer && (gi.tick_rate == 20 || gi.tick_rate == 40) &&
|
||||
if (g_quick_weapon_switch->integer && (gi.tick_rate >= 20) &&
|
||||
(ent->client->weaponstate == WEAPON_ACTIVATING || ent->client->weaponstate == WEAPON_DROPPING))
|
||||
ent->client->ps.gunrate = 20;
|
||||
else
|
||||
@@ -635,6 +635,10 @@ Drop_Weapon
|
||||
*/
|
||||
void Drop_Weapon(edict_t *ent, gitem_t *item)
|
||||
{
|
||||
// [Paril-KEX]
|
||||
if (deathmatch->integer && g_dm_weapons_stay->integer)
|
||||
return;
|
||||
|
||||
item_id_t index = item->id;
|
||||
// see if we're already using it
|
||||
if (((item == ent->client->pers.weapon) || (item == ent->client->newweapon)) && (ent->client->pers.inventory[index] == 1))
|
||||
@@ -817,6 +821,7 @@ inline weapon_ready_state_t Weapon_HandleReady(edict_t *ent, int FRAME_FIRE_FIRS
|
||||
(ent->client->pers.inventory[ent->client->pers.weapon->ammo] >= ent->client->pers.weapon->quantity))
|
||||
{
|
||||
ent->client->weaponstate = WEAPON_FIRING;
|
||||
ent->client->last_firing_time = level.time + COOP_DAMAGE_FIRING_TIME;
|
||||
return READY_FIRING;
|
||||
}
|
||||
else
|
||||
@@ -928,6 +933,7 @@ void Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST,
|
||||
|
||||
if (ent->client->weaponstate == WEAPON_FIRING && ent->client->weapon_think_time <= level.time)
|
||||
{
|
||||
ent->client->last_firing_time = level.time + COOP_DAMAGE_FIRING_TIME;
|
||||
ent->client->ps.gunframe++;
|
||||
Weapon_HandleFiring(ent, FRAME_IDLE_FIRST, [&]() {
|
||||
for (int n = 0; fire_frames[n]; n++)
|
||||
@@ -963,6 +969,7 @@ void Weapon_Repeating(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST
|
||||
|
||||
if (ent->client->weaponstate == WEAPON_FIRING && ent->client->weapon_think_time <= level.time)
|
||||
{
|
||||
ent->client->last_firing_time = level.time + COOP_DAMAGE_FIRING_TIME;
|
||||
Weapon_HandleFiring(ent, FRAME_IDLE_FIRST, [&]() { fire(ent); });
|
||||
|
||||
if (ent->client->weapon_thunk)
|
||||
@@ -1092,6 +1099,8 @@ void Throw_Generic(edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int F
|
||||
|
||||
if (ent->client->weaponstate == WEAPON_FIRING)
|
||||
{
|
||||
ent->client->last_firing_time = level.time + COOP_DAMAGE_FIRING_TIME;
|
||||
|
||||
if (ent->client->weapon_think_time <= level.time)
|
||||
{
|
||||
if (prime_sound && ent->client->ps.gunframe == FRAME_PRIME_SOUND)
|
||||
@@ -1108,12 +1117,10 @@ void Throw_Generic(edict_t *ent, int FRAME_FIRE_LAST, int FRAME_IDLE_LAST, int F
|
||||
if (ent->client->ps.gunframe == FRAME_THROW_HOLD)
|
||||
{
|
||||
if (!ent->client->grenade_time && !ent->client->grenade_finished_time)
|
||||
{
|
||||
ent->client->grenade_time = level.time + GRENADE_TIMER + 200_ms;
|
||||
|
||||
if (primed_sound)
|
||||
ent->client->weapon_sound = gi.soundindex(primed_sound);
|
||||
}
|
||||
if (primed_sound && !ent->client->grenade_blew_up)
|
||||
ent->client->weapon_sound = gi.soundindex(primed_sound);
|
||||
|
||||
// they waited too long, detonate it in their hand
|
||||
if (EXPLODE && !ent->client->grenade_blew_up && level.time >= ent->client->grenade_time)
|
||||
@@ -1775,8 +1782,19 @@ RAILGUN
|
||||
|
||||
void weapon_railgun_fire(edict_t *ent)
|
||||
{
|
||||
int damage = 100;
|
||||
int kick = 200;
|
||||
int damage, kick;
|
||||
|
||||
// normal damage too extreme for DM
|
||||
if (deathmatch->integer)
|
||||
{
|
||||
damage = 100;
|
||||
kick = 200;
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = 125;
|
||||
kick = 225;
|
||||
}
|
||||
|
||||
if (is_quad)
|
||||
{
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ using std::clamp;
|
||||
template<typename T>
|
||||
constexpr T lerp(T from, T to, float t)
|
||||
{
|
||||
return t * from + (1.f - t) * to;
|
||||
return (to * t) + (from * (1.f - t));
|
||||
}
|
||||
|
||||
// angle indexes
|
||||
|
||||
@@ -60,7 +60,7 @@ USE(stationarymonster_triggered_spawn_use) (edict_t *self, edict_t *other, edict
|
||||
// we have a one frame delay here so we don't telefrag the guy who activated us
|
||||
self->think = stationarymonster_triggered_spawn;
|
||||
self->nextthink = level.time + FRAME_TIME_S;
|
||||
if (activator->client)
|
||||
if (activator && activator->client)
|
||||
self->enemy = activator;
|
||||
self->use = monster_use;
|
||||
}
|
||||
|
||||
@@ -91,26 +91,26 @@ inline item_id_t FindSubstituteItem(edict_t *ent)
|
||||
if (!itflags || (itflags & (IF_NOT_GIVEABLE | IF_TECH | IF_NOT_RANDOM)) || !it->pickup || !it->world_model)
|
||||
continue;
|
||||
|
||||
itflags = GetSubstituteItemFlags(i);
|
||||
|
||||
// don't respawn spheres if they're dmflag disabled.
|
||||
if (g_no_spheres->integer)
|
||||
{
|
||||
if (ent->item->id == IT_ITEM_SPHERE_VENGEANCE ||
|
||||
ent->item->id == IT_ITEM_SPHERE_HUNTER ||
|
||||
ent->item->id == IT_ITEM_SPHERE_DEFENDER)
|
||||
if (i == IT_ITEM_SPHERE_VENGEANCE ||
|
||||
i == IT_ITEM_SPHERE_HUNTER ||
|
||||
i == IT_ITEM_SPHERE_DEFENDER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_no_nukes->integer && ent->item->id == IT_AMMO_NUKE)
|
||||
if (g_no_nukes->integer && i == IT_AMMO_NUKE)
|
||||
continue;
|
||||
|
||||
if (g_no_mines->integer &&
|
||||
(ent->item->id == IT_AMMO_PROX || ent->item->id == IT_AMMO_TESLA || ent->item->id == IT_AMMO_TRAP))
|
||||
(i == IT_AMMO_PROX || i == IT_AMMO_TESLA || i == IT_AMMO_TRAP || i == IT_WEAPON_PROXLAUNCHER))
|
||||
continue;
|
||||
|
||||
itflags = GetSubstituteItemFlags(i);
|
||||
|
||||
if ((itflags & IF_TYPE_MASK) == (myflags & IF_TYPE_MASK))
|
||||
possible_items[possible_item_count++] = i;
|
||||
}
|
||||
|
||||
@@ -567,6 +567,8 @@ bool fire_player_melee(edict_t *self, const vec3_t &start, const vec3_t &aim, in
|
||||
|
||||
if (!hit->inuse || !hit->takedamage)
|
||||
continue;
|
||||
else if (!CanDamage(self, hit))
|
||||
continue;
|
||||
|
||||
// do the damage
|
||||
vec3_t closest_point_to_check = closest_point_to_box(start, hit->s.origin + hit->mins, hit->s.origin + hit->maxs);
|
||||
|
||||
@@ -169,7 +169,7 @@ THINK(spawngrow_think) (edict_t *self) -> void
|
||||
|
||||
float t = 1.f - ((level.time - self->teleport_time).seconds() / self->wait);
|
||||
|
||||
self->s.scale = clamp(lerp(self->accel, self->decel, t) / 16.f, 0.001f, 16.f);
|
||||
self->s.scale = clamp(lerp(self->decel, self->accel, t) / 16.f, 0.001f, 16.f);
|
||||
self->s.alpha = t * t;
|
||||
|
||||
self->nextthink += FRAME_TIME_MS;
|
||||
|
||||
@@ -31,15 +31,15 @@ void drawbbox(edict_t *self);
|
||||
|
||||
void ED_CallSpawn(edict_t *ent);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_death;
|
||||
static int sound_sight;
|
||||
static int sound_rail;
|
||||
static int sound_spawn;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_rail;
|
||||
static cached_soundindex sound_spawn;
|
||||
|
||||
static int sound_cg_down, sound_cg_loop, sound_cg_up;
|
||||
static cached_soundindex sound_cg_down, sound_cg_loop, sound_cg_up;
|
||||
|
||||
float orig_yaw_speed;
|
||||
|
||||
@@ -1002,48 +1002,9 @@ DIE(carrier_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int dama
|
||||
|
||||
MONSTERINFO_CHECKATTACK(Carrier_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
bool enemy_infront, enemy_inback, enemy_below;
|
||||
float enemy_yaw;
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_PLAYER | CONTENTS_MONSTER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
{
|
||||
// go ahead and spawn stuff if we're mad a a client
|
||||
if (self->enemy->client && M_SlotsLeft(self) > 2)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_BLIND;
|
||||
return true;
|
||||
}
|
||||
|
||||
// PGM - we want them to go ahead and shoot at info_notnulls if they can.
|
||||
if (self->enemy->solid != SOLID_NOT || tr.fraction < 1.0f) // PGM
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enemy_infront = infront(self, self->enemy);
|
||||
enemy_inback = inback(self, self->enemy);
|
||||
enemy_below = below(self, self->enemy);
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
bool enemy_infront = infront(self, self->enemy);
|
||||
bool enemy_inback = inback(self, self->enemy);
|
||||
bool enemy_below = below(self, self->enemy);
|
||||
|
||||
// PMM - shoot out the back if appropriate
|
||||
if ((enemy_inback) || (!enemy_infront && enemy_below))
|
||||
@@ -1061,53 +1022,7 @@ MONSTERINFO_CHECKATTACK(Carrier_CheckAttack) (edict_t *self) -> bool
|
||||
}
|
||||
}
|
||||
|
||||
// melee attack
|
||||
if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (level.time < self->monsterinfo.attack_finished)
|
||||
// return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MID)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.5f;
|
||||
}
|
||||
|
||||
// PGM - go ahead and shoot every time if it's a info_notnull
|
||||
if ((frandom() < chance) || (self->enemy->solid == SOLID_NOT))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->flags & FL_FLY)
|
||||
{
|
||||
if (frandom() < 0.6f)
|
||||
self->monsterinfo.attack_state = AS_SLIDING;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_STRAIGHT;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.8f, 0.8f, 0.5f, 0.f);
|
||||
}
|
||||
|
||||
void CarrierPrecache()
|
||||
@@ -1145,17 +1060,17 @@ void SP_monster_carrier(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("carrier/pain_md.wav");
|
||||
sound_pain2 = gi.soundindex("carrier/pain_lg.wav");
|
||||
sound_pain3 = gi.soundindex("carrier/pain_sm.wav");
|
||||
sound_death = gi.soundindex("carrier/death.wav");
|
||||
sound_rail = gi.soundindex("gladiator/railgun.wav");
|
||||
sound_sight = gi.soundindex("carrier/sight.wav");
|
||||
sound_spawn = gi.soundindex("medic_commander/monsterspawn1.wav");
|
||||
sound_pain1.assign("carrier/pain_md.wav");
|
||||
sound_pain2.assign("carrier/pain_lg.wav");
|
||||
sound_pain3.assign("carrier/pain_sm.wav");
|
||||
sound_death.assign("carrier/death.wav");
|
||||
sound_rail.assign("gladiator/railgun.wav");
|
||||
sound_sight.assign("carrier/sight.wav");
|
||||
sound_spawn.assign("medic_commander/monsterspawn1.wav");
|
||||
|
||||
sound_cg_down = gi.soundindex("weapons/chngnd1a.wav");
|
||||
sound_cg_loop = gi.soundindex("weapons/chngnl1a.wav");
|
||||
sound_cg_up = gi.soundindex("weapons/chngnu1a.wav");
|
||||
sound_cg_down.assign("weapons/chngnd1a.wav");
|
||||
sound_cg_loop.assign("weapons/chngnl1a.wav");
|
||||
sound_cg_up.assign("weapons/chngnu1a.wav");
|
||||
|
||||
self->monsterinfo.engine_sound = gi.soundindex("bosshovr/bhvengn1.wav");
|
||||
|
||||
|
||||
@@ -12,12 +12,12 @@ stalker
|
||||
#include "m_rogue_stalker.h"
|
||||
#include <float.h>
|
||||
|
||||
static int sound_pain;
|
||||
static int sound_die;
|
||||
static int sound_sight;
|
||||
static int sound_punch_hit1;
|
||||
static int sound_punch_hit2;
|
||||
static int sound_idle;
|
||||
static cached_soundindex sound_pain;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_punch_hit1;
|
||||
static cached_soundindex sound_punch_hit2;
|
||||
static cached_soundindex sound_idle;
|
||||
|
||||
bool stalker_do_pounce(edict_t *self, const vec3_t &dest);
|
||||
void stalker_walk(edict_t *self);
|
||||
@@ -979,12 +979,12 @@ void SP_monster_stalker(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain = gi.soundindex("stalker/pain.wav");
|
||||
sound_die = gi.soundindex("stalker/death.wav");
|
||||
sound_sight = gi.soundindex("stalker/sight.wav");
|
||||
sound_punch_hit1 = gi.soundindex("stalker/melee1.wav");
|
||||
sound_punch_hit2 = gi.soundindex("stalker/melee2.wav");
|
||||
sound_idle = gi.soundindex("stalker/idle.wav");
|
||||
sound_pain.assign("stalker/pain.wav");
|
||||
sound_die.assign("stalker/death.wav");
|
||||
sound_sight.assign("stalker/sight.wav");
|
||||
sound_punch_hit1.assign("stalker/melee1.wav");
|
||||
sound_punch_hit2.assign("stalker/melee2.wav");
|
||||
sound_idle.assign("stalker/idle.wav");
|
||||
|
||||
// PMM - precache bolt2
|
||||
gi.modelindex("models/objects/laser/tris.md2");
|
||||
|
||||
@@ -28,7 +28,7 @@ void turret_run(edict_t *self);
|
||||
extern const mmove_t turret_move_fire;
|
||||
extern const mmove_t turret_move_fire_blind;
|
||||
|
||||
static int sound_moved, sound_moving;
|
||||
static cached_soundindex sound_moved, sound_moving;
|
||||
|
||||
void TurretAim(edict_t *self)
|
||||
{
|
||||
@@ -399,18 +399,10 @@ void TurretFire(edict_t *self)
|
||||
|
||||
chance = frandom();
|
||||
|
||||
// rockets fire less often than the others do.
|
||||
if (self->spawnflags.has(SPAWNFLAG_TURRET_ROCKET))
|
||||
{
|
||||
chance = chance * 3;
|
||||
|
||||
rocketSpeed = 650;
|
||||
}
|
||||
else if (self->spawnflags.has(SPAWNFLAG_TURRET_BLASTER))
|
||||
{
|
||||
rocketSpeed = 800;
|
||||
chance = chance * 2;
|
||||
}
|
||||
else
|
||||
rocketSpeed = 0;
|
||||
|
||||
@@ -500,16 +492,11 @@ void TurretFireBlind(edict_t *self)
|
||||
return;
|
||||
|
||||
if (self->spawnflags.has(SPAWNFLAG_TURRET_ROCKET))
|
||||
{
|
||||
if (skill->integer == 2)
|
||||
{
|
||||
rocketSpeed += (int) frandom(200);
|
||||
}
|
||||
else if (skill->integer == 3)
|
||||
{
|
||||
rocketSpeed += (int) frandom(100, 300);
|
||||
}
|
||||
}
|
||||
rocketSpeed = 650;
|
||||
else if (self->spawnflags.has(SPAWNFLAG_TURRET_BLASTER))
|
||||
rocketSpeed = 800;
|
||||
else
|
||||
rocketSpeed = 0;
|
||||
|
||||
start = self->s.origin;
|
||||
end = self->monsterinfo.blind_fire_target;
|
||||
@@ -524,9 +511,9 @@ void TurretFireBlind(edict_t *self)
|
||||
dir.normalize();
|
||||
|
||||
if (self->spawnflags.has(SPAWNFLAG_TURRET_BLASTER))
|
||||
monster_fire_blaster(self, start, dir, 20, 1000, MZ2_TURRET_BLASTER, EF_BLASTER);
|
||||
monster_fire_blaster(self, start, dir, TURRET_BLASTER_DAMAGE, rocketSpeed, MZ2_TURRET_BLASTER, EF_BLASTER);
|
||||
else if (self->spawnflags.has(SPAWNFLAG_TURRET_ROCKET))
|
||||
monster_fire_rocket(self, start, dir, 50, rocketSpeed, MZ2_TURRET_ROCKET);
|
||||
monster_fire_rocket(self, start, dir, 40, rocketSpeed, MZ2_TURRET_ROCKET);
|
||||
}
|
||||
// pmm
|
||||
|
||||
@@ -623,7 +610,7 @@ DIE(turret_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damag
|
||||
if (self->teamchain)
|
||||
{
|
||||
base = self->teamchain;
|
||||
base->solid = SOLID_BBOX;
|
||||
base->solid = SOLID_NOT;
|
||||
base->takedamage = false;
|
||||
base->movetype = MOVETYPE_NONE;
|
||||
base->teammaster = base;
|
||||
@@ -937,8 +924,8 @@ void SP_monster_turret(edict_t *self)
|
||||
}
|
||||
|
||||
// pre-caches
|
||||
sound_moved = gi.soundindex("turret/moved.wav");
|
||||
sound_moving = gi.soundindex("turret/moving.wav");
|
||||
sound_moved.assign("turret/moved.wav");
|
||||
sound_moving.assign("turret/moving.wav");
|
||||
gi.modelindex("models/objects/debris1/tris.md2");
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/turret/tris.md2");
|
||||
|
||||
@@ -22,10 +22,10 @@ constexpr int WIDOW_RAIL_DAMAGE = 50;
|
||||
|
||||
bool infront(edict_t *self, edict_t *other);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_rail;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_rail;
|
||||
|
||||
static uint32_t shotsfired;
|
||||
|
||||
@@ -1126,13 +1126,6 @@ void WidowPowerups(edict_t *self)
|
||||
|
||||
MONSTERINFO_CHECKATTACK(Widow_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
float enemy_yaw;
|
||||
float real_enemy_range;
|
||||
|
||||
if (!self->enemy)
|
||||
return false;
|
||||
|
||||
@@ -1165,85 +1158,7 @@ MONSTERINFO_CHECKATTACK(Widow_CheckAttack) (edict_t *self) -> bool
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
{
|
||||
// go ahead and spawn stuff if we're mad a a client
|
||||
if (self->enemy->client && M_SlotsLeft(self) >= 2)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_BLIND;
|
||||
return true;
|
||||
}
|
||||
|
||||
// PGM - we want them to go ahead and shoot at info_notnulls if they can.
|
||||
if (self->enemy->solid != SOLID_NOT || tr.fraction < 1.0f) // PGM
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
real_enemy_range = realrange(self, self->enemy);
|
||||
|
||||
// melee attack
|
||||
if (real_enemy_range <= (MELEE_DISTANCE + 20))
|
||||
{
|
||||
// don't always melee in easy mode
|
||||
if (skill->integer == 0 && irandom(4))
|
||||
return false;
|
||||
if (self->monsterinfo.melee)
|
||||
self->monsterinfo.attack_state = AS_MELEE;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MELEE)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.7f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MID)
|
||||
{
|
||||
chance = 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.5f;
|
||||
}
|
||||
|
||||
// PGM - go ahead and shoot every time if it's a info_notnull
|
||||
if ((frandom() < chance) || (self->enemy->solid == SOLID_NOT))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.7f, 0.6f, 0.5f, 0.f);
|
||||
}
|
||||
|
||||
MONSTERINFO_BLOCKED(widow_blocked) (edict_t *self, float dist) -> bool
|
||||
@@ -1333,10 +1248,10 @@ void SP_monster_widow(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("widow/bw1pain1.wav");
|
||||
sound_pain2 = gi.soundindex("widow/bw1pain2.wav");
|
||||
sound_pain3 = gi.soundindex("widow/bw1pain3.wav");
|
||||
sound_rail = gi.soundindex("gladiator/railgun.wav");
|
||||
sound_pain1.assign("widow/bw1pain1.wav");
|
||||
sound_pain2.assign("widow/bw1pain2.wav");
|
||||
sound_pain3.assign("widow/bw1pain3.wav");
|
||||
sound_rail.assign("gladiator/railgun.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
@@ -14,12 +14,12 @@ black widow, part 2
|
||||
#include "m_rogue_widow2.h"
|
||||
#include "../m_flash.h"
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_pain2;
|
||||
static int sound_pain3;
|
||||
static int sound_death;
|
||||
static int sound_search1;
|
||||
static int sound_tentacles_retract;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_pain2;
|
||||
static cached_soundindex sound_pain3;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_search1;
|
||||
static cached_soundindex sound_tentacles_retract;
|
||||
|
||||
// sqrt(64*64*2) + sqrt(28*28*2) => 130.1
|
||||
constexpr vec3_t spawnpoints[] = {
|
||||
@@ -685,14 +685,19 @@ MONSTERINFO_WALK(widow2_walk) (edict_t *self) -> void
|
||||
M_SetAnimation(self, &widow2_move_walk);
|
||||
}
|
||||
|
||||
void widow2_attack(edict_t *self);
|
||||
|
||||
MONSTERINFO_MELEE(widow2_melee) (edict_t *self) -> void
|
||||
{
|
||||
M_SetAnimation(self, &widow2_move_tongs);
|
||||
if (self->timestamp >= level.time)
|
||||
widow2_attack(self);
|
||||
else
|
||||
M_SetAnimation(self, &widow2_move_tongs);
|
||||
}
|
||||
|
||||
MONSTERINFO_ATTACK(widow2_attack) (edict_t *self) -> void
|
||||
{
|
||||
float range, luck;
|
||||
float luck;
|
||||
bool blocked = false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_BLOCKED)
|
||||
@@ -704,6 +709,31 @@ MONSTERINFO_ATTACK(widow2_attack) (edict_t *self) -> void
|
||||
if (!self->enemy)
|
||||
return;
|
||||
|
||||
float real_enemy_range = realrange(self, self->enemy);
|
||||
|
||||
// melee attack
|
||||
if (self->timestamp < level.time)
|
||||
{
|
||||
if (real_enemy_range < 300)
|
||||
{
|
||||
vec3_t f, r, u;
|
||||
AngleVectors(self->s.angles, f, r, u);
|
||||
vec3_t spot1 = G_ProjectSource2(self->s.origin, offsets[0], f, r, u);
|
||||
vec3_t spot2 = self->enemy->s.origin;
|
||||
if (widow2_tongue_attack_ok(spot1, spot2, 256))
|
||||
{
|
||||
// melee attack ok
|
||||
|
||||
// be nice in easy mode
|
||||
if (skill->integer != 0 || irandom(4))
|
||||
{
|
||||
M_SetAnimation(self, &widow2_move_tongs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self->bad_area)
|
||||
{
|
||||
if ((frandom() < 0.75f) || (level.time < self->monsterinfo.attack_finished))
|
||||
@@ -731,9 +761,7 @@ MONSTERINFO_ATTACK(widow2_attack) (edict_t *self) -> void
|
||||
return;
|
||||
}
|
||||
|
||||
range = realrange(self, self->enemy);
|
||||
|
||||
if (range < 600)
|
||||
if (real_enemy_range < 600)
|
||||
{
|
||||
luck = frandom();
|
||||
if (M_SlotsLeft(self) >= 2)
|
||||
@@ -924,14 +952,6 @@ DIE(widow2_die) (edict_t *self, edict_t *inflictor, edict_t *attacker, int damag
|
||||
|
||||
MONSTERINFO_CHECKATTACK(Widow2_CheckAttack) (edict_t *self) -> bool
|
||||
{
|
||||
vec3_t spot1, spot2;
|
||||
vec3_t temp;
|
||||
float chance;
|
||||
trace_t tr;
|
||||
float enemy_yaw;
|
||||
float real_enemy_range;
|
||||
vec3_t f, r, u;
|
||||
|
||||
if (!self->enemy)
|
||||
return false;
|
||||
|
||||
@@ -944,92 +964,7 @@ MONSTERINFO_CHECKATTACK(Widow2_CheckAttack) (edict_t *self) -> bool
|
||||
return true;
|
||||
}
|
||||
|
||||
if (self->enemy->health > 0)
|
||||
{
|
||||
// see if any entities are in the way of the shot
|
||||
spot1 = self->s.origin;
|
||||
spot1[2] += self->viewheight;
|
||||
spot2 = self->enemy->s.origin;
|
||||
spot2[2] += self->enemy->viewheight;
|
||||
|
||||
tr = gi.traceline(spot1, spot2, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_SLIME | CONTENTS_LAVA);
|
||||
|
||||
// do we have a clear shot?
|
||||
if (tr.ent != self->enemy && !(tr.ent->svflags & SVF_PLAYER))
|
||||
{
|
||||
// go ahead and spawn stuff if we're mad a a client
|
||||
if (self->enemy->client && M_SlotsLeft(self) >= 2)
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_BLIND;
|
||||
return true;
|
||||
}
|
||||
|
||||
// PGM - we want them to go ahead and shoot at info_notnulls if they can.
|
||||
if (self->enemy->solid != SOLID_NOT || tr.fraction < 1.0f) // PGM
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
float enemy_range = range_to(self, self->enemy);
|
||||
temp = self->enemy->s.origin - self->s.origin;
|
||||
enemy_yaw = vectoyaw(temp);
|
||||
|
||||
self->ideal_yaw = enemy_yaw;
|
||||
|
||||
// melee attack
|
||||
if (self->timestamp < level.time)
|
||||
{
|
||||
real_enemy_range = realrange(self, self->enemy);
|
||||
if (real_enemy_range < 300)
|
||||
{
|
||||
AngleVectors(self->s.angles, f, r, u);
|
||||
spot1 = G_ProjectSource2(self->s.origin, offsets[0], f, r, u);
|
||||
spot2 = self->enemy->s.origin;
|
||||
if (widow2_tongue_attack_ok(spot1, spot2, 256))
|
||||
{
|
||||
// melee attack ok
|
||||
|
||||
// be nice in easy mode
|
||||
if (skill->integer == 0 && irandom(4))
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.melee)
|
||||
self->monsterinfo.attack_state = AS_MELEE;
|
||||
else
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (level.time < self->monsterinfo.attack_finished)
|
||||
return false;
|
||||
|
||||
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
|
||||
{
|
||||
chance = 0.4f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_NEAR)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else if (enemy_range <= RANGE_MID)
|
||||
{
|
||||
chance = 0.8f;
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 0.5f;
|
||||
}
|
||||
|
||||
// PGM - go ahead and shoot every time if it's a info_notnull
|
||||
if ((frandom() < chance) || (self->enemy->solid == SOLID_NOT))
|
||||
{
|
||||
self->monsterinfo.attack_state = AS_MISSILE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return M_CheckAttack_Base(self, 0.4f, 0.8f, 0.8f, 0.5f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
void Widow2Precache()
|
||||
@@ -1072,12 +1007,12 @@ void SP_monster_widow2(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("widow/bw2pain1.wav");
|
||||
sound_pain2 = gi.soundindex("widow/bw2pain2.wav");
|
||||
sound_pain3 = gi.soundindex("widow/bw2pain3.wav");
|
||||
sound_death = gi.soundindex("widow/death.wav");
|
||||
sound_search1 = gi.soundindex("bosshovr/bhvunqv1.wav");
|
||||
sound_tentacles_retract = gi.soundindex("brain/brnatck3.wav");
|
||||
sound_pain1.assign("widow/bw2pain1.wav");
|
||||
sound_pain2.assign("widow/bw2pain2.wav");
|
||||
sound_pain3.assign("widow/bw2pain3.wav");
|
||||
sound_death.assign("widow/death.wav");
|
||||
sound_search1.assign("bosshovr/bhvunqv1.wav");
|
||||
sound_tentacles_retract.assign("brain/brnatck3.wav");
|
||||
|
||||
// self->s.sound = gi.soundindex ("bosshovr/bhvengn1.wav");
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// defines
|
||||
|
||||
constexpr spawnflags_t SPAWNFLAG_DBALL_GOAL_TEAM1 = 0x0001_spawnflag;
|
||||
[[maybe_unused]] constexpr spawnflags_t SPAWNFLAG_DBALL_GOAL_TEAM1 = 0x0001_spawnflag;
|
||||
// unused; assumed by not being team1
|
||||
// constexpr uint32_t SPAWNFLAG_DBALL_GOAL_TEAM2 = 0x0002;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ void SP_misc_transport(edict_t *ent)
|
||||
/*QUAKED misc_amb4 (1 0 0) (-16 -16 -16) (16 16 16)
|
||||
Mal's amb4 loop entity
|
||||
*/
|
||||
static int amb4sound;
|
||||
static cached_soundindex amb4sound;
|
||||
|
||||
THINK(amb4_think) (edict_t *ent) -> void
|
||||
{
|
||||
@@ -129,7 +129,7 @@ void SP_misc_amb4(edict_t *ent)
|
||||
{
|
||||
ent->think = amb4_think;
|
||||
ent->nextthink = level.time + 1_sec;
|
||||
amb4sound = gi.soundindex("world/amb4.wav");
|
||||
amb4sound.assign("world/amb4.wav");
|
||||
gi.linkentity(ent);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
bool infront(edict_t *self, edict_t *other);
|
||||
bool FindTarget(edict_t *self);
|
||||
|
||||
static int sound_pain1;
|
||||
static int sound_die;
|
||||
static int sound_weld1;
|
||||
static int sound_weld2;
|
||||
static int sound_weld3;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_die;
|
||||
static cached_soundindex sound_weld1;
|
||||
static cached_soundindex sound_weld2;
|
||||
static cached_soundindex sound_weld3;
|
||||
|
||||
void fixbot_run(edict_t *self);
|
||||
void fixbot_attack(edict_t *self);
|
||||
@@ -1335,6 +1335,8 @@ PAIN(fixbot_pain) (edict_t *self, edict_t *other, float kick, int damage, const
|
||||
M_SetAnimation(self, &fixbot_move_painb);
|
||||
else
|
||||
M_SetAnimation(self, &fixbot_move_paina);
|
||||
|
||||
abortHeal(self, false, false, false);
|
||||
}
|
||||
|
||||
void fixbot_dead(edict_t *self)
|
||||
@@ -1364,12 +1366,12 @@ void SP_monster_fixbot(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_pain1 = gi.soundindex("flyer/flypain1.wav");
|
||||
sound_die = gi.soundindex("flyer/flydeth1.wav");
|
||||
sound_pain1.assign("flyer/flypain1.wav");
|
||||
sound_die.assign("flyer/flydeth1.wav");
|
||||
|
||||
sound_weld1 = gi.soundindex("misc/welder1.wav");
|
||||
sound_weld2 = gi.soundindex("misc/welder2.wav");
|
||||
sound_weld3 = gi.soundindex("misc/welder3.wav");
|
||||
sound_weld1.assign("misc/welder1.wav");
|
||||
sound_weld2.assign("misc/welder2.wav");
|
||||
sound_weld3.assign("misc/welder3.wav");
|
||||
|
||||
self->s.modelindex = gi.modelindex("models/monsters/fixbot/tris.md2");
|
||||
|
||||
|
||||
@@ -12,22 +12,22 @@ constexpr spawnflags_t SPAWNFLAG_GEKK_CHANT = 8_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_GEKK_NOJUMPING = 16_spawnflag;
|
||||
constexpr spawnflags_t SPAWNFLAG_GEKK_NOSWIM = 32_spawnflag;
|
||||
|
||||
static int sound_swing;
|
||||
static int sound_hit;
|
||||
static int sound_hit2;
|
||||
static int sound_speet;
|
||||
static int loogie_hit;
|
||||
static int sound_death;
|
||||
static int sound_pain1;
|
||||
static int sound_sight;
|
||||
static int sound_search;
|
||||
static int sound_step1;
|
||||
static int sound_step2;
|
||||
static int sound_step3;
|
||||
static int sound_thud;
|
||||
static int sound_chantlow;
|
||||
static int sound_chantmid;
|
||||
static int sound_chanthigh;
|
||||
static cached_soundindex sound_swing;
|
||||
static cached_soundindex sound_hit;
|
||||
static cached_soundindex sound_hit2;
|
||||
static cached_soundindex sound_speet;
|
||||
static cached_soundindex loogie_hit;
|
||||
static cached_soundindex sound_death;
|
||||
static cached_soundindex sound_pain1;
|
||||
static cached_soundindex sound_sight;
|
||||
static cached_soundindex sound_search;
|
||||
static cached_soundindex sound_step1;
|
||||
static cached_soundindex sound_step2;
|
||||
static cached_soundindex sound_step3;
|
||||
static cached_soundindex sound_thud;
|
||||
static cached_soundindex sound_chantlow;
|
||||
static cached_soundindex sound_chantmid;
|
||||
static cached_soundindex sound_chanthigh;
|
||||
|
||||
void gekk_swim(edict_t *self);
|
||||
|
||||
@@ -1589,23 +1589,23 @@ void SP_monster_gekk(edict_t *self)
|
||||
return;
|
||||
}
|
||||
|
||||
sound_swing = gi.soundindex("gek/gk_atck1.wav");
|
||||
sound_hit = gi.soundindex("gek/gk_atck2.wav");
|
||||
sound_hit2 = gi.soundindex("gek/gk_atck3.wav");
|
||||
sound_speet = gi.soundindex("gek/gk_atck4.wav");
|
||||
loogie_hit = gi.soundindex("gek/loogie_hit.wav");
|
||||
sound_death = gi.soundindex("gek/gk_deth1.wav");
|
||||
sound_pain1 = gi.soundindex("gek/gk_pain1.wav");
|
||||
sound_sight = gi.soundindex("gek/gk_sght1.wav");
|
||||
sound_search = gi.soundindex("gek/gk_idle1.wav");
|
||||
sound_step1 = gi.soundindex("gek/gk_step1.wav");
|
||||
sound_step2 = gi.soundindex("gek/gk_step2.wav");
|
||||
sound_step3 = gi.soundindex("gek/gk_step3.wav");
|
||||
sound_thud = gi.soundindex("mutant/thud1.wav");
|
||||
sound_swing.assign("gek/gk_atck1.wav");
|
||||
sound_hit.assign("gek/gk_atck2.wav");
|
||||
sound_hit2.assign("gek/gk_atck3.wav");
|
||||
sound_speet.assign("gek/gk_atck4.wav");
|
||||
loogie_hit.assign("gek/loogie_hit.wav");
|
||||
sound_death.assign("gek/gk_deth1.wav");
|
||||
sound_pain1.assign("gek/gk_pain1.wav");
|
||||
sound_sight.assign("gek/gk_sght1.wav");
|
||||
sound_search.assign("gek/gk_idle1.wav");
|
||||
sound_step1.assign("gek/gk_step1.wav");
|
||||
sound_step2.assign("gek/gk_step2.wav");
|
||||
sound_step3.assign("gek/gk_step3.wav");
|
||||
sound_thud.assign("mutant/thud1.wav");
|
||||
|
||||
sound_chantlow = gi.soundindex("gek/gek_low.wav");
|
||||
sound_chantmid = gi.soundindex("gek/gek_mid.wav");
|
||||
sound_chanthigh = gi.soundindex("gek/gek_high.wav");
|
||||
sound_chantlow.assign("gek/gek_low.wav");
|
||||
sound_chantmid.assign("gek/gek_mid.wav");
|
||||
sound_chanthigh.assign("gek/gek_high.wav");
|
||||
|
||||
self->movetype = MOVETYPE_STEP;
|
||||
self->solid = SOLID_BBOX;
|
||||
|
||||
Reference in New Issue
Block a user