Some spicing up of the Doom 2 secret maps.
More achievement icons.
This commit is contained in:
parent
98012daf26
commit
4d7cd9c564
190 changed files with 707 additions and 373 deletions
|
|
@ -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':
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
552
zscript/swwm_monsters.zsc
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 )
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue