swwmgz_m/zscript/items/swwm_baseitem.zsc
Marisa the Magician 80db58b0d0 Bump zscript ver to 4.14.1, plus a whole lot of stuff.
- Try to get rid of all implicit casts from string to name, color or class.
 - Use FindClass where needed.
 - Used a map in a case where a dictionary was unneeded.
 - Use new bounce flags where needed.
 - Replace Legacy of Rust weapons/ammo.
2025-03-13 14:50:58 +01:00

291 lines
7.5 KiB
Text

// Inventory stuff
Mixin Class SWWMAutoUseFix
{
override bool HandlePickup( Inventory item )
{
if ( GetClass() == item.GetClass() )
{
if ( deathmatch && !bALWAYSPICKUP )
{
// don't allow picking up any more than just one copy in DM unless it can be auto-used
if ( Use(true) ) Amount--;
else return true;
}
else if ( Use(true) ) Amount--;
// sell excess if there's a price
if ( !deathmatch && bALWAYSPICKUP && (Amount+item.Amount > MaxAmount) && (Stamina != 0) )
{
if ( Owner.player )
{
int sellprice = abs(Stamina)/2;
SWWMCredits.Give(Owner.player,sellprice);
if ( Owner.player == players[consoleplayer] )
{
SWWMScoreObj.SpawnAtActorBunch(sellprice,Owner);
Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRA_FEM":"$SWWM_SELLEXTRA"),GetTag(),sellprice);
}
else Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRAREM_FEM":"$SWWM_SELLEXTRAREM"),Owner.player.GetUserName(),GetTag(),sellprice);
}
item.bPickupGood = true;
}
}
return Super.HandlePickup(item);
}
override bool TryPickup( Actor &toucher )
{
if ( !deathmatch ) return Super.TryPickup(toucher);
// pretend to have a max amount of 0 so we can only be picked up if we can be used
int oldmax = MaxAmount;
MaxAmount = 0;
bool ret = Super.TryPickup(toucher);
MaxAmount = oldmax;
return ret;
}
}
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 )
{
// can't pick up
if ( !bSPECIAL ) return false;
// no use through melee
if ( (user.player.ReadyWeapon is 'SWWMWeapon') && SWWMWeapon(user.player.ReadyWeapon).wallponch )
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,ignoreallactors:true);
// 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 : SWWMNonInteractiveActor
{
FSpawnParticleParams flare;
default
{
Args 0,3,2;
-NOBLOCKMAP; // needed so player can "sense" it
}
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 ( freezetics > 0 )
{
freezetics--;
return;
}
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;
if ( !flare.texture )
{
flare.color1 = Color(args[0]*85,args[1]*85,args[2]*85);
flare.texture = TexMan.CheckForTexture("graphics/Particles/xflare.png");
flare.style = STYLE_AddShaded;
flare.flags = SPF_FULLBRIGHT;
flare.fadestep = -1;
}
flare.pos = pos+(0,0,16);
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);
flare.lifetime = Random[ExploS](30,60);
flare.size = FRandom[ExploS](2.,3.);
flare.vel = SWWMUtility.Vec3FromAngles(ang,pt)*FRandom[ExploS](0.,.8);
flare.startalpha = FRandom[ExploS](.45,.9)*str;
flare.sizestep = FRandom[ExploS](-.04,-.02)*str;
level.SpawnParticle(flare);
}
}
}
Mixin Class SWWMPickupGlow
{
override Inventory CreateTossable( int amt )
{
let ret = Super.CreateTossable(amt);
// reattach our glow if we became a pickup
if ( (ret == self) && (PickupFlash is 'SWWMPickupFlash') )
{
let p = Spawn(PickupFlash,pos);
p.target = self;
p.SetStateLabel('Pickup');
}
return ret;
}
}
Class SWWMItemOverlay : SWWMNonInteractiveActor
{
Default
{
RenderStyle 'Add';
+FLOATBOB;
FloatBobStrength .25;
}
override void Tick()
{
if ( !target )
{
Destroy();
return;
}
prev = target.prev;
if ( (target.pos != pos) || (target.vel != (0,0,0)) ) SetOrigin(target.pos+target.vel,true);
if ( (angle != target.angle) && bINTERPOLATEANGLES ) angle = target.angle; // copy angle for rotating pickups
FloatBobPhase = target.FloatBobPhase;
bInvisible = target.bInvisible||Inventory(target).Owner;
}
States
{
Spawn:
XZW1 A -1 Bright;
Stop;
}
}
Mixin Class SWWMRotatingPickup
{
Default
{
+INTERPOLATEANGLES;
}
override void Tick()
{
Super.Tick();
if ( !Owner ) angle -= (180./64.);
}
}
Mixin Class SWWMUnrealStyleDrop
{
override void OnDrop( Actor dropper )
{
if ( !(dropper is 'Demolitionist') ) return;
Vector3 ofs = SWWMUtility.RotateVector3((dropper.radius,0.,dropper.height*.5),dropper.angle);
SetOrigin(level.Vec3Offset(dropper.pos,ofs),false);
vel = SWWMUtility.GetPlayerViewDir(dropper)*12.+(0.,0.,4.);
angle = dropper.angle;
pitch = 0;
roll = 0;
}
}
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);
}
}