Various optimizations and a couple changes:

- Lightweight Tick() for smoke and debris (has some glitches I gotta figure out).
- Add option for buckshot to gib (on by default).
- Clips are replaced by shells again.
- Increased look sensitivity when crouching with Silver Bullet.
- Fix 3D floor handling of nonsolids.
- Fix combat trackers not updating their position when an actor changes height while stationary (e.g.: crouching players).
This commit is contained in:
Mari the Deer 2020-09-13 14:39:24 +02:00
commit 431e2d5ddc
19 changed files with 510 additions and 54 deletions

View file

@ -94,7 +94,7 @@ Coming from the **Doom** modding side of things, this gun really packs a punch,
The **Spreadgun** uses 10 gauge ammunition, apparently just for the sake of making it feel more powerful due to the increased recoil.
### 10Ga shells ~ Replaces Shells, Ethereal Arrows, Chaos Device/Banishment Device
### 10Ga shells ~ Replaces Clip / Shells, Wand Crystal / Ethereal Arrows, Chaos Device / Banishment Device
![](docimg/shells.png)
Available in the following types, with varying chances of appearing depending

View file

@ -81,3 +81,4 @@ server bool swwm_simplefog = false; // simplified teleport fogs (useful to spee
user bool swwm_bigtags = false; // use a bigger font for targeter tags
user bool swwm_intermusic = false; // use original intermission music
server bool swwm_enemydrops = false; // allow enemies to drop ammo and weapons
server bool swwm_shotgib = true; // buckshot can gib (some people don't like this for some reason, so it's an option now)

View file

@ -86,7 +86,7 @@ SWWM_INTERTYPE = "Intermission Art";
SWWM_INTERDEF = "N/A";
SWWM_INTERART = "Fanart";
SWWM_INTER4KOMA = "4Koma";
SWWM_BALLUSE = "Lead Balls can activate switches";
SWWM_BALLUSE = "Lead Balls can Activate Switches";
SWWM_BOSSBAR = "Show Boss Healthbars";
SWWM_BTITLE = "Balance Options";
SWWM_BOSSENHANCE = "Enhance Vanilla Bosses";
@ -115,6 +115,9 @@ SWWM_YNYKRONALERT = "Cap Ynykron Alert";
SWWM_MENUPAUSE = "Pause on Demolitionist Menu";
SWWM_FTITLE = "Fun Options";
SWWM_FUNTAGS = "Monster Renaming";
SWWM_OMNIBUST = "Omni-Busting";
SWWM_SUPERFUEL = "Unlimited Fuel";
SWWM_PARTYTIME = "Super Fun Party Time";
SWWM_SIMPLEFOG = "Simplified Teleport Fog";
SWWM_BIGTAGS = "Use Large Font for Names";
SWWM_INTERMUSIC = "Use Original Intermission Music";
@ -123,6 +126,7 @@ SWWM_MAXGIBS = "Gib Limit";
SWWM_MAXCASINGS = "Casing Limit";
SWWM_MAXDEBRIS = "Debris Limit";
SWWM_ENEMYDROPS = "Enemies Drop Weapons and Ammo";
SWWM_SHOTGIB = "Buckshot can Gib";
TOOLTIP_SWWM_VOICETYPE = "Sets the voice pack for the player.";
TOOLTIP_SWWM_MUTEVOICE = "Control what gets muted, if you'd rather have a more silent protagonist.";
TOOLTIP_SWWM_FLASHSTRENGTH = "Screen flashes usually happen when firing some weapons, you can lower this if these effects are harmful for you.";
@ -179,6 +183,9 @@ TOOLTIP_SWWM_NOTRACK = "Completely disables combat tracking (responsible for hea
TOOLTIP_SWWM_YNYKRONALERT = "By default the Ynykron wakes all monsters in the map. This may sometimes cause issues (and would destroy your framerate with huge monstercounts).";
TOOLTIP_SWWM_MENUPAUSE = "In single player, the Demolitionist Menu by default will pause everything. You can disable this if you want a more Souls-like experience (or if you want to have a read while actively waiting for some looooooooong elevator or other timed event).";
TOOLTIP_SWWM_FUNTAGS = "Replaces the names of various vanilla monsters with funny alternatives.";
TOOLTIP_SWWM_OMNIBUST = "Allows any weapon to potentially bust walls.";
TOOLTIP_SWWM_SUPERFUEL = "Your fuel never runs out.";
TOOLTIP_SWWM_PARTYTIME = "Killed enemies shoot out a cloud of confetti.";
TOOLTIP_SWWM_SIMPLEFOG = "Replaces particle-based teleport fogs with simple sprites. Useful if they cause performance issues.";
TOOLTIP_SWWM_BIGTAGS = "By default name labels on healthbars are shown with a small, compact font. Enabling this will use a bigger one.";
TOOLTIP_SWWM_INTERMUSIC = "If enabled, intermission screens will use the original music from the current IWAD or map pack.";
@ -187,6 +194,7 @@ TOOLTIP_SWWM_MAXGIBS = "Caps the maximum amount of gibs. Surpassing this limit w
TOOLTIP_SWWM_MAXCASINGS = "Caps the maximum amount of casings and spent magazines. Surpassing this limit will cause the excess to fade out.";
TOOLTIP_SWWM_MAXDEBRIS = "Caps the maximum amount of rubble from explosions and others. Surpassing this limit will cause the excess to fade out.";
TOOLTIP_SWWM_ENEMYDROPS = "If enabled, enemies will drop weapons and ammo like they would in vanilla. This is not recommended as it easily breaks progression.";
TOOLTIP_SWWM_SHOTGIB = "Some people don't like this for some reason, so here it is as an option.";
// knowledge base
SWWM_COMINGSOON = "(coming soon)";
SWWM_MISSTAB = "Mission";

View file

@ -83,7 +83,7 @@ SWWM_REVIVECOOLDOWN = "Tiempo de recarga de Reinicio";
SWWM_UNLIMITED = "Ilimitado";
SWWM_NONE = "Ninguno";
SWWM_INTERTYPE = "Arte de Intermisión";
SWWM_BALLUSE = "Las Bolas de Plomo activan botones";
SWWM_BALLUSE = "Las Bolas de Plomo Activan Botones";
SWWM_BOSSBAR = "Mostrar Barras de Salud de Bosses";
SWWM_BTITLE = "Opciones de Balance";
SWWM_BOSSENHANCE = "Mejorar Bosses Vanilla";
@ -112,6 +112,9 @@ SWWM_YNYKRONALERT = "Limitar Alerta de Ynykron";
SWWM_MENUPAUSE = "Pausar en Menú de Demolicionista";
SWWM_FTITLE = "Opciones Divertidas";
SWWM_FUNTAGS = "Renombrar Monstruos";
SWWM_OMNIBUST = "Omni-Reventamiento";
SWWM_SUPERFUEL = "Combustible Ilimitado";
SWWM_PARTYTIME = "Modo Fiesta Tope";
SWWM_SIMPLEFOG = "Efecto de Teletransporte Simple"
SWWM_BIGTAGS = "Usar Fuente Grande para Nombres";
SWWM_INTERMUSIC = "Usar Música de Intermisión Original";
@ -120,6 +123,7 @@ SWWM_MAXGIBS = "Límite de Vísceras";
SWWM_MAXCASINGS = "Límite de Casquillos";
SWWM_MAXDEBRIS = "Límite de Escombros";
SWWM_ENEMYDROPS = "Enemigos Sueltan Armas y Munición";
SWWM_SHOTGIB = "Los Perdigones pueden Desviscerar";
TOOLTIP_SWWM_VOICETYPE = "Selecciona el pack de voz para el jugador.";
TOOLTIP_SWWM_MUTEVOICE = "Controla lo que se mutea, si prefieres tener un protagonista más silencioso.";
TOOLTIP_SWWM_FLASHSTRENGTH = "Los destellos en pantalla suelen ocurrir al disparar algunas armas, puedes reducirlo si este tipo de effectos te causan malestar.";
@ -176,6 +180,9 @@ TOOLTIP_SWWM_NOTRACK = "Desactiva completamente el rastreo de combate (responsab
TOOLTIP_SWWM_YNYKRONALERT = "Por defecto el Ynykron alerta a todos los monstruos en el mapa. Esto puede causar problemas a veces (o destruir tus frames con números enormes de monstruos).";
TOOLTIP_SWWM_MENUPAUSE = "En modo de un jugador, el Menú de Demolicionista por defecto paus a todo. Puedes desactivar esto si quieres una experiencia más Souls-like (o si quieres leer un poco mientras esperas activamente algun ascensor leeeeeeento o algún otro evento temporizado)."
TOOLTIP_SWWM_FUNTAGS = "Reemplaza los nombres de monstruos vanilla por alternativas graciosas.";
TOOLTIP_SWWM_OMNIBUST = "Permite que cualquier arma puede potencialmente reventar paredes.";
TOOLTIP_SWWM_SUPERFUEL = "Tu combustible no se agota nunca.";
TOOLTIP_SWWM_PARTYTIME = "Los enemigos expulsan una nube de confetti al morir.";
TOOLTIP_SWWM_SIMPLEFOG = "Reemplaza los efectos de teletransporte basados en partículas con simples sprites. Útil si causan problemas de rendimiento.";
TOOLTIP_SWWM_BIGTAGS = "Por defecto los nombres de las barras de vida usan una fuente pequeña. Activando esta opción, se cambiará por una mayor.";
TOOLTIP_SWWM_INTERMUSIC = "Al activar, las pantallas de intermisión usan la música original del IWAD o pack de mapas usado.";
@ -184,6 +191,7 @@ TOOLTIP_SWWM_MAXGIBS = "Limita la cantidad máxima de vísceras. Sobrepasar este
TOOLTIP_SWWM_MAXCASINGS = "Limita la cantidad máxima de casquillos y cargadores usados. Sobrepasar este límite causará que el exceso se desvanezca.";
TOOLTIP_SWWM_MAXDEBRIS = "Limita la cantidad máxima de escombros por explosiones y otros. Sobrepasar este límite causará que el exceso se desvanezca.";
TOOLTIP_SWWM_ENEMYDROPS = "Al activar, los enemigos soltarán armas y munición como harían en vanilla. Ésto no se recomienda ya que rompe fácilmente la progresión.";
TOOLTIP_SWWM_SHOTGIB = "Hay gente a la que no le gusta esto por alguna razón, así que aquí está como opción.";
// knowledge base
SWWM_COMINGSOON = "(próximamente)";
SWWM_MISSTAB = "Misión";

View file

@ -1,2 +1,2 @@
[default]
SWWM_MODVER="\chSWWM \cwGZ\c- r542 (Sun 13 Sep 10:14:01 CEST 2020)";
SWWM_MODVER="\chSWWM \cwGZ\c- r543 (Sun 13 Sep 14:39:24 CEST 2020)";

View file

@ -71,6 +71,9 @@ OptionMenu "SWWMOptionMenu"
StaticText " "
StaticText "$SWWM_FTITLE", "Gold"
Option "$SWWM_FUNTAGS", "swwm_funtags", "YesNo"
//Option "$SWWM_OMNIBUST", "swwm_omnibust", "YesNo"
//Option "$SWWM_SUPERFUEL", "swwm_superfuel", "YesNo"
//Option "$SWWM_PARTYTIME", "swwm_partytime", "YesNo"
StaticText " "
StaticText "$SWWM_BTITLE", "Gold"
Option "$SWWM_ENEMYDROPS", "swwm_enemydrops", "YesNo"
@ -84,6 +87,7 @@ OptionMenu "SWWMOptionMenu"
Option "$SWWM_NOTRACK", "swwm_notrack", "YesNo"
Option "$SWWM_YNYKRONALERT", "swwm_ynykronalert", "YesNo"
Option "$SWWM_SIMPLEFOG", "swwm_simplefog", "YesNo"
Option "$SWWM_SHOTGIB", "swwm_shotgib", "YesNo"
StaticText " "
StaticText "$SWWM_ITITLE", "Gold"
Option "$SWWM_ARMORUSE", "swwm_autousearmor", "YesNo"

View file

@ -656,6 +656,7 @@ Mixin Class HellblazerGrenade
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -668,6 +669,7 @@ Mixin Class HellblazerGrenade
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
@ -988,6 +990,7 @@ Class HellblazerRavagerArm : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -1000,6 +1003,7 @@ Class HellblazerRavagerArm : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;

View file

@ -161,7 +161,7 @@ Class mkBloodDrop : Actor
FCheckPosition tm;
// gravitational pull
vel.z -= GetGravity();
// movement subdivision (these damn things are tiny
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
@ -211,6 +211,7 @@ Class mkBloodDrop : Actor
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;

View file

@ -975,7 +975,7 @@ Class Wallbuster : SWWMWeapon
for ( int i=0; i<t.HitList.Size(); i++ )
{
int realdmg = dmg?dmg:t.HitList[i].HitDamage;
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large);
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large&&!swwm_shotgib);
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Wallbuster](0.4,1.2));
if ( t.HitList[i].HitActor.bNOBLOOD || t.HitList[i].HitActor.bINVULNERABLE )
{

View file

@ -81,7 +81,7 @@ Class PaletteLight : DynamicLight
}
}
// Generic particles
// Generic smoke, lightweight tick
Class SWWMSmoke : Actor
{
Default
@ -98,39 +98,108 @@ Class SWWMSmoke : Actor
+ROLLCENTER;
+THRUACTORS;
+NOTELEPORT;
+CANBOUNCEWATER;
-BOUNCEAUTOOFF;
BounceType "Hexen";
BounceFactor 1.0;
WallBounceFactor 1.0;
Scale 0.3;
+NOINTERACTION;
Scale .3;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
double ang, pt;
scale *= FRandom[Puff](0.5,1.5);
alpha *= FRandom[Puff](0.5,1.5);
scale *= FRandom[Puff](.5,1.5);
alpha *= FRandom[Puff](.5,1.5);
ang = FRandom[Puff](0,360);
pt = FRandom[Puff](-90,90);
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](0.2,0.8);
vel += (cos(pt)*cos(ang),cos(pt)*sin(ang),-sin(pt))*FRandom[Puff](.2,.8);
roll = Frandom[Puff](0,360);
scale.x *= RandomPick[Puff](-1,1);
scale.y *= RandomPick[Puff](-1,1);
}
override void Tick()
{
Super.Tick();
prev = pos; // for interpolation
if ( isFrozen() ) return;
vel *= 0.96;
vel.z += 0.01;
vel *= .96;
vel.z += .01;
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, slide along it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, slide along it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, slide along it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
if ( (waterlevel > 0) && !bAMBUSH )
{
let b = Spawn("SWWMBubble",pos);
b.scale *= abs(scale.x);
b.vel = vel;
Destroy();
return;
}
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
@ -142,7 +211,7 @@ Class SWWMSmoke : Actor
}
}
// ultra-lightweight non-interacting smoke, used by fire trails
// strictly non-interacting smoke, much lighter tick, used for heavier effects
Class SWWMHalfSmoke : Actor
{
Default
@ -175,6 +244,7 @@ Class SWWMHalfSmoke : Actor
}
override void Tick()
{
prev = pos; // for interpolation
if ( isFrozen() ) return;
vel *= 0.96;
vel.z += 0.01;
@ -208,7 +278,6 @@ Class SWWMSmallSmoke : SWWMHalfSmoke
{
override void PostBeginPlay()
{
Actor.PostBeginPlay();
double ang, pt;
scale *= FRandom[Puff](0.1,0.3);
alpha *= FRandom[Puff](0.5,1.5);
@ -228,13 +297,13 @@ Class SWWMSmallSmoke : SWWMHalfSmoke
}
}
Class SWWMViewSmoke : SWWMSmoke
// visual smoke, very strictly non-interacting, updates even when game is frozen
Class SWWMViewSmoke : SWWMHalfSmoke
{
Vector3 ofs, vvel;
override void PostBeginPlay()
{
Actor.PostBeginPlay();
double ang, pt;
scale *= FRandom[Puff](0.1,0.3);
alpha *= FRandom[Puff](0.5,1.5);
@ -245,7 +314,7 @@ Class SWWMViewSmoke : SWWMSmoke
override void Tick()
{
Actor.Tick();
prev = pos; // for interpolation
if ( !target || !target.player )
{
Destroy();
@ -255,12 +324,18 @@ Class SWWMViewSmoke : SWWMSmoke
[x, y, z] = swwm_CoordUtil.GetAxes(target.pitch,target.angle,target.roll);
Vector3 origin = level.Vec3Offset(target.Vec2OffsetZ(0,0,target.player.viewz),x*ofs.x+y*ofs.y+z*ofs.z);
SetOrigin(origin,true);
UpdateWaterLevel();
bInvisible = (players[consoleplayer].camera != target);
if ( isFrozen() ) return;
ofs += vvel;
vvel *= 0.96;
vvel.z += 0.01;
if ( (waterlevel > 0) && !bAMBUSH ) Destroy();
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
}
@ -276,11 +351,12 @@ Class SWWMBubble : Actor
+DONTSPLASH;
+FORCEXYBILLBOARD;
+NOTELEPORT;
+THRUACTORS;
+NOINTERACTION;
Scale 0.5;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
double ang, pt;
scale *= FRandom[Puff](0.5,1.5);
ang = FRandom[Puff](0,360);
@ -291,11 +367,85 @@ Class SWWMBubble : Actor
}
override void Tick()
{
Super.Tick();
prev = pos;
if ( isFrozen() ) return;
vel *= 0.96;
vel.z += 0.05;
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, slide along it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, slide along it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, slide along it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = vel-FRandom[Puff](1.,1.2)*normal*(vel dot normal);
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
UpdateWaterLevel();
if ( (waterlevel <= 0) || !Random[Puff](0,100) ) Destroy();
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
States
{
@ -307,6 +457,10 @@ Class SWWMBubble : Actor
Class SWWMSpark : Actor
{
bool dead;
Sector tracksector;
int trackplane;
Default
{
RenderStyle "Add";
@ -314,25 +468,143 @@ Class SWWMSpark : Actor
Height 2;
+NOBLOCKMAP;
+FORCEXYBILLBOARD;
+MISSILE;
+DROPOFF;
+THRUACTORS;
+NOTELEPORT;
+DONTSPLASH;
BounceType "Doom";
BounceFactor 0.4;
+NOINTERACTION;
Gravity 0.2;
Scale 0.05;
}
override void Tick()
{
Super.Tick();
prev = pos;
if ( isFrozen() ) return;
if ( dead )
{
// do nothing but follow floor movement
if ( tracksector )
{
double trackz;
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy);
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
if ( trackz != pos.z )
{
SetZ(trackz);
UpdateWaterLevel(false);
}
}
}
else
{
vel.z -= GetGravity();
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, bounce on it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = .4*(vel-2.*normal*(vel dot normal));
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, bounce on it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = .4*(vel-2.*normal*(vel dot normal));
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, bounce on it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = .4*(vel-2.*normal*(vel dot normal));
readjust = true;
}
CheckPortalTransition();
if ( readjust ) break; // movement changed, can't keep stepping
}
}
if ( (max(abs(vel.x),max(abs(vel.y),abs(vel.z))) < 1.) && (pos.z <= floorz) )
{
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
if ( ff )
{
tracksector = ff.model;
trackplane = 1;
}
else
{
tracksector = FloorSector;
trackplane = 0;
}
vel = (0,0,0);
dead = true;
SetStateLabel("Death");
return;
}
}
UpdateWaterLevel();
if ( waterlevel > 0 )
{
let b = Spawn("SWWMBubble",pos);
b.vel = vel;
b.scale *= 0.3;
Destroy();
return;
}
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
States
@ -351,15 +623,15 @@ Class SWWMChip : Actor
SWWMChip prevchip, nextchip;
bool killme;
double rollvel;
bool dead;
Sector tracksector;
int trackplane;
Default
{
Radius 2;
Height 2;
+NOBLOCKMAP;
+MISSILE;
+DROPOFF;
+MOVEWITHSECTOR;
+THRUACTORS;
+NOTELEPORT;
+DONTSPLASH;
@ -367,14 +639,12 @@ Class SWWMChip : Actor
+ROLLSPRITE;
+ROLLCENTER;
+FORCEXYBILLBOARD;
BounceType "Doom";
BounceFactor 0.3;
+NOINTERACTION;
Gravity 0.35;
Scale 0.2;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
rollvel = FRandom[Junk](10,30)*RandomPick[Junk](-1,1);
frame = Random[Junk](0,5);
scale *= Frandom[Junk](0.8,1.2);
@ -387,14 +657,135 @@ Class SWWMChip : Actor
}
override void Tick()
{
Super.Tick();
prev = pos; // for interpolation
if ( isFrozen() ) return;
if ( dead )
{
// do nothing but follow floor movement
if ( tracksector )
{
double trackz;
if ( trackplane ) trackz = tracksector.ceilingplane.ZAtPoint(pos.xy);
else trackz = tracksector.floorplane.ZAtPoint(pos.xy);
if ( trackz != pos.z )
{
SetZ(trackz);
UpdateWaterLevel(false);
}
}
}
else
{
vel.z -= GetGravity();
FCheckPosition tm;
// movement subdivision (these damn things are tiny)
int steps = 8;
while ( (abs(vel.x) >= radius*steps) || (abs(vel.y) >= radius*steps) || (abs(vel.z) >= height*steps) )
steps++;
bool domove = (vel!=(0,0,0));
if ( domove )
{
Vector3 steppy = vel/steps;
int changexy = steppy.X||steppy.Y;
bool readjust = false;
for ( int i=0; i<steps; i++ )
{
if ( changexy && !TryMove(Vec2Offset(steppy.x,steppy.y),1,false,tm) )
{
// hit wall, bounce on it
if ( BlockingLine )
{
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();;
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) )
normal *= -1;
vel = .3*(vel-2.*normal*(vel dot normal));
}
readjust = true;
}
AddZ(steppy.z);
UpdateWaterLevel();
if ( pos.z <= floorz )
{
// landed on floor, bounce on it
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.ceilingplane.Normal;
else normal = FloorSector.floorplane.Normal;
vel = .3*(vel-2.*normal*(vel dot normal));
readjust = true;
}
if ( pos.z+height > ceilingz )
{
// hit the ceiling, bounce on it
SetZ(ceilingz-height);
F3DFloor ff;
for ( int i=0; i<CeilingSector.Get3DFloorCount(); i++ )
{
if ( !(CeilingSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = CeilingSector.Get3DFloor(i);
break;
}
Vector3 normal;
if ( ff ) normal = -ff.model.floorplane.Normal;
else normal = CeilingSector.ceilingplane.Normal;
vel = .3*(vel-2.*normal*(vel dot normal));
readjust = true;
}
CheckPortalTransition();
if ( readjust )
{
SetStateLabel("Bounce");
break; // movement changed, can't keep stepping
}
}
}
if ( (max(abs(vel.x),max(abs(vel.y),abs(vel.z))) < 1.) && (pos.z <= floorz) )
{
SetZ(floorz);
F3DFloor ff;
for ( int i=0; i<FloorSector.Get3DFloorCount(); i++ )
{
if ( !(FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(FloorSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = FloorSector.Get3DFloor(i);
break;
}
if ( ff )
{
tracksector = ff.model;
trackplane = 1;
}
else
{
tracksector = FloorSector;
trackplane = 0;
}
vel = (0,0,0);
dead = true;
SetStateLabel("Death");
return;
}
}
if ( killme ) A_FadeOut(.01);
if ( waterlevel > 0 )
{
vel.xy *= .98;
vel *= .98;
rollvel *= .98;
}
if ( !CheckNoDelay() || (tics == -1) ) return;
if ( tics > 0 ) tics--;
while ( !tics )
{
if ( !SetState(CurState.NextState) )
return;
}
}
States
{
@ -619,7 +1010,7 @@ Class SmolInvisibleSplasher : InvisibleSplasher
{
Default
{
Mass 25;
Mass 10;
}
}
@ -690,7 +1081,7 @@ Class SWWMBulletTrail : LineTracer
}
}
// Elastic recoil from DT
// Elastic recoil from DT (unused)
Enum ESwingMode
{
SWING_Straight, // constant increment

View file

@ -152,6 +152,7 @@ Class EvisceratorChunk : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -164,6 +165,7 @@ Class EvisceratorChunk : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;

View file

@ -1235,7 +1235,28 @@ 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 == 'Clip') || (e.Replacee == 'GoldWandAmmo') || (e.Replacee == 'GoldWandHefty') )
e.Replacement = 'SWWMNothing';
{
switch( Random[Replacement](0,14) )
{
case 0:
case 1:
case 2:
e.Replacement = redpool[Random[Replacement](0,1)];
break;
case 4:
case 5:
case 6:
e.Replacement = greenpool[Random[Replacement](0,1)];
break;
case 7:
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,13) )

View file

@ -182,6 +182,7 @@ Class PusherProjectile : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -194,6 +195,7 @@ Class PusherProjectile : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;

View file

@ -1431,6 +1431,7 @@ Class CompanionLamp : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
normal = -BlockingFloor.Get3DFLoor(i).top.Normal;
break;
@ -1445,6 +1446,7 @@ Class CompanionLamp : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
normal = -BlockingCeiling.Get3DFloor(i).bottom.Normal;
break;

View file

@ -317,6 +317,7 @@ Class DragonBreathArm : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -329,6 +330,7 @@ Class DragonBreathArm : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
@ -1123,6 +1125,7 @@ Class FlamingChunk : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -1135,6 +1138,7 @@ Class FlamingChunk : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
@ -1428,6 +1432,7 @@ Class TheBall : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -1446,6 +1451,7 @@ Class TheBall : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;
@ -2056,7 +2062,7 @@ Class Spreadgun : SWWMWeapon
for ( int i=0; i<t.HitList.Size(); i++ )
{
int realdmg = dmg?dmg:t.HitList[i].HitDamage;
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large);
SWWMDamageAccumulator.Accumulate(t.HitList[i].HitActor,realdmg,invoker,self,'shot',!large&&!swwm_shotgib);
SWWMUtility.DoKnockback(t.HitList[i].HitActor,t.HitList[i].x+(0,0,0.025),mm*FRandom[Spreadgun](0.4,1.2));
if ( t.HitList[i].HitActor.bNOBLOOD || t.HitList[i].HitActor.bINVULNERABLE )
{

View file

@ -1696,6 +1696,7 @@ Class BiosparkCore : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
{
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
ff = BlockingFloor.Get3DFloor(i);
break;
@ -1708,6 +1709,7 @@ Class BiosparkCore : Actor
// find closest 3d floor for its normal
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
{
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
ff = BlockingCeiling.Get3DFloor(i);
break;

View file

@ -677,7 +677,7 @@ Class SilverBullet : SWWMWeapon
{
if ( !proneme ) Owner.A_StartSound("silverbullet/crouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);
proneme = true;
lookscale = .25;
lookscale = .4;
return;
}
if ( proneme ) Owner.A_StartSound("silverbullet/uncrouch",CHAN_WEAPONEXTRA,CHANF_OVERLAP);

View file

@ -848,24 +848,27 @@ Class SWWMCombatTracker : Thinker
if ( mytarget && mytarget.bDORMANT )
return;
// update
if ( mytarget && ((mytarget.pos != oldpos) || (mytarget.prev != oldprev)) )
if ( !mytarget || (mytarget.Health <= 0) )
{
// we're done
if ( updated > level.maptime ) updated = level.maptime;
lasthealth = 0;
prevpos = pos; // prevent stuttering
intp.Update(lasthealth);
if ( level.maptime > updated+35 ) Destroy();
return;
}
// only update height/position while alive
bool heightchanged = false;
if ( height != mytarget.height ) heightchanged = true;
height = mytarget.height;
if ( mytarget && (heightchanged || (mytarget.pos != oldpos) || (mytarget.prev != oldprev)) )
{
oldpos = mytarget.pos;
oldprev = mytarget.prev;
pos = level.Vec3Offset(mytarget.pos,(0,0,height));
prevpos = level.Vec3Offset(mytarget.prev,(0,0,height));
}
if ( !mytarget || (mytarget.Health <= 0) )
{
// we're done
if ( updated > level.maptime ) updated = level.maptime;
lasthealth = 0;
intp.Update(lasthealth);
if ( level.maptime > updated+35 ) Destroy();
return;
}
// only update height while alive
height = mytarget.height;
tcnt++;
if ( (tcnt == 1) && !mytarget.player )
{

View file

@ -224,6 +224,7 @@ Class SWWMUtility
F3DFloor ff;
for ( int i=0; i<a.FloorSector.Get3DFloorCount(); i++ )
{
if ( !(a.FloorSector.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
if ( !(a.FloorSector.Get3DFloor(i).top.ZAtPoint(a.pos.xy) ~== a.floorz) ) continue;
ff = a.FloorSector.Get3DFloor(i);
break;