set g_balance_arc_beam_refire 0.5
set g_balance_arc_beam_returnspeed 8
set g_balance_arc_beam_tightness 0.5
+set g_balance_arc_burst_ammo 0
set g_balance_arc_burst_damage 500
set g_balance_arc_burst_healing_aps 100
set g_balance_arc_burst_healing_hps 100
set g_balance_devastator_remote_damage 70
set g_balance_devastator_remote_edgedamage 35
set g_balance_devastator_remote_force 400
+set g_balance_devastator_remote_jump_damage 40
+set g_balance_devastator_remote_jump_radius 200
+set g_balance_devastator_remote_jump_velocity_z_add 500
+set g_balance_devastator_remote_jump_velocity_z_max 1500
+set g_balance_devastator_remote_jump_velocity_z_min 500
set g_balance_devastator_remote_radius 110
set g_balance_devastator_speed 1300
set g_balance_devastator_speedaccel 1300
set g_balance_devastator_speedstart 1000
set g_balance_devastator_switchdelay_drop 0.3
set g_balance_devastator_switchdelay_raise 0.2
-set g_balance_devastator_weaponreplace "arc"
+set g_balance_devastator_weaponreplace ""
set g_balance_devastator_weaponstart 0
set g_balance_devastator_weaponstartoverride -1
set g_balance_devastator_weaponthrowable 1
-// Mark all cvars listed in cl_forced_saved_cvars as saved. That way they'll never disappear from config.cfg.
-alias _cl_forced_saved_cvars_next "set _forced_saved_cvar_ doit; set _forced_saved_cvar_${1 ?} done; _cl_forced_saved_cvars_chck ${* ?}"
-alias _cl_forced_saved_cvars_chck "_cl_forced_saved_cvars_$_forced_saved_cvar_ ${* ?}"
-alias _cl_forced_saved_cvars_doit "seta $1 \"${$1}\"; _cl_forced_saved_cvars_next ${2- ?}"
-alias _cl_forced_saved_cvars_done ""
-_cl_forced_saved_cvars_next $cl_forced_saved_cvars
+// Mark all cvars listed in menu_forced_saved_cvars as saved. That way they'll never disappear from config.cfg.
+alias _menu_forced_saved_cvars_next "set _forced_saved_cvar_ doit; set _forced_saved_cvar_${1 ?} done; _menu_forced_saved_cvars_chck ${* ?}"
+alias _menu_forced_saved_cvars_chck "_menu_forced_saved_cvars_$_forced_saved_cvar_ ${* ?}"
+alias _menu_forced_saved_cvars_doit "seta $1 \"${$1}\"; _menu_forced_saved_cvars_next ${2- ?}"
+alias _menu_forced_saved_cvars_done ""
+_menu_forced_saved_cvars_next ${menu_forced_saved_cvars ?}
float TrueAimCheck()
{
- float nudge = 1; // added to traceline target and subtracted from result
+ float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
vector vecs, trueaimpoint, w_shotorg;
vector mi, ma, dv;
float shottype;
self.effects = self.csqcmodel_effects;
self.modelflags = self.csqcmodel_modelflags;
}
+void Reset_ArcBeam(void);
void CSQCModel_Effects_PostUpdate(void)
{
+ if (self == csqcplayer) {
+ if (self.csqcmodel_teleported) {
+ Reset_ArcBeam();
+ }
+ }
self.csqcmodel_effects = self.effects;
self.csqcmodel_modelflags = self.modelflags;
self.effects = 0;
#define HUD_PANEL(NAME,draw_func,name) \
float HUD_PANEL_##NAME; \
- void ##draw_func(void); \
+ void draw_func(void); \
void RegisterHUD_Panel_##NAME() \
{ \
HUD_PANEL_LAST = HUD_PANEL_##NAME = HUD_PANEL_NUM; \
hud_panelent.classname = "hud_panel"; \
hud_panelent.panel_name = #name; \
hud_panelent.panel_id = HUD_PANEL_##NAME; \
- hud_panelent.panel_draw = ##draw_func; \
+ hud_panelent.panel_draw = draw_func; \
++HUD_PANEL_NUM; \
} \
ACCUMULATE_FUNCTION(RegisterHUD_Panels, RegisterHUD_Panel_##NAME);
.float beam_prev;
.float beam_initialized;
.float beam_bursting;
+.float beam_teleporttime;
#endif
#ifdef CSQC
void Ent_ReadArcBeam(float isnew);
return TRUE;
}
+void Reset_ArcBeam(entity player, vector forward)
+{
+ if (!player.arc_beam) {
+ return;
+ }
+ player.arc_beam.beam_dir = forward;
+ player.arc_beam.beam_teleporttime = time;
+}
+
void W_Arc_Beam_Think(void)
{
if(self != self.owner.arc_beam)
||
self.owner.deadflag != DEAD_NO
||
- (!self.owner.BUTTON_ATCK && !self.beam_bursting)
+ (!self.owner.BUTTON_ATCK /* FIXME(Samual): && !self.beam_bursting */)
||
self.owner.freezetag_frozen
)
WEP_CVAR(arc, beam_range)
);
+ // After teleport, "lock" the beam until the teleport is confirmed.
+ if (time < self.beam_teleporttime + ANTILAG_LATENCY(self.owner)) {
+ w_shotdir = self.beam_dir;
+ }
+
// network information: shot origin and want/aim direction
if(self.beam_start != w_shotorg)
{
}
}
+ // te_explosion(trace_endpos);
+
// if we're bursting, use burst visual effects
new_beam_type += burst;
void W_Arc_Beam(float burst)
{
+ // FIXME(Samual): remove this when overheat and burst work.
+ if (burst)
+ {
+ centerprint(self, "^4NOTE:^7 Arc burst (secondary) is not implemented yet.");
+ }
+
// only play fire sound if 1 sec has passed since player let go the fire button
if(time - self.beam_prev > 1)
{
}
#endif
- if(self.BUTTON_ATCK || self.BUTTON_ATCK2 || self.arc_beam.beam_bursting)
+ if(self.BUTTON_ATCK || self.BUTTON_ATCK2 /* FIXME(Samual): || self.arc_beam.beam_bursting */)
{
if(self.BUTTON_ATCK_prev)
{
Draw_ArcBeam_callback_last_bottom = WarpZone_UnTransformOrigin(WarpZone_trace_transform, bottom);
}
+void Reset_ArcBeam(void)
+{
+ entity e;
+ for (e = world; (e = findfloat(e, beam_usevieworigin, 1)); ) {
+ e.beam_initialized = FALSE;
+ }
+ for (e = world; (e = findfloat(e, beam_usevieworigin, 2)); ) {
+ e.beam_initialized = FALSE;
+ }
+}
+
void Draw_ArcBeam(void)
{
if(!self.beam_usevieworigin)
// into a weapon system for client code.
// find where we are aiming
- makevectors(view_angles);
+ makevectors(warpzone_save_view_angles);
+ vector forward = v_forward;
+ vector right = v_right;
+ vector up = v_up;
// decide upon start position
if(self.beam_usevieworigin == 2)
- { start_pos = view_origin; }
+ { start_pos = warpzone_save_view_origin; }
else
{ start_pos = self.origin; }
// trace forward with an estimation
WarpZone_TraceLine(
start_pos,
- start_pos + view_forward * self.beam_range,
+ start_pos + forward * self.beam_range,
MOVE_NOMONSTERS,
self
);
// untransform in case our trace went through a warpzone
- vector vf, vr, vu;
- vf = view_forward;
- vr = view_right;
- vu = view_up;
vector end_pos = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
- view_forward = vf;
- view_right = vr;
- view_up = vu;
// un-adjust trueaim if shotend is too close
- if(vlen(end_pos - view_origin) < g_trueaim_minrange)
- end_pos = view_origin + (view_forward * g_trueaim_minrange);
+ if(vlen(end_pos - start_pos) < g_trueaim_minrange)
+ end_pos = start_pos + (forward * g_trueaim_minrange);
// move shot origin to the actual gun muzzle origin
vector origin_offset =
- view_forward * self.beam_shotorigin_x
- + view_right * -self.beam_shotorigin_y
- + view_up * self.beam_shotorigin_z;
+ right * -self.beam_shotorigin_y
+ + up * self.beam_shotorigin_z;
start_pos = start_pos + origin_offset;
+ // Move it also forward, but only as far as possible without hitting anything. Don't poke into walls!
+ traceline(start_pos, start_pos + forward * self.beam_shotorigin_x, MOVE_NORMAL, self);
+ start_pos = trace_endpos;
+
// calculate the aim direction now
wantdir = normalize(end_pos - start_pos);
beamdir = self.beam_dir;
// finally, set self.angles to the proper direction so that muzzle attachment points in proper direction
- self.angles = fixedvectoangles2(view_forward, view_up);
+ self.angles = fixedvectoangles2(forward, up); // TODO(Samual): is this == warpzone_save_view_angles?
}
else
{
}
setorigin(self, start_pos);
- //self.beam_muzzleentity.angles_z = random() * 360; // WEAPONTODO: use avelocity instead?
+ self.beam_muzzleentity.angles_z = random() * 360; // WEAPONTODO: use avelocity instead?
vector beam_endpos = (start_pos + (beamdir * self.beam_range));
vector beam_controlpoint = start_pos + wantdir * (self.beam_range * (1 - self.beam_tightness));
Draw_ArcBeam_callback
);
- // Do all the transforms for warpzones right now, as we already
- // "are" in the post-trace system (if we hit a player, that's
- // always BEHIND the last passed wz).
+ // Do all the transforms for warpzones right now, as we already "are" in the post-trace
+ // system (if we hit a player, that's always BEHIND the last passed wz).
last_origin = trace_endpos;
start_pos = WarpZone_TransformOrigin(WarpZone_trace_transform, start_pos);
beam_controlpoint = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_controlpoint);
Draw_ArcBeam_callback_last_top = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_top);
Draw_ArcBeam_callback_last_bottom = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_bottom);
- //printf("segment: %d, warpzone transform: %d\n", i, (WarpZone_trace_transform != world));
-
- // WEAPONTODO:
- // Figure out some way to detect a collision with geometry with callback...
- // That way we can know when we are done drawing the beam and skip
- // the rest of the segments without breaking warpzone support.
- //
- // Not needed to do this in the callback. trace_fraction != 1 is a good abort condition.
-
- if (trace_fraction < 1)
- break;
+ if(trace_fraction < 1) { break; }
}
// visual effects for startpoint and endpoint
if(self.beam_hiteffect)
{
+ // FIXME we really should do this on the server so it actually
+ // matches gameplay. What this client side stuff is doing is no
+ // more than guesswork.
pointparticles(
self.beam_hiteffect,
last_origin,
w_cvar(id, sn, NONE, remote_damage) \
w_cvar(id, sn, NONE, remote_edgedamage) \
w_cvar(id, sn, NONE, remote_force) \
+ w_cvar(id, sn, NONE, remote_jump_damage) \
+ w_cvar(id, sn, NONE, remote_jump_radius) \
+ w_cvar(id, sn, NONE, remote_jump_velocity_z_add) \
+ w_cvar(id, sn, NONE, remote_jump_velocity_z_max) \
+ w_cvar(id, sn, NONE, remote_jump_velocity_z_min) \
w_cvar(id, sn, NONE, remote_radius) \
w_cvar(id, sn, NONE, speed) \
w_cvar(id, sn, NONE, speedaccel) \
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
- RadiusDamage(self, self.realowner, WEP_CVAR(devastator, damage), WEP_CVAR(devastator, edgedamage), WEP_CVAR(devastator, radius), world, world, WEP_CVAR(devastator, force), self.projectiledeathtype, other);
+ RadiusDamage(
+ self,
+ self.realowner,
+ WEP_CVAR(devastator, damage),
+ WEP_CVAR(devastator, edgedamage),
+ WEP_CVAR(devastator, radius),
+ world,
+ world,
+ WEP_CVAR(devastator, force),
+ self.projectiledeathtype,
+ other
+ );
if(self.realowner.weapon == WEP_DEVASTATOR)
{
self.event_damage = func_null;
self.takedamage = DAMAGE_NO;
- RadiusDamage(self, self.realowner, WEP_CVAR(devastator, remote_damage), WEP_CVAR(devastator, remote_edgedamage), WEP_CVAR(devastator, remote_radius), world, world, WEP_CVAR(devastator, remote_force), self.projectiledeathtype | HITTYPE_BOUNCE, world);
+ float handled_as_rocketjump = FALSE;
+
+ entity head = WarpZone_FindRadius(
+ self.origin,
+ WEP_CVAR(devastator, remote_jump_radius),
+ FALSE
+ );
+
+ while(head)
+ {
+ if(head.takedamage && (head == self.realowner))
+ {
+ float distance_to_head = vlen(self.origin - head.WarpZone_findradius_nearest);
+ if(distance_to_head <= WEP_CVAR(devastator, remote_jump_radius))
+ {
+ // we handled this as a rocketjump :)
+ handled_as_rocketjump = TRUE;
+
+ // modify velocity
+ head.velocity_x *= 0.9;
+ head.velocity_y *= 0.9;
+ head.velocity_z = bound(
+ WEP_CVAR(devastator, remote_jump_velocity_z_min),
+ head.velocity_z + WEP_CVAR(devastator, remote_jump_velocity_z_add),
+ WEP_CVAR(devastator, remote_jump_velocity_z_max)
+ );
+
+ // now do the damage
+ RadiusDamage(
+ self,
+ head,
+ WEP_CVAR(devastator, remote_jump_damage),
+ WEP_CVAR(devastator, remote_jump_damage),
+ WEP_CVAR(devastator, remote_jump_radius),
+ world,
+ head,
+ 0,
+ self.projectiledeathtype | HITTYPE_BOUNCE,
+ world
+ );
+ break;
+ }
+ }
+ head = head.chain;
+ }
+
+ RadiusDamage(
+ self,
+ self.realowner,
+ WEP_CVAR(devastator, remote_damage),
+ WEP_CVAR(devastator, remote_edgedamage),
+ WEP_CVAR(devastator, remote_radius),
+ (handled_as_rocketjump ? head : world),
+ world,
+ WEP_CVAR(devastator, remote_force),
+ self.projectiledeathtype | HITTYPE_BOUNCE,
+ world
+ );
if(self.realowner.weapon == WEP_DEVASTATOR)
{
void W_Devastator_Think(void)
{
vector desireddir, olddir, newdir, desiredorigin, goal;
-#if 0
- float cosminang, cosmaxang, cosang;
-#endif
float velspeed, f;
self.nextthink = time;
if(time > self.cnt)
// create properties for weapon settings
#define WEP_ADD_PROP(wepid,wepname,type,prop,name) \
- .type ##prop; \
+ .type prop; \
[[last]] type autocvar_g_balance_##wepname##_##name;
// read cvars from weapon settings
#define TELEPORT_NORMAL 1 // play sounds/effects etc
#define TELEPORT_SIMPLE 2 // only do teleport, nothing special
+void Reset_ArcBeam(entity player, vector forward);
void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
{
entity telefragger;
player.velocity = to_velocity;
BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+ makevectors(player.angles);
+ Reset_ArcBeam(player, v_forward);
UpdateCSQCProjectileAfterTeleport(player);
if(IS_PLAYER(player))
void WarpZone_PostTeleportPlayer_Callback(entity pl)
{
+ makevectors(pl.angles);
+ Reset_ArcBeam(pl, v_forward);
UpdateCSQCProjectileAfterTeleport(pl);
// "disown" projectiles after teleport
if(pl.owner)
// make sure you call makevectors first (FIXME?)
void W_SetupShot_Dir_ProjectileSize_Range(entity ent, vector s_forward, vector mi, vector ma, float antilag, float recoil, string snd, float chan, float maxdamage, float range)
{
- float nudge = 1; // added to traceline target and subtracted from result
+ float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
float oldsolid;
vector vecs, dv;
oldsolid = ent.dphitcontentsmask;
vector org, ang, nearclip, corner0, corner1, corner2, corner3, o;
float f;
- org = getpropertyvec(VF_ORIGIN);
- ang = getpropertyvec(VF_ANGLES);
+ warpzone_save_view_origin = org = getpropertyvec(VF_ORIGIN);
+ warpzone_save_view_angles = ang = getpropertyvec(VF_ANGLES);
#ifdef WORKAROUND_XON010
float dirty;
dirty = checkextension("DP_CSQC_ROTATEMOVES");
void WarpZone_Init();
void WarpZone_Shutdown();
+
+vector warpzone_save_view_origin;
+vector warpzone_save_view_angles;