diff --git a/FuturePlans.md b/FuturePlans.md index bd619947f..70f5c2f5e 100644 --- a/FuturePlans.md +++ b/FuturePlans.md @@ -32,7 +32,6 @@ This is just a bit of *"future planning"* for stuff that I ***might*** add after - Gate Node (actual replacement for chaos devices) * ***(Maybe)* Fake livestream chat overlay, with dynamic reactions to all sorts of stuff** * **Replace all hitscan with *"light projectiles"*** -* **Quick Grenade sticks mags to walls (or things) if facing one** * **Leaning and a lot of other stuff involving ViewAngles and ViewPos** * **Crouch sliding *(+ proper crouch dashing)*** * **Expand third person animations** diff --git a/language.def_base b/language.def_base index b037ae407..b6acf8beb 100644 --- a/language.def_base +++ b/language.def_base @@ -729,7 +729,7 @@ SWWM_INTERTIP45 = "This mod may contain politics™. If you are sensitive to pol SWWM_INTERTIP46 = "Finding (or buying) a second Explodium Gun will allow you to switch to a dual-wield mode. Just for the sake of it (and because someone made fanart featuring this and I HAD to add it)."; SWWM_INTERTIP47 = "The duration of powerup effects will stack with each use."; SWWM_INTERTIP48 = "Black lives matter."; -SWWM_INTERTIP49 = "The quick grenade button will allow you to readily throw an Explodium Mag at any given moment, no matter what other weapon you were using."; +SWWM_INTERTIP49 = "The quick grenade button will allow you to readily throw an Explodium Mag at any given moment, no matter what other weapon you were using. If looking at a wall or the floor, you will instead plant the mag there, quite useful for setting up traps."; SWWM_INTERTIP50 = "Capitalism is a disease, a cancer that will bring this world to its ruin if we don't excise it soon."; SWWM_INTERTIP51 = "If an item is ever so slightly out of reach to be picked up by touch, you can press use to manually take it. Do note that this only works for items from this mod. Do also note that walk triggers will still be activated, so you're not going to avoid any traps this way."; SWWM_INTERTIP52 = "Lucky Chanceboxes may sometimes appear in secret areas, rewarding you with lots of goodies, including unique collectibles."; diff --git a/language.es_base b/language.es_base index 9f8aa0621..4a6f01a6a 100644 --- a/language.es_base +++ b/language.es_base @@ -647,7 +647,7 @@ SWWM_INTERTIP45 = "Este mod puede contener política™. Si eres sensible a la p SWWM_INTERTIP46 = "Al encontrar (o comprar) una segunda Pistola de Explodium podrás alternar a un modo dual. Solo por que sí (y porque alguien hizo fanart con esto y TENÍA que añadirlo)."; SWWM_INTERTIP47 = "La duración de los efectos de potenciador se va apilando con cada uso."; SWWM_INTERTIP48 = "Las vidas negras importan."; -SWWM_INTERTIP49 = "El botón de granada rápida te permitirá lanzar un Cargador de Explodium en cualquier momento, sin importar qué otra arma estés usando."; +SWWM_INTERTIP49 = "El botón de granada rápida te permitirá lanzar un Cargador de Explodium en cualquier momento, sin importar qué otra arma estés usando. Si estás mirando una pared o el suelo, plantarás el cargador ahí, muy útil para crear trampas."; SWWM_INTERTIP50 = "El capitalismo es una enfermedad, un cáncer que conducirá este mundo a la ruina si no lo eliminamos pronto."; SWWM_INTERTIP51 = "Si un ítem está casi a tu alcance pero no puedes tocarlo, puedes pulsar uso para recogerlo manualmente. Ten en cuenta que esto solo funciona con ítems de este mod. Ten también en cuenta que las trampas activadas por contacto se activarán igual, así que no vas a zafarte de ellas."; SWWM_INTERTIP52 = "Las Cajas Afortunadas pueden aparecer a veces en zonas secretas, recompensándote con varios regalos, incluyendo coleccionables exclusivos."; diff --git a/language.version b/language.version index 642d6fb48..0d338b5c4 100644 --- a/language.version +++ b/language.version @@ -1,3 +1,3 @@ [default] -SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r331 \cu(Sun 7 Mar 20:50:10 CET 2021)\c-"; -SWWM_SHORTVER="\cw0.9.11b-pre r331 \cu(2021-03-07 20:50:10)\c-"; +SWWM_MODVER="\chSWWM \czGZ\c- \cw0.9.11b-pre r332 \cu(Mon 8 Mar 00:27:48 CET 2021)\c-"; +SWWM_SHORTVER="\cw0.9.11b-pre r332 \cu(2021-03-08 00:27:48)\c-"; diff --git a/lore/default/explodiumgun.txt b/lore/default/explodiumgun.txt index 8388ee680..b697f221b 100644 --- a/lore/default/explodiumgun.txt +++ b/lore/default/explodiumgun.txt @@ -22,6 +22,8 @@ A custom-built semiautomatic handgun designed for proprietary .387 caliber **Exp \cfTechniques:\c- If you can get your hands on a second gun, you can switch to a dual-wield mode. In this mode, secondary fire instead shoots the left hand gun. +\cfAdditional Notes:\c- Magazines can be used on their own as a "quick grenade" while wielding any weapon. You can also place them on the walls or the floor to set up traps. + \cxSaya's Notes:\c- \cfThis one's on my main, level three-eighty-seven.\c- diff --git a/lore/es/explodiumgun.txt b/lore/es/explodiumgun.txt index 6901d1e01..2870fa6d3 100644 --- a/lore/es/explodiumgun.txt +++ b/lore/es/explodiumgun.txt @@ -18,6 +18,8 @@ Una pistola semiautomática hecha a medida, diseñada para balas propietarias de \cfTécnicas:\c- Si consigues hacerte con una segunda pistola, puedes alternar a un modo a dos manos. En este modo, el fuego secundario cambia a disparar la pistola a mano izquierda. +\cfNotas Adicionales:\c- Los cargadores se pueden usar por cuenta propia como una "granada rápida" mientras tienes cualquier otra arma. También puedes colocarlos en las paredes o el suelo para crear trampas. + \cxNotas de Saya:\c- \cfThis one's on my main, level three-eighty-seven.\c- diff --git a/modeldef.explodiumgun b/modeldef.explodiumgun index ea4136577..6d99c0881 100644 --- a/modeldef.explodiumgun +++ b/modeldef.explodiumgun @@ -43,6 +43,23 @@ Model "ExplodiumMagProj" FrameIndex XZW1 A 0 1 } +Model "ExplodiumMagAttach" +{ + Path "models" + + Model 0 "ExplodiumMag_d.3d" + Skin 0 "ExplodiumGun.png" + Scale 0.03 0.03 0.03 + USEACTORPITCH + USEACTORROLL + AngleOffset 90 + + FrameIndex XZW1 A 0 1 + RollOffset 90 + FrameIndex XZW1 B 0 1 + RollOffset -90 + FrameIndex XZW1 C 0 1 +} Model "ExplodiumGun" { diff --git a/modeldef.gesture b/modeldef.gesture index 6319b5b07..6a9d8269a 100644 --- a/modeldef.gesture +++ b/modeldef.gesture @@ -129,7 +129,7 @@ Model "SWWMGesture" FrameIndex XZW4 V 0 5 // arm FrameIndex XZW4 W 0 6 FrameIndex XZW4 X 0 7 - FrameIndex XZW4 Y 0 8 + FrameIndex XZW4 Y 0 8 // check surface FrameIndex XZW4 Z 0 9 FrameIndex XZW5 A 0 10 FrameIndex XZW5 B 0 11 // swing @@ -143,6 +143,23 @@ Model "SWWMGesture" FrameIndex XZW5 I 0 18 FrameIndex XZW5 J 0 19 FrameIndex XZW5 K 0 20 + FrameIndex XZW5 L 0 21 + // Quick Grenade (Surface) + SurfaceSkin 0 3 "ExplodiumGun.png" + FrameIndex XZW5 M 0 31 + FrameIndex XZW5 N 0 32 + FrameIndex XZW5 O 0 33 + FrameIndex XZW5 P 0 34 + FrameIndex XZW5 Q 0 35 + FrameIndex XZW5 R 0 36 + FrameIndex XZW5 S 0 37 + FrameIndex XZW5 T 0 38 + FrameIndex XZW5 U 0 39 + SurfaceSkin 0 3 "" + FrameIndex XZW5 V 0 40 // plant + FrameIndex XZW5 W 0 41 + FrameIndex XZW5 X 0 42 + FrameIndex XZW5 Y 0 43 } Model "SWWMGesture" { diff --git a/models/Grenade1st.blend b/models/Grenade1st.blend index f99bd9b01..8b2325381 100644 Binary files a/models/Grenade1st.blend and b/models/Grenade1st.blend differ diff --git a/models/Grenade1st_a.3d b/models/Grenade1st_a.3d index 3b16c8831..28d16b482 100644 Binary files a/models/Grenade1st_a.3d and b/models/Grenade1st_a.3d differ diff --git a/zscript/swwm_gesture.zsc b/zscript/swwm_gesture.zsc index cb147cf87..8190b6a0d 100644 --- a/zscript/swwm_gesture.zsc +++ b/zscript/swwm_gesture.zsc @@ -264,6 +264,33 @@ Class SWWMGesture : SWWMWeapon p.vel += vel*.5; } + action bool CanPlantGrenade() + { + let weap = Weapon(invoker); + if ( !weap ) return false; + Vector3 x, y, z; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x); + FLineTraceData d; + LineTrace(angle,DEFMELEERANGE*1.5,pitch,TRF_ABSPOSITION|TRF_THRUACTORS|TRF_NOSKY,origin.z,origin.x,origin.y,d); + return (d.HitType != TRACE_HitNone); + } + + action void A_PlantMag() + { + let weap = Weapon(invoker); + if ( !weap ) return; + Vector3 x, y, z; + [x, y, z] = swwm_CoordUtil.GetAxes(pitch,angle,roll); + Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x); + let p = Spawn("ExplodiumMagAttach",origin); + p.special1 = 7; + p.target = self; + p.angle = angle; + p.pitch = pitch; + p.vel = x*p.speed; + } + action void A_Smooch() { if ( swwm_mutevoice < 4 ) @@ -443,7 +470,7 @@ Class SWWMGesture : SWWMWeapon XZW4 U 3 A_PlayerReload(); XZW4 V 2 A_StartSound("explodium/magpin",CHAN_WEAPON,CHANF_OVERLAP); XZW4 WX 2; - XZW4 Y 3; + XZW4 Y 3 A_JumpIf(CanPlantGrenade(),"QuickGrenadePlant"); XZW4 Z 2 { A_StartSound("explodium/throwmag",CHAN_WEAPON,CHANF_OVERLAP); @@ -453,7 +480,17 @@ Class SWWMGesture : SWWMWeapon XZW5 CDEF 2; XZW5 G 2 A_ThrowMag(); XZW5 HIJ 3; - XZW5 K 4; + XZW5 KL 4; + XZW4 Q 0 A_JumpIf(player.cmd.buttons&BT_USER4,"QuickGrenade"); + XZW4 Q -1 A_FinishGesture(); + Stop; + QuickGrenadePlant: + XZW4 Y 3; + XZW5 M 2 A_PlayerMelee(); + XZW5 NOPQRSTU 2; + XZW5 V 2 A_PlantMag(); + XZW5 W 4 A_StartSound("demolitionist/handsdown",CHAN_WEAPON,CHANF_OVERLAP); + XZW5 XY 4; XZW4 Q 0 A_JumpIf(player.cmd.buttons&BT_USER4,"QuickGrenade"); XZW4 Q -1 A_FinishGesture(); Stop; diff --git a/zscript/utility/swwm_utility.zsc b/zscript/utility/swwm_utility.zsc index ce2b8cf49..a5f281163 100644 --- a/zscript/utility/swwm_utility.zsc +++ b/zscript/utility/swwm_utility.zsc @@ -394,18 +394,40 @@ Class SWWMUtility } // Thanks to ZZYZX and Nash + static play void SetToSlopeSpecific( Actor a, double dang, SecPlane plane, bool flipnorm ) + { + Vector3 fnormal; + if ( flipnorm ) fnormal = -plane.Normal; + else fnormal = plane.Normal; + vector2 fnormalp1 = ((fnormal.x != 0) || (fnormal.y != 0))?(fnormal.x,fnormal.y).Unit():(0,0); + vector2 fnormalp2 = ((fnormal.x,fnormal.y).Length(),fnormal.z); + double fang = atan2(fnormalp1.y,fnormalp1.x); // floor angle (not pitch!) + double fpitch = atan2(fnormalp2.x,fnormalp2.y); // floor pitch + double ddiff1 = sin(fang-dang); + double ddiff2 = cos(fang-dang); + a.pitch = fpitch*ddiff2; + a.roll = -fpitch*ddiff1; + a.angle = dang; + } + static play void SetToSlope( Actor a, double dang, bool ceil = false ) { Sector sect; + SecPlane plane; Vector3 fnormal; + bool flipnorm; if ( ceil ) { sect = a.CeilingSector; + plane = sect.ceilingplane; + flipnorm = true; fnormal = -sect.ceilingplane.Normal; } else { sect = a.FloorSector; + plane = sect.floorplane; + flipnorm = false; fnormal = sect.floorplane.Normal; } // find closest 3d floor for its normal @@ -420,18 +442,20 @@ Class SWWMUtility } if ( ff ) { - if ( ceil ) fnormal = ff.bottom.Normal; - else fnormal = -ff.top.Normal; + if ( ceil ) + { + plane = ff.bottom; + flipnorm = false; + fnormal = ff.bottom.Normal; + } + else + { + plane = ff.top; + flipnorm = true; + fnormal = -ff.top.Normal; + } } - vector2 fnormalp1 = ((fnormal.x != 0) || (fnormal.y != 0))?(fnormal.x,fnormal.y).Unit():(0,0); - vector2 fnormalp2 = ((fnormal.x,fnormal.y).Length(),fnormal.z); - double fang = atan2(fnormalp1.y,fnormalp1.x); // floor angle (not pitch!) - double fpitch = atan2(fnormalp2.x,fnormalp2.y); // floor pitch - double ddiff1 = sin(fang-dang); - double ddiff2 = cos(fang-dang); - a.pitch = fpitch*ddiff2; - a.roll = -fpitch*ddiff1; - a.angle = dang; + SetToSlopeSpecific(a,dang,plane,flipnorm); } static clearscope int Round100( double x ) diff --git a/zscript/weapons/swwm_splode_fx.zsc b/zscript/weapons/swwm_splode_fx.zsc index 21bc5b691..9f2988008 100644 --- a/zscript/weapons/swwm_splode_fx.zsc +++ b/zscript/weapons/swwm_splode_fx.zsc @@ -203,6 +203,234 @@ Class ExplodiumMagProj : Actor } } +Class ExplodiumMagHitbox : Actor +{ + Default + { + Radius 2; + Height 4; + +NOGRAVITY; + +DONTSPLASH; + +NOTELEPORT; + +SHOOTABLE; + } + override void Tick() + { + if ( !target || target.bKILLED ) + { + Destroy(); + return; + } + SetOrigin(target.Vec3Offset(0,0,-height*.5),false); + let bt = BlockThingsIterator.Create(self,128); + while ( bt.Next() ) + { + if ( !bt.Thing || (bt.Thing == self) || !bt.Thing.bSHOOTABLE || (bt.Thing == target.target) || !SWWMUtility.BoxIntersect(self,bt.Thing) ) + continue; + target.bKILLED = true; + target.SetStateLabel("Detonate"); + Destroy(); + break; + } + } + override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle ) + { + if ( target && !target.bKILLED ) + { + target.bKILLED = true; + target.SetStateLabel("Detonate"); + Destroy(); + } + return 0; + } +} + +Class ExplodiumMagAttach : ExplodiumMagProj +{ + Line atline; + int atside; + int atpart; + int atplane; + Sector atsector; + double atz; + Vector3 normal; + Actor hitbox; + + default + { + +MOVEWITHSECTOR; + Speed 15; + } + + override int SpecialMissileHit( Actor victim ) + { + if ( victim is 'ExplodiumMagHitbox' ) return 1; + return -1; + } + override void Tick() + { + Super.Tick(); + if ( isFrozen() ) return; + if ( bKILLED ) return; + if ( atline ) // attempt to follow the movement of the line + { + if ( atpart == 1 ) + { + if ( atline.flags&Line.ML_DONTPEGTOP ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true); + else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(1)),true); + } + else if ( atpart == -1 ) + { + if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true); + else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[!atside].sector.GetPlaneTexZ(0)),true); + } + else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(0)),true); + else SetOrigin(Vec2OffsetZ(0,0,atz+atline.sidedef[atside].sector.GetPlaneTexZ(1)),true); + if ( (pos.z > ceilingz) || (pos.z < floorz) ) bKILLED = true; + } + else if ( atsector ) // attempt to follow the movement of the plane + { + SetOrigin(Vec2OffsetZ(0,0,atz+atsector.GetPlaneTexZ(atplane)),true); + if ( ceilingz-floorz <= 2 ) bKILLED = true; + } + if ( bKILLED ) SetStateLabel("Detonate"); + } + void A_Attach() + { + F3DFloor ff; + A_NoGravity(); + A_Stop(); + if ( BlockingFloor ) + { + // find closest 3d floor for its normal + for ( int i=0; i (pos.z+height) ) atpart = -1; // lower + else + { + atpart = 0; + // check if we're touching a 3d floor line + Sector backsector = atline.sidedef[!atside].sector; + for ( int i=0; i (pos.z+height) ) continue; + if ( backsector.Get3DFloor(i).top.ZAtPoint(pos.xy) < pos.z ) continue; + ff = backsector.Get3DFloor(i); + break; + } + // attach to it + if ( ff ) + { + atline = ff.master; + atside = 0; + } + } + if ( atpart == 1 ) + { + if ( atline.flags&Line.ML_DONTPEGTOP ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1); + else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(1); + } + else if ( atpart == -1 ) + { + if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0); + else atz = pos.z-atline.sidedef[!atside].sector.GetPlaneTexZ(0); + } + else if ( atline.flags&Line.ML_DONTPEGBOTTOM ) atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(0); + else atz = pos.z-atline.sidedef[atside].sector.GetPlaneTexZ(1); + angle = atan2(normal.y,normal.x)+180; + pitch = 0; + } + else + { + bKILLED = true; + SetStateLabel("Detonate"); + return; + } + let b = Spawn("ExplodiumMagHitbox",pos); + b.target = self; + A_StartSound("explodium/jamitin",CHAN_BODY,CHANF_DEFAULT,.65,2.5); + } + States + { + Spawn: + XZW1 A -1; + Stop; + Death: + XZW1 A -1 A_Attach(); + Stop; + Detonate: + XZW1 # 2; + TNT1 A 0 + { + cvel = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch)); + A_BlowUp(); + } + XEX1 ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] 1 Bright; + Stop; + } +} + Class ExploLight : PaletteLight { Default