swwmgz_m/zscript/player/swwm_player_think.zsc

335 lines
11 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;
bool remove;
TextureID replacewith;
[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 x, y, z, dir;
[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);
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;
}
}
override void PlayerThink()
{
oldangle = angle;
oldpitch = pitch;
oldroll = 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") )
{
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) )
{
int loudlv = swwm_voiceamp;
A_StartSound(String.Format("voice/%s/usegrunt",myvoice.GetString()),CHAN_DEMOVOICE,CHANF_OVERLAP);
if ( loudlv > 1 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice.GetString()),CHAN_DEMOVOICEAUX,CHANF_OVERLAP);
if ( loudlv > 2 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice.GetString()),CHAN_DEMOVOICEAUX2,CHANF_OVERLAP);
if ( loudlv > 3 ) A_StartSound(String.Format("voice/%s/usegrunt",myvoice.GetString()),CHAN_DEMOVOICEAUX3,CHANF_OVERLAP);
failcooldown = int(S_GetLength(String.Format("voice/%s/usegrunt",myvoice.GetString()))*GameTicRate);
failcounter = max(2,failcounter-1);
}
}
else if ( gametic > lastuse+50 ) failcounter = 0;
oldlagangle = lagangle;
oldlagpitch = lagpitch;
oldlagroll = lagroll;
lagangle = lagangle*.8+angle*.2;
lagpitch = lagpitch*.8+pitch*.2;
lagroll = lagroll*.8+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()
{
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);
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 ( 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) && !FindInventory("SWWMReviveDisabler") && swwm_revive )
{
// reboot (if possible)
if ( !FindInventory("ReviveCooldown") && (((swwm_revivecooldown >= 0) && (G_SkillPropertyInt(SKILLP_ACSReturn) < 4)) || !hasrevived) )
{
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;
}
}