327 lines
7.7 KiB
Text
327 lines
7.7 KiB
Text
// various stat tracking thinkers and others
|
|
|
|
// Korax instakill handler
|
|
Class UglyBoyGetsFuckedUp : Thinker
|
|
{
|
|
bool wedone;
|
|
|
|
override void Tick()
|
|
{
|
|
if ( wedone ) return;
|
|
if ( level.killed_monsters < level.total_monsters )
|
|
{
|
|
// stop portal door
|
|
int sidx = level.CreateSectorTagIterator(145).Next();
|
|
if ( sidx == -1 ) return;
|
|
Sector door = level.Sectors[sidx];
|
|
let ti = ThinkerIterator.Create("SectorEffect");
|
|
SectorEffect se;
|
|
while ( se = SectorEffect(ti.Next()) )
|
|
{
|
|
if ( se.GetSector() != door ) continue;
|
|
se.Destroy();
|
|
door.StopSoundSequence(CHAN_VOICE);
|
|
}
|
|
return;
|
|
}
|
|
wedone = true;
|
|
level.ExecuteSpecial(Door_Open,null,null,false,145,8);
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
// ensures a polyobj stays out of bounds FOREVER
|
|
Class SWWMBustedPolyobj : swwm_PolyobjectEffector
|
|
{
|
|
Actor whomstdve;
|
|
|
|
override void PolyTick()
|
|
{
|
|
if ( Polyobject.GetPos() == (32000,32000) ) return;
|
|
double dist = (Polyobject.GetPos()-(32000,32000)).length();
|
|
Level.ExecuteSpecial(Polyobj_Stop,whomstdve,Polyobject.StartLine,Line.Front,Polyobject.PolyobjectNum);
|
|
if ( Polyobject.Mirror ) Level.ExecuteSpecial(Polyobj_Stop,whomstdve,Polyobject.Mirror.StartLine,Line.Front,Polyobject.Mirror.PolyobjectNum);
|
|
Level.ExecuteSpecial(Polyobj_MoveTo,whomstdve,Polyobject.StartLine,Line.Front,Polyobject.PolyobjectNum,int(dist*8),32000,32000);
|
|
if ( Polyobject.Mirror ) Level.ExecuteSpecial(Polyobj_Stop,whomstdve,Polyobject.Mirror.StartLine,Line.Front,Polyobject.Mirror.PolyobjectNum);
|
|
}
|
|
}
|
|
|
|
// prevents floors/ceilings from ever moving again, as they're "broken crushers"
|
|
Class SWWMCrusherBroken : Thinker
|
|
{
|
|
Sector fsec, csec;
|
|
double diffh;
|
|
int fphase, cphase;
|
|
int ftics, ctics;
|
|
SectorEffect fse, cse; // pointers to zero-speed movers
|
|
|
|
static void Create( Sector f, Sector c, double diffh )
|
|
{
|
|
if ( !f && !c ) return;
|
|
let ti = ThinkerIterator.Create("SWWMCrusherBroken",STAT_USER);
|
|
SWWMCrusherBroken cb;
|
|
while ( cb = SWWMCrusherBroken(ti.Next()) )
|
|
{
|
|
if ( (cb.fsec == f) && (cb.csec == c) )
|
|
return; // we already have this
|
|
if ( cb.fsec && (cb.fsec == f) )
|
|
{
|
|
cb.Destroy(); // we override this one
|
|
continue;
|
|
}
|
|
if ( cb.csec && (cb.csec == c) )
|
|
{
|
|
cb.Destroy(); // we override this one
|
|
continue;
|
|
}
|
|
}
|
|
cb = new("SWWMCrusherBroken");
|
|
cb.fsec = f;
|
|
cb.csec = c;
|
|
cb.ChangeStatNum(STAT_USER);
|
|
cb.diffh = diffh;
|
|
if ( f && f.floordata ) f.floordata.Destroy();
|
|
if ( c && c.ceilingdata ) c.ceilingdata.Destroy();
|
|
}
|
|
|
|
static void Remove( Sector f, Sector c )
|
|
{
|
|
if ( !f && !c ) return;
|
|
let ti = ThinkerIterator.Create("SWWMCrusherBroken",STAT_USER);
|
|
SWWMCrusherBroken cb;
|
|
while ( cb = SWWMCrusherBroken(ti.Next()) )
|
|
{
|
|
if ( (cb.fsec == f) && (cb.csec == c) )
|
|
cb.Destroy(); // destroy entirely
|
|
else if ( f && (cb.fsec == f) )
|
|
cb.fsec = null; // only clear the floor
|
|
else if ( c && (cb.csec == c) )
|
|
cb.csec = null; // only clear the ceiling
|
|
}
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
if ( fsec )
|
|
{
|
|
if ( cphase <= 0 )
|
|
{
|
|
if ( level.CreateFloor(fsec,Floor.floorLowerByValue,null,16.,diffh*.4) )
|
|
{
|
|
ftics = int(diffh*.4/16.)+40;
|
|
fphase = 1;
|
|
}
|
|
}
|
|
else if ( fphase == 1 )
|
|
{
|
|
ftics--;
|
|
if ( (ftics <= 0) && level.CreateFloor(fsec,Floor.floorLowerByValue,null,1.,diffh*.6) )
|
|
{
|
|
ftics = int(diffh*.6)+8;
|
|
fphase = 2;
|
|
}
|
|
}
|
|
else if ( fphase == 2 )
|
|
{
|
|
ftics--;
|
|
if ( ftics <= 0 ) fphase = 3;
|
|
}
|
|
else if ( (fphase >= 3) && (!fse || (fsec.floordata != fse)) )
|
|
{
|
|
if ( fsec.floordata ) fsec.floordata.Destroy();
|
|
level.CreateFloor(fsec,Floor.floorLowerByValue,null,0.,1.);
|
|
fsec.StopSoundSequence(CHAN_WEAPON);
|
|
fse = fsec.floordata;
|
|
}
|
|
}
|
|
if ( csec )
|
|
{
|
|
if ( cphase <= 0 )
|
|
{
|
|
if ( level.CreateCeiling(csec,Ceiling.ceilRaiseByValue,null,16.,16.,diffh*.4) )
|
|
{
|
|
ctics = int(diffh*.4/16.)+40;
|
|
cphase = 1;
|
|
}
|
|
}
|
|
else if ( cphase == 1 )
|
|
{
|
|
ctics--;
|
|
if ( (ctics <= 0) && level.CreateCeiling(csec,Ceiling.ceilRaiseByValue,null,1.,1.,diffh*.6) )
|
|
{
|
|
ctics = int(diffh*.6)+10;
|
|
cphase = 2;
|
|
}
|
|
}
|
|
else if ( cphase == 2 )
|
|
{
|
|
ctics--;
|
|
if ( ctics <= 0 ) cphase = 3;
|
|
}
|
|
else if ( (cphase >= 3) && (!cse || (csec.ceilingdata != cse)) )
|
|
{
|
|
if ( csec.ceilingdata ) csec.ceilingdata.Destroy();
|
|
level.CreateCeiling(csec,Ceiling.ceilRaiseByValue,null,0.,0.,1.);
|
|
csec.StopSoundSequence(CHAN_VOICE);
|
|
cse = csec.ceilingdata;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// cache data for manual lockdefs parsing nonsense
|
|
Class LIEntry
|
|
{
|
|
int locknumber;
|
|
bool hascolor;
|
|
Color mapcolor;
|
|
}
|
|
|
|
Class SWWMCachedLockInfo : SWWMStaticThinker
|
|
{
|
|
Array<LIEntry> ent;
|
|
|
|
static clearscope bool IsValidLock( int l )
|
|
{
|
|
let ti = ThinkerIterator.Create("SWWMCachedLockInfo",STAT_STATIC);
|
|
SWWMCachedLockInfo cli = SWWMCachedLockInfo(ti.Next());
|
|
if ( !cli ) return false;
|
|
for ( int i=0; i<cli.ent.Size(); i++ )
|
|
{
|
|
if ( cli.ent[i].locknumber == l )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static clearscope Color GetLockColor( int l )
|
|
{
|
|
let ti = ThinkerIterator.Create("SWWMCachedLockInfo",STAT_STATIC);
|
|
SWWMCachedLockInfo cli = SWWMCachedLockInfo(ti.Next());
|
|
if ( !cli ) return 0;
|
|
for ( int i=0; i<cli.ent.Size(); i++ )
|
|
{
|
|
if ( (cli.ent[i].locknumber == l) && cli.ent[i].hascolor )
|
|
return cli.ent[i].mapcolor;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static SWWMCachedLockInfo GetInstance()
|
|
{
|
|
let ti = ThinkerIterator.Create("SWWMCachedLockInfo",STAT_STATIC);
|
|
SWWMCachedLockInfo cli = SWWMCachedLockInfo(ti.Next());
|
|
if ( cli ) return cli;
|
|
cli = new("SWWMCachedLockInfo");
|
|
cli.ChangeStatNum(STAT_STATIC);
|
|
return cli;
|
|
}
|
|
}
|
|
|
|
Class SWWMCorpseCleaner : Thinker
|
|
{
|
|
transient ThinkerIterator ti;
|
|
Array<Actor> toclean;
|
|
int nstep, i;
|
|
|
|
private bool CmpDist( Actor activator, Vector3 a, Vector3 b )
|
|
{
|
|
double dista = level.Vec3Diff(activator.pos,a).length();
|
|
double distb = level.Vec3Diff(activator.pos,b).length();
|
|
return (dista > distb);
|
|
}
|
|
|
|
private int partition_cleanup( Actor activator, Array<Actor> a, int l, int h )
|
|
{
|
|
Actor pv = a[h];
|
|
int i = (l-1);
|
|
for ( int j=l; j<=(h-1); j++ )
|
|
{
|
|
if ( CmpDist(activator,pv.pos,a[j].pos) )
|
|
{
|
|
i++;
|
|
Actor tmp = a[j];
|
|
a[j] = a[i];
|
|
a[i] = tmp;
|
|
}
|
|
}
|
|
Actor tmp = a[h];
|
|
a[h] = a[i+1];
|
|
a[i+1] = tmp;
|
|
return i+1;
|
|
}
|
|
private void qsort_cleanup( Actor activator, Array<Actor> a, int l, int h )
|
|
{
|
|
if ( l >= h ) return;
|
|
int p = partition_cleanup(activator,a,l,h);
|
|
qsort_cleanup(activator,a,l,p-1);
|
|
qsort_cleanup(activator,a,p+1,h);
|
|
}
|
|
|
|
void Init( Actor activator )
|
|
{
|
|
toclean.Clear();
|
|
let ti = ThinkerIterator.Create("Actor");
|
|
Actor a;
|
|
while ( a = Actor(ti.Next()) )
|
|
{
|
|
if ( !a.bKILLED || (a.tics != -1) ) continue;
|
|
toclean.Push(a);
|
|
}
|
|
if ( toclean.Size() <= 0 )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
nstep = max(1,toclean.Size()/100);
|
|
i = 0;
|
|
// sort by distance to activator (if any)
|
|
if ( !activator ) return;
|
|
qsort_cleanup(activator,toclean,0,toclean.Size()-1);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
for ( int j=0; j<nstep; j++ )
|
|
{
|
|
if ( i >= toclean.Size() )
|
|
{
|
|
Console.Printf("%d corpses cleaned.",toclean.Size());
|
|
Destroy();
|
|
return;
|
|
}
|
|
Actor a = toclean[i++];
|
|
if ( !a || !a.bKILLED || (a.tics != -1) ) continue;
|
|
let f = a.Spawn("SWWMItemFog",a.pos);
|
|
f.A_StartSound("bestsound",CHAN_ITEM);
|
|
a.Destroy();
|
|
}
|
|
}
|
|
}
|
|
|
|
Class OnelinerHistory
|
|
{
|
|
String type;
|
|
Array<int> lines;
|
|
}
|
|
|
|
Class SWWMGlobals : SWWMStaticThinker
|
|
{
|
|
// set so these messages only happen once
|
|
bool ccstartonce, cclilithonce;
|
|
|
|
// for oneliners
|
|
Array<OnelinerHistory> lastlines;
|
|
|
|
static play SWWMGlobals Get()
|
|
{
|
|
let ti = ThinkerIterator.Create("SWWMGlobals",STAT_STATIC);
|
|
SWWMGlobals g = SWWMGlobals(ti.Next());
|
|
if ( !g )
|
|
{
|
|
g = new("SWWMGlobals");
|
|
g.ChangeStatNum(STAT_STATIC);
|
|
}
|
|
return g;
|
|
}
|
|
}
|