Some spicing up of the Doom 2 secret maps.

More achievement icons.
This commit is contained in:
Mari the Deer 2021-04-09 20:57:49 +02:00
commit 4d7cd9c564
190 changed files with 707 additions and 373 deletions

View file

@ -21,6 +21,7 @@ Class SWWMLevelCompatibility : LevelPostProcessor
{
int ncellsa = 0, ncellsb = 0;
int nbackpack = 0;
bool wolfmap31 = false;
switch ( checksum )
{
case 'none':
@ -183,6 +184,58 @@ Class SWWMLevelCompatibility : LevelPostProcessor
nbackpack++;
}
break;
// Doom 2 MAP31
case '0BB515B79E0A6C42C4846C4E6F5F1D73':
case '3FF94E27423F91C1585B3396F0C03459':
case 'F2235342F1591B59154022E1DAF3EB2F':
case '3FF94E27423F91C1585B3396F0C03459':
wolfmap31 = true;
// Doom 2 MAP32
case '34A8DB0B341A32267CB461D8C219DF0A':
case 'AA4CA3FC891D13821ACCABD836E29EB5':
case '9AA7780B46EC4471F630572798943D71':
// sound sequence handling
for ( int i=0; i<level.Lines.Size(); i++ )
{
Line l = level.Lines[i];
if ( !l.backsector ) continue;
TextureID t;
bool wolfdoor = false;
for ( int k=0; k<3; k++ )
{
t = l.sidedef[0].GetTexture(k);
if ( t.IsValid() && ((TexMan.GetName(t) == "ZDOORF1") || (TexMan.GetName(t) == "ZDOORB1") || (TexMan.GetName(t) == "ZELDOOR")) )
{
wolfdoor = true;
break;
}
}
if ( !wolfdoor && l.sidedef[1] ) for ( int k=0; k<3; k++ )
{
t = l.sidedef[1].GetTexture(k);
if ( t.IsValid() && ((TexMan.GetName(t) == "ZDOORF1") || (TexMan.GetName(t) == "ZDOORB1") || (TexMan.GetName(t) == "ZELDOOR")) )
{
wolfdoor = true;
break;
}
}
if ( wolfdoor )
l.backsector.SeqName = 'DoorWolf3D';
else if ( (l.special == Door_Open) || (l.special == Door_Raise) )
l.backsector.SeqName = 'PushwallWolf3D';
}
// enemy replacements
for ( int i=0; i<GetThingCount(); i++ )
{
int ednum = GetThingEdNum(i);
if ( (ednum == 84) || (ednum == 3004) )
SetThingEdNum(i,wolfmap31?4206990:4206992); // guard / ss
else if ( ednum == 3002 )
SetThingEdNum(i,4206993); // dog
else if ( ednum == 16 )
SetThingEdNum(i,4206991); // hans grosse
}
break;
// Kinsie's Test Map
case '0EADB2F82732A968B8513E4DC6138439':
case 'D70250F93C6B6072DA39D9672B37F236':

View file

@ -186,7 +186,7 @@ extend Class SWWMHandler
SWWMUtility.AchievementProgressInc('swwm_progress_stomp',1,src.player);
else if ( e.DamageType == 'GroundPound' )
SWWMUtility.AchievementProgressInc('swwm_progress_thicc',1,src.player);
else if ( (e.DamageType == 'Love') && !(e.Thing is 'WolfensteinSS') )
else if ( (e.DamageType == 'Love') && !(e.Thing is 'WolfensteinSS') && (e.Thing.Species != 'WolfensteinSS') )
SWWMUtility.AchievementProgressInc('swwm_progress_love',1,src.player);
if ( e.Inflictor && e.Inflictor.FindInventory('ParriedBuff') )
SWWMUtility.AchievementProgressInc('swwm_progress_reflect',1,src.player);
@ -238,7 +238,7 @@ extend Class SWWMHandler
{
scr.xscore[ofs] = 0;
scr.xtcolor[ofs] = Font.FindFontColor('BlushPink');
scr.xstr[ofs] = StringTable.Localize((e.Thing is 'WolfensteinSS')?"$SWWM_LOVED_ALT":"$SWWM_LOVED");
scr.xstr[ofs] = StringTable.Localize(((e.Thing is 'WolfensteinSS')||(e.Thing.Species=='WolfensteinSS'))?"$SWWM_LOVED_ALT":"$SWWM_LOVED");
scr.xcnt = ++ofs;
}
}

View file

@ -294,7 +294,7 @@ Class GhostTarget : Actor
{
let t = bt.Thing;
if ( !t || !t.bIsMonster || t.player || !t.IsHostile(master) || (t.target != self) ) continue;
if ( SWWMUtility.BoxIntersect(self,t,pad:16) )
if ( SWWMUtility.BoxIntersect(self,t,pad:16) || t.CheckMeleeRange() )
{
// they found out, there's no one here
diedie = true;
@ -370,7 +370,11 @@ Class GhostPower : PowerInvisibility
continue;
}
if ( a.target != Owner ) continue;
if ( !gt ) gt = Spawn("GhostTarget",Owner.pos);
if ( !gt )
{
gt = Spawn("GhostTarget",Owner.pos);
if ( Owner.bFRIENDLY || Owner.player ) gt.bFRIENDLY = true;
}
a.target = gt;
a.LastHeard = gt;
gt.master = Owner;

View file

@ -25,367 +25,7 @@ const MaxBouncePerTic = 40; // maximum simultaneous bounces in one tic for a lig
// (somehow this hackaround doesn't break anything in devbuilds)
const SKILLP_SpawnMulti = SKILLP_PlayerRespawn+1;
// Future planning, will be filled out with AI stuff and whatnot someday
Class SWWMMonster : Actor abstract
{
// integrated fun tags
virtual clearscope String GetFunTag( String defstr = "" )
{
return GetTag(defstr);
}
// the function that should be overriden in subclasses
virtual int HandleLocationalDamage( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
{
return damage;
}
// locational damage support, akin to UE1, but hitlocation will be treated as a relative offset, to make things easier
// this one should be called directly by everything in this mod, when possible
int LocationalDamageMobj( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
{
damage = HandleLocationalDamage(inflictor,source,damage,mod,HitLocation,flags,angle);
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
}
// "estimated" locational damage for the vanilla DamageMobj
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
{
Vector3 guesspos = (0,0,Height/2.);
// use inflictor if available, as it may be a projectile or hitscan puff
// if damage comes from an item, use owner
// all of this could be done better (or implemented as an engine feature), but whatever
Actor whomst = inflictor?inflictor:source;
if ( whomst is 'Inventory' ) whomst = Inventory(whomst).Owner;
if ( whomst )
{
if ( whomst.bMISSILE || (flags&DMG_INFLICTOR_IS_PUFF) )
guesspos = level.Vec3Diff(pos,whomst.pos);
else guesspos = level.Vec3Diff(pos,whomst.Vec3Offset(0,0,whomst.Height/2));
guesspos.x = clamp(guesspos.x,-radius,radius);
guesspos.y = clamp(guesspos.y,-radius,radius);
guesspos.z = clamp(guesspos.z,0,height);
}
return LocationalDamageMobj(inflictor,source,damage,mod,guesspos,flags,angle);
}
}
// Less mean-spirited Keen
Class SWWMHangingKeen : Actor
{
action void A_DropKeen()
{
Spawn("SWWMDroppedKeen",Vec3Offset(0,0,8));
}
override bool Used( Actor user )
{
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
if ( Health > 0 )
{
DamageMobj(user,user,Health,'Untie',DMG_FORCED|DMG_THRUSTLESS);
return true;
}
return false;
}
Default
{
Tag "$FN_KEEN";
Health 100;
Radius 10;
Height 54;
Mass int.max;
PainChance 256;
+SOLID;
+SPAWNCEILING;
+NOGRAVITY;
+SHOOTABLE;
+NOICEDEATH;
+DONTFALL;
+NOBLOOD;
+DONTTHRUST;
}
States
{
Spawn:
KEE2 A -1;
Stop;
Death:
KEE2 A 6 A_StartSound("newkeen/hit");
KEE2 B 6 A_DropKeen();
KEE2 C 6;
KEE2 DE 6;
KEE2 F 30;
KEE2 F -1 A_KeenDie();
Stop;
Pain:
KEE2 G 4 A_StartSound("newkeen/hit");
KEE2 G 8;
Goto Spawn;
}
}
Class SWWMDroppedKeen : Actor
{
Default
{
Radius 10;
Height 32;
Gravity .5;
+NOBLOCKMAP;
}
States
{
Spawn:
KEE3 A 0 NoDelay
{
A_StartSound("newkeen/fall",volume:.5);
A_StartSound("newkeen/die",CHAN_VOICE);
}
KEE3 A 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 1
{
A_StartSound("newkeen/bounce");
vel.z = 4;
}
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 1
{
A_StartSound("newkeen/bounce",volume:.8);
vel.z = 2;
}
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 12 A_StartSound("newkeen/bounce",volume:.6);
TNT1 A 1 { Spawn("TeleportFog",pos,ALLOW_REPLACE); }
Stop;
}
}
Class SWWMBossBrainExpl : Actor
{
void A_Ignite()
{
A_QuakeEx(3,3,3,20,0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollintensity:2.);
A_StartSound("explodium/hit",CHAN_VOICE,CHANF_DEFAULT,.4,.5);
Scale *= FRandom[ExploS](0.8,1.1);
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
int numpt = Random[ExploS](8,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,4);
s.scale *= 2.8;
s.alpha *= .4;
}
numpt = Random[ExploS](5,10);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
numpt = int(Random[ExploS](-1,2)+special1);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("SWWMBossBrainExplArm",pos);
s.target = target;
}
}
Default
{
RenderStyle "Add";
Scale 2.5;
Radius .1;
Height 0.;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
+FORCEXYBILLBOARD;
}
States
{
Spawn:
TNT1 A 10;
TNT1 A 0 A_Ignite();
XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright;
Stop;
}
}
Class SWWMBossBrainExplArm : Actor
{
Default
{
PROJECTILE;
+THRUACTORS;
+BOUNCEONWALLS;
+BOUNCEONFLOORS;
+BOUNCEONCEILINGS;
-NOGRAVITY;
Gravity 0.35;
BounceFactor 1.0;
Radius 4;
Height 4;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
reactiontime = Random[ExploS](10,15);
double ang, pt;
ang = FRandom[ExploS](0,360);
pt = FRandom[ExploS](-90,90);
vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[ExploS](8.,20.);
}
States
{
Spawn:
TNT1 A 1
{
A_CountDown();
Spawn("ExplodiumMagTrail",pos);
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
let s = Spawn("SWWMHalfSmoke",pos);
s.vel = pvel+vel*.2;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,3);
s.scale *= 2.4;
s.alpha *= 0.1+.4*(ReactionTime/15.);
}
Wait;
}
}
Class SWWMBossBrainPain : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
}
States
{
Spawn:
MBRN B 1 Bright A_FadeOut(.05);
Wait;
}
}
Class SWWMBossBrain : BossBrain
{
bool eyeless;
int smallcooldown;
override void PostBeginPlay()
{
Super.PostBeginPlay();
let ti = ThinkerIterator.Create("BossEye");
if ( ti.Next() ) eyeless = false;
else eyeless = true;
if ( !eyeless )
{
// proper boss
bCOUNTKILL = true;
level.total_monsters++;
}
}
void SpawnBrainExpl( bool death = false )
{
if ( death )
{
// big explosions throughout
for ( int x=-350; x<=350; x+=10 )
{
let s = Spawn("SWWMBossBrainExpl",Vec2OffsetZ(x,-280,Random[BrainExplode](120,500)));
s.tics = Random[BrainExplode](5,120);
s.special1 = Random[BrainExplode](0,3);
}
return;
}
if ( level.maptime < smallcooldown ) return;
smallcooldown = level.maptime+10;
// small explosion on brain hole
for ( int x=-40; x<=40; x+=20 )
{
let s = Spawn("SWWMBossBrainExpl",Vec2OffsetZ(x,-280,Random[BrainExplode](380,420)));
s.tics = Random[BrainExplode](1,10);
s.scale *= .5;
}
}
// kill every single monster in the map, burn away spawn cubes, remove eyes
// just let players have their 100% kills in peace
void EverythingDies()
{
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a = Actor(ti.Next()) )
{
if ( a is 'BossEye' ) a.SetStateLabel("Null");
else if ( a is 'SpawnShot' )
{
a.Spawn("SpawnFire",a.pos,ALLOW_REPLACE);
a.SetStateLabel("Null");
}
else if ( (a.Health > 0) && (a.bBossSpawned || a.bCOUNTKILL) )
a.DamageMobj(self,self,a.Health,'EndMii',DMG_FORCED|DMG_THRUSTLESS);
}
}
Default
{
Tag "$FN_BOSSBRAIN";
Radius 20;
Height 40;
+NOBLOOD;
}
States
{
Spawn:
MBRN A -1;
Stop;
Pain:
MBRN A 10
{
A_StartSound("brain/pain",CHAN_VOICE,attenuation:ATTN_NONE);
A_QuakeEx(3,3,3,15,0,65535,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.3);
if ( !eyeless ) SpawnBrainExpl(false);
Spawn("SWWMBossBrainPain",pos);
}
Goto Spawn;
Death:
MBRN A 120
{
A_StartSound("brain/death",CHAN_VOICE,attenuation:ATTN_NONE);
A_QuakeEx(9,9,9,120,0,65535,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
if ( !eyeless )
{
SpawnBrainExpl(true);
EverythingDies();
}
Spawn("SWWMBossBrainPain",pos);
}
MBRN A -1 A_BrainDie();
Stop;
}
}
// basic "does nothing" actor, used to remove stuff in CheckReplacement
Class SWWMNothing : Actor
{
States

552
zscript/swwm_monsters.zsc Normal file
View file

@ -0,0 +1,552 @@
// enemies 'n stuff
// Future planning, will be filled out with AI stuff and whatnot someday
Class SWWMMonster : Actor abstract
{
// integrated fun tags
virtual clearscope String GetFunTag( String defstr = "" )
{
return GetTag(defstr);
}
// the function that should be overriden in subclasses
virtual int HandleLocationalDamage( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
{
return damage;
}
// locational damage support, akin to UE1, but hitlocation will be treated as a relative offset, to make things easier
// this one should be called directly by everything in this mod, when possible
int LocationalDamageMobj( Actor inflictor, Actor source, int damage, Name mod, Vector3 HitLocation, int flags = 0, double angle = 0 )
{
damage = HandleLocationalDamage(inflictor,source,damage,mod,HitLocation,flags,angle);
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
}
// "estimated" locational damage for the vanilla DamageMobj
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
{
Vector3 guesspos = (0,0,Height/2.);
// use inflictor if available, as it may be a projectile or hitscan puff
// if damage comes from an item, use owner
// all of this could be done better (or implemented as an engine feature), but whatever
Actor whomst = inflictor?inflictor:source;
if ( whomst is 'Inventory' ) whomst = Inventory(whomst).Owner;
if ( whomst )
{
if ( whomst.bMISSILE || (flags&DMG_INFLICTOR_IS_PUFF) )
guesspos = level.Vec3Diff(pos,whomst.pos);
else guesspos = level.Vec3Diff(pos,whomst.Vec3Offset(0,0,whomst.Height/2));
guesspos.x = clamp(guesspos.x,-radius,radius);
guesspos.y = clamp(guesspos.y,-radius,radius);
guesspos.z = clamp(guesspos.z,0,height);
}
return LocationalDamageMobj(inflictor,source,damage,mod,guesspos,flags,angle);
}
}
// Less mean-spirited Keen
Class SWWMHangingKeen : Actor
{
action void A_DropKeen()
{
Spawn("SWWMDroppedKeen",Vec3Offset(0,0,8));
}
override bool Used( Actor user )
{
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
if ( Health > 0 )
{
DamageMobj(user,user,Health,'Untie',DMG_FORCED|DMG_THRUSTLESS);
return true;
}
return false;
}
Default
{
Tag "$FN_KEEN";
Health 100;
Radius 10;
Height 54;
Mass int.max;
PainChance 256;
+SOLID;
+SPAWNCEILING;
+NOGRAVITY;
+SHOOTABLE;
+NOICEDEATH;
+DONTFALL;
+NOBLOOD;
+DONTTHRUST;
}
States
{
Spawn:
KEE2 A -1;
Stop;
Death:
KEE2 A 6 A_StartSound("newkeen/hit");
KEE2 B 6 A_DropKeen();
KEE2 C 6;
KEE2 DE 6;
KEE2 F 30;
KEE2 F -1 A_KeenDie();
Stop;
Pain:
KEE2 G 4 A_StartSound("newkeen/hit");
KEE2 G 8;
Goto Spawn;
}
}
Class SWWMDroppedKeen : Actor
{
Default
{
Radius 10;
Height 32;
Gravity .5;
+NOBLOCKMAP;
}
States
{
Spawn:
KEE3 A 0 NoDelay
{
A_StartSound("newkeen/fall",volume:.5);
A_StartSound("newkeen/die",CHAN_VOICE);
}
KEE3 A 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 1
{
A_StartSound("newkeen/bounce");
vel.z = 4;
}
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 1
{
A_StartSound("newkeen/bounce",volume:.8);
vel.z = 2;
}
KEE3 B 1 A_JumpIf(pos.z<=floorz,1);
Wait;
KEE3 B 12 A_StartSound("newkeen/bounce",volume:.6);
TNT1 A 1 { Spawn("TeleportFog",pos,ALLOW_REPLACE); }
Stop;
}
}
Class SWWMBossBrainExpl : Actor
{
void A_Ignite()
{
A_QuakeEx(3,3,3,20,0,400,"",QF_RELATIVE|QF_SCALEDOWN,falloff:300,rollintensity:2.);
A_StartSound("explodium/hit",CHAN_VOICE,CHANF_DEFAULT,.4,.5);
Scale *= FRandom[ExploS](0.8,1.1);
Scale.x *= RandomPick[ExploS](-1,1);
Scale.y *= RandomPick[ExploS](-1,1);
int numpt = Random[ExploS](8,16);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,6);
let s = Spawn("SWWMSmoke",pos);
s.vel = pvel;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,4);
s.scale *= 2.8;
s.alpha *= .4;
}
numpt = Random[ExploS](5,10);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,12);
let s = Spawn("SWWMSpark",pos);
s.vel = pvel;
}
numpt = Random[ExploS](10,15);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](2,24);
let s = Spawn("SWWMChip",pos);
s.vel = pvel;
}
numpt = int(Random[ExploS](-1,2)+special1);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("SWWMBossBrainExplArm",pos);
s.target = target;
}
}
Default
{
RenderStyle "Add";
Scale 2.5;
Radius .1;
Height 0.;
+NOGRAVITY;
+NOBLOCKMAP;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
+FORCEXYBILLBOARD;
}
States
{
Spawn:
TNT1 A 10;
TNT1 A 0 A_Ignite();
XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright;
Stop;
}
}
Class SWWMBossBrainExplArm : Actor
{
Default
{
PROJECTILE;
+THRUACTORS;
+BOUNCEONWALLS;
+BOUNCEONFLOORS;
+BOUNCEONCEILINGS;
-NOGRAVITY;
Gravity 0.35;
BounceFactor 1.0;
Radius 4;
Height 4;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
reactiontime = Random[ExploS](10,15);
double ang, pt;
ang = FRandom[ExploS](0,360);
pt = FRandom[ExploS](-90,90);
vel = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[ExploS](8.,20.);
}
States
{
Spawn:
TNT1 A 1
{
A_CountDown();
Spawn("ExplodiumMagTrail",pos);
Vector3 pvel = (FRandom[ExploS](-1,1),FRandom[ExploS](-1,1),FRandom[ExploS](-1,1)).unit()*FRandom[ExploS](1,5);
let s = Spawn("SWWMHalfSmoke",pos);
s.vel = pvel+vel*.2;
s.SetShade(Color(1,1,1)*Random[ExploS](64,224));
s.special1 = Random[ExploS](1,3);
s.scale *= 2.4;
s.alpha *= 0.1+.4*(ReactionTime/15.);
}
Wait;
}
}
Class SWWMBossBrainPain : Actor
{
Default
{
RenderStyle "Add";
Radius .1;
Height 0.;
}
States
{
Spawn:
MBRN B 1 Bright A_FadeOut(.05);
Wait;
}
}
Class SWWMBossBrain : BossBrain
{
bool eyeless;
int smallcooldown;
override void PostBeginPlay()
{
Super.PostBeginPlay();
let ti = ThinkerIterator.Create("BossEye");
if ( ti.Next() ) eyeless = false;
else eyeless = true;
if ( !eyeless )
{
// proper boss
bCOUNTKILL = true;
level.total_monsters++;
}
}
void SpawnBrainExpl( bool death = false )
{
if ( death )
{
// big explosions throughout
for ( int x=-350; x<=350; x+=10 )
{
let s = Spawn("SWWMBossBrainExpl",Vec2OffsetZ(x,-280,Random[BrainExplode](120,500)));
s.tics = Random[BrainExplode](5,120);
s.special1 = Random[BrainExplode](0,3);
}
return;
}
if ( level.maptime < smallcooldown ) return;
smallcooldown = level.maptime+10;
// small explosion on brain hole
for ( int x=-40; x<=40; x+=20 )
{
let s = Spawn("SWWMBossBrainExpl",Vec2OffsetZ(x,-280,Random[BrainExplode](380,420)));
s.tics = Random[BrainExplode](1,10);
s.scale *= .5;
}
}
// kill every single monster in the map, burn away spawn cubes, remove eyes
// just let players have their 100% kills in peace
void EverythingDies()
{
let ti = ThinkerIterator.Create("Actor");
Actor a;
while ( a = Actor(ti.Next()) )
{
if ( a is 'BossEye' ) a.SetStateLabel("Null");
else if ( a is 'SpawnShot' )
{
a.Spawn("SpawnFire",a.pos,ALLOW_REPLACE);
a.SetStateLabel("Null");
}
else if ( (a.Health > 0) && (a.bBossSpawned || a.bCOUNTKILL) )
a.DamageMobj(self,self,a.Health,'EndMii',DMG_FORCED|DMG_THRUSTLESS);
}
}
Default
{
Tag "$FN_BOSSBRAIN";
Radius 20;
Height 40;
+NOBLOOD;
}
States
{
Spawn:
MBRN A -1;
Stop;
Pain:
MBRN A 10
{
A_StartSound("brain/pain",CHAN_VOICE,attenuation:ATTN_NONE);
A_QuakeEx(3,3,3,15,0,65535,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.3);
if ( !eyeless ) SpawnBrainExpl(false);
Spawn("SWWMBossBrainPain",pos);
}
Goto Spawn;
Death:
MBRN A 120
{
A_StartSound("brain/death",CHAN_VOICE,attenuation:ATTN_NONE);
A_QuakeEx(9,9,9,120,0,65535,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
if ( !eyeless )
{
SpawnBrainExpl(true);
EverythingDies();
}
Spawn("SWWMBossBrainPain",pos);
}
MBRN A -1 A_BrainDie();
Stop;
}
}
// MAP31/MAP32 wolfenstein enemies (rough DOS replication)
Class SWWMGuard : Actor
{
Default
{
Scale 2;
Health 20;
Radius 40;
Height 112;
Speed 12;
PainChance 170;
Monster;
+FLOORCLIP;
SeeSound "wolf3d/guardsight";
DeathSound "wolf3d/guarddie";
AttackSound "wolf3d/guardfire";
Obituary "$OB_WOLFGUARD";
Tag "$FN_WOLFGUARD";
Species "WolfensteinSS";
DropItem "Clip";
}
States
{
Spawn:
XGRD A 5 A_Look;
Wait;
See:
XGRD BBCCDDEE 2 A_Chase;
Loop;
Missile:
XGRD FG 8 A_FaceTarget;
XGRD H 0 A_StartSound(AttackSound,CHAN_WEAPON);
XGRD H 8 Bright A_CustomBulletAttack(22.5,0,1,Random[PosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
Goto See;
Pain:
XGRD I 0 A_JumpIf(Health&1,2);
XGRD I 2 A_Pain();
Goto See;
XGRD J 2 A_Pain();
Goto See;
Death:
XGRD K 5;
XGRD L 5 A_Scream();
XGRD M 5 A_NoBlocking();
XGRD N -1;
Stop;
}
}
Class SWWMSS : Actor
{
Default
{
Scale 2;
Health 50;
Radius 40;
Height 112;
Speed 12;
PainChance 170;
Monster;
+FLOORCLIP;
SeeSound "wolf3d/sssight";
DeathSound "wolf3d/ssdie";
AttackSound "wolf3d/ssfire";
Obituary "$OB_WOLFSS";
Tag "$FN_WOLFSS";
Species "WolfensteinSS";
DropItem "Clip";
}
States
{
Spawn:
XSSW W 5 A_Look;
Wait;
See:
XSSW AABBCCDD 2 A_Chase;
Loop;
Missile:
XSSW EF 5 A_FaceTarget();
XSSW G 0 A_StartSound(AttackSound,CHAN_WEAPON);
XSSW G 2 Bright A_CustomBulletAttack(22.5,0,1,Random[CPosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
XSSW F 3 A_FaceTarget();
XSSW G 2 Bright A_CustomBulletAttack(22.5,0,1,Random[CPosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
XSSW F 3 A_FaceTarget();
XSSW G 2 Bright A_CustomBulletAttack(22.5,0,1,Random[CPosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
XSSW F 3 A_FaceTarget();
XSSW G 2 Bright A_CustomBulletAttack(22.5,0,1,Random[CPosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
Goto See;
Pain:
XSSW H 0 A_JumpIf(Health&1,2);
XSSW H 2 A_Pain();
Goto See;
XSSW I 2 A_Pain();
Goto See;
Death:
XSSW J 5;
XSSW K 5 A_Scream();
XSSW L 5 A_NoBlocking();
XSSW M -1;
Stop;
}
}
Class SWWMHans : Actor
{
Default
{
Scale 2;
Health 1200;
Radius 40;
Height 112;
Mass 1000;
Speed 12;
Monster;
MinMissileChance 160;
+BOSS;
+MISSILEMORE;
+FLOORCLIP;
+NORADIUSDMG;
+DONTMORPH;
+LOOKALLAROUND;
AttackSound "wolf3d/hansfire";
DeathSound "wolf3d/hansdie";
SeeSound "wolf3d/hanssight";
Obituary "$OB_WOLFHANS";
Tag "$FN_WOLFHANS";
Species "WolfensteinSS";
}
States
{
Spawn:
XHNS A 5 A_Look();
Wait;
See:
XHNS AABBCCDD 2 A_Chase();
Loop;
Missile:
XHNS E 8 A_FaceTarget();
XHNS F 4 A_FaceTarget();
XHNS G 0 A_StartSound(AttackSound,CHAN_WEAPON);
XHNS GFGFGE 3 Bright A_CustomBulletAttack(22.5,0,3,Random[CPosAttack](1,5)*3,flags:CBAF_NORANDOM,spawnheight:64);
Goto See;
Death:
XHNS H 10;
XHNS I 10 A_Scream();
XHNS J 10 A_NoBlocking();
XHNS K -1;
Stop;
}
}
Class SWWMDog : Actor
{
Default
{
Scale 2;
Health 1;
Speed 12;
Radius 24;
Height 56;
Mass 100;
Monster;
AttackSound "wolf3d/dogbite";
DeathSound "wolf3d/dogdie";
SeeSound "wolf3d/dogsight";
Obituary "$OB_DOG";
Tag "$FN_DOG";
}
States
{
Spawn:
XDOG A 5 A_Look();
Wait;
See:
XDOG AABBCCDD 2 A_Chase();
Loop;
Melee:
XDOG EF 5 A_FaceTarget();
XDOG G 5 A_SargAttack();
XDOG EA 5;
Goto See;
Death:
XDOG H 5;
XDOG I 5 A_Scream();
XDOG J 5 A_NoBlocking();
XDOG K -1;
Stop;
}
}

View file

@ -526,7 +526,8 @@ Class Demolitionist : PlayerPawn
TextureID replacewith;
[remove, replacewith] = SWWMUtility.DefaceTexture(d.HitTexture);
if ( !remove ) return;
player.usedown = true;
if ( (d.HitType != TRACE_HitWall) || !d.HitLine.special || !(d.HitLine.activation&SPAC_Use) )
player.usedown = true;
A_StartSound("bestsound",CHAN_ITEMEXTRA,CHANF_OVERLAP);
lastbump *= .97;
if ( d.HitType == TRACE_HitWall )

View file

@ -854,14 +854,22 @@ Class SWWMUtility
basetag = "BOSSBRAIN";
break;
case 'WolfensteinSS':
case 'SWWMSS':
basetag = "WOLFSS";
break;
case 'SWWMHangingKeen':
basetag = "KEEN";
break;
case 'MBFHelperDog':
case 'SWWMDog':
basetag = "DOG";
break;
case 'SWWMGuard':
basetag = "WOLFGUARD";
break;
case 'SWWMHans':
basetag = "WOLFHANS";
break;
// Heretic
case 'Chicken':
basetag = "CHICKEN";
@ -1144,9 +1152,9 @@ Class SWWMUtility
static clearscope bool IdentifyingDog( Actor a )
{
if ( a is 'MBFHelperDog' ) return true;
// reminder that mark is a terrible person
if ( a.GetClassName() == 'GermanDog' ) return true;
if ( a.GetClassName() == '64HellHound' ) return true;
if ( a is 'SWWMDog' ) return true;
if ( a.GetClassName() == 'GermanDog' ) return true; // brote dote
if ( a.GetClassName() == '64HellHound' ) return true; // brote dote 64
if ( a.GetClassName() == 'AbyssDemon2' ) return true; // CH
if ( a.GetClassName() == 'WHOLETTHEDOGSOUT' ) return true; // CH
// more dogs will be added as found