swwmgz_m/zscript/swwm_thinkers.zsc

318 lines
7.5 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 SWWMGlobals : SWWMStaticThinker
{
// set so these messages only happen once
bool ccstartonce, cclilithonce;
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;
}
}