swwmgz_m/zscript/player/swwm_player_think.zsc
Marisa the Magician f78b747ff7 Add secret difficulty for a dragon.
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).
2023-10-16 14:00:46 +02:00

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;
}
}