mirror of
https://github.com/nzp-team/quakec.git
synced 2025-02-21 11:11:42 +00:00
SERVER: Revamp Ray Gun logic and FX.
PC/FTE now usesa custom flash and low-level light to help it look a bit better. Damage values are more accurate, with detection for direct impact vs splash damage. Also moved into its own file to improve source readability.
This commit is contained in:
parent
5bee39d063
commit
b9246fff17
5 changed files with 192 additions and 97 deletions
|
@ -27,6 +27,7 @@
|
||||||
../source/server/entities/machines.qc
|
../source/server/entities/machines.qc
|
||||||
|
|
||||||
../source/server/weapons/frames_core.qc
|
../source/server/weapons/frames_core.qc
|
||||||
|
../source/server/weapons/ray_gun.qc
|
||||||
../source/server/weapons/weapon_core.qc
|
../source/server/weapons/weapon_core.qc
|
||||||
|
|
||||||
../source/server/entities/powerups.qc
|
../source/server/entities/powerups.qc
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
../source/server/entities/machines.qc
|
../source/server/entities/machines.qc
|
||||||
|
|
||||||
../source/server/weapons/frames_core.qc
|
../source/server/weapons/frames_core.qc
|
||||||
|
../source/server/weapons/ray_gun.qc
|
||||||
../source/server/weapons/weapon_core.qc
|
../source/server/weapons/weapon_core.qc
|
||||||
../source/server/entities/powerups.qc
|
../source/server/entities/powerups.qc
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
../source/server/entities/machines.qc
|
../source/server/entities/machines.qc
|
||||||
|
|
||||||
../source/server/weapons/frames_core.qc
|
../source/server/weapons/frames_core.qc
|
||||||
|
../source/server/weapons/ray_gun.qc
|
||||||
../source/server/weapons/weapon_core.qc
|
../source/server/weapons/weapon_core.qc
|
||||||
../source/server/entities/powerups.qc
|
../source/server/entities/powerups.qc
|
||||||
|
|
||||||
|
|
189
source/server/weapons/ray_gun.qc
Normal file
189
source/server/weapons/ray_gun.qc
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
server/weapons/ray_gun.qc
|
||||||
|
|
||||||
|
Core logic for the Ray Gun special weapon.
|
||||||
|
Modified from Unofficial Patch implementation.
|
||||||
|
|
||||||
|
Copyright (C) 2021-2022 NZ:P Team
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ray_BeamExplode(direct_impact)
|
||||||
|
// Calculates damage values, calls for an explosion, and
|
||||||
|
// plays the light effects for the Ray Beam detonation.
|
||||||
|
// ---
|
||||||
|
// direct_impact: Denotes whether or not the Beam collided
|
||||||
|
// with a Monster or if it hit something else (the world).
|
||||||
|
//
|
||||||
|
void(float direct_impact) Ray_BeamExplode =
|
||||||
|
{
|
||||||
|
float raybeam_damage_min;
|
||||||
|
float raybeam_damage_max;
|
||||||
|
float raybeam_damage_radius = 64;
|
||||||
|
|
||||||
|
// Direct shots to the Zombie always deals the same
|
||||||
|
// amount of damage, regardless of PaP status.
|
||||||
|
if (direct_impact == true) {
|
||||||
|
raybeam_damage_min = 1000;
|
||||||
|
raybeam_damage_max = 1000;
|
||||||
|
} else if (IsPapWeapon(self.weapon)) {
|
||||||
|
raybeam_damage_min = 300;
|
||||||
|
raybeam_damage_max = 2000;
|
||||||
|
} else {
|
||||||
|
raybeam_damage_min = 300;
|
||||||
|
raybeam_damage_max = 1800;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the Damage.
|
||||||
|
DamgageExplode(self, self.owner, raybeam_damage_max,
|
||||||
|
raybeam_damage_min, raybeam_damage_radius);
|
||||||
|
|
||||||
|
// Spawn Effects
|
||||||
|
#ifdef PC
|
||||||
|
// Determine color of the beam
|
||||||
|
vector raybeam_color;
|
||||||
|
|
||||||
|
if (IsPapWeapon(self.weapon)) raybeam_color = '1 0 0';
|
||||||
|
else raybeam_color = '0 1 0';
|
||||||
|
|
||||||
|
te_customflash(self.origin, raybeam_damage_radius, 300,
|
||||||
|
raybeam_color);
|
||||||
|
#else
|
||||||
|
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
||||||
|
#ifdef HANDHELD
|
||||||
|
if (self.effects & EF_RAYGREEN)
|
||||||
|
WriteByte (MSG_BROADCAST, TE_RAYSPLASHGREEN);
|
||||||
|
else
|
||||||
|
WriteByte (MSG_BROADCAST, TE_RAYSPLASHRED);
|
||||||
|
#else
|
||||||
|
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
||||||
|
#endif // HANDHELD
|
||||||
|
WriteCoord (MSG_BROADCAST, self.origin_x);
|
||||||
|
WriteCoord (MSG_BROADCAST, self.origin_y);
|
||||||
|
WriteCoord (MSG_BROADCAST, self.origin_z);
|
||||||
|
#endif // PC
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
SUB_Remove ();
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ray_VelocityIncrease()
|
||||||
|
// Constant think function to speed up the Beam gradually.
|
||||||
|
//
|
||||||
|
void() Ray_VelocityIncrease =
|
||||||
|
{
|
||||||
|
self.velocity *= 1.5;
|
||||||
|
self.nextthink = time + 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ray_Impact()
|
||||||
|
// When something touches the Beam, check it's validity for
|
||||||
|
// being used to set up the explosion.
|
||||||
|
//
|
||||||
|
void() Ray_Impact =
|
||||||
|
{
|
||||||
|
if (!other.solid || other.solid == SOLID_TRIGGER)
|
||||||
|
if (other != world)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (other == self.owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float direct_impact;
|
||||||
|
|
||||||
|
if (other.flags & FL_MONSTER)
|
||||||
|
direct_impact = true;
|
||||||
|
else
|
||||||
|
direct_impact = false;
|
||||||
|
|
||||||
|
Ray_BeamExplode(direct_impact);
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// W_FireRay()
|
||||||
|
// Called by weapon_core for the Ray firetype. Sets up the
|
||||||
|
// beam/missile and prepares it for impact and force forward.
|
||||||
|
//
|
||||||
|
void() W_FireRay =
|
||||||
|
{
|
||||||
|
// Initially define the beam.
|
||||||
|
entity porter;
|
||||||
|
porter = spawn();
|
||||||
|
porter.owner = self;
|
||||||
|
porter.movetype = MOVETYPE_FLY;
|
||||||
|
porter.weapon = self.weapon;
|
||||||
|
porter.solid = SOLID_BBOX;
|
||||||
|
|
||||||
|
// Start initial velocity projection.
|
||||||
|
makevectors(self.v_angle);
|
||||||
|
porter.velocity = v_forward*2000;
|
||||||
|
porter.avelocity = '0 0 0';
|
||||||
|
|
||||||
|
// Make sure our angle is always FORWARD
|
||||||
|
porter.angles = vectoangles(porter.velocity);
|
||||||
|
porter.angles_z += (porter.angles_z + 180 < 360)? 180 : -180;
|
||||||
|
porter.angles = vectoangles(v_forward);
|
||||||
|
porter.v_angle = '0 0 200';
|
||||||
|
|
||||||
|
// Prepare for Impact and Force forward.
|
||||||
|
porter.touch = Ray_Impact;
|
||||||
|
porter.think = Ray_VelocityIncrease;
|
||||||
|
porter.nextthink = time + 0.1;
|
||||||
|
|
||||||
|
// Set model.
|
||||||
|
setmodel(porter, "models/misc/raybeam.mdl");
|
||||||
|
setsize(porter, '0 0 0', '0 0 0');
|
||||||
|
|
||||||
|
// Prepare trail effects.
|
||||||
|
if (IsPapWeapon(porter.weapon)) {
|
||||||
|
#ifdef HANDHELD
|
||||||
|
porter.effects = EF_RAYRED;
|
||||||
|
#endif // HANDHELD
|
||||||
|
#ifdef QUAKESPASM
|
||||||
|
porter.effects = EF_RED;
|
||||||
|
#endif // QUAKESPASM
|
||||||
|
#ifdef PC
|
||||||
|
Light_Custom(porter, false, 75, 2, 0.25, 0.25);
|
||||||
|
#endif // PC
|
||||||
|
} else {
|
||||||
|
#ifdef HANDHELD
|
||||||
|
porter.effects = EF_RAYGREEN;
|
||||||
|
#endif // HANDHELD
|
||||||
|
#ifdef QUAKESPASM
|
||||||
|
porter.effects = EF_GREEN;
|
||||||
|
#endif // QUAKESPASM
|
||||||
|
#ifdef PC
|
||||||
|
Light_Custom(porter, false, 75, 0.25, 2, 0.25);
|
||||||
|
#endif // PC
|
||||||
|
}
|
||||||
|
|
||||||
|
// final setup!
|
||||||
|
porter.origin = self.origin + self.view_ofs;
|
||||||
|
porter.origin += v_forward * 0;
|
||||||
|
setorigin(porter, porter.origin);
|
||||||
|
|
||||||
|
self.animend = ReturnWeaponModel;
|
||||||
|
self.callfuncat = 0;
|
||||||
|
}
|
|
@ -1072,103 +1072,6 @@ void(float side) W_FireGrenade =
|
||||||
setorigin(nade, nade.origin);
|
setorigin(nade, nade.origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// RAY GUN - modified from patch <3
|
|
||||||
//
|
|
||||||
|
|
||||||
void() RayBulletExplode =
|
|
||||||
{
|
|
||||||
DamgageExplode (self, self.owner, 1800, 1800, 64);//we want A SMALL radius of explosion
|
|
||||||
|
|
||||||
// MOTO - FTE explosions are.. large, let's flash instead.
|
|
||||||
|
|
||||||
#ifdef PC
|
|
||||||
te_smallflash(self.origin);
|
|
||||||
#else
|
|
||||||
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
|
|
||||||
#ifdef HANDHELD
|
|
||||||
if (self.effects & EF_RAYGREEN)
|
|
||||||
WriteByte (MSG_BROADCAST, TE_RAYSPLASHGREEN);
|
|
||||||
else
|
|
||||||
WriteByte (MSG_BROADCAST, TE_RAYSPLASHRED);
|
|
||||||
#else
|
|
||||||
WriteByte (MSG_BROADCAST, TE_EXPLOSION);
|
|
||||||
#endif
|
|
||||||
WriteCoord (MSG_BROADCAST, self.origin_x);
|
|
||||||
WriteCoord (MSG_BROADCAST, self.origin_y);
|
|
||||||
WriteCoord (MSG_BROADCAST, self.origin_z);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SUB_Remove ();
|
|
||||||
};
|
|
||||||
|
|
||||||
void() velocity_increase_ray =
|
|
||||||
{
|
|
||||||
if (!other.solid || other.solid == SOLID_TRIGGER)
|
|
||||||
if (other != world)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (other == self.owner)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (other.solid == SOLID_NOT) {
|
|
||||||
RayBulletExplode();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.velocity = self.velocity*1.5;
|
|
||||||
|
|
||||||
RayBulletExplode();
|
|
||||||
};
|
|
||||||
|
|
||||||
void() W_FireRay =
|
|
||||||
{
|
|
||||||
local entity porter;
|
|
||||||
|
|
||||||
porter = spawn();
|
|
||||||
porter.owner = self;
|
|
||||||
porter.movetype = MOVETYPE_FLY;
|
|
||||||
porter.solid = SOLID_BBOX;
|
|
||||||
|
|
||||||
makevectors(self.v_angle);
|
|
||||||
|
|
||||||
porter.velocity = v_forward*2000;
|
|
||||||
porter.avelocity = '0 0 0';
|
|
||||||
|
|
||||||
porter.angles = vectoangles(porter.velocity);
|
|
||||||
porter.angles_z += (porter.angles_z + 180 < 360)? 180 : -180;
|
|
||||||
porter.angles = vectoangles(v_forward);
|
|
||||||
|
|
||||||
porter.v_angle = '0 0 200';
|
|
||||||
|
|
||||||
porter.touch = velocity_increase_ray;
|
|
||||||
setmodel(porter, "models/misc/raybeam.mdl");
|
|
||||||
setsize(porter, '0 0 0', '0 0 0');
|
|
||||||
|
|
||||||
|
|
||||||
if (self.weapon == W_PORTER) {
|
|
||||||
#ifdef HANDHELD
|
|
||||||
porter.effects = EF_RAYRED;
|
|
||||||
#else
|
|
||||||
porter.effects = EF_RED;
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#ifdef HANDHELD
|
|
||||||
porter.effects = EF_RAYGREEN;
|
|
||||||
#else
|
|
||||||
porter.effects = EF_GREEN;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
porter.origin = self.origin + self.view_ofs;
|
|
||||||
porter.origin += v_forward * 0;
|
|
||||||
|
|
||||||
setorigin(porter, porter.origin);
|
|
||||||
|
|
||||||
self.animend = ReturnWeaponModel;
|
|
||||||
self.callfuncat = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove zombie, add money, request clone spawn.
|
// Remove zombie, add money, request clone spawn.
|
||||||
void(entity hit_ent) LightningHit =
|
void(entity hit_ent) LightningHit =
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue