351 lines
12 KiB
Text
351 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()
|
|
{
|
|
if ( !player || (player.playerstate != PST_DEAD) ) deadtimer = 0;
|
|
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;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|