Sheen HMG fully functional. May need touchups later.

This commit is contained in:
Mari the Deer 2022-07-22 20:19:57 +02:00
commit 57253d5434
36 changed files with 528 additions and 94 deletions

View file

@ -13,8 +13,8 @@ More weapons, because we need 'em. In addition, all the "easy to implement" mini
- High Noon *(Land 6 killing shots in a single Puntzer Beta reload)*
- [4] Puntzer Gamma *(Ultra Suite 2)*
- You Gained Brouzouf *(Unload an entire mag in fuller auto with the Puntzer Gamma without missing a single shot)*
- [5] Sheen HMG *(SWWM Platinum Ep2)*
- Dakka *(Fire the Sheen HMG at 700 RPM for 30 seconds straight)*
- [5] Sheen HMG *(SWWM Platinum Ep2)*
- Dakka *(Fire the Sheen HMG at 700 RPM for 30 seconds straight)*
- [6] Quadravol *(UnSX)*
- Gravely Roast *(Perform 50 bayonet combos with the Quadravol)*
- [7] Sparkster x3 *(UnSX 2)*

BIN
graphics/HUD/SheenBar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 B

View file

@ -788,9 +788,9 @@ TT_PUNTZERGAMMA =
"\cfAltfire:\c- Fuller-auto fire.\n"
"\cfReload:\c- Reload weapon.";
TT_SHEENHMG =
"\cfFire:\c- Slow fire.\n"
"\cfAltfire:\c- Moderate fire.\n"
"\cfZoom:\c- Fast fire.";
"\cfFire:\c- Shoot weapon.\n"
"\cfAltfire:\c- Increase speed.\n"
"\cfZoom:\c- Decrease speed.";
TT_QUADRAVOL =
"\cfFire:\c- Shoot weapon.\n"
"\cfAltfire:\c- Pump weapon.\n"
@ -810,7 +810,7 @@ TT_RAYKHOM =
"\cfZoom:\c- Use scope.";
TT_MORTALRIFLE =
"\cfFire:\c- Shoot weapon.\n"
"\cfAltfire:\c- Shoot grenade.\n"
"\cfAltfire:\c- Shoot/reload grenade.\n"
"\cfZoom:\c- Cycle fire modes.\n"
"\cfReload:\c- Reload weapon.";
TT_RAFANKOS =

View file

@ -1459,7 +1459,7 @@ SWWM_LORETXT_HEAVYMAHSHEENGUN =
"\n"
"\cf300 RPM:\c- A slow spin. Sustained fire in this mode is theoretically endless, as the heat produced can be efficiently nullified by the internal cooling systems, it is therefore the recommended mode for most situations.\n"
"\n"
"\cf700 RPM:\c- Much faster spin, with moderate heat buildup. It's still possible to keep firing in this mode for about a minute or so from a cold start. If you need to deliver more pain and have the ammunition to spare, choose this.\n"
"\cf700 RPM:\c- Much faster spin, with moderate heat buildup. It's still possible to keep firing within operational temperature for an extended period of time, albeit less accurately. If you need to deliver more pain and have the ammunition to spare, choose this.\n"
"\n"
"\cf2100 RPM:\c- Extremely fast, with the highest heat potential. Sustained fire in this mode may quickly trigger the weapon's safety lock should the rising heat get too close to non-operational temperature. If you want things dead fast and don't care about running out of ammo in a matter of seconds, do pick this.\n"
"\n"

View file

@ -494,6 +494,7 @@ SWWM_KBASETAB = "Library";
SWWM_STORETAB = "Store";
SWWM_STOREFULL = "You can't hold more of that.";
SWWM_STOREMUNS = "You don't have enough money.";
SWWM_STORESWAP = "You already own a weapon in the same slot: %s.";
SWWM_NOSTORE = "(no items left to buy)";
SWWM_NOSTORESELL = "(no items to be sold)";
SWWM_CHATTAB = "Messages";

View file

@ -667,7 +667,7 @@ TT_PLASMABLAST =
TT_PLASMABLAST2 =
"\cfPrimario:\c- Disparar arma derecha.\n"
"\cfSecundario:\c- Disparar arma izquierda.\n"
"\cfRecarga:\c- Recargar arna(s).";
"\cfRecarga:\c- Recargar arma(s).";
TT_PUNTZERBETA =
"\cfPrimario:\c- Disparar arma.\n"
"\cfSecundario:\c- Modo de disparo rápido.\n"
@ -677,9 +677,9 @@ TT_PUNTZERGAMMA =
"\cfSecundario:\c- Fuego super-automático.\n"
"\cfRecarga:\c- Recargar arma.";
TT_SHEENHMG =
"\cfPrimario:\c- Fuego lento.\n"
"\cfSecundario:\c- Fuego moderado.\n"
"\cfZoom:\c- Fuego rápido.";
"\cfPrimario:\c- Disparar arma.\n"
"\cfSecundario:\c- Incrementar velocidad.\n"
"\cfZoom:\c- Reducir velocidad.";
TT_QUADRAVOL =
"\cfPrimario:\c- Disparar arma.\n"
"\cfSecundario:\c- Bombear arma.\n"
@ -699,7 +699,7 @@ TT_RAYKHOM =
"\cfZoom:\c- Usar mira.";
TT_MORTALRIFLE =
"\cfPrimario:\c- Disparar arma.\n"
"\cfSecundario:\c- Disparar granada.\n"
"\cfSecundario:\c- Disparar/recargar granada.\n"
"\cfZoom:\c- Cambiar modo de disparo.\n"
"\cfRecarga:\c- Recargar arma.";
TT_RAFANKOS =

View file

@ -1350,7 +1350,7 @@ SWWM_LORETXT_HEAVYMAHSHEENGUN =
"\n"
"\cf300 RPM:\c- Velocidad lenta. El fuego prolongado en este modo es en teoría infinito, ya que el calor producido puede ser anulado eficientemente por los sistemas de refrigeración internos, es entonces el modo recomendado para la mayoría de situaciones.\n"
"\n"
"\cf700 RPM:\c- Mayor velocidad, con calentamiento moderado. Aun es posible el fuego continuado en este modo, durante al menos un minuto aproximadamente desde un inicio en frío. Si necesitas repartir más dolor y tienes munición de sobra, usa esto.\n"
"\cf700 RPM:\c- Mayor velocidad, con calentamiento moderado. El fuego prolongado sigue siendo posible dentro de la temperatura recomendada, aunque esto afectará a la puntería. Si necesitas repartir más dolor y tienes munición de sobra, usa esto.\n"
"\n"
"\cf2100 RPM:\c- Extremadamente rápido, con el mayor potencial de calor. El fuego prolongado en este modo puede activar rápidamente el bloqueo de seguridad del arma si el aumento de temperatura se acerca a niveles no operacionales. Si tienes prisa por matar y no te importa quedarte sin munición en pocos segundos, entonces elige esto.\n"
"\n"

View file

@ -459,6 +459,7 @@ SWWM_KBASETAB = "Biblioteca";
SWWM_STORETAB = "Tienda";
SWWM_STOREFULL = "No puedes llevar más de eso.";
SWWM_STOREMUNS = "No tienes suficiente dinero.";
SWWM_STORESWAP = "Ya posees un arma en la misma ranura: %s.";
SWWM_NOSTORE = "(no queda nada que comprar)";
SWWM_NOSTORESELL = "(no tienes ítems que vender)";
SWWM_CHATTAB = "Mensajes";

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r195 \cu(Fri 22 Jul 01:34:12 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r195 \cu(2022-07-22 01:34:12)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r197 \cu(Fri 22 Jul 20:20:58 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r197 \cu(2022-07-22 20:20:58)\c-";

View file

@ -22,7 +22,7 @@ The weapon is rated for three speeds:
\cf300 RPM:\c- A slow spin. Sustained fire in this mode is theoretically endless, as the heat produced can be efficiently nullified by the internal cooling systems, it is therefore the recommended mode for most situations.
\cf700 RPM:\c- Much faster spin, with moderate heat buildup. It's still possible to keep firing in this mode for about a minute or so from a cold start. If you need to deliver more pain and have the ammunition to spare, choose this.
\cf700 RPM:\c- Much faster spin, with moderate heat buildup. It's still possible to keep firing within operational temperature for an extended period of time, albeit less accurately. If you need to deliver more pain and have the ammunition to spare, choose this.
\cf2100 RPM:\c- Extremely fast, with the highest heat potential. Sustained fire in this mode may quickly trigger the weapon's safety lock should the rising heat get too close to non-operational temperature. If you want things dead fast and don't care about running out of ammo in a matter of seconds, do pick this.

View file

@ -18,7 +18,7 @@ El arma está preparada para tres velocidades:
\cf300 RPM:\c- Velocidad lenta. El fuego prolongado en este modo es en teoría infinito, ya que el calor producido puede ser anulado eficientemente por los sistemas de refrigeración internos, es entonces el modo recomendado para la mayoría de situaciones.
\cf700 RPM:\c- Mayor velocidad, con calentamiento moderado. Aun es posible el fuego continuado en este modo, durante al menos un minuto aproximadamente desde un inicio en frío. Si necesitas repartir más dolor y tienes munición de sobra, usa esto.
\cf700 RPM:\c- Mayor velocidad, con calentamiento moderado. El fuego prolongado sigue siendo posible dentro de la temperatura recomendada, aunque esto afectará a la puntería. Si necesitas repartir más dolor y tienes munición de sobra, usa esto.
\cf2100 RPM:\c- Extremadamente rápido, con el mayor potencial de calor. El fuego prolongado en este modo puede activar rápidamente el bloqueo de seguridad del arma si el aumento de temperatura se acerca a niveles no operacionales. Si tienes prisa por matar y no te importa quedarte sin munición en pocos segundos, entonces elige esto.

View file

@ -70,7 +70,7 @@ Model "SheenAmmo"
Model 0 "SheenBullet_d.3d"
Skin 0 "SheenBullet.png"
Scale 0.04 0.04 0.04
Scale 0.025 0.025 0.025
ZOffset 16
PitchOffset 30
ROTATING
@ -83,7 +83,7 @@ Model "SheenAmmo2"
Model 0 "SheenBullet2_d.3d"
Skin 0 "SheenBullet.png"
Scale 0.04 0.04 0.04
Scale 0.025 0.025 0.025
ZOffset 16
ROTATING
@ -95,7 +95,7 @@ Model "SheenAmmo3"
Model 0 "SheenBullet3_d.3d"
Skin 0 "SheenBullet.png"
Scale 0.04 0.04 0.04
Scale 0.025 0.025 0.025
ZOffset 16
ROTATING
@ -108,7 +108,7 @@ Model "SheenSmallAmmo"
Model 0 "SheenBullet10_d.3d"
SurfaceSkin 0 0 "SheenBullet.png"
SurfaceSkin 0 1 "SheenAmmoBand.png"
Scale 0.04 0.04 0.04
Scale 0.025 0.025 0.025
ZOffset 16
ROTATING
@ -120,7 +120,7 @@ Model "SheenBigAmmo"
Model 0 "SheenBullet50_d.3d"
Skin 0 "SheenAmmoBox.png"
Scale 0.08 0.08 0.08
Scale 0.05 0.05 0.05
ZOffset 16
ROTATING

View file

@ -1,3 +1,86 @@
Model "SheenTrail"
{
Path "models/extra"
Model 0 "BaseBeam_d.3d"
Scale 1.5625 0.05 0.05
Offset 200 0 0
DONTCULLBACKFACES
USEACTORPITCH
USEACTORROLL
Skin 0 "dlc/SheenTracer.png"
FrameIndex XZW1 A 0 0
// recolors, whew
Skin 0 "dlc/SheenTracer_White.png"
FrameIndex XZW1 B 0 0
Skin 0 "dlc/SheenTracer_Red.png"
FrameIndex XZW1 C 0 0
Skin 0 "dlc/SheenTracer_Yellow.png"
FrameIndex XZW1 D 0 0
Skin 0 "dlc/SheenTracer_Green.png"
FrameIndex XZW1 E 0 0
Skin 0 "dlc/SheenTracer_Cyan.png"
FrameIndex XZW1 F 0 0
Skin 0 "dlc/SheenTracer_Blue.png"
FrameIndex XZW1 G 0 0
Skin 0 "dlc/SheenTracer_Magenta.png"
FrameIndex XZW1 H 0 0
Skin 0 "dlc/SheenTracer_TransBlue.png"
FrameIndex XZW1 I 0 0
Skin 0 "dlc/SheenTracer_TransPink.png"
FrameIndex XZW1 J 0 0
}
Model "SheenPhantom"
{
Path "models/extra"
Model 0 "BaseBeam_d.3d"
Scale 0.1953125 0.02 0.02
Offset 25 0 0
DONTCULLBACKFACES
USEACTORPITCH
USEACTORROLL
Skin 0 "ChunkTrail.png"
FrameIndex XZW1 A 0 0
// recolors, whew
Skin 0 "ChunkTrail_White.png"
FrameIndex XZW1 B 0 0
Skin 0 "ChunkTrail_Red.png"
FrameIndex XZW1 C 0 0
Skin 0 "ChunkTrail_Yellow.png"
FrameIndex XZW1 D 0 0
Skin 0 "ChunkTrail_Green.png"
FrameIndex XZW1 E 0 0
Skin 0 "ChunkTrail_Cyan.png"
FrameIndex XZW1 F 0 0
Skin 0 "ChunkTrail_Blue.png"
FrameIndex XZW1 G 0 0
Skin 0 "ChunkTrail_Magenta.png"
FrameIndex XZW1 H 0 0
Skin 0 "ChunkTrail_TransBlue.png"
FrameIndex XZW1 I 0 0
Skin 0 "ChunkTrail_TransPink.png"
FrameIndex XZW1 J 0 0
}
Model "SheenCasing"
{
Path "models"
Model 0 "SheenBulletCase_d.3d"
Skin 0 "SheenBullet_Fired.png"
Scale 0.025 0.025 0.025
AngleOffset -90
USEACTORPITCH
USEACTORROLL
FrameIndex XZW1 A 0 0
ZOffset 0.5
FrameIndex XZW1 B 0 0
}
Model "HeavyMahSheenGun"
{
Path "models"
@ -13,6 +96,41 @@ Model "HeavyMahSheenGun"
FrameIndex XZW1 A 0 0
}
Model "HeavyMahSheenGun"
{
Path "models/extra"
Model 2 "Flat_d.3d"
Offset 0 -60 -15
RollOffset 90
AngleOffset 90
Scale 0.12 0.12 0.12
Skin 2 "dlc/SheenMuz0.png"
FrameIndex XZW0 A 2 0
Scale 0.11 0.11 0.11
Skin 2 "dlc/SheenMuz1.png"
FrameIndex XZW0 B 2 0
Scale 0.10 0.10 0.10
Skin 2 "dlc/SheenMuz2.png"
FrameIndex XZW0 C 2 0
Scale 0.09 0.09 0.09
Skin 2 "dlc/SheenMuz3.png"
FrameIndex XZW0 D 2 0
Scale 0.08 0.08 0.08
Skin 2 "dlc/SheenMuz4.png"
FrameIndex XZW0 E 2 0
Scale 0.07 0.07 0.07
Skin 2 "dlc/SheenMuz5.png"
FrameIndex XZW0 F 2 0
Scale 0.06 0.06 0.06
Skin 2 "dlc/SheenMuz6.png"
FrameIndex XZW0 G 2 0
Scale 0.05 0.05 0.05
Skin 2 "dlc/SheenMuz7.png"
FrameIndex XZW0 H 2 0
}
Model "HeavyMahSheenGun"
{
Path "models"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

35
shaders/glsl/SheenLED.fp Normal file
View file

@ -0,0 +1,35 @@
// this is a temporary gross hack
void SetupMaterial( inout Material mat )
{
mat.Base = getTexel(vTexCoord.st);
// extract data from bytes of camtex
vec4 ccol = texture(camtex,vec2(.5));
int xy = int(ccol.r*255.); // low and mid digits (*F = HOT, F* = OK)
int zw = int(ccol.g*255.); // high digit and speed (*F = blink)
int u = int(ccol.b*255.); // width of heat bar
int digit0 = zw&0x0F;
int digit1 = (xy&0xF0)>>4;
int digit2 = xy&0x0F;
if ( digit0 != 0x0F )
{
vec2 tc;
if ( digit1 == 0x0F )
{
// OK
}
else if ( digit2 == 0x0F )
{
// HOT
}
else
{
// digits
tc = vec2(.125*(digit0%8),.5*(digit0/8));
}
}
vec2 uv = vTexCoord.st*vec2(textureSize(tex,0));
mat.Base *= 1.5*texture(pixtex,uv);
mat.Normal = ApplyNormalMap(vTexCoord.st);
mat.Bright = vec4(1.);
}

View file

@ -62,7 +62,13 @@ sheen/700rpm sounds/dlc1/sheen/sheen_700rpm.ogg
sheen/2100rpm sounds/dlc1/sheen/sheen_2100rpm.ogg
sheen/crankin sounds/dlc1/sheen/sheen_crankin.ogg
sheen/crankout sounds/dlc1/sheen/sheen_crankout.ogg
// TODO overheat alarm
sheen/overheat sounds/dlc1/sheen/sheen_overheat.ogg
sheen/unlock sounds/dlc1/sheen/sheen_unlock.ogg
sheen/casing1 sounds/dlc1/sheen/sheen_case1.ogg
sheen/casing2 sounds/dlc1/sheen/sheen_case2.ogg
sheen/casing3 sounds/dlc1/sheen/sheen_case3.ogg
sheen/casing4 sounds/dlc1/sheen/sheen_case4.ogg
$random sheen/casing { sheen/casing1 sheen/casing2 sheen/casing3 sheen/casing4 }
quadshot/select sounds/dlc1/quadshot/quad_select.ogg
quadshot/deselect sounds/dlc1/quadshot/quad_deselect.ogg

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -67,8 +67,8 @@ Class SheenAmmo : SWWMAmmo
+FLOATBOB;
FloatBobStrength 0.25;
Accuracy 35;
Radius 4;
Height 24;
Radius 2;
Height 22;
}
States
{
@ -82,7 +82,7 @@ Class SheenAmmo2 : SheenAmmo
Default
{
Inventory.Amount 2;
Radius 6;
Radius 4;
}
}
Class SheenAmmo3 : SheenAmmo
@ -90,7 +90,7 @@ Class SheenAmmo3 : SheenAmmo
Default
{
Inventory.Amount 3;
Radius 6;
Radius 4;
}
}
Class SheenSmallAmmo : SheenAmmo
@ -98,7 +98,7 @@ Class SheenSmallAmmo : SheenAmmo
Default
{
Inventory.Amount 10;
Radius 6;
Radius 4;
}
}
Class SheenBigAmmo : SheenAmmo
@ -106,7 +106,7 @@ Class SheenBigAmmo : SheenAmmo
Default
{
Inventory.Amount 50;
Radius 16;
Radius 12;
}
}

View file

@ -3,7 +3,7 @@
// Sheen HMG
extend Class HeavyMahSheenGun
{
ui TextureID WeaponBox, BulletTex[2], SpeedTex, BarTex[4];
ui TextureID WeaponBox, BulletTex[2], SpeedTex, BarTex;
override void DrawWeapon( double TicFrac, double bx, double by, double hs, Vector2 ss )
{
@ -11,16 +11,16 @@ extend Class HeavyMahSheenGun
if ( !BulletTex[0] ) BulletTex[0] = TexMan.CheckForTexture("graphics/HUD/SheenRound.png",TexMan.Type_Any);
if ( !BulletTex[1] ) BulletTex[1] = TexMan.CheckForTexture("graphics/HUD/SheenCasing.png",TexMan.Type_Any);
if ( !SpeedTex ) SpeedTex = TexMan.CheckForTexture("graphics/HUD/SheenSpeed.png",TexMan.Type_Any);
if ( !BarTex[0] ) BarTex[0] = TexMan.CheckForTexture("graphics/HUD/SheenBar0.png",TexMan.Type_Any);
if ( !BarTex[1] ) BarTex[1] = TexMan.CheckForTexture("graphics/HUD/SheenBar1.png",TexMan.Type_Any);
if ( !BarTex[2] ) BarTex[2] = TexMan.CheckForTexture("graphics/HUD/SheenBar2.png",TexMan.Type_Any);
if ( !BarTex[3] ) BarTex[3] = TexMan.CheckForTexture("graphics/HUD/SheenBar3.png",TexMan.Type_Any);
if ( !BarTex ) BarTex = TexMan.CheckForTexture("graphics/HUD/SheenBar.png",TexMan.Type_Any);
Screen.DrawTexture(WeaponBox,false,bx-23,by-24,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
if ( firespeed == 0 ) for ( int i=0; i<2; i++ ) Screen.DrawTexture(SpeedTex,false,bx-21,(by-14)+i*8,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
else if ( firespeed == 1 ) for ( int i=0; i<3; i++ ) Screen.DrawTexture(SpeedTex,false,bx-21,(by-14)+i*4,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
else if ( firespeed == 2 ) for ( int i=0; i<5; i++ ) Screen.DrawTexture(SpeedTex,false,bx-21,(by-14)+i*2,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
// TODO heat bar
Screen.DrawText(NewConsoleFont,Font.CR_RED,64,64,String.Format("heat: %g\nshake: %g\nspread: %g\ntimer: %d",barrelheat,vibrate,aimerror,firetimer?((gametic-firetimer)/GameTicRate):0));
double ht = clamp(HeatInter?HeatInter.GetValue(TicFrac):barrelheat,0.,100.);
double hw = ht*.18;
bool blinking = (incooldown)&&(gametic%8>=4);
Screen.DrawTexture(BarTex,false,bx-20,by-21,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_SrcWidth,hw,DTA_DestWidthF,hw,DTA_ColorOverlay,Color(255,0,0,0));
Screen.DrawTexture(BarTex,false,bx-21,by-22,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_SrcWidth,hw,DTA_DestWidthF,hw,DTA_ColorOverlay,blinking?Color(128,0,0,0):Color(0,0,0,0));
bool isfired = !!fired;
double firefact = 0.;
if ( firespeed == 0 )

View file

@ -7,37 +7,192 @@ Class HeavyMahSheenGun : SWWMWeapon
int firespeed;
double barrelheat, aimerror, vibrate;
bool incooldown, stopfire, firstshot;
int firetimer;
int firetimer, shotcnt;
transient ui SmoothDynamicValueInterpolator HeatInter;
transient SpreadSlugTracer st;
override void HudTick()
{
Super.HudTick();
if ( !HeatInter ) HeatInter = SmoothDynamicValueInterpolator.Create(barrelheat,.5,1.,25.);
HeatInter.Update(barrelheat);
}
action void A_DropCasing()
{
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),4*x+8*y-12*z);
let c = Spawn("SheenCasing",origin);
c.angle = angle;
c.pitch = pitch;
c.vel = x*FRandom[Junk](-.5,.5)+y*FRandom[Junk](.5,2.)-(0,0,FRandom[Junk](2.,5.));
c.vel += vel*.5;
}
action void A_SheenFire()
{
double spreadfct = (1.+invoker.aimerror+(invoker.barrelheat/50.)+invoker.firespeed**2.);
invoker.stopfire = ((invoker.Ammo1.Amount<=1)||!(player.cmd.buttons&BT_ATTACK)||(player.Health<=0));
invoker.barrelheat = invoker.barrelheat*(1.025-invoker.firespeed*.008)+3.-(invoker.firespeed**.8)*1.35;
invoker.aimerror = min(1.,invoker.aimerror*1.01+.01+invoker.firespeed*.01);
Vector3 x, y, z;
[x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-4*z);
SWWMHandler.DoFlash(self,Color(32,255,224,64),3);
A_SWWMFlash();
if ( invoker.firespeed == 1 )
{
A_AlertMonsters(swwm_uncapalert?0:3000);
A_BumpFOV(.98);
A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.2);
A_StartSound("sheen/700rpm",CHAN_WEAPONEXTRA,CHANF_LOOPING,attenuation:.5);
invoker.vibrate = .25;
A_Overlay(-9999,"EjectRound3");
SWWMUtility.DoKnockback(self,-x,9000.);
SWWMUtility.AchievementProgress("dakka",(gametic-invoker.firetimer)/GameTicRate,player);
}
else if ( invoker.firespeed == 2 )
{
A_AlertMonsters(swwm_uncapalert?0:5000);
A_BumpFOV(.99+FRandom[Sheen](-.005,.005));
A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.15);
A_StartSound("sheen/2100rpm",CHAN_WEAPONEXTRA,CHANF_LOOPING,attenuation:.4);
invoker.vibrate = min(1.,invoker.vibrate*1.05+.05);
SWWMUtility.DoKnockback(self,-x,15000.);
A_Overlay(-9999,"EjectRound1");
}
else if ( invoker.firespeed == 0 )
{
A_AlertMonsters(swwm_uncapalert?0:2000);
A_BumpFOV(.97);
A_QuakeEx(2,2,2,8,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.25);
A_StartSound("sheen/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.6);
SWWMUtility.DoKnockback(self,-x,6000.);
A_Overlay(-9999,"EjectRound7");
}
if ( invoker.barrelheat > 100. ) invoker.stopfire = invoker.incooldown = true;
if ( invoker.barrelheat > 100. )
{
A_StartSound("sheen/overheat",CHAN_WEAPONEXTRA2,CHANF_LOOPING,attenuation:3.);
invoker.stopfire = invoker.incooldown = true;
}
invoker.firstshot = true;
if ( !sv_infiniteammo && !FindInventory('PowerInfiniteAmmo',true) )
invoker.Ammo1.Amount--;
invoker.fired = gametic;
// TODO the actual firing itself
// dakka dakka dakka
Vector3 x2, y2, z2;
[x2, y2, z2] = swwm_CoordUtil.GetAxes(BulletSlope(),angle,roll);
double a = FRandom[Sheen](0,360), s = FRandom[Sheen](.002,.02)*spreadfct;
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
if ( !invoker.st ) invoker.st = new("SpreadSlugTracer");
let st = invoker.st; // thanks zscript
st.ignoreme = self;
st.penetration = 80.;
st.hitlist.Clear();
st.shootthroughlist.Clear();
st.waterhitlist.Clear();
st.Trace(origin,level.PointInSector(origin.xy),dir,8000.,TRACE_HitSky);
if ( swwm_omnibust )
{
// Wall busting
BusterWall.Bust(st.Results,int(st.penetration),self,st.Results.HitVector,st.Results.HitPos.z);
}
for ( int i=0; i<st.ShootThroughList.Size(); i++ )
{
st.ShootThroughList[i].Activate(self,0,SPAC_PCross);
st.ShootThroughList[i].Activate(self,0,SPAC_Impact);
}
for ( int i=0; i<st.WaterHitList.Size(); i++ )
{
let b = Spawn("InvisibleSplasher",st.WaterHitList[i].hitpos);
b.A_CheckTerrain();
}
for ( int i=5; i<st.Results.Distance; i+=10 )
{
if ( !Random[Boolet](0,2) ) continue;
let b = Actor.Spawn("SWWMBubble",level.Vec3Offset(origin,dir*i));
b.Scale *= FRandom[Boolet](.1,.3);
}
for ( int i=0; i<st.HitList.Size(); i++ )
{
int realdmg = st.HitList[i].HitDamage;
let p = SWWMPuff.Setup(st.HitList[i].HitLocation,st.HitList[i].x,invoker,self,st.HitList[i].HitActor);
SWWMDamageAccumulator.Accumulate(st.HitList[i].HitActor,realdmg,p,self,'shot',flags:DMG_INFLICTOR_IS_PUFF);
SWWMUtility.DoKnockback(st.HitList[i].HitActor,st.HitList[i].x+(0,0,0.025),15000.*FRandom[Sheen](0.4,1.2));
if ( st.HitList[i].HitActor.bNOBLOOD || st.HitList[i].HitActor.bDORMANT || st.HitList[i].HitActor.bINVULNERABLE )
{
let p = Spawn("SWWMBulletImpact",st.HitList[i].HitLocation);
p.angle = atan2(st.HitList[i].x.y,st.HitList[i].x.x)+180;
p.pitch = asin(st.HitList[i].x.z);
}
else
{
st.HitList[i].HitActor.TraceBleed(realdmg,self);
st.HitList[i].HitActor.SpawnBlood(st.HitList[i].HitLocation,atan2(st.HitList[i].x.y,st.HitList[i].x.x)+180,realdmg);
st.HitList[i].HitActor.A_StartSound("spreadgun/slugf",CHAN_DAMAGE,CHANF_OVERLAP,1.,2.);
}
}
if ( (st.Results.HitType != TRACE_HitNone) && (st.Results.HitType != TRACE_HasHitSky) && (st.Results.HitType != TRACE_HitActor) )
{
Vector3 hitnormal = -st.Results.HitVector;
if ( st.Results.HitType == TRACE_HitFloor )
{
if ( st.Results.FFloor ) hitnormal = -st.Results.FFloor.top.Normal;
else hitnormal = st.Results.HitSector.floorplane.Normal;
}
else if ( st.Results.HitType == TRACE_HitCeiling )
{
if ( st.Results.FFloor ) hitnormal = -st.Results.FFloor.bottom.Normal;
else hitnormal = st.Results.HitSector.ceilingplane.Normal;
}
else if ( st.Results.HitType == TRACE_HitWall )
{
hitnormal = (-st.Results.HitLine.delta.y,st.Results.HitLine.delta.x,0).unit();
if ( !st.Results.Side ) hitnormal *= -1;
}
let p = Spawn("SWWMBulletImpact",st.Results.HitPos+hitnormal*4);
p.angle = atan2(hitnormal.y,hitnormal.x);
p.pitch = asin(-hitnormal.z);
if ( st.Results.HitType == TRACE_HitFloor ) p.CheckSplash(40);
if ( st.Results.HitLine ) st.Results.HitLine.RemoteActivate(self,st.Results.Side,SPAC_Impact,st.Results.HitPos);
}
for ( int i=0; i<(5-invoker.firespeed); i++ )
{
let s = Spawn("SWWMSmoke",origin);
s.scale *= .5;
s.alpha *= .1;
s.speed *= .7;
s.vel += vel*.5+x*FRandom[Sheen](1.,3.);
}
if ( st.Results.Distance > 200. )
{
int trail = CVar.GetCVar('swwm_funtrails',player).GetInt();
if ( trail == 8 ) trail = Random[Sheen](1,7);
else if ( trail == 9 ) trail = 2+(invoker.shotcnt%6);
else if ( trail == 10 ) switch ( invoker.shotcnt%5 )
{
case 0:
case 3:
trail = 8;
break;
case 1:
case 4:
trail = 9;
break;
case 2:
trail = 1;
break;
}
let t = Spawn("SheenTrail",origin);
t.target = self;
t.angle = atan2(dir.y,dir.x);
t.pitch = asin(-dir.z);
t.specialf1 = st.Results.Distance;
t.frame = trail;
}
invoker.shotcnt++;
}
action void A_CheckContinueFire()
{
@ -46,11 +201,6 @@ Class HeavyMahSheenGun : SWWMWeapon
}
override void OwnerDied()
{
if ( Owner.IsActorPlayingSound(CHAN_WEAPONEXTRA) )
{
A_StopSound(CHAN_WEAPONEXTRA);
A_StartSound("sheen/fire",CHAN_WEAPON,CHANF_OVERLAP,attenuation:.6,starttime:.2);
}
Super.OwnerDied();
aimerror = 0.;
vibrate = 0.;
@ -64,21 +214,32 @@ Class HeavyMahSheenGun : SWWMWeapon
override void DoEffect()
{
Super.DoEffect();
barrelheat = max(0.,barrelheat*.99-.15);
if ( barrelheat <= 0. ) incooldown = false;
if ( incooldown ) barrelheat = max(0.,barrelheat*.995-.1);
else barrelheat = max(0.,barrelheat*.99-.15);
bool hascooled = false;
if ( barrelheat <= 0. )
{
hascooled = incooldown;
incooldown = false;
}
if ( !Owner || !Owner.player || (Owner.player.ReadyWeapon != self) )
{
aimerror = 0.;
vibrate = 0.;
return;
}
if ( hascooled )
{
Owner.A_StopSound(CHAN_WEAPONEXTRA2);
Owner.A_StartSound("sheen/unlock",CHAN_WEAPONEXTRA2,CHANF_OVERLAP,attenuation:3.);
}
let pspm = Owner.player.FindPSprite(PSP_WEAPON);
if ( pspm )
{
pspm.x = FRandom[Shivers](-1.,1.)*vibrate*4.;
pspm.y = 32+FRandom[Shivers](-1.,1.)*vibrate*4.;
}
aimerror *= .95;
aimerror *= .9;
}
override bool CheckAmmo( int firemode, bool autoswitch, bool requireammo, int ammocount )
{
@ -128,7 +289,11 @@ Class HeavyMahSheenGun : SWWMWeapon
XZW1 A -1;
Stop;
Select:
XZW2 K 3 A_FullRaise();
XZW2 K 3
{
A_FullRaise();
if ( invoker.incooldown ) A_StartSound("sheen/overheat",CHAN_WEAPONEXTRA2,CHANF_LOOPING,attenuation:3.);
}
XZW2 LMNOP 3;
XZW2 QRSTUV 2;
XZW2 WX 3;
@ -136,6 +301,7 @@ Class HeavyMahSheenGun : SWWMWeapon
Ready:
XZW2 A 1
{
invoker.shotcnt = 0;
invoker.firetimer = gametic;
invoker.aimerror = 0.;
invoker.vibrate = 0.;
@ -149,7 +315,7 @@ Class HeavyMahSheenGun : SWWMWeapon
}
Wait;
Fire:
XZW2 A 1;
XZW2 A 2;
XZW2 Z 1
{
invoker.firstshot = false;
@ -320,29 +486,29 @@ Class HeavyMahSheenGun : SWWMWeapon
XZW4 L 0;
Goto VeryFastFireHold;
EndFireFast7:
XZW4 MNO 1 { invoker.vibrate *= .25; }
XZW4 MNO 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast6:
XZW4 PQR 1 { invoker.vibrate *= .25; }
XZW4 PQR 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast5:
XZW4 STU 1 { invoker.vibrate *= .25; }
XZW4 STU 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast4:
XZW4 VWX 1 { invoker.vibrate *= .25; }
XZW4 VWX 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast3:
XZW4 YZ 1 { invoker.vibrate *= .25; }
XZW5 A 1 { invoker.vibrate *= .25; }
XZW4 YZ 2 { invoker.vibrate *= .25; }
XZW5 A 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast2:
XZW5 BCD 1 { invoker.vibrate *= .25; }
XZW5 BCD 2 { invoker.vibrate *= .25; }
Goto Ready;
EndFireFast1:
XZW5 EFG 1 { invoker.vibrate *= .25; }
XZW5 EFG 2 { invoker.vibrate *= .25; }
Goto Ready;
StopFire:
XZW2 Z 1 A_StopSound(CHAN_WEAPONEXTRA); // just in case
XZW2 Z 2 A_StopSound(CHAN_WEAPONEXTRA); // just in case
Goto Ready;
EjectRound7:
TNT1 A 7;
@ -351,10 +517,10 @@ Class HeavyMahSheenGun : SWWMWeapon
TNT1 A 3;
Goto EjectRound;
EjectRound1:
TNT1 A 7;
TNT1 A 1;
Goto EjectRound;
EjectRound:
TNT1 A 1; // TODO
TNT1 A 1 A_DropCasing();
Stop;
AltFire:
XZW2 A 3 A_StartSound("sheen/crankin",CHAN_WEAPON,CHANF_OVERLAP);
@ -403,7 +569,21 @@ Class HeavyMahSheenGun : SWWMWeapon
Deselect:
XZW2 A 2 A_StartSound("sheen/deselect",CHAN_WEAPON,CHANF_OVERLAP);
XZW2 BCDEFGHIJK 2;
XZW2 K -1 A_FullLower();
XZW2 K -1
{
A_StopSound(CHAN_WEAPONEXTRA2);
A_FullLower();
}
Stop;
Flash:
XZW0 A 2
{
let psp = player.GetPSprite(PSP_FLASH);
psp.frame = Random[GunFlash](0,7);
let l = Spawn("SWWMWeaponLight",pos);
l.target = self;
l.Args[3] -= psp.frame*5;
}
Stop;
}
}

View file

@ -1 +1,108 @@
// Sheen HMG projectiles and effects
Class SheenCasing : SWWMCasing
{
Default
{
BounceSound "sheen/casing";
}
}
Class SheenPhantom : Actor
{
Default
{
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
+INTERPOLATEANGLES;
Radius .1;
Height 0.;
Alpha .5;
RenderStyle "Add";
}
override void Tick()
{
if ( isFrozen() ) return;
A_FadeOut(frame?.02:.05);
}
States
{
Spawn:
XZW1 A -1 Bright;
Stop;
}
}
Class SheenTrail : Actor
{
Default
{
Obituary "$O_SHEENHMG";
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+NOTELEPORT;
+NOINTERACTION;
+INTERPOLATEANGLES;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
Speed 200;
Radius .1;
Height 0.;
RenderStyle "Add";
}
override void Tick()
{
Vector3 oldpos = pos;
if ( isFrozen() ) return;
if ( CurState == SpawnState )
{
Vector3 dir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
Vector3 newpos = level.Vec3Offset(pos,dir*min(speed,specialf1));
special1++;
for ( int i=0; i<4; i++ )
{
let p = Spawn("SheenPhantom",level.Vec3Offset(pos,dir*(i+1)*50.));
p.angle = angle;
p.pitch = pitch;
p.frame = frame;
p.alpha *= clamp((special1+i*.25)/2.,.25,1.);
}
// burn the air throughout
Vector3 tdir = level.Vec3Diff(pos,newpos);
double dist = tdir.length();
tdir /= dist;
for ( int i=0; i<dist; i+=25 )
{
SetOrigin(level.Vec3Offset(pos,tdir*i),true);
SWWMUtility.DoExplosion(self,min(5*special1,30),2000,50,damagetype:'Fire',ignoreme:target);
}
prev = oldpos; // interpolation
SetOrigin(newpos,true);
specialf1 -= speed;
if ( specialf1 <= 0 ) SetStateLabel("Death");
return;
}
if ( !CheckNoDelay() || (tics == -1) ) return;
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
States
{
Spawn:
XZW1 A -1 Bright;
Stop;
Death:
TNT1 A 5;
Stop;
}
}

View file

@ -350,37 +350,6 @@ extend Class SWWMHandler
if ( SWWMCredits.Take(players[e.Args[0]],e.Args[1]) )
{
let def = GetDefaultByType(item);
SWWMWeapon sw;
// drop the swapweapon if we own it first
if ( swwm_swapweapons && (item is 'SWWMWeapon') && (sw = SWWMWeapon(def).HasSwapWeapon(players[e.Args[0]].mo)) )
{
// special case, otherwise candy gun won't drop itself
if ( sw is 'CandyGun' ) CandyGun(sw).swapdrop = true;
bool swapto = (sw == players[e.Args[0]].ReadyWeapon) || (sw.SisterWeapon && (sw.Sisterweapon == players[e.Args[0]].ReadyWeapon));
int ngun = sw.Amount;
if ( ngun == 2 )
{
// create a dual giver to drop
let dg = SWWMDualWeaponGiver(Actor.Spawn("SWWMDualWeaponGiver",players[e.Args[0]].mo.pos+(0,0,10)));
dg.angle = players[e.Args[0]].mo.angle;
dg.VelFromAngle(5.);
dg.vel.z += 1.;
dg.vel += players[e.Args[0]].mo.vel;
// transfer both guns
dg.giveme[0] = SWWMWeapon(sw.CreateTossable(1));
dg.giveme[0].AttachToOwner(dg);
dg.giveme[1] = SWWMWeapon(sw.CreateTossable(1));
dg.giveme[1].AttachToOwner(dg);
dg.SetPickupState();
}
else players[e.Args[0]].mo.DropInventory(sw); // just drop it
// don't autoswitch just yet (hacky)
if ( swapto )
{
players[e.Args[0]].ReadyWeapon = null;
players[e.Args[0]].PendingWeapon = WP_NOCHANGE;
}
}
if ( (item is 'ArmorNuggetItem') || (item is 'HealthNuggetItem') )
{
// these have to be given in a loop because fun reasons

View file

@ -598,6 +598,19 @@ Class DemolitionistMenuStoreItem : DemolitionistMenuListItem
master.tmsgtic = Menu.MenuTime()+70;
return;
}
if ( (inv is 'SWWMWeapon') && swwm_swapweapons )
{
// check swapweapon
let wpn = GetDefaultByType((Class<SWWMWeapon>)(inv));
let sw = wpn.HasSwapWeapon(players[consoleplayer].mo);
if ( sw )
{
master.MenuSound("menu/noinvuse");
master.tmsg = String.Format(StringTable.Localize("$SWWM_STORESWAP"),sw.GetTag());
master.tmsgtic = Menu.MenuTime()+70;
return;
}
}
let cur = players[consoleplayer].mo.FindInventory(inv);
int camt, max;
if ( cur )

View file

@ -2813,8 +2813,11 @@ Class Demolitionist : PlayerPawn
// weapon get oneliner
if ( (item is 'Weapon') && !(item is 'SWWMGesture') && !(item is 'SWWMItemGesture') && mystats && !mystats.GotWeapon(Weapon(item).GetClass()) && (player == players[consoleplayer]) && !ingivecheat )
{
if ( (item is 'HeavyMahSheenGun') && Random[DemoLines](0,2) && SWWMHandler.AddOneliner("sheenspecial",2,20) )
if ( (item is 'HeavyMahSheenGun') && !Random[DemoLines](0,2) && SWWMHandler.AddOneliner("sheenspecial",2,20) )
{
A_StartSound("sheen/specialpick",CHAN_ITEM,CHANF_OVERLAP,1.,.5);
A_StartSound("sheen/specialpick",CHAN_ITEM,CHANF_OVERLAP,1.,.5);
}
else if ( (item is 'SWWMWeapon') && (SWWMWeapon(item).GetLine != "") )
{
// fall back to generic weapon get if voicepack lacks weapon-specific lines

View file

@ -170,6 +170,7 @@ Class SWWMStats : SWWMStaticThinker
else if ( ((inflictor is 'SaltImpact') && !inflictor.Args[0]) || ((inflictor is 'SaltBeam') && !inflictor.Args[1]) || (inflictor is 'CorrodeDebuff') || (inflictor is 'CorrosiveFlechette') || ((inflictor is 'TheBall') && !inflictor.special1) || (inflictor is 'GoldenImpact') || (inflictor is 'GoldenSubImpact') || (inflictor is 'GoldenSubSubImpact') ) which = 'Spreadgun';
else if ( ((inflictor is 'SaltImpact') && inflictor.Args[0]) || ((inflictor is 'SaltBeam') && inflictor.Args[1]) || ((inflictor is 'TheBall') && inflictor.special1) ) which = 'Wallbuster';
else if ( (inflictor is 'EvisceratorChunk') || (inflictor is 'EvisceratorProj') ) which = 'Eviscerator';
else if ( inflictor is 'SheenTrail' ) which = 'HeavyMahSheenGun';
else if ( (inflictor is 'HellblazerMissile') || (inflictor is 'HellblazerRavagerArm') || (inflictor is 'HellblazerWarheadArm') ) which = 'Hellblazer';
else if ( (inflictor is 'BigBiospark') || (inflictor is 'BiosparkBall') || (inflictor is 'BiosparkBeamImpact') || (inflictor is 'BiosparkComboImpact') || (inflictor is 'BiosparkComboImpactSub') || (inflictor is 'BiosparkBeam') || (inflictor is 'BiosparkArc') || (inflictor is 'BiosparkCore') ) which = 'Sparkster';
else if ( (inflictor is 'SilverAirRip') || (inflictor is 'SilverAirRip2') || (inflictor is 'SilverImpact') || (inflictor is 'FatChodeImpact') || (inflictor is 'FatChodeExplosionArm') ) which = 'SilverBullet';

View file

@ -100,7 +100,7 @@ Class SWWMWeapon : Weapon abstract
// if the toucher owns our SwapWeapon, drop it before picking us up
bool swapto = false;
SWWMWeapon sw;
if ( swwm_swapweapons && (sw = HasSwapWeapon(user)) )
if ( swwm_swapweapons && (sw = HasSwapWeapon(user)) && (user.player.WeaponState&WF_WEAPONSWITCHOK) && !(user.player.WeaponState&WF_DISABLESWITCH) )
{
// special case, otherwise candy gun won't drop itself
if ( sw is 'CandyGun' ) CandyGun(sw).swapdrop = true;