Decouple precise crosshairs from weapons. 100% smoother now.

This commit is contained in:
Mari the Deer 2022-09-24 21:33:48 +02:00
commit 84fb9c036f
21 changed files with 194 additions and 269 deletions

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r502 \cu(Sat 24 Sep 14:56:35 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r502 \cu(2022-09-24 14:56:35)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r503 \cu(Sat 24 Sep 21:33:48 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r503 \cu(2022-09-24 21:33:48)\c-";

View file

@ -29,6 +29,7 @@ version "4.9"
#include "zscript/swwm_blod.zsc"
// handler code
#include "zscript/handler/swwm_handler_cheats.zsc"
#include "zscript/handler/swwm_handler_crosshair.zsc"
#include "zscript/handler/swwm_handler_damage.zsc"
#include "zscript/handler/swwm_handler_debugrender.zsc"
#include "zscript/handler/swwm_handler_flash.zsc"

View file

@ -44,6 +44,7 @@ Class DualPlasmaBlast : SWWMWeapon
Obituary "$O_PLASMABLAST";
SWWMWeapon.Tooltip "$TT_PLASMABLAST2";
SWWMWeapon.GetLine "getplasmablast2";
SWWMWeapon.NumCrosshairs 2;
Weapon.SlotNumber 2;
Weapon.SlotPriority 4.;
Weapon.SelectionOrder 1050;

View file

@ -45,7 +45,7 @@ Class HeavyMahSheenGun : SWWMWeapon
c.vel += vel*.5;
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10,0,-4);
}

View file

@ -200,7 +200,7 @@ Class MisterRifle : SWWMWeapon
lastfiremode = firemode+1;
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10,2.8,-2.4);
}

View file

@ -35,7 +35,7 @@ Class Quadravol : SWWMWeapon
else origin.A_StartSound(UpSound,CHAN_WEAPON,CHANF_OVERLAP);
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return onehand?(10,3.5,-2):(10,3,-2.5);
}

View file

@ -0,0 +1,154 @@
// precise crosshair (now fully independent from weapons)
const MAX_CROSSHAIRS = 25;
Class SWWMCrosshairTracer : LineTracer
{
Actor ignoreme;
override ETraceStatus TraceCallback()
{
if ( Results.HitType == TRACE_HitActor )
{
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop;
return TRACE_Skip;
}
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
{
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
return TRACE_Stop;
return TRACE_Skip;
}
return TRACE_Stop;
}
}
extend Class SWWMHandler
{
transient ui SWWMCrosshairTracer ctr; // very simple crosshair tracer
transient ui int numcrosshairs; // how many crosshairs the current weapon has
transient ui Vector3 tpos[MAX_CROSSHAIRS]; // current trace positions in world space
transient ui Color tcol[MAX_CROSSHAIRS]; // current crosshair colors
transient ui SWWMProjectionData tprojdata; // cached Gutamatics projection data
transient ui Vector3 lagtndc[MAX_CROSSHAIRS]; // "lagged" NDC for crosshairs
transient ui Weapon lasttw; // last player weapon, to "reset" crosshair positions
transient ui double prevframe; // previous frame timestamp
private ui void TraceCrosshairs( RenderEvent e )
{
// trace precise crosshair(s)
Vector3 traceofs[MAX_CROSSHAIRS];
let sw = SWWMWeapon(players[consoleplayer].ReadyWeapon);
if ( !sw )
{
numcrosshairs = 1;
traceofs[0] = (0,0,0);
}
else
{
numcrosshairs = sw.NumCrosshairs;
for ( int i=0; i<numcrosshairs; i++ )
traceofs[i] = sw.GetTraceOffset(i);
}
let mo = players[consoleplayer].mo;
if ( !ctr ) ctr = new("SWWMCrosshairTracer");
ctr.ignoreme = mo;
Vector3 x, y, z, ofs, origin;
Color col;
[x, y, z] = swwm_CoordUtil.GetAxes(e.ViewPitch,e.ViewAngle,e.ViewRoll);
int chp = crosshairhealth;
for ( int i=0; i<numcrosshairs; i++ )
{
origin = level.Vec3Offset(e.ViewPos,traceofs[i].x*x+traceofs[i].y*y+traceofs[i].z*z);
ctr.Trace(origin,level.PointInSector(origin.xy),x,10000.,0);
if ( chp >= 2 )
{
int hp = Clamp(mo.Health,0,200);
double sat = (hp<150)?1.:(1.-(hp-150)/100.);
Vector3 rgb = SWWMUtility.HSVtoRGB((hp/300.,sat,1.));
col = Color(int(rgb.x*255),int(rgb.y*255),int(rgb.z*255));
}
else if ( chp == 1 )
{
double hp = Clamp(mo.Health,0,100)/100.;
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
else if ( (ctr.Results.HitType == TRACE_HitActor) && ctr.Results.HitActor.bSHOOTABLE )
{
// show target health, rather than our own
double hp = ctr.Results.HitActor.Health/double(ctr.Results.HitActor.GetSpawnHealth());
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
else col = crosshaircolor;
if ( ctr.Results.HitType == TRACE_HitNone ) tpos[i] = level.Vec3Offset(origin,x*10000.);
else tpos[i] = ctr.Results.HitPos;
tcol[i] = col;
}
// copy over used slots to unused slots, so transition between weapons is smoother
int j = 0;
for ( int i=numcrosshairs; i<MAX_CROSSHAIRS; i++ )
{
tpos[i] = tpos[j];
tcol[i] = tcol[j];
j = (j+1)%numcrosshairs;
}
}
private ui void RenderCrosshairs( RenderEvent e )
{
double frametime = (MSTimeF()-prevframe)/1000.;
double theta = clamp(15.*frametime,0.,.5); // naive, but whatever
// draw precise crosshair(s)
if ( automapactive || !(players[consoleplayer].Camera is 'PlayerPawn') ) return;
if ( !swwm_precisecrosshair ) return;
if ( crosshairforce ) return;
if ( !crosshairon && (swwm_precisecrosshair <= 1) ) return;
int cnum = abs(CVar.FindCVar('crosshair').GetInt());
if ( !cnum ) return;
String tn = String.Format("XHAIR%s%d",(Screen.GetWidth()<640)?"S":"B",cnum);
TextureID ctex = TexMan.CheckForTexture(tn,TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture(String.Format("XHAIR%s1",(Screen.GetWidth()<640)?"S":"B"),TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture("XHAIRS1",TexMan.Type_MiscPatch);
Vector2 ts = TexMan.GetScaledSize(ctex);
double cs = crosshairscale;
double sz = 1.;
if ( cs > 0. ) sz = Screen.GetHeight()*cs/200.;
if ( crosshairgrow ) sz *= StatusBar.CrosshairSize;
SWWMUtility.PrepareProjData(tprojdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov);
let w = players[consoleplayer].ReadyWeapon;
for ( int i=0; i<numcrosshairs; i++ )
{
Vector3 cpos = tpos[i];
Color ccol = tcol[i];
Vector3 tdir = level.Vec3Diff(e.ViewPos,cpos);
// project
Vector3 ndc = SWWMUtility.ProjectPoint(tprojdata,e.ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
Vector2 vpos = SWWMUtility.NDCToViewport(tprojdata,ndc);
if ( !prevframe ) lagtndc[i] = ndc;
if ( lagtndc[i].z >= 1. ) continue;
Vector2 oldvpos = SWWMUtility.NDCToViewport(tprojdata,lagtndc[i]);
lagtndc[i] = SWWMUtility.LerpVector3(lagtndc[i],ndc,theta);
if ( lagtndc[i].z >= 1. ) continue;
Vector2 lagvpos = SWWMUtility.NDCToViewport(tprojdata,lagtndc[i]);
int streak = int(max(abs(oldvpos.x-lagvpos.x),abs(oldvpos.y-lagvpos.y)));
for ( int i=0; i<streak; i++ ) Screen.DrawTexture(ctex,false,int(SWWMUtility.lerp(oldvpos.x,lagvpos.x,i/double(streak))),int(SWWMUtility.lerp(oldvpos.y,lagvpos.y,i/double(streak))),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol,DTA_Alpha,(i*.5)/streak);
Screen.DrawTexture(ctex,false,int(lagvpos.x),int(lagvpos.y),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol);
}
// copy over used slots to unused slots, so transition between weapons is smoother
int j = 0;
for ( int i=numcrosshairs; i<MAX_CROSSHAIRS; i++ )
{
lagtndc[i] = lagtndc[j];
j = (j+1)%numcrosshairs;
}
prevframe = MSTimeF();
}
}

View file

@ -45,16 +45,6 @@ Class SWWMGesture : SWWMWeapon
{
return false;
}
override void RenderUnderlay( RenderEvent e )
{
Super.RenderUnderlay(e);
// avoid jumpy switching
if ( formerweapon is 'SWWMWeapon' )
{
SWWMWeapon(formerweapon).lagvpos = lagvpos;
SWWMWeapon(formerweapon).prevframe = prevframe;
}
}
override void DoEffect()
{
Super.DoEffect();
@ -666,16 +656,6 @@ Class SWWMItemGesture : SWWMWeapon abstract
{
return false;
}
override void RenderUnderlay( RenderEvent e )
{
Super.RenderUnderlay(e);
// avoid jumpy switching
if ( gest && (gest.formerweapon is 'SWWMWeapon') )
{
SWWMWeapon(gest.formerweapon).lagvpos = lagvpos;
SWWMWeapon(gest.formerweapon).prevframe = prevframe;
}
}
override void DoEffect()
{
Super.DoEffect();

View file

@ -311,6 +311,8 @@ Class SWWMHandler : EventHandler
sw.RenderUnderlay(e);
if ( sw.bHASSCRTEX ) sw.RenderTexture(e);
}
TraceCrosshairs(e);
RenderCrosshairs(e);
if ( !statusbar || !(statusbar is 'SWWMStatusBar') ) return;
SWWMStatusBar(statusbar).viewpos = e.viewpos;
SWWMStatusBar(statusbar).viewrot = (e.viewangle,e.viewpitch,e.viewroll);

View file

@ -432,6 +432,10 @@ Class SWWMWeapon : Weapon abstract
virtual ui void DrawWeapon( double TicFrac, double bx, double by, double hs, Vector2 ss )
{
}
// extra drawing, usually scopes
virtual ui void RenderUnderlay( RenderEvent e )
{
}
// HUD-side ticking
virtual ui void HudTick()
{

View file

@ -1,32 +1,15 @@
// precise crosshair
Class SWWMCrosshairTracer : LineTracer
{
Actor ignoreme;
override ETraceStatus TraceCallback()
{
if ( Results.HitType == TRACE_HitActor )
{
if ( Results.HitActor == ignoreme ) return TRACE_Skip;
if ( Results.HitActor.bSHOOTABLE ) return TRACE_Stop;
return TRACE_Skip;
}
else if ( (Results.HitType == TRACE_HitWall) && (Results.Tier == TIER_Middle) )
{
if ( !Results.HitLine.sidedef[1] || (Results.HitLine.Flags&(Line.ML_BlockHitscan|Line.ML_BlockEverything)) )
return TRACE_Stop;
return TRACE_Skip;
}
return TRACE_Stop;
}
}
extend Class SWWMWeapon
{
ui SWWMCrosshairTracer ctr;
ui Vector2 lagvpos;
transient ui double prevframe;
int NumCrosshairs; // how many crosshairs this weapon has (for multi-barrel weapons, or dual-wielding)
Property NumCrosshairs : NumCrosshairs;
Default
{
SWWMWeapon.NumCrosshairs 1;
}
override void DoEffect()
{
@ -36,93 +19,8 @@ extend Class SWWMWeapon
else crosshair = 0;
}
// extra drawing, usually scopes
virtual ui void RenderUnderlay( RenderEvent e )
{
Vector3 cpos;
Color ccol;
[cpos, ccol] = TraceForCrosshair();
// avoid jumpy switching
if ( (Owner.player.PendingWeapon is 'SWWMWeapon') && (Owner.player.PendingWeapon != SisterWeapon) )
{
SWWMWeapon(Owner.player.PendingWeapon).lagvpos = lagvpos;
SWWMWeapon(Owner.player.PendingWeapon).prevframe = prevframe;
}
// draw custom crosshair
if ( automapactive || !(players[consoleplayer].Camera is 'PlayerPawn') ) return;
if ( !swwm_precisecrosshair ) return;
if ( crosshairforce ) return;
if ( !crosshairon && (swwm_precisecrosshair <= 1) ) return;
let sb = SWWMStatusBar(StatusBar);
if ( !sb ) return;
SWWMUtility.PrepareProjData(sb.projdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov);
Vector3 tdir = level.Vec3Diff(e.ViewPos,cpos);
// project
Vector3 ndc = SWWMUtility.ProjectPoint(sb.projdata,e.ViewPos+tdir);
if ( ndc.z >= 1. ) return;
Vector2 vpos = SWWMUtility.NDCToViewport(sb.projdata,ndc);
double frametime = (MSTimeF()-prevframe)/1000.;
double theta = clamp(15.*frametime,0.,.5); // naive, but whatever
Vector2 oldvpos = lagvpos;
if ( !prevframe || (lagvpos == (0,0)) ) oldvpos = lagvpos = vpos;
else lagvpos = SWWMUtility.LerpVector2(lagvpos,vpos,theta);
prevframe = MSTimeF();
int cnum = abs(CVar.FindCVar('crosshair').GetInt());
if ( !cnum ) return;
String tn = String.Format("XHAIR%s%d",(Screen.GetWidth()<640)?"S":"B",cnum);
TextureID ctex = TexMan.CheckForTexture(tn,TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture(String.Format("XHAIR%s1",(Screen.GetWidth()<640)?"S":"B"),TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture("XHAIRS1",TexMan.Type_MiscPatch);
Vector2 ts = TexMan.GetScaledSize(ctex);
double cs = crosshairscale;
double sz = 1.;
if ( cs > 0. ) sz = Screen.GetHeight()*cs/200.;
if ( crosshairgrow ) sz *= sb.CrosshairSize;
int streak = int(max(abs(oldvpos.x-lagvpos.x),abs(oldvpos.y-lagvpos.y)));
for ( int i=0; i<streak; i++ ) Screen.DrawTexture(ctex,false,int(SWWMUtility.lerp(oldvpos.x,lagvpos.x,i/double(streak))),int(SWWMUtility.lerp(oldvpos.y,lagvpos.y,i/double(streak))),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol,DTA_Alpha,(i*.5)/streak);
Screen.DrawTexture(ctex,false,int(lagvpos.x),int(lagvpos.y),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol);
}
ui Vector3, Color TraceForCrosshair()
{
if ( !ctr ) ctr = new("SWWMCrosshairTracer");
ctr.ignoreme = Owner;
Vector3 x, y, z, ofs;
double s;
[x, y, z] = swwm_CoordUtil.GetAxes(Owner.pitch,Owner.angle,Owner.roll);
ofs = GetTraceOffset();
Vector3 origin = level.Vec3Offset(Owner.Vec2OffsetZ(0,0,Owner.player.viewz),ofs.x*x+ofs.y*y+ofs.z*z);
ctr.Trace(origin,level.PointInSector(origin.xy),x,10000.,0);
Color col = crosshaircolor;
int chp = crosshairhealth;
if ( chp >= 2 )
{
int hp = Clamp(Owner.Health,0,200);
double sat = (hp<150)?1.:(1.-(hp-150)/100.);
Vector3 rgb = SWWMUtility.HSVtoRGB((hp/300.,sat,1.));
col = Color(int(rgb.x*255),int(rgb.y*255),int(rgb.z*255));
}
else if ( chp == 1 )
{
double hp = Clamp(Owner.Health,0,100)/100.;
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
else if ( (ctr.Results.HitType == TRACE_HitActor) && ctr.Results.HitActor.bSHOOTABLE )
{
// show target health, rather than our own
double hp = ctr.Results.HitActor.Health/double(ctr.Results.HitActor.GetSpawnHealth());
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
if ( ctr.Results.HitType == TRACE_HitNone ) return level.Vec3Offset(origin,x*10000.), col;
else return ctr.Results.HitPos, col;
}
// where the trace is coming from relative to eyes
virtual clearscope Vector3 GetTraceOffset() const
virtual clearscope Vector3 GetTraceOffset( int index ) const
{
return (0.,0.,0.);
}

View file

@ -155,7 +155,7 @@ Class Hellblazer : SWWMWeapon
lastammo = nextammo;
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,3.5,-5.);
}

View file

@ -15,8 +15,6 @@ Class Wallbuster : SWWMWeapon
Class<Ammo> curobt;
ui Vector2 lagvpos25[25];
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
{
if ( curobt is 'RedShell' ) return StringTable.Localize("$O_WALLBUSTER_RED");
@ -40,118 +38,6 @@ Class Wallbuster : SWWMWeapon
SelectionOrder = 1400;
}
override void RenderUnderlay( RenderEvent e )
{
Vector3 cpos;
Color ccol;
[cpos, ccol] = TraceForCrosshair();
// avoid jumpy switching
if ( Owner.player.PendingWeapon is 'SWWMWeapon' )
{
SWWMWeapon(Owner.player.PendingWeapon).lagvpos = lagvpos;
SWWMWeapon(Owner.player.PendingWeapon).prevframe = prevframe;
}
Vector3 cpos25[25];
Color ccol25[25];
// 25-trace
for ( int i=0; i<25; i++ )
[cpos25[i], ccol25[i]] = TraceForCrosshair25(i);
// draw custom crosshair
if ( automapactive || !(players[consoleplayer].Camera is 'PlayerPawn') ) return;
if ( !swwm_precisecrosshair ) return;
if ( crosshairforce ) return;
if ( !crosshairon && (swwm_precisecrosshair <= 1) ) return;
let sb = SWWMStatusBar(StatusBar);
if ( !sb ) return;
SWWMUtility.PrepareProjData(sb.projdata,e.ViewPos,e.ViewAngle,e.ViewPitch,e.ViewRoll,players[consoleplayer].fov);
int cnum = abs(CVar.FindCVar('crosshair').GetInt());
if ( !cnum ) return;
String tn = String.Format("XHAIR%s%d",(Screen.GetWidth()<640)?"S":"B",cnum);
TextureID ctex = TexMan.CheckForTexture(tn,TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture(String.Format("XHAIR%s1",(Screen.GetWidth()<640)?"S":"B"),TexMan.Type_MiscPatch);
if ( !ctex.IsValid() ) ctex = TexMan.CheckForTexture("XHAIRS1",TexMan.Type_MiscPatch);
Vector2 ts = TexMan.GetScaledSize(ctex);
double cs = crosshairscale;
double sz = 1.;
if ( cs > 0. ) sz = Screen.GetHeight()*cs/200.;
if ( crosshairgrow ) sz *= sb.CrosshairSize;
Vector3 tdir = level.Vec3Diff(e.ViewPos,cpos);
// project
Vector3 ndc = SWWMUtility.ProjectPoint(sb.projdata,e.ViewPos+tdir);
if ( ndc.z >= 1. ) return;
Vector2 vpos = SWWMUtility.NDCToViewport(sb.projdata,ndc);
double frametime = (MSTimeF()-prevframe)/1000.;
double theta = clamp(15.*frametime,0.,1.); // naive, but whatever
if ( !prevframe || (lagvpos == (0,0)) ) lagvpos = vpos;
else lagvpos = SWWMUtility.LerpVector2(lagvpos,vpos,theta);
Vector2 oldvpos;
for ( int i=0; i<25; i++ )
{
tdir = level.Vec3Diff(e.ViewPos,cpos25[i]);
// project
ndc = SWWMUtility.ProjectPoint(sb.projdata,e.ViewPos+tdir);
if ( ndc.z >= 1. ) continue;
vpos = SWWMUtility.NDCToViewport(sb.projdata,ndc);
oldvpos = lagvpos25[i];
if ( !prevframe || (lagvpos25[i] == (0,0)) ) oldvpos = lagvpos25[i] = vpos;
else lagvpos25[i] = SWWMUtility.LerpVector2(lagvpos25[i],vpos,theta);
int streak = int(max(abs(oldvpos.x-lagvpos25[i].x),abs(oldvpos.y-lagvpos25[i].y)));
for ( int j=0; j<streak; j++ ) Screen.DrawTexture(ctex,false,int(SWWMUtility.lerp(oldvpos.x,lagvpos25[i].x,j/double(streak))),int(SWWMUtility.lerp(oldvpos.y,lagvpos25[i].y,j/double(streak))),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol,DTA_Alpha,(j*.5)/streak);
Screen.DrawTexture(ctex,false,int(lagvpos25[i].x),int(lagvpos25[i].y),DTA_DestWidthF,ts.x*sz,DTA_DestHeightF,ts.y*sz,DTA_AlphaChannel,true,DTA_FillColor,ccol25[i]);
}
prevframe = MSTimeF();
}
ui Vector3, Color TraceForCrosshair25( int i )
{
if ( !ctr ) ctr = new("SWWMCrosshairTracer");
ctr.ignoreme = Owner;
Vector3 x, y, z, ofs;
double s;
[x, y, z] = swwm_CoordUtil.GetAxes(Owner.pitch,Owner.angle,Owner.roll);
ofs = GetTraceOffset25(i);
Vector3 origin = level.Vec3Offset(Owner.Vec2OffsetZ(0,0,Owner.player.viewz),ofs.x*x+ofs.y*y+ofs.z*z);
ctr.Trace(origin,level.PointInSector(origin.xy),x,10000.,0);
Color col = crosshaircolor;
int chp = crosshairhealth;
if ( chp >= 2 )
{
int hp = Clamp(Owner.Health,0,200);
double sat = (hp<150)?1.:(1.-(hp-150)/100.);
Vector3 rgb = SWWMUtility.HSVtoRGB((hp/300.,sat,1.));
col = Color(int(rgb.x*255),int(rgb.y*255),int(rgb.z*255));
}
else if ( chp == 1 )
{
double hp = Clamp(Owner.Health,0,100)/100.;
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
else if ( (ctr.Results.HitType == TRACE_HitActor) && ctr.Results.HitActor.bSHOOTABLE )
{
// show target health, rather than our own
double hp = ctr.Results.HitActor.Health/double(ctr.Results.HitActor.GetSpawnHealth());
if ( hp <= 0 ) col = Color(255,0,0);
else if ( hp < .3 ) col = Color(255,int(hp*255/.3),0);
else if ( hp < .85 ) col = Color(int((.6-hp)*255/.3),255,0);
else col = Color(0,255,0);
}
if ( ctr.Results.HitType == TRACE_HitNone ) return level.Vec3Offset(origin,x*10000.), col;
else return ctr.Results.HitPos, col;
}
clearscope Vector3 GetTraceOffset25( int i ) const
{
double t1 = 90-int(i%5)*72;
double t2 = 360-int(i/5)*72;
Vector2 b = AngleToVector(t1,1.2);
b.y += 3.;
Vector2 n = RotateVector(b,t2);
return (10.,3.5+n.x,-6.+n.y);
}
override bool UsesAmmo( Class<Ammo> kind )
{
static const Class<Ammo> types[] = {"RedShell","GreenShell","BlueShell","PurpleShell"};
@ -283,9 +169,14 @@ Class Wallbuster : SWWMWeapon
if ( t.Results.HitType == TRACE_HitFloor ) p.CheckSplash(40);
}
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,3.5,-6.);
double t1 = 90-int(index%5)*72;
double t2 = 360-int(index/5)*72;
Vector2 b = AngleToVector(t1,1.2);
b.y += 3.;
Vector2 n = RotateVector(b,t2);
return (10.,3.5+n.x,-6.+n.y);
}
action void A_FireShells( int num = 1 )
{
@ -764,6 +655,7 @@ Class Wallbuster : SWWMWeapon
Obituary "$O_WALLBUSTER_RED";
SWWMWeapon.Tooltip "$TT_WALLBUSTER";
SWWMWeapon.GetLine "getwallbuster";
SWWMWeapon.NumCrosshairs 25;
Weapon.SlotNumber 4;
Weapon.SelectionOrder 400;
Weapon.UpSound "wallbuster/select";

View file

@ -77,7 +77,7 @@ Class Eviscerator : SWWMWeapon
invoker.loadtics = -delay;
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,4.,-5.);
}

View file

@ -71,7 +71,7 @@ Class Ynykron : SWWMWeapon
}
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (15.,4.,-1.);
}

View file

@ -85,7 +85,7 @@ Class DeepImpact : SWWMWeapon
}
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,2.,-3.);
}

View file

@ -356,7 +356,7 @@ Class Spreadgun : SWWMWeapon
}
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,2.,-2.);
}

View file

@ -24,7 +24,7 @@ Class Sparkster : SWWMWeapon
return Super.ReportHUDAmmo();
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,4.5,-5.);
}

View file

@ -12,9 +12,8 @@ Class ExplodiumGun : SWWMWeapon
Property ClipCount : ClipCount;
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
if ( Owner.player.ReadyWeapon == SisterWeapon ) return (10.,3.5,-2.);
return (10.,3.,-2.);
}
@ -575,16 +574,9 @@ Class DualExplodiumGun : SWWMWeapon
Property ClipCount : ClipCount;
override void RenderUnderlay( RenderEvent e )
override Vector3 GetTraceOffset( int index )
{
Super.RenderUnderlay(e);
// draw both crosshairs
SWWMWeapon(SisterWeapon).RenderUnderlay(e);
}
override Vector3 GetTraceOffset()
{
if ( Owner.player.ReadyWeapon == SisterWeapon ) return (10.,-3.,-2.);
if ( index == 1 ) return (10.,3.5,-2.);
return (10.,-3.5,-2.);
}
@ -777,6 +769,7 @@ Class DualExplodiumGun : SWWMWeapon
Obituary "$O_EXPLODIUM";
SWWMWeapon.Tooltip "$TT_EXPLODIUM2";
SWWMWeapon.GetLine "getexplodiumgun2";
SWWMWeapon.NumCrosshairs 2;
Weapon.UpSound "explodium/select";
Weapon.SisterWeapon "ExplodiumGun";
Weapon.SlotNumber 2;

View file

@ -113,7 +113,7 @@ Class CandyGun : SWWMWeapon
return gotstuff, gotspares;
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
return (10.,3,-2.);
}

View file

@ -614,7 +614,7 @@ Class SilverBullet : SWWMWeapon
s.Explode();
}
}
override Vector3 GetTraceOffset()
override Vector3 GetTraceOffset( int index )
{
if ( zoomed ) return (0.,0.,0.);
return (10.,1,-1.);