Remove 2x speed mult from hardest skill(s) (causes glitches). Allow moths to still attack while following the lamp. (Still do not know what causes moths to print "asin domain error" to terminal).
354 lines
12 KiB
Text
354 lines
12 KiB
Text
// playerthink / deaththink
|
|
extend Class Demolitionist
|
|
{
|
|
void CheckDefaceTexture()
|
|
{
|
|
if ( player.usedown )
|
|
return;
|
|
FLineTraceData d;
|
|
LineTrace(angle,DEFMELEERANGE*2,pitch,TRF_THRUACTORS,player.viewheight,data:d);
|
|
if ( d.HitType == TRACE_HitNone ) return;
|
|
let [remove, replacewith] = SWWMUtility.DefaceTexture(d.HitTexture);
|
|
if ( !remove ) return;
|
|
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;
|
|
int scr = (TexMan.GetName(d.HitTexture).Left(6)~=="ZZWOLF")?200:20;
|
|
if ( scr == 20 ) SWWMUtility.AchievementProgressInc("doodle",1,player);
|
|
SWWMCredits.Give(player,scr);
|
|
if ( player == players[consoleplayer] ) SWWMScoreObj.Spawn(scr,d.HitLocation);
|
|
if ( d.HitType == TRACE_HitWall )
|
|
{
|
|
if ( d.Hit3DFloor )
|
|
{
|
|
// TODO connected textures for upper/lower
|
|
if ( d.Hit3DFloor.flags&F3DFloor.FF_UPPERTEXTURE ) d.HitLine.sidedef[d.LineSide].SetTexture(0,replacewith);
|
|
else if ( d.Hit3DFloor.flags&F3DFloor.FF_LOWERTEXTURE ) d.HitLine.sidedef[d.LineSide].SetTexture(2,replacewith);
|
|
else d.Hit3DFloor.master.sidedef[0].SetTexture(1,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sidedefs with the same texture
|
|
Array<Line> con;
|
|
con.Clear();
|
|
con.Push(d.HitLine);
|
|
Sector s = d.LineSide?d.HitLine.backsector:d.HitLine.frontsector;
|
|
int found = 0;
|
|
do
|
|
{
|
|
found = 0;
|
|
foreach ( l:s.Lines )
|
|
{
|
|
if ( !l.sidedef[d.LineSide] || (l.sidedef[d.LineSide].GetTexture(d.LinePart) != d.HitTexture) )
|
|
continue;
|
|
if ( con.Find(l) < con.Size() ) continue;
|
|
bool notmatched = true;
|
|
foreach ( c:con )
|
|
{
|
|
if ( (l.v1 != c.v1) && (l.v2 != c.v2) && (l.v1 != c.v2) && (l.v2 != c.v1) )
|
|
continue;
|
|
notmatched = false;
|
|
break;
|
|
}
|
|
if ( notmatched ) continue;
|
|
con.Push(l);
|
|
found++;
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
foreach ( c:con )
|
|
c.sidedef[d.LineSide].SetTexture(d.LinePart,replacewith);
|
|
}
|
|
}
|
|
else if ( d.HitType == TRACE_HitCeiling )
|
|
{
|
|
if ( d.Hit3DFloor )
|
|
{
|
|
if ( d.Hit3DFloor.flags&F3DFloor.FF_INVERTSECTOR ) d.Hit3DFloor.model.SetTexture(1,replacewith);
|
|
else d.Hit3DFloor.model.SetTexture(0,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sectors with the same ceiling texture (THIS IS VERY UGLY CODE)
|
|
Array<Sector> con;
|
|
con.Clear();
|
|
con.Push(d.HitSector);
|
|
int found;
|
|
do
|
|
{
|
|
found = 0;
|
|
foreach ( s:con )
|
|
{
|
|
foreach ( l:s.Lines )
|
|
{
|
|
// only check two-sided
|
|
if ( !l.sidedef[1] ) continue;
|
|
// don't check if there's a height difference
|
|
if ( (l.frontsector.ceilingplane.ZAtPoint(l.v1.p) != l.backsector.ceilingplane.ZAtPoint(l.v1.p))
|
|
|| (l.frontsector.ceilingplane.ZAtPoint(l.v2.p) != l.backsector.ceilingplane.ZAtPoint(l.v2.p)) )
|
|
continue;
|
|
if ( (l.frontsector.GetTexture(1) == d.HitTexture) && (con.Find(l.frontsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.frontsector);
|
|
}
|
|
if ( (l.backsector.GetTexture(1) == d.HitTexture) && (con.Find(l.backsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.backsector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
foreach ( s:con )
|
|
s.SetTexture(1,replacewith);
|
|
}
|
|
}
|
|
else if ( d.HitType == TRACE_HitFloor )
|
|
{
|
|
if ( d.Hit3DFloor )
|
|
{
|
|
if ( d.Hit3DFloor.flags&F3DFloor.FF_INVERTSECTOR ) d.Hit3DFloor.model.SetTexture(0,replacewith);
|
|
else d.Hit3DFloor.model.SetTexture(1,replacewith);
|
|
}
|
|
else
|
|
{
|
|
// find connected sectors with the same floor texture (THIS IS VERY UGLY CODE)
|
|
Array<Sector> con;
|
|
con.Clear();
|
|
con.Push(d.HitSector);
|
|
int found;
|
|
do
|
|
{
|
|
found = 0;
|
|
foreach ( s:con )
|
|
{
|
|
foreach ( l:s.Lines )
|
|
{
|
|
// only check two-sided
|
|
if ( !l.sidedef[1] ) continue;
|
|
// don't check if there's a height difference
|
|
if ( (l.frontsector.floorplane.ZAtPoint(l.v1.p) != l.backsector.floorplane.ZAtPoint(l.v1.p))
|
|
|| (l.frontsector.floorplane.ZAtPoint(l.v2.p) != l.backsector.floorplane.ZAtPoint(l.v2.p)) )
|
|
continue;
|
|
if ( (l.frontsector.GetTexture(0) == d.HitTexture) && (con.Find(l.frontsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.frontsector);
|
|
}
|
|
if ( (l.backsector.GetTexture(0) == d.HitTexture) && (con.Find(l.backsector) >= con.Size()) )
|
|
{
|
|
found++;
|
|
con.Push(l.backsector);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
while ( found > 0 );
|
|
foreach ( s:con )
|
|
s.SetTexture(0,replacewith);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CheckItemUsePickup()
|
|
{
|
|
if ( player.usedown )
|
|
return;
|
|
if ( !itrace ) itrace = new("SWWMItemTracer");
|
|
Vector3 dir;
|
|
let [x, y, z] = SWWMUtility.GetPlayerAxes(self);
|
|
Vector3 origin = SWWMUtility.GetPlayerEye(self);
|
|
Sector os = level.PointInSector(origin.xy);
|
|
int rings = 1;
|
|
Array<Actor> ignoreme;
|
|
ignoreme.Clear();
|
|
for ( double i=0; i<.2; i+=.02 )
|
|
{
|
|
for ( int j=0; j<360; j+=(360/rings) )
|
|
{
|
|
dir = SWWMUtility.ConeSpread(x,y,z,j,i);
|
|
itrace.Trace(origin,os,dir,UseRange,0,ignore:self);
|
|
if ( itrace.Results.HitType != TRACE_HitActor ) continue;
|
|
if ( ignoreme.Find(itrace.Results.HitActor) < ignoreme.Size() ) continue;
|
|
player.usedown = true; // we found an item, ignore further uses
|
|
if ( itrace.Results.HitActor.Used(self) ) return;
|
|
ignoreme.Push(itrace.Results.HitActor);
|
|
}
|
|
rings += 2;
|
|
}
|
|
}
|
|
|
|
bool CheckMirrorUse()
|
|
{
|
|
if ( !mtrace ) mtrace = new("SWWMMirrorTracer");
|
|
Vector3 dir = SWWMUtility.GetPlayerAimDir(self);
|
|
Vector3 origin = SWWMUtility.GetPlayerEye(self);
|
|
mtrace.Trace(origin,level.PointInSector(origin.xy),dir,UseRange,0,ignoreallactors:true);
|
|
if ( mtrace.Results.HitType != TRACE_HitWall ) return false;
|
|
// there's a mirror here
|
|
if ( (gametic > mirrorcooldown) && (swwm_mutevoice < 2) )
|
|
mirrorcooldown = SWWMHandler.AddOneliner("mirror",2,10)+70;
|
|
// mute fail use
|
|
A_StopSound(CHAN_VOICE);
|
|
return true;
|
|
}
|
|
|
|
override void PlayerThink()
|
|
{
|
|
oldangles = (angle,pitch,roll);
|
|
if ( player && (player.mo == self) && (player.playerstate != PST_DEAD) && (player.cmd.buttons&BT_USE) )
|
|
{
|
|
if ( !player.usedown ) lastuse = gametic;
|
|
CheckDefaceTexture();
|
|
if ( !player.usedown && froggy )
|
|
player.usedown = froggy.Used(self);
|
|
// try to "use" the item closest to the crosshair
|
|
CheckItemUsePickup();
|
|
}
|
|
Super.PlayerThink();
|
|
if ( (gametic == lastuse) && IsActorPlayingSound(CHAN_VOICE,"*usefail") && !CheckMirrorUse() ) // don't play fail use if we're checking out a mirror
|
|
{
|
|
failcounter++;
|
|
if ( (failcounter > 8) && !Random[DemoLines](0,max(0,12-failcounter/3)) && (gametic > failcooldown) && (swwm_mutevoice < 2) )
|
|
{
|
|
failcooldown = SWWMHandler.AddOneliner("usefail",2,20);
|
|
failcounter = max(4,failcounter-10);
|
|
}
|
|
else if ( (failcounter > 2) && Random[DemoLines](0,1) && (gametic > failcooldown) && (swwm_mutevoice < 4) )
|
|
{
|
|
String myvoice = CVar.GetCVar('swwm_voicetype',player).GetString();
|
|
int loudlv = swwm_voiceamp;
|
|
int maxusegrunt = StringTable.Localize("$SWWM_"..myvoice.."_NUSEGRUNT").ToInt();
|
|
int idx = (maxusegrunt<=1)?1:Random[DemoLines](1,maxusegrunt);
|
|
A_StartSound(String.Format("voice/%s/usegrunt",myvoice,idx),CHAN_DEMOVOICE,CHANF_OVERLAP);
|
|
if ( loudlv > 1 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice,idx),CHAN_DEMOVOICEAUX,CHANF_OVERLAP);
|
|
if ( loudlv > 2 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice,idx),CHAN_DEMOVOICEAUX2,CHANF_OVERLAP);
|
|
if ( loudlv > 3 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice,idx),CHAN_DEMOVOICEAUX3,CHANF_OVERLAP);
|
|
failcooldown = int(S_GetLength(String.Format("voice/%s/usegrunt",myvoice,idx))*GameTicRate);
|
|
failcounter = max(2,failcounter-1);
|
|
}
|
|
}
|
|
else if ( gametic > lastuse+50 ) failcounter = 0;
|
|
oldlagangles = lagangles;
|
|
lagangles = lagangles*.8+(angle,pitch,roll)*.2;
|
|
oldlagdangles = lagdangles;
|
|
lagdangles = lagdangles*.8+(deltaangle(oldangles.x,angle),deltaangle(oldangles.y,pitch),deltaangle(oldangles.z,roll))*.2;
|
|
if ( !player || (player.mo != self) ) return;
|
|
if ( (player.playerstate != PST_DEAD) && (player.jumptics != 0) )
|
|
{
|
|
// faster falloff
|
|
player.jumptics -= 5;
|
|
if ( player.onground && (player.jumptics < -18) )
|
|
player.jumptics = 0;
|
|
}
|
|
if ( (player.playerstate != PST_DEAD) && !ReactionTime )
|
|
{
|
|
// quick grenade
|
|
if ( player.cmd.buttons&BT_USER4 )
|
|
SWWMGesture.SetGesture(self,GS_Grenade);
|
|
// emergency melee with no weapon
|
|
else if ( !player.ReadyWeapon && (player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK|BT_USER1)) )
|
|
SWWMGesture.SetGesture(self,GS_EmptyMelee);
|
|
}
|
|
}
|
|
|
|
override void DeathThink()
|
|
{
|
|
oldangles = (angle,pitch,roll);
|
|
player.Uncrouch();
|
|
TickPSprites();
|
|
player.onground = (pos.Z<=floorz);
|
|
// ded (demo-chan falls faster tho)
|
|
player.deltaviewheight = 0;
|
|
if ( player.viewheight > 6 ) player.viewheight -= 3;
|
|
if ( player.viewheight < 6 ) player.viewheight = 6;
|
|
// center pitch
|
|
double dpitch = clamp(deltaangle(pitch,0),-6,6);
|
|
if ( abs(dpitch) < 3. ) pitch = 0.;
|
|
else A_SetPitch(pitch+dpitch,SPF_INTERPOLATE);
|
|
// add roll
|
|
double droll = clamp(deltaangle(roll,50)*.5,-5,5);
|
|
if ( abs(droll) < 2. ) roll = 50.;
|
|
else A_SetRoll(roll+droll,SPF_INTERPOLATE);
|
|
// bob interpolation still active
|
|
oldlagangles = lagangles;
|
|
lagangles = lagangles*.8+(angle,pitch,roll)*.2;
|
|
oldlagdangles = lagdangles;
|
|
lagdangles = lagdangles*.8+(deltaangle(oldangles.x,angle),deltaangle(oldangles.y,pitch),deltaangle(oldangles.z,roll))*.2;
|
|
player.mo.CalcHeight();
|
|
if ( player.damagecount ) player.damagecount--;
|
|
if ( player.poisoncount ) player.poisoncount--;
|
|
// solid unless we can respawn, for safety
|
|
if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) )
|
|
bSolid = false;
|
|
else bSolid = true;
|
|
if ( player.viewheight <= 6 )
|
|
{
|
|
deadtimer++;
|
|
if ( (deadtimer == 60) && (player == players[consoleplayer]) )
|
|
A_StartSound("demolitionist/youdied",CHAN_DEMOVOICE,CHANF_OVERLAP|CHANF_UI);
|
|
if ( !hnd ) hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) )
|
|
{
|
|
// standard behaviour, respawn normally
|
|
if ( (((player.cmd.buttons&BT_USE) || ((deathmatch || alwaysapplydmflags) && sv_forcerespawn)) && !sv_norespawn)
|
|
&& ((Level.maptime >= player.respawn_time) || ((player.cmd.buttons&BT_USE) && !player.Bot)) )
|
|
{
|
|
player.cls = null;
|
|
player.playerstate = PST_REBORN;
|
|
if ( special1 > 2 ) special1 = 0;
|
|
}
|
|
}
|
|
else if ( (player.cmd.buttons&BT_USE) && (deadtimer > 120) )
|
|
{
|
|
// reload save
|
|
player.cls = null;
|
|
player.playerstate = PST_ENTER;
|
|
if ( special1 > 2 ) special1 = 0;
|
|
}
|
|
else if ( (player.cmd.buttons&BT_ATTACK) && (deadtimer > 120) && (!hnd || !hnd.gdat.disablerevive) && swwm_revive )
|
|
{
|
|
// reboot (if possible)
|
|
if ( !FindInventory("ReviveCooldown") && (((swwm_revivecooldown >= 0) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 4)) || !hasrevived) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 6) )
|
|
{
|
|
if ( hasrevived ) SWWMUtility.MarkAchievement("sekiro",player);
|
|
hasrevived = true;
|
|
player.Resurrect();
|
|
player.damagecount = 0;
|
|
player.bonuscount = 0;
|
|
player.poisoncount = 0;
|
|
blinktime = 30;
|
|
SetState(FindState("Spawn")+1); // skip tweening
|
|
roll = 0;
|
|
let s = Spawn("DemolitionistShockwave",pos);
|
|
s.target = self;
|
|
s.special1 = 30;
|
|
ReactionTime = 17;
|
|
A_Stop();
|
|
A_AlertMonsters(swwm_uncapalert?0:2500);
|
|
if ( player == players[consoleplayer] )
|
|
{
|
|
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP);
|
|
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.7);
|
|
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.4);
|
|
}
|
|
lastbump *= 1.5;
|
|
SWWMHandler.DoFlash(self,Color(255,255,255,255),10);
|
|
SWWMHandler.DoFlash(self,Color(255,128,192,255),30);
|
|
if ( special1 > 2 ) special1 = 0;
|
|
if ( (swwm_revivecooldown > 0) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 4) )
|
|
GiveInventory("ReviveCooldown",1);
|
|
}
|
|
else if ( level.maptime > revivefail )
|
|
{
|
|
if ( player == players[consoleplayer] ) A_StartSound("menu/fail",CHAN_ITEM,CHANF_UI);
|
|
revivefail = level.maptime+120;
|
|
}
|
|
}
|
|
}
|
|
else deadtimer = 0;
|
|
}
|
|
}
|