Added Lead Ball ammo type to Spreadgun.
Partial implementation of Fuck Your Shit rounds, currently in progress. Added various shader effects to some powerups, and to player damage. Added custom view effects to player death, disabled "face attacker" because it looks weird with model-based players. Added "untouchable" spree tracking to the Stats tab. Implemented "emergency reboot system" for people who want a less shameful form of the Resurrect cheat. Cooldown for consecutive reboots can be configured. Rebalanced armors. Small language string corrections. Adjusted pickup model sizes of some weapons. Fixed missing punch sound (damn typos). Fix targetter always displaying voodoo dolls. Fix uptime breaking when loading saves, now based on total playtime rather than gametic. Readjusted Spreadgun ammo availability. Flush HUD interpolators alongside messages, fixes things such as the score VERY slowly counting up when loading a save. Spare armors now only get auto-used on pickup if there is NO armor available of that type. Added some extra visual effects to punching walls and non-bleeding actors. Slightly altered the melee range so it's not as awkward. Fixed punching not using flesh sounds for bleeding actors. Pusher primary now drags the player towards their target, like the Chainsaw. Fixed the player having no pain sounds whatsoever. Fixed stair step anchoring not working. The damage dealt when walljumping on a monster now also gets boosted by the Ragekit.
This commit is contained in:
parent
a4994ee132
commit
d1b1a0541d
33 changed files with 1112 additions and 89 deletions
|
|
@ -73,6 +73,7 @@ be purchased from the store, they have to be found in maps.
|
|||
Item | Price
|
||||
------------- | -----
|
||||
Health Nugget | 1200
|
||||
Froggy Chair | 1440
|
||||
H.Tetrahedron | 3000
|
||||
H.Cube | 8000
|
||||
Refresher | 160000
|
||||
|
|
|
|||
10
README.md
10
README.md
|
|
@ -374,20 +374,20 @@ The upper cap for these is 200%.
|
|||
|
||||
### Blast Suit, replaces Green Armor, Silver Shield, Mesh Armor
|
||||
|
||||
The blast suit is a nice little light armor which provides a 75% reduction to
|
||||
The blast suit is a nice little light armor which provides a 30% reduction to
|
||||
damage and an additional 50% to splash damage.
|
||||
|
||||
Can handle a total of 200 damage before breaking.
|
||||
Can handle a total of 150 damage before breaking.
|
||||
|
||||
### War Armor, replaces Blue Armor, Enchanted Shield, Falcon Shield
|
||||
|
||||
Decent armor, protects very well against all damage. Reduction factors are as
|
||||
follows:
|
||||
* 90% reduction for elemental (fire, ice, electric, etc.)
|
||||
* 80% reduction to everything else
|
||||
* 80% reduction for elemental (fire, ice, electric, etc.)
|
||||
* 50% reduction to everything else
|
||||
* 70% reduction for all splash damage (multiplicative on top of the other two)
|
||||
|
||||
The armor can eat up a total of 600 damage before breaking.
|
||||
The armor can eat up a total of 250 damage before breaking.
|
||||
|
||||
### Grilled Cheese Sandwich, replaces Megasphere, Morph Ovum, Platinum Helm
|
||||
|
||||
|
|
|
|||
|
|
@ -32,3 +32,5 @@ user bool swwm_fly6dof = true; // flying uses 6dof movement, toggleable for th
|
|||
user bool swwm_othervoice = true; // can hear other player's voice lines in coop
|
||||
user bool swwm_shaders = true; // use pp shaders for some effects
|
||||
user bool swwm_earbuster = false; // limits loudness of wallbuster fire sounds
|
||||
server bool swwm_revive = false; // allows the player to do an "emergency reboot" when dying
|
||||
server int swwm_revivecooldown = 30; // cooldown after using a revive, in seconds (0: no limit)
|
||||
|
|
|
|||
28
decaldef.txt
28
decaldef.txt
|
|
@ -25,6 +25,34 @@ decalgroup WallCrack
|
|||
WallCrack2 1
|
||||
}
|
||||
|
||||
decal BigWallCrack1
|
||||
{
|
||||
pic WallCrk1
|
||||
translucent 0.75
|
||||
shade "00 00 00"
|
||||
x-scale 1.1
|
||||
y-scale 1.1
|
||||
randomflipx
|
||||
randomflipy
|
||||
}
|
||||
decal BigWallCrack2
|
||||
{
|
||||
pic WallCrk2
|
||||
translucent 0.75
|
||||
shade "00 00 00"
|
||||
x-scale 1.1
|
||||
y-scale 1.1
|
||||
randomflipx
|
||||
randomflipy
|
||||
}
|
||||
|
||||
decalgroup BigWallCrack
|
||||
{
|
||||
BigWallCrack1 1
|
||||
BigWallCrack2 1
|
||||
}
|
||||
|
||||
|
||||
decal SaltMark
|
||||
{
|
||||
pic saltmark
|
||||
|
|
|
|||
17
gldefs.pp
17
gldefs.pp
|
|
@ -19,3 +19,20 @@ HardwareShader PostProcess scene
|
|||
Uniform float timer
|
||||
Uniform float xtrastr
|
||||
}
|
||||
|
||||
HardwareShader PostProcess scene
|
||||
{
|
||||
Name "Glitch"
|
||||
Shader "shaders/glsl/Glitch.frag" 330
|
||||
Uniform float Timer
|
||||
Uniform float str1
|
||||
Uniform float str2
|
||||
}
|
||||
HardwareShader PostProcess scene
|
||||
{
|
||||
Name "Grain"
|
||||
Shader "shaders/glsl/Grain.frag" 330
|
||||
Uniform float Timer
|
||||
Uniform float ni
|
||||
Texture NoiseTexture "textures/rgbnoise.png"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,3 +38,7 @@ HardwareShader Texture "models/silvermap.png"
|
|||
{
|
||||
Shader "shaders/glsl/Shinemap.fp"
|
||||
}
|
||||
HardwareShader Texture "models/leadmap.png"
|
||||
{
|
||||
Shader "shaders/glsl/Shinemap.fp"
|
||||
}
|
||||
|
|
|
|||
BIN
graphics/HUD/Icons/I_Revive.png
Normal file
BIN
graphics/HUD/Icons/I_Revive.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
48
language.txt
48
language.txt
|
|
@ -70,6 +70,9 @@ SWWM_SCOREBONUS = "Show Score Bonuses";
|
|||
SWWM_EARBUSTER = "Reduce Wallbuster Loudness";
|
||||
SWWM_SHADERS = "Use Screen Shaders";
|
||||
SWWM_OTHERVOICE = "Co-op Voice";
|
||||
SWWM_REVIVE = "Emergency Reboot System";
|
||||
SWWM_REVIVECOOLDOWN = "Reboot Cooldown";
|
||||
SWWM_UNLIMITED = "Unlimited";
|
||||
TOOLTIP_SWWM_VOICETYPE = "Sets the voice pack for the player.";
|
||||
TOOLTIP_SWWM_MUTEVOICE = "Control what gets muted, if you'd rather have a more silent protagonist.";
|
||||
TOOLTIP_SWWM_FLASHSTRENGTH = "Screen flashes usually happen when firing some weapons, you can lower this if these effects are harmful for you.";
|
||||
|
|
@ -96,6 +99,8 @@ TOOLTIP_SWWM_SCOREBONUS = "Show additional bonus strings above score numbers (e.
|
|||
TOOLTIP_SWWM_EARBUSTER = "The Wallbuster's firing sounds may be painfully loud at times. This setting will limit the loudness to something more bearable.";
|
||||
TOOLTIP_SWWM_SHADERS = "Use postprocess shaders for things like powerups and the Silver Bullet scope. You can disable this if you'd prefer something lighter on the eyes.";
|
||||
TOOLTIP_SWWM_OTHERVOICE = "Allows you to hear other player's voice lines, provided you're close enough.";
|
||||
TOOLTIP_SWWM_REVIVE = "Allows the player to get back up after dying by pressing Fire. Has a configurable cooldown.";
|
||||
TOOLTIP_SWWM_REVIVECOOLDOWN = "Time in seconds of downtime after using a reboot, where if you die again, you can't get back up. Set to 0 to allow unlimited reboots.";
|
||||
// knowledge base
|
||||
SWWM_COMINGSOON = "(coming soon)";
|
||||
SWWM_MISSTAB = "Mission";
|
||||
|
|
@ -116,6 +121,7 @@ SWWM_STATTDEALT = "Highest Damage Dealt: ";
|
|||
SWWM_STATDTAKEN = "Total Damage Taken: ";
|
||||
SWWM_STATTTAKEN = "Highest Damage Taken: ";
|
||||
SWWM_STATMKILL = "Highest Kill Combo: ";
|
||||
SWWM_STATSKILL = "Longest Untouchable Spree: ";
|
||||
SWWM_STATFAVWEAP = "Favorite Weapon: ";
|
||||
SWWM_STATHISCORE = "Highest Score: ";
|
||||
SWWM_INVTAB = "Inventory";
|
||||
|
|
@ -305,10 +311,10 @@ SWWM_LORETXT_BLASTSUIT =
|
|||
"Summary: A simple vest designed to protect against explosions. The main body is made of very elastic nanofabrics, and should provide adequate protection against small arms. The plating is made of a highly shock-absorbing proprietary alloy.\n"
|
||||
"\n"
|
||||
"Protection:\n"
|
||||
" - 75% reduction to all types of damage.\n"
|
||||
" - 30% reduction to all types of damage.\n"
|
||||
" - Additional 50% reduction to explosions.\n"
|
||||
"\n"
|
||||
"Durability: Can absorb a total of 200 units of damage before breaking.\n"
|
||||
"Durability: Can absorb a total of 150 units of damage before breaking.\n"
|
||||
"\n"
|
||||
"Addendum: The blast suit can be worn under other armor.";
|
||||
SWWM_LORETAG_CANDYGUN = "Candy Gun";
|
||||
|
|
@ -1347,11 +1353,11 @@ SWWM_LORETXT_WARARMOR =
|
|||
"Summary: Very robust, durable plate armor. Made of the finest almasteel in Devanikna. Originally commissioned for the third entry in Zanaveth's Instant Action arena events.\n"
|
||||
"\n"
|
||||
"Protection:\n"
|
||||
" - 90% reduction to heat, cold, electricity, slime and other elemental types.\n"
|
||||
" - 80% reduction to all other types of damage.\n"
|
||||
" - 80% reduction to heat, cold, electricity, slime and other elemental types.\n"
|
||||
" - 50% reduction to all other types of damage.\n"
|
||||
" - Additional 70% reduction to explosions.\n"
|
||||
"\n"
|
||||
"Durability: Can absorb a total of 600 units of damage before breaking.\n"
|
||||
"Durability: Can absorb a total of 250 units of damage before breaking.\n"
|
||||
"\n"
|
||||
"Addendum: Worn over a blast suit, you're pretty much ready for anything that could be thrown at you.";
|
||||
SWWM_LORETAG_YNYKRON = "Ynykron Artifact";
|
||||
|
|
@ -1690,6 +1696,11 @@ D_INVINCIBALL = "You are no longer invincible.";
|
|||
D_RAGEKIT = "The Ragekit has ragequit.";
|
||||
D_REFRESHER = "The Refresher boost has ended.";
|
||||
D_WARARMOR = "The War Armor is no more.";
|
||||
SWWM_URDED = "Demolitionist Unit \"%s\" has fallen";
|
||||
SWWM_URDED2 = "Press \cfUse\c- to restart from the most recent save";
|
||||
SWWM_URDED3 = "...or press \cfFire\c- to attempt an emergency reboot";
|
||||
SWWM_REFAIL = "EMERGENCY REBOOT FAILED - NOT ENOUGH AUXILIARY POWER AVAILABLE";
|
||||
D_REFAIL = "The Emergency Reboot System has recharged completely.";
|
||||
// targetter
|
||||
SWWM_OVERKILL = "Overkill";
|
||||
SWWM_MULTIKILL = "Multi Kill";
|
||||
|
|
@ -2028,6 +2039,9 @@ SWWM_SCOREBONUS = "Mostrar Bonificaciones de Puntuación";
|
|||
SWWM_EARBUSTER = "Reducir Estruendo del Wallbuster";
|
||||
SWWM_SHADERS = "Usar Shaders de Pantalla";
|
||||
SWWM_OTHERVOICE = "Voz en Cooperativo";
|
||||
SWWM_REVIVE = "Sistema de Reinicio de Emergencia";
|
||||
SWWM_REVIVECOOLDOWN = "Tiempo de recarga de Reinicio";
|
||||
SWWM_UNLIMITED = "Ilimitado";
|
||||
TOOLTIP_SWWM_VOICETYPE = "Selecciona el pack de voz para el jugador.";
|
||||
TOOLTIP_SWWM_MUTEVOICE = "Controla lo que se mutea, si prefieres tener un protagonista más silencioso.";
|
||||
TOOLTIP_SWWM_FLASHSTRENGTH = "Los destellos en pantalla suelen ocurrir al disparar algunas armas, puedes reducirlo si este tipo de effectos te causan malestar.";
|
||||
|
|
@ -2054,6 +2068,8 @@ TOOLTIP_SWWM_SCOREBONUS = "Muestra textos de bonificación extra sobre los punto
|
|||
TOOLTIP_SWWM_EARBUSTER = "Los sonidos de disparo del Wallbuster pueden a veces ser dolorosamente estridentes. Esta opción limitará la intensidad a un valor más soportable.";
|
||||
TOOLTIP_SWWM_SHADERS = "Usa shaders de postprocesado para cosas como powerups y la mira del Silver Bullet. Puedes desactivar esto si prefieres algo más ligero para la vista.";
|
||||
TOOLTIP_SWWM_OTHERVOICE = "Te permite oír los comentarios de voz de otros jugadores, si estás lo suficientemente cerca.";
|
||||
TOOLTIP_SWWM_REVIVE = "Permite al jugador volver a levantarse tras morir pulsando Fuego. Tiene un cooldown configurable.";
|
||||
TOOLTIP_SWWM_REVIVECOOLDOWN = "Tiempo en segundos tras reiniciar, durante el cual si mueres otra vez, no puedes volver a levantarte. Pon a 0 para permitir reinicios ilimitados.";
|
||||
// knowledge base
|
||||
SWWM_COMINGSOON = "(próximamente)";
|
||||
SWWM_MISSTAB = "Misión";
|
||||
|
|
@ -2074,6 +2090,7 @@ SWWM_STATTDEALT = "Mayor Daño Infligido: ";
|
|||
SWWM_STATDTAKEN = "Daño Total Recibido: ";
|
||||
SWWM_STATTTAKEN = "Mayor Daño Recibido: ";
|
||||
SWWM_STATMKILL = "Mayor Racha: ";
|
||||
SWWM_STATSKILL = "Mayor Racha Intocable: ";
|
||||
SWWM_STATFAVWEAP = "Arma Favorita: ";
|
||||
SWWM_STATHISCORE = "Puntuación Máxima: ";
|
||||
SWWM_INVTAB = "Inventario";
|
||||
|
|
@ -2243,10 +2260,10 @@ SWWM_LORETXT_BLASTSUIT =
|
|||
"Resumen: Un simple chaleco diseñado para proteger contra explosiones. El cuerpo principal está hecho de nanotejidos muy elásticos, y deberían proveer de una protección decente contra armamento ligero. El blindaje está hecho de una aleación propietaria altamente resistente al impacto.\n"
|
||||
"\n"
|
||||
"Protección:\n"
|
||||
" - Reducción de un 75% contra todo tipo de daños.\n"
|
||||
" - Reducción de un 30% contra todo tipo de daños.\n"
|
||||
" - Reducción adicional de un 50% contra explosiones.\n"
|
||||
"\n"
|
||||
"Durabilidad: Puede absorber un total de 200 unidades de daño antes de romperse.\n"
|
||||
"Durabilidad: Puede absorber un total de 150 unidades de daño antes de romperse.\n"
|
||||
"\n"
|
||||
"Apéndice: El chaleco se puede llevar por debajo de otras armaduras.";
|
||||
SWWM_LORETAG_CANDYGUN = "Pistola Caramelo";
|
||||
|
|
@ -3043,7 +3060,7 @@ SWWM_LORETXT_UAC2 =
|
|||
"\n"
|
||||
"Apéndice: La compañía cayó en el control de los demonios durante la invasión (aunque algunos dicen que esto pudo ser el caso mucho antes del evento), y actualmente sigue recuperándose. Sin embargo no hay muchas esperanzas por una recuperación completa, ya que muchos de sus empleados siguen marchándose.\n"
|
||||
"\n"
|
||||
"Nota de Saya: Si es que me da un gusto de cojones ver caer a este asqueroso gigante. Tío, todo lo de la invasión fue horrible, sabes. Pero me alegro de que al menos hubieramos podido ayudar, aunque no fuera nada comparado con lo que el tal Slayer hizo...";
|
||||
"Nota de Saya: Si es que me da un gusto de cojones ver caer a este asqueroso gigante. Tía, todo lo de la invasión fue horrible, sabes. Pero me alegro de que al menos hubieramos podido ayudar, aunque no fuera nada comparado con lo que el tal Slayer hizo...";
|
||||
SWWM_LORETXT_UNISSIX =
|
||||
"Nombre Completo: Misa Azadeku Unissix, o \"Unissix Bokurou Azadeku\"\n"
|
||||
"Nacionalidad: Devanikana\n"
|
||||
|
|
@ -3087,11 +3104,11 @@ SWWM_LORETXT_WARARMOR =
|
|||
"Resumen: Armadura robusta y durable. Hecha con el mejor almacero de Devanikna. Originalmente encargada para la tercera entrada en los eventos Instant Action de Zanaveth.\n"
|
||||
"\n"
|
||||
"Protección:\n"
|
||||
" - Reducción del 90% contra calor, frío, electricidad, lodo y otros tipos elementales.\n"
|
||||
" - Reducción del 80% de todos los demás tipos de daño.\n"
|
||||
" - Reducción del 80% contra calor, frío, electricidad, lodo y otros tipos elementales.\n"
|
||||
" - Reducción del 50% de todos los demás tipos de daño.\n"
|
||||
" - Reducción adicional del 70% al daño por explosión.\n"
|
||||
"\n"
|
||||
"Durabilidad: Puede absorber un total de 600 unidades de daño antes de romperse.\n"
|
||||
"Durabilidad: Puede absorber un total de 250 unidades de daño antes de romperse.\n"
|
||||
"\n"
|
||||
"Apéndice: Combinado con un chaleco antiexplosivos, estás preparada para todo lo que te puedan soltar encima.";
|
||||
SWWM_LORETAG_YNYKRON = "Artefacto Ynykron";
|
||||
|
|
@ -3116,7 +3133,7 @@ SWWM_LORETXT_WHITESCAR =
|
|||
"\n"
|
||||
"Resumen: En Junio de 2073, el Presidente de los Estados Unidos realizó unos comentarios muy ofensivos sobre los Nukuri, que en aquel momento estaban pasando por su séptima Guerra Mundial. No fueron muy bien recibidos. Muchos Nukuri anteriormente asentados en la Tierra emigraron en protesta, el emperador de Nahkami tuvo muchas cosas que decir, y la bola siguió pasándose. En poco tiempo, el conflicto llegó a su punto de ebullición, y el Imperio Nukuri declaró la guerra a los EEUU, listo para lanzar un ataque directo como \"castigo por su insolencia\". Se desplegaron unidades de tierra en 2074, y así empezó la guerra. Hubo muchas bajas en ambos bandos, en su intento de \"matar a la bestia desde dentro\", sin embargo, en solo tres años más, el país entero había caído. Al presidente se le dieron dos opciones: o bien disculparse públicamente por sus palabras contra el Imperio Nukuri, o si no ver como la ira del Emperador cae sobre su gente. Rechazó esta proposición, y se ordenó la retirada de todas las fuerzas Nukuri en el área. Entonces, ocurrió: Con un destello de luz cegadora, un ataque orbital alcanzó varias grandes ciudades Estadounidenses, reduciéndolas a cenizas. La mayoría de la gente que se encontraba bajo techo pudo sobrevivir, los demás no tuvieron tanta suerte.\n"
|
||||
"\n"
|
||||
"Apéndice: Al llegar las noticias de lo que ocurrió en la tierra, estallaron las protestas por todo el Imperio Nukuri, avivando aun más las llamas de la Séptima Guerra Mundial. El caos continuó durante casi 30 años, hasta que los fundadores de la Universidad de Nos-Kora intervinieron, y pusieron fin a la guerra ellos solos. Su ultimátum fue tomado muy en serio, y así una reforma masiva comenzó, empezando con la retirada forzosa del Emperador y su consiguiente exilio, sin derecho a volver jamás. La reforma llegó a su climax en 2108, con la formación del Gobierno Nukuri Unificado. A pesar de todo esto, las relaciones con los Nukuri nunca se han recuperado, con la excepción de algunos países todavía aliados, como Escocia y Japón.\n"
|
||||
"Apéndice: Al llegar las noticias de lo que ocurrió en la Tierra, estallaron las protestas por todo el Imperio Nukuri, avivando aun más las llamas de la Séptima Guerra Mundial. El caos continuó durante casi 30 años, hasta que los fundadores de la Universidad de Nos-Kora intervinieron, y pusieron fin a la guerra ellos solos. Su ultimátum fue tomado muy en serio, y así una reforma masiva comenzó, empezando con la retirada forzosa del Emperador y su consiguiente exilio, sin derecho a volver jamás. La reforma llegó a su climax en 2108, con la formación del Gobierno Nukuri Unificado. A pesar de todo esto, las relaciones con los Nukuri nunca se han recuperado, con la excepción de algunos países todavía aliados, como Escocia y Japón.\n"
|
||||
"\n"
|
||||
"Nota de Saya: Dios es que este fue uno de los momentos más oscuros de la historia. Me jode muchísimo pensar en ello otra vez, sobre todo despues de que Zana-sama me contara como fue todo al otro lado. Los Nukuri no eran gente muy pacífica en aquellos tiempos, pero solo por que el tío que mandaba era un puto supervillano megalomaníaco asqueroso, es que joder, achicharrar los Estados Unidos por UNOS TWITS. Casi todo dios ahí se puso en su contra cuando pasó. El muy capullo es que firmó su propia sentencia de muerte, vamos. Y encima lo de que los dos frikis esos fueran y... ACABARAN la guerra por su cuenta. Madre de dios, espero no cabrearlos nunca.";
|
||||
SWWM_LORETXT_XANIMEN =
|
||||
|
|
@ -3183,7 +3200,7 @@ T_GREENSHELLS = "Slugs";
|
|||
T_WHITESHELL = "Cartucho Dragon's Breath";
|
||||
T_WHITESHELLS = "Cartuchos Dragon's Breath";
|
||||
T_BLUESHELL = "Cartucho de Sal de Kinylum";
|
||||
T_BLUESHELLS = "Cartucho de Sal Kinylum";
|
||||
T_BLUESHELLS = "Cartucho de Sal de Kinylum";
|
||||
T_BLACKSHELL = "Cartucho de Napalm";
|
||||
T_BLACKSHELLS = "Cartuchos de Napalm";
|
||||
T_PURPLESHELL = "Cartucho de Bola de Plomo";
|
||||
|
|
@ -3400,6 +3417,11 @@ D_INVINCIBALL = "Ya no eres invencible.";
|
|||
D_RAGEKIT = "El Ragekit ha hecho ragequit.";
|
||||
D_REFRESHER = "El boost del Refrescador ha terminado.";
|
||||
D_WARARMOR = "La Armadura de Guerra ya no da para más.";
|
||||
SWWM_URDED = "La Unidad Demolicionista \"%s\" ha caído";
|
||||
SWWM_URDED2 = "Pulsa \cfUsar\c- para reiniciar desde la última partida guardada";
|
||||
SWWM_URDED3 = "...o pulsa \cfDisparar\c- para intentar un reinicio de emergencia";
|
||||
SWWM_REFAIL = "REINICIO DE EMERGENCIA FALLIDO - NO HAY SUFICIENTE POTENCIA AUXILIAR DISPONIBLE";
|
||||
D_REFAIL = "El Sistema de Reinicio de Emergencia se ha recargado completamente.";
|
||||
// targetter
|
||||
SWWM_MULTIKILL = "Racha";
|
||||
SWWM_SPREEKILL = "Intocable";
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ OptionMenu "SWWMOptionMenu"
|
|||
SWWMVoiceOption "$SWWM_VOICETYPE", "swwm_voicetype"
|
||||
Option "$SWWM_MUTELEVEL", "swwm_mutevoice", "SWWMVoice"
|
||||
Option "$SWWM_6DOF", "swwm_fly6dof", "YesNo"
|
||||
Option "$SWWM_REVIVE", "swwm_revive", "YesNo"
|
||||
ScaleSlider "$SWWM_REVIVECOOLDOWN", "swwm_revivecooldown", 0, 300, 30, "$SWWM_UNLIMITED"
|
||||
StaticText " "
|
||||
StaticText "$SWWM_OTITLE", "Gold"
|
||||
Slider "$SWWM_FLASH", "swwm_flashstrength", 0.0, 1.0, 0.1, 1
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ Model "CandyGun"
|
|||
|
||||
Model 0 "ExplodiumGunPickup_d.3d"
|
||||
Skin 0 "CandyGun.png"
|
||||
Scale 0.06 0.06 0.06
|
||||
Scale 0.05 0.05 0.05
|
||||
ZOffset 16
|
||||
ROTATING
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Model "ExplodiumGun"
|
|||
|
||||
Model 0 "ExplodiumGunPickup_d.3d"
|
||||
Skin 0 "ExplodiumGun.png"
|
||||
Scale 0.04 0.04 0.04
|
||||
Scale 0.05 0.05 0.05
|
||||
ZOffset 16
|
||||
ROTATING
|
||||
|
||||
|
|
|
|||
|
|
@ -144,13 +144,23 @@ Model "SaltBeam"
|
|||
FrameIndex XZW2 M 0 12
|
||||
}
|
||||
|
||||
Model "TheBall"
|
||||
{
|
||||
Model 0 "models/extra/BaseSphere_d.3d"
|
||||
Skin 0 "models/leadmap.png"
|
||||
Scale 0.008 0.008 0.008
|
||||
ZOffset 2
|
||||
|
||||
FrameIndex XZW1 A 0 0
|
||||
}
|
||||
|
||||
Model "Spreadgun"
|
||||
{
|
||||
Path "models"
|
||||
|
||||
Model 0 "SpreadgunPickup_d.3d"
|
||||
Skin 0 "Spreadgun.png"
|
||||
Scale 0.035 0.035 0.035
|
||||
Scale 0.04 0.04 0.04
|
||||
AngleOffset 180
|
||||
ZOffset 16
|
||||
ROTATING
|
||||
|
|
|
|||
BIN
models/ASmallPriceToPay.png
Normal file
BIN
models/ASmallPriceToPay.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
models/ASmallPriceToPay_a.3d
Normal file
BIN
models/ASmallPriceToPay_a.3d
Normal file
Binary file not shown.
BIN
models/ASmallPriceToPay_d.3d
Normal file
BIN
models/ASmallPriceToPay_d.3d
Normal file
Binary file not shown.
BIN
models/leadmap.png
Normal file
BIN
models/leadmap.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -13,7 +13,7 @@ void main()
|
|||
vec2 uv_c[3] = vec2[3](coord,coord,coord);
|
||||
vec2 blka = floor(coord*vec2(22.0,12.0));
|
||||
vec2 blkb = floor(coord*vec2(6.0,9.0));
|
||||
float noiz = pow(rnd2(blka),thr1)*pow(rnd2(blkb),thr2)-pow(rnd(4.53),thr3)*str2;
|
||||
float noiz = pow(rnd2(blka),6.4)*pow(rnd2(blkb),8.6)-pow(rnd(4.53),19.3)*str2;
|
||||
uv_c[0].x += str1*noiz*(rnd(3.35)-0.5);
|
||||
uv_c[1].x += str1*noiz*(rnd(4.63)-0.5);
|
||||
uv_c[2].x += str1*noiz*(rnd(5.62)-0.5);
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
Complex grain shader ported over from MariENB
|
||||
(C)2012-2018 Marisa Kirisame
|
||||
*/
|
||||
const float nf = 0.000005;
|
||||
const float nf = 0.00001;
|
||||
const vec3 nm1 = vec3(2.05,3.11,2.22);
|
||||
const float nk = 0.04;
|
||||
const vec3 nm2 = vec3(4.25,9.42,6.29);
|
||||
const float ns = -0.08;
|
||||
const float np = 3.95;
|
||||
const float bnp = 1.7;
|
||||
const float ns = -0.28;
|
||||
const float np = 2.1;
|
||||
const float bnp = 0.7;
|
||||
|
||||
#define darkmask(a,b) (a>0.5)?(2.0*a*(0.5+b)):(1.0-2.0*(1.0-a)*(1.0-((0.5+b))))
|
||||
|
||||
|
|
@ -52,8 +52,8 @@ void main()
|
|||
{
|
||||
vec2 coord = TexCoord;
|
||||
vec4 res = texture(InputTexture,coord);
|
||||
/*vec2 sfact = max(vec2(320.0,200.0),textureSize(InputTexture,0)*0.5);
|
||||
coord = floor(coord*sfact)/sfact;*/
|
||||
vec2 sfact = max(vec2(640.0,400.0),textureSize(InputTexture,0)*0.5);
|
||||
coord = floor(coord*sfact)/sfact;
|
||||
res.rgb = grain(res.rgb,coord);
|
||||
FragColor = res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ $random demolitionist/punch { demolitionist/punch1 demolitionist/punch2 demoliti
|
|||
demolitionist/punchf1 sounds/demolitionist/demopunchf1.ogg
|
||||
demolitionist/punchf2 sounds/demolitionist/demopunchf2.ogg
|
||||
demolitionist/punchf3 sounds/demolitionist/demopunchf3.ogg
|
||||
$random demolitionist/punchf { demolitionist/puncfh1 demolitionist/punchf2 demolitionist/punchf3 }
|
||||
$random demolitionist/punchf { demolitionist/punchf1 demolitionist/punchf2 demolitionist/punchf3 }
|
||||
demolitionist/bump1 sounds/demolitionist/demobump1.ogg
|
||||
demolitionist/bump2 sounds/demolitionist/demobump2.ogg
|
||||
demolitionist/bump3 sounds/demolitionist/demobump3.ogg
|
||||
|
|
@ -315,6 +315,7 @@ demolitionist/kick1 sounds/demolitionist/demokick1.ogg
|
|||
demolitionist/kick2 sounds/demolitionist/demokick2.ogg
|
||||
demolitionist/kick3 sounds/demolitionist/demokick3.ogg
|
||||
$random demolitionist/kick { demolitionist/kick1 demolitionist/kick2 demolitionist/kick3 }
|
||||
demolitionist/revive sounds/demolitionist/demorevive.ogg
|
||||
|
||||
$playersound demolitionist neutral *grunt DSEMPTY
|
||||
$playeralias demolitionist neutral *pain100 demolitionist/lopain
|
||||
|
|
|
|||
BIN
sounds/demolitionist/demorevive.ogg
Normal file
BIN
sounds/demolitionist/demorevive.ogg
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 32 KiB |
BIN
textures/rgbnoise.png
Normal file
BIN
textures/rgbnoise.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
|
|
@ -38,3 +38,4 @@ version "4.3"
|
|||
#include "zscript/swwm_thiccboolet.zsc"
|
||||
#include "zscript/swwm_tastytreat.zsc"
|
||||
#include "zscript/swwm_deathlydeathcannon.zsc"
|
||||
#include "zscript/swwm_funstuff.zsc"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Class ArmorNugget : SWWMArmor
|
|||
|
||||
override int HandleDamage( int damage, Name damageType, int flags )
|
||||
{
|
||||
double factor = amount*.01;
|
||||
double factor = amount*.1;
|
||||
return int(ceil(damage*factor));
|
||||
}
|
||||
}
|
||||
|
|
@ -57,9 +57,9 @@ Class BlastSuit : SWWMArmor
|
|||
Default
|
||||
{
|
||||
Inventory.Icon "graphics/HUD/Icons/I_BlastSuit.png";
|
||||
Inventory.Amount 200;
|
||||
Inventory.MaxAmount 200;
|
||||
Inventory.InterHubAmount 200;
|
||||
Inventory.Amount 150;
|
||||
Inventory.MaxAmount 150;
|
||||
Inventory.InterHubAmount 150;
|
||||
SWWMArmor.ArmorPriority 2;
|
||||
SWWMArmor.DrainMessage "$D_BLASTSUIT";
|
||||
SWWMArmor.GiverArmor "BlastSuitItem";
|
||||
|
|
@ -67,7 +67,7 @@ Class BlastSuit : SWWMArmor
|
|||
|
||||
override int HandleDamage( int damage, Name damageType, int flags )
|
||||
{
|
||||
double factor = .75;
|
||||
double factor = .3;
|
||||
if ( flags&DMG_EXPLOSION ) factor = 1.-(1.-factor)*.5;
|
||||
return int(ceil(damage*factor));
|
||||
}
|
||||
|
|
@ -102,9 +102,9 @@ Class WarArmor : SWWMArmor
|
|||
Default
|
||||
{
|
||||
Inventory.Icon "graphics/HUD/Icons/I_WarArmor.png";
|
||||
Inventory.Amount 600;
|
||||
Inventory.MaxAmount 600;
|
||||
Inventory.InterHubAmount 600;
|
||||
Inventory.Amount 250;
|
||||
Inventory.MaxAmount 250;
|
||||
Inventory.InterHubAmount 250;
|
||||
SWWMArmor.ArmorPriority 6;
|
||||
SWWMArmor.DrainMessage "$D_WARARMOR";
|
||||
SWWMArmor.GiverArmor "WarArmorItem";
|
||||
|
|
@ -114,8 +114,8 @@ Class WarArmor : SWWMArmor
|
|||
{
|
||||
double factor;
|
||||
// should be enough "elemental" damage types I guess
|
||||
if ( (damageType == 'Fire') || (damageType == 'Ice') || (damageType == 'Slime') || (damageType == 'Lightning') || (damageType == 'Wind') || (damageType == 'Water') ) factor = .9;
|
||||
else factor = .8;
|
||||
if ( (damageType == 'Fire') || (damageType == 'Ice') || (damageType == 'Slime') || (damageType == 'Lightning') || (damageType == 'Wind') || (damageType == 'Water') ) factor = .8;
|
||||
else factor = .5;
|
||||
if ( flags&DMG_EXPLOSION ) factor = 1.-(1.-factor)*.7;
|
||||
return int(ceil(damage*factor));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Class SWWMStats : Thinker
|
|||
PlayerInfo myplayer;
|
||||
int lastspawn, dashcount, boostcount, stompcount, airtime, kills,
|
||||
deaths, damagedealt, damagetaken, mkill, hiscore, topdealt,
|
||||
toptaken;
|
||||
toptaken, skill;
|
||||
double grounddist, airdist, fuelusage, topspeed;
|
||||
Array<WeaponUsage> wstats;
|
||||
Array<Class<Weapon> > alreadygot;
|
||||
|
|
@ -596,8 +596,11 @@ Class SWWMCombatTracker : Thinker
|
|||
if ( newhealth != lasthealth ) updated = level.maptime+35;
|
||||
if ( (mytarget.bISMONSTER || mytarget.player) && !mytarget.bINVISIBLE )
|
||||
{
|
||||
// enemies within 2000mu that have us as target
|
||||
if ( mytarget.target && (mytarget.target.Health > 0) && (mytarget.target.player == players[consoleplayer]) && mytarget.CheckSight(mytarget.target) && (mytarget.Vec3To(mytarget.target).length() < 2000) ) updated = level.maptime+70;
|
||||
if ( mytarget.player ) updated = level.maptime+35;
|
||||
// players (but not voodoo dolls), always visible in sp/coop
|
||||
if ( !deathmatch && mytarget.player && (mytarget.player.mo == mytarget) ) updated = level.maptime+35;
|
||||
// enemies we're directly aiming at within 600mu
|
||||
if ( players[consoleplayer].mo.CheckSight(mytarget) && ((mytarget.Vec3To(players[consoleplayer].mo).length() < 600) || (players[consoleplayer].mo.AimTarget() == mytarget)) ) updated = level.maptime;
|
||||
}
|
||||
lasthealth = newhealth;
|
||||
|
|
@ -1544,6 +1547,12 @@ Class SWWMHandler : EventHandler
|
|||
Demolitionist(players[i].mo).CheckUnderwaterAmb(true);
|
||||
}
|
||||
}
|
||||
PlayerInfo p = players[consoleplayer];
|
||||
Shader.SetEnabled(p,"RagekitShader",false);
|
||||
Shader.SetEnabled(p,"GhostShader",false);
|
||||
Shader.SetEnabled(p,"InvinciShader",false);
|
||||
Shader.SetEnabled(p,"Glitch",false);
|
||||
Shader.SetEnabled(p,"Grain",false);
|
||||
}
|
||||
|
||||
override void PlayerDied( PlayerEvent e )
|
||||
|
|
@ -1596,7 +1605,7 @@ Class SWWMHandler : EventHandler
|
|||
s = new("SWWMStats");
|
||||
s.ChangeStatNum(Thinker.STAT_STATIC);
|
||||
s.myplayer = p;
|
||||
s.lastspawn = gametic;
|
||||
s.lastspawn = level.totaltime;
|
||||
s.favweapon = -1;
|
||||
}
|
||||
// reset some vars
|
||||
|
|
@ -1640,7 +1649,7 @@ Class SWWMHandler : EventHandler
|
|||
}
|
||||
// reset uptime since player had just died
|
||||
SWWMStats s = SWWMStats.Find(e.Thing.player);
|
||||
if ( s ) s.lastspawn = gametic;
|
||||
if ( s ) s.lastspawn = level.totaltime;
|
||||
}
|
||||
|
||||
override void WorldTick()
|
||||
|
|
@ -1865,6 +1874,8 @@ Class SWWMHandler : EventHandler
|
|||
Console.Printf(StringTable.Localize("$SWWM_LASTMONSTER"),e.DamageSource.player.GetUserName(),5000);
|
||||
}
|
||||
spreecount[pnum]++;
|
||||
if ( s && spreecount[pnum] > s.skill )
|
||||
s.skill = spreecount[pnum];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2002,7 +2013,6 @@ Class SWWMHandler : EventHandler
|
|||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
e.Replacement = redpool[Random[Replacement](0,1)];
|
||||
break;
|
||||
case 4:
|
||||
|
|
@ -2023,67 +2033,65 @@ Class SWWMHandler : EventHandler
|
|||
}
|
||||
else if ( (e.Replacee == 'Shell') || (e.Replacee is 'CrossbowAmmo') )
|
||||
{
|
||||
switch( Random[Replacement](0,14) )
|
||||
switch( Random[Replacement](0,13) )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
e.Replacement = redpool[Random[Replacement](1,2)];
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
e.Replacement = greenpool[Random[Replacement](1,2)];
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
e.Replacement = whitepool[Random[Replacement](0,1)];
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
e.Replacement = purplepool[Random[Replacement](0,1)];
|
||||
break;
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
e.Replacement = bluepool[Random[Replacement](0,2)];
|
||||
break;
|
||||
case 14:
|
||||
case 13:
|
||||
e.Replacement = blackpool[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( (e.Replacee == 'ShellBox') || (e.Replacee is 'CrossbowHefty') )
|
||||
{
|
||||
switch( Random[Replacement](0,15) )
|
||||
switch( Random[Replacement](0,14) )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
e.Replacement = redpool[Random[Replacement](2,5)];
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
e.Replacement = greenpool[Random[Replacement](2,4)];
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
e.Replacement = whitepool[Random[Replacement](1,3)];
|
||||
break;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
e.Replacement = purplepool[Random[Replacement](1,2)];
|
||||
break;
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
e.Replacement = bluepool[Random[Replacement](2,3)];
|
||||
break;
|
||||
case 15:
|
||||
case 14:
|
||||
e.Replacement = blackpool[Random[Replacement](0,2)];
|
||||
break;
|
||||
}
|
||||
|
|
@ -2364,6 +2372,27 @@ Class SWWMHandler : EventHandler
|
|||
Shader.SetUniform1f(p,"InvinciShader","str",str);
|
||||
}
|
||||
else Shader.SetEnabled(p,"InvinciShader",false);
|
||||
if ( pc && (mo is 'Demolitionist') )
|
||||
{
|
||||
let demo = Demolitionist(mo);
|
||||
Shader.SetEnabled(p,"Glitch",true);
|
||||
Shader.SetEnabled(p,"Grain",true);
|
||||
Shader.SetUniform1f(p,"Glitch","Timer",(gametic+e.FracTic)/Thinker.TICRATE);
|
||||
Shader.SetUniform1f(p,"Grain","Timer",(gametic+e.FracTic)/Thinker.TICRATE);
|
||||
int lastdmg = (demo.Health>0)?demo.lastdamage:Random[Flicker](60,80);
|
||||
int lastdmgtic = (demo.Health>0)?demo.lastdamagetic:(gametic+Random[Flicker](30,20));
|
||||
double noiz = min(lastdmg*.3*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),.7);
|
||||
Shader.SetUniform1f(p,"Grain","ni",noiz);
|
||||
noiz = min(lastdmg*.16*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),.8);
|
||||
Shader.SetUniform1f(p,"Glitch","str1",noiz);
|
||||
noiz = min(lastdmg*.12*max(0,(lastdmgtic-(gametic+e.Fractic))/35.),3.5);
|
||||
Shader.SetUniform1f(p,"Glitch","str2",noiz);
|
||||
}
|
||||
else
|
||||
{
|
||||
Shader.SetEnabled(p,"Glitch",false);
|
||||
Shader.SetEnabled(p,"Grain",false);
|
||||
}
|
||||
}
|
||||
|
||||
static void DoFlash( Actor camera, Color c, int duration )
|
||||
|
|
|
|||
5
zscript/swwm_funstuff.zsc
Normal file
5
zscript/swwm_funstuff.zsc
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// collectable items that may drop sometimes (future feature)
|
||||
|
||||
Class SWWMCollectable : Inventory
|
||||
{
|
||||
}
|
||||
|
|
@ -48,6 +48,12 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
|
||||
override void FlushNotify()
|
||||
{
|
||||
// flush interpolators (useful since this virtual gets called
|
||||
// when loading saves, too)
|
||||
HealthInter.Reset(CPlayer.Health);
|
||||
ScoreInter.Reset(SWWMCredits.Get(CPlayer));
|
||||
FuelInter.Reset((CPlayer.mo is 'Demolitionist')?int(Demolitionist(CPlayer.mo).dashfuel):0);
|
||||
DashInter.Reset((CPlayer.mo is 'Demolitionist')?int((40-Demolitionist(CPlayer.mo).dashcooldown)*3.):0);
|
||||
if ( level.maptime <= 1 )
|
||||
{
|
||||
// flush ALL messages
|
||||
|
|
@ -683,12 +689,12 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
}
|
||||
if ( ht > 200 )
|
||||
{
|
||||
hw = int(min(ht-100,400)*0.25);
|
||||
hw = int(min(ht-200,300)/3.);
|
||||
Screen.DrawTexture(HealthTex[2],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
||||
}
|
||||
if ( ht > 500 )
|
||||
{
|
||||
hw = int(min(ht-500,500)*0.2);
|
||||
hw = int(min(ht-500,500)/5.);
|
||||
Screen.DrawTexture(HealthTex[3],false,margin+2,ss.y-(margin+15),DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_WindowRight,hw);
|
||||
}
|
||||
int hcolor = Font.CR_RED;
|
||||
|
|
@ -804,6 +810,50 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
// don't do anything
|
||||
}
|
||||
|
||||
private void DrawDeath()
|
||||
{
|
||||
// death prompt
|
||||
let demo = Demolitionist(CPlayer.mo);
|
||||
if ( !demo || (CPlayer.Health > 0) ) return;
|
||||
String str;
|
||||
double alph;
|
||||
int len;
|
||||
double xx, yy;
|
||||
if ( demo.player.viewheight <= 6 )
|
||||
{
|
||||
Screen.Dim("Black",min(demo.deadtimer/80.,1.),0,0,Screen.GetWidth(),Screen.GetHeight());
|
||||
alph = clamp((demo.deadtimer-60)/60.,0.,1.);
|
||||
str = String.Format(StringTable.Localize("$SWWM_URDED"),CPlayer.GetUserName());
|
||||
len = mTewiFont.mFont.StringWidth(str);
|
||||
xx = (ss.x-len)/2.;
|
||||
yy = (ss.y-mTewiFont.mFont.GetHeight()*4)/2.;
|
||||
Screen.DrawText(mTewiFont.mFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
||||
alph = clamp((demo.deadtimer-120)/60.,0.,1.);
|
||||
str = String.Format(StringTable.Localize("$SWWM_URDED2"),CPlayer.GetUserName());
|
||||
len = mTewiFont.mFont.StringWidth(str);
|
||||
xx = (ss.x-len)/2.;
|
||||
yy = ss.y/2.;
|
||||
Screen.DrawText(mTewiFont.mFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
||||
if ( !swwm_revive )
|
||||
return;
|
||||
alph = clamp((demo.deadtimer-200)/60.,0.,1.);
|
||||
str = String.Format(StringTable.Localize("$SWWM_URDED3"),CPlayer.GetUserName());
|
||||
len = mTewiFont.mFont.StringWidth(str);
|
||||
xx = (ss.x-len)/2.;
|
||||
yy = (ss.y+mTewiFont.mFont.GetHeight()*2)/2.;
|
||||
Screen.DrawText(mTewiFont.mFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true,DTA_Alpha,alph);
|
||||
if ( demo.revivefail > level.maptime )
|
||||
{
|
||||
str = StringTable.Localize("$SWWM_REFAIL");
|
||||
len = mTewiFont.mFont.StringWidth(str);
|
||||
xx = (ss.x-len)/2.;
|
||||
yy = ss.y-30;
|
||||
if ( (gametic%12) < 6 )
|
||||
Screen.DrawText(mTewiFont.mFont,Font.CR_RED,xx,yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override void Draw( int state, double TicFrac )
|
||||
{
|
||||
Super.Draw(state,TicFrac);
|
||||
|
|
@ -823,5 +873,6 @@ Class SWWMStatusBar : BaseStatusBar
|
|||
DrawStatus();
|
||||
DrawWeapon();
|
||||
DrawMessages();
|
||||
DrawDeath();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ Class SWWMSpareArmor : Inventory abstract
|
|||
else shouldautouse = CVar.GetCVar('swwm_autousearmor',Owner.player).GetBool();
|
||||
if ( pickup && !shouldautouse ) return false;
|
||||
let cur = Owner.FindInventory(giveme);
|
||||
if ( !cur || (cur.Amount < cur.MaxAmount) )
|
||||
if ( !cur || (cur.Amount <= 0) )
|
||||
{
|
||||
Owner.GiveInventory(giveme,GetDefaultByType(giveme).Amount);
|
||||
if ( UseSound ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_DEFAULT,.6);
|
||||
|
|
@ -356,6 +356,94 @@ Class SWWMWeaponLight : DynamicLight
|
|||
}
|
||||
}
|
||||
|
||||
Class PunchImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_QuakeEx(2,2,2,12,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.3);
|
||||
A_StartSound("demolitionist/punch",CHAN_VOICE);
|
||||
A_SprayDecal("WallCrack",-20);
|
||||
int numpt = Random[Ponch](5,10);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Ponch](-.8,.8),FRandom[Ponch](-.8,.8),FRandom[Ponch](-.8,.8))).unit()*FRandom[Ponch](.1,1.2);
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Ponch](128,192));
|
||||
}
|
||||
numpt = Random[Ponch](4,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Ponch](-1,1),FRandom[Ponch](-1,1),FRandom[Ponch](-1,1)).unit()*FRandom[Ponch](2,8);
|
||||
let s = Spawn("SWWMSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Ponch](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Ponch](-1,1),FRandom[Ponch](-1,1),FRandom[Ponch](-1,1)).unit()*FRandom[Ponch](2,8);
|
||||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class BigPunchImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_QuakeEx(8,8,8,18,0,600,"",QF_RELATIVE|QF_SCALEDOWN,falloff:200,rollIntensity:.9);
|
||||
A_StartSound("pusher/althit",CHAN_VOICE);
|
||||
A_SprayDecal("BigWallCrack",-20);
|
||||
int numpt = Random[Ponch](9,16);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Ponch](-.8,.8),FRandom[Ponch](-.8,.8),FRandom[Ponch](-.8,.8))).unit()*FRandom[Ponch](.1,1.2);
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Ponch](128,192));
|
||||
}
|
||||
numpt = Random[Ponch](9,15);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Ponch](-1,1),FRandom[Ponch](-1,1),FRandom[Ponch](-1,1)).unit()*FRandom[Ponch](2,8);
|
||||
let s = Spawn("SWWMSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Ponch](9,16);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Ponch](-1,1),FRandom[Ponch](-1,1),FRandom[Ponch](-1,1)).unit()*FRandom[Ponch](2,8);
|
||||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
// Base class for all SWWM Weapons
|
||||
Class SWWMWeapon : Weapon abstract
|
||||
{
|
||||
|
|
@ -363,7 +451,7 @@ Class SWWMWeapon : Weapon abstract
|
|||
|
||||
FlagDef NoFirstGive : SWeaponFlags, 0; // don't give ammo on first pickup (for weapons with a clip count)
|
||||
|
||||
override void AttachToOwner (Actor other)
|
||||
override void AttachToOwner( Actor other )
|
||||
{
|
||||
Inventory.AttachToOwner(other);
|
||||
Ammo1 = AddAmmo(Owner,AmmoType1,bNoFirstGive?0:AmmoGive1);
|
||||
|
|
@ -445,16 +533,17 @@ Class SWWMWeapon : Weapon abstract
|
|||
private action bool TryMelee( double angle, int dmg )
|
||||
{
|
||||
FTranslatedLineTarget t;
|
||||
double slope = AimLineAttack(angle,2*DEFMELEERANGE,t,0.,ALF_CHECK3D);
|
||||
double slope = AimLineAttack(angle,1.5*DEFMELEERANGE,t,0.,ALF_CHECK3D);
|
||||
FLineTraceData d;
|
||||
LineTrace(angle,2*DEFMELEERANGE,slope,0,player.viewheight,data:d);
|
||||
LineTrace(angle,1.5*DEFMELEERANGE,slope,0,player.viewheight,data:d);
|
||||
bool raging = CountInv("RagekitPower");
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
bool bloodless = true;
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
self.angle += clamp(diff,-5.,5.);
|
||||
SWWMHandler.DoKnockback(d.HitActor,d.HitDir+(0,0,.2),dmg*2000);
|
||||
if ( CountInv("RagekitPower") )
|
||||
if ( raging )
|
||||
{
|
||||
invoker.bEXTREMEDEATH = true;
|
||||
invoker.bNOEXTREMEDEATH = false;
|
||||
|
|
@ -468,15 +557,22 @@ Class SWWMWeapon : Weapon abstract
|
|||
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'Melee',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
|
||||
invoker.bEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
|
||||
invoker.bNOEXTREMEDEATH = invoker.default.bEXTREMEDEATH;
|
||||
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.25);
|
||||
int quakin = raging?8:2;
|
||||
if ( d.HitActor.player ) d.HitActor.A_QuakeEx(quakin,quakin,quakin,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.125*quakin);
|
||||
if ( !d.HitActor.bNOBLOOD && !d.HitActor.bINVULNERABLE )
|
||||
{
|
||||
d.HitActor.TraceBleed(dmg,invoker);
|
||||
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
|
||||
bloodless = false;
|
||||
}
|
||||
else bloodless = false;
|
||||
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12);
|
||||
A_StartSound(bloodless?"demolitionist/punch":"demolitionist/punchf",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
else
|
||||
{
|
||||
let p = Spawn(raging?"BigPunchImpact":"PunchImpact",d.HitLocation);
|
||||
p.angle = atan2(-d.HitDir.y,-d.HitDir.x);
|
||||
}
|
||||
A_QuakeEx(quakin/2,quakin/2,quakin/2,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.06*quakin);
|
||||
if ( raging ) A_StartSound(bloodless?"pusher/althit":"pusher/altmeat",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
else A_StartSound(bloodless?"demolitionist/punch":"demolitionist/punchf",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_AlertMonsters(300);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -484,7 +580,8 @@ Class SWWMWeapon : Weapon abstract
|
|||
}
|
||||
action void A_Melee( int dmg = 40 )
|
||||
{
|
||||
int maxang = CountInv("RagekitPower")?24:12;
|
||||
bool raging = CountInv("RagekitPower");
|
||||
int maxang = raging?18:12;
|
||||
for ( int i=0; i<maxang; i++ ) if ( TryMelee(angle+i*(45./16),dmg) || TryMelee(angle-i*(45./16),dmg) ) return;
|
||||
// check for walls instead
|
||||
FTranslatedLineTarget t;
|
||||
|
|
@ -492,10 +589,29 @@ Class SWWMWeapon : Weapon abstract
|
|||
FLineTraceData d;
|
||||
LineTrace(angle,DEFMELEERANGE,slope,TRF_THRUACTORS,player.viewheight,data:d);
|
||||
if ( d.HitType == TRACE_HitNone ) return;
|
||||
if ( d.HitType == TRACE_HitWall )
|
||||
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation-d.HitDir*4);
|
||||
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12);
|
||||
A_StartSound("demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
Vector3 HitNormal = -d.HitDir;
|
||||
if ( d.HitType == TRACE_HitFloor )
|
||||
{
|
||||
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.top.Normal;
|
||||
else HitNormal = d.HitSector.floorplane.Normal;
|
||||
}
|
||||
else if ( d.HitType == TRACE_HitCeiling )
|
||||
{
|
||||
if ( d.Hit3DFloor ) HitNormal = -d.Hit3DFloor.bottom.Normal;
|
||||
else HitNormal = d.HitSector.ceilingplane.Normal;
|
||||
}
|
||||
else if ( d.HitType == TRACE_HitWall )
|
||||
{
|
||||
HitNormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
|
||||
if ( !d.LineSide ) HitNormal *= -1;
|
||||
d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation+HitNormal*4);
|
||||
}
|
||||
let p = Spawn(raging?"BigPunchImpact":"PunchImpact",d.HitLocation+HitNormal*4);
|
||||
p.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
p.pitch = asin(-HitNormal.z);
|
||||
int quakin = raging?4:1;
|
||||
A_QuakeEx(quakin,quakin,quakin,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.12*quakin);
|
||||
A_StartSound(raging?"pusher/althit":"demolitionist/punch",CHAN_WEAPON,CHANF_OVERLAP);
|
||||
A_AlertMonsters(100);
|
||||
}
|
||||
override void PlayUpSound( Actor origin )
|
||||
|
|
|
|||
|
|
@ -331,7 +331,6 @@ Class PusherWeapon : SWWMWeapon
|
|||
A_QuakeEx(3,3,3,7,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
|
||||
A_AlertMonsters(1200);
|
||||
int dmg = int(3+invoker.chargelevel*2);
|
||||
bool bloodless = false;
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
|
|
@ -351,6 +350,8 @@ Class PusherWeapon : SWWMWeapon
|
|||
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
|
||||
d.HitActor.A_StartSound("pusher/meat",CHAN_ITEMEXTRA,CHANF_OVERLAP);
|
||||
}
|
||||
// move towards target
|
||||
vel.xy += Vec2To(d.HitActor).unit();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -413,7 +414,6 @@ Class PusherWeapon : SWWMWeapon
|
|||
A_QuakeEx(8,8,8,12,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.8);
|
||||
A_AlertMonsters(1600);
|
||||
int dmg = int(80*invoker.chargelevel);
|
||||
bool bloodless = false;
|
||||
if ( d.HitType == TRACE_HitActor )
|
||||
{
|
||||
double diff = deltaangle(self.angle,AngleTo(d.HitActor));
|
||||
|
|
|
|||
|
|
@ -430,7 +430,6 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
if ( players[consoleplayer].Health <= 0 )
|
||||
{
|
||||
// ded
|
||||
MenuSound("menu/democlose");
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
|
@ -440,7 +439,7 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
// alphabetically sorted inventory
|
||||
for ( Inventory inv=players[consoleplayer].mo.Inv; inv; inv=inv.Inv )
|
||||
{
|
||||
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) ) continue;
|
||||
if ( (inv.Amount <= 0) || !inv.SpawnState.ValidateSpriteFrame() || (inv is 'Key') || (inv is 'BasicArmor') || (inv is 'HexenArmor') || (inv is 'Powerup') || (inv is 'SWWMArmor') || (!(inv is 'Ammo') && !(inv is 'Weapon') && !inv.bINVBAR) && !(inv is 'HammerspaceEmbiggener') && !(inv is 'SWWMCollectable') ) continue;
|
||||
String tag = inv.GetTag();
|
||||
bool greater = false;
|
||||
for ( int i=0; i<invlist.Size(); i++ )
|
||||
|
|
@ -796,9 +795,9 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
xx = 9;
|
||||
yy = 23;
|
||||
// wish I could use macros for this
|
||||
int thour = ((gametic-stats.lastspawn)/(3600*Thinker.TICRATE));
|
||||
int tmin = ((gametic-stats.lastspawn)/(60*Thinker.TICRATE))%60;
|
||||
int tsec = ((gametic-stats.lastspawn)/Thinker.TICRATE)%60;
|
||||
int thour = ((level.totaltime-stats.lastspawn)/(3600*Thinker.TICRATE));
|
||||
int tmin = ((level.totaltime-stats.lastspawn)/(60*Thinker.TICRATE))%60;
|
||||
int tsec = ((level.totaltime-stats.lastspawn)/Thinker.TICRATE)%60;
|
||||
str = String.Format("\cx%s\c-%02d\cu:\c-%02d\cu:\c-%02d",StringTable.Localize("$SWWM_STATUPTIME"),thour,tmin,tsec);
|
||||
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += 16;
|
||||
|
|
@ -852,6 +851,9 @@ Class SWWMKnowledgeBaseMenu : GenericMenu
|
|||
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATMKILL"),stats.mkill);
|
||||
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += 16;
|
||||
str = String.Format("\cx%s\c-%d",StringTable.Localize("$SWWM_STATSKILL"),stats.skill);
|
||||
Screen.DrawText(TewiFont,Font.CR_WHITE,origin.x+xx,origin.y+yy,str,DTA_VirtualWidthF,ss.x,DTA_VirtualHeightF,ss.y,DTA_KeepRatio,true);
|
||||
yy += 16;
|
||||
str = String.Format("\cx%s\c-",StringTable.Localize("$SWWM_STATFAVWEAP"));
|
||||
if ( stats.favweapon == -1 ) str = str.."N/A";
|
||||
else
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Class Demolitionist : PlayerPawn
|
|||
bool sendtoground;
|
||||
bool key_reentrant;
|
||||
|
||||
int lastdamage;
|
||||
int lastdamage, lastdamagetic;
|
||||
bool lastground;
|
||||
int lastgroundtic;
|
||||
double lastvelz, prevvelz;
|
||||
|
|
@ -33,6 +33,7 @@ Class Demolitionist : PlayerPawn
|
|||
};
|
||||
|
||||
int lastunder;
|
||||
int deadtimer, revivefail;
|
||||
|
||||
Default
|
||||
{
|
||||
|
|
@ -503,7 +504,8 @@ Class Demolitionist : PlayerPawn
|
|||
// lucky collar
|
||||
if ( Health < 25 ) damage /= 4;
|
||||
if ( source == self ) damage /= 2;
|
||||
int lastdamage = Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
||||
lastdamage = Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
||||
lastdamagetic = max(lastdamagetic,gametic+clamp(lastdamage,10,80));
|
||||
if ( (lastdamage > 0) && (PainChance == 0) && (level.maptime>lastmpain) )
|
||||
{
|
||||
lastmpain = level.maptime;
|
||||
|
|
@ -627,7 +629,6 @@ Class Demolitionist : PlayerPawn
|
|||
double spd = vel.length();
|
||||
if ( spd > 10. ) vel = (vel+accel/TICRATE).unit()*spd;
|
||||
else vel = vel+accel/TICRATE;
|
||||
player.jumptics = -2;
|
||||
}
|
||||
if ( abs(roll) > 0. ) roll += clamp(deltaangle(roll,0),-3.,3.);
|
||||
}
|
||||
|
|
@ -635,7 +636,7 @@ Class Demolitionist : PlayerPawn
|
|||
guidepitch *= .9;
|
||||
guideroll *= .9;
|
||||
// anchor to ground when going down steps
|
||||
if ( !player.onground && !bFly && !bFlyCheat && (waterlevel < 2) && (abs(pos.z-floorz) <= maxdropoffheight) && (player.jumptics == 0) && (vel.z < 0) )
|
||||
if ( lastground && !player.onground && !bFly && !bFlyCheat && (waterlevel < 2) && (abs(pos.z-floorz) <= maxdropoffheight) && (player.jumptics == 0) && (vel.z < 0) )
|
||||
{
|
||||
ssup = max(0,(pos.z-floorz));
|
||||
SetOrigin(Vec2OffsetZ(0,0,floorz),true);
|
||||
|
|
@ -801,8 +802,78 @@ Class Demolitionist : PlayerPawn
|
|||
}
|
||||
override void DeathThink()
|
||||
{
|
||||
// TODO reboot mechanic, death camera that doesn't move body
|
||||
Super.DeathThink();
|
||||
player.Uncrouch();
|
||||
TickPSprites();
|
||||
player.onground = (pos.Z<=floorz);
|
||||
// ded (demo-chan falls faster tho)
|
||||
player.deltaviewheight = 0;
|
||||
if ( player.viewheight > 6 ) player.viewheight -= 3;
|
||||
if ( player.viewheight < 6 ) player.viewheight = 6;
|
||||
// center pitch
|
||||
double dpitch = clamp(deltaangle(pitch,0),-6,6);
|
||||
if ( abs(dpitch) < 3. ) pitch = 0.;
|
||||
else pitch += dpitch;
|
||||
// add roll
|
||||
double droll = clamp(deltaangle(roll,50)*.5,-5,5);
|
||||
if ( abs(droll) < 2. ) roll = 50.;
|
||||
else roll += droll;
|
||||
player.mo.CalcHeight();
|
||||
if ( player.damagecount ) player.damagecount--;
|
||||
if ( player.poisoncount ) player.poisoncount--;
|
||||
if ( player.viewheight <= 6 )
|
||||
{
|
||||
deadtimer++;
|
||||
if ( multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn) )
|
||||
{
|
||||
// standard behaviour, respawn normally
|
||||
if ( (Level.maptime >= player.respawn_time) || ((player.cmd.buttons&BT_USE) && !player.Bot) )
|
||||
{
|
||||
player.cls = null;
|
||||
player.playerstate = PST_REBORN;
|
||||
if ( special1 > 2 ) special1 = 0;
|
||||
}
|
||||
}
|
||||
else if ( (player.cmd.buttons&BT_USE) && (deadtimer > 150) )
|
||||
{
|
||||
// reload save
|
||||
player.cls = null;
|
||||
player.playerstate = PST_ENTER;
|
||||
if ( special1 > 2 ) special1 = 0;
|
||||
}
|
||||
else if ( (player.cmd.buttons&BT_ATTACK) && (deadtimer > 150) && swwm_revive )
|
||||
{
|
||||
// reboot (if possible)
|
||||
if ( !FindInventory("ReviveCooldown") )
|
||||
{
|
||||
player.Resurrect();
|
||||
roll = 0;
|
||||
let s = Spawn("DemolitionistShockwave",pos);
|
||||
s.target = self;
|
||||
s.special1 = 30;
|
||||
ReactionTime = 17;
|
||||
A_Stop();
|
||||
A_AlertMonsters();
|
||||
if ( player == players[consoleplayer] )
|
||||
{
|
||||
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP);
|
||||
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.7);
|
||||
A_StartSound("demolitionist/hardland",CHAN_FOOTSTEP,CHANF_OVERLAP,pitch:.4);
|
||||
}
|
||||
SWWMHandler.DoFlash(self,Color(255,255,255,255),10);
|
||||
SWWMHandler.DoFlash(self,Color(255,128,192,255),30);
|
||||
if ( special1 > 2 ) special1 = 0;
|
||||
if ( swwm_revivecooldown > 0 )
|
||||
GiveInventory("ReviveCooldown",1);
|
||||
}
|
||||
else
|
||||
{
|
||||
A_StartSound("*usefail",CHAN_ITEM,CHANF_UI|CHANF_LOCAL);
|
||||
SWWMHandler.DoFlash(self,Color(64,255,0,0),30);
|
||||
revivefail = level.maptime+20;
|
||||
}
|
||||
}
|
||||
}
|
||||
else deadtimer = 0;
|
||||
}
|
||||
override void PlayIdle()
|
||||
{
|
||||
|
|
@ -1480,3 +1551,38 @@ Class DemolitionistShockwave : Actor
|
|||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class ReviveCooldown : Powerup
|
||||
{
|
||||
Default
|
||||
{
|
||||
Inventory.Icon "graphics/HUD/Icons/I_Revive.png";
|
||||
Powerup.Duration -30;
|
||||
}
|
||||
|
||||
override void Tick()
|
||||
{
|
||||
if ( !Owner ) Destroy();
|
||||
if ( Owner.Health <= 0 ) return; // timer does not go down when dead
|
||||
if ( (EffectTics == 0) || ((EffectTics > 0) && (--EffectTics == 0)) )
|
||||
Destroy ();
|
||||
}
|
||||
override void InitEffect()
|
||||
{
|
||||
Super.InitEffect();
|
||||
// adjust the duration
|
||||
EffectTics = max(0,swwm_revivecooldown)*Thinker.TICRATE;
|
||||
}
|
||||
override void EndEffect()
|
||||
{
|
||||
Super.EndEffect();
|
||||
if ( !Owner ) return;
|
||||
Owner.A_StartSound("demolitionist/revive",CHAN_ITEMEXTRA);
|
||||
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_REFAIL"));
|
||||
}
|
||||
override void OwnerDied()
|
||||
{
|
||||
// do nothing, this "powerup" is preserved on death
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -711,7 +711,7 @@ Class RagekitPower : Powerup
|
|||
|
||||
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags )
|
||||
{
|
||||
if ( !passive && ((damageType == 'Melee') || (damageType == 'Dash') || (damageType == 'GroundPound')) )
|
||||
if ( !passive && ((damageType == 'Melee') || (damageType == 'Jump') || (damageType == 'Dash') || (damageType == 'GroundPound')) )
|
||||
{
|
||||
newdamage = damage*8;
|
||||
if ( level.maptime > lasteffect+5 )
|
||||
|
|
|
|||
|
|
@ -820,6 +820,600 @@ Class SaltBeam : Actor
|
|||
}
|
||||
}
|
||||
|
||||
Class OnFireLight : DynamicLight
|
||||
{
|
||||
OnFire of;
|
||||
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
if ( !of || !of.victim )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
Args[0] = clamp(of.Amount*4,0,255);
|
||||
Args[1] = clamp(of.Amount*2,0,128);
|
||||
Args[3] = int(max(of.victim.radius,of.victim.height)*2.+20+clamp(of.amount/5,0,80));
|
||||
SetOrigin(of.Victim.Vec3Offset(0,0,of.Victim.Height/2),true);
|
||||
}
|
||||
}
|
||||
|
||||
Class OnFire : Actor
|
||||
{
|
||||
Actor victim, instigator, lite;
|
||||
int amount, cnt, delay;
|
||||
double oangle;
|
||||
|
||||
override void Tick()
|
||||
{
|
||||
if ( !victim )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( victim.waterlevel > 0 )
|
||||
{
|
||||
if ( lite ) lite.Destroy();
|
||||
amount -= int(victim.waterlevel**2);
|
||||
}
|
||||
if ( (victim.Health <= 0) || ((victim is 'FlamingChunk') && !victim.bMISSILE) ) amount = min(amount,100);
|
||||
if ( !(level.maptime%3) )
|
||||
amount--;
|
||||
if ( victim.player ) amount -= int(abs(actor.deltaangle(victim.angle,oangle))/30);
|
||||
oangle = victim.angle;
|
||||
if ( amount < -30 )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( cnt > 0 ) cnt--;
|
||||
else
|
||||
{
|
||||
cnt = 10;
|
||||
if ( victim.bSHOOTABLE && (victim.Health > 0) && (amount > 0) )
|
||||
victim.DamageMobj(self,instigator,clamp(int(amount*(victim.bBOSS?0.05:0.15)),1,20),'Fire',DMG_THRUSTLESS); // the only reason why we need to use an actor
|
||||
if ( !victim )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ( delay > 0 ) delay--;
|
||||
if ( level.maptime%5 ) return;
|
||||
int numpt = clamp(int(Random[FlameT](2,4)*amount*0.02),1,4);
|
||||
double mult = max(victim.radius,victim.height)/30.;
|
||||
numpt = int(clamp(numpt*mult**.5,1,5));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pos = victim.Vec3Offset(FRandom[FlameT](-victim.radius,victim.radius)*0.8,FRandom[FlameT](-victim.radius,victim.radius)*0.8,FRandom[FlameT](victim.height*0.2,victim.height*0.8));
|
||||
double ang = FRandom[FlameT](0,360);
|
||||
double pt = FRandom[FlameT](-90,90);
|
||||
if ( amount > 0 )
|
||||
{
|
||||
let c = victim.Spawn("OnFireTrail",pos);
|
||||
c.scale *= max(.3,mult*0.5);
|
||||
c.vel = victim.vel*0.5+(cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[FlameT](.5,2.)*c.scale.x;
|
||||
}
|
||||
let s = victim.Spawn("SWWMSmoke",pos);
|
||||
s.scale *= max(1.,1.6*mult);
|
||||
s.alpha *= min(amount+30,100)*0.02;
|
||||
s.vel = victim.vel*0.5+(cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*FRandom[FlameT](.2,.6)*s.scale.x;
|
||||
}
|
||||
if ( amount <= 0 ) return;
|
||||
// spread to nearby actors
|
||||
let bt = BlockThingsIterator.Create(victim);
|
||||
while ( bt.Next() )
|
||||
{
|
||||
let t = bt.Thing;
|
||||
if ( !t || !t.bSHOOTABLE || (t.Health <= 0) || (t == victim) || ((t == instigator) && (delay > 0)) || (victim.Distance3D(t) > victim.radius+t.radius+20) || !victim.CheckSight(t) ) continue;
|
||||
int amt = max(1,amount/10);
|
||||
if ( IsOnFire(t) ) amt = min(5,amt);
|
||||
Apply(t,instigator,amt);
|
||||
}
|
||||
}
|
||||
|
||||
static OnFire Apply( Actor victim, Actor instigator, int amount, int delay = 0 )
|
||||
{
|
||||
if ( amount <= 0 ) return null;
|
||||
let ti = ThinkerIterator.Create("OnFire");
|
||||
OnFire t;
|
||||
while ( t = OnFire(ti.Next()) )
|
||||
{
|
||||
if ( t.victim != victim ) continue;
|
||||
if ( instigator ) t.instigator = instigator;
|
||||
t.amount = min(500,t.amount+amount);
|
||||
t.cnt = min(t.cnt,5);
|
||||
return t;
|
||||
}
|
||||
t = OnFire(Spawn("OnFire"));
|
||||
t.victim = victim;
|
||||
t.instigator = instigator;
|
||||
t.amount = min(500,amount);
|
||||
t.cnt = 1;
|
||||
// for chunks
|
||||
t.delay = delay;
|
||||
t.lite = Actor.Spawn("OnFireLight",victim.pos);
|
||||
OnFireLight(t.lite).of = t;
|
||||
t.oangle = victim.angle;
|
||||
return t;
|
||||
}
|
||||
|
||||
static bool IsOnFire( Actor victim )
|
||||
{
|
||||
let ti = ThinkerIterator.Create("OnFire");
|
||||
OnFire t;
|
||||
while ( t = OnFire(ti.Next()) )
|
||||
{
|
||||
if ( t.victim != victim ) continue;
|
||||
return (t.amount>0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Default
|
||||
{
|
||||
+NOGRAVITY;
|
||||
+NOBLOCKMAP;
|
||||
+DONTSPLASH;
|
||||
Obituary "$O_SPREADGUN_BLACK";
|
||||
}
|
||||
}
|
||||
|
||||
Class OnFireTrailLight : PaletteLight
|
||||
{
|
||||
Default
|
||||
{
|
||||
Tag "HellExpl";
|
||||
Args 0,0,0,40;
|
||||
ReactionTime 40;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
Super.Tick();
|
||||
Args[0] /= 10;
|
||||
Args[1] /= 10;
|
||||
Args[2] /= 10;
|
||||
Args[3] += 3;
|
||||
if ( !target || (target.waterlevel > 0) )
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
SetOrigin(target.pos,true);
|
||||
}
|
||||
}
|
||||
|
||||
Class OnFireTrail : Actor
|
||||
{
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
Scale.x *= RandomPick[ExploS](-1,1);
|
||||
Scale.y *= RandomPick[ExploS](-1,1);
|
||||
roll = FRandom[ExploS](0,360);
|
||||
}
|
||||
action void A_Flame()
|
||||
{
|
||||
if ( waterlevel > 0 )
|
||||
vel *= 0.9;
|
||||
else
|
||||
{
|
||||
vel *= 0.98;
|
||||
vel.z += 0.2*abs(scale.x);
|
||||
}
|
||||
if ( waterlevel > 0 )
|
||||
{
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = (FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2));
|
||||
s.vel += vel*0.3;
|
||||
s.alpha *= alpha*4;
|
||||
s.scale *= 0.5+abs(scale.x)*(.5+GetAge()/6.);
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
if ( !Random[FlameT](0,int(40*(default.alpha-alpha))) )
|
||||
{
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = (FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2),FRandom[FlameT](-0.2,0.2));
|
||||
s.vel += vel*0.3;
|
||||
s.alpha *= alpha*4;
|
||||
s.scale *= 0.5+abs(scale.x)*(.5+GetAge()/6.);
|
||||
}
|
||||
}
|
||||
Default
|
||||
{
|
||||
RenderStyle "Add";
|
||||
Speed 2;
|
||||
Radius 4;
|
||||
Height 4;
|
||||
Alpha 0.3;
|
||||
Scale 0.6;
|
||||
+NOBLOCKMAP;
|
||||
+NOGRAVITY;
|
||||
+NOFRICTION;
|
||||
+SLIDESONWALLS;
|
||||
+ACTIVATEPCROSS;
|
||||
+ACTIVATEIMPACT;
|
||||
+NOTELEPORT;
|
||||
+FORCEXYBILLBOARD;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+DROPOFF;
|
||||
+NOBLOCKMONST;
|
||||
+DONTSPLASH;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
XFLM ABCDEFGHIJKLMNOPQRST 1 Bright
|
||||
{
|
||||
A_Flame();
|
||||
A_SetScale(scale.x*0.98);
|
||||
A_FadeOut(0.01);
|
||||
vel.z += 0.1;
|
||||
}
|
||||
Wait;
|
||||
}
|
||||
}
|
||||
|
||||
Class FlamingChunk : Actor
|
||||
{
|
||||
double rollvel;
|
||||
OnFire myfire;
|
||||
Vector3 oldvel;
|
||||
int deadtimer;
|
||||
Actor lasthit;
|
||||
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
rollvel = FRandom[FlameT](10,30)*RandomPick[FlameT](-1,1);
|
||||
Scale *= FRandom[FlameT](.8,1.2);
|
||||
if ( waterlevel <= 0 ) myfire = OnFire.Apply(self,target,int(120*scale.x),6);
|
||||
frame = Random[FlameT](0,5);
|
||||
}
|
||||
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
|
||||
{
|
||||
if ( target != lasthit )
|
||||
{
|
||||
OnFire.Apply(target,self.target,myfire?myfire.Amount:1);
|
||||
lasthit = target;
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
oldvel = vel;
|
||||
Super.Tick();
|
||||
if ( isFrozen() ) return;
|
||||
if ( InStateSequence(CurState,ResolveState("Death")) )
|
||||
{
|
||||
deadtimer++;
|
||||
if ( deadtimer > 300 ) A_FadeOut(0.05);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void A_HandleBounce()
|
||||
{
|
||||
bHITOWNER = true;
|
||||
lasthit = null;
|
||||
Vector3 HitNormal = -vel.unit();
|
||||
F3DFloor ff;
|
||||
if ( BlockingFloor )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(CurSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
||||
ff = CurSector.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.top.Normal;
|
||||
else HitNormal = BlockingFloor.floorplane.Normal;
|
||||
}
|
||||
else if ( BlockingCeiling )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(CurSector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
||||
ff = CurSector.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.bottom.Normal;
|
||||
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
||||
}
|
||||
else if ( BlockingLine )
|
||||
{
|
||||
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
||||
if ( !BlockingLine.sidedef[1] || (CurSector == BlockingLine.frontsector) )
|
||||
HitNormal *= -1;
|
||||
}
|
||||
else if ( BlockingMobj )
|
||||
{
|
||||
Vector3 diff = level.Vec3Diff(BlockingMobj.Vec3Offset(0,0,BlockingMobj.Height/2),pos);
|
||||
HitNormal = diff.unit();
|
||||
}
|
||||
// undo the bounce, we need to hook in our own
|
||||
vel = oldvel;
|
||||
// re-do the bounce with our formula
|
||||
vel = .8*((vel dot HitNormal)*HitNormal*-1.2+vel);
|
||||
gravity = .35;
|
||||
if ( (vel.length() < 5) && (pos.z <= floorz) )
|
||||
{
|
||||
ClearBounce();
|
||||
ExplodeMissile();
|
||||
}
|
||||
rollvel = FRandom[FlameT](10,30)*RandomPick[FlameT](-1,1);
|
||||
}
|
||||
Default
|
||||
{
|
||||
Obituary "$O_SPREADGUN_BLACK";
|
||||
DamageFunction 1;
|
||||
DamageType 'Fire';
|
||||
Radius 4;
|
||||
Height 4;
|
||||
Speed 15;
|
||||
Gravity 0.2;
|
||||
PROJECTILE;
|
||||
-NOGRAVITY;
|
||||
+ROLLSPRITE;
|
||||
+ROLLCENTER;
|
||||
+EXPLODEONWATER;
|
||||
+FORCERADIUSDMG;
|
||||
+FORCEXYBILLBOARD;
|
||||
+NODAMAGETHRUST;
|
||||
+INTERPOLATEANGLES;
|
||||
+RIPPER;
|
||||
+BLOODLESSIMPACT;
|
||||
+NOTELEPORT;
|
||||
+BOUNCEONWALLS;
|
||||
+BOUNCEONFLOORS;
|
||||
+BOUNCEONCEILINGS;
|
||||
+USEBOUNCESTATE;
|
||||
BounceFactor 1.0;
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
JUNK # 1 { roll += rollvel; }
|
||||
Wait;
|
||||
Bounce:
|
||||
JUNK # 0 A_HandleBounce();
|
||||
Goto Spawn;
|
||||
Death:
|
||||
JUNK # -1 { bMOVEWITHSECTOR = true; }
|
||||
Stop;
|
||||
Dummy:
|
||||
JUNK ABCDEF -1;
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class BallImpact : Actor
|
||||
{
|
||||
Default
|
||||
{
|
||||
Radius 0.1;
|
||||
Height 0;
|
||||
+NOGRAVITY;
|
||||
+NOCLIP;
|
||||
+DONTSPLASH;
|
||||
+NOTELEPORT;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_QuakeEx(3,3,3,12,0,200,"",QF_RELATIVE|QF_SCALEDOWN,falloff:100,rollIntensity:.3);
|
||||
A_StartSound("spreadgun/ball",CHAN_VOICE);
|
||||
A_SprayDecal("WallCrack",-20);
|
||||
int numpt = Random[Spreadgun](5,10);
|
||||
Vector3 x = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (x+(FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8),FRandom[Spreadgun](-.8,.8))).unit()*FRandom[Spreadgun](.1,1.2);
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.vel = pvel;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](128,192));
|
||||
}
|
||||
numpt = Random[Spreadgun](4,12);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMSpark",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
numpt = Random[Spreadgun](4,8);
|
||||
for ( int i=0; i<numpt; i++ )
|
||||
{
|
||||
Vector3 pvel = (FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1),FRandom[Spreadgun](-1,1)).unit()*FRandom[Spreadgun](2,8);
|
||||
let s = Spawn("SWWMChip",pos);
|
||||
s.vel = pvel;
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Class TheBall : Actor
|
||||
{
|
||||
double heat;
|
||||
int deadtimer;
|
||||
Vector3 oldvel;
|
||||
Actor lasthit;
|
||||
|
||||
Default
|
||||
{
|
||||
Obituary "$O_SPREADGUN_PURPLE";
|
||||
+NOBLOCKMAP;
|
||||
+BOUNCEONWALLS;
|
||||
+BOUNCEONFLOORS;
|
||||
+BOUNCEONCEILINGS;
|
||||
+USEBOUNCESTATE;
|
||||
+MISSILE;
|
||||
+NODAMAGETHRUST;
|
||||
+NOTELEPORT;
|
||||
-NOGRAVITY;
|
||||
Speed 80;
|
||||
Gravity 0.1;
|
||||
BounceFactor 1.0;
|
||||
Radius 2;
|
||||
Height 2;
|
||||
}
|
||||
override int SpecialMissileHit( Actor victim )
|
||||
{
|
||||
if ( (vel.length() <= 5) || ((victim == target) && !bHITOWNER) || (victim == lasthit) || (!victim.bSHOOTABLE && !victim.bSOLID) )
|
||||
return 1;
|
||||
// check if we should rip or bounce
|
||||
// girthitude
|
||||
double girth = (victim.radius+victim.height)/2.*max(50,victim.mass);
|
||||
// how hard this damn thing is going to slam
|
||||
double slamforce = vel.length()*350.+heat*120;
|
||||
SWWMHandler.DoKnockback(victim,vel.unit(),slamforce);
|
||||
bool bleeds = (victim && !victim.bINVULNERABLE && !victim.bNOBLOOD && victim.bSHOOTABLE);
|
||||
int dmg = int(vel.length()*4.2+heat*80);
|
||||
dmg = victim.DamageMobj(self,target,dmg,'Concussion',DMG_THRUSTLESS);
|
||||
Vector3 dir = -vel.unit();
|
||||
// slam jam
|
||||
if ( bleeds )
|
||||
{
|
||||
A_StartSound("spreadgun/ballf",CHAN_VOICE,CHANF_OVERLAP,(vel.length()/75.)**.5);
|
||||
victim.TraceBleed(dmg,self);
|
||||
SpawnBlood(pos,atan2(dir.y,dir.x),dmg);
|
||||
}
|
||||
else
|
||||
{
|
||||
A_StartSound("spreadgun/ball",CHAN_VOICE,CHANF_OVERLAP,(vel.length()/75.)**.5);
|
||||
if ( vel.length() > 15 )
|
||||
{
|
||||
let s = Spawn("BallImpact",pos);
|
||||
s.angle = atan2(dir.y,dir.x);
|
||||
s.pitch = asin(-dir.z);
|
||||
}
|
||||
}
|
||||
if ( slamforce > girth )
|
||||
{
|
||||
vel *= .8;
|
||||
return 1;
|
||||
}
|
||||
// force bounce
|
||||
BlockingMobj = victim;
|
||||
A_HandleBounce();
|
||||
lasthit = victim;
|
||||
// pretend to pass through
|
||||
return 1;
|
||||
}
|
||||
override void PostBeginPlay()
|
||||
{
|
||||
Super.PostBeginPlay();
|
||||
A_StartSound("pusher/fly",CHAN_WEAPON,CHANF_LOOPING,.6,3.,2.);
|
||||
heat = 1.;
|
||||
}
|
||||
override void Tick()
|
||||
{
|
||||
oldvel = vel;
|
||||
Super.Tick();
|
||||
if ( isFrozen() ) return;
|
||||
if ( InStateSequence(CurState,ResolveState("Death")) )
|
||||
{
|
||||
deadtimer++;
|
||||
if ( deadtimer > 300 ) A_FadeOut(0.05);
|
||||
return;
|
||||
}
|
||||
heat -= 0.004+0.0004*vel.length();
|
||||
A_SoundVolume(CHAN_WEAPON,vel.length()/75.);
|
||||
if ( heat <= 0 ) return;
|
||||
let s = Spawn("SWWMSmoke",pos);
|
||||
s.alpha *= heat;
|
||||
}
|
||||
void A_HandleBounce()
|
||||
{
|
||||
bHITOWNER = true;
|
||||
lasthit = null;
|
||||
Vector3 HitNormal = -vel.unit();
|
||||
F3DFloor ff;
|
||||
if ( BlockingFloor )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(CurSector.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
||||
ff = CurSector.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.top.Normal;
|
||||
else HitNormal = BlockingFloor.floorplane.Normal;
|
||||
}
|
||||
else if ( BlockingCeiling )
|
||||
{
|
||||
// find closest 3d floor for its normal
|
||||
for ( int i=0; i<CurSector.Get3DFloorCount(); i++ )
|
||||
{
|
||||
if ( !(CurSector.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
||||
ff = CurSector.Get3DFloor(i);
|
||||
break;
|
||||
}
|
||||
if ( ff ) HitNormal = -ff.bottom.Normal;
|
||||
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
||||
}
|
||||
else if ( BlockingLine )
|
||||
{
|
||||
HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
||||
if ( !BlockingLine.sidedef[1] || (CurSector == BlockingLine.frontsector) )
|
||||
HitNormal *= -1;
|
||||
}
|
||||
else if ( BlockingMobj )
|
||||
{
|
||||
Vector3 diff = level.Vec3Diff(BlockingMobj.Vec3Offset(0,0,BlockingMobj.Height/2),pos);
|
||||
HitNormal = diff.unit();
|
||||
}
|
||||
// undo the bounce, we need to hook in our own
|
||||
vel = oldvel;
|
||||
// re-do the bounce with our formula
|
||||
double bcefact = .9;
|
||||
if ( BlockingMobj )
|
||||
{
|
||||
bcefact *= .7;
|
||||
if ( !BlockingMobj.bINVULNERABLE && !BlockingMobj.bNOBLOOD )
|
||||
bcefact *= .6;
|
||||
}
|
||||
vel = bcefact*((vel dot HitNormal)*HitNormal*-1.2+vel);
|
||||
// slam jam
|
||||
if ( !BlockingMobj )
|
||||
{
|
||||
A_StartSound("spreadgun/ball",CHAN_VOICE,CHANF_OVERLAP,max(0.,(vel.length()/60.-.1))**.5);
|
||||
if ( vel.length() > 15 )
|
||||
{
|
||||
let s = Spawn("BallImpact",pos);
|
||||
s.angle = atan2(HitNormal.y,HitNormal.x);
|
||||
s.pitch = asin(-HitNormal.z);
|
||||
}
|
||||
}
|
||||
gravity = .35;
|
||||
if ( (vel.length() < 5) && (pos.z <= floorz) )
|
||||
{
|
||||
ClearBounce();
|
||||
ExplodeMissile();
|
||||
}
|
||||
}
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
XZW1 A -1;
|
||||
Stop;
|
||||
Bounce:
|
||||
XZW1 A 0 A_HandleBounce();
|
||||
Goto Spawn;
|
||||
Death:
|
||||
XZW1 A -1
|
||||
{
|
||||
bMOVEWITHSECTOR = true;
|
||||
A_StopSound(CHAN_WEAPON);
|
||||
}
|
||||
Stop;
|
||||
}
|
||||
}
|
||||
|
||||
Class Spreadgun : SWWMWeapon
|
||||
{
|
||||
bool fired; // shell was used
|
||||
|
|
@ -1190,7 +1784,39 @@ Class Spreadgun : SWWMWeapon
|
|||
Console.Printf("\cg// TODO Napalm Rounds\c-");
|
||||
break;
|
||||
case 5:
|
||||
Console.Printf("\cg// TODO The Ball\c-");
|
||||
a = FRandom[Spreadgun](0,360);
|
||||
s = FRandom[Spreadgun](0,.03);
|
||||
let b = Spawn("TheBall",origin);
|
||||
b.target = self;
|
||||
b.angle = atan2(x2.y,x2.x);
|
||||
b.pitch = asin(-x2.z);
|
||||
b.vel = x2*b.speed;
|
||||
for ( int i=0; i<4; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMViewSmoke",origin);
|
||||
SWWMViewSmoke(s).ofs = (15,3,-3);
|
||||
s.target = self;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.alpha *= 0.4;
|
||||
}
|
||||
for ( int i=0; i<8; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSmoke",origin);
|
||||
s.scale *= .6;
|
||||
s.alpha *= .25;
|
||||
s.SetShade(Color(1,1,1)*Random[Spreadgun](96,192));
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](3.,5.);
|
||||
}
|
||||
for ( int i=0; i<8; i++ )
|
||||
{
|
||||
let s = Spawn("SWWMSpark",origin);
|
||||
s.scale *= .2;
|
||||
s.alpha *= .4;
|
||||
s.vel += vel*.5+x*FRandom[Spreadgun](4.,8.)+y*FRandom[Spreadgun](-1,1)+z*FRandom[Spreadgun](-1,1);
|
||||
}
|
||||
SWWMHandler.DoKnockback(self,-x,2500.);
|
||||
A_Recoil(1.);
|
||||
invoker.srecoil = -.35;
|
||||
break;
|
||||
case 6:
|
||||
Console.Printf("\cg// TODO Golden Shell\c-");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue