swwmgz_m/zscript/items/swwm_baseitem.zsc
Marisa Kirisame 3500f72db0 Add "exclusive use to pickup" option.
Make "pickup through melee" optional (disabled by default).
Increased leniency of use to pickup (nice for items with small hitboxes).
2021-05-29 23:26:12 +02:00

185 lines
5 KiB
Text

// Inventory stuff
Mixin Class SWWMAutoUseFix
{
override bool HandlePickup( Inventory item )
{
if ( GetClass() == item.GetClass() )
{
if ( Use(true) ) Amount--;
// sell excess if there's a price
if ( bALWAYSPICKUP && (Amount+item.Amount > MaxAmount) && (Stamina != 0) )
{
int sellprice = int(abs(Stamina)*.5);
SWWMScoreObj.Spawn(sellprice,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2));
SWWMCredits.Give(Owner.player,sellprice);
if ( Owner.player )
Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRA_FEM":"$SWWM_SELLEXTRA"),Owner.player.GetUserName(),GetTag(),sellprice);
}
}
return Super.HandlePickup(item);
}
}
Class CrossLineFinder : LineTracer
{
Array<Line> clines;
Array<int> csides;
override ETraceStatus TraceCallback()
{
if ( (Results.HitType == TRACE_HitWall) && (Results.HitLine.activation&SPAC_Cross) )
{
clines.Push(Results.HitLine);
csides.Push(Results.Side);
}
return TRACE_Skip;
}
}
Mixin Class SWWMUseToPickup
{
bool bUsePickup;
// allow pickup by use
override bool Used( Actor user )
{
// no use through melee
if ( (user.player.ReadyWeapon is 'SWWMWeapon') && SWWMWeapon(user.player.ReadyWeapon).wallponch && !swwm_meleepickup )
return false;
Vector3 itempos = Vec3Offset(0,0,Height/2),
userpos = user.Vec2OffsetZ(0,0,user.player.viewz);
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
bUsePickup = true;
Touch(user);
bUsePickup = false;
// we got picked up
if ( bDestroyed || Owner || !bSPECIAL )
{
Vector3 tracedir = level.Vec3Diff(userpos,itempos);
double dist = tracedir.length();
tracedir /= dist;
let cf = new("CrossLineFinder");
cf.Trace(userpos,level.PointInSector(userpos.xy),tracedir,dist,0);
// trigger all player cross lines found between user and item
for ( int i=0; i<cf.clines.Size(); i++ )
cf.clines[i].Activate(user,cf.csides[i],SPAC_Cross);
return true;
}
return false;
}
override void Touch( Actor toucher )
{
if ( toucher.player && swwm_usetopickup && !bUsePickup )
return;
Super.Touch(toucher);
}
}
Mixin Class SWWMOverlapPickupSound
{
// overlap sounds
override void PlayPickupSound( Actor toucher )
{
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
if ( hnd )
{
if ( hnd.lastpickuptic[toucher.PlayerNumber()] == gametic )
return; // don't play if picked up on the same exact tic (overlapping items)
hnd.lastpickuptic[toucher.PlayerNumber()] = gametic;
}
double atten;
int flags = CHANF_OVERLAP|CHANF_MAYBE_LOCAL;
if ( bNoAttenPickupSound ) atten = ATTN_NONE;
else atten = ATTN_NORM;
if ( toucher && toucher.CheckLocalView() )
flags |= CHANF_NOPAUSE;
toucher.A_StartSound(PickupSound,CHAN_ITEM,flags,1.,atten);
}
}
Class SWWMRespawnTimer : Actor
{
default
{
+NOGRAVITY;
+NOINTERACTION;
+DONTSPLASH;
+NOTELEPORT;
Radius .1;
Height 0.;
Args 0,3,2;
}
override void PostBeginPlay()
{
args[3] = Random[ExploS](0,30);
if ( !Inventory(tracer) || !Inventory(tracer).PickupFlash ) return;
// copy pickup flash color
let fog = GetDefaultByType(Inventory(tracer).PickupFlash);
for ( int i=0; i<3; i++ ) args[i] = fog.args[i+1];
}
override void Tick()
{
if ( !tracer || !tracer.InStateSequence(tracer.CurState,tracer.FindState("HideDoomish")) )
{
Destroy();
return;
}
special2 = tracer.tics;
if ( isFrozen() ) return;
double str = 1.-special2/double(special1);
int freq = int(clamp(30*(1.-str),3,30));
if ( (level.maptime+args[3])%freq ) return;
int numpt = int(Random[ExploS](0,10)*str);
for ( int i=0; i<numpt; i++ )
{
double ang = FRandom[ExploS](0,360);
double pt = FRandom[ExploS](-90,90);
A_SpawnParticle(Color(args[0]*85,args[1]*85,args[2]*85),SPF_FULLBRIGHT,Random[ExploS](30,60),FRandom[ExploS](1.,2.),0,0,0,16,FRandom[ExploS](-.8,.8),FRandom[ExploS](-.8,.8),FRandom[ExploS](-.8,.8),0,0,0,FRandom[ExploS](.45,.9)*str,-1,FRandom[ExploS](-.04,-.02)*str);
}
}
States
{
Spawn:
TNT1 A -1;
Stop;
}
}
Mixin Class SWWMRespawn
{
override void Hide()
{
bSPECIAL = false;
bNOGRAVITY = true;
bINVISIBLE = true;
SetState(FindState("HideDoomish"));
tics = 1050;
if ( (self is 'Ammo') || (self is 'MagAmmo') )
tics -= 350;
if ( self.bBIGPOWERUP || SWWMUtility.IsVIPItem(self) )
tics += 1050;
if ( RespawnTics != 0 ) tics = RespawnTics;
if ( ShouldRespawn() )
{
Vector3 oldpos = pos;
A_RestoreSpecialPosition();
let t = Spawn("SWWMRespawnTimer",pos);
t.tracer = self;
t.special1 = tics;
t.A_SetSize(radius,height);
SetOrigin(oldpos,false);
}
}
override bool ShouldRespawn()
{
// always respawn in DM
if ( deathmatch && !bNEVERRESPAWN ) return true;
if ( (bBigPowerup || SWWMUtility.IsVIPItem(self)) && !sv_respawnsuper ) return false;
if ( bNEVERRESPAWN ) return false;
return (sv_itemrespawn||bALWAYSRESPAWN);
}
}