diff --git a/cvarinfo.txt b/cvarinfo.txt index f8e3a92..e4234b1 100644 --- a/cvarinfo.txt +++ b/cvarinfo.txt @@ -1 +1,2 @@ server int snektech_spawnflags = 3; +user string snektech_spraypattern = "SnekSpray_TransPride"; diff --git a/decaldef.txt b/decaldef.txt index e76514a..9b604da 100644 --- a/decaldef.txt +++ b/decaldef.txt @@ -10,3 +10,17 @@ decal KiriTestDecal animator KiriInstantFade randomflipx } + +decal SnekSpray_TransPride +{ + pic KSPYA0 + animator KiriInstantFade + randomflipx +} + +decal SnekSpray_LesbianPride +{ + pic KSPYB0 + animator KiriInstantFade + randomflipx +} diff --git a/sndinfo.txt b/sndinfo.txt index 25982d6..35a1dbc 100644 --- a/sndinfo.txt +++ b/sndinfo.txt @@ -1,5 +1,9 @@ kiri/gretchencounter_click "sounds/gretchencounter_click.ogg" kiri/gretchencounter_blip "sounds/gretchencounter_blip.ogg" kiri/gretchencounter_onoff "sounds/gretchencounter_onoff.ogg" + kiri/cacoplushie_throw "sounds/cacoplushie_throw.ogg" kiri/cacoplushie_despawn "sounds/cacoplushie_despawn.ogg" + +kiri/spraycan_rattle "sounds/spraycan_rattle.ogg" +kiri/spraycan_spray "sounds/spraycan_spray.ogg" diff --git a/sounds/spraycan_rattle.aup3 b/sounds/spraycan_rattle.aup3 new file mode 100644 index 0000000..e15134b Binary files /dev/null and b/sounds/spraycan_rattle.aup3 differ diff --git a/sounds/spraycan_rattle.ogg b/sounds/spraycan_rattle.ogg new file mode 100644 index 0000000..2e76fc6 Binary files /dev/null and b/sounds/spraycan_rattle.ogg differ diff --git a/sounds/spraycan_spray.aup3 b/sounds/spraycan_spray.aup3 new file mode 100644 index 0000000..548ba9f Binary files /dev/null and b/sounds/spraycan_spray.aup3 differ diff --git a/sounds/spraycan_spray.ogg b/sounds/spraycan_spray.ogg new file mode 100644 index 0000000..80a8992 Binary files /dev/null and b/sounds/spraycan_spray.ogg differ diff --git a/source_data/spray_lesbianpride.aseprite b/source_data/spray_lesbianpride.aseprite new file mode 100644 index 0000000..5dd4d89 Binary files /dev/null and b/source_data/spray_lesbianpride.aseprite differ diff --git a/textures.txt b/textures.txt index 95eda57..044c865 100644 --- a/textures.txt +++ b/textures.txt @@ -117,6 +117,14 @@ Sprite "KSPYA0", 250, 150 Patch KSPYA0,0,0 { } } +Sprite "KSPYB0", 250, 150 +{ + XScale 2 + YScale 2 + Offset 125, 75 + Patch KSPYB0,0,0 { } +} + Sprite "KSPRB0", 48, 48 { Offset 24, 24 diff --git a/zscript/spraycan.zs b/zscript/spraycan.zs index b8f0c2c..6e0e1ed 100644 --- a/zscript/spraycan.zs +++ b/zscript/spraycan.zs @@ -1,5 +1,18 @@ +// FIXME: Make consts and enums consistent formatting. + const KIRI_SPRAYDISTANCE = 96; +const KIRI_SPRAY_SHAKEANIM_MAXANGLE = 20.0; +const KIRI_SPRAY_MAXPAINT = 50; +const KIRI_SPRAY_MAXPRESSURE = 100; +const KIRI_SPRAY_PRESSUREBUILDSCALE = 20; +const KIRI_SPRAY_PRESSURE_PER_USE = (KIRI_SPRAY_MAXPRESSURE / 2); + +enum KiriSprayerStatus +{ + KIRISPRAYER_PAINT = 1, + KIRISPRAYER_PRESSURE = 2 +} class Sprayer : HDWeapon { @@ -27,46 +40,239 @@ class Sprayer : HDWeapon KSPR A 1 { A_WeaponReady(WRF_ALL); A_WeaponBusy(false); } goto readyend; + reload: + KSPR A 1 offset(0, 20) { + A_OverlayPivot(0, 0.5, 1.0); + A_OverlayRotate(0, 0); + + A_StartSound( + "kiri/spraycan_rattle", + CHAN_WEAPON, CHANF_NOSTOP); + } + KSPR A 1 offset(0, 40) { A_OverlayRotate(0, sin(level.time * 5.0) * KIRI_SPRAY_SHAKEANIM_MAXANGLE * 1.0/3.0); } + KSPR A 1 offset(0, 60) { A_OverlayRotate(0, sin(level.time * 5.0) * KIRI_SPRAY_SHAKEANIM_MAXANGLE * 2.0/3.0); } + KSPR A 1 offset(0, 80) { + A_OverlayRotate(0, sin(level.time * 5.0) * KIRI_SPRAY_SHAKEANIM_MAXANGLE); + + // Taper off pressure increase amount based on how much + // pressure is in there already. + float pressureIncreaseScale = 1.0 - ( + float(invoker.weaponstatus[KIRISPRAYER_PRESSURE]) / + float(KIRI_SPRAY_MAXPRESSURE)); + pressureIncreaseScale *= pressureIncreaseScale; + + // Add pressure. + invoker.weaponstatus[KIRISPRAYER_PRESSURE] += + random(0, + KIRI_SPRAY_PRESSUREBUILDSCALE + * invoker.weaponstatus[KIRISPRAYER_PAINT] + / KIRI_SPRAY_MAXPAINT); + + // Cap pressure amount. + if(invoker.weaponstatus[KIRISPRAYER_PRESSURE] > KIRI_SPRAY_MAXPRESSURE) { + invoker.weaponstatus[KIRISPRAYER_PRESSURE] = KIRI_SPRAY_MAXPRESSURE; + } + + } + KSPR A 1 offset(0, 60) { A_OverlayRotate(0, sin(level.time * 5.0) * KIRI_SPRAY_SHAKEANIM_MAXANGLE * 2.0/3.0); } + KSPR A 1 offset(0, 40) { A_OverlayRotate(0, sin(level.time * 5.0) * KIRI_SPRAY_SHAKEANIM_MAXANGLE * 1.0/3.0); } + KSPR A 1 offset(0, 20) { A_OverlayRotate(0, 0); } + goto ready; + fire: KSPR A 2 { - Actor spawnedThing; - bool success; - float zOffset = GunHeight() * 0.8; - FLineTraceData lineTraceData; + if(invoker.weaponstatus[KIRISPRAYER_PRESSURE] < KIRI_SPRAY_PRESSURE_PER_USE) { - bool traceHit = LineTrace( - angle, - KIRI_SPRAYDISTANCE, - pitch, - flags : TRF_THRUACTORS, - offsetz : zOffset, - data : lineTraceData); + invoker.owner.A_Log("Not enough pressure to spray."); - if(traceHit) { + } else { - if(lineTraceData.HitLine) { + Actor spawnedThing; + bool success; + float zOffset = GunHeight() * 0.8; + FLineTraceData lineTraceData; + + class sprayerPatternClass = "SprayerPattern"; + + // Find the spray pattern class that matches the + // player's CVar for selected pattern. + String currentSprayCVar = CVar.GetCVar( + "snektech_spraypattern", + invoker.owner.player).GetString(); + for(int i = 0; i < AllActorClasses.size(); i++) { + class thisPatternClass = (class)(AllActorClasses[i]); + if(thisPatternClass) { + if(thisPatternClass.GetClassName() == currentSprayCVar) { + sprayerPatternClass = (class)(AllActorClasses[i]); + break; + } + } + } + + // Get the actual decal name out of it. + let defaultSprayClass = GetDefaultByType(sprayerPatternClass); + String actualDecalName = defaultSprayClass.decalName; + + // Find a wall to spray on. + bool traceHit = LineTrace( + angle, + KIRI_SPRAYDISTANCE, + pitch, + flags : TRF_THRUACTORS, + offsetz : zOffset, + data : lineTraceData); + + if(traceHit && lineTraceData.HitLine) { + + A_StartSound( + "kiri/spraycan_spray", + CHAN_WEAPON); - console.printf("spray spray spray"); [success, spawnedThing] = A_SpawnItemEx( "SprayerDecalSpawner", xofs : 0, yofs : 0, zofs : zOffset); - if(success) { - spawnedThing.A_SetPitch(pitch); - spawnedThing.A_SetAngle(angle); - spawnedThing.master = invoker.owner; + SprayerDecalSpawner spawner = SprayerDecalSpawner(spawnedThing); + + if(success && spawner) { + spawner.A_SetPitch(pitch); + spawner.A_SetAngle(angle); + spawner.actualDecalName = actualDecalName; + spawner.master = invoker.owner; + + invoker.weaponstatus[KIRISPRAYER_PRESSURE] -= KIRI_SPRAY_PRESSURE_PER_USE; + invoker.weaponstatus[KIRISPRAYER_PAINT] -= 1; } + + } else { + + invoker.owner.A_Log("Not close enough to a wall to spray."); + } } } goto waiting; + altfire: + KSPR A 2 { invoker.CycleSprayPattern(); } + goto waiting; + waiting: KSPR A 5; - KSPR A 0 A_Refire("waiting"); + KSPR A 0 A_Refire("waiting"); goto ready; + select0: + KSPR A 0 offset(0, 120); + ---- A 1 A_Raise(12); + wait; + + deselect0: + KSPR A 0; + ---- A 1 A_Lower(12); + wait; + + } + + override void InitializeWepStats(bool idfa) + { + super.InitializeWepStats(idfa); + + weaponstatus[KIRISPRAYER_PRESSURE] = 0; + + // Add a little bit of randomness to the amount of paint in + // the can. + weaponstatus[KIRISPRAYER_PAINT] = + KIRI_SPRAY_MAXPAINT + - random(0, KIRI_SPRAY_MAXPAINT / 10); + } + + override void Tick() + { + super.Tick(); + + // Gradually decay pressure. + if(random(0, 256) < 4) { + weaponstatus[KIRISPRAYER_PRESSURE] -= 1; + if(weaponstatus[KIRISPRAYER_PRESSURE] < 0) { + weaponstatus[KIRISPRAYER_PRESSURE] = 0; + } + } + } + + override void DrawHUDStuff( + HDStatusBar statusBar, HDWeapon weapon, + HDPlayerPawn pawn) + { + // Current pressure (top bar). + statusBar.DrawWepNum( + weaponstatus[KIRISPRAYER_PRESSURE], + KIRI_SPRAY_MAXPRESSURE, posy:-10); + + // Total paint remaining (bottom bar). + statusBar.DrawWepNum( + weaponstatus[KIRISPRAYER_PAINT], + KIRI_SPRAY_MAXPAINT); + } + + void GetSprayPatternList(Array ret) + { + ret.clear(); + for(int i = 0; i < AllActorClasses.Size(); i++) { + class c = AllActorClasses[i]; + if(c is "SprayerPattern" && c != "SprayerPattern") { + ret.push(c.GetClassName()); + } + } + } + + void CycleSprayPattern() + { + // Find the current entry in the list of patterns. + String currentPattern = CVar.GetCVar("snektech_spraypattern", owner.player).GetString(); + Array patternList; + GetSprayPatternList(patternList); + int currentIndex = patternList.find(currentPattern); + + // Make sure we're actually in the list (CVar might not be in + // list, due to mods getting shuffled around and whatever). + if(currentIndex >= patternList.size()) { + currentIndex = -1; + } + + // Increment the index. + int newIndex = (currentIndex + 1) % patternList.size(); + + // Set the new CVar. + CVar.GetCVar("snektech_spraypattern", owner.player).SetString(patternList[newIndex]); + currentPattern = CVar.GetCVar("snektech_spraypattern", owner.player).GetString(); + invoker.owner.A_Log("Selected spray pattern: "..currentPattern); + + // Current pattern is referenced in the help text, so reset + // it. + A_SetHelpText(); + } + + override String GetHelpText() + { + super.GetHelpText(); + + int messageIndex = level.time; //(level.time / 60); + Array messages = { + "Deface the tyrant's property.", + "Engage in civil disobedience.", + "Create a beautiful work of art.", + "Show the world that you still exist.", + "Defy the tyrant." + }; + + String currentPattern = CVar.GetCVar("snektech_spraypattern", owner.player).GetString(); + + return + WEPHELP_ALTFIRE.. " Cycle pattern (current: "..currentPattern..").\n".. + WEPHELP_RELOAD .. " Shake the can.\n".. + WEPHELP_FIRE .. " "..messages[messageIndex % messages.Size()].."\n"; } } @@ -86,12 +292,12 @@ class SprayerDecalSpawner : Actor int timeSinceLastSpray; int thisSprayerId; + String actualDecalName; override void PostBeginPlay() { Super.PostBeginPlay(); - console.printf("SPRAY"); - A_SprayDecal("KiriTestDecal", KIRI_SPRAYDISTANCE); + A_SprayDecal(actualDecalName, KIRI_SPRAYDISTANCE); // Figure out a new ID number. ThinkerIterator iter = ThinkerIterator.Create("SprayerDecalSpawner"); @@ -131,12 +337,40 @@ class SprayerDecalSpawner : Actor override void Tick() { + super.Tick(); + timeSinceLastSpray++; if(timeSinceLastSpray >= 35 * 60) { - A_SprayDecal("KiriTestDecal", KIRI_SPRAYDISTANCE); + A_SprayDecal(actualDecalName, KIRI_SPRAYDISTANCE); timeSinceLastSpray = 0; } } } +class SprayerPattern : Actor +{ + string decalName; + property decalName:decalName; + + default { + SprayerPattern.decalName "KiriTestDecal"; + } +} + +class SnekSpray_TransPride : SprayerPattern +{ + default + { + SprayerPattern.decalName "SnekSpray_TransPride"; + } +} + +class SnekSpray_LesbianPride : SprayerPattern +{ + default + { + SprayerPattern.decalName "SnekSpray_LesbianPride"; + } +} +