Added various screen shaders, plus a bunch of other changes.

Spreadgun rebalancing.
Underwater sounds.
Embiggener use sound.
Other small things here and there.
This commit is contained in:
Mari the Deer 2020-03-02 14:41:28 +01:00
commit 42db2d3603
30 changed files with 754 additions and 194 deletions

View file

@ -13,12 +13,19 @@ after the first release.
- Super Happy Fun Ball (SWWM Z)
* Additional Demolitionist Menu features
- Per-monster kill tracker in stats tab
- Music player with a selection of Saya's favourite tracks
- Radio
- Pong minigame
- Selling items at the store
* Fanart on the intermission screen
* 4komas on the intermission screen
* Actually make a fancy titlemap
* Mod trailer
* Additional HUD stuff
- Minimap with radar like in SWWM Z
- Fake livestream chat, with dynamic reactions to all sorts of stuff
* Character and item images for the library
* Full Mashiro model for Lämp easter egg
* Summonable Ibuki companion (w/ optional "stream friendly" clothing)
* Saya model, for scenes or something idk
* Japanese Localization???
* Strife support, with rewritten dialogue

BIN
brightmaps/Nobright.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

View file

@ -31,4 +31,4 @@ user bool swwm_scorebonus = true; // show score bonuses
user bool swwm_fly6dof = true; // flying uses 6dof movement, toggleable for those who get motion sickness
user bool swwm_othervoice = true; // can hear other player's voice lines in coop
user bool swwm_shaders = true; // use pp shaders for some effects
user bool swwm_earbuster = false; // limits loudness of wallbuster fire sounds
user bool swwm_earbuster = false; // limits loudness of wallbuster fire sounds

View file

@ -36,22 +36,32 @@ HardwareShader Texture "models/Refresher.png"
Brightmap Texture "models/GhostArtifact.png"
{
Map "models/GhostArtifact_bright.png"
DisableFullbright
}
Brightmap Texture "models/Gravity.png"
{
Map "models/Gravity_bright.png"
DisableFullbright
}
Brightmap Texture "models/Ragekit.png"
{
Map "models/Ragekit_bright.png"
DisableFullbright
}
Brightmap Texture "models/Omnisight.png"
{
Map "models/Omnisight_bright.png"
DisableFullbright
}
Brightmap Texture "models/Lamp.png"
{
Map "models/Lamp_bright.png"
DisableFullbright
}
Brightmap Texture "models/Invinciball.png"
{
Map "brightmaps/nobright.png"
DisableFullbright
}
Brightmap Texture "models/Moth_Mashiro.png"
{

21
gldefs.pp Normal file
View file

@ -0,0 +1,21 @@
HardwareShader PostProcess beforebloom
{
Name "GhostShader"
Shader "shaders/glsl/Ghostscreen.fp" 330
}
HardwareShader PostProcess scene
{
Name "InvinciShader"
Shader "shaders/glsl/Invinciscreen.fp" 330
Uniform float str
}
HardwareShader PostProcess scene
{
Name "RagekitShader"
Shader "shaders/glsl/Ragescreen.fp" 330
Texture WarpTex "textures/ragewarp.png"
Texture NoiseTex "textures/graynoise.png"
Uniform float timer
Uniform float xtrastr
}

View file

@ -128,7 +128,6 @@ Model "GhostArtifactX"
SurfaceSkin 0 0 "darkmap.png"
Scale 0.05 0.05 0.05
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}
@ -138,39 +137,66 @@ Model "GravitySuppressor"
Path "models"
Model 0 "Gravity_d.3d"
SurfaceSkin 0 0 "Gravity.png"
SurfaceSkin 0 1 "silvermap.png"
Scale 0.06 0.06 0.06
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}
Model "GravityX"
{
Path "models"
Model 0 "Gravity_d.3d"
SurfaceSkin 0 1 "silvermap.png"
Scale 0.06 0.06 0.06
ZOffset 16
FrameIndex XZW1 A 0 0
}
Model "FuckingInvinciball"
{
Path "models"
Model 0 "Invinciball_d.3d"
SurfaceSkin 0 0 "Invinciball.png"
SurfaceSkin 0 1 "invincimap.png"
Scale 0.04 0.04 0.04
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}
Model "InvinciballX"
{
Path "models"
Model 0 "Invinciball_d.3d"
SurfaceSkin 0 1 "invincimap.png"
Scale 0.04 0.04 0.04
ZOffset 16
FrameIndex XZW1 A 0 0
}
Model "Ragekit"
{
Path "models"
Model 0 "Ragekit_d.3d"
SurfaceSkin 0 0 "Ragekit.png"
SurfaceSkin 0 1 "ragemap.png"
Scale 0.05 0.05 0.05
ZOffset 16
ROTATING
FrameIndex XZW1 A 0 0
}
Model "RagekitX"
{
Path "models"
Model 0 "Ragekit_d.3d"
SurfaceSkin 0 1 "ragemap.png"
Scale 0.05 0.05 0.05
ZOffset 16
FrameIndex XZW1 A 0 0
}
Model "Omnisight"
{

View file

@ -0,0 +1,12 @@
void main()
{
vec2 uv = TexCoord;
vec3 col = texture(InputTexture,uv).rgb;
float p = distance(uv,vec2(.5))/sqrt(2.);
for ( float i=0.; i<4.; i+=1. )
{
vec2 suv = fract((.5-uv)*(1.-i*p*p)+.5);
col += texture(InputTexture,suv).rgb*pow(p,2.)*vec3(.6,.8,1.3);
}
FragColor = vec4(col,1.0);
}

29
shaders/glsl/Glitch.frag Normal file
View file

@ -0,0 +1,29 @@
float rnd2( in vec2 sd )
{
return fract(cos(dot(sd*floor(Timer*15.0),vec2(145.34,142.55)))*2745.84);
}
float rnd( in float sd )
{
return rnd2(vec2(sd,1.0));
}
void main()
{
vec2 coord = TexCoord;
vec2 uv_c[3] = vec2[3](coord,coord,coord);
vec2 blka = floor(coord*vec2(22.0,12.0));
vec2 blkb = floor(coord*vec2(6.0,9.0));
float noiz = pow(rnd2(blka),thr1)*pow(rnd2(blkb),thr2)-pow(rnd(4.53),thr3)*str2;
uv_c[0].x += str1*noiz*(rnd(3.35)-0.5);
uv_c[1].x += str1*noiz*(rnd(4.63)-0.5);
uv_c[2].x += str1*noiz*(rnd(5.62)-0.5);
uv_c[0].y += str1*noiz*(rnd(4.55)-0.5);
uv_c[1].y += str1*noiz*(rnd(3.67)-0.5);
uv_c[2].y += str1*noiz*(rnd(5.54)-0.5);
vec4 res;
res.r = texture(InputTexture,uv_c[0]).r;
res.g = texture(InputTexture,uv_c[1]).g;
res.b = texture(InputTexture,uv_c[2]).b;
res.a = 1.0;
FragColor = res;
}

59
shaders/glsl/Grain.frag Normal file
View file

@ -0,0 +1,59 @@
/*
Complex grain shader ported over from MariENB
(C)2012-2018 Marisa Kirisame
*/
const float nf = 0.000005;
const vec3 nm1 = vec3(2.05,3.11,2.22);
const float nk = 0.04;
const vec3 nm2 = vec3(4.25,9.42,6.29);
const float ns = -0.08;
const float np = 3.95;
const float bnp = 1.7;
#define darkmask(a,b) (a>0.5)?(2.0*a*(0.5+b)):(1.0-2.0*(1.0-a)*(1.0-((0.5+b))))
vec3 grain( in vec3 res, in vec2 coord )
{
float ts = Timer*nf;
vec2 s1 = coord+vec2(0.0,ts);
vec2 s2 = coord+vec2(ts,0.0);
vec2 s3 = coord+vec2(ts,ts);
float n1, n2, n3;
vec2 nr = textureSize(NoiseTexture,0);
s1 = mod(s1*nm1.x*nr,1.0);
s2 = mod(s2*nm1.y*nr,1.0);
s3 = mod(s3*nm1.z*nr,1.0);
n1 = texture(NoiseTexture,s1).r;
n2 = texture(NoiseTexture,s2).g;
n3 = texture(NoiseTexture,s3).b;
s1 = coord+vec2(ts+n1*nk,n2*nk);
s2 = coord+vec2(n2,ts+n3*nk);
s3 = coord+vec2(ts+n3*nk,ts+n1*nk);
s1 = mod(s1*nm2.x*nr,1.0);
s2 = mod(s2*nm2.y*nr,1.0);
s3 = mod(s3*nm2.z*nr,1.0);
n1 = texture(NoiseTexture,s1).r;
n2 = texture(NoiseTexture,s2).g;
n3 = texture(NoiseTexture,s3).b;
float n4 = (n1+n2+n3)/3.0;
vec3 ng = vec3(n4);
vec3 nc = vec3(n1,n2,n3);
vec3 nt = pow(clamp(mix(ng,nc,ns),0.0,1.0),vec3(np));
float bn = 1.0-clamp((res.r+res.g+res.b)/3.0,0.0,1.0);
bn = pow(bn,bnp);
vec3 nn = clamp(nt*bn,vec3(0.0),vec3(1.0));
res.r = darkmask(res.r,(nn.r*ni));
res.g = darkmask(res.g,(nn.g*ni));
res.b = darkmask(res.b,(nn.b*ni));
return res;
}
void main()
{
vec2 coord = TexCoord;
vec4 res = texture(InputTexture,coord);
/*vec2 sfact = max(vec2(320.0,200.0),textureSize(InputTexture,0)*0.5);
coord = floor(coord*sfact)/sfact;*/
res.rgb = grain(res.rgb,coord);
FragColor = res;
}

View file

@ -0,0 +1,28 @@
vec3 sharpened( vec2 uv )
{
vec3 col = texture(InputTexture,uv).rgb*9.;
vec2 bresl = vec2(textureSize(InputTexture,0));
vec2 bof = vec2(1./bresl.x,1./bresl.y);
col -= texture(InputTexture,uv+vec2(bof.x,0)).rgb;
col -= texture(InputTexture,uv+vec2(2.*bof.x,0)).rgb;
col -= texture(InputTexture,uv+vec2(-bof.x,0)).rgb;
col -= texture(InputTexture,uv+vec2(-2.*bof.x,0)).rgb;
col -= texture(InputTexture,uv+vec2(0,bof.y)).rgb;
col -= texture(InputTexture,uv+vec2(0,2.*bof.y)).rgb;
col -= texture(InputTexture,uv+vec2(0,-bof.y)).rgb;
col -= texture(InputTexture,uv+vec2(0,-2.*bof.y)).rgb;
return col;
}
void main()
{
vec2 uv = TexCoord;
vec3 col = texture(InputTexture,uv).rgb;
float p = distance(uv,vec2(.5));
for ( float i=0.; i<4.; i+=1. )
{
vec2 suv = fract((uv-.5)*(1.-.01*i*(.3+str*4.))+.5);
col += sharpened(suv)*pow(p,2.4)*vec3(1.2,.7,.2)*(.4+str);
}
FragColor = vec4(col,1.0);
}

View file

@ -0,0 +1,20 @@
#define TWOPI 6.28318530718
void main()
{
vec2 uv = TexCoord;
vec3 col = texture(InputTexture,uv).rgb;
col *= vec3(.5)+texture(WarpTex,vec2(fract(uv.x+.1*sin(uv.y*TWOPI)),fract(uv.y-timer*.1))).rgb*xtrastr;
col *= vec3(.5)+texture(WarpTex,2.*vec2(fract(uv.x+.1*cos(uv.y*TWOPI)),fract(uv.y-timer*.1))).rgb*xtrastr;
for ( float i=0.; i<4.; i+=1. )
{
float str = texture(NoiseTex,vec2(fract(timer*.2),fract(timer*.02))).x*.07;
str *= pow(xtrastr,1.5);
float p = distance(uv,vec2(.5));
vec2 suv = (uv-.5)*(1.-(str*i*p))+.5;
col += texture(InputTexture,suv).rgb+pow(p,2.)*vec3(1.8,.2,0.)*xtrastr;
}
col /= 5.;
col *= vec3(1.2,.9,.7);
FragColor = vec4(col,1.0);
}

View file

@ -551,6 +551,16 @@ misc/chat sounds/menu/chatsnd.ogg
misc/chat2 sounds/menu/chatsnd.ogg
misc/sundowner sounds/SUNDOWNER.ogg
misc/underwater sounds/general/uWater1a.ogg
misc/underslime sounds/general/uGoop1.ogg
misc/underlava sounds/general/uLava1.ogg
misc/waterenter sounds/general/DIVE.ogg
misc/slimeenter sounds/general/GoopJ1.ogg
misc/lavaenter sounds/general/LavaJ1.ogg
misc/waterexit sounds/general/surfaceb.ogg
misc/slimeexit sounds/general/GoopE1.ogg
misc/lavaexit sounds/general/LavaE1.ogg
armor/blastsuit sounds/items/blastsuit.ogg
armor/wararmor sounds/items/wararmor.ogg
armor/hit1 sounds/items/hullhit.ogg
@ -575,8 +585,9 @@ powerup/invinciballend sounds/items/invincioff.ogg
powerup/ragekit sounds/items/ragekiton.ogg
powerup/ragekitact sounds/items/ragekitact.ogg
powerup/ragekithit sounds/items/ragekithit.ogg
powerup/ragekitend sounds/items/ragekitend.ogg
powerup/ragekitend sounds/items/ragekitoff.ogg
powerup/omnisight sounds/items/omnisight.ogg
powerup/embiggener sounds/items/embiggen.ogg
lamp/on sounds/items/lampon.ogg
lamp/off sounds/items/lampoff.ogg

BIN
sounds/general/DIVE.ogg Normal file

Binary file not shown.

BIN
sounds/general/GoopE1.ogg Normal file

Binary file not shown.

BIN
sounds/general/GoopJ1.ogg Normal file

Binary file not shown.

BIN
sounds/general/LavaE1.ogg Normal file

Binary file not shown.

BIN
sounds/general/LavaJ1.ogg Normal file

Binary file not shown.

BIN
sounds/general/surfaceb.ogg Normal file

Binary file not shown.

BIN
sounds/general/uGoop1.ogg Normal file

Binary file not shown.

BIN
sounds/general/uLava1.ogg Normal file

Binary file not shown.

BIN
sounds/general/uWater1a.ogg Normal file

Binary file not shown.

BIN
sounds/items/embiggen.ogg Normal file

Binary file not shown.

BIN
textures/ragewarp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -931,6 +931,7 @@ Class HammerspaceEmbiggener : Inventory
{
override Inventory CreateCopy( Actor other )
{
other.A_StartSound("powerup/embiggener",CHAN_ITEMEXTRA);
// Find every unique type of ammoitem. Give it to the player if
// he doesn't have it already, and increase its maximum capacity.
for ( int i=0; i<AllActorClasses.Size(); i++ )
@ -996,6 +997,7 @@ Class HammerspaceEmbiggener : Inventory
bool res = Super.HandlePickup(item);
if ( item.GetClass() == GetClass() )
{
Owner.A_StartSound("powerup/embiggener",CHAN_ITEMEXTRA);
// readjust ammo values to new capacity
for ( Inventory i=Owner.Inv; i; i=i.Inv )
{

View file

@ -1,14 +1,15 @@
// common code goes here
enum ESWWMGZChannels
{
CHAN_YOUDONEFUCKEDUP = 63200,
CHAN_DEMOVOICE = 63201,
CHAN_FOOTSTEP = 63202,
CHAN_WEAPONEXTRA = 63203,
CHAN_POWERUP = 63204,
CHAN_POWERUPEXTRA = 63205,
CHAN_JETPACK = 63206,
CHAN_ITEMEXTRA = 63207
CHAN_YOUDONEFUCKEDUP = 63200, // exception handler
CHAN_DEMOVOICE = 63201, // demolitionist voices
CHAN_FOOTSTEP = 63202, // footstep sounds and others
CHAN_WEAPONEXTRA = 63203, // additional weapon sounds (usually loops)
CHAN_POWERUP = 63204, // powerup sounds
CHAN_POWERUPEXTRA = 63205, // additional powerup sounds
CHAN_JETPACK = 63206, // jetpack sound
CHAN_ITEMEXTRA = 63207, // additional item sounds
CHAN_AMBEXTRA = 63208 // player ambience when submerged
};
// Misc. Utility code
@ -367,6 +368,8 @@ Class SWWMScoreObj : Thinker
int lifespan, initialspan;
int starttic, seed, seed2;
int ofs;
SWWMScoreObj prev, next;
bool damnum;
static SWWMScoreObj Spawn( int score, Vector3 pos, int tcolor = Font.CR_GOLD, String str = "", int ofs = 0 )
{
@ -381,9 +384,56 @@ Class SWWMScoreObj : Thinker
o.seed = Random[ScoreBits]();
o.seed2 = Random[ScoreBits]();
o.ofs = ofs;
o.damnum = (tcolor == Font.CR_RED) || (tcolor == Font.CR_GREEN);
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
if ( o.damnum )
{
o.next = hnd.damnums;
if ( hnd.damnums ) hnd.damnums.prev = o;
hnd.damnums = o;
hnd.damnums_cnt++;
}
else
{
o.next = hnd.scorenums;
if ( hnd.scorenums ) hnd.scorenums.prev = o;
hnd.scorenums = o;
hnd.scorenums_cnt++;
}
}
return o;
}
override void OnDestroy()
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
if ( damnum )
{
hnd.damnums_cnt--;
if ( !prev ) hnd.damnums = next;
}
else
{
hnd.scorenums_cnt--;
if ( !prev ) hnd.scorenums = next;
}
if ( !prev )
{
if ( next ) next.prev = null;
}
else
{
prev.next = next;
if ( next ) next.prev = prev;
}
}
Super.OnDestroy();
}
override void Tick()
{
lifespan--;
@ -403,6 +453,7 @@ Class SWWMInterest : Thinker
Key trackedkey;
Line trackedline;
Vector3 pos;
SWWMInterest prev, next;
static SWWMInterest Spawn( Vector3 pos = (0,0,0), Key thekey = null, Line theline = null )
{
@ -419,9 +470,37 @@ Class SWWMInterest : Thinker
return null;
}
i.pos = thekey?thekey.Vec3Offset(0,0,thekey.height/2):pos;
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
i.next = hnd.intpoints;
if ( hnd.intpoints ) hnd.intpoints.prev = i;
hnd.intpoints = i;
hnd.intpoints_cnt++;
}
return i;
}
override void OnDestroy()
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
hnd.intpoints_cnt--;
if ( !prev )
{
hnd.intpoints = next;
if ( next ) next.prev = null;
}
else
{
prev.next = next;
if ( next ) next.prev = prev;
}
}
Super.OnDestroy();
}
override void Tick()
{
// update
@ -439,6 +518,7 @@ Class SWWMCombatTracker : Thinker
DynamicValueInterpolator intp;
Vector3 pos, prevpos;
PlayerInfo myplayer;
SWWMCombatTracker prev, next;
static SWWMCombatTracker Spawn( Actor target )
{
@ -461,9 +541,37 @@ Class SWWMCombatTracker : Thinker
t.prevpos = level.Vec3Offset(target.prev,(0,0,target.default.height));
t.intp = DynamicValueInterpolator.Create(t.lasthealth,.5,1,100);
t.myplayer = target.player;
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
t.next = hnd.trackers;
if ( hnd.trackers ) hnd.trackers.prev = t;
hnd.trackers = t;
hnd.trackers_cnt++;
}
return t;
}
override void OnDestroy()
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
hnd.trackers_cnt--;
if ( !prev )
{
hnd.trackers = next;
if ( next ) next.prev = null;
}
else
{
prev.next = next;
if ( next ) next.prev = prev;
}
}
Super.OnDestroy();
}
override void Tick()
{
// update
@ -1217,6 +1325,10 @@ Class SWWMHandler : EventHandler
transient int highesttic;
transient Array<QueuedFlash> flashes;
transient Array<LastLine> lastlines;
SWWMCombatTracker trackers;
SWWMScoreObj scorenums, damnums;
SWWMInterest intpoints;
int trackers_cnt, scorenums_cnt, damnums_cnt, intpoints_cnt;
bool tookdamage[MAXPLAYERS];
int spreecount[MAXPLAYERS];
int lastkill[MAXPLAYERS];
@ -1224,6 +1336,7 @@ Class SWWMHandler : EventHandler
int lastitemcount[MAXPLAYERS];
transient CVar mutevoice;
transient ui CVar useshaders;
static int AddOneliner( String type, int level, int delay = 5 )
{
@ -1420,10 +1533,16 @@ Class SWWMHandler : EventHandler
else if ( e.IsSaveGame || e.IsReopen )
{
// clear all floating numbers
let ti = ThinkerIterator.Create("SWWMScoreObj",Thinker.STAT_USER);
Thinker t;
while ( t = ti.Next() )
t.Destroy();
for ( SWWMScoreObj sc=scorenums; sc; sc=sc.Next )
sc.lifespan = 0;
for ( SWWMScoreObj sc=damnums; sc; sc=sc.Next )
sc.lifespan = 0;
// restore underwater sounds for players
for ( int i=0; i<MAXPLAYERS; i++ )
{
if ( !playeringame[i] || (players[i].mo is 'Demolitionist') ) continue;
Demolitionist(players[i].mo).CheckUnderwaterAmb(true);
}
}
}
@ -1876,74 +1995,7 @@ Class SWWMHandler : EventHandler
}
else if ( e.Replacee is 'CWeaponPiece2' ) e.Replacement = 'CandyGun';
else if ( e.Replacee is 'MWeaponPiece1' ) e.Replacement = 'Ynykron';
else if ( e.Replacee is 'ArtiPoisonBag' )
{
switch( Random[Replacement](0,6) )
{
case 0:
case 1:
case 2:
e.Replacement = redpool[!Random[Replacement](0,2)];
break;
case 3:
case 4:
e.Replacement = greenpool[!Random[Replacement](0,2)];
break;
default:
e.Replacement = 'SWWMNothing';
}
}
else if ( (e.Replacee == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') )
{
switch( Random[Replacement](0,6) )
{
case 0:
case 1:
case 2:
e.Replacement = redpool[Random[Replacement](0,2)];
break;
case 3:
case 4:
e.Replacement = greenpool[Random[Replacement](0,2)];
break;
case 5:
e.Replacement = whitepool[Random[Replacement](0,1)];
break;
case 6:
e.Replacement = purplepool[0];
break;
}
}
else if ( (e.Replacee == 'Shell') || (e.Replacee is 'CrossbowAmmo') )
{
switch( Random[Replacement](0,10) )
{
case 0:
case 1:
case 2:
e.Replacement = redpool[Random[Replacement](2,3)];
break;
case 3:
case 4:
e.Replacement = greenpool[Random[Replacement](2,3)];
break;
case 5:
case 6:
e.Replacement = whitepool[Random[Replacement](1,2)];
break;
case 7:
case 8:
e.Replacement = purplepool[Random[Replacement](0,2)];
break;
case 9:
e.Replacement = bluepool[Random[Replacement](0,2)];
break;
case 10:
e.Replacement = blackpool[0];
break;
}
}
else if ( (e.Replacee == 'ShellBox') || (e.Replacee is 'CrossbowHefty') )
else if ( (e.Replacee == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') || (e.Replacee is 'ArtiPoisonBag') )
{
switch( Random[Replacement](0,14) )
{
@ -1951,27 +2003,87 @@ Class SWWMHandler : EventHandler
case 1:
case 2:
case 3:
e.Replacement = redpool[Random[Replacement](3,5)];
e.Replacement = redpool[Random[Replacement](0,1)];
break;
case 4:
case 5:
case 6:
e.Replacement = greenpool[Random[Replacement](3,4)];
e.Replacement = greenpool[Random[Replacement](0,1)];
break;
case 7:
e.Replacement = purplepool[0];
break;
case 8:
e.Replacement = purplepool[0];
break;
default:
e.Replacement = 'SWWMNothing';
break;
}
}
else if ( (e.Replacee == 'Shell') || (e.Replacee is 'CrossbowAmmo') )
{
switch( Random[Replacement](0,14) )
{
case 0:
case 1:
case 2:
case 3:
e.Replacement = redpool[Random[Replacement](1,2)];
break;
case 4:
case 5:
case 6:
e.Replacement = greenpool[Random[Replacement](1,2)];
break;
case 7:
case 8:
e.Replacement = whitepool[Random[Replacement](0,1)];
break;
case 9:
case 10:
case 11:
e.Replacement = purplepool[Random[Replacement](0,1)];
break;
case 12:
case 13:
e.Replacement = bluepool[Random[Replacement](0,2)];
break;
case 14:
e.Replacement = blackpool[0];
break;
}
}
else if ( (e.Replacee == 'ShellBox') || (e.Replacee is 'CrossbowHefty') )
{
switch( Random[Replacement](0,15) )
{
case 0:
case 1:
case 2:
case 3:
e.Replacement = redpool[Random[Replacement](2,5)];
break;
case 4:
case 5:
case 6:
e.Replacement = greenpool[Random[Replacement](2,4)];
break;
case 7:
case 8:
case 9:
e.Replacement = whitepool[Random[Replacement](2,3)];
e.Replacement = whitepool[Random[Replacement](1,3)];
break;
case 10:
case 11:
case 12:
e.Replacement = purplepool[Random[Replacement](1,2)];
break;
case 12:
case 13:
case 14:
e.Replacement = bluepool[Random[Replacement](2,3)];
break;
case 14:
case 15:
e.Replacement = blackpool[Random[Replacement](0,2)];
break;
}
@ -2224,6 +2336,36 @@ Class SWWMHandler : EventHandler
SWWMStatusBar(statusbar).viewrot = (e.viewangle,e.viewpitch,e.viewroll);
}
// various shaders
override void RenderOverlay( RenderEvent e )
{
PlayerInfo p = players[consoleplayer];
if ( !useshaders ) useshaders = CVar.GetCVar('swwm_shaders',p);
let mo = p.mo;
if ( !mo ) return;
bool pc = (p.camera == mo);
let rage = RagekitPower(mo.FindInventory("RagekitPower"));
if ( pc && rage && useshaders.GetBool() )
{
Shader.SetEnabled(p,"RagekitShader",true);
Shader.SetUniform1f(p,"RagekitShader","timer",(gametic+e.FracTic)/Thinker.TICRATE);
double xstrastr = 1.+max(0,rage.lastpulse-(gametic+e.Fractic))/35.;
Shader.SetUniform1f(p,"RagekitShader","xtrastr",xstrastr**2.);
}
else Shader.SetEnabled(p,"RagekitShader",false);
let ghost = GhostPower(mo.FindInventory("GhostPower"));
if ( pc && ghost && useshaders.GetBool() ) Shader.SetEnabled(p,"GhostShader",true);
else Shader.SetEnabled(p,"GhostShader",false);
let sunny = InvinciballPower(mo.FindInventory("InvinciballPower"));
if ( pc && sunny && useshaders.GetBool() )
{
Shader.SetEnabled(p,"InvinciShader",true);
double str = max(0,sunny.lastpulse-(gametic+e.Fractic))/35.;
Shader.SetUniform1f(p,"InvinciShader","str",str);
}
else Shader.SetEnabled(p,"InvinciShader",false);
}
static void DoFlash( Actor camera, Color c, int duration )
{
// don't flash when paused

View file

@ -16,9 +16,13 @@ Class SWWMStatusBar : BaseStatusBar
// this can be accessed from a section of the knowledge base
Array<MsgLine> MainQueue, PickupQueue, FullHistory;
Array<SWWMCombatTracker> targets; // healthbars
Array<SWWMScoreObj> scoreobjects; // floating scores
Array<SWWMInterest> interesting; // points of interest for omnisight
// sorted arrays of various elements
Array<SWWMInterest> intpoints;
Array<SWWMScoreObj> scoreobjs;
Array<SWWMCombatTracker> trackers;
// the event handler, holding all sorts of stuff
SWWMHandler hnd;
// client cvars
transient CVar safezone, maxchat[2], maxpick, chatduration, msgduration, pickduration, chatcol, teamcol, obitcol, critcol, pickcol, targetter, healthnums, scorenums, scorebonus, targettag;
@ -141,11 +145,13 @@ Class SWWMStatusBar : BaseStatusBar
private bool CmpTarget( SWWMCombatTracker a, SWWMCombatTracker b )
{
if ( !a || !b ) return true;
return (a.myplayer && !b.myplayer);
}
private bool CmpScore( SWWMScoreObj a, SWWMScoreObj b )
{
if ( !a || !b ) return true;
int srt[4] = { Font.CR_GOLD, Font.CR_FIRE, Font.CR_GREEN, Font.CR_RED };
int s1 = 0, s2 = 0;
for ( int i=0; i<3; i++ )
@ -158,6 +164,7 @@ Class SWWMStatusBar : BaseStatusBar
private bool CmpInterest( SWWMInterest a, SWWMInterest b )
{
if ( !a || !b ) return true;
return a.type < b.type;
}
@ -193,99 +200,9 @@ Class SWWMStatusBar : BaseStatusBar
MainQueue.Delete(i);
i--;
}
// update omnisight stuff
if ( CPlayer.mo.FindInventory("Omnisight") )
{
interesting.Clear();
let ii = ThinkerIterator.Create("SWWMInterest",Thinker.STAT_USER);
SWWMInterest poi; // :3
while ( poi = SWWMInterest(ii.Next()) ) interesting.Push(poi);
// sort by distance
for ( int i=0; i<interesting.Size(); i++ )
{
int j = 1;
while ( j < interesting.Size() )
{
int k = j;
while ( (k > 0) && (CmpInterest(interesting[k-1],interesting[k]) || CmpDist(interesting[k-1].pos,interesting[k].pos)) )
{
SWWMInterest tmp = interesting[k];
interesting[k] = interesting[k-1];
interesting[k-1] = tmp;
k--;
}
j++;
}
}
}
// update target stuff
targets.Clear();
if ( targetter.GetBool() )
{
let ti = ThinkerIterator.Create("SWWMCombatTracker",Thinker.STAT_USER);
SWWMCombatTracker ct;
int extratime = 35;
if ( CPlayer.mo.FindInventory("Omnisight") ) extratime += 105;
while ( ct = SWWMCombatTracker(ti.Next()) )
{
// ignore player unless chasecamming
if ( (ct.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( ct.myplayer && deathmatch ) continue; // no players in dm
if ( level.maptime > ct.updated+extratime ) continue;
targets.Push(ct);
}
// sort by distance (give priority to players)
for ( int i=0; i<targets.Size(); i++ )
{
int j = 1;
while ( j < targets.Size() )
{
int k = j;
while ( (k > 0) && (CmpTarget(targets[k-1],targets[k]) || CmpDist(targets[k-1].pos,targets[k].pos)) )
{
SWWMCombatTracker tmp = targets[k];
targets[k] = targets[k-1];
targets[k-1] = tmp;
k--;
}
j++;
}
}
// trim size, to unclutter
if ( targets.Size() > 40 ) targets.Resize(40);
}
// update floating scores
scoreobjects.Clear();
let si = ThinkerIterator.Create("SWWMScoreObj",Thinker.STAT_USER);
SWWMScoreObj so;
while ( so = SWWMScoreObj(si.Next()) )
{
if ( ((so.tcolor == Font.CR_RED) || (so.tcolor == Font.CR_GREEN)) && (!healthnums.GetBool() || (level.Vec3Diff(viewpos,so.pos).length() > 2000)) ) continue;
else if ( !scorenums.GetBool() || ((so.tcolor != Font.CR_GOLD) && !scorebonus.GetBool()) ) continue;
scoreobjects.Push(so);
// prevent slowdowns if hurting too many enemies at once
if ( scoreobjects.Size() >= 100 ) break;
}
// sort by distance
for ( int i=0; i<scoreobjects.Size(); i++ )
{
int j = 1;
while ( j < scoreobjects.Size() )
{
int k = j;
while ( (k > 0) && (CmpScore(scoreobjects[k-1],scoreobjects[k]) || CmpDist(scoreobjects[k-1].pos,scoreobjects[k].pos)) )
{
SWWMScoreObj tmp = scoreobjects[k];
scoreobjects[k] = scoreobjects[k-1];
scoreobjects[k-1] = tmp;
k--;
}
j++;
}
}
// update interpolators
HealthInter.Update(CPlayer.health);
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
ScoreInter.Update(SWWMCredits.Get(CPlayer));
let d = Demolitionist(CPlayer.mo);
if ( d )
@ -301,6 +218,98 @@ Class SWWMStatusBar : BaseStatusBar
// let weapons update their own interpolators
if ( CPlayer.ReadyWeapon is 'SWWMWeapon' )
SWWMWeapon(CPlayer.ReadyWeapon).HudTick();
bool thesight = CPlayer.mo.FindInventory("Omnisight");
if ( thesight )
{
// update omnisight stuff
if ( intpoints.Size() != hnd.intpoints_cnt )
intpoints.Resize(hnd.intpoints_cnt);
int i = 0;
for ( SWWMInterest poi=hnd.intpoints; poi; poi=poi.next )
intpoints[i++] = poi;
// sort by distance
for ( int i=0; i<hnd.intpoints_cnt; i++ )
{
int j = 1;
while ( j < hnd.intpoints_cnt )
{
int k = j;
while ( (k > 0) && (CmpInterest(intpoints[k-1],intpoints[k]) || CmpDist(intpoints[k-1].pos,intpoints[k].pos)) )
{
SWWMInterest tmp = intpoints[k];
intpoints[k] = intpoints[k-1];
intpoints[k-1] = tmp;
k--;
}
j++;
}
}
}
if ( targetter.GetBool() )
{
// update target stuff
if ( trackers.Size() != hnd.trackers_cnt )
trackers.Resize(hnd.trackers_cnt);
int i = 0, actual = 0;
for ( SWWMCombatTracker trk=hnd.trackers; trk; trk=trk.next )
{
actual++;
// ignore player unless chasecamming
if ( (trk.mytarget == players[consoleplayer].mo) && (players[consoleplayer].Camera == players[consoleplayer].mo) && !(players[consoleplayer].cheats&CF_CHASECAM) ) continue;
if ( trk.myplayer && deathmatch ) continue; // no players in dm
int mtime = 35;
if ( thesight && (trk.lasthealth > 0) ) mtime += 105;
if ( level.maptime > trk.updated+mtime ) continue;
trackers[i++] = trk;
}
// squeeze if some were discarded
if ( i != hnd.trackers_cnt )
trackers.Resize(i);
// sort by distance (give priority to players)
for ( int i=0; i<trackers.Size(); i++ )
{
int j = 1;
while ( j < trackers.Size() )
{
int k = j;
while ( (k > 0) && (CmpTarget(trackers[k-1],trackers[k]) || CmpDist(trackers[k-1].pos,trackers[k].pos)) )
{
SWWMCombatTracker tmp = trackers[k];
trackers[k] = trackers[k-1];
trackers[k-1] = tmp;
k--;
}
j++;
}
}
}
// update floating scores, adding the scorenums first, then the damnums
int total_sz = hnd.scorenums_cnt;
total_sz += min(100,hnd.damnums_cnt);
if ( scoreobjs.Size() != total_sz )
scoreobjs.Resize(total_sz);
int i = 0;
for ( SWWMScoreObj scr=hnd.scorenums; scr; scr=scr.next )
scoreobjs[i++] = scr;
for ( SWWMScoreObj scr=hnd.damnums; scr && (i<total_sz); scr=scr.next )
scoreobjs[i++] = scr;
// sort by distance
for ( int i=0; i<total_sz; i++ )
{
int j = 1;
while ( j < total_sz )
{
int k = j;
while ( (k > 0) && (CmpScore(scoreobjs[k-1],scoreobjs[k]) || CmpDist(scoreobjs[k-1].pos,scoreobjs[k].pos)) )
{
SWWMScoreObj tmp = scoreobjs[k];
scoreobjs[k] = scoreobjs[k-1];
scoreobjs[k-1] = tmp;
k--;
}
j++;
}
}
}
override void Init()
@ -339,6 +348,7 @@ Class SWWMStatusBar : BaseStatusBar
gl_proj = new("swwmLe__GLScreen");
sw_proj = new("swwmLe__SWScreen");
PrepareProjection();
hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
}
static private string FormatDist( double dist )
@ -350,6 +360,8 @@ Class SWWMStatusBar : BaseStatusBar
private void DrawTarget()
{
// don't draw when dead or with automap open
if ( (CPlayer.health <= 0) || automapactive ) return;
if ( !targettag ) targettag = CVar.GetCVar('swwm_targettags',players[consoleplayer]);
viewport.FromHud();
proj.CacheResolution();
@ -362,17 +374,19 @@ Class SWWMStatusBar : BaseStatusBar
String tag;
if ( thesight )
{
for ( int i=0; i<interesting.Size(); i++ )
for ( int i=0; i<intpoints.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,interesting[i].pos);
let poi = intpoints[i];
if ( !poi ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,poi.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( interesting[i].type == INT_Key ) tag = String.Format("\cf%s\c-",StringTable.Localize(interesting[i].trackedkey.GetTag()));
else if ( interesting[i].type == INT_Exit )
if ( poi.type == INT_Key ) tag = String.Format("\cf%s\c-",StringTable.Localize(poi.trackedkey.GetTag()));
else if ( poi.type == INT_Exit )
{
if ( interesting[i].trackedline.special == Exit_Secret )
if ( poi.trackedline.special == Exit_Secret )
tag = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_SEXIT"));
else tag = String.Format("\cy%s\c-",StringTable.Localize("$SWWM_NEXIT"));
}
@ -382,89 +396,96 @@ Class SWWMStatusBar : BaseStatusBar
}
}
// targetting array
for ( int i=0; i<targets.Size(); i++ )
int displayed = 0;
for ( int i=0; i<trackers.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,targets[i].prevpos*(1.-fractic)+targets[i].pos*fractic);
let targ = trackers[i];
if ( !targ ) continue;
// cap to 40, so the screen isn't too cluttered
if ( displayed++ > 40 ) break;
Vector3 tdir = Level.Vec3Diff(ViewPos,targ.prevpos*(1.-fractic)+targ.pos*fractic);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
tag = targets[i].mytag;
tag = targ.mytag;
int mtime = 35;
if ( thesight && (targets[i].lasthealth > 0) ) mtime += 105;
double alph = clamp(((targets[i].updated+mtime)-level.maptime)/35.,0.,1.);
if ( thesight && (targ.lasthealth > 0) ) mtime += 105;
double alph = clamp(((targ.updated+mtime)-level.maptime)/35.,0.,1.);
Vector2 barsiz = TexMan.GetScaledSize(EnemyBTex);
barsiz.x *= hs.x;
barsiz.y *= hs.y;
Vector2 barpos = vpos-(barsiz/2.);
barpos.y -= 16.;
if ( targettag.GetBool() || targets[i].myplayer && (tag != "") )
if ( targettag.GetBool() || targ.myplayer && (tag != "") )
Screen.DrawText(mMiniwiFont.mFont,Font.CR_WHITE,(barpos.x+barsiz.x/2.-(mMiniwiFont.mFont.StringWidth(tag)*hs.x)/2.)/hs.x,(barpos.y-mMiniwiFont.mFont.GetHeight()*hs.y)/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
Screen.DrawTexture(EnemyBTex,false,barpos.x/hs.x,barpos.y/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
int ht = clamp(targets[i].intp.GetValue(),0,targets[i].maxhealth*10);
int hw = int((min(ht,targets[i].maxhealth)*50.)/targets[i].maxhealth);
if ( targets[i].mytarget && (targets[i].mytarget.bInvulnerable || (targets[i].myplayer && (targets[i].myplayer.cheats&(CF_GODMODE|CF_GODMODE2))) || targets[i].mytarget.FindInventory("InvinciballPower")) )
int ht = clamp(targ.intp.GetValue(),0,targ.maxhealth*10);
int hw = int((min(ht,targ.maxhealth)*50.)/targ.maxhealth);
if ( targ.mytarget && (targ.mytarget.bInvulnerable || (targ.myplayer && (targ.myplayer.cheats&(CF_GODMODE|CF_GODMODE2))) || targ.mytarget.FindInventory("InvinciballPower")) )
{
Screen.DrawTexture(EnemyHTex[4],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
continue;
}
Screen.DrawTexture(EnemyHTex[0],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
if ( ht > targets[i].maxhealth )
if ( ht > targ.maxhealth )
{
hw = int((min(ht-targets[i].maxhealth,targets[i].maxhealth)*50.)/targets[i].maxhealth);
hw = int((min(ht-targ.maxhealth,targ.maxhealth)*50.)/targ.maxhealth);
Screen.DrawTexture(EnemyHTex[1],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targets[i].maxhealth*2 )
if ( ht > targ.maxhealth*2 )
{
hw = int((min(ht-targets[i].maxhealth*2,targets[i].maxhealth*3)*50.)/(targets[i].maxhealth*3));
hw = int((min(ht-targ.maxhealth*2,targ.maxhealth*3)*50.)/(targ.maxhealth*3));
Screen.DrawTexture(EnemyHTex[2],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
if ( ht > targets[i].maxhealth*5 )
if ( ht > targ.maxhealth*5 )
{
hw = int((min(ht-targets[i].maxhealth*5,targets[i].maxhealth*5)*50.)/(targets[i].maxhealth*5));
hw = int((min(ht-targ.maxhealth*5,targ.maxhealth*5)*50.)/(targ.maxhealth*5));
Screen.DrawTexture(EnemyHTex[3],false,(barpos.x+2*hs.x)/hs.x,(barpos.y+2*hs.y)/hs.y,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph,DTA_WindowRight,hw);
}
}
// floating kill scores and others
for ( int i=0; i<scoreobjects.Size(); i++ )
for ( int i=0; i<scoreobjs.Size(); i++ )
{
Vector3 tdir = Level.Vec3Diff(ViewPos,scoreobjects[i].pos);
let snum = scoreobjs[i];
if ( !snum ) continue;
Vector3 tdir = Level.Vec3Diff(ViewPos,snum.pos);
proj.ProjectWorldPos(ViewPos+tdir);
Vector2 npos = proj.ProjectToNormal();
if ( !proj.IsInFront() ) continue;
Vector2 vpos = viewport.SceneToWindow(npos);
if ( scoreobjects[i].str != "" )
if ( snum.str != "" )
{
tag = StringTable.Localize(scoreobjects[i].str);
if ( scoreobjects[i].score == int.max ) tag.AppendFormat(" %s",StringTable.Localize("$SWWM_MAX"));
else if ( scoreobjects[i].score > 0 ) tag.AppendFormat(" x%d",scoreobjects[i].score);
tag = StringTable.Localize(snum.str);
if ( snum.score == int.max ) tag.AppendFormat(" %s",StringTable.Localize("$SWWM_MAX"));
else if ( snum.score > 0 ) tag.AppendFormat(" x%d",snum.score);
}
else tag = String.Format("%+d",scoreobjects[i].score);
double alph = clamp((scoreobjects[i].lifespan+fractic)/35.,0.,1.);
else tag = String.Format("%+d",snum.score);
double alph = clamp((snum.lifespan+fractic)/35.,0.,1.);
Vector2 fo = (0,0);
if ( scoreobjects[i].tcolor == Font.CR_RED )
if ( snum.tcolor == Font.CR_RED )
{
// damage falls down
int initspd = (128-scoreobjects[i].seed);
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 64+scoreobjects[i].seed2/2;
fo.x = (.05*initspd)*((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**.8);
fo.y = -((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**1.5)+boostup*sin((90./scoreobjects[i].initialspan)*(level.maptime+fractic-scoreobjects[i].starttic));
int boostup = 64+snum.seed2/2;
fo.x = (.05*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.8);
fo.y = -((snum.initialspan-(snum.lifespan-fractic))**1.5)+boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else if ( scoreobjects[i].tcolor == Font.CR_GREEN )
else if ( snum.tcolor == Font.CR_GREEN )
{
// health falls up (?)
int initspd = (128-scoreobjects[i].seed);
int initspd = (128-snum.seed);
if ( initspd >= 0 && initspd < 32 ) initspd = 32;
if ( initspd < 0 && initspd > -32 ) initspd = -32;
int boostup = 16+scoreobjects[i].seed2/4;
fo.x = (.15*initspd)*((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**.6);
fo.y = ((scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic))**1.2)-boostup*sin((90./scoreobjects[i].initialspan)*(level.maptime+fractic-scoreobjects[i].starttic));
int boostup = 16+snum.seed2/4;
fo.x = (.15*initspd)*((snum.initialspan-(snum.lifespan-fractic))**.6);
fo.y = ((snum.initialspan-(snum.lifespan-fractic))**1.2)-boostup*sin((90./snum.initialspan)*(level.maptime+fractic-snum.starttic));
}
else fo.y = scoreobjects[i].initialspan-(scoreobjects[i].lifespan-fractic); // score rises linearly
fo.y += scoreobjects[i].ofs*mMiniwiFont.mFont.GetHeight();
Screen.DrawText(mMiniwiFont.mFont,scoreobjects[i].tcolor,(vpos.x-hs.x*(fo.x+mMiniwiFont.mFont.StringWidth(tag)/2.))/hs.x,(vpos.y-hs.y*(fo.y+(mMiniwiFont.mFont.GetHeight()/2.)))/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
else fo.y = snum.initialspan-(snum.lifespan-fractic); // score rises linearly
fo.y += snum.ofs*mMiniwiFont.mFont.GetHeight();
Screen.DrawText(mMiniwiFont.mFont,snum.tcolor,(vpos.x-hs.x*(fo.x+mMiniwiFont.mFont.StringWidth(tag)/2.))/hs.x,(vpos.y-hs.y*(fo.y+(mMiniwiFont.mFont.GetHeight()/2.)))/hs.y,tag,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
}
}

View file

@ -306,7 +306,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
}
return true;
case MKEY_ENTER:
if ( (curtab == TAB_INVENTORY) && (invlist.Size() > 0) )
if ( (curtab == TAB_INVENTORY) && (invlist.Size() > 0) && (sel0 < invlist.Size()) )
{
// can't use this
if ( invlist[sel0] is 'Ammo' ) return true;
@ -317,7 +317,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
checkuse = gametic+1;
EventHandler.SendNetworkEvent(String.Format("swwmuseitem.%s",invlist[sel0].GetClassName()),consoleplayer);
}
else if ( (curtab == TAB_STORE) && (storelist.Size() > 0) )
else if ( (curtab == TAB_STORE) && (storelist.Size() > 0) && (sel0 < storelist.Size()) )
{
int moni = SWWMCredits.Get(players[consoleplayer]);
let itm = GetDefaultByType(storelist[sel0]);
@ -359,7 +359,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
MenuSound("menu/democlose");
sub = false;
}
else if ( lorelist.Size() > 0 )
else if ( (lorelist.Size() > 0) && (sel0 < lorelist.Size()) )
{
// mark as read
if ( !lorelist[sel0].read )
@ -440,7 +440,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
// alphabetically sorted inventory
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
{
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') ) continue;
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) ) continue;
String tag = inv.GetTag();
bool greater = false;
for ( int i=0; i<invlist.Size(); i++ )

View file

@ -19,12 +19,21 @@ Class Demolitionist : PlayerPawn
SWWMStats mystats;
int cairtime;
Vector3 oldpos;
int lastmpain;
double guideangle, guidepitch, guideroll;
enum EUnderType
{
UNDER_NONE,
UNDER_WATER,
UNDER_SLIME,
UNDER_LAVA
};
int lastunder;
Default
{
Speed 1;
@ -246,7 +255,6 @@ Class Demolitionist : PlayerPawn
{
Super.PostBeginPlay();
mystats = SWWMStats.Find(player);
oldpos = pos;
lastground = true;
}
void A_Dash()
@ -290,12 +298,87 @@ Class Demolitionist : PlayerPawn
}
fuelcooldown = max(20,fuelcooldown);
}
void CheckUnderwaterAmb( bool restore = false )
{
Vector3 headpos = Vec3Offset(0,0,player.viewheight);
Vector3 centerpos = Vec3Offset(0,0,height/2);
Sector headregion = null;
if ( CurSector.moreflags&Sector.SECMF_UNDERWATER ) // check underwater sector
headregion = CurSector;
else if ( CurSector.heightsec ) // check height transfer
{
let hsec = CurSector.heightsec;
double fh = hsec.floorplane.ZAtPoint(pos.xy);
if ( pos.z < fh )
{
if ( headpos.z <= fh )
headregion = hsec;
}
else if ( !(hsec.moreflags&Sector.SECMF_FAKEFLOORONLY) && (headpos.z > hsec.ceilingplane.ZAtPoint(pos.xy)) )
headregion = hsec;
}
else // check 3D floors
{
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
{
let ff = CurSector.Get3DFloor(i);
if ( !(ff.flags&F3DFloor.FF_EXISTS) || (ff.flags&F3DFloor.FF_SOLID) || (!(ff.flags&F3DFloor.FF_SWIMMABLE) && (ff.alpha == 0)) ) continue;
double ff_bottom = ff.bottom.ZAtPoint(pos.xy);
double ff_top = ff.top.ZAtPoint(pos.xy);
if ( (ff_top <= pos.z) || (ff_bottom > centerpos.z) ) continue;
if ( headpos.z <= ff_top )
{
headregion = ff.model;
}
break;
}
}
int curunder = UNDER_NONE;
if ( headregion )
{
switch ( headregion.damagetype )
{
case 'Fire':
case 'Lava':
curunder = UNDER_LAVA;
break;
case 'Slime':
case 'Poison':
case 'PoisonCloud':
curunder = UNDER_SLIME;
break;
case 'Ice':
case 'Drowning':
default:
curunder = UNDER_WATER;
break;
}
}
if ( (curunder != lastunder) || restore )
{
static const string undersnd[] = {"","misc/underwater","misc/underslime","misc/underlava"};
static const string entersnd[] = {"","misc/waterenter","misc/slimeenter","misc/lavaenter"};
static const string exitsnd[] = {"","misc/waterexit","misc/slimeexit","misc/lavaexit"};
A_StopSound(CHAN_AMBEXTRA);
if ( curunder > UNDER_NONE )
{
A_StartSound(undersnd[curunder],CHAN_AMBEXTRA,CHANF_LOOPING|CHANF_UI);
if ( !restore && (players[consoleplayer].Camera == self) )
A_StartSound(entersnd[curunder],CHAN_FOOTSTEP,CHANF_OVERLAP|CHANF_UI);
}
if ( !restore && (lastunder > UNDER_NONE) && (players[consoleplayer].Camera == self) )
A_StartSound(exitsnd[lastunder],CHAN_FOOTSTEP,CHANF_OVERLAP|CHANF_UI);
}
if ( curunder > UNDER_NONE )
A_SoundVolume(CHAN_AMBEXTRA,(players[consoleplayer].Camera==self)?1.:0.);
lastunder = curunder;
}
override void Tick()
{
Super.Tick();
if ( !player ) return;
double traveldist = level.Vec3Diff(oldpos,pos).length();
if ( waterlevel < 3 )
double traveldist = level.Vec3Diff(prev,pos).length();
if ( waterlevel < 2 )
{
if ( !player.onground || bNoGravity )
{
@ -309,8 +392,8 @@ Class Demolitionist : PlayerPawn
mystats.grounddist += traveldist;
}
}
if ( traveldist > mystats.topspeed ) mystats.topspeed = traveldist;
oldpos = pos;
CheckUnderwaterAmb();
if ( vel.length() > mystats.topspeed ) mystats.topspeed = vel.length();
if ( !myvoice ) myvoice = CVar.GetCVar('swwm_voicetype',player);
if ( !mute ) mute = CVar.GetCVar('swwm_mutevoice',player);
if ( player.onground && !bNoGravity && !lastground && (waterlevel < 2) && (health > 0) )
@ -334,7 +417,8 @@ Class Demolitionist : PlayerPawn
if ( lastvelz < -10 ) A_StartSound("demolitionist/runstop",CHAN_FOOTSTEP,CHANF_OVERLAP);
if ( (player == players[consoleplayer]) && (lastvelz < -gruntspeed) && (mute.GetInt() < 4) )
A_StartSound(String.Format("voice/%s/grunt",myvoice.GetString()),CHAN_DEMOVOICE,CHANF_OVERLAP);
A_Footstep(0,true,clamp(-lastvelz*0.05,0.01,1.0));
if ( lastvelz < -1 )
A_Footstep(0,true,clamp(-lastvelz*0.05,0.0,1.0));
}
lastground = player.onground;
lastvelz = prevvelz;
@ -381,7 +465,7 @@ Class Demolitionist : PlayerPawn
double moveang = atan2(dir.y,dir.x);
Vector3 sc = level.SphericalCoords(pos,a.pos,(moveang,0));
if ( abs(sc.x) > 60 ) continue;
// bosses and large monsters will stop the player
// large monsters will stop the player
A_QuakeEx(1,1,1,3,0,128,"",QF_RELATIVE|QF_SCALEDOWN);
a.A_StartSound("demolitionist/bump",CHAN_FOOTSTEP,CHANF_OVERLAP);
if ( a.bDONTTHRUST || (a.Mass >= Mass*5) )
@ -715,6 +799,11 @@ Class Demolitionist : PlayerPawn
last_jump_held = level.maptime+1;
}
}
override void DeathThink()
{
// TODO reboot mechanic, death camera that doesn't move body
Super.DeathThink();
}
override void PlayIdle()
{
if ( !player )

View file

@ -136,6 +136,7 @@ Class GhostPower : PowerInvisibility
{
Super.InitEffect();
if ( !Owner ) return;
SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20);
DoEffect();
}
override void EndEffect()
@ -144,6 +145,7 @@ Class GhostPower : PowerInvisibility
if ( !Owner ) return;
Owner.bNOTARGET = false;
Owner.A_StartSound("powerup/ghostend",CHAN_ITEMEXTRA);
SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20);
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_GHOSTARTI"));
}
@ -334,6 +336,14 @@ Class GravityPower : Powerup
}
Class GravityX : GhostArtifactX
{
Default
{
RenderStyle "Normal";
}
}
Class GravitySuppressor : Inventory
{
Mixin SWWMAutoUseFix;
@ -347,6 +357,15 @@ Class GravitySuppressor : Inventory
else Owner.GiveInventory("GravityPower",1);
return true;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tracer = Spawn("GravityX",pos);
tracer.angle = angle;
tracer.target = self;
tracer.FloatBobPhase = FloatBobPhase;
}
Default
{
Tag "$T_GRAVITYS";
@ -439,6 +458,7 @@ Class InvinciballPower : Powerup
{
Actor l, snd;
int lasteffect;
transient int lastpulse;
Default
{
@ -455,6 +475,8 @@ Class InvinciballPower : Powerup
l = Spawn("InvinciballLight",Owner.pos);
l.target = Owner;
l.master = self;
lastpulse = max(lastpulse,gametic+35);
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
}
override void DoEffect()
@ -471,6 +493,7 @@ Class InvinciballPower : Powerup
Super.EndEffect();
if ( !Owner ) return;
Owner.A_StartSound("powerup/invinciballend",CHAN_ITEMEXTRA);
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_INVINCIBALL"));
}
@ -489,11 +512,20 @@ Class InvinciballPower : Powerup
SWWMHandler.DoFlash(Owner,Color(64,255,64,0),15);
Owner.A_StartSound("powerup/invinciballhit",CHAN_POWERUP);
lasteffect = level.maptime;
lastpulse = max(lastpulse,gametic+20);
}
}
}
}
Class InvinciballX : GhostArtifactX
{
Default
{
RenderStyle "Normal";
}
}
Class FuckingInvinciball : Inventory
{
Mixin SWWMAutoUseFix;
@ -510,10 +542,24 @@ Class FuckingInvinciball : Inventory
Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
Owner.A_StartSound("misc/sundowner",CHAN_POWERUPEXTRA);
let i = InvinciballPower(Owner.FindInventory("InvinciballPower"));
if ( i ) i.EffectTics = i.default.EffectTics;
if ( i )
{
i.EffectTics = i.default.EffectTics;
i.lastpulse = max(i.lastpulse,gametic+35);
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
}
else Owner.GiveInventory("InvinciballPower",1);
return true;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tracer = Spawn("InvinciballX",pos);
tracer.angle = angle;
tracer.target = self;
tracer.FloatBobPhase = FloatBobPhase;
}
Default
{
Tag "$T_INVINCIBALL";
@ -607,6 +653,7 @@ Class RagekitPower : Powerup
{
Actor l, snd;
int lasteffect, lastrage;
transient int lastpulse;
override double GetSpeedFactor()
{
@ -629,6 +676,7 @@ Class RagekitPower : Powerup
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
lasteffect = int.min;
lastpulse = max(lastpulse,gametic+35);
l = Spawn("RagekitLight",Owner.pos);
l.target = Owner;
l.master = self;
@ -647,6 +695,7 @@ Class RagekitPower : Powerup
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) )
lastrage = SWWMHandler.AddOneliner("ragekit",2,5);
Owner.A_QuakeEx(2,2,2,Random[Rage](1,2),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
lastpulse = max(lastpulse,gametic+10);
}
}
@ -655,6 +704,8 @@ Class RagekitPower : Powerup
Super.EndEffect();
if ( !Owner ) return;
Owner.A_StartSound("powerup/ragekitend",CHAN_ITEMEXTRA);
SWWMHandler.DoFlash(Owner,Color(128,255,0,0),30);
Owner.A_QuakeEx(4,4,4,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_RAGEKIT"));
}
@ -671,6 +722,7 @@ Class RagekitPower : Powerup
lastrage = SWWMHandler.AddOneliner("ragekit",2,5);
Owner.A_StartSound("powerup/ragekithit",CHAN_POWERUP);
lasteffect = level.maptime;
lastpulse = max(lastpulse,gametic+35);
}
}
else if ( passive )
@ -678,6 +730,14 @@ Class RagekitPower : Powerup
}
}
Class RagekitX : GhostArtifactX
{
Default
{
RenderStyle "Normal";
}
}
Class Ragekit : Inventory
{
Mixin SWWMAutoUseFix;
@ -687,10 +747,25 @@ Class Ragekit : Inventory
if ( pickup && !deathmatch ) return false;
Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
let r = RagekitPower(Owner.FindInventory("RagekitPower"));
if ( r ) r.EffectTics = r.default.EffectTics;
if ( r )
{
r.EffectTics = r.default.EffectTics;
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
r.lastpulse = max(r.lastpulse,gametic+35);
}
else Owner.GiveInventory("RagekitPower",1);
return true;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
tracer = Spawn("RagekitX",pos);
tracer.angle = angle;
tracer.target = self;
tracer.FloatBobPhase = FloatBobPhase;
}
Default
{
Tag "$T_RAGEKIT";

View file

@ -525,7 +525,7 @@ Class SaltLight : PaletteLight
{
Tag "SaltTail";
ReactionTime 30;
Args 0,0,0,80;
Args 0,0,0,120;
}
}
Class SaltLight2 : PaletteLight
@ -534,7 +534,7 @@ Class SaltLight2 : PaletteLight
{
Tag "SaltExpl";
ReactionTime 30;
Args 0,0,0,80;
Args 0,0,0,70;
}
}
@ -543,7 +543,7 @@ Class SaltImpact : Actor
Default
{
Obituary "$O_SPREADGUN_BLUE";
DamageType "Salt";
DamageType "Electricity";
RenderStyle "Add";
Radius 0.1;
Height 0;
@ -614,7 +614,7 @@ Class SaltBeam : Actor
Default
{
Obituary "$O_SPREADGUN_BLUE";
DamageType "Salt";
DamageType "Electricity";
RenderStyle "Add";
Radius 0.1;
Height 0;
@ -645,7 +645,7 @@ Class SaltBeam : Actor
let b = Actor.Spawn("InvisibleSplasher",t.WaterHitList[i].hitpos);
b.A_CheckTerrain();
}
for ( int i=8; i<t.Results.Distance; i+=16 )
for ( int i=16; i<t.Results.Distance; i+=32 )
{
if ( !Random[Spreadgun](0,Stamina) ) continue;
let b = Actor.Spawn("SWWMSmoke",level.Vec3Offset(pos,x*i));
@ -688,8 +688,16 @@ Class SaltBeam : Actor
}
return;
}
else if ( (args[0] > 20) && !Random[Spreadgun](0,800/args[0]) )
{
let i = Spawn("SaltImpact",level.Vec3Offset(pos,x*32));
i.angle = atan2(x.y,x.x);
i.pitch = asin(-x.z);
i.target = target;
return;
}
// next beam
if ( !(special2%2) && !Random[Spreadgun](0,2) )
if ( !(special2%2) && !Random[Spreadgun](0,4) )
Spawn("SaltLight",level.Vec3Offset(pos,x*16));
let next = Spawn("SaltBeam",level.Vec3Offset(pos,x*32));
double a = FRandom[Spreadgun](0,360), s = FRandom[Spreadgun](0,.06);
@ -698,6 +706,7 @@ Class SaltBeam : Actor
next.pitch = asin(-dir.z);
next.target = target;
next.special2 = (special2+1)%10;
next.args[0] = args[0]+1;
next.SetStateLabel("TrailSpawn");
}
@ -714,10 +723,10 @@ Class SaltBeam : Actor
A_FadeOut(.04);
if ( Random[Spreadgun](-2,GetAge()/10) == 0 )
{
SWWMHandler.DoBlast(self,48,5000,target);
A_Explode(5,48,0);
SWWMHandler.DoBlast(self,64,5000,target);
A_Explode(5,64,0);
}
if ( (special2 || GetAge()) && !special1 ) SpreadOut();
if ( ((special2%5) || GetAge()) && !special1 ) SpreadOut();
}
States
@ -1311,8 +1320,7 @@ Class Spreadgun : SWWMWeapon
{
Super.ModifyDropAmount(dropamount);
// toss some ammo while we're at it
let am = (Class<Ammo>)(GetReplacement("Shell"));
A_DropItem(am,Random[Spreadgun](3,5));
A_DropItem(Random[Spreadgun](0,2)?"RedShell":"GreenShell",Random[Spreadgun](1,3));
}
Default