// collectable items that may drop sometimes (future feature) Class SWWMCollectable : Inventory abstract { int avail; Property Availability : avail; // minimum gametype requirements enum EAvailability { AVAIL_Strife = GAME_Strife, AVAIL_Hexen = AVAIL_Strife|GAME_Hexen, AVAIL_Heretic = AVAIL_Hexen|GAME_Heretic, AVAIL_All = AVAIL_Heretic|GAME_DoomChex }; Default { Inventory.PickupSound "menu/buyinv"; Inventory.Amount 1; Inventory.MaxAmount 1; SWWMCollectable.Availability AVAIL_All; +INVENTORY.UNTOSSABLE; +INVENTORY.UNDROPPABLE; +INVENTORY.UNCLEARABLE; +FLOATBOB; FloatBobStrength 0.25; } override string PickupMessage() { return StringTable.Localize(PickupMsg)..String.Format(" \cj(\cg„\cf%d\cj)\c-",Stamina); } override void AttachToOwner( Actor other ) { Super.AttachToOwner(other); // give credit if ( other.player ) { SWWMScoreObj.Spawn(Stamina,other.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+other.Height/2),Font.CR_GOLD); SWWMCredits.Give(other.player,Stamina); } } States { Spawn: XZW1 A -1; Stop; } } // April Fools 2020 Class FroggyChair : SWWMCollectable { int cdown; Default { Tag "$T_FROGGY"; Inventory.PickupMessage "$T_FROGGY"; Stamina 1440; } override void AttachToOwner( Actor other ) { Super.AttachToOwner(other); cdown = 150; } override void DoEffect() { Super.DoEffect(); if ( Owner && Owner.CheckLocalView() ) { if ( cdown == 140 ) Console.MidPrint(newsmallfont,"$D_FROGGY1"); else if ( cdown == 70 ) Console.MidPrint(newsmallfont,"$D_FROGGY2"); } if ( cdown > 0 ) cdown--; } } // The other collectables, which will be implemented eventually /* Class MMiaSRVol1 : SWWMCollectable { Default { Tag "$T_SEXROBOT1"; Inventory.PickupMessage "$T_SEXROBOT1"; Stamina 2000; } } Class MMiaSRVol2 : SWWMCollectable { Default { Tag "$T_SEXROBOT2"; Inventory.PickupMessage "$T_SEXROBOT2"; Stamina 2000; } } Class MMiaSRVol3 : SWWMCollectable { Default { Tag "$T_SEXROBOT3"; Inventory.PickupMessage "$T_SEXROBOT3"; Stamina 2000; } } Class MothPlushy : SWWMCollectable { Default { Tag "$T_MOTHPLUSH"; Inventory.PickupMessage "$T_MOTHPLUSH"; Stamina 5000; } } Class BRCDebutLP : SWWMCollectable { Default { Tag "$T_BLACKRATS"; Inventory.PickupMessage "$T_BLACKRATS"; Stamina 6000; } } Class AkariProject : SWWMCollectable { Default { Tag "$T_AKARIPROJECT"; Inventory.PickupMessage "$T_AKARIPROJECT"; Stamina 3000; } } Class CatCatcherPoster : SWWMCollectable { Default { Tag "$T_CATCATCHER"; Inventory.PickupMessage "$T_CATCATCHER"; Stamina 1500; } } Class LoveSignalsCD : SWWMCollectable { Default { Tag "$T_LOVESIGNALS"; Inventory.PickupMessage "$T_LOVESIGNALS"; Stamina 4000; } } Class NutatcoBar : SWWMCollectable { Default { Tag "$T_NUTATCO"; Inventory.PickupMessage "$T_NUTATCO"; Stamina 200; } } Class HegeCactus : SWWMCollectable { Default { Tag "$T_HEGE"; Inventory.PickupMessage "$T_HEGE"; Stamina 8000; } } Class RaideminFig : SWWMCollectable { Default { Tag "$T_RAIDEMIN"; Inventory.PickupMessage "$T_RAIDEMIN"; Stamina 9000; } } Class FrispyCorn : SWWMCollectable { Default { Tag "$T_FRISPYCORN"; Inventory.PickupMessage "$T_FRISPYCORN"; Stamina 500; } } Class Hoagie : SWWMCollectable { Default { Tag "$T_HOAGIE"; Inventory.PickupMessage "$T_HOAGIE"; Stamina 800; } } Class LithiumVol1 : SWWMCollectable { Default { Tag "$T_LITHIUM"; Inventory.PickupMessage "$T_LITHIUM"; Stamina 3500; } } Class MeetTheSniper : SWWMCollectable { Default { Tag "$T_PISS"; Inventory.PickupMessage "$T_PISS"; Stamina 1200; } } // Heretic Class DemoPlush : SWWMCollectable { Default { Tag "$T_DEMOPLUSH"; Inventory.PickupMessage "$T_DEMOPLUSH"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 6400; } } Class Firemace : SWWMCollectable { Default { Tag "$T_FIREMACE"; Inventory.PickupMessage "$T_FIREMACE"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 10000; } } Class DoomguyFig : SWWMCollectable { Default { Tag "$T_DOOMFIG"; Inventory.PickupMessage "$T_DOOMFIG"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 9000; } } Class TomeOfPower : SWWMCollectable { Default { Tag "$T_TOMEPOWER"; Inventory.PickupMessage "$T_TOMEPOWER"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 16000; } } Class QuartzFlask : SWWMCollectable { Default { Tag "$T_YEFLASK"; Inventory.PickupMessage "$T_YEFLASK"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 4000; } } Class SayaBean : SWWMCollectable { Default { Tag "$T_SAYABEAN"; Inventory.PickupMessage "$T_SAYABEAN"; SWWMCollectable.Availability AVAIL_Heretic; Stamina 12000; } } // Hexen Class PuzzleDesignBook : SWWMCollectable { Default { Tag "$T_PUZZLEBOOK"; Inventory.PickupMessage "$T_PUZZLEBOOK"; SWWMCollectable.Availability AVAIL_Hexen; Stamina 2500; } } Class KirinCummies : SWWMCollectable { Default { Tag "$T_PEACH"; Inventory.PickupMessage "$T_PEACH"; SWWMCollectable.Availability AVAIL_Hexen; Stamina 400; } } Class MilkBreads : SWWMCollectable { Default { Tag "$T_MILKBREAD"; Inventory.PickupMessage "$T_MILKBREAD"; SWWMCollectable.Availability AVAIL_Hexen; Stamina 900; } } Class EyeObelisk : SWWMCollectable { Default { Tag "$T_OBELISK"; Inventory.PickupMessage "$T_OBELISK"; SWWMCollectable.Availability AVAIL_Hexen; Stamina 24000; } } Class KirinManga : SWWMCollectable { Default { Tag "$T_KIRINMANGA"; Inventory.PickupMessage "$T_KIRINMANGA"; SWWMCollectable.Availability AVAIL_Hexen; Stamina 1600; } } */ // yay! Class FancyConfetti : Actor { int deadtimer; double anglevel, pitchvel, rollvel; Default { Radius 2; Height 2; +NOBLOCKMAP; +DROPOFF; +MOVEWITHSECTOR; +THRUACTORS; +NOTELEPORT; +DONTSPLASH; +INTERPOLATEANGLES; +ROLLSPRITE; +ROLLCENTER; +SLIDESONWALLS; Gravity 0.05; } override void PostBeginPlay() { Super.PostBeginPlay(); deadtimer = Random[Junk](-30,30); anglevel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1); pitchvel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1); rollvel = FRandom[Junk](3,12)*RandomPick[Junk](-1,1); if ( bAMBUSH ) frame = 0; else frame = Random[Junk](0,9); scale *= Frandom[Junk](0.8,1.2); } override void Tick() { Super.Tick(); if ( isFrozen() ) return; vel.xy *= 0.98; if ( vel.z > 0 ) vel.z *= 0.98; if ( CurState == ResolveState("Death") ) { deadtimer++; if ( deadtimer > 300 ) A_FadeOut(0.05); return; } } States { Spawn: XZW1 # 1 { angle += anglevel; pitch += pitchvel; roll += rollvel; return A_JumpIf(pos.z<=floorz,"Death"); } Loop; Death: XZW1 # -1 { A_Stop(); pitch = roll = 0; } Stop; Dummy: XZW1 ABCDEFGHIJ -1; Stop; } } // Collectable box (recycling of discarded "chance box" item) Class Chancebox : Actor { static void SpawnChanceboxes() { // TODO the whole damn deal of finding secret sectors and whatnot // this will be huge, and get called from the event handler on first level load } action void A_DropSomething() { Array > candidates; candidates.Clear(); for ( int i=0; i)(AllActorClasses[i]); if ( !c || (c == 'SWWMCollectable') ) continue; let def = GetDefaultByType(c); // check that we can collect it in this IWAD if ( !(gameinfo.gametype&def.avail) ) continue; candidates.Push(c); } let ti = ThinkerIterator.Create("SWWMCollectable"); SWWMCollectable c; while ( c = SWWMCollectable(ti.Next()) ) { int f = candidates.Find(inv.GetClass()); if ( f < candidates.Size() ) candidates.Delete(f); } if ( candidates.Size() <= 0 ) { // TODO no candidates? just spawn some random loot Console.Printf("\cg// TODO spawn random loot\c-"); } else { // pop one at random let a = Spawn(candidates[Random[Chancebox](0,candidates.Size()-1)],pos); a.bDROPPED = true; a.bNOGRAVITY = false; a.vel.z = FRandom[Chancebox](2,4); } int numpt = Random[ExploS](16,32); for ( int i=0; i40,"BlowUp"); } Wait; BlowUp: XZW2 A 1 { A_SetSize(16,4); A_QuakeEx(2,2,2,9,0,500,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.2); A_StartSound("chancebox/explode",CHAN_VOICE); angle = specialf1; pitch = roll = 0; let t = Spawn("ChanceboxTop",Vec3Offset(0,0,32)); t.angle = angle; let s1 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((16,0),angle+90),0))); s1.angle = angle+90; let s2 = Spawn("ChanceboxSide",level.Vec3Offset(pos,(RotateVector((16,0),angle-90),0))); s2.angle = angle-90; A_DropSomething(); } XZW2 BCDEFGHIJKLMNO 1; XZW2 P -1 A_Confetti(); Stop; } } // top side of chancebox, shoots upwards Class ChanceboxTop : Actor { Default { Radius 16; Height 4; PROJECTILE; } override void PostBeginPlay() { Super.PostBeginPlay(); vel = (0,0,20); } States { Spawn: XZW1 A 1 { double magvel = vel.length(); if ( magvel > 0. ) { magvel = min(60,magvel*1.2); vel = vel.unit()*magvel; } } Wait; Death: TNT1 A 1 A_SpawnItemEx("ExplodiumBulletImpact"); Stop; } } // left/right side of chancebox, shoots forward Class ChanceboxSide : Actor { Default { Radius 16; Height 32; PROJECTILE; } override void PostBeginPlay() { Super.PostBeginPlay(); vel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch))*20; } States { Spawn: XZW1 A 1 { double magvel = vel.length(); if ( magvel > 0. ) { magvel = min(60,magvel*1.2); vel = vel.unit()*magvel; } } Wait; Death: TNT1 A 1 A_SpawnItemEx("ExplodiumBulletImpact"); Stop; } }