From 97bccd3be610eaaf8b169d110ed5736e699a815f Mon Sep 17 00:00:00 2001 From: Spike <> Date: Thu, 27 Oct 2016 19:35:10 -0600 Subject: [PATCH] quakespasm-spike-r5 --- e1m1_effects/maps/e1m1.ent | 2037 ++++++++++++++ e1m1_effects/particles/flare.tga | Bin 0 -> 16402 bytes e1m1_effects/particles/lib_effects_0.cfg | 316 +++ e1m1_effects/particles/railstuff.cfg | 123 + haze.cfg | 3174 ++++++++++++++++++++++ high.cfg | 915 +++++++ particles.txt | 335 +++ qs-spike.txt | 233 ++ qsextensions.qc | 441 +++ quakespasm/Quake/cl_main.c | 76 +- quakespasm/Quake/cl_parse.c | 32 +- quakespasm/Quake/client.h | 1 + quakespasm/Quake/cmd.c | 5 +- quakespasm/Quake/gl_model.c | 24 +- quakespasm/Quake/gl_model.h | 4 + quakespasm/Quake/gl_refrag.c | 25 +- quakespasm/Quake/glquake.h | 4 + quakespasm/Quake/host.c | 2 + quakespasm/Quake/host_cmd.c | 2 +- quakespasm/Quake/net_dgrm.c | 4 +- quakespasm/Quake/net_main.c | 5 +- quakespasm/Quake/net_udp.c | 6 + quakespasm/Quake/pr_cmds.c | 119 +- quakespasm/Quake/pr_edict.c | 43 +- quakespasm/Quake/pr_ext.c | 130 +- quakespasm/Quake/progdefs.q1 | 0 quakespasm/Quake/progs.h | 5 + quakespasm/Quake/protocol.h | 7 +- quakespasm/Quake/r_part_fte.c | 520 ++-- quakespasm/Quake/server.h | 4 + quakespasm/Quake/sv_main.c | 126 +- weather.cfg | 116 + 32 files changed, 8496 insertions(+), 338 deletions(-) create mode 100755 e1m1_effects/maps/e1m1.ent create mode 100755 e1m1_effects/particles/flare.tga create mode 100755 e1m1_effects/particles/lib_effects_0.cfg create mode 100755 e1m1_effects/particles/railstuff.cfg create mode 100755 haze.cfg create mode 100755 high.cfg create mode 100755 particles.txt create mode 100755 qs-spike.txt create mode 100755 qsextensions.qc mode change 100644 => 100755 quakespasm/Quake/progdefs.q1 create mode 100755 weather.cfg diff --git a/e1m1_effects/maps/e1m1.ent b/e1m1_effects/maps/e1m1.ent new file mode 100755 index 00000000..3ee4ed40 --- /dev/null +++ b/e1m1_effects/maps/e1m1.ent @@ -0,0 +1,2037 @@ +{ +"worldtype" "2" +"sounds" "6" +"classname" "worldspawn" +"wad" "gfx/base.wad" +"message" "the Spikegate Complex Seven" +"_texpart_*slime0" "lib_effects_0.liquidfog" //baker's somewhat lame slime effect +"_texpart_sky4" "lib_effects_0.skyrain" //make it rain +"_texpart_edoor01_1" "railstuff.railslug" //periodically spam railgun effects from doors. because we can. this tests submodel emissions (they might still fire when open thanks to the lip value on doors). +} +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// BEGIN EXTRA EFFECTS ENTITIES /////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +"classname" "misc_model" // Wiring in e1m1.cfg ... +"origin" "716 250 100" // r_effect "progs/v_shot.mdl" lib_effects_0.sparkcascadelite +"angles" "0" +"emiteffect" "lib_effects_0.sparkcascadelite" +} +{ +"classname" "misc_model" // Wiring in e1m1.cfg ... +"origin" "264 233 90" // r_effect "progs/v_shot.mdl" lib_effects_0.sparkcascadelite +"angles" "0" +"emiteffect" "lib_effects_0.sparkcascadelite" +} +{ +"classname" "misc_model" // Wiring in e1m1.cfg ... +"origin" "502 304 187" // r_effect "progs/v_shot2.mdl" lib_effects_0.sparkcascadeheavy +"angles" "90 0 0" +"emiteffect" "lib_effects_0.sparkcascadeheavy" +} +{ +"classname" "misc_model" +"origin" "620 730 137" +"angles" "90 0 0" //point down +"emiteffect" "lib_effects_0.misty" +} +{ +"classname" "misc_model" +"origin" "118 582 115" +"angles" "0" +"emiteffect" "lib_effects_0.waterdrip" +} +{ +"classname" "misc_model" +"origin" "-95 1175 -205" +"angles" "0" +"emiteffect" "lib_effects_0.waterpour" +} +{ +"classname" "misc_model" +"origin" "-95 1275 -205" // Water pour west +"angles" "0" +"emiteffect" "lib_effects_0.waterpour" +} +{ +"classname" "misc_model" +"origin" "359 1175 -150" +"angle" "180" +"emiteffect" "lib_effects_0.waterpour" +} +{ +"classname" "misc_model" +"origin" "359 1275 -150" // Water pour east +"angle" "180" +"emiteffect" "lib_effects_0.waterpour" +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// END CUSTOM EFFECTS ///////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////// +{ +"classname" "info_player_start" +"origin" "480 -352 88" +"angle" "90" +} +{ +"classname" "light" +"origin" "480 96 168" +"light" "250" +} +{ +"classname" "light" +"origin" "480 288 168" +"light" "250" +} +{ +"classname" "light" +"origin" "272 96 80" +} +{ +"origin" "272 288 80" +"classname" "light" +} +{ +"classname" "light" +"origin" "272 192 80" +} +{ +"origin" "688 192 80" +"classname" "light_fluorospark" +"style" "10" +} +{ +"style" "10" +"classname" "light" +"origin" "688 288 80" +} +{ +"origin" "688 96 80" +"classname" "light" +"style" "10" +} +{ +"classname" "light" +"origin" "480 -280 168" +"light" "200" +} +{ +"origin" "480 -144 168" +"classname" "light" +"light" "200" +} +{ +"classname" "light" +"origin" "480 -376 120" +"light" "200" +} +{ +"light" "160" +"origin" "480 -40 168" +"classname" "light" +} +{ +"speed" "400" +"sounds" "2" +"angle" "270" +"classname" "func_door" +"model" "*1" +} +{ +"speed" "400" +"angle" "90" +"classname" "func_door" +"model" "*2" +} +{ +"light" "250" +"origin" "592 544 88" +"classname" "light_fluoro" +} +{ +"origin" "456 600 104" +"classname" "light" +} +{ +"light" "180" +"origin" "688 648 136" +"classname" "light" +} +{ +"classname" "light" +"origin" "688 520 136" +"light" "180" +} +{ +"origin" "688 480 80" +"classname" "item_armor1" +} +{ +"angle" "180" +"spawnflags" "768" +"origin" "616 72 40" +"classname" "monster_army" +} +{ +"light" "250" +"origin" "0 576 120" +"classname" "light" +} +{ +"light" "180" +"origin" "160 576 72" +"classname" "light" +} +{ +"light" "200" +"origin" "560 -32 72" +"classname" "light" +} +{ +"light" "200" +"classname" "light" +"origin" "400 -32 72" +} +{ +"light" "200" +"origin" "0 712 72" +"classname" "light" +} +{ +"classname" "light" +"origin" "0 728 -136" +"light" "200" +} +{ +"light" "200" +"origin" "0 592 -136" +"classname" "light" +} +{ +"wait" "5" +"angle" "-2" +"sounds" "2" +"targetname" "t1" +"classname" "func_door" +"dmg" "10" +"model" "*3" +} +{ +"sounds" "1" +"target" "t1" +"angle" "180" +"classname" "func_button" +"model" "*4" +} +{ +"light" "200" +"origin" "412 780 136" +"classname" "light" +} +{ +"light" "200" +"classname" "light" +"origin" "328 904 72" +} +{ +"light" "200" +"origin" "168 800 72" +"classname" "light" +} +{ +"light" "200" +"classname" "light" +"origin" "-72 864 72" +} +{ +"origin" "264 888 -136" +"classname" "light" +} +{ +"classname" "light" +"origin" "-8 992 -136" +"light" "200" +} +{ +"light" "250" +"classname" "light" +"origin" "272 1064 -136" +} +{ +"light" "250" +"origin" "-8 1232 -136" +"classname" "light" +} +{ +"light" "250" +"classname" "light" +"origin" "256 1272 -136" +} +{ +"light" "250" +"origin" "312 1464 -136" +"classname" "light" +} +{ +"light" "200" +"origin" "128 968 72" +"classname" "light" +} +{ +"light" "250" +"classname" "light" +"origin" "-48 1168 72" +} +{ +"light" "250" +"origin" "312 1168 72" +"classname" "light" +} +{ +"light" "220" +"classname" "light" +"origin" "128 1504 -120" +} +{ +"light" "250" +"classname" "light" +"origin" "-56 1464 -136" +} +{ +"sounds" "2" +"classname" "func_door" +"angle" "180" +"speed" "400" +"model" "*5" +} +{ +"classname" "func_door" +"angle" "0" +"speed" "400" +"model" "*6" +} +{ +"classname" "light_fluoro" +"origin" "176 1744 -152" +} +{ +"origin" "80 1744 -152" +"classname" "light_fluoro" +} +{ +"light" "250" +"origin" "-232 1600 -136" +"classname" "light" +} +{ +"light" "250" +"classname" "light" +"origin" "488 1600 -136" +} +{ +"origin" "-56 1448 72" +"classname" "light" +"light" "250" +} +{ +"light" "250" +"classname" "light" +"origin" "312 1448 72" +} +{ +"light" "260" +"classname" "light_fluoro" +"origin" "416 2064 -112" +} +{ +"light" "260" +"origin" "416 1968 -112" +"classname" "light_fluoro" +} +{ +"light" "250" +"origin" "128 1880 -112" +"classname" "light" +} +{ +"origin" "616 1944 -88" +"classname" "light" +} +{ +"style" "10" +"classname" "light_fluorospark" +"origin" "344 2216 -88" +} +{ +"light" "180" +"origin" "352 2016 -112" +"classname" "light" +} +{ +"classname" "light" +"origin" "128 2056 -112" +"light" "250" +} +{ +"light" "250" +"origin" "-112 1984 -112" +"classname" "light" +} +{ +"light" "350" +"origin" "-472 2064 -88" +"classname" "light_fluoro" +} +{ +"classname" "light" +"origin" "-192 2208 8" +"light" "250" +} +{ +"light" "250" +"origin" "-424 2208 8" +"classname" "light" +} +{ +"light" "250" +"origin" "-248 2088 -96" +"classname" "light" +} +{ +"origin" "-200 2384 -72" +"classname" "light" +} +{ +"classname" "light" +"origin" "-424 2384 -72" +} +{ +"light" "200" +"origin" "-448 2408 -128" +"classname" "light" +} +{ +"classname" "light" +"origin" "-176 2408 -128" +"light" "200" +} +{ +"sounds" "1" +"classname" "func_plat" +"model" "*7" +} +{ +"light" "350" +"origin" "-352 2656 184" +"classname" "light" +} +{ +"light" "350" +"classname" "light" +"origin" "-352 2464 184" +} +{ +"origin" "-576 2800 -40" +"classname" "light" +} +{ +"light" "500" +"origin" "160 2920 232" +"classname" "light" +} +{ +"classname" "light" +"origin" "160 2720 232" +"light" "500" +} +{ +"origin" "-288 2992 8" +"classname" "light" +} +{ +"classname" "light" +"origin" "-168 2776 -40" +} +{ +"classname" "light" +"origin" "160 2824 104" +"light" "200" +} +{ +"light" "150" +"origin" "-64 2760 136" +"classname" "light" +} +{ +"light" "200" +"origin" "16 2832 -152" +"classname" "light" +} +{ +"classname" "light" +"origin" "304 2832 -152" +"light" "200" +} +{ +"origin" "504 2816 16" +"classname" "light" +} +{ +"sounds" "3" +"wait" "-1" +"speed" "600" +"targetname" "t2" +"spawnflags" "1" +"angle" "270" +"classname" "func_door" +"model" "*8" +} +{ +"classname" "light" +"origin" "160 2840 -152" +"light" "200" +} +{ +"light" "80" +"origin" "16 2904 -88" +"classname" "light" +} +{ +"classname" "light" +"origin" "304 2904 -88" +"light" "80" +} +{ +"classname" "light" +"origin" "160 2904 -88" +"light" "80" +} +{ +"wait" "-1" +"sounds" "1" +"target" "t2" +"speed" "50" +"angle" "270" +"classname" "func_button" +"model" "*9" +} +{ +"light" "100" +"origin" "0 1800 -32" +"classname" "light" +} +{ +"classname" "light" +"origin" "248 1800 -32" +"light" "100" +} +{ +"style" "32" +"targetname" "t3" +"origin" "8 2352 200" +"classname" "light" +} +{ +"style" "32" +"targetname" "t3" +"classname" "light" +"origin" "32 2392 200" +} +{ +"style" "32" +"targetname" "t3" +"origin" "56 2352 200" +"classname" "light" +} +{ +"style" "32" +"targetname" "t3" +"classname" "light" +"origin" "32 2312 200" +} +{ +"style" "32" +"targetname" "t3" +"light" "200" +"origin" "32 2352 88" +"classname" "light" +} +{ +"spawnflags" "2048" +"origin" "112 2352 16" +"classname" "weapon_nailgun" +"emiteffect" "lib_effects_0.smokey" +} +{ +"sounds" "3" +"targetname" "t3" +"spawnflags" "3" +"angle" "270" +"classname" "func_door_secret" +"model" "*10" +} +{ +"style" "32" +"sounds" "3" +"target" "t3" +"classname" "trigger_once" +"model" "*11" +} +{ +"origin" "304 2368 96" +"classname" "light" +} +{ +"angle" "180" +"origin" "248 2392 40" +"classname" "monster_army" +} +{ +"origin" "272 2352 64" +"classname" "item_spikes" +} +{ +"style" "32" +"sounds" "3" +"target" "t3" +"classname" "trigger_once" +"model" "*12" +} +{ +"origin" "832 2608 16" +"classname" "light" +"light" "220" +} +{ +"light" "220" +"classname" "light" +"origin" "832 2480 0" +} +{ +"light" "240" +"origin" "800 2816 24" +"classname" "light" +} +{ +"style" "33" +"targetname" "t11" +"spawnflags" "1" +"classname" "light" +"origin" "752 2000 -88" +"light" "400" +} +{ +"style" "34" +"spawnflags" "1" +"targetname" "t12" +"origin" "1280 2000 -152" +"classname" "light" +"light" "400" +} +{ +"style" "35" +"spawnflags" "1" +"targetname" "t13" +"classname" "light" +"origin" "1280 2496 -216" +"light" "400" +} +{ +"style" "36" +"spawnflags" "1" +"targetname" "t14" +"origin" "784 2496 -280" +"classname" "light" +} +{ +"classname" "light" +"origin" "1368 2584 -488" +"light" "200" +} +{ +"origin" "1368 1944 -488" +"classname" "light" +"light" "200" +} +{ +"classname" "light" +"origin" "696 2584 -488" +"light" "150" +} +{ +"origin" "1016 2584 -488" +"classname" "light" +"light" "200" +} +{ +"classname" "light" +"origin" "1016 1944 -488" +"light" "200" +} +{ +"origin" "1368 2272 -488" +"classname" "light" +"light" "200" +} +{ +"classname" "light" +"origin" "696 2272 -488" +"light" "200" +} +{ +"classname" "light" +"origin" "960 2296 -488" +"light" "200" +} +{ +"light" "200" +"origin" "1032 2352 -488" +"classname" "light" +} +{ +"classname" "light" +"origin" "888 2352 -488" +"light" "200" +} +{ +"light" "200" +"origin" "960 2408 -488" +"classname" "light" +} +{ +"light" "100" +"classname" "light" +"origin" "984 2448 -304" +} +{ +"classname" "light" +"origin" "832 2360 112" +"light" "400" +} +{ +"classname" "light" +"origin" "1144 2448 -488" +} +{ +"origin" "1232 2360 -488" +"classname" "light" +} +{ +"classname" "light" +"origin" "1320 2448 -488" +"light" "200" +} +{ +"light" "200" +"origin" "1232 2536 -488" +"classname" "light" +} +{ +"classname" "light" +"origin" "1232 2136 -488" +} +{ +"origin" "1144 2048 -488" +"classname" "light" +} +{ +"classname" "light" +"origin" "1232 1960 -488" +"light" "200" +} +{ +"light" "200" +"origin" "1320 2048 -488" +"classname" "light" +} +{ +"classname" "light" +"origin" "832 2336 -200" +} +{ +"classname" "func_door_secret" +"angle" "90" +"spawnflags" "2" +"sounds" "3" +"model" "*13" +} +{ +"classname" "func_door_secret" +"angle" "180" +"sounds" "3" +"model" "*14" +} +{ +"classname" "light" +"origin" "552 2480 -56" +"light" "200" +} +{ +"light" "200" +"origin" "544 2296 -56" +"classname" "light" +} +{ +"classname" "light" +"origin" "664 2480 -56" +"light" "200" +} +{ +"classname" "func_door" +"targetname" "t4" +"angle" "-2" +"spawnflags" "1" +"sounds" "2" +"lip" "-4" +"origin" "0 0 -2" +"model" "*15" +} +{ +"classname" "trigger_multiple" +"target" "t4" +"health" "1" +"model" "*16" +} +{ +"spawnflags" "2048" +"classname" "func_door" +"angle" "90" +"targetname" "t5" +"wait" "-1" +"sounds" "2" +"model" "*17" +} +{ +"spawnflags" "2048" +"classname" "trigger_once" +"target" "t5" +"model" "*18" +} +{ +"classname" "item_artifact_super_damage" +"origin" "544 2480 -88" +"emiteffect" "lib_effects_0.mystical" +} +{ +"classname" "light" +"origin" "832 2104 -208" +} +{ +"classname" "light" +"origin" "832 2048 -368" +"light" "150" +} +{ +"classname" "light" +"origin" "1120 2464 112" +} +{ +"origin" "1120 2080 112" +"classname" "light" +} +{ +"classname" "light" +"origin" "752 2080 112" +"light" "200" +} +{ +"classname" "light" +"origin" "1048 2280 -72" +} +{ +"classname" "func_button" +"angle" "270" +"target" "t1" +"model" "*19" +} +{ +"classname" "light" +"origin" "1136 1848 -504" +"light" "220" +} +{ +"origin" "1136 1672 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1008 1672 -504" +"light" "220" +} +{ +"origin" "1008 1848 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1288 1848 -504" +"light" "220" +} +{ +"origin" "1400 1584 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1224 1584 -504" +"light" "220" +} +{ +"origin" "1400 1736 -504" +"classname" "light" +"light" "220" +} +{ +"origin" "880 1672 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "744 1672 -504" +"light" "220" +} +{ +"classname" "light" +"origin" "1312 1648 -392" +"light" "220" +} +{ +"light" "170" +"origin" "1312 1520 -392" +"classname" "light" +} +{ +"classname" "light" +"origin" "1200 1760 -392" +"light" "220" +} +{ +"light" "170" +"origin" "1072 1760 -392" +"classname" "light" +} +{ +"classname" "light" +"origin" "944 1760 -392" +"light" "170" +} +{ +"origin" "832 1992 -208" +"classname" "light" +"light" "220" +} +{ +"origin" "744 1832 -504" +"classname" "light" +} +{ +"light" "170" +"origin" "832 1760 -392" +"classname" "light" +} +{ +"light" "220" +"origin" "680 1936 -504" +"classname" "light" +} +{ +"classname" "light" +"origin" "1312 1392 -352" +"light" "170" +} +{ +"light" "170" +"origin" "1312 1264 -288" +"classname" "light" +} +{ +"classname" "light" +"origin" "1312 1136 -232" +} +{ +"origin" "1224 1456 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1400 1456 -504" +"light" "220" +} +{ +"origin" "1400 1328 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1224 1328 -504" +"light" "220" +} +{ +"origin" "1224 1200 -504" +"classname" "light" +"light" "220" +} +{ +"classname" "light" +"origin" "1400 1200 -504" +"light" "220" +} +{ +"origin" "1312 960 -208" +"classname" "light" +} +{ +"classname" "trigger_teleport" +"target" "t6" +"model" "*20" +} +{ +"classname" "light" +"origin" "1312 912 -472" +} +{ +"classname" "light" +"origin" "1312 1080 -368" +} +{ +"classname" "light" +"origin" "1128 1064 -504" +"light" "170" +} +{ +"origin" "1128 856 -504" +"classname" "light" +"light" "170" +} +{ +"classname" "light" +"origin" "1496 856 -504" +"light" "170" +} +{ +"origin" "1496 1064 -504" +"classname" "light" +"light" "170" +} +{ +"classname" "light" +"origin" "1312 776 -504" +"light" "170" +} +{ +"spawnflags" "2" +"angle" "90" +"classname" "func_door_secret" +"model" "*21" +} +{ +"origin" "1072 1024 -168" +"classname" "light" +} +{ +"spawnflags" "1" +"height" "400" +"angle" "-1" +"sounds" "1" +"classname" "func_plat" +"model" "*22" +} +{ +"targetname" "t8" +"spawnflags" "2" +"angle" "90" +"classname" "func_door_secret" +"model" "*23" +} +{ +"target" "t8" +"classname" "trigger_multiple" +"model" "*24" +} +{ +"light" "220" +"origin" "792 888 -248" +"classname" "light" +} +{ +"light" "180" +"classname" "light" +"origin" "944 608 -248" +} +{ +"light" "150" +"origin" "792 512 -248" +"classname" "light" +} +{ +"classname" "light" +"origin" "792 512 -56" +"light" "150" +} +{ +"classname" "light" +"origin" "624 928 -240" +"light" "220" +} +{ +"light" "220" +"origin" "504 1200 -248" +"classname" "light" +} +{ +"origin" "936 800 -248" +"classname" "light" +"light" "180" +} +{ +"light" "180" +"classname" "light" +"origin" "960 984 -208" +} +{ +"classname" "light" +"origin" "792 512 128" +"light" "150" +} +{ +"spawnflags" "2" +"origin" "944 1008 -272" +"classname" "item_health" +} +{ +"spawnflags" "1792" +"origin" "144 2352 16" +"classname" "weapon_rocketlauncher" +} +{ +"spawnflags" "1792" +"origin" "1216 1040 -432" +"classname" "weapon_grenadelauncher" +} +{ +"spawnflags" "1793" +"origin" "1392 1024 -432" +"classname" "item_rockets" +} +{ +"targetname" "t6" +"origin" "-32 1800 -56" +"classname" "info_teleport_destination" +} +{ +"spawnflags" "1792" +"origin" "832 2448 -368" +"classname" "weapon_supernailgun" +} +{ +"spawnflags" "1792" +"origin" "128 1216 -208" +"classname" "weapon_supershotgun" +} +{ +"origin" "296 2136 -192" +"classname" "item_shells" +} +{ +"spawnflags" "1" +"origin" "1424 904 -432" +"classname" "item_health" +} +{ +"classname" "item_health" +"origin" "1376 808 -432" +} +{ +"origin" "1176 936 -432" +"classname" "item_health" +} +{ +"spawnflags" "2048" +"target" "t9" +"wait" "-1" +"angle" "0" +"classname" "func_button" +"model" "*25" +} +{ +"spawnflags" "2048" +"target" "t9" +"wait" "-1" +"angle" "90" +"classname" "func_button" +"model" "*26" +} +{ +"spawnflags" "2048" +"target" "t9" +"wait" "-1" +"angle" "270" +"classname" "func_button" +"model" "*27" +} +{ +"target" "t10" +"targetname" "t9" +"count" "3" +"classname" "trigger_counter" +"model" "*28" +} +{ +"message" "You must press the three buttons..." +"spawnflags" "2048" +"sounds" "2" +"wait" "-1" +"targetname" "t10" +"angle" "180" +"classname" "func_door" +"model" "*29" +} +{ +"light" "150" +"origin" "832 1928 -384" +"classname" "light" +} +{ +"style" "33" +"sounds" "3" +"target" "t11" +"classname" "trigger_once" +"model" "*30" +} +{ +"style" "34" +"sounds" "3" +"target" "t12" +"classname" "trigger_once" +"model" "*31" +} +{ +"style" "35" +"sounds" "3" +"target" "t13" +"classname" "trigger_once" +"model" "*32" +} +{ +"style" "36" +"sounds" "3" +"target" "t14" +"classname" "trigger_once" +"model" "*33" +} +{ +"sounds" "1" +"wait" "-1" +"targetname" "t11" +"spawnflags" "1" +"angle" "-2" +"classname" "func_door" +"model" "*34" +} +{ +"targetname" "t12" +"classname" "func_door" +"angle" "-2" +"spawnflags" "1" +"wait" "-1" +"sounds" "1" +"model" "*35" +} +{ +"targetname" "t13" +"sounds" "1" +"wait" "-1" +"spawnflags" "1" +"angle" "-2" +"classname" "func_door" +"model" "*36" +} +{ +"targetname" "t14" +"classname" "func_door" +"angle" "-2" +"spawnflags" "1" +"wait" "-1" +"sounds" "1" +"model" "*37" +} +{ +"angle" "90" +"origin" "1312 880 -248" +"classname" "info_player_deathmatch" +} +{ +"spawnflags" "1" +"origin" "1376 1024 -272" +"classname" "item_spikes" +} +{ +"origin" "1184 992 -272" +"classname" "item_health" +} +{ +"spawnflags" "1" +"origin" "1376 856 -272" +"classname" "item_health" +} +{ +"spawnflags" "1" +"origin" "1256 1704 -432" +"classname" "item_health" +} +{ +"angle" "90" +"origin" "480 48 24" +"classname" "info_player_deathmatch" +} +{ +"angle" "180" +"origin" "528 1888 -168" +"classname" "info_player_deathmatch" +} +{ +"angle" "0" +"origin" "-272 2928 -56" +"classname" "info_player_deathmatch" +} +{ +"angle" "0" +"origin" "832 2048 -152" +"classname" "info_player_deathmatch" +} +{ +"speed" "300" +"message" "This door opens elsewhere..." +"spawnflags" "2048" +"targetname" "t15" +"angle" "270" +"classname" "func_door" +"wait" "-1" +"model" "*38" +} +{ +"spawnflags" "2048" +"target" "t15" +"classname" "trigger_once" +"model" "*39" +} +{ +"spawnflags" "1792" +"origin" "480 576 0" +"classname" "weapon_nailgun" +} +{ +"spawnflags" "1793" +"origin" "464 728 64" +"classname" "item_spikes" +} +{ +"origin" "328 848 -224" +"classname" "item_health" +} +{ +"classname" "item_health" +"origin" "344 920 -224" +} +{ +"spawnflags" "1" +"origin" "-16 2064 -208" +"classname" "item_health" +} +{ +"spawnflags" "1792" +"origin" "-480 2240 -160" +"classname" "item_rockets" +} +{ +"spawnflags" "1793" +"origin" "-96 2456 16" +"classname" "item_shells" +} +{ +"classname" "item_rockets" +"origin" "-104 2216 16" +"spawnflags" "1793" +} +{ +"classname" "item_artifact_invulnerability" +"origin" "256 1808 -40" +"spawnflags" "1792" +} +{ +"classname" "monster_army" +"origin" "0 576 24" +"angle" "0" +"spawnflags" "256" +} +{ +"classname" "monster_army" +"origin" "8 1520 -200" +"angle" "270" +} +{ +"classname" "monster_dog" +"origin" "88 1520 -200" +"angle" "270" +} +{ +"classname" "monster_army" +"origin" "224 1552 -200" +"angle" "270" +"spawnflags" "768" +} +{ +"spawnflags" "768" +"angle" "270" +"origin" "-8 936 -200" +"classname" "monster_army" +} +{ +"classname" "monster_army" +"origin" "648 736 104" +"spawnflags" "768" +"angle" "180" +} +{ +"classname" "item_artifact_envirosuit" +"origin" "712 2040 -408" +"angle" "90" +} +{ +"classname" "light" +"origin" "712 2040 -360" +"light" "100" +} +{ +"classname" "item_rockets" +"origin" "1328 2536 -528" +"spawnflags" "1793" +} +{ +"classname" "item_health" +"origin" "916 2416 -136" +"spawnflags" "2" +} +{ +"spawnflags" "1" +"classname" "monster_army" +"origin" "1312 936 -248" +"angle" "90" +} +{ +"classname" "monster_dog" +"origin" "1336 1784 -408" +"angle" "180" +"spawnflags" "257" +} +{ +"spawnflags" "257" +"angle" "90" +"origin" "1392 928 -248" +"classname" "monster_army" +} +{ +"classname" "monster_army" +"origin" "1384 1008 -248" +"angle" "90" +"spawnflags" "768" +} +{ +"spawnflags" "768" +"angle" "90" +"origin" "1240 1008 -248" +"classname" "monster_army" +} +{ +"classname" "monster_army" +"origin" "1256 1760 -408" +"angle" "180" +"spawnflags" "257" +} +{ +"classname" "monster_army" +"origin" "824 1784 -408" +"spawnflags" "257" +"angle" "90" +} +{ +"classname" "monster_dog" +"origin" "1128 1760 -408" +"angle" "180" +"spawnflags" "769" +} +{ +"classname" "path_corner" +"origin" "880 2048 -168" +"target" "t16" +"targetname" "t17" +} +{ +"origin" "1232 2048 -232" +"classname" "path_corner" +"targetname" "t16" +"target" "t17" +} +{ +"classname" "monster_army" +"origin" "1232 2088 -216" +"target" "t16" +} +{ +"classname" "monster_army" +"origin" "1232 2448 -280" +"angle" "270" +"spawnflags" "256" +} +{ +"classname" "monster_army" +"origin" "832 2464 -344" +"angle" "0" +"spawnflags" "256" +} +{ +"classname" "monster_army" +"origin" "832 2072 -408" +"angle" "90" +} +{ +"classname" "monster_dog" +"origin" "840 1960 -408" +"angle" "90" +"spawnflags" "768" +} +{ +"classname" "trigger_multiple" +"target" "t18" +"health" "1" +"model" "*40" +} +{ +"classname" "func_door_secret" +"angle" "90" +"spawnflags" "2" +"targetname" "t18" +"model" "*41" +} +{ +"classname" "weapon_supershotgun" +"origin" "-360 2912 -80" +} +{ +"classname" "trigger_multiple" +"target" "t18" +"model" "*42" +} +{ +"classname" "light" +"origin" "-352 2912 -24" +"light" "120" +} +{ +"classname" "light" +"origin" "160 3024 0" +"light" "120" +} +{ +"classname" "item_shells" +"origin" "528 720 80" +} +{ +"classname" "monster_army" +"origin" "416 1912 -168" +"angle" "180" +"spawnflags" "768" +} +{ +"classname" "monster_dog" +"origin" "432 2120 -168" +"angle" "180" +"spawnflags" "256" +} +{ +"classname" "path_corner" +"origin" "248 1992 -200" +"targetname" "t19" +"target" "t20" +} +{ +"origin" "-200 1992 -200" +"classname" "path_corner" +"targetname" "t20" +"target" "t21" +} +{ +"classname" "path_corner" +"origin" "-136 1912 -200" +"targetname" "t21" +"target" "t22" +} +{ +"origin" "248 1912 -200" +"classname" "path_corner" +"target" "t19" +"targetname" "t22" +} +{ +"classname" "monster_army" +"origin" "80 2024 -184" +"target" "t20" +} +{ +"classname" "monster_army" +"origin" "-16 1888 -184" +"spawnflags" "256" +"target" "t22" +} +{ +"classname" "monster_dog" +"origin" "-248 2144 -136" +"spawnflags" "768" +"angle" "315" +} +{ +"classname" "path_corner" +"origin" "-560 2352 40" +"targetname" "t23" +"target" "t24" +} +{ +"origin" "-104 2352 40" +"classname" "path_corner" +"target" "t23" +"targetname" "t24" +} +{ +"classname" "monster_army" +"origin" "-432 2352 56" +"spawnflags" "768" +"target" "t23" +} +{ +"angle" "0" +"classname" "monster_dog" +"origin" "-544 2584 56" +"spawnflags" "256" +} +{ +"classname" "monster_army" +"origin" "-344 2656 -104" +"angle" "270" +} +{ +"classname" "monster_dog" +"origin" "-72 2896 -56" +"spawnflags" "256" +"angle" "225" +} +{ +"classname" "monster_army" +"origin" "432 2920 -56" +"target" "t25" +} +{ +"classname" "monster_army" +"origin" "424 2832 -56" +"spawnflags" "256" +"angle" "180" +} +{ +"classname" "path_corner" +"origin" "368 2936 -72" +"targetname" "t25" +"target" "t26" +} +{ +"origin" "368 2696 -72" +"classname" "path_corner" +"targetname" "t26" +"target" "t27" +} +{ +"classname" "path_corner" +"origin" "480 2696 -72" +"targetname" "t27" +"target" "t28" +} +{ +"origin" "480 2936 -72" +"classname" "path_corner" +"target" "t25" +"targetname" "t28" +} +{ +"classname" "monster_army" +"origin" "424 2672 -56" +"target" "t27" +} +{ +"classname" "monster_army" +"origin" "424 2880 -56" +"angle" "180" +"spawnflags" "768" +} +{ +"classname" "monster_army" +"origin" "424 2760 -56" +"spawnflags" "768" +"angle" "180" +} +{ +"classname" "path_corner" +"origin" "832 2712 -88" +"targetname" "t29" +"target" "t30" +} +{ +"origin" "832 2416 -104" +"classname" "path_corner" +"target" "t29" +"targetname" "t30" +} +{ +"classname" "monster_army" +"origin" "848 2584 -72" +"spawnflags" "257" +"target" "t29" +} +{ +"classname" "monster_army" +"origin" "824 2008 -152" +"angle" "90" +"spawnflags" "768" +} +{ +"classname" "item_health" +"origin" "-376 1704 -224" +"spawnflags" "1" +} +{ +"angle" "180" +"spawnflags" "768" +"origin" "248 2352 40" +"classname" "monster_army" +} +{ +"spawnflags" "768" +"angle" "270" +"origin" "-72 2464 40" +"classname" "monster_army" +} +{ +"spawnflags" "768" +"angle" "225" +"origin" "904 1024 -248" +"classname" "monster_army" +} +{ +"light" "100" +"style" "10" +"classname" "light" +"origin" "688 0 80" +} +{ +"message" "Shoot this secret door..." +"spawnflags" "1" +"angle" "0" +"classname" "func_door_secret" +"model" "*43" +} +{ +"origin" "672 -40 48" +"classname" "item_shells" +} +{ +"classname" "trigger_secret" +"model" "*44" +} +{ +"classname" "trigger_secret" +"model" "*45" +} +{ +"classname" "trigger_secret" +"model" "*46" +} +{ +"classname" "trigger_secret" +"model" "*47" +} +{ +"classname" "trigger_secret" +"model" "*48" +} +{ +"classname" "trigger_secret" +"model" "*49" +} +{ +"light" "100" +"origin" "0 632 -88" +"classname" "light" +} +{ +"classname" "item_health" +"origin" "600 2200 -128" +"spawnflags" "1" +} +{ +"light" "220" +"classname" "light" +"origin" "832 1880 -504" +} +{ +"origin" "72 2056 -208" +"classname" "misc_explobox" +} +{ +"light" "200" +"origin" "-128 584 72" +"classname" "light" +} +{ +"light" "200" +"origin" "-128 568 -136" +"classname" "light" +} +{ +"light" "100" +"origin" "-56 632 -168" +"classname" "light" +} +{ +"light" "200" +"origin" "-56 864 -136" +"classname" "light" +} +{ +"light" "200" +"origin" "40 1672 -40" +"classname" "light" +} +{ +"classname" "light" +"origin" "216 1672 -40" +"light" "200" +} +{ +"classname" "light" +"origin" "128 1080 -152" +"light" "200" +} +{ +"light" "200" +"origin" "128 1096 72" +"classname" "light" +} +{ +"light" "250" +"classname" "light" +"origin" "-352 1656 72" +} +{ +"origin" "608 1640 72" +"classname" "light" +"light" "250" +} +{ +"origin" "-48 1144 -320" +"classname" "light" +"light" "170" +} +{ +"light" "170" +"classname" "light" +"origin" "-48 1256 -320" +} +{ +"origin" "320 1256 -320" +"classname" "light" +"light" "170" +} +{ +"light" "170" +"classname" "light" +"origin" "312 1128 -320" +} +{ +"origin" "136 1128 -320" +"classname" "light" +"light" "170" +} +{ +"light" "170" +"classname" "light" +"origin" "136 1272 -320" +} +{ +"spawnflags" "3072" +"wait" "5" +"sounds" "2" +"message" "You can jump across..." +"classname" "trigger_multiple" +"targetname" "t32" +"model" "*50" +} +{ +"spawnflags" "3072" +"wait" "5" +"message" "You can jump up here..." +"sounds" "2" +"classname" "trigger_multiple" +"targetname" "t31" +"model" "*51" +} +{ +"light" "150" +"origin" "1008 2128 -408" +"classname" "light" +} +{ +"light" "250" +"origin" "1312 544 -184" +"classname" "light" +} +{ +"light" "200" +"classname" "light" +"origin" "1208 456 -184" +} +{ +"origin" "1416 456 -184" +"classname" "light" +"light" "200" +} +{ +"light" "170" +"origin" "1312 728 -56" +"classname" "light" +} +{ +"map" "e1m2" +"classname" "trigger_changelevel" +"model" "*52" +} +{ +"classname" "item_health" +"origin" "1224 2464 -304" +"spawnflags" "1" +} +{ +"classname" "light" +"origin" "688 1680 -160" +"light" "160" +} +{ +"light" "160" +"origin" "-392 1688 -160" +"classname" "light" +} +{ +"spawnflags" "768" +"angle" "270" +"origin" "288 1536 -200" +"classname" "monster_army" +} +{ +"spawnflags" "768" +"origin" "968 2432 -112" +"classname" "monster_army" +} +{ +"wait" "5" +"message" "Walk into the slipgate to exit." +"classname" "trigger_multiple" +"sounds" "2" +"angle" "270" +"model" "*53" +} +{ +"classname" "trigger_once" +"killtarget" "t31" +"target" "t31" +"spawnflags" "3072" +"model" "*54" +} +{ +"classname" "trigger_once" +"spawnflags" "3072" +"target" "t32" +"killtarget" "t32" +"model" "*55" +} +{ +"classname" "item_armor2" +"origin" "1312 1048 -432" +} +{ +"classname" "ambient_comp_hum" +"origin" "250 194 72" +} +{ +"origin" "714 194 72" +"classname" "ambient_comp_hum" +} +{ +"classname" "ambient_comp_hum" +"origin" "626 2058 -104" +} +{ +"origin" "466 2226 -104" +"classname" "ambient_comp_hum" +} +{ +"classname" "info_intermission" +"origin" "-112 704 56" +"mangle" "20 45 0" +} +{ +"classname" "info_intermission" +"origin" "-208 2736 192" +"mangle" "20 225 0" +} +{ +"classname" "info_intermission" +"origin" "240 2664 104" +"mangle" "20 120 0" +} +{ +"classname" "info_intermission" +"origin" "1376 1936 64" +"mangle" "20 135 0" +} +{ +"angle" "90" +"origin" "528 -296 72" +"classname" "info_player_coop" +} +{ +"classname" "info_player_coop" +"origin" "432 -296 72" +"angle" "90" +} +{ +"angle" "90" +"origin" "480 -240 72" +"classname" "info_player_coop" +} +{ +"classname" "func_wall" +"spawnflags" "1792" +"model" "*56" +} +{ +"classname" "func_wall" +"spawnflags" "1792" +"model" "*57" +} +{ +"classname" "ambient_drone" +"origin" "1314 450 -200" +} diff --git a/e1m1_effects/particles/flare.tga b/e1m1_effects/particles/flare.tga new file mode 100755 index 0000000000000000000000000000000000000000..3558a3f09dd996e3c5bb526d8f6ec4be6fb8af20 GIT binary patch literal 16402 zcmeI3d#s&hmBwFNpj0We<FgzT5-l}h#LQ!#DruLqh=3&qXA&%B@aM}Z#{Qq*e*WT*$t8UhNUK~^A#gG*2Fehy=NJj*FaGiy7 zbJI4huHo?f-fOSA;qM`(BZf+jlm0{V`<%1^cHr+v3m5(EL#!AZhewAu8=vTEee1Et zIKD);W2N&u%KSK?EQsOye4KP0DjA}`4ap-m>CiRUha)&K7Al5n9QFVHX4iP=u50GB z27ZZg@P31IN1p}KePNs=IWa%aPd(qRzgZUO`}{awe>*;HFi*e3c8(3lhwTA>AUx~P z;p5HR+kPLEYni7t%{!>GW4z)WozQzxoKhA`z8E7VU;%xHH64e^1_=Hi+J^yba8%l2 z?!ou~PvC>|hsp+jiL*EQZoi;+M`E0Hy_7udk|oR{agFV{PU<_aU`Q2cNx^dBty6T`;{ zX9!q?&){rh5**?y@QfbTaZFhfV|3<99H;SUz16qkFB$-f_#;JWa!9JsPJvKO5VjL_=`+D(={3wF3sHd>PU zI2Ni6YzK5DKI-2_>sqjc?IuXZ=~<_w{=|lH2_D<8ziTjfog6kS{bHYi-%AF*8 zo3R-?3xpBpQ0fR`^HA_0Hmw+d(?=u@S<_OjXQ_1Ynv6^1leJD32BxOo*kDDRBMh7= z{ijGK_34j}V{{Mntv(*Fa})Jjt~(>IzeV>#97hxM{Be>-4spHUIB*TtJ`OOZ;8r+q zXySg6o(+b*rqlb@Nt~aSKEf{OPwaO~=M}>LO34bvK(}nt)n^0laZ_@|_&j1$;-gE~ z+^V?2W?+bWaE|x^1H=~`1J>XLxDsxnCThR_*pfWhjDeBq1N2{}b#+QFV!d0(&h**o z2mRNnwRa~ER2!U=x^b=j%RPvPNoh~)vr2lejtg|WK-ZopJ4}}yruE(5Ho$gp0=!ZE zPrZ34@<7D^JnLLXEq8MI0Us}ueqFh~v-{R*pLNR?_WxP(|Mb*nO;Q*MlU=R9{SW_)OkSo&>fckh8UxKWrF$AM;QowU zFg!Vk*eB27XE3llaSL|A`&nA|v_5~HU)D&U-ng>th*^>kmrXIVtdC2j-^IFSM(T;a zoa>GEq->1K(*~=A17e}-zclfW{v(8a`bqZ+?c+druL`!HpCbn7QENW~7oH>>j!XO! zpEcfzUvS(bf3A_A*GVsQ-xgPud*gFuZ(LXQ#AnO)_-MH;K3F!(7MrE>ZMtSlykGJG zeSV*8^q$n8IH>wB6Gt@bUvq$G3*^CO-wg~0wXbQ+Bj6U#ZNM6QL(K#J$Y11hxC{Sa zgO&0X`mfQt*9q&J;tJ_LtK1czDG$Y>@>twl_Qj3mzL-<)jBCoS_?YCXl%4SrUHjp( zRW|6=@37sfI6v_Ozqp1V4_5rsE4VJB4`~ku%z4BV`nm?Bw?U`{-K*2vfB|wjJk}{r zB<{gJvAkBe?u~bs+oj9y_++^!ZYYn$^72%yD^E!FMOV2$7U=xvCD#ZO|4_aZS7&@| z6%L4lb&8uF=?|vhNBobytNshK{-SrLK5bV|i2m>$dSYMhUwc#6e6IUOhzCwg3{b0d zipRUf2l#)rIBT6^dvm;3`g}zCf%_%p@mOEJ8#^RB%QvI9d^NgtesOs~Sh!dC*d3q9 z>#^A;{dR-whaJJw@+SSk9kzG>NKIOCKrPf-92oycrJuxrfhI|#t=DxI-0yotw8-u{&PP_pFsaSEPYn%!GYHU75~IKaek7XRr?RHNA4Y! zIe>bYwNT4+37hz+M_ApUytP&M-6h}OoxWeFxL;lVIkx}wzvIDwe<}8rAH_p`HrQOg zo;Fw{J6&7uP^|2T*@~O@Cnv5~48Q^O5;u!umSo*IPS3A3IP(-{2=t3}cGgNg1oy-F z#K1e!-`1acd}4|@m>S+fP0}g-SBU>sEA}^P&D(_Gdlb_T#eBtm*XMs3n_fH+cfRs^ zeC6c>uRZ?B-^Mq}zs4iwdvT9A;kM+4`=diKa821MKHQ<)Kpr3uQU_2Ak!z_n>4oqE zy%7Fk=0INd?2vreYER^x=X`fUU%sbrp_he&umd=xW~b+M-ERHQlm9OhhG&c8uaj>( z#dp2``Eu+&@Ope%@^#6RFTWN~f8vGscKKO6UY=Dvd_#P&SGi$NTrUj31G9u7^57M^ z-z6DS)E00oJvIGwqYh>!GQ7$Et@cBX0p_!wXOZve)xZEYppT)}r+%GyF#o~*)UO*d z=UuIs?of=cE8mYj+kYSXUV7!#$IxB!^#8v4+Wv_6LDwJRJLTu`XvV@Lu}U^uApJir z{Cr6IzgHZ3X~xqUalooR{hbFIJizS0wJ>?W{ougkzft!)2Qs7e43plA9)w;59Kc8J z1*ikxnHZ&hrKZ^--g{8_{@cR#FJkXSzmF%-`+p9+{)~?MUwrAM=XU=op6mLL_+I%{ zd`o=rfN-)&zga5$UnA^)NE~{Z{C;89(Dabh7}&j;1C9M*$=9A2w#NUSBjNu+vL*99 z=X*GY+Mk$r4~WiZq_8%6wjTNZHu-C(xa&^w*k0-XkFllvIvy^6jDLFW#rXc855)dI zyb?bs{}#_m@2AW2ih<|jo8@0(ulRABa^f=i|61K=mbm{?<&z82wl^ua5`XS};9uvz z>UVhGeNd~|Z}=Z9QSW%hMZWheir8bG;do%f6X_Gd15xI8Bg_-@>;>sN?3zaZ>iCEQ=Gd(V*m zXG!{4vH=Q}t17J9rp<5Q|_7MCZ*?LUlr%a7&jpTyUM^#@bm$8`SDSgYEgNBqB5 zy5FiiNN;d`>Q4z+ZC-ZQ)iN36{X9fmZu>rsL+{gW% z=liZV>rA@NF5yGh0OkbvV7k`*Zt=he)%Sfi>s$2wR&124m!DUbhlPu~Wt+RQ|G7?f zxL&xwUb=rKbH`Tofm@{iI`K)5@;|eYTeBAg2c9XDd$B)#2!3iO|4{>SKXBF9&+;A& zHuwCN`p-4cEn17YfF9s%t@|Qz_?5|n_e!s?%Fp{$-_Qd;pk9y}z?ZVtrT_hy^!~Wc zeJcBf?ehKB%>P%a{<} zlchiSrxv(SF>qPdu;{c~e7;kBuvK||v+9G5s_oDX|5D?71~fD01=z#2{}q~vF#}*G z$}FAOKSP+CBp-~|TG$I?4hHt?erPNFSL2>MN*!7EyQl#h`I}Hn{71`{buXK_0y7W#>$_SeiNC^z{-2(JnwT;TQ_v}xjF}h51E02{c&0w`-0>`_IM{|y}nF3PzzKXtWMuf*SWf< z!`^}S$+!;eklW~WypP5n5x%bdKJ^ayp8a#re?0qPAD}&buV?7=P|TCLXG5?t&vA?# zC+sl;_iW6wi27~=d!p0>?B{u3XSHx&_k)>}5X0!{JrwVk!X5My^w#jHYYXQXFovza zs5*Rpa(<1&{Se`9{Y`vOxF=L@CpLfywbr{5Rxo;&%@m?S^hKdiC!y^sDiGd8GF z_kf5E=LciobpXDvy$F~9pVTK{oBcmH92~Gu#yRHXuHBfW5<8PpZ(<&s@muttuY1A4 zey7Oqg@AYX*}9YS-1D}_@74d!$C?+71N7(F_@BJzcM?WvjqXP|Vh{L=ScV7D8@<>w z^}Z?it}|TvsBt>aJb^uBdK>zDzvtonOYPzM!}AXG_kM@twRyem{%rj{6ZTx#H6e2W zzxM(z@l!|E1@%1%zYF1a7wA*qM0gv#*Seh<4(~rXe{wBC+;dNC?0my~gEJsHQ;OF7;ZFIQZrLOdUi){^}A!_G{?o5 zyeGPQrbo>2OlooGpVsr;KyXs^hX;rOasV?Z_y``Zd!z0X(F@x&Vwl+hwQ`-`uxDZ6 zTK-nK1ba5#@gl}67gt-fTJH`-|B3~;z_W4o-oPgQK>RK!ws4(P?P6Q`JvsL7954PY z*AnO6Ycr4VJJ)p0Gd#P{12DiYG_@~wmyrV%6P5rYA^6nwx;H5n?Kjz*+zdK Yde=1{IllF|=ZMXZ*!&0v+JJ%o1DF-3-~a#s literal 0 HcmV?d00001 diff --git a/e1m1_effects/particles/lib_effects_0.cfg b/e1m1_effects/particles/lib_effects_0.cfg new file mode 100755 index 00000000..4247a9b1 --- /dev/null +++ b/e1m1_effects/particles/lib_effects_0.cfg @@ -0,0 +1,316 @@ +// License: +// +// So that single player releases are not overwriting each other's particle script files by using the same names ... +// And that everyone's maps play nice with each other ... +// ... and NOT stomping each others files by people using the same name. +// +// You agree to the following +// +// 1) You will include these comments at the top of your effects file to help make sure others do the same +// 2) You agree to rename this file to the following convention if you do a single player map release ... +// +// * lib_effects_0_.cfg // For a gamedir release +// Example: lib_effects_0_travail.cfg // If your intended gamedir is "travail" +// Example: lib_effects_0_travail_mymap.cfg // If you are one to contributor releasing a map to a group pack +// +// * lib_effects_0_.cfg // For a map release that doesn't use a gamedir +// Example: lib_effects_0_mymap.cfg // If your map name is "mymap.bsp" +// +// Have fun!!! Enjoy! +// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Lib Effects 0 - October 5, 2016 +// +// The file contains specific effects. +// If your map is named "mymap.bsp", you should also have a "mymap.cfg" to indicate which models call the effects in this file. +// + + +r_part waterpour +{ + texture ball + type smoke + scale 12 + scalefactor 1 + count 300 + velwrand 24 14 8 + veladd 200 + alpha 1 + rgb 192 192 192 + rgbrand 0 0 64 + die 2 + gravity 200 + cliptype waterpoursplash + clipbounce 100 + clipcount 5 +} + +r_part waterpoursplash +{ + texture ball + type texturedspark + randomvel 50 50 + count 1 + scalefactor 1 + alpha 0.1 + rgb 255 255 255 + die 0.4 + scale 50 + stretchfactor -2.5 + veladd 1 + scale 1 + gravity 800 +} + +r_part waterdrip +{ + texture ball + type texturedspark + scale 1 + stretchfactor -1.5 + scalefactor 1 + count 2 + spawnchance 0.25 + orgbias 0 0 0 + veladd 0 + velbias 0 0 -200 + alpha 1 + rgb 192 192 192 + rgbrand 0 0 64 + die 3 + cliptype waterdripsplash + clipbounce 100 + clipcount 5 +} + + +r_part waterdripsplash +{ + texture ball + type texturedspark + randomvel 50 50 + count 1 + scalefactor 1 + alpha 0.1 + rgb 255 255 255 + die 0.4 + scale 50 + stretchfactor -2.5 + veladd 1 + scale 1 + gravity 800 +} + +r_part misty +{ + type normal + count 80 + scale 40 + scalerand 15 + scalefactor 1 + scaledelta -15 + alpha 0 + die 4 + randomvel 4 12 + veladd 50 + rgb 255 255 255 + rgbdelta 0 -11 -5 + blend alpha + spawnorg 20 5 + spawnmode box + spawnvel 6 0 + up 15 + rampmode delta + ramp 0 0 0 -0.7 + ramp 0 0 0 0.4 + ramp 0 0 0 0.3 + cliptype misty + clipbounce -1 + clipcount 0 +} + +r_part smokey +{ + type normal + count 64 + scale 40 + scalerand 15 + scalefactor 1 + scaledelta -15 + alpha 0 + die 3 + velwrand 0 0 0 + velbias 0 0 50 + gravity 0 + up 15 + rgb 8 8 8 + rgbrand 2 2 2 + blend modulate + spawnorg 10 5 + spawnmode box + spawnvel 6 0 + rampmode delta + ramp 0 0 0 -1 + ramp 0 0 0 0.4 + ramp 0 0 0 0.3 + cliptype smokey + clipbounce -1 + clipcount 0 +} + +r_part mystical +{ + texture "particles/flare" + count 40 + scale 40 + scalerand 15 + scalefactor 1 + scaledelta -15 + alpha 0 + die 2 + randomvel 8 12 + veladd 5 -10 + rgb 255 255 255 + blend modulate + spawnorg 10 5 + spawnmode box + spawnvel 6 0 + up 15 + rampmode delta + ramp 0 0 0 -0.7 // Changes scale + ramp 0 0 0 0.4 // Changes scale + ramp 0 0 0 2400 // Changes scale +} + +r_part sparkcascadelite +{ + type spark + count 25 + spawnchance 0.10 + scale 40 + scalefactor 1 + spawnmode box + spawnorg 0 0 + orgbias 0 0 0 + velwrand 70 70 8 + gravity 400 + die 1 + cliptype sparkcascadelite + clipbounce -1 + clipcount 10 + alpha 1 + blend add + rgb 255 128 76 + rampmode delta + ramp 0 0 0 1 +} + +r_part sparkcascadeheavy +{ + type spark + count 500 + spawnchance 0.10 + scale 40 + scalefactor 1 + spawnmode box + spawnorg 0 0 + orgbias 0 0 0 + randomvel 140 0 + gravity 400 + die 1 + cliptype sparkcascadeheavy + clipbounce -1 + clipcount 10 + alpha 1 + blend add + rgb 255 128 76 + rampmode delta + ramp 0 0 0 1 +} + +r_part liquidfog +{ + type normal + scale 80 + scalerand 20 + up -6 + count 2 + alpha 0 + blend add + rgb 32 255 32 + rgbrand 8 8 8 + die 3.5 + veladd 0 + randomvel 11 + gravity -15 + rgb 32 32 32 + rgbrand 2 2 2 + spawnmode ball + cliptype liquidfog + clipbounce -1 + clipcount 0 + rampmode delta + ramp 0 0 0 -0.25 + ramp 0 0 0 0.125 + ramp 0 0 0 0.125 +} + +//snow from sky surfaces is often within a box +//this means we don't want the snow to ever settle. +//we also have no volume, so make the snow fall a little further. +r_part skysnow +{ + texture ball + scalefactor 1 + rainfrequency 2 + count 1 + alpha 1 + rgb 255 255 255 + die 8 + veladd 0 + velbias 0 0 -100 + scale 5 + flurry 40 + gravity 400 + friction 5 + cliptype skysnow + clipbounce 0 +} + +r_part skyrain +{ + texture ball + type texturedspark + scale 1 + stretchfactor -40 + scalefactor 1 + rainfrequency 10 + count 1 + veladd 0 + velbias -200 -200 -2000 + alpha 0.1 + rgb 255 255 255 + die 2 + cliptype skyrainsplash + clipbounce 100 + clipcount 5 + inwater skyrainsplash +} + +r_part skyrainsplash +{ + randomvel 50 50 + count 1 + texture ball + scalefactor 1 + alpha 0.1 + rgb 255 255 255 + die 0.4 + scale 50 + stretchfactor -2.5 + veladd 1 + scale 1 + type texturedspark + gravity 800 +} diff --git a/e1m1_effects/particles/railstuff.cfg b/e1m1_effects/particles/railstuff.cfg new file mode 100755 index 00000000..6a773730 --- /dev/null +++ b/e1m1_effects/particles/railstuff.cfg @@ -0,0 +1,123 @@ +r_part railtrail +{ + //blue spiral, mimicing quake2 + texture "classicparticle" + tcoords 0 0 16 16 32 + scale 0.5 + alpha 1 + scalefactor 0.8 + step 1 + spawnmode spiral 64 + spawnorg 3 + spawnvel 6 + die 1 1.2 +// colorindex 116 7 //this would be quake2's palette, which we can't use, so we have to make it up + rgb 1 31 42 + rgbrand 27 52 69 + rgbrandsync 1 +} +r_part +railtrail +{ + //grey filler, mimicing quake2 + texture "classicparticle" + tcoords 0 0 16 16 32 + scale 0.5 + alpha 1 + scalefactor 0.8 + step 0.75 + spawnorg 3 + spawnvel 3 + die 0.6 0.8 + colorindex 0 15 +} + +//circley effect when the slugs impacts something +r_part railslugimpact +{ + type normal + count 120 + die 1 + scale 5 + alpha 1 + spawnmode circle + spawnvel 30 0 + spawnorg 1 0 + rgb 28 83 111 + friction 1.5 +} + +//invisible particle that leaves our trail +r_part railslug +{ + rainfrequency 0.2 + + count 5 + scale 0 + scalefactor 1 + spawnmode box + spawnorg 0 0 + orgbias 0 0 0 + randomvel 300 + veladd 600 +// gravity 800 + die 3 + alpha 0 + blend add + + bounce 1.5 + clipcount 120 + cliptype railslugimpact + + + + //give it a trail + emit railtrail + emitinterval -1 + + //sound + sound "enforcer/enfire.wav" 1 1 0 0 + //light + lightrgb .25 .5 4 + lightradius 300 + lightradiusfade 600 + lighttime 0.333 +// lightcorona 1 0.25 +// lightshadows 0 +// lightcubemap 0 //cubemaps/%i (not supported by quakespasm) +// lightscales 0 1 1 //ambient, diffuse, specular (not supported by quakespasm) +} + +//small proxy effect that spawns our real effect only periodically. +//(thereby avoiding a sound every single frame) +r_part sparkcascadeheavy +{ + count 2 + spawnchance 0.20 + scale 10 + die 0 + alpha 1 + rgb 255 255 255 + veladd 1 + + emit railslug +} + + +//example if you want to spew particles from certain models, in this case grunts. unfortunately it includes corpses. +//r_part modelspew +//{ +// type normal +// count 800 +// scale 10 +// scalefactor 1 +// die 1 +// alpha .5 +// rgb 255 255 128 +// veladd 300 +// bounce 1.5 +// randomvel 100 100 +// gravity 800 +//} + +//r_effect "progs/soldier.mdl" modelspew forwards + diff --git a/haze.cfg b/haze.cfg new file mode 100755 index 00000000..598f29be --- /dev/null +++ b/haze.cfg @@ -0,0 +1,3174 @@ +//desc:Haze Particle Set +if $developer>0 then echo "Haze Particles Initialized (Nov 2015)" + +r_bouncysparks 1 +r_grenadetrail 1 +r_rockettrail 1 +r_part_sparks_trifan 1 +r_part_rain 1 +sv_nailhack 1 +cl_muzzleflash 1 + +r_effect "progs/lavapool.mdl" tex_*lava1 +r_effect "progs/flame2.mdl" cu_flame 1 +r_effect "progs/flame.mdl" cu_torch 0 +r_effect "progs/s_explod.spr" pyroflame11 1 +r_trail "progs/s_explod.spr" pyroflame1 1 +r_effect "progs/s_expl.spr" pyroflame11 1 +r_trail "progs/s_expl.spr" pyroflame1 1 +r_effect "progs/s_light.mdl" sham_lightning1 0 +r_effect "progs/v_spike.mdl" tr_vorelight +r_effect "progs/quaddama.mdl" te_quad_lite +r_trail "progs/quaddama.mdl" te_quad2 +r_effect "progs/invulner.mdl" te_pent_lite +r_trail "progs/invulner.mdl" te_pent2 +r_trail "progs/spike.mdl" nailtrail +r_trail "progs/s_spike.mdl" nailtrail +//r_trail "progs/v_spike.mdl" te_tracer3 +r_trail "progs/laser.mdl" tr_enforcerlaser +r_trail "progs/v_spike.mdl" tr_vorespike +r_trail "progs/s_light.mdl" sham_lightning2 0 +r_trail "progs/beam.mdl" te_railtrail 0 +r_effect "progs/beam.mdl" te_raillight 0 +r_trail "progs/beam2.mdl" te_railtrail 0 +r_effect "progs/beam2.mdl" te_raillight 0 +r_trail "progs/e_spike1.mdl" te_railtrail 0 +r_effect "progs/e_spike1.mdl" te_raillight 0 +r_trail "progs/e_spike2.mdl" te_railtrail 0 +r_effect "progs/e_spike2.mdl" te_raillight 0 +r_trail "progs/proxgren.mdl" proxygren1 +r_effect "progs/proxgren.mdl" proxygren2 +r_trail "progs/w_proxgren.mdl" proxygren1 +r_effect "progs/w_proxgren.mdl" proxygren2 +r_effect "progs/s_ablast.spr" ctf_airblast_0 1 +r_trail "progs/s_ablast.spr" ctf_airblast_1 1 +r_effect "progs/sm2.spr" ctf_smokescreen_0 1 +r_trail "progs/sm2.spr" ctf_smokescreen_1 1 +r_trail "progs/lasrspik.mdl" ctf_lasercannon +r_effect "progs/s_bubble.spr" gunbubble2 1 + +r_part te_pent +{ + texture "particles/flame" + count 64 + scale 40 + scalerand 15 + scalefactor 1 + scaledelta -15 + alpha 0 + die 2 + randomvel 4 12 + veladd 5 + rgb 222 11 5 + #rgbdelta 0 -11 -5 + blend modulate + spawnorg 10 5 + spawnmode box + spawnvel 6 0 + up 15 + #assoc cu_torchbits + rampmode delta + ramp -444 -4 -2 -0.7 + ramp -222 -4 -2 0.4 + ramp -222 -4 -2 0.3 +} + +r_part +te_pent +{ + texture "ball" + type texturedspark + count 25 + scale 0.3 + scalerand 0.3 + scalefactor 1 + veladd 11 + randomvel 30 + spawnorg 5 5 + spawnvel 5 40 + alpha 0.7 + die 1.2 + diesubrand 0.2 + rgb 11 1 1 + gravity 50 + blend modulate + cliptype bloodsplat_small_dark + clipcount 1 +} + + +r_part te_pent2 +{ + texture "" + step 1 + veladd 10 + up 30 + spawnorg 20 20 + spawnmode ball + alpha 0 + #rgb 64 64 255 + die 0 +} + +r_part te_quad +{ + texture "particles/menudot6.png" + scale 10 + scaledelta 300 + count 0.5 + veladd 0 + up 20 + gravity 0 + spawnmode ball + spawnorg 2 2 + spawnvel 0 + alpha 0.1 + rgb 64 64 255 + die 2 + rotationstart 227 + scalefactor 1 +} + +r_part +te_quad +{ + texture "particles/menudot6.png" + scale 3 + scalerand 2 + count 30 + veladd 0 + up 20 + gravity 0 + spawnmode ball + spawnorg 40 40 + spawnvel -30 -30 + randomvel -5 -5 + alpha 0.5 + rgb 64 64 255 + rgbrandsync 20 20 20 + die 1.5 + diesubrand 0.3 + #rotationstart 227 + scalefactor 1 +} + +r_part +te_quad +{ + texture "particles/zing1.png" + #type texturedspark + scale 30 + scalerand 10 + scaledelta 200 + count 10 + veladd 0 + up 20 + gravity 0 + spawnmode ball + spawnorg 10 10 + spawnvel 0 + alpha 0.1 + alphadelta -0.3 + rgb 128 128 255 + rgbrandsync 128 + die 0.3 + diesubrand 0.1 + #rotationstart 227 //227 + scalefactor 1 + cliptype "" + clipcount 0 + #rampmode delta + #ramp 0 0 0 0.3 + #ramp 0 0 0 -0.1 + #ramp 0 0 0 -0.1 +} + + +r_part te_quad_sparkfan +{ + texture "" + type sparkfan + scale 200 + scale delta 400 + count 20 + veladd 0 + up 20 + gravity 0 + spawnmode ball + spawnorg 20 20 + spawnvel 400 + alpha 0.1 + rgb 128 128 255 + rgbrandsync 128 + die 0.3 + #diesubrand 0.2 + #rotationstart 227 + scalefactor 1 + cliptype "" + clipcount 0 + rampmode delta + ramp 0 0 0 -1 + ramp 0 0 0 1 + ramp 0 0 0 1 +} + + +r_part te_quad2 +{ + texture "" + step 1 + veladd 10 + up 30 + spawnorg 20 20 + spawnmode ball + alpha 0 + rgb 64 64 255 + die 0 +} + +r_part TE_MUZZLEFLASHx +{ + texture "particles/gunflash.PNG" + count 1 + scale 15 + scalefactor 1 + stretchfactor 10 + alpha 1 + alphadelta -20 + scaledelta -20 + die 0.05 + up 15 + rgb 255 128 76 + blend add + friction 10 + veladd 300 + lighttime 0.1 + lightshadows 1 + lightradius 155 + lightrgb 1 1 1 +} + +//hazed telporter effect + +r_part tex_*teleport +{ + texture "" + scale 15 + count 11 + alpha 0 + die 6 + diesubrand 1 + randomvel 1 + veladd 1 + rgb 222 255 222 + gravity 0 + blend merge + scalefactor 1 + spawnorg 5 5 + emit teletrifan + emitinterval 0.2 + rampmode delta + ramp 0 0 0 -0.05 0 + ramp 0 0 0 -0.05 0 + ramp 0 0 0 0.05 0 + ramp 0 0 0 0.05 0 + ramp 0 0 0 0.1 0 +} + +r_part teletrifan +{ + texture "particles/generic.png" + alpha 0 + count 1 + scale 1 + scalerand 0.5 + scalefactor 1 + die 0.5 + rgb 255 214 170 + gravity 0 + randomvel 0 + rampmode delta + ramp 0 0 0 -1.5 + ramp 0 0 0 1 + spawnvel -10 + spawnorg 40 +} + +//hazed teleport splash + +r_part te_teleport //splash +{ + count 64 + spawnmode ball + spawnorg 20 50 + texture "particles/generic.png" + blend add + die 0.7 + diesubrand 0.1 + friction 2 + gravity 0 + addvel 10 + scale 50 + scalerand 25 + scaledelta -25 + alpha 0.2 + alphadelta -0.3 + randomvel 46 + rgb 255 255 255 + scalefactor 1 + lighttime 0.1 + lightradiusfade 150 + lightshadows 1 + lightradius 300 + lightrgb 1 1 1 +} + +r_part +te_teleport //little particles +{ + count 64 + spawnmode ball + spawnorg 20 50 + texture "particles/generic.png" + blend add + die 0.7 + friction 0 + gravity 0 + veladd 11 + scale 1 + alpha 0.6 + randomvel 64 + rgb 255 255 255 + scalefactor 1 +} + +r_part +te_teleport //big fans +{ + texture "" + type sparkfan + spawnmode ball + spawnorg 2 2 + count 10 + alpha 0.2 + die 0.2 + diesubrand 0 + randomvel 400 + veladd 200 + rgb 255 255 255 + gravity 0 + blend add + scalefactor 1 + scale 111 + cliptype nothing + clipcount 1 +} + +//hazed rocket trail + +r_part t_rocket +{ + texture "particles/rfire" + count 1 + scale 10 + alpha 0.2 + die 0.2 + randomvel 0 + veladd 0 + rgb 255 192 128 + rgbdelta 28 -600 -600 + blend add + gravity 0 + scalefactor 1 + scaledelta -10 + inwater bubbletrail1 +} + +r_part +t_rocket +{ + texture "particles/smoke.tga" + count 1 + scale 12 + scalerand 6 + scaledelta 50 + alpha 0.3 + die 0.8 + diesubrand 0.2 + randomvel 1 + veladd 0 + rgb 255 50 10 + rgbdelta -400 -100 -30 + gravity -10 + scalefactor 1 + inwater bubbletrail1 +} + +r_part +t_rocket +{ + texture "particles/rtrail" + count 1 + scale 8 + scalefactor 1 + scaledelta 30 + alpha 0.3 + die 0.7 + diesubrand 0.2 + randomvel 11 + veladd 0 + rgb 60 10 4 + rgbdelta -80 -16 -8 + gravity -10 + blend modulate + spawnmode spiral + spawnparam1 360 + spawnvel 6 + spawnorg 2 2 + inwater bubbletrail1 +} + +r_part +t_rocket +{ + texture "particles/rtrail" + count 1 + scale 8 + scalefactor 1 + scaledelta 30 + alpha 0.3 + die 0.7 + diesubrand 0.2 + randomvel 11 + veladd 0 + #rgb 5 5 5 + rgb 60 10 4 + rgbdelta -80 -16 -8 + gravity -10 + blend modulate + spawnmode spiral + spawnparam1 240 + spawnvel 6 + spawnorg 2 2 + inwater bubbletrail1 +} + +r_part +t_rocket +{ + texture "particles/rtrail" + count 1 + scale 3 + scalefactor 1 + scaledelta 30 + alpha 0.3 + die 0.7 + diesubrand 0.2 + randomvel 11 + veladd 0 + rgb 255 192 128 + rgbdelta -655 -755 -755 + gravity -10 + blend modulate + spawnmode spiral + spawnparam1 120 + spawnvel 6 + spawnorg 1 1 + inwater bubbletrail1 +} + +r_part bubbletrail1 +{ + texture "particles/rfire" + count 1 + scale 5 + alpha 1 + die 0.1 + randomvel 0 + veladd 0 + rgb 255 192 128 + rgbdelta 28 -800 -800 + blend add + #assoc bubbletrail2 + gravity 0 + scalefactor 1 + scaledelta -10 +} + +r_part +bubbletrail1 +{ + texture "particles/bubble.png" + count 0.5 + scale 1 + scalerand 22 + scaledelta -10 + alpha 0.6 + die 1.2 + diesubrand 0.4 + blend add + veladd 130 + randomvel 40 + spawnorg 3 3 + spawnvel 3 3 + friction 0.3 + rgb 255 255 255 + gravity -100 + scalefactor 1 +} + + +//hazed explosions + +r_part te_explosion +{ + type decal + texture "particles/blood3.tga" + count 1 + scale 65 + scalerand 35 + alpha 0.8 + die 20 + inwater expbubble1 +} + +r_part +te_explosion +{ + texture "particles/exp.tga" + count 15 + scale 111 + scalefactor 1 + scalerand 22 + alpha 0.6 + die 0.5 + diesubrand 0.2 + randomvel 88 + rgb 1 1 1 + rgbdelta 510 256 152 + friction 0 + blend merge #modulate + spawnmode ball + emit zz_explosion + emitinterval 2 + inwater expbubble1 + lighttime 0.1 + lightradiusfade 150 + lightshadows 1 + lightradius 300 + lightrgb 1 1 1 + rampmode delta + ramp 0 0 0 0.1 + ramp 510 256 152 0.5 + ramp -300 -152 -60 0.3 +} + +r_part +te_explosion +{ + texture "particles/exp.tga" + count 5 + scale 111 + scalefactor 1 + die 2 + randomvel -33 + veladd 0 + gravity -44 + friction 1 + spawnmode circle + diesubrand 0.3 + alpha 1 + rgb 1 1 1 + rgbdelta 4 4 4 + rgbrand 1 1 1 + inwater expbubble + +} + +r_part +te_explosion //ember +{ + count 50 + texture "particles/fireline4g.tga" + rgb 255 125 68 + alpha 0.5 + scalerand 22 + scale 55 + scalefactor 1 + friction 0 + gravity -55 + diesubrand 0.2 + die 0.5 + blend add + randomvel -77 + spawnmode ball + inwater expbubble +} + +r_part ember +{ + count 1 + spawnmode ball + spawnorg 10 + #spawnvel 10 + texture "" + type texturedspark + scale 1 + rgb 255 128 76 + gravity 200 + die 0.6 + disubrand 0.3 + up 5 + alpha 0.5 + blend add + randomvel 10 + veladd 1 + cliptype randomspark + clipcount 1 + inwater expbubble +} + +r_part zz_explosion +{ + texture "particles/flame.tga" + count 2 + scale 7 + scalefactor 1 + scalerand 0.5 + veladd 5 + randomvel -133 + alpha 0.7 + die 0.4 + diesubrand 0.1 + rgb 255 200 200 + friction 0 + gravity 222 + blend add + emit ember + emitinterval 1 + inwater expbubble +} + +r_part ember2 +{ + count 1 + texture "particles/flame.tga" + rgb 255 128 76 + rgbdelta 255 255 255 + blend modulate + alpha 0.7 + scale 7 + scalefactor 1 + scalerand 0.5 + die 0.4 + diesubrand 0.1 + blend add + randomvel 111 + #rampmode delta + #ramp 0 0 0 1 + inwater expbubble +} + +r_part randomspark +{ + count 1 + texture "" + scale 0 + rgb 255 128 76 + alpha 1 + gravity 200 + spawnmode ball + die 1 + blend add + randomvel 111 + veladd 0 + inwater expbubble +} + + +r_part expbubble +{ + texture "particles/bubble.png" + count 5 + scale 1 + scalerand 6 + alpha 1 + die 1.5 + diesubrand 0.4 + blend add + veladd 0 + randomvel 20 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -150 + scalefactor 1 +} + +r_part expbubble1 +{ + texture "particles/bubble.png" + count 22 + scale 10 + scalerand 20 + scalechange -20 + alpha 1 + die 1.1 + diesubrand 0.4 + blend add + veladd 0 + randomvel 0 + spawnorg 10 0 + spawnvel 10 -50 + rgb 255 255 255 + gravity -205 + scalefactor 1 + assoc expbubble2 + emit zz_explosionbubble + emitinterval 2 +} + +r_part expbubble2 +{ + texture "particles/bubble.png" + count 5 + scale 1 + scalerand 6 + alpha 1 + die 1.5 + diesubrand 0.4 + blend add + veladd 0 + randomvel 20 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -150 + scalefactor 1 + assoc expbubble3 +} + +r_part expbubble3 +{ + texture "particles/generic.png" + count 5 + scale 96 + scalefactor 1 + spawnorg 20 20 + alpha 0.4 + die 0.7 + diesubrand 0.2 + randomvel 23 + rgb 255 128 76 + rgbdelta -255 -128 -76 + blend add + spawnmode ball +} + +r_part zz_explosionbubble +{ + texture "particles/fireline4g.tga" + count 2 + scale 1 + scalefactor 1 + scalerand 1 + veladd 0 + randomvel -500 + alpha 1 + die 0.1 + diesubrand 0.05 + rgb 255 200 200 + stains 0 + friction 0 + gravity -300 + blend add + emit ember2 + emitinterval 0.01 + spawnorg 2 2 + spawnvel 30 30 +} + +r_part explosion_decal +{ + type decal + texture "particles/blood3.tga" + count 1 + scale 100 + alpha 0.8 + die 20 + #blend modulate + #blend invmod +} + +//Hazed flame effect + +r_part cu_flame +{ + texture "particles/flame" + count 64 + scale 50 + scalerand 15 + scalefactor 1 + scaledelta 0 + alpha 0 + die 1 + randomvel 4 24 + veladd -24 + rgb 255 128 76 + rgbdelta 0 -64 -38 + blend add + spawnorg 10 0 + spawnmode box + spawnvel -6 0 + up -8 + assoc cu_flamebits + rampmode delta + ramp 0 0 0 -0.6 + ramp 0 0 0 0.3 + ramp 0 0 0 0.3 +} + +r_part cu_flamebits +{ + texture "particles/generic.png" + count 6 + scale 1 + scalerand 3 + scalefactor 1 + scaledelta -3 + alpha 0.7 + die 0.8 + randomvel -15 + veladd -15 + rgb 200 200 180 + blend modulate + spawnorg 10 10 + spawnvel -5 10 + spawnmode box + gravity -200 + assoc cu_flamebits2 +} + +r_part cu_flamebits2 +{ + texture "particles/smoke" + count 6 + scale 33 + scalerand 11 + scalefactor 1 + scaledelta 0 + alpha 0 + die 1 + randomvel -5 + veladd -25 + rgb 1 1 1 + blend merge + spawnorg 15 + spawnvel 5 + spawnmode box + gravity -30 + up 20 + rampmode delta + ramp 0 0 0 -0.3 + ramp 0 0 0 -0.5 + ramp 0 0 0 -0.7 + ramp 0 0 0 0.7 + ramp 0 0 0 0.5 + ramp 0 0 0 0.3 +} + +//hazed torch effect + +r_part cu_torch +{ + texture "particles/flame" + count 64 + scale 30 + scalerand 7 + scalefactor 1 + scaledelta 0 + alpha 0 + die 0.8 + randomvel 4 24 + veladd -18 + rgb 255 128 76 + rgbdelta 0 -64 -38 + blend add + spawnorg 5 0 + spawnmode box + spawnvel -6 0 + up 4 + assoc cu_torchbits + rampmode delta + ramp 0 0 0 -0.7 + ramp 0 0 0 0.4 + ramp 0 0 0 0.3 + +} + +r_part cu_torchbits +{ + texture "particles/generic.png" + count 3 + scale 1 + scalerand 2 + scalefactor 1 + scaledelta -2 + alpha 0.7 + die 0.8 + randomvel -15 + veladd -15 + rgb 200 200 180 + blend modulate + spawnorg 5 5 + spawnvel -3 5 + spawnmode box + gravity -100 + assoc cu_torchbits2 + up 8 +} + +r_part cu_torchbits2 +{ + texture "particles/smoke" + count 6 + scale 15 + scalerand 5 + scalefactor 1 + scaledelta 0 + alpha 0 + die 1 + randomvel -5 + veladd -25 + rgb 1 1 1 + blend merge + spawnorg 7 + spawnvel 5 + spawnmode box + gravity -30 + up 10 + rampmode delta + ramp 0 0 0 -0.3 + ramp 0 0 0 -0.5 + ramp 0 0 0 -0.7 + ramp 0 0 0 0.7 + ramp 0 0 0 0.5 + ramp 0 0 0 0.3 +} + +//spark effects + +r_part gunshotsparks +{ + texture "" + count 1 + scale 0 + scalefactor 1 + alpha 1 + die 1 + randomvel 140 + veladd 44 + rgb 255 128 76 + gravity 400 + blend add + cliptype randomspark #gunshotsparks + clipcount 1 + assoc gunshotsmoke + rampmode delta + ramp 0 0 0 1 + inwater gunbubble2 +} + +r_part gunshotsmoke +{ + texture "particles/smoke.tga" + count 1 + scale 10 + scalerand 5 + scalefactor 1 + scaledelta 20 + alpha 0.1 + die 1 + randomvel 5 + veladd 5 + rgb 255 255 255 + gravity 5 + blend add + rampmode delta + ramp 0 0 0 0.2 + ramp 0 0 0 0.2 + inwater gunbubble2 +} + +// spark effect of axehit/gunshot +r_part te_gunshot +{ + texture "" + count 2 + scale 5 + scalefactor 1 + alpha 0.4 + die 0.1 + randomvel 150 + veladd 0 + rgb 255 128 76 + gravity 80 + blend add + friction 0 + assoc gunshotsparks + emit gunshotbits + emitinterval 1 + lighttime 0.1 + lightshadows 1 + lightradius 5 + lightrgb 1 1 1 + inwater gunbubble2 + cliptype gunshot_decal + clipcount 1 +} + +r_part gunshot_decal +{ + type decal + texture "particles/explosion" + count 1 + scale 5 + alpha 0.8 + die 20 + blend invmod +} + +r_part gunshotbits +{ + texture "ball" + type texturedspark + count 0.3 + scale 1 + scalefactor 1 + veladd 0 + randomvel -111 + alpha 0.2 + die 0.5 + rgb 255 128 76 + friction 0 + gravity 400 + blend add + inwater gunbubble +} + +r_part te_superspike +{ + texture "" + count 13 + scale 5 7 + scalefactor 1 + alpha 0.2 + die 0.1 + randomvel 150 + veladd 0 + rgb 255 128 76 + gravity 80 + blend add + friction 0 + assoc gunshotsparks + emit gunshotbits + emitinterval 1 + inwater gunbubble2 + lighttime 0.1 + lightradiusfade 0 + lightshadows 1 + lightradius 11 + lightrgb 1 1 1 + cliptype spike_decal + clipcount 1 +} + +r_part te_spike +{ + texture "" + count 13 + scale 5 7 + scalefactor 1 + alpha 0.2 + die 0.1 + randomvel 150 + veladd 0 + rgb 255 128 76 + gravity 80 + blend add + friction 0 + assoc gunshotsparks + emit gunshotbits + emitinterval 1 + inwater gunbubble2 + lighttime 0.1 + lightradiusfade 0 + lightshadows 1 + lightradius 11 + lightrgb 1 1 1 + cliptype spike_decal + clipcount 1 +} + +r_part spike_decal +{ + type decal + texture "particles/explosion" + count 1 + scale 5 + alpha 0.3 + die 20 + blend invmod +} + +r_part gunbubble +{ + texture "particles/bubble.png" + count 1 + scale 1 + scalerand 6 + scaledelta -4 + alpha 0.8 + die 1 + diesubrand 0.4 + blend add + veladd 0 + randomvel 20 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -150 + scalefactor 1 +} + +r_part gunbubble2 +{ + texture "" + count 2 + scale 5 + scalefactor 1 + alpha 0.8 + die 0.1 + randomvel 150 + veladd 0 + rgb 255 128 76 + gravity 80 + blend add + friction 0 + assoc gunbubble +} + +//Hazed grenade trail + +r_part t_grenade +{ + texture "particles/smoke" + step 4 + scale 22 + alpha 0.4 + die 0.4 + randomvel 5 + veladd 2 + rgb 64 64 64 + blend add + #assoc grenadetrail + scalefactor 1 + inwater grenadebubble +} + +r_part +t_grenade +{ + texture "" + count 1 + scale 1 + alpha 1 + die 0.4 + diesubrand 0.2 + randomvel 10 + veladd 0 + rgb 233 150 122 + rgbdelta -233 -150 -122 + gravity -25 + scalefactor 1 + blend add + lighttime 0.1 + lightradiusfade 50 + lightshadows 1 + lightradius 100 + lightrgb 0.3 0.2 0 +} + +r_part grenadebubble +{ + texture "particles/bubble.png" + count 0.5 + scale 0.1 + scalerand 8 + scaledelta -8 + alpha 0.7 + die 1.3 + diesubrand 0.4 + blend add + veladd 15 + randomvel 10 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -100 + scalefactor 1 +} + +//hazed lightning bolt for gun/shambler/chton +//uses molgrums beam + +r_part te_lightning1 //Shambler lightning +{ + die 0 + type beam + alpha 0.6 + step 5 + scale 1 + scalefactor 0 + rgb 98 98 128 + spawnmode distball + spawnorg 7 + spawnparam1 0.2 + blend add + averageout + nospreadfirst + assoc te_lightning2b + lighttime 1 + lightshadows 0 + lightradius 300 + lightrgb 2 2 2 +} + +r_part sham_lightning2 +{ + spawnmode ball + count 1 + texture "" + up 250 + gravity 0 + lighttime 0 + lightshadows 0 + lightradius 500 + lightrgb 1 1 1 +} + +r_part sham_lightning1 +{ + spawnmode ball + count 200 + spawnorg 300 300 + spawnvel -1000 + friction 0 + texture "" + type spark + #scale 30 + alpha 0.7 + die 0.2 + diesubrand 0.1 + up 25 + rotationspeed 90 + rotationstart 0 360 + rgb 150 150 250 + rgbrand 100 100 0 + gravity 0 + scalefactor 1 //0.4 +} + +r_part +sham_lightning1 +{ + spawnmode ball + count 200 + spawnorg 1 1 + spawnvel 1000 + friction 0 + texture "" + type texturedspark + scale 1 + alpha 0.5 + die 0.2 + diesubrand 0.1 + up 25 + rotationspeed 90 + rotationstart 0 360 + rgb 150 150 250 + rgbrand 100 100 0 + gravity 0 + scalefactor 1 //0.4 +} + +r_part te_lightning2 //player lightning +{ + die 0 + type beam + alpha 0.6 + step 5 + scale 1 + scalefactor 0 + rgb 98 98 128 + spawnmode distball + spawnorg 7 + spawnparam1 0.2 + blend add + averageout + nospreadfirst + assoc te_lightning2b + lighttime 0 + lightshadows 0 + lightradius 300 + lightrgb 2 2 2 +} + +r_part te_lightning3 //Chthon trap lightning +{ + die 0 + alpha 1 + step 5 + scale 1 + scalefactor 0 + rgb 98 98 128 + spawnmode distball + spawnorg 7 + spawnparam1 0.2 + blend add + averageout + nospreadfirst + assoc te_lightning2b + lighttime 0 + lightshadows 1 + lightradius 500 + lightrgb 2 2 2 +} + +r_part te_lightning2b +{ + texture "" + count 1 + alpha 0.5 + die 0 + randomvel 88 + veladd 0 + rgb 150 200 255 + rgbdelta 0 -8888 0 + gravity 0 + blend add + scalefactor 1 + assoc te_lightning2c + spawnmode tracer +} + +r_part te_lightning2c +{ + texture "" + step 15 + alpha 0.6 + scale 1 + rgb 200 222 255 + gravity 0 + blend add + spawnmode distball + spawnorg -5 -5 + type beam + scalefactor 1 + scalerand 2 + assoc te_lightning2d + spawnparam1 0.2 +} + +r_part te_lightning2d +{ + texture "" + step 15 + alpha 0.6 + scale 1 + scalerand 2 + rgb 200 222 255 + gravity 0 + blend add + spawnmode distball + spawnorg 5 5 + type beam + scalefactor 1 + spawnparam1 0.2 +} + +//(modified from spikeset) + +r_part te_lightning1_end +{ + texture "" + die 0.3 + alpha 1 + count 2 + scale 0 + rgb 128 128 255 + rgbrand 63 63 0 + rgbrandsync 1 + randomvel 190 + spawnorg 2 + blend add + gravity 300 + cliptype te_lightning2_end2 + clipcount 1 + scalefactor 11 + lighttime 0.1 + lightradiusfade 10 + lightshadows 0 + lightradius 100 + lightrgb 1 1 1 +} + +r_part +te_lightning1_end +{ + texture "particles/smoke" + count 4 + scalerand 30 + scale 33 + scalefactor 1 + alpha 0.3 + die 1 + randomvel 11 + veladd 1 + rgb 0 0 0 + gravity -70 + blend modulate +} + +r_part te_lightning2_end +{ + texture "" + die 0.3 + alpha 1 + count 2 + scale 0 + rgb 128 128 255 + rgbrand 63 63 0 + rgbrandsync 1 + randomvel 190 + spawnorg 2 + blend add + gravity 300 + cliptype te_lightning2_end2 + clipcount 1 + scalefactor 11 + lighttime 0.1 + lightradiusfade 10 + lightshadows 0 + lightradius 100 + lightrgb 1 1 1 +} + +r_part +te_lightning2_end //lightning decal +{ + type decal + texture "particles/explosion" + count 1 + scale 11 + alpha 0.8 + die 20 + blend invmod +} + +r_part +te_lightning2_end +{ + texture "particles/smoke" + count 4 + scalerand 30 + scale 33 + scalefactor 1 + alpha 0.3 + die 1 + randomvel 11 + veladd 1 + rgb 0 0 0 + gravity -70 + blend modulate +} + +r_part te_lightning2_end2 +{ + count 1 + texture "" + scale 0 + rgb 128 128 255 + rgbrand 63 63 0 + rgbrandsync 1 + alpha 1 + gravity 300 + spawnmode ball + die 1 + blend add + randomvel -111 + veladd 0 + scalefactor 1 +} + +r_part shamblerzaps +{ texture "" + alpha 0.8 + die 0.1 + diesubrand 0.1 + count 1 + scale 1 + rgb 128 128 255 + rgbrand 63 63 0 + rgbrandsync 1 + spawnorg 100 + spawnmode ball + spawnvel -400 + blend add + scalefactor 1 + lighttime 0.1 + lightradiusfade 10 + lightshadows 1 + lightradius 50 + lightrgb 1 1 1 +} + +/////hazed EMP #3 (heavily modified from jedilammas) + +r_part cte_greenexplosion +{ + texture "particles/generic.png" + count 11 + scale 111 + alpha 0.6 + die 0.4 + randomvel 32 + veladd 10 + rgb 128 255 76 + rgbdelta 0 0 0 + gravity 0 + blend add + scalefactor 1 + scaledelta -50 +} + +r_part empcentral +{ + texture "particles/spot01drk.tga" + count 11 + scale 80 + alpha 0.4 + die 0.5 + randomvel 20 + veladd -111 + rgb 128 128 255 + gravity 0 + friction 0.2 + stains 0 + blend add + assoc littlebits + spawnmode circle + spawnorg 44 44 + spawnvel 42 0 + scalefactor 1 + scaledelta 5 +} + +r_part empinner +{ + texture "particles/flame.tga" + count 30 + scale 1 + alpha 0.4 + die 0.5 + randomvel 100 0 + rgb 128 128 255 + rgbdelta 0 0 0 + gravity 200 + friction 0 + stains 0 + blend add + assoc empcentral + spawnmode circle + spawnvel 200 0 + scalefactor 1 + emit 2shockwave + emitinterval 0.1 + up 15 +} + +r_part te_tarexplosion +{ + texture "particles/duolight02grey.tga" + count 140 + scale 40 + alpha 0.2 + die 0.3 + randomvel 0 + veladd -11 + rgb 128 255 76 + rgbdelta 0 0 0 + gravity 0 + friction -0.9 + blend add + spawnmode uniformcircle + spawnorg 64 0 + spawnvel 366 0 + scalefactor 1 + emit empelectric + emitinterval 0.01 + lighttime 0.3 + lightshadows 0 + lightradius 350 + lightrgb 0.27 .27 1 +} + +r_part +te_tarexplosion +{ + texture "particles/flame.tga" + count 30 + scale 1 + alpha 0.4 + die 0.5 + randomvel 100 0 + rgb 128 128 255 + rgbdelta 0 0 0 + gravity 200 + friction 0 + stains 0 + blend add + spawnmode circle + spawnvel 200 0 + scalefactor 1 + emit 2shockwave + emitinterval 0.1 + up 15 +} + +r_part +te_tarexplosion +{ + texture "particles/spot01drk.tga" + count 11 + scale 80 + alpha 0.4 + die 0.5 + randomvel 20 + veladd -111 + rgb 128 128 255 + gravity 0 + friction 0.2 + stains 0 + blend add + spawnmode circle + spawnorg 44 44 + spawnvel 42 0 + scalefactor 1 + scaledelta 5 +} +r_part +te_tarexplosion +{ + texture "particles/generic.png" + count 5 + scale 5 + alpha 0.4 + die 0.5 + randomvel 5 + veladd 0 + rgbdelta 240 -270 0 + rgb 0 255 255 + gravity 0 + friction 2 + blend add + cliptype littlebits + clipcount 1 + spawnorg 1 1 + spawnvel 64 64 + emit littlebits2 + emitinterval 0.1 + scalefactor 1 + spawnmode circle +} + +r_part +te_tarexplosion +{ + texture "particles/generic.png" + count 11 + scale 111 + alpha 0.6 + die 0.4 + randomvel 32 + veladd 10 + rgb 128 255 76 + rgbdelta 0 0 0 + gravity 0 + blend add + scalefactor 1 + scaledelta -50 +} + +r_part empelectric +{ + texture "" + count 5 + alpha 0.4 + die 0.2 + diesubrand 0.3 + randomvel 76 + veladd 0 + rgb 0 255 255 + rgbdelta 0 -555 -255 + gravity 0 + blend add + scalefactor 1 +} + +r_part littlebits +{ + texture "particles/generic.png" + count 5 + scale 5 + alpha 0.4 + die 0.5 + randomvel 5 + veladd 0 + rgbdelta 240 -270 0 + rgb 0 255 255 + gravity 0 + friction 2 + blend add + cliptype littlebits + clipcount 1 + spawnorg 1 1 + spawnvel 64 64 + assoc cte_greenexplosion + emit littlebits2 + emitinterval 0.1 + scalefactor 1 + spawnmode circle +} +r_part littlebits2 +{ + texture "" + count 5 + alpha 0.3 + rgb 120 120 255 + scale 15 + die 0.3 + gravity 0 + friction 2 + blend add + spawnorg 1 0 + spawnvel 85 0 + spawnmode uniformcircle + randomvel 333 + scalefactor 1 +} + +r_part 2shockwave +{ + texture "" + count 15 + scalerand 10 + scale 11 + scalefactor 1 + die 0.2 + alpha 0.05 + rgb 35 125 68 + blend add + spawnmode uniformcircle + spawnorg 0 140 + spawnvel 288 0 + randomvel 100 0 + rotationstart 0 360 + up -5 + rampmode delta + ramp 0 0 0 0.1 + ramp -33 -55 -66 0.1 +} + +//haze TeamFortress railgun +r_part te_raillight +{ + lighttime 0 + lightshadows 0 + lightradius 100 + lightrgb 0 0.2 0.8 +} + +r_part te_railtrail +{ + type texturedspark + texture "particles/flare2.tga" + count 1 + scale 1 + alpha 0.5 + die 0.6 + diesubrand 0.2 + rgb 55 178 238 + veladd -520 + randomvel 5 + blend add + spawnparam1 120 + spawnmode spiral + spawnorg 4 + inwater railbubble +} + +r_part +te_railtrail +{ + type texturedspark + texture "particles/flare2.tga" + count 1 + scale 1 + alpha 0.5 + die 0.6 + diesubrand 0.1 + rgb 200 200 255 + reddelta 255 + blend add + scalefactor 1 + spawnmode spiral + spawnparam1 240 + scalefactor 1 + spawnorg 2 2 + veladd -520 +} + +r_part +te_railtrail +{ + type texturedspark + texture "particles/flare2.tga" + count 1 + scale 1 + alpha 0.5 + die 0.4 + rgb 0 200 255 + reddelta 255 + blend add + scalefactor 1 + spawnmode spiral + spawnparam1 360 + scalefactor 1 + spawnorg 3 3 + veladd -520 +} + +r_part railbubble +{ + texture "particles/bubble.png" + count 1 + scale 0.1 + scalerand 6 + alpha 1 + die 1.5 + diesubrand 0.4 + blend add + veladd 0 + randomvel 10 + spawnvel 3 3 + rgb 255 255 255 + gravity -50 + scalefactor 1 + spawnparam1 50 + spawnmode spiral + spawnorg 5 +} + +//hazed MegaTeamFortress proxy + +r_part proxygren1 +{ + #lighttime 0.1 + #lightshadows 0 + #lightradius 200 + #lightrgb 1 0.5 1 +} + +r_part zproxygren2 +{ + texture "particles/grate7.tga" + count 33 + spawnmode circle + scale 0 + scalerand 3 + scalefactor 1 + spawnvel -33 + spawnorg 25 + up 3 + alpha 0 + rgb 200 22 180 + gravity 0 + die 0.6 + blend add + rampmode delta + ramp 0 0 0 -0.9 + ramp 0 0 0 -100 +} + +r_part zproxygren2 +{ + texture "particles/icespriteray.bmp" //generic.png" + count 1 + spawnmode circle + #spawnorg 2 0 + #spawnvel 50 0 + #veladd 40 + scale 5 + scaledelta 440 + scalefactor 1 + rotationstart 240 + #spawnparam1 270 + alpha 1 + up 4 + rgb 200 22 180 + die 1 + blend add + #rampmode delta + #ramp 0 0 0 1.1 + gravity 0 + cliptype nothing + clipcount 1 +} + +r_part proxygren2 +{ + texture "particles/generic.png" + count 111 + spawnmode circle + spawnorg 20 0 + spawnvel 5 0 + #veladd 40 + scale 1 + scalerand 4 + scaledelta 0 + scalefactor 1 + #rotationstart 240 + #spawnparam1 270 + alpha 1 + up 4 + rgb 200 22 180 + rgbrand 0 100 50 + die 1 + blend add + friction -1 + rampmode delta + ramp 0 0 0 0.3 + ramp 0 0 0 0.5 + ramp 0 0 0 0.6 + gravity 0 + cliptype nothing + clipcount 1 +} + +r_part +proxygren2 +{ + texture "particles/generic.png" + count 111 + spawnmode circle + spawnorg 0 20 + spawnvel 0 5 + #veladd 40 + scale 1 + scalerand 4 + scaledelta 0 + scalefactor 1 + #rotationstart 240 + #spawnparam1 270 + alpha 1 + up 4 + rgb 200 22 180 + rgbrand 0 100 50 + die 1 + blend add + friction -1 + rampmode delta + ramp 0 0 0 0.3 + ramp 0 0 0 0.5 + ramp 0 0 0 0.6 + gravity 0 + cliptype nothing + clipcount 1 +} + + +// haze spy gas // but also bosses lava splash...so green looks funny. + +r_part te_lavasplash +{ + texture "particles/smoke.tga" + count 75 + scale 80 + scalerand 45 + alpha 0 + die 3 + diesubrand 1 + randomvel 10 + veladd 0 + rgb 55 30 30 + gravity -5 + blend add + spawnorg 175 50 + spawnvel 0 0 + assoc gassmoke + scalefactor 1 + scaledelta 20 + up 40 + rampmode delta + ramp 0 0 0 -0.5 + ramp 0 0 0 -0.5 + ramp 0 0 0 0.6 + ramp 0 0 0 0.6 +} + +r_part gassmoke +{ + texture "particles/bloodsplat2.tga" + count 55 + scale 60 + scalerand 60 + alpha 0.3 + die 3 + randomvel 60 + rgb 20 255 20 + diesubrand 1 + friction 1 + gravity -5 + spawnorg 100 0 + spawnvel 60 60 + blend modulate + emit gassmoke2 + emitinterval 1 + emitintervalrand 1 + scalefactor 1 + up 40 +} + +r_part gassmoke2 +{ + texture "particles/round.tga" + count 2 + scale 90 + scalerand 40 + alpha 0 + die 3 + randomvel 15 + veladd 0 + rgb 22 66 22 + diesubrand 1 + friction 0.2 + gravity -5 + spawnmode circle + spawnorg 10 10 + clipcount 1 + cliptype nothing + blend add + scalefactor 1 + rampmode delta + ramp 0 0 0 -0.2 + ramp 0 0 0 -0.2 + ramp 0 0 0 -0.2 + ramp 0 0 0 0.2 + ramp 0 0 0 0.3 + ramp 0 0 0 0.4 +} +//hazed vorath trail + +r_part tr_vorespike +{ + texture "particles/gravity_0.tga" + step 2 + scale 30 + scaledelta -20 + alpha 0.2 + die 0.4 + randomvel 2 + veladd 2 + rgb 128 0 128 + gravity 0 + reddelta -128 0 -128 + blend add + spawnmode tracer + scalefactor 1 +} + +r_part +tr_vorespike +{ + texture "" + count 1 + scale 0 + scalefactor 1 + alpha 0.3 + die 0.3 + randomvel 140 + veladd 44 + rgb 200 0 200 //255 128 76 + gravity 400 + blend add + cliptype tracer3sparks + clipcount 1 + inwater tracer3bubble +} + +r_part tr_vorelight +{ + lighttime 0 + lightshadows 0 + lightradius 150 + lightrgb 0.5 0 0.5 +} + +r_part tracer3bits +{ + texture "ball" + type texturedspark + count 1 + scale 1.3 + scalefactor 1 + veladd 0 + randomvel -111 + alpha 0.4 + die 0.2 + rgb 255 128 76 + stains 0 + friction 0 + gravity 400 + blend add +} + +r_part tracer3bubble +{ + texture "particles/bubble.png" + count 1 + scale 0.1 + scalerand 6 + alpha 1 + die 1.5 + diesubrand 0.4 + blend add + veladd 0 + randomvel 10 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -50 + scalefactor 1 +} + +//haze pyro flamethrower (much of this is Jedilamma's) + +r_part pyroflame11 +{ + +} + +r_part pyroflamexp +{ + texture "particles/flame" + scale 55 + scalerand 30 + scaledelta -20 + count 1 + die 0.3 + diesubrand 0.2 + randomvel 24 + alpha 0.4 + gravity 0 + rgb 255 160 128 + friction 1 + blend add + spawnmode ball + spawnorg 1 0 + spawnvel 0 + scalefactor 1 + inwater gunbubble2 +} + +r_part pyroflame1 +{ + texture "particles/flame" + scale 55 + scalerand 30 + scaledelta -20 + count 0.5 + die 0.6 + diesubrand 0.2 + randomvel 24 + alpha 0.4 + gravity 0 + rgb 255 160 128 + friction 1 + blend add + spawnmode ball + spawnorg 1 0 + spawnvel 0 + scalefactor 1 + emit pyroflame2 + emitinterval 1 + inwater gunbubble2 +} + +r_part pyroflame2 +{ + texture "particles/flame" + scale 55 + scalefactor 1 + scaledelta 1 + count 1 + die 1.2 + diesubrand 0.2 + randomvel 20 + alpha 0.5 + rgb 25 5 1 + rgbdelta -25 -5 -1 + blend modulate + spawnmode ball + spawnorg -10 -10 + spawnvel 10 10 + emit pyrosparks + emitinterval 1.5 + gravity -20 + inwater gunbubble2 +} + +r_part pyrosparks +{ + texture "" + count 1 + scale 0 + alpha 0.3 + die 0.8 + randomvel 1 + veladd 1 + rgb 255 180 80 + gravity 0 + blend add + clipcount 1 + scalefactor 1 + spawnorg 2 2 + spawnvel 5 22 + cliptype pyroflame3 + clipcount 1 + inwater gunbubble +} + +r_part pyroflame3 +{ + texture "particles/flame" + scale 20 + count 2 + die 0.5 + randomvel 10 + alpha 0.5 + gravity 0 + red 160 + green 100 + blue 75 + friction 1 + blend add + spawnmode box + scalefactor 1 + emitinterval 0.33 + emitintevalrand 0.33 + emit pyroflame4 + stains 0 + inwater gunbubble2 +} + +r_part pyroflame4 +{ + texture "particles/flame" + scale 30 + count 2 + die 0.5 + randomvel 20 + alpha 0.5 + gravity -100 + red 160 + green 100 + blue 75 + friction 1 + blend add + spawnmode box + scalefactor 1 + emit pyroflame5 + emitinterval 0.5 + inwater gunbubble +} + +r_part pyroflame5 +{ + texture "particles/flame" + scale 15 + count 2 + die 0.5 + randomvel 10 + alpha 0.2 + gravity -100 + red 10 + green 5 + blue 2 + friction 1 + blend modulate + spawnmode box + scalefactor 1 + inwater gunbubble +} + +//haze blood + +r_part te_blood +{ + texture "particles/generic.png" + count 5 + scale 1 + scalerand 8 + alpha 0.4 + die 0.4 + diesubrand 0.2 + rgb 11 1 1 + stains 0 + scalefactor 1 + assoc te_blooda + spawnmode ball + spawnvel 5 5 + spawnorg 2 2 + randomvel 10 + gravity 100 + inwater waterblood +} + + +r_part te_blooda +{ + texture "particles/bloodsplat1.tga" + count 5 + scale 11 + scalerand 11 + alpha 0.3 + alphachange 1 + die 0.3 + diesubrand 0.1 + rgb 22 1 1 + gravity 0 + stains 0 + scalefactor 1 + spawnvel -22 + assoc te_bloodb +} + +r_part te_bloodb +{ + texture "ball" + type texturedspark + count 5 + scale 0.3 + scalefactor 1 + veladd 11 + randomvel 30 + spawnorg 0 5 + spawnvel 0 40 + alpha 0.5 + die 1 + diesubrand 0.1 + rgb 11 1 1 + stains 0 + gravity 200 + blend modulate + assoc te_bloodc +} + +r_part te_bloodc +{ + texture "ball" + type normal + count 4 + scale 0.2 + scalerand 0.9 + scalefactor 1 + veladd 10 + randomvel 30 + spawnvel 0 50 + spawnorg 0 5 + alpha 0.6 + die 0.9 + diesubrand 0.1 + rgb 11 1 1 + stains 0 + gravity 200 + blend modulate + cliptype bloodsplat_small + clipcount 0.1 +} + +r_part bloodsplat_small +{ + type decal + texture "particles/bloodsplat1.tga" + count 1 + scale 10 + scalerand 20 + alpha 0.4 + die 20 + rgb 33 1 1 +} + +r_part bloodsplat_small_dark +{ + type decal + texture "particles/bloodsplat1.tga" + count 1 + scale 10 + scalerand 20 + alpha 0.4 + die 20 + rgb 5 1 1 +} + +r_partredirect te_blood2 te_blood +r_partredirect te_blood3 te_blood +r_partredirect te_null te_blood + +r_part pe_default //a fallback from high.cfg +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 4 + veladd 15 + die 0.4 + alphadelta 0 + diesubrand 0.4 + gravity 40 + spawnorg 8 +} + +r_part pe_73 //zombies + buttons bleed this +{ + texture "particles/generic.png" + count 0.5 + scale 1 + scalerand 8 + alpha 0.6 + die 0.4 + diesubrand 0.2 + rgb 11 1 1 + scalefactor 1 + assoc te_blooda + spawnvel 5 5 + spawnorg 2 2 + randomvel 10 + inwater waterblood + gravity 100 +} + +r_part pe_225 //single player lightning blood +{ + texture "particles/generic.png" + count 1 + scale 1 + scalerand 8 + alpha 0 + die 0 + scalefactor 1 + spawnvel 60 + spawnorg 1 1 + rgb 5 1 1 + blend modulate + assoc te_lightningblooda + inwater waterblood + gravity 100 +} + +r_part tr_slightblood //t_zomgib //meaty chunk gibs. zombies throw, shambler+fiend hack this off you. +{ + texture "particles/generic.png" + count 1 + scale 1 + scalerand 9 + alpha 0.5 + die 0.3 + diesubrand 0.2 + rgb 11 1 1 + scalefactor 1 + assoc te_blooda + spawnvel 5 5 + spawnorg 2 2 + randomvel 10 + inwater waterblood + gravity 100 +} + +r_part t_gib //zombies explode this +{ + texture "particles/generic.png" + count 1 + scale 11 + scalerand 6 + alpha 0.6 + die 0.4 + diesubrand 0.2 + rgb 11 1 1 + stains 0 + scalefactor 1 + assoc te_blooda + spawnvel 5 5 + spawnorg 2 2 + randomvel 10 + inwater waterblood + gravity 100 +} + +r_part te_lightningblood //deathmatch lightning blood +{ + texture "particles/generic.png" + count 1 + scale 1 + scalerand 8 + alpha 0 + die 0 + scalefactor 1 + spawnvel 60 + spawnorg 1 1 + rgb 5 1 1 + blend modulate + assoc te_lightningblooda + inwater waterblood + gravity 100 +} + +r_part te_lightningblooda +{ + texture "particles/generic.png" + count 1 + scale 1 + scalerand 8 + alpha 0.4 + die 0.7 + diesubrand 0.2 + rgb 5 1 1 + scalefactor 1 + assoc te_lightningbloodb + spawnvel 5 5 + spawnorg 2 2 + randomvel 10 + inwater waterblood + gravity 100 + up 10 +} + +r_part te_lightningbloodb +{ + texture "particles/bloodsplat2.tga" + count 5 //1 + scale 22 + scalerand 11 + alpha 0.1 + die 0.2 + rgb 5 1 1 + gravity 0 + scalefactor 1 + spawnvel -2 + assoc te_lightningbloodc + inwater waterblood + up 10 +} + +r_part te_lightningbloodc +{ + texture "ball" + type normal + count 22 + scale 0.4 + scalerand 0.9 + scalefactor 1 + veladd 10 + randomvel 40 + spawnvel 20 50 + spawnorg 5 5 + alpha 1 + die 1.3 + rgb 11 1 1 + stains 0 + gravity 200 + blend modulate + assoc te_lightningbloodd + inwater waterblood + up 10 +} + +r_part te_lightningbloodd +{ + texture "ball" + type texturedspark + count 5 + scale 0.3 + scalefactor 1 + veladd 5 + randomvel 30 + spawnorg 5 5 + spawnvel 20 40 + alpha 0.8 + die 1 + rgb 11 1 1 + stains 0 + gravity 300 + blend modulate + assoc te_bloodc + inwater waterblood + cliptype bloodsplat_small_dark + clipcount 1 + up 10 +} + +r_part waterblood +{ + texture "particles/generic.png" + count 0.4 + scale 33 + scalerand 11 + scaledelta 60 + alpha 0.4 + alphachange 1 + die 2 + rgb 22 1 1 + gravity 0 + stains 0 + scalefactor 1 + spawnorg 3 3 + spawnvel 11 11 +} + +//hazed nail trail + +r_part nailtrail +{ + texture "" + type sparkfan + count 1 + scale 1 + alpha 0.05 + die 0.2 + rgb 122 122 122 + gravity 0 + blend modulate + scalefactor 1 + inwater nailbubble +} + +r_part nailbubble +{ + texture "particles/bubble.png" + count 0.1 + scale 0.1 + scalerand 6 + alpha 1 + die 1.5 + diesubrand 0.4 + blend add + veladd 0 + randomvel 10 + spawnorg 3 3 + spawnvel 3 3 + rgb 255 255 255 + gravity -50 + scalefactor 1 +} + +////hazed lava + +r_part tex_*lava1 +{ + texture "particles/exp.tga" + scale 66 + scalerand 80 + rgb 255 69 0 + count 11 + alpha 0 + blend add + die 1.1 + up -6 + diesubrand 0.2 + veladd 0 + randomvel -22 + gravity 22 + scalefactor 1 + spawnmode ball + rampmode delta + ramp -50 -15 0 -0.3 0 + ramp -50 -15 0 -0.3 0 + ramp -50 -15 0 -0.3 0 + ramp -50 -15 0 0.2 0 + ramp -50 -9 0 0.2 0 + ramp 0 0 0 0.2 0 + assoc lava2 + rotationstart 0 360 + rotationspeed 0 55 +} + +r_part lava2 +{ + texture "textures/generic.png" + scale 86 + scalerand 46 + count 1 + alpha 0.3 + blend modulate + rgb 1 1 1 + die 4 + diesubrand 1.2 + veladd 0 + randomvel 5 + spawnvel 10 0 + spawnorg 10 + spawnmode circle + gravity -10 + scalefactor 1 + cliptype nothing + clipcount 0 + up 1 //25 + rotationstart 0 360 + rotationspeed -180 180 + assoc lava3 + rampmode delta + ramp 0 0 0 -0.2 20 + ramp 1 1 1 -0.4 20 + ramp 1 1 1 0.2 20 + ramp 1 1 1 0.2 20 + ramp 1 1 1 0.2 20 +} + +r_part lava3 +{ + texture "particles/generic.png" + scale 1 + scalerand 8 + rgb 255 69 0 + count 1 + alpha 0.3 + blend add + die 1.3 + diesubrand 0.2 + veladd 55 + randomvel 55 + gravity 155 + scalefactor 1 + spawnmode ball + rampmode delta + ramp 0 0 0 -0.3 + ramp 0 0 0 0.5 + cliptype nothing + clipcount 0 + up 10 +} +r_partredirect tex_*lava_2 tex_*lava1 +r_partredirect tex_*lava2 tex_*lava1 +r_partredirect tex_*lava5 tex_*lava1 +r_partredirect tex_*lava_q3 tex_*lava1 +r_partredirect tex_*lava_dc tex_*lava1 +r_partredirect tex_*safelava tex_*lava1 +r_partredirect tex_*lava10 tex_*lava1 +r_partredirect tex_*lavakelvin tex_*lava1 +r_partredirect tex_*lavahell tex_*lava1 +r_partredirect tex_*lava_frib tex_*lava1 + +//haze slime + +r_part tex_*slime +{ + texture "particles/smokelite.png" + scale 40 + scalerand 20 + up -6 + count 2 + alpha 1 + blend add + rgb 255 255 255 + die 3.5 + veladd 0 + randomvel 11 + gravity -15 + scalefactor 1 + spawnmode ball + assoc slime2 +} + +r_part slime2 +{ + texture "particles/flame.tga" + scale 6 + scalerand 5 + count 1 + alpha 0.4 + up 1 + blend add + rgb 0 255 0 + die 0.5 + veladd 35 + randomvel 25 + gravity 300 + scalefactor 1 + spawnmode circle +} +r_partredirect tex_*slime10 tex_*slime +r_partredirect tex_*slime0 tex_*slime +r_partredirect tex_*slime1 tex_*slime +r_partredirect tex_*slimekelvin tex_*slime +r_partredirect tex_*slimeDranzFRIB tex_*slime +r_partredirect tex_*slimeik1tex_*slime + +//hellknights fireball???not sure. +r_part t_tracer2z +{ + texture "particles/inferno1.tga" + step 5 + scale 10 + scalerand 6 + alpha 0.7 + die 0.7 + randomvel 2 + rotationangle 360 + veladd 0 + rgb 255 255 255 + blend blend + gravity -20 + scalefactor 1 + scaledelta 15 + friction 0.1 + stains 0 + rgbdelta -555 -555 -555 + emit knightflame2 + emitinterval 1 + inwater gunbubble2 +} + +//hellknights fireball impact + +r_part te_knightspike +{ + texture "particles/flame" + scale + scalerand 30 + scaledelta -20 + count 10 + die 0.6 + diesubrand 0.2 + randomvel 24 + alpha 0.6 + gravity 0 + rgb 255 160 128 + friction 1 + blend add + spawnmode ball + spawnorg 1 0 + spawnvel 0 + scalefactor 1 + emit knightflame2 + emitinterval 1 + inwater gunbubble2 + +} + +//hellknights fireball + +r_part tr_knightspike +{ + texture "particles/flame" + scale 11 + scalerand 30 + scaledelta -20 + count 1 + die 0.5 + diesubrand 0.2 + randomvel 24 + alpha 0.3 + gravity 0 + rgb 255 160 128 + rgbdelta -1000 -1000 -1000 + friction 1 + blend add + spawnmode ball + spawnorg 1 0 + spawnvel 0 + scalefactor 1 + emit knightflame2 + emitinterval 1 + inwater gunbubble2 + lighttime 1 + lightradiusfade 35 + lightshadows 1 + lightradius 75 + lightrgb 0.8 0.1 0.1 + +} + +r_part knightflame2 +{ + texture "particles/flame" + scale 55 + scalefactor 1 + scaledelta -20 + count 1 + die 1.2 + randomvel 20 + alpha 0.3 + rgb 25 5 1 + rgbdelta -25 -5 -1 + blend modulate + spawnmode box + spawnorg -10 -10 + spawnvel 10 10 + emit knightsparks + emitinterval 1.5 + gravity -20 + inwater gunbubble +} + +r_part knightsparks +{ + texture "" + count 1 + scale 0 + alpha 0.3 + die 0.3 + randomvel 1 + veladd 1 + rgb 255 180 80 + gravity 0 + blend add + scalefactor 1 + spawnorg 2 2 + spawnvel 5 22 + cliptype knightflame3 + clipcount 1 + inwater gunbubble +} + +r_part knightflame3 +{ + texture "particles/flame" + scale 20 + count 2 + die 3 + randomvel 10 + alpha 0.5 + gravity 0 + rgb 160 100 75 + friction 1 + blend add + spawnmode box + scalefactor 1 + emitinterval 0.33 + emitintervalrand 0.33 + emit knightflame4 + stains 0 + inwater gunbubble +} + + +r_part knightflame4 +{ + texture "particles/flame" + scale 30 + count 2 + die 0.9 + randomvel 20 + alpha 0.5 + gravity -100 + rgb 160 100 75 + friction 1 + blend add + spawnmode box + scalefactor 1 + emit knightflame5 + emitinterval 0.5 + inwater gunbubble +} + +r_part knightflame5 +{ + texture "particles/flame" + scale 15 + count 2 + die 0.9 + randomvel 10 + alpha 0.2 + gravity -100 + rgb 10 5 2 + friction 1 + blend modulate + spawnmode box + scalefactor 1 + inwater gunbubble +} + +//haze wizard acid trail + +r_part tr_wizspike +{ + count 1 + texture "particles/grate8.tga" + type texturedspark + scale 1 + scalerand 5 + scalefactor 1 + scaledelta -15 + rgb 5 15 5 + friction 0 + die 0.6 + alpha 0.6 + blend add + spawnmode spiral + randomvel 12 + veladd -210 + spawnorg 2 2 + lighttime 0.5 + lightradiusfade 75 + lightshadows 1 + lightradius 150 + lightrgb 0.1 0.7 0.1 +} + +r_part +tr_wizspike +{ + count 1 + texture "particles/generic.png" + scale 0.1 + scalerand 3 + scalefactor 1 + scaledelta -5 + spawnmode ball + spawnorg 4 4 + rgb 5 15 5 + rgbrand 5 15 5 + friction 0 + die 0.3 + alpha 1 + blend add +} + +//haze wizard acid hit +r_part te_wizspike +{ + count 16 + texture "particles/spot01drk.tga" + scale 10 + scalerand 10 + scalefactor 1 + rgb 5 32 5 + friction 0 + die 0.4 + gravity 20 + alpha 0.6 + blend add + spawnmode circle + randomvel -25 + veladd -24 + spawnorg 2 +} + +//haze enforcer laser trail +r_part tr_enforcerlaser +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 5 + step 4 + alpha 0.3 + die 0.3 + rgb 255 69 0 + veladd -260 + spawnmode spiral + spawnvel 0 + randomvel 32 + friction 0 + scalefactor 1 + blend add + lighttime 0.2 + lightshadows 1 + lightradius 150 + lightrgb 1 0.27 0 + lightrgbfade 5 1 0 + lightcorona 2 0.25 + inwater bubbletrail1 +} + +//haze custom-tf airfist blast +r_part ctf_airblast_0 +{ + +} +r_part ctf_airblast_1 +{ + scale 1 + scalerand 2 + scalefactor 1 + count 3 + spawnmode box + spawnorg 25 25 + texture "particles/generic.png" + alpha 0.4 + veladd 100 + randomvel 100 + die 0.2 + rgb 255 255 255 + gravity 0 +} + +//haze custom TF smoke screen grenade +r_part ctf_smokescreen_0 +{ + +} + +r_part ctf_smokescreen_1 +{ + texture "particles/smokelite.png" + scale 120 + scalerand 120 + count 1 + alpha 0.6 + blend add + rgb 255 255 255 + die 2.5 + diesubrand 0.5 + veladd 50 + randomvel 50 + gravity -10 + scalefactor 1 + spawnmode box + spawnorg 60 60 +} + +r_part +ctf_smokescreen_1 +{ + texture "particles/smoketenebrae.tga" + scale 240 + scalerand 120 + count 0.2 + alpha 0 + blend add + rgb 255 255 255 + die 2.5 + diesubrand 0.5 + veladd 10 + randomvel 10 + gravity 0 + scalefactor 1 + spawnmode box + spawnorg 60 60 + rampmode delta + ramp 0 0 0 -0.2 + ramp 0 0 0 0 + ramp 0 0 0 0.1 + ramp 0 0 0 0.1 + ramp 0 0 0 0.2 +} + +//haze customTF laser cannon +r_part ctf_lasercannon +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 4 + step 4 + alpha 0.3 + die 0.2 + rgb 255 69 0 + veladd -460 + spawnmode spiral + spawnvel 0 + randomvel 24 + friction 0 + scalefactor 1 + blend add + lighttime 0 + lightshadows 0 + lightradius 150 + lightrgb 1 0.27 0 + lightrgbfade 5 1 0 + inwater bubbletrail1 +} diff --git a/high.cfg b/high.cfg new file mode 100755 index 00000000..c83516a5 --- /dev/null +++ b/high.cfg @@ -0,0 +1,915 @@ +/////////////////////////////// +//rain +r_part te_rain +{ + texture ball; scalefactor 1; count 1; alpha 0.4; rgb 255 255 255; die 2; veladd 2; scale 2; type texturedspark + cliptype rainsplash + clipbounce 1 + clipcount 5 +} + +r_part rainsplash +{ + randomvel 50 50 + count 1; + texture ball; scalefactor 1; alpha 0.1; rgb 255 255 255; die 0.4; scale 50; + stretchfactor 4 + veladd 50; scale 1; type texturedspark + gravity 400 +} + +/////////////////////////////// +//rocket trail + +// flame trail +r_part tr_rocket +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + step 1 + scale 12 + alpha 0.4 + die 0.5 + rgb 255 127 100 + rgbdelta -14 -300 -300 + blend add + scalefactor 1 + scaledelta -15 +} + +// smoke puffs +r_part +tr_rocket +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + step 5 + scale 30 + alpha 0.2 + die 0.75 + //diesubrand 10.25 + randomvel 0.2 + rgb 5 5 5 + //rgbdelta -230 -45 -9 + gravity -15 + scalefactor 1 + scaledelta 20 + spawnvel 5 +} + + +// burst sparks +r_part +tr_rocket +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 1 + scale 2 + scalefactor 1 + scaledelta -15 + alpha 0.2 + die 0.25 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 1 + spawnvel 50 + veladd 500 + friction 0.01 + gravity 100 +} + +/////////////////////////////////////////// +//alternate rocket trail, which is used by a handful of qw players. +//r_part tr_altrocket +//{ +//} + + +/////////////////////////////////////////// +//grenade trail + +r_part tr_grenade +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + step 6 + scale 32 + scaledelta 12 + alpha 0.3 + die 1.25 + randomvel 2 + veladd 15 + rgb 75 75 75 + //rgb 255 50 50 + //rgbdelta -255 -75 -75 + gravity -25 + scalefactor 1 + blend modulate +} +r_part +tr_grenade +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + scale 1 + scaledelta 0.25 + alpha 0.2 + step 4 + die 0.8 + randomvel 0 + rgb 255 150 150 + rgbdelta 0 -150 -150 + type beam + blend add +} + +////////////////////////////////// +//shotgun impacts +r_part gunshotsmoke +{ + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 3 + scale 25 + scalefactor 1 + die 0.8 + alpha 0.12 + rgb 32 32 32 + blend add + spawnmode ball + spawnorg 2 + spawnvel 20 + veladd -20 +} +r_part te_gunshot +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 3 + scale 2 + scalefactor 1 + alpha 0.5 + die 0.8 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 1 + spawnvel 100 + veladd -80 + friction 0.3 + gravity 400 + assoc gunshotsmoke +} + +////////////////////////////////// +//nail impacts + +r_part te_spike +{ + type sparkfan + count 10 + scale 1 + scalefactor 1 + alpha 0.5 + die 0.2 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 12 + spawnvel 300 +} +r_part +te_spike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 1 + scalefactor 1 + scaledelta 190 + die 0.1 + alpha 0.6 + rgb 255 128 0 + blend add + assoc gunshotsmoke +} + +r_part te_superspike +{ + type sparkfan + count 20 + scale 1 + scalefactor 1 + alpha 0.5 + die 0.2 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 12 + spawnvel 300 +} +r_part +te_superspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 1 + scalefactor 1 + scaledelta 190 + die 0.1 + alpha 0.6 + rgb 255 128 0 + blend add + assoc gunshotsmoke +} + +//////////////////////////////////////////////// +//explosion + +//red bit +r_part te_explosion +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + count 1 + scale 500 + alpha 0.4 + die 0.2 + rgb 255 127 100 + rgbdelta -14 -300 -300 + blend add + scalefactor 1 + scaledelta -15 + randomvel 0 +// lightradius 350 +// lightrgb 1.4 1.2 1.05 +// lighttime 0.5 +// lightradiusfade 350 +// lightrgbfade 2 2 2 +} +//smoke +r_part +te_explosion +{ + texture "particles/fteparticlefont.tga" + tcoords 97 97 191 191 256 + count 7 + scale 300 + alpha 0.2 + die 0.8 + //diesubrand 10.25 + randomvel 100 + rgb 5 5 5 + //rgbdelta -230 -45 -9 + gravity -15 + scalefactor 1 + scaledelta 40 + spawnvel 5 +} +// burst sparks +r_part +te_explosion +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 100 + scale 5 + scalefactor 1 + scaledelta -15 + alpha 0.2 + die 0.5 + rgb 255 128 0 + blend add + spawnmode ball + spawnorg 1 + randomvel 1000 + friction 0.01 + gravity 100 + stretchfactor -80 +} + +//hide lights in explosions. +//r_explosionlight 0 + +//hide the explosion sprite in qw +cl_expsprite 0 +//hide it in nq - WARNING: some mods use this sprite as a flame thrower. +//r_effect "progs/s_explod.spr" hidden 1 + + +////////////////////////////////////////// +//rogue te_explosion2 effect +//note: if not otherwise defined, te_explosion2_BASE_RAND maps to this, and specifies the palette colours. +r_part te_explosion2 +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 256 + scale 5 + scalefactor 1 + scaledelta -15 + alpha 0.2 + die 0.5 + blend add + spawnmode ball + spawnorg 1 + randomvel 1000 + friction 0.01 + gravity 100 + stretchfactor -80 +} +//dragon fireball +//r_part te_explosion2_228_5 + +//rogue multigrenade sub explosion +//also triggered from a shielded rogue player touching another player (and doing some damage) +//also used during the ending. +//red particles +//r_part te_explosion2_230_5 + +//rogue plasma explosion +//also rogue timemachine explosion +//white particles splaying outwards +//r_part te_explosion2_244_3 + +////////////////////////////////////////// +//for when a spawn dies. +//also used by TF for emp explosions. +r_part te_tarexplosion +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 128 + scale 5 + scalefactor 1 + scaledelta -15 + rgb 0 0 17 + alpha 0.5 + die 0.5 + spawnmode ball + spawnorg 1 + randomvel 500 + friction 0.01 + gravity 100 + stretchfactor -80 +} +r_part +te_tarexplosion +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 256 + scale 5 + scalefactor 1 + scaledelta -15 + rgb 83 67 115 + alpha 0.3 + die 0.5 + blend add + spawnmode ball + spawnorg 1 + randomvel 500 + friction 0.01 + gravity 100 + stretchfactor -80 +} + +////////////////////////////////////////// +//cthon falling into lava. +//often also used for TF gas grenades. +r_part te_lavasplash +{ + texture "particles/fteparticlefont.tga" + tcoords 129 1 191 63 256 + count 654 + scale 15 + alpha 0.7 + die 4 + randomvel 64 + rgb 255 128 128 + gravity 50 + blend add + spawnorg 192 64 + up 48 +} + +////////////////////////////////////////// +//FIXME: what if we don't have glsl support? +r_part te_teleport +{ + scale 250 + count 1 + alpha 0.3 + die 0.5 + scalefactor 1 + rotationstart 45 + rotationspeed 0 + + shader + { + surfaceparm noshadows + surfaceparm nodlight + glslprogram + { + varying vec2 tcoord; + varying vec4 scoord; + varying float alph; +#ifdef VERTEX_SHADER + attribute vec2 v_texcoord; + attribute vec4 v_colour; + + void main(void) + { + scoord = ftetransform(); + tcoord = (v_texcoord.st - 0.5)*2.0; + alph = v_colour.a; + gl_Position = scoord; + } +#endif +#ifdef FRAGMENT_SHADER + uniform sampler2D s_t0; + void main(void) + { + vec2 nst; + float f; + nst = scoord.xy / scoord.w; + nst = (1.0 + nst)/2.0; + f = 1.0 - length(tcoord); +// f = 1.0 - tcoord*tcoord; + if (f < 0.0) discard; + f *= alph; + gl_FragColor = texture2D(s_t0, nst - tcoord*f); + } +#endif + } + { + map $currentrender + blendfunc blend + } + } +} + + +////////////////////////////////////////// +//hellknight +r_part tr_knightspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 1 + alpha 0.6 + die 0.2 + rgb 192 96 48 + veladd 0 + randomvel 2 + friction 4 + scalefactor 0.825 + blend add + spawnmode spiral + spawnvel -50 + lighttime 0 + lightshadows 0 + lightradius 150 + lightrgb 0.75 0.37 0.18 +} + +r_part te_knightspike +{ + type sparkfan + count 200 + scale 3 + scalefactor 1 + alpha 0.5 + die 0.5 + rgb 192 96 48 + blend add + spawnmode ball + spawnorg 12 + spawnvel 100 + stretchfactor 10 +} + +///////////////////////////////////////// +//vore missiles +r_part tr_vorespike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 1 + alpha 0.6 + die 0.5 + rgb 192 96 192 + veladd 15 + spawnmode spiral + spawnvel 50 + randomvel 0 + friction 0 + scalefactor 1 + blend add + lighttime 0 + lightshadows 0 + lightradius 150 + lightrgb 0.75 0.37 0.75 +} +//rygel's pack sucks +r_trail "progs/v_spike.mdl" tr_vorespike + + +//////////////////// +//enforcer laser effect +r_part tr_enforcerlaser +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 4 + alpha 0.3 + die 0.5 + rgb 255 69 0 + veladd -32 + spawnmode spiral + spawnvel 16 + randomvel 32 + friction 0 + scalefactor 1 + blend add + lighttime 0.2 + lightshadows 0 + lightradius 150 + lightrgb 1 0.27 0 + lightrgbfade 5 1 0 + lightcorona 2 0.25 +} +r_trail "progs/laser.mdl" tr_enforcerlaser + +///////////////////////////////////////// +//rogue wrath enemy's projectiles +r_part tr_wrathball +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 4 + alpha 0.3 + die 0.5 + rgb 255 0 0 + veladd -32 + spawnmode spiral + spawnvel 16 + randomvel 32 + friction 0 + scalefactor 1 + blend add + lighttime 0.2 + lightshadows 0 + lightradius 150 + lightrgb 1 0.27 0 + lightrgbfade 5 1 0 + lightcorona 2 0.5 +} +r_trail "progs/w_ball.mdl" tr_wrathball + +//wrath death +//grey particles +//no difference from the fallback except for the blend mode. this should ensure that we are not quite so invisible. +r_part te_explosion2_0_4 +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 65 31 95 256 8 32 + count 256 + scale 5 + scalefactor 1 + scaledelta -15 + alpha 0.2 + die 0.5 + spawnmode ball + spawnorg 1 + randomvel 1000 + friction 0.01 + gravity 100 + stretchfactor -80 +} + +///////////////////////////////////////// +//rogue lavaspikes +r_part tr_lavaspike +{ + type spark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 4 + alpha 0.3 + die 0.5 + rgb 255 0 0 + veladd -32 + spawnmode spiral + spawnvel 16 + randomvel 32 + friction 0 + scalefactor 1 + blend add +} +r_trail "progs/lspike.mdl" tr_lavaspike + +///////////////////////////////////////// +//rogue plasma gun +r_part tr_plasma +{ + type texturedspark + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 4 + alpha 0.3 + die 0.25 + rgb 128 128 255 + veladd -32 + spawnmode spiral + spawnvel 16 + randomvel 32 + friction 0 + scalefactor 1 + blend add + lighttime 0.2 + lightshadows 0 + lightradius 150 + lightrgb 1 1 2 + lightrgbfade 5 1 0.5 + lightcorona 2 0.5 +} +r_trail "progs/plasma.mdl" tr_plasma + + +///////////////////////////////////////// +//scrag missiles. +r_part tr_wizspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 4 + alpha 0.6 + die 0.2 + rgb 25 200 25 + veladd 0 + randomvel 2 + friction 4 + scalefactor 0.825 + spawnmode spiral + spawnvel 25 + blend add + lighttime 2 + lightradiusfade 75 + lightshadows 0 + lightradius 150 + lightrgb 0.1 0.7 0.1 +} + +r_part tr_wizspike2 +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 4 + step 1 + alpha 0.6 + die 0.2 + rgb 25 200 25 + veladd 64 + randomvel 64 + friction 4 + scalefactor 0.825 + spawnmode spiral + spawnvel 25 + blend add +} +//scrag impact +r_part te_wizspike +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + alpha 0.6 + rgb 25 200 25 + friction 0 + scalefactor 0.825 + blend add + count 5 + veladd -256 + randomvel 256 + die 1 + diesubrand 0.5 + gravity 800 + emit tr_wizspike2 + emitinterval -1 + bounce 1.5 +} + +///////////////////////////////////////// +//shambler stuff +r_part shambercharging +{ + spawnmode ball + count 200 + spawnorg 128 + spawnvel -256 + texture "particles/fteparticlefont.tga" + tcoords 1 1 63 63 256 2 64 + scale 4 + alpha 1 + die 0.5 + orgadd -64 + rotationspeed 90 + rotationstart 0 360 + rgb 100 100 250 + rgbrand 0 0 0 + gravity 0 + scalefactor 0.4 + lighttime 0 + lightshadows 0 + lightradius 400 + lightrgb 2 2 2 +} +r_effect progs/s_light.mdl shambercharging 0 + +///////////////////////////////////////// +//blood effects +r_part te_blood +{ + texture fte_bloodparticle + blend subtract + count 1 + scale 32 + alpha 0 + die 1 + randomvel 64 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 32 64 64 + rgbdelta -32 -64 -64 + gravity 200 + scalefactor 0.8 +} + +r_part high.pe_73 +{ + texture fte_bloodparticle + blend subtract + count 1 + scale 32 + alpha 0 + die 1 + randomvel 64 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 32 64 64 + rgbdelta -32 -64 -64 + gravity 200 + scalefactor 0.8 +} + +r_part te_lightningblood +{ + texture fte_bloodparticle + blend subtract + count 1 + scale 32 + alpha 0 + die 1 + randomvel 32 + veladd 5 + rotationspeed 90 + rotationstart 0 360 + rgb 64 128 128 + rgbdelta -64 -128 -128 + gravity 200 + scalefactor 0.8 +} +r_part high.pe_225 +{ + texture fte_bloodparticle + blend subtract + count 0.5 + scale 32 + alpha 0 + die 1 + randomvel 32 + veladd 5 + rotationspeed 90 + rotationstart 0 360 + rgb 64 128 128 + rgbdelta -64 -128 -128 + gravity 200 + scalefactor 0.8 +} + +///////////////////////////////////////// +//zombie body-part blood trails +r_part tr_slightblood +{ + texture fte_bloodparticle + blend subtract +// tcoords 1 1 63 63 256 2 64 + step 16 + scale 64 + alpha 0 + die 1 + randomvel 32 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 64 128 128 + rgbdelta -64 -128 -128 + gravity 200 + scalefactor 0.8 + scaledelta -10 + stains -0.5 +} + +////////////////////////////////////////// +//regular ol' blood trails +r_part tr_blood +{ + texture fte_bloodparticle + blend subtract + step 8 + scale 64 + alpha 0 + die 1 + randomvel 32 + veladd 10 + rotationspeed 90 + rotationstart 0 360 + rgb 32 128 128 + rgbdelta -32 -128 -128 + gravity 200 + scalefactor 0.8 + scaledelta -10 + stains -0.5 +} + +////////////////////////////////// +//fallbacks + +r_part pe_default +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 4 + veladd 15 + die 0.4 + alphadelta 0 + diesubrand 0.4 + gravity 40 + spawnorg 8 +} +r_part pe_defaulttrail +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + scale 15 + step 1 + alpha 0.6 + die 0.2 + rgb 192 96 48 + veladd 0 + randomvel 2 + friction 4 + scalefactor 0.825 + spawnmode spiral + spawnvel 25 + blend add +} + +////////////////////////////////// +//map debugging +r_part pe_pointfile +{ + texture "particles/fteparticlefont.tga" + tcoords 1 97 95 191 256 + count 1 + scale 50 + die 30 + alphadelta 0 + rgb 255 255 0 +} + + + + + + + + + + + diff --git a/particles.txt b/particles.txt new file mode 100755 index 00000000..1493131f --- /dev/null +++ b/particles.txt @@ -0,0 +1,335 @@ +Example: +r_part blah +{ + texture textures/particles/myimage.tga + tcoords 0 0 64 64 64 + die 2 + scalefactor 1 + scale 20 + alpha 0.5 + rgb 255 0 0 + rgbdelta 0 128 128 + spawnmode ball + spawnorg 32 +} + +will give transparent (0.5) red particles that will fade to fully white when they go fully transparent 2 seconds later. +they will spawn within a ball of 32 units radius. + + +Types: +Always try to include a type. The engine will guess what your particle is meant to be otherwise, based on textures and other nonsense. That stuff is generally unreliable, and probably not what you want. + +Chaining: +You can add multiple particle descriptions to a single effect. The first should be 'r_part foo', and the others should be 'r_part +foo'. Particles without a + will reset the chain. + +Effect naming: +Effects loaded by r_particledesc will be given an internal prefix, eg: foo.cfg. +If the gamecode explicitly states foo.bar, your foo.cfg will automatically be executed, and will automatically use the bar effect from it. +The effect can still be overriden from a custom config by explicitly naming the effect foo.bar - the effect bar in the config foo will not override this, but would override bar on its own. + +Scale: +scale values are defined in 1/4th qu, for some reason. +scalefactor typically needs to be explicitly set to 1. this value affects how the particle scales with distance from view, rather than the actual size of the particle. + + + +texture + specifies to use an image named TEXTURENAME for this effect. + +tcoords [tscale] [rsmax] [rsstep] + specifies to use a subsection of the image. + if tscale is set, all units are divided by this. it is the virtual size of your texture. So a value of 1 means that your texture coords must be between 0 and 1. But if it properly matches your texture's size, the coords are in pixels. + if rsmax is present, each particle will use a random image. These images must be on a single row in your particle font. + rsstep specifies the stride (gap from one to the next) in your particle font, and is only needed if rsmax is present and greater than 1. + +rotationstart [max] + the particle will start with a rotation rotated between min and max. + if max is missing, the particle will always start with the min value. + +beamtexstep + only valid if the effect is a beam. + specifies the number of quake units per beam texture repitition. + +beamtexspeed + only valid if the effect is a beam. + controls how fast the texture scrolls on the beam. + +scale [max] + particles will start with a diameter of this many quake units. + actual scale will be randomly chosen between min and max (max defaults to equal if min is missing) + +scalerand + obsolete + overrides the scale max value + actual scale will be now be randomly chosen between min and min+extra + +scalefactor + controls how the particle scales with distance. + 1 makes the particle scale the same as anything else + 0 makes the particle not change size no matter how far it is + +scaledelta + controls how the particle scales over time + specifies the change in the particle scale per second. + +step + trails/beams only + specifies the distance between each particle in the trail (or beam). + +count + point/box effects only (not trails or beams) + specifies how many particles are spawned per effect (some classic effects contain an extra scaler which is multiplied by the resulting value) + +alpha + specifies the initial alpha value of the effect + +alphadelta + specifies how much the alpha value of the effect changes per second (subtracted) + +die + specifies the maximum age of the particle + +diesubrand + obsolete (set by die) + specifies the maximum starting age of the particle. + basically the particle will live up to this much less time. the alpha value will also be aged by the amount chosen by this value + +randomvel [vert] + controls how fast the particle moves when it spawns. This works regardless of any requested velocities. + if vert is not specified, horiz is used instead. + +veladd + controls how much of the effect's spawn velocity is used, can be greater than 1, or negative. + +orgadd + biases how much to add to the starting origin relative to the requested velocity. + +friction <| | > + Proportion of the particle's speed that should be lost from friction. Negative values are accepted. + +gravity + amount that the particle's velocity changes per second, in quake units. + +clipbounce + how much of the particle's velocity to use if the particle is clipped. See cliptype. + Defaults to 0.8 + +cliptype + Specifies which new effect to spawn when the particle hits something. + The origin and velocity of the particle are used to spawn the new effect. + The clipbounce value is used as a scaler for the reflected velocity. + If the effect named is the effect itself, the particle will merely bounce, instead of spawning a new effect. + FIXME: make default to bounce if clipbounce is set without cliptype. + +clipcount + The scaler to use for the number of particles to spawn upon a clip event. + Only valid in conjunction with cliptype. + +assoc + Specifies another effect to spawn at the same time that this effect is spawned. + Thus allowing two sets of particles from one effect. + +inwater + obsolete + Specifies a replacement effect to use when this one is spawned underwater. + assoc used is the replacement effect. the assoc value from the replaced effect is ignored (this includes +foo chains). + +overwater [content names] + Specifies that this particle should ONLY be spawned when out of water. + The particle will not spawn under water (this does not affect assoc chains). + Content names are a space-separated list of: water slime lava sky solid fluid. Default is fluid if not specified. + The r_part_contentswitch cvar must be enabled for this to function correctly. + +underwater [content names] + Specifies that this particle should ONLY be spawned when underwater. + The particle will not spawn if the spawn position is non-water (this does not affect assoc chains). + +colorindex [rand] + Specifies a palette index to spawn the particle with. + The index used is between index and index+rand. + overrides the normal starting colours. + +colorrand + obsolete. + replaces the [rand] part of the colorindex setting. + +citracer + only valid if colorindex is set. + adds a palette index between 0 and 3, based on the particle index in the effect or trail. + +red +green +blue +rgb +rgb + Specifies the initial red, green, and/or blue values for each particle. + Fully opaque is 255 or above. + Values above 255 are valid, but will remain opaque until the value drops below 255 from the colour deltas. + +redrand +greenrand +bluerand +rgbrand +rgbrand + Specifies how much extra red, green, and/or blue there may be for particles. + The initial colour will be multiplied by this amount before addition. + Each componant is separately randomized. EG, red might add nothing, while the full green is added, and only half the blue. + Fully opaque is 255 or above. + +redrandsync +greenrandsync +bluerandsync +rgbrandsync +rgbrandsync + Specifies how much extra red, green, and/or blue there may be for particles. + The initial colour will be multiplied by this amount before addition. + Componants are syncronised. EG, if the full amount of red is added, the full amount of green and blue will also be added. + Fully opaque is 255 or above. + +reddelta +greendelta +bluedelta +rgbdelta +rgbdelta + Specifies how much the red, green, and/or blue values of each particle change over time. + The value 255 is the value required to go from opaque to invisible in 1 second. + +rgbdeltatime + Specifies for how long the particle may change colours for. After this many seconds, the particle may no longer change colours (delta becomes 0). + +rampmode + mode may be one of: + none: uses rgb+rand+sync+delta+scale+scaledelta values. + absolute: the ramp overrides all colour+scale values. The effect moves from one absolute ramp index to the next. + delta: uses rgb+rand+sync+scale, but not delta values. All delta values come from the colour ramp instead. + + if not none, the ramp index used is based upon the particle's age, its lifetime, and how many ramp elements there are. + +rampindexlist [ [idx3 ...]] + Scale used is the currently set scale value. + Specifies a set of palette index values to use for the effect as part of the effect's colour ramp. + +rampindex + Specifies an individual palette index value and particle scale to use for the effect as part of the effect's colour ramp + +ramp [alpha] [scale] + Specifies a ramp index in rgb terms, regardless of palette. + +stains + How much the effect discolours the wall upon impact. + The stained colour is based upon the colour of the particle upon impact. + +blend + mode may be one of: add, subtract, blendcolour/blendcolor, blend + if the texture used is actually a shader, this is ignored. + +spawnmode [arg1] [arg2] + This affects how particles are positioned when they first spawn, and their initial velocities. + for point effects, mode may be one of: + box: simple axially aligned box of particles. + circle: particles spawn within a ball with uniform distance from the center. none will appear in the middle. + arg1: percentage of the circle to cover. a value of 5 will go around the circle 5 separate times. this can be used for weird beam effects. + areaspread: the radius of the ball + areaspreadvert: the height of the ball. if 0, will be a flat circle + ball: particles spawn randomly within a ball. + areaspread: the radius of the ball + areaspreadvert: the height of the ball. if 0, will be a flat circle. + telebox: matches quake's telebox + lavasplash: like chthon's lava splash + uniformcircle: particles are spawned in a circle with uniform distance between and from the center. z=0. + syncfield: particles spawn at predictable locations based upon time within a rough sphere. Only useful for effects that are regenerated+replaced every frame. + distball: + *default*: regular box. particles are spawned inside an axially aligned box. + + for trail effects, mode may be one of: + spiral: particles are given velocities perpendicular to the direction based on the distance moved. + tracer: particles spawn with alternating horizontal velocities (a wake effect). + *default*: particles spawn as a regular trail. + +spawnparam1 + obsolete. see spawnmode. + +spawnparam2 + obsolete. see spawnmode. + +up + the particle's starting origin is moved upwards by this amount (worldspace). + +type + How the particles look. + mode may be: + beam: valid only for trails. Particles form a single textured beam acting as nodes along it. + spark: particles are lines, their length depending upon their speed. + sparkfan: particles are non-planar triangle fans, their length depending upon their speed. + texturedspark: textured particles are aligned along their direction of movement, their length depending upon their speed, width equal to their scale. + cdecal/decal: particles are spawned only upon bsp geometry. They are clipped by it. + udecal: unclipped decal. exact semantics are subject to change. + *default*: Particles are regular, rotating, 2d images. + +isbeam + obsolete. + please use 'type beam' instead. + +spawntime +spawnchance + + +emit + Specifies the effect to periodically emit. + +emitinterval + Particles will not emit additional effects for this duration after emitting one. + +emitintervalrand + FIXME: fold into emitinterval + + +emitstart + Prevents the particle from emitting anything for this duration when it first spawns. + +spawnorg [vert] +spawnvel [vert] + obsolete + +viewspace [frac] + Specifies that this particle type should move relative to the camera. + Not compatible with splitscreen. + Should not normally be used in combination with clipping/bouncing. + +perframe + apply inverse frametime to count (causes emits to be per frame). + +averageout + average trail points from start to end, useful with t_lightning, etc + +nostate + Causes the particle system to ignore all state information. + +nospreadfirst + don't randomize org/vel for first generated particle + +nospreadlast + don't randomize org/vel for last generated particle + +sound [pitch] [delay] + When the effect is first spawned, the named sound will play with the given volume and attenuation at the center point. This may not work with all spawn methods, as it will ignore any count scales. + +lightradius +lightradiusfade +lightrgb +lightrgbfade +lighttime + Spawns a dlight when the effect is spawned. + dlight is removed when radius drops to 0 or the age is exceeded. + at this time it is not possible to override the corona/specular levels. + +lightcubemap + value 0 means no cubemap. + otherwise with eg cubemap 5, uses image files cubemaps/5ft.tga, cubemaps/5bk.tga, etc. + fixme: at the current time, the cubemap is world-aligned and cannot rotate. + +model + spawns sprites or models that fly away with random angles and run through some frame sequence. handy for simple gib effects. + +spawnstain \ No newline at end of file diff --git a/qs-spike.txt b/qs-spike.txt new file mode 100755 index 00000000..419a716c --- /dev/null +++ b/qs-spike.txt @@ -0,0 +1,233 @@ +this is an attempt to fix some of the deficiencies (as I see them) in quakespasm, while trying not to change how it feels to the user. + +changes: +extra builtins - + added lots of misc builtins, including: + string manipulation+buffers, + file access, + bsp introspection, + maths, + tracebox, + botclient stuff, + clientcommands, + etc. + Setting pr_checkextensions 0 will a) prevent extensions from being advertised to the mod. b) display a warning when any extended builtin is used (assuming it would otherwise crash anyway). +stub builtins - + also added stubs for builtins that either don't make sense in quakespasm or would need protocol extensions. + these are merely present to avoid crashes and will display a warning the first time they're called. +multicast - + supports pvs culling. still does not support phs. +precache builtins - + these can now be used mid-map. be warned that this will result in other clients disconnecting (will still display warnings on the server). +misc stuff - + MOVETYPE_FOLLOW and SOLID_CORPSE now work, .movement is supported. +cvar changes - + for mods, autocvars now work. the set+seta command also now works. + I bumped the cbuf size, because not only were well-documented mods were being punished for it, but also stuffcmded aliases were overflowing it. +clc_stringcmd - + rewrote client->server string commands a little. + this security fix blocks clients from being able to execute server-side aliases/cvars with names similar to 'allowed' console commands. +SV_TouchLinks - + rewrote this to avoid potential crashes within recursive touch events (yes, this can happen in rare cases, even in the prior quakespasm version). + may have minor behaviour differences, pr_checkextensions 0 disables this, restoring prior behaviour including instability-from-recursion. +single server socket - + the server now only uses a single socket per protocol family. + this makes NATs/firewalls much easier to deal with as servers no longer need to be DMZoned, only a single port needs to be forwarded.. +ipv6 - + this build can natively use ipv6, but will still assume ipv4 first. + uses non-hybrid sockets so this should work on winxp too. + use -noudp4 or -noudp6 to disable one and not the other. by default it'll try to use both. + reduced mtu size to avoid connectivity issues. still higher than vanilla though, which may also cause other issues. +master servers - + it is now possible to automatically list your server globally. hurrah... + unfortunately the server list is still lame and provides no ping info, so have fun with that. :) + thanks to ipv6, servers might get listed twice. + you can turn this on with sv_public, or via the 'new game' menu. +proquake angles - + now uses 16bit angles when connecting to proquake servers, or really most protocol15 servers including qrack+dp+etc. + also advertises protocols, allowing fte servers to serve protocol 666+999 as needed. +bug fixes - + spritegroups will now animate properly - this was a vanilla glquake bug. +model loader - + alpha-tested models now supported + spr32 sprites now supported (still using alpha testing rather than changing all sprites to use blending, so the alpha channel might as well still be 1bit) + many limit-exceeding models will now safely fail to load rather than crashing the engine. + note that some limits were not properly enforced before, and this might mean that a couple of models will newly fail to load (but won't crash the engine any more). + known-but-unsupported model formats will display a more helpful message, without crashing. unknown formats will similarly no longer crash. + bspx coloured lighting is now supported (somewhat common in the qw community). use -bspxlit argument with tyrutils-ericw's light util and discard the lit. + added support for tyrutil-ericw's qbsp's -notex argument that omits textures, reducing file size and avoiding gpl violations. still doesn't do replacements though. + fixed bsps that were compiled with vanilla qbsp's -noclip argument. will retain the correct view height, but will otherwise use the point-hull for everything. +binds menu - + if provided, will parse a bindlist.lst file from the gamedir. this should take the form of lines like: + +thecommand "some desc" "optional much longer description of it" + lines with a command that is just a hyphen are treated as comments/separators. + quakespasm ignores that third part, fte displays it on mouse-over. + if any binds are provided this way, they will completely replace the built-in list. + there is no limit to the binds that can be added, the menu will scroll, but there's no indicator that there are more/less. +particles - + now includes fte's scriptable particle system. + the config parser is a little different from fte (fte uses actual console commands, qs parses directly without the console). + this means that configs are limited to just r_part+r_effect+r_trail. setting cvars from particle configs are not supported here. + also currently missing support for models, embedded shaders (obviously), stains, viewspace particles. + tga images are supported, png+jpg are not. + no effects will be loaded by default, causing the engine to fall back on the existing particle system until a config is loaded. + users can set r_particledesc if they really specific particle effects. mods should include the config name as a namespace/prefix. + example usage (using FTE_SV_POINTPARTICLES with FTE_PART_NAMESPACES): + float myexplosion = particleeffectnum("mypartcfg.myexplosion"); + pointparticles(myexplosion, self.origin, trace_plane_normal, 1); + note that DP_SV_POINTPARTICLES and FTE_SV_POINTPARTICLES qc extensions are supposed to be identical, except that *certain* mods see DP_ and assume the entire particle system too, which is NOT the case, hence the need to check both extensions. + note that if FTE_PART_NAMESPACES is supported, then particleeffectnum("mypartcfg.myexplosion") will automatically load the 'mypartcfg' particle set, however the engine deals with that. + note that for dp compat, if FTE_PART_NAMESPACE_EFFECTINFO is supported, then "effectinfo.*" or "effectinfo_*.*" are supported namespaces that will should be compatible with DP's effects (if you ignore the prefix). + Precaching a single particle effect like this will include this config for all particles with no namespace. + So for dp compat, you can use the following: + if (checkextension("FTE_SV_POINTPARTICLES") || checkextension("DP_SV_POINTPARTICLES")) + { + if (checkextension("FTE_PART_NAMESPACE_EFFECTINFO")) + { + particleeffectnum("effectinfo.dummy"); //so clients will attempt to load the effectinfo namespace, if not already available. + particleeffectnum(strcat("effectinfo_", mapname, ".dummy")); //map-specific effects + } + //else we have no idea where we're loading the config from... lets hope its either dp or the user helps us out + //do precaches + myexplosioneffect = particleeffectnum("myexplosioneffect"); + } + //later + if (myexplosioneffect) + pointparticles(myexplosioneffect, self.origin, trace_plane_normal, 1); + else + te_explosion(self.origin); //'generic' fallback + (or you can just set 'r_particledesc effectinfo' in your mod's default.cfg and hope the user doesn't change it to something else) + note that particleeffectnum acts as a precache. you don't need to cache the result in a spawn function, but you do need to have called it early enough to avoid warning message. + note that any use of particleeffectnum will cause other clients to disconnect with 'illegible server message'. + it is *ENTIRELY* the modder's/user's responsibility to keep things consistent and not garish. pay close attention to particle sizes, texture resolution, etc. + mappers can add something like the following to their worldspawn entity: + "_texpart_sky1" "weather.tex_rainsky" + surfaces with the "sky1" texture will then act as emitters. this includes _texpart_*teleport or whatever. this doesn't require new gamecode. + r_partredirect can be used to redirect emitters (or effects) dynamically. redirections are normally meant to be a user feature, so mods should probably try to avoid tex_* effects in case the user switches gamedirs. + this command can work recursively, up to 5 itterations. +replacement network protocol - + namely FTE's nack-based PEXT2_REPLACEMENTDELTAS protocol extension. if you're a networking nerd, the archetecture is documented here: https://sourceforge.net/p/fteqw/code/HEAD/tree/trunk/specs/replacementdeltas.txt?format=raw + The extension applies to a base protocol, in this case 15, 666, or 999. There are some differences for QW vs NQ base protocols due to the netchan, these are not applicable to quakespasm. + the protocol is specced for lots of extended entity state, but most of that will be ignored/unused by the rest of the engine, and consequently won't be transmitted either. + automatically disabled per-client if unsupported by that client + all of the below will result in 'illegible server message' in older clients. usage of other extensions will be silently stripped, which may cause weirdness (eg: viewmodelforclient). + use of custom particles (particleeffectnum, trailparticles, pointparticles) + use of late precaches (at least if they were not already precached in a spawn function) [you shouldn't rely on this anyway]. + this server implementation has not been applied to everything: + makestatic - static entities will not benefit from extensions like EF_NOSHADOW. + entities are sent as deltas from the previous packet + entity data is split up to not exceed the mtu (without needing netchan changes) + with PEXT2_PREDINFO, stats are also sent semi-unreliably using the same mechanism (avoids reliables-stall issues). + clc_clientdata is redundant. + all stats have full precision. + protocol does not change simply because a mission pack is loaded. + gamedir added to serverinfo, the client responds by displaying a warning if the gamedir does not match + baselines are generated per-client and split over multiple packets, so the signon buffer size is no longer a limiting factor for maps with insane entity counts (for all supported protocols). + MAX_VISEDICTS is gone. + however, try not to have them all visible at once. drawing 5k or 10k entities is a massive performance drain, as can them all getting angry at the player. + this implementation will reduce overall data sizes by avoiding retransmissions, but there is no rate limiting which can result in significant burst. + this may result in extra packetloss bursts if you have saturated tcp/etc connections running at the time. + packetloss is detected serverside and triggers resends + it will recover fully, but new entities appearing may have significant delays to them (especially if static) proportionally to other entities. + interpolation code unchanged, there is no time drifting, which means the engine will not be able to hide packetloss, resulting in slightly jerky player movement. + because of this FTE will still be smoother for internet play. + still playable while simulating 50% packetloss, but not smooth. this tested with no extra ping, so would be worse online. + the protocol does not carry nextthink hints, and quakespasm is too stupid to infer intervals, so assumes interpolation intervals of 0.1. + the protocol supports prediction, but this implementation does not. + To prevent the server from detecting replacement deltas (so they don't appear in demos), use "sv_protocol 666-" (omitting the - will neither enable nor disable fte extensions). + To re-enable extensions, use "sv_protocol FTE+666" + Other than a couple of extended svcs that a mod might use, 666 is effectively obsolete (but still useful as a base protocol for earlier quakespasm, fitzquake, etc). + Using 999 as the base protocol still provides map size increases. + This will also cause custom particle effects to become invisible to all clients. + To prevent the client from advertising support for replacement deltas, use 'cl_nopext 1'. + The server will fall back to only the base protocol, if *either* the client or server has it disabled (or both, obviously). + Ideally, leave it enabled on the server and disable it as desired on the client, but I guess people are not familiar with that yet. + This will allow you to record compatible demos even if you don't have rcon access to the server. +lightstyles - + bumped to 255 (the last index is not valid in bsps, so not relevant). + presense of additional lightmaps won't bug anything out, but actually using them might break other clients if they don't support this raised limit yet. +rcon - + proquake-compatible rcon is implemented server-side. + WARNING: the password is sent as plain text! it is NOT secure! (protocol limitation from ) + set rcon_password to enable it, the default blank value will unconditionally treat all attempts as invalid. + no client support. there's no real reason for this, I just didn't bother writing the code (presumably it would be like the 'test' command, but *vomit*). + +test mods: +dpmod - + a quick test of this seems to run fine, with the exception of a few non-generic particle effect builtins which are still stubs, mostly modified quad-damage effects. +smc - + this does actually run, but is not exactly enjoyable due to: + the use of pk3s means that everything needs to be extracted first. + use of md3 format (these models will be invisible) + high mdl poly counts making mdls unloadable (resulting in them being .. you guessed it, invisible) + unsupported stereo sounds (won't play, and might spam) + no shader support (hey, at least qs won't obey the 'depthfunc equal' lines) + smc loves late precaches (spammy). + additionally an smc bug causes monsters to be spawned underground (monsters can't move). + there's likely other issues. I've not tested it that extensively. +arcane dimensions - + urm. still works?.. + gains DP_QC_GETSURFACE, so broken vanilla skies stop being broken (ad's only use for this extension). + gains EF_NOSHADOW. + ad's engine particle system usage assumes dp internals, and needs a tweak in order to get it to behave more generically. +rogue - + still need to test the ending with its writebyte hacks + + +issues: + (note that listed critisisms are not always bad things for the average qs user, but are probably bad for _someone_ and do limit potential mods) + (some things can only be good, except for how invasive such a thing would be resulting in too many bugs, or I'm just too lazy/selfish to do them myself) +protocol changes - + late precaches are in, but will still display warnings if depended upon. late precaches can still be an issue if the reliable is delayed while the unreliable is not. + sounds are still sent fully unreliably. this means they are subject to packetloss, and is especially significant on func_plat entities (where the sounds are typically looping, and thus might never be replaced/stopped). + staticsounds still use the sv.signon buffer, and are thus still limited to the underlying protocol and single-signon-buffer size. + pointparticles and trailparticles are new, but there is no support for most extended TE_* values (rain+snow are the only added TEs). Use pointparticles if you need such other effects. + while the protocol supports a range of extra entity state, much of that data is still unused (parsed and not sent). including ef_additive, tags, etc +not added - + voip would be a nice idea for all those first-playthrough map demos + no download mechanism added. I would want to use paks, which would make this far too complex. there's no automatic gamedir switching either. + (there is a gamedir hint, but currently it results in only a warning print because I really cba to rewrite quakespasm's filesystem code) +serious dp protocol issues - + sending 666 or 999 to a dp client results in dp spamming loads of useless gibberish that obscures the actual error, such that few people actually report the actual problem... + the only way I can think of getting DP to be remotely sane is to send it an svc_version for it to crap out on, reducing the spam in the hopes that people will read up a little. + the alternative is to hack in some 'cmd dpcheck $somedponlycvar' and see what the client says that cvar is set to (if $foo is supported). + unfortunately there's no version cvar, or any other kind of useful feature that I'm aware of, so this would fuck up for other clients with seta etc getting saved into $gamedir/config.cfg and then poluting other engines. + (this is not a new issue) +proquake+vanilla sucks: + sv_protocol=666 has higher limits. if this is inadvertantly set, then the server is permitted to send larger serverinfo packets (that exceed the 8192 limit). + proquake then displays 'read error' (due to recvfrom returning EMSGSIZE), which is awkward but not our bug, just a vanilla limitation. + (this is not a new issue) + note that reliables larger than 8192 but with an mtu compatible with vanilla can be used to crash both vanilla and proquake. this is true even if it is a client that sent the packets, crashing the server. + (this is not present in qss) +limited renderer changes - + no md3 support + no iqm support + harsh mdl limits + sprites still alpha-tested + still using render-to-texture instead of glsl for drawing water (which would allow mipmaps and anisotropic filtering, instead of using a random noise texture...) +randomization - + quakespasm likes seeding the random number generator as a handy trick... which can result in timers+particles getting a little too predictable +no filesystem updates - + no pk3s (could potentially decompress to a temp file, and fix up over time, but meh) + still only numbered paks, no pak.lst file or fs enumeration + 'game' console command is still stupid (backwards, hardcoded special cases, limited paths) + I did add a 'gamedir' command as an alternative name for 'game', because quakeworld. I'd do show_fps too, but cvars make that messy. +console - + is still annoying + still prints non-ascii/non-unicode chars to stdout, which may include escape codes or other xterm/etc exploits. + con_printf is still horribly slow (at least with vsync), and likely to crash on someone... and not just me. fixing this would make a few poorly designed blocking things not refresh properly. +no markup - + all that ^1funny ^2and ^3annoying ^7text isn't handled, and remains as gibberish. +menu - + still no mouse support + still no way to add mod-specific cvars onto the menu + +compiling: + export CFLAGS="-Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -DBUILD_SPECIAL=-spiked-rFOO" + is the CFLAGS environment setting that I'm compiling with. I only really mention that for branding. Also I'm building in windows with cygwin. + There's no 3rd-party dependancies from the vanilla quakespasm code included. this isn't an issue if you're going to compile for linux, where the dependancies are generally preinstalled as part of your distro, or you can just apt-get them or whatever. + So if you're going to compile for windows or osx, you'll need to do an svn checkout of vanilla quakespasm first, and then overwrite with the extra files (or just apply the patch to your checkout). + +running: + win32+win64 binaries are included. linux users will need to build their own. osx users are screwed. + no 3rd-party libraries are included. It is assumed that you'll have previously installed vanilla QuakeSpasm and thus won't need them. In which case grab the exe that matches the archetecture of your existing QS install and just run that as if it were vanilla QuakeSpasm. Delete the other or whatever, it doesn't matter.. \ No newline at end of file diff --git a/qsextensions.qc b/qsextensions.qc new file mode 100755 index 00000000..0c17c93f --- /dev/null +++ b/qsextensions.qc @@ -0,0 +1,441 @@ +/* +Extensions file for QuakeSpasm 0.92.2-spiked-r5 +This file is auto-generated by pr_dumpplatform with no args. +You will probably need to use FTEQCC to compile this. +*/ + + +//QuakeSpasm only supports ssqc, so including this file in some other situation is a user error +#if defined(QUAKEWORLD) || defined(CSQC) || defined(MENU) +#error Mixed up module defs +#endif + + +//List of advertised extensions +//DP_ENT_ALPHA +//DP_CON_SET +//DP_CON_SETA +//DP_EF_NOSHADOW +//DP_QC_AUTOCVARS +//DP_QC_ASINACOSATANATAN2TAN +//DP_QC_COPYENTITY +//DP_QC_CRC16 +//DP_QC_CVAR_DEFSTRING +//DP_QC_CVAR_STRING +//DP_QC_CVAR_TYPE +//DP_QC_EDICT_NUM +//DP_QC_ENTITYDATA +//DP_QC_ETOS +//DP_QC_FINDCHAIN +//DP_QC_FINDCHAINFLAGS +//DP_QC_FINDCHAINFLOAT +//DP_QC_FINDFLAGS +//DP_QC_FINDFLOAT +//DP_QC_GETSURFACE +//DP_QC_GETSURFACETRIANGLE +//DP_QC_GETSURFACEPOINTATTRIBUTE +//DP_QC_MINMAXBOUND +//DP_QC_MULTIPLETEMPSTRINGS +//DP_QC_RANDOMVEC +//DP_QC_SINCOSSQRTPOW +//DP_QC_STRFTIME +//DP_QC_STRING_CASE_FUNCTIONS +//DP_QC_STRINGBUFFERS +//DP_QC_STRREPLACE +//DP_QC_TOKENIZEBYSEPARATOR +//DP_QC_TRACEBOX +//DP_QC_TRACETOSS +//DP_QC_TRACE_MOVETYPES +//DP_QC_URI_ESCAPE +//DP_QC_VECTOANGLES_WITH_ROLL +//DP_QC_VECTORVECTORS +//DP_QC_WHICHPACK +//DP_REGISTERCVAR +//DP_SV_BOTCLIENT +//DP_SV_DROPCLIENT +//DP_SV_POINTSOUND +//DP_SV_SETCOLOR +//DP_SV_SPAWNFUNC_PREFIX +//DP_SV_WRITEUNTERMINATEDSTRING +//DP_TE_BLOOD +//DP_TE_STANDARDEFFECTBUILTINS +//EXT_BITSHIFT +//FRIK_FILE +//FTE_PART_SCRIPT +//FTE_PART_NAMESPACES +//FTE_PART_NAMESPACE_EFFECTINFO +//FTE_QC_CHECKCOMMAND +//FTE_QC_INTCONV +//FTE_SV_POINTPARTICLES +//KRIMZON_SV_PARSECLIENTCOMMAND +//ZQ_QC_STRINGS + + +//Explicitly flag this stuff as probably-not-referenced, meaning fteqcc will shut up about it and silently strip what it can. +#pragma noref 1 + + +//Some custom types (that might be redefined as accessors by fteextensions.qc, although we don't define any methods here) +#ifdef _ACCESSORS +accessor strbuf:float; +accessor searchhandle:float; +accessor hashtable:float; +accessor infostring:string; +accessor filestream:float; +#else +#define strbuf float +#define searchhandle float +#define hashtable float +#define infostring string +#define filestream float +#endif + + +//Supported Extension fields +.float gravity; +//.float items2; /*if defined, overrides serverflags for displaying runes on the hud*/ +.float alpha; /*entity opacity*/ +.float traileffectnum; /*can also be set with 'traileffect' from a map editor*/ +.float emiteffectnum; /*can also be set with 'traileffect' from a map editor*/ +.vector movement; /*describes which forward/right/up keys the player is holidng*/ +.entity viewmodelforclient; /*attaches this entity to the specified player's view. invisible to other players*/ + + +//Supported Extension Constants +const float MOVETYPE_FOLLOW = 12; +const float SOLID_CORPSE = 5; +const float FILE_READ = 0; +const float FILE_APPEND = 1; +const float FILE_WRITE = 2; +const float CLIENTTYPE_DISCONNECT = 0; +const float CLIENTTYPE_REAL = 1; +const float CLIENTTYPE_BOT = 2; +const float CLIENTTYPE_NOTCLIENT = 3; +const float EF_NOSHADOW = 0x1000; +const float MSG_MULTICAST = 4; +const float MULTICAST_ALL = MULTICAST_ALL_U; +const float MULTICAST_PVS = MULTICAST_PVS_U; +const float MULTICAST_ONE = MULTICAST_ONE_U; +const float MULTICAST_ALL_R = MULTICAST_ALL_R; +const float MULTICAST_PVS_R = MULTICAST_PVS_R; +const float MULTICAST_ONE_R = MULTICAST_ONE_R; +const float MULTICAST_INIT = MULTICAST_INIT; + + +//Builtin list +vector(vector fwd, optional vector up) vectoangles2 = #51; /* + Returns the angles (+x=UP) required to orient an entity to look in the given direction. The 'up' argument is required if you wish to set a roll angle, otherwise it will be limited to just monster-style turning. */ + +float(float angle) sin = #60; +float(float angle) cos = #61; +float(float value) sqrt = #62; +void(entity ent, entity ignore) tracetoss = #64; +string(entity ent) etos = #65; +string(entity e, string key) infokey = #80; /* + If e is world, returns the field 'key' from either the serverinfo or the localinfo. If e is a player, returns the value of 'key' from the player's userinfo string. There are a few special exceptions, like 'ip' which is not technically part of the userinfo. */ + +float(string) stof = #81; +#define unicast(pl,reli) do{msg_entity = pl; multicast('0 0 0', reli?MULITCAST_ONE_R:MULTICAST_ONE);}while(0) +void(vector where, float set) multicast = #82; /* + Once the MSG_MULTICAST network message buffer has been filled with data, this builtin is used to dispatch it to the given target, filtering by pvs for reduced network bandwidth. */ + +void(vector start, vector mins, vector maxs, vector end, float nomonsters, entity ent) tracebox = #90; /* + Exactly like traceline, but a box instead of a uselessly thin point. Acceptable sizes are limited by bsp format, q1bsp has strict acceptable size values. */ + +vector() randomvec = #91; /* + Returns a vector with random values. Each axis is independantly a value between -1 and 1 inclusive. */ + +vector(vector org) getlight = #92; +float(string cvarname, string defaultvalue) registercvar = #93; /* + Creates a new cvar on the fly. If it does not already exist, it will be given the specified value. If it does exist, this is a no-op. + This builtin has the limitation that it does not apply to configs or commandlines. Such configs will need to use the set or seta command causing this builtin to be a noop. + In engines that support it, you will generally find the autocvar feature easier and more efficient to use. */ + +float(float a, float b, ...) min = #94; /* + Returns the lowest value of its arguments. */ + +float(float a, float b, ...) max = #95; /* + Returns the highest value of its arguments. */ + +float(float minimum, float val, float maximum) bound = #96; /* + Returns val, unless minimum is higher, or maximum is less. */ + +float(float value, float exp) pow = #97; +#define findentity findfloat +entity(entity start, .__variant fld, __variant match) findfloat = #98; /* + Equivelent to the find builtin, but instead of comparing strings contents, this builtin compares the raw values. This builtin requires multiple calls in order to scan all entities - set start to the previous call's return value. + world is returned when there are no more entities. */ + +float(string extname) checkextension = #99; /* + Checks for an extension by its name (eg: checkextension("FRIK_FILE") says that its okay to go ahead and use strcat). + Use cvar("pr_checkextension") to see if this builtin exists. */ + +float(__variant funcref) checkbuiltin = #0; /* + Checks to see if the specified builtin is supported/mapped. This is intended as a way to check for #0 functions, allowing for simple single-builtin functions. */ + +float(string builtinname) builtin_find = #100; /* + Looks to see if the named builtin is valid, and returns the builtin number it exists at. */ + +float(float value) anglemod = #102; +filestream(string filename, float mode, optional float mmapminsize) fopen = #110; /* + Opens a file, typically prefixed with "data/", for either read or write access. */ + +void(filestream fhandle) fclose = #111; +string(filestream fhandle) fgets = #112; /* + Reads a single line out of the file. The new line character is not returned as part of the string. Returns the null string on EOF (use if not(string) to easily test for this, which distinguishes it from the empty string which is returned if the line being read is blank */ + +void(filestream fhandle, string s, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7) fputs = #113; /* + Writes the given string(s) into the file. For compatibility with fgets, you should ensure that the string is terminated with a \n - this will not otherwise be done for you. It is up to the engine whether dos or unix line endings are actually written. */ + +#define ftell fseek //c-compat +int(filestream fhandle, optional int newoffset) fseek = #0; /* + Changes the current position of the file, if specified. Returns prior position, in bytes. */ + +float(string s) strlen = #114; +string(string s1, optional string s2, optional string s3, optional string s4, optional string s5, optional string s6, optional string s7, optional string s8) strcat = #115; +string(string s, float start, float length) substring = #116; +vector(string s) stov = #117; +string(string s, ...) strzone = #118; /* + Create a semi-permanent copy of a string that only becomes invalid once strunzone is called on the string (instead of when the engine assumes your string has left scope). */ + +void(string s) strunzone = #119; /* + Destroys a string that was allocated by strunzone. Further references to the string MAY crash the game. */ + +float(float number, float quantity) bitshift = #218; +void(vector org) te_lightningblood = #219; +float(string s1, string sub, optional float startidx) strstrofs = #221; /* + Returns the 0-based offset of sub within the s1 string, or -1 if sub is not in s1. + If startidx is set, this builtin will ignore matches before that 0-based offset. */ + +float(string str, float index) str2chr = #222; /* + Retrieves the character value at offset 'index'. */ + +string(float chr, ...) chr2str = #223; /* + The input floats are considered character values, and are concatenated. */ + +string(float pad, string str1, ...) strpad = #225; /* + Pads the string with spaces, to ensure its a specific length (so long as a fixed-width font is used, anyway). If pad is negative, the spaces are added on the left. If positive the padding is on the right. */ + +#define strcmp strncmp +float(string s1, string s2, optional float len, optional float s1ofs, optional float s2ofs) strncmp = #228; /* + Compares up to 'len' chars in the two strings. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if the two strings are equal, a negative value if s1 appears numerically lower, and positive if s1 appears numerically higher. */ + +float(string s1, string s2) strcasecmp = #229; /* + Compares the two strings without case sensitivity. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +float(string s1, string s2, float len, optional float s1ofs, optional float s2ofs) strncasecmp = #230; /* + Compares up to 'len' chars in the two strings without case sensitivity. s1ofs allows you to treat s2 as a substring to compare against, or should be 0. + Returns 0 if they are equal. The sign of the return value may be significant, but should not be depended upon. */ + +string(string s) strtrim = #0; /* + Trims the whitespace from the start+end of the string. */ + +void(vector org, float count) te_bloodqw = #239; +float(float a, float n) mod = #245; +int(string) stoi = #259; /* + Converts the given string into a true integer. Base 8, 10, or 16 is determined based upon the format of the string. */ + +string(int) itos = #260; /* + Converts the passed true integer into a base10 string. */ + +int(string) stoh = #261; /* + Reads a base-16 string (with or without 0x prefix) as an integer. Bugs out if given a base 8 or base 10 string. :P */ + +string(int) htos = #262; /* + Formats an integer as a base16 string, with leading 0s and no prefix. Always returns 8 characters. */ + +int(float) ftoi = #0; /* + Converts the given float into a true integer without depending on extended qcvm instructions. */ + +float(int) itof = #0; /* + Converts the given true integer into a float without depending on extended qcvm instructions. */ + +#define dotproduct(v1,v2) ((vector)(v1)*(vector)(v2)) +vector(vector v1, vector v2) crossproduct = #0; /* + Small helper function to calculate the crossproduct of two vectors. */ + +float(float modidx, string framename) frameforname = #276; /* + Looks up a framegroup from a model by name, avoiding the need for hardcoding. Returns -1 on error. */ + +float(float modidx, float framenum) frameduration = #277; /* + Retrieves the duration (in seconds) of the specified framegroup. */ + +void(float buf, float fl) WriteFloat = #280; +string(float modidx, float framenum) frametoname = #284; +float(string name) checkcommand = #294; /* + Checks to see if the supplied name is a valid command, cvar, or alias. Returns 0 if it does not exist. */ + +float(string effectname) particleeffectnum = #335; /* + Precaches the named particle effect. If your effect name is of the form 'foo.bar' then particles/foo.cfg will be loaded by the client if foo.bar was not already defined. + Different engines will have different particle systems, this specifies the QC API only. */ + +void(float effectnum, entity ent, vector start, vector end) trailparticles = #336; /* + Draws the given effect between the two named points. If ent is not world, distances will be cached in the entity in order to avoid framerate dependancies. The entity is not otherwise used. */ + +void(float effectnum, vector origin, optional vector dir, optional float count) pointparticles = #337; /* + Spawn a load of particles from the given effect at the given point traveling or aiming along the direction specified. The number of particles are scaled by the count argument. */ + +void(string s, ...) print = #339; /* + Unconditionally print on the local system's console, even in ssqc (doesn't care about the value of the developer cvar). */ + +float(entity ent) wasfreed = #353; /* + Quickly check to see if the entity is currently free. This function is only valid during the two-second non-reuse window, after that it may give bad results. Try one second to make it more robust. */ + +entity(entity from, optional entity to) copyentity = #400; /* + Copies all fields from one entity to another. */ + +void(entity ent, float colours) setcolors = #401; /* + Changes a player's colours. The bits 0-3 are the lower/trouser colour, bits 4-7 are the upper/shirt colours. */ + +entity(.string field, string match) findchain = #402; +entity(.float fld, float match) findchainfloat = #403; +void(vector org, vector dir, float count) te_blood = #405; +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain = #409; +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow = #410; +void(vector org, optional float count) te_gunshot = #418; +void(vector org) te_spike = #419; +void(vector org) te_superspike = #420; +void(vector org) te_explosion = #421; +void(vector org) te_tarexplosion = #422; +void(vector org) te_wizspike = #423; +void(vector org) te_knightspike = #424; +void(vector org) te_lavasplash = #425; +void(vector org) te_teleport = #426; +void(vector org, float color, float colorlength) te_explosion2 = #427; +void(entity own, vector start, vector end) te_lightning1 = #428; +void(entity own, vector start, vector end) te_lightning2 = #429; +void(entity own, vector start, vector end) te_lightning3 = #430; +void(entity own, vector start, vector end) te_beam = #431; +void(vector dir) vectorvectors = #432; +float(entity e, float s) getsurfacenumpoints = #434; +vector(entity e, float s, float n) getsurfacepoint = #435; +vector(entity e, float s) getsurfacenormal = #436; +string(entity e, float s) getsurfacetexture = #437; +float(entity e, vector p) getsurfacenearpoint = #438; +vector(entity e, float s, vector p) getsurfaceclippedpoint = #439; +void(entity e, string s) clientcommand = #440; +float(string s) tokenize = #441; +string(float n) argv = #442; +float() argc = #0; +string(string cvarname) cvar_string = #448; +entity(entity start, .float fld, float match) findflags = #449; +entity(.float fld, float match) findchainflags = #450; +void(entity player) dropclient = #453; +entity() spawnclient = #454; /* + Spawns a dummy player entity. + Note that such dummy players will be carried from one map to the next. + Warning: DP_SV_CLIENTCOLORS DP_SV_CLIENTNAME are not implemented in quakespasm, so use KRIMZON_SV_PARSECLIENTCOMMAND's clientcommand builtin to change the bot's name/colours/skin/team/etc, in the same way that clients would ask. */ + +float(entity client) clienttype = #455; +void(float target, string str) WriteUnterminatedString = #456; +entity(float entnum) edict_num = #459; +strbuf() buf_create = #460; +void(strbuf bufhandle) buf_del = #461; +float(strbuf bufhandle) buf_getsize = #462; +void(strbuf bufhandle_from, strbuf bufhandle_to) buf_copy = #463; +void(strbuf bufhandle, float sortprefixlen, float backward) buf_sort = #464; +string(strbuf bufhandle, string glue) buf_implode = #465; +string(strbuf bufhandle, float string_index) bufstr_get = #466; +void(strbuf bufhandle, float string_index, string str) bufstr_set = #467; +float(strbuf bufhandle, string str, float order) bufstr_add = #468; +void(strbuf bufhandle, float string_index) bufstr_free = #469; +float(float s) asin = #471; +float(float c) acos = #472; +float(float t) atan = #473; +float(float c, float s) atan2 = #474; +float(float a) tan = #475; +string(float uselocaltime, string format, ...) strftime = #478; +float(string s, string separator1, ...) tokenizebyseparator = #479; +string(string s) strtolower = #480; +string(string s) strtoupper = #481; +string(string s) cvar_defstring = #482; +void(vector origin, string sample, float volume, float attenuation) pointsound = #483; +string(string search, string replace, string subject) strreplace = #484; +string(string search, string replace, string subject) strireplace = #485; +vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; +float(float caseinsensitive, string s, ...) crc16 = #494; +float(string name) cvar_type = #495; +float() numentityfields = #496; /* + Gives the number of named entity fields. Note that this is not the size of an entity, but rather just the number of unique names (ie: vectors use 4 names rather than 3). */ + +float(string fieldname) findentityfield = #0; /* + Find a field index by name. */ + +typedef .__variant field_t; +field_t(float fieldnum) entityfieldref = #0; /* + Returns a field value that can be directly used to read entity fields. Be sure to validate the type with entityfieldtype before using. */ + +string(float fieldnum) entityfieldname = #497; /* + Retrieves the name of the given entity field. */ + +float(float fieldnum) entityfieldtype = #498; /* + Provides information about the type of the field specified by the field num. Returns one of the EV_ values. */ + +string(float fieldnum, entity ent) getentityfieldstring = #499; +float(float fieldnum, entity ent, string s) putentityfieldstring = #500; +string(string filename, optional float makereferenced) whichpack = #503; /* + Returns the pak file name that contains the file specified. progs/player.mdl will generally return something like 'pak0.pak'. If makereferenced is true, clients will automatically be told that the returned package should be pre-downloaded and used, even if allow_download_refpackages is not set. */ + +string(string in) uri_escape = #510; +string(string in) uri_unescape = #511; +float(entity ent) num_for_edict = #512; +float(string str) tokenize_console = #514; /* + Tokenize a string exactly as the console's tokenizer would do so. The regular tokenize builtin became bastardized for convienient string parsing, which resulted in a large disparity that can be exploited to bypass checks implemented in a naive SV_ParseClientCommand function, therefore you can use this builtin to make sure it exactly matches. */ + +float(float idx) argv_start_index = #515; /* + Returns the character index that the tokenized arg started at. */ + +float(float idx) argv_end_index = #516; /* + Returns the character index that the tokenized arg stopped at. */ + +string(string cvarname) cvar_description = #518; /* + Retrieves the description of a cvar, which might be useful for tooltips or help files. This may still not be useful. */ + +float(optional float timetype) gettime = #519; +float(float v, optional float base) log = #532; /* + Determines the logarithm of the input value according to the specified base. This can be used to calculate how much something was shifted by. */ + +float(string filename, strbuf bufhandle) buf_loadfile = #535; /* + Appends the named file into a string buffer (which must have been created in advance). The return value merely says whether the file was readable. */ + +float(filestream filehandle, strbuf bufhandle, optional float startpos, optional float numstrings) buf_writefile = #536; /* + Writes the contents of a string buffer onto the end of the supplied filehandle (you must have already used fopen). Additional optional arguments permit you to constrain the writes to a subsection of the stringbuffer. */ + +void(.../*, string funcname*/) callfunction = #605; /* + Invokes the named function. The function name is always passed as the last parameter and must always be present. The others are passed to the named function as-is */ + +float(string s) isfunction = #607; /* + Returns true if the named function exists and can be called with the callfunction builtin. */ + +float(entity e, string s, optional float offset) parseentitydata = #613; /* + Reads a single entity's fields into an already-spawned entity. s should contain field pairs like in a saved game: {"foo1" "bar" "foo2" "5"}. Returns <=0 on failure, otherwise returns the offset in the string that was read to. */ + +string(string fmt, ...) sprintf = #627; +float(entity e, float s) getsurfacenumtriangles = #628; +vector(entity e, float s, float n) getsurfacetriangle = #629; + + +//Builtin Stubs List (these are present for simpler compatibility, but not properly supported in QuakeSpasm at this time). +/* +void(vector org, string modelname, float startframe, float endframe, float framerate) effect = #404; +void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower = #406; +void(vector org, vector color) te_explosionrgb = #407; +void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube = #408; +void(vector org, vector vel, float howmany) te_spark = #411; +void(vector org) te_gunshotquad = #412; +void(vector org) te_spikequad = #413; +void(vector org) te_superspikequad = #414; +void(vector org) te_explosionquad = #415; +void(vector org) te_smallflash = #416; +void(vector org, float radius, float lifetime, vector color) te_customflash = #417; +void(vector org) te_plasmaburn = #433; +void(entity e, entity tagentity, string tagname) setattachment = #443; +float(string s) strlennocol = #476; +string(string s) strdecolorize = #477; +*/ + + +//Reset this back to normal. +#pragma noref 0 diff --git a/quakespasm/Quake/cl_main.c b/quakespasm/Quake/cl_main.c index f7d2555f..da59afa3 100644 --- a/quakespasm/Quake/cl_main.c +++ b/quakespasm/Quake/cl_main.c @@ -67,6 +67,25 @@ entity_t **cl_visedicts; extern cvar_t r_lerpmodels, r_lerpmove; //johnfitz +void CL_ClearTrailStates(void) +{ + int i; + for (i = 0; i < cl.num_statics; i++) + { + PScript_DelinkTrailstate(&(cl_static_entities[i].trailstate)); + PScript_DelinkTrailstate(&(cl_static_entities[i].emitstate)); + } + for (i = 0; i < cl_max_edicts; i++) + { + PScript_DelinkTrailstate(&(cl_entities[i].trailstate)); + PScript_DelinkTrailstate(&(cl_entities[i].emitstate)); + } + for (i = 0; i < MAX_BEAMS; i++) + { + PScript_DelinkTrailstate(&(cl_beams[i].trailstate)); + } +} + /* ===================== CL_ClearState @@ -80,6 +99,8 @@ void CL_ClearState (void) if (!sv.active) Host_ClearMemory (); + CL_ClearTrailStates(); + // wipe the entire cl structure memset (&cl, 0, sizeof(cl)); @@ -438,15 +459,17 @@ void CL_RelinkEntities (void) float bobjrotate; vec3_t oldorg; dlight_t *dl; - float frametime = cl.time - cl.oldtime; + float frametime; + +// determine partial update time + frac = CL_LerpPoint (); + + frametime = cl.time - cl.oldtime; if (frametime < 0) frametime = 0; if (frametime > 0.1) frametime = 0.1; -// determine partial update time - frac = CL_LerpPoint (); - if (cl_numvisedicts + 64 > cl_maxvisedicts) { cl_maxvisedicts = cl_maxvisedicts+64; @@ -481,7 +504,7 @@ void CL_RelinkEntities (void) for (i=1,ent=cl_entities+1 ; imodel) - { // empty slot + { // empty slot, ish. if (ent->forcelink) R_RemoveEfrags (ent); // just became empty continue; @@ -559,10 +582,10 @@ void CL_RelinkEntities (void) //johnfitz -- assume muzzle flash accompanied by muzzle flare, which looks bad when lerped if (r_lerpmodels.value != 2) { - if (ent == &cl_entities[cl.viewentity]) - cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames - else - ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames + if (ent == &cl_entities[cl.viewentity]) + cl.viewent.lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames + else + ent->lerpflags |= LERP_RESETANIM|LERP_RESETANIM2; //no lerping for two frames } //johnfitz } @@ -583,18 +606,18 @@ void CL_RelinkEntities (void) } #ifdef PSET_SCRIPT - if (ent->model->traileffect >= 0) - { - vec3_t axis[3]; - AngleVectors(ent->angles, axis[0], axis[1], axis[2]); - PScript_ParticleTrail(oldorg, ent->origin, ent->model->traileffect, i, axis, &ent->trailstate); - } - else if (ent->netstate.traileffectnum > 0 && ent->netstate.traileffectnum < MAX_PARTICLETYPES) + if (ent->netstate.traileffectnum > 0 && ent->netstate.traileffectnum < MAX_PARTICLETYPES) { vec3_t axis[3]; AngleVectors(ent->angles, axis[0], axis[1], axis[2]); PScript_ParticleTrail(oldorg, ent->origin, cl.particle_precache[ent->netstate.traileffectnum].index, i, axis, &ent->trailstate); } + else if (ent->model->traileffect >= 0) + { + vec3_t axis[3]; + AngleVectors(ent->angles, axis[0], axis[1], axis[2]); + PScript_ParticleTrail(oldorg, ent->origin, ent->model->traileffect, i, axis, &ent->trailstate); + } else #endif if (ent->model->flags & EF_GIB) @@ -640,9 +663,26 @@ void CL_RelinkEntities (void) ent->forcelink = false; #ifdef PSET_SCRIPT - if (ent->model->emiteffect >= 0) + if (ent->netstate.emiteffectnum > 0) { - PScript_RunParticleEffectState(ent->origin, NULL, frametime, ent->model->emiteffect, &ent->emitstate); + vec3_t axis[3]; + AngleVectors(ent->angles, axis[0], axis[1], axis[2]); + if (ent->model->type == mod_alias) + axis[0][2] *= -1; //stupid vanilla bug + PScript_RunParticleEffectState(ent->origin, axis[0], frametime, cl.particle_precache[ent->netstate.emiteffectnum].index, &ent->emitstate); + } + else if (ent->model->emiteffect >= 0) + { + vec3_t axis[3]; + AngleVectors(ent->angles, axis[0], axis[1], axis[2]); + if (ent->model->flags & MOD_EMITFORWARDS) + { + if (ent->model->type == mod_alias) + axis[0][2] *= -1; //stupid vanilla bug + } + else + VectorScale(axis[2], -1, axis[0]); + PScript_RunParticleEffectState(ent->origin, axis[0], frametime, ent->model->emiteffect, &ent->emitstate); if (ent->model->flags & MOD_EMITREPLACE) continue; } diff --git a/quakespasm/Quake/cl_parse.c b/quakespasm/Quake/cl_parse.c index f02be16e..b287648c 100644 --- a/quakespasm/Quake/cl_parse.c +++ b/quakespasm/Quake/cl_parse.c @@ -374,6 +374,7 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, c if (bits & UF_SOLID) { //knowing the size of an entity is important for prediction + //without prediction, its a bit pointless. /*if (cl.protocol_pext2 & PEXT2_NEWSIZEENCODING) { qbyte enc = MSG_ReadByte(); @@ -464,7 +465,17 @@ static unsigned int CLFTE_ReadDelta(unsigned int entnum, entity_state_t *news, c /*news->lightpflags =*/ MSG_ReadByte(); } if (bits & UF_TRAILEFFECT) - news->traileffectnum = MSG_ReadShort(); + { + unsigned short v = MSG_ReadShort(); + news->emiteffectnum = 0; + news->traileffectnum = v & 0x3fff; + if (v & 0x8000) + news->emiteffectnum = MSG_ReadShort() & 0x3fff; + if (news->traileffectnum >= MAX_PARTICLETYPES) + news->traileffectnum = 0; + if (news->emiteffectnum >= MAX_PARTICLETYPES) + news->emiteffectnum = 0; + } if (bits & UF_COLORMOD) { @@ -680,13 +691,23 @@ static void CLFTE_ParseEntitiesUpdate(void) } if (cl.protocol_pext2 & PEXT2_PREDINFO) - { + { //stats should normally be sent before the entity data. VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); ent = CL_EntityNum(cl.viewentity); cl.mvelocity[0][0] = ent->netstate.velocity[0]*(1/8.0); cl.mvelocity[0][1] = ent->netstate.velocity[1]*(1/8.0); cl.mvelocity[0][2] = ent->netstate.velocity[2]*(1/8.0); cl.onground = (ent->netstate.eflags & EFLAGS_ONGROUND)?true:false; + + + cl.punchangle[0] = cl.statsf[STAT_PUNCHANGLE_X]; + cl.punchangle[1] = cl.statsf[STAT_PUNCHANGLE_Y]; + cl.punchangle[2] = cl.statsf[STAT_PUNCHANGLE_Z]; + if (v_punchangles[0][0] != cl.punchangle[0] || v_punchangles[0][1] != cl.punchangle[1] || v_punchangles[0][2] != cl.punchangle[2]) + { + VectorCopy (v_punchangles[0], v_punchangles[1]); + VectorCopy (cl.punchangle, v_punchangles[0]); + } } if (!cl.requestresend) @@ -1535,6 +1556,10 @@ static void CL_ParseStatic (int version) //johnfitz -- added a parameter // copy it to the current state + ent->netstate = ent->baseline; + + ent->trailstate = NULL; + ent->emitstate = NULL; ent->model = cl.model_precache[ent->baseline.modelindex]; ent->lerpflags |= LERP_RESETANIM; //johnfitz -- lerping ent->frame = ent->baseline.frame; @@ -1742,7 +1767,8 @@ void CL_ParseServerMessage (void) else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); - cl.onground = false; // unless the server says otherwise + if (!(cl.protocol_pext2 & PEXT2_PREDINFO)) + cl.onground = false; // unless the server says otherwise // // parse the message // diff --git a/quakespasm/Quake/client.h b/quakespasm/Quake/client.h index 7cd70dd3..28b741e7 100644 --- a/quakespasm/Quake/client.h +++ b/quakespasm/Quake/client.h @@ -341,6 +341,7 @@ void CL_ParseTEnt (void); void CL_UpdateTEnts (void); void CL_ClearState (void); +void CL_ClearTrailStates(void); // // cl_demo.c diff --git a/quakespasm/Quake/cmd.c b/quakespasm/Quake/cmd.c index afd13b90..99df8cf7 100644 --- a/quakespasm/Quake/cmd.c +++ b/quakespasm/Quake/cmd.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "quakedef.h" +cvar_t cl_nopext = {"cl_nopext","0",CVAR_NONE}; //Spike -- prevent autodetection of protocol extensions, so that servers fall back to only their base protocol (without needing to reconfigure the server. Requires reconnect. void Cmd_ForwardToServer (void); #define MAX_ALIAS_NAME 32 @@ -517,6 +518,8 @@ void Cmd_Init (void) Cmd_AddCommand ("alias",Cmd_Alias_f); Cmd_AddCommand ("cmd", Cmd_ForwardToServer); Cmd_AddCommand ("wait", Cmd_Wait_f); + + Cvar_RegisterVariable (&cl_nopext); } /* @@ -793,7 +796,7 @@ void Cmd_ForwardToServer (void) SZ_Print (&cls.message, "protocols 15 666 999"); return; } - if (!strcmp(Cmd_Args(), "pext")) + if (!strcmp(Cmd_Args(), "pext") && !cl_nopext.value) { //server asked us for a key+value list of the extensions+attributes we support SZ_Print (&cls.message, va("pext %#x %#x", PROTOCOL_FTE_PEXT2, PEXT2_SUPPORTED_CLIENT)); return; diff --git a/quakespasm/Quake/gl_model.c b/quakespasm/Quake/gl_model.c index 36d6ec58..9147d4c3 100644 --- a/quakespasm/Quake/gl_model.c +++ b/quakespasm/Quake/gl_model.c @@ -192,6 +192,7 @@ void Mod_ClearAll (void) { mod->needload = true; TexMgr_FreeTexturesForOwner (mod); //johnfitz + PScript_ClearSurfaceParticles(mod); } } @@ -206,7 +207,10 @@ void Mod_ResetAll (void) for (i=0 , mod=mod_known ; ineedload) //otherwise Mod_ClearAll() did it already + { TexMgr_FreeTexturesForOwner (mod); + PScript_ClearSurfaceParticles(mod); + } memset(mod, 0, sizeof(qmodel_t)); } mod_numknown = 0; @@ -288,26 +292,28 @@ qmodel_t *Mod_LoadModel (qmodel_t *mod, qboolean crash) return mod; // not cached at all } -// -// because the world is so huge, load it one piece at a time -// - if (!crash) - { - - } - // // load the file // - buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id); + if (*mod->name == '*') + buf = NULL; + else + buf = COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), & mod->path_id); if (!buf) { if (crash) Sys_Error ("Mod_LoadModel: %s not found", mod->name); //johnfitz -- was "Mod_NumForName" + else if (mod->name[0] == '*' && (mod->name[1] < '0' || mod->name[1] > '9')) + ; //*foo doesn't warn, unless its *NUM. inline models. gah. + else + Con_Warning("Mod_LoadModel: %s not found\n", mod->name); //avoid crashes mod->needload = false; mod->type = mod_ext_invalid; + mod->flags = 0; + + Mod_SetExtraFlags (mod); //johnfitz. spike -- moved this to be generic, because most of the flags are anyway. return mod; return NULL; diff --git a/quakespasm/Quake/gl_model.h b/quakespasm/Quake/gl_model.h index 62a667aa..7bc03471 100644 --- a/quakespasm/Quake/gl_model.h +++ b/quakespasm/Quake/gl_model.h @@ -401,6 +401,7 @@ typedef enum {mod_brush, mod_sprite, mod_alias, mod_ext_invalid} modtype_t; //johnfitz //spike -- added this for particle stuff #define MOD_EMITREPLACE 2048 //particle effect completely replaces the model (for flames or whatever). +#define MOD_EMITFORWARDS 4096 //particle effect is emitted forwards, rather than downwards. why down? good question. typedef struct qmodel_s { @@ -418,6 +419,9 @@ typedef struct qmodel_s #ifdef PSET_SCRIPT int emiteffect; //spike -- this effect is emitted per-frame by entities with this model int traileffect; //spike -- this effect is used when entities move + struct skytris_s *skytris; //spike -- surface-based particle emission for this model + struct skytriblock_s *skytrimem; //spike -- surface-based particle emission for this model (for better cache performance+less allocs) + double skytime; //doesn't really cope with multiples. oh well... #endif // // volume occupied by the model graphics diff --git a/quakespasm/Quake/gl_refrag.c b/quakespasm/Quake/gl_refrag.c index e5e68fb7..467b9174 100644 --- a/quakespasm/Quake/gl_refrag.c +++ b/quakespasm/Quake/gl_refrag.c @@ -238,9 +238,30 @@ void R_StoreEfrags (efrag_t **ppefrag) pent->visframe = r_framecount; #ifdef PSET_SCRIPT - if (pent->model->emiteffect >= 0) + if (pent->netstate.emiteffectnum > 0) { - PScript_RunParticleEffectState(pent->origin, NULL, ((host_frametime>0.1)?0.1:host_frametime), pent->model->emiteffect, &pent->emitstate); + float t = cl.time-cl.oldtime; + vec3_t axis[3]; + if (t < 0) t = 0; else if (t > 0.1) t= 0.1; + AngleVectors(pent->angles, axis[0], axis[1], axis[2]); + if (pent->model->type == mod_alias) + axis[0][2] *= -1; //stupid vanilla bug + PScript_RunParticleEffectState(pent->origin, axis[0], t, cl.particle_precache[pent->netstate.emiteffectnum].index, &pent->emitstate); + } + else if (pent->model->emiteffect >= 0) + { + float t = cl.time-cl.oldtime; + vec3_t axis[3]; + if (t < 0) t = 0; else if (t > 0.1) t= 0.1; + AngleVectors(pent->angles, axis[0], axis[1], axis[2]); + if (pent->model->flags & MOD_EMITFORWARDS) + { + if (pent->model->type == mod_alias) + axis[0][2] *= -1; //stupid vanilla bug + } + else + VectorScale(axis[2], -1, axis[0]); + PScript_RunParticleEffectState(pent->origin, axis[0], t, pent->model->emiteffect, &pent->emitstate); if (pent->model->flags & MOD_EMITREPLACE) continue; } diff --git a/quakespasm/Quake/glquake.h b/quakespasm/Quake/glquake.h index d0e2ee28..371229fb 100644 --- a/quakespasm/Quake/glquake.h +++ b/quakespasm/Quake/glquake.h @@ -112,8 +112,10 @@ int PScript_FindParticleType(const char *fullname); int PScript_RunParticleEffectTypeString (vec3_t org, vec3_t dir, float count, const char *name); int PScript_EntParticleTrail(vec3_t oldorg, entity_t *ent, const char *name); int PScript_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count); +void PScript_DelinkTrailstate(struct trailstate_s **tsk); void PScript_ClearParticles (void); void PScript_UpdateModelEffects(qmodel_t *mod); +void PScript_ClearSurfaceParticles(qmodel_t *mod); //model is being unloaded. #else #define PScript_RunParticleEffectState(o,d,c,t,s) true #define PScript_RunParticleEffectTypeString(o,d,c,n) true //just unconditionally returns an error @@ -121,6 +123,8 @@ void PScript_UpdateModelEffects(qmodel_t *mod); #define PScript_ParticleTrail(o,e,t,d,a,s) true #define PScript_EntParticleTrail(o,e,n) true #define PScript_RunParticleEffect(o,d,p,c) true +#define PScript_ClearSurfaceParticles(m) +#define PScript_DelinkTrailstate(tsp) #endif //==================================================== diff --git a/quakespasm/Quake/host.c b/quakespasm/Quake/host.c index 229cbbce..9b31abae 100644 --- a/quakespasm/Quake/host.c +++ b/quakespasm/Quake/host.c @@ -556,6 +556,8 @@ void Host_ClearMemory (void) Hunk_FreeToLowMark (host_hunklevel); cls.signon = 0; free(sv.edicts); // ericw -- sv.edicts switched to use malloc() + cl_max_edicts = 0; // Spike -- paranoia + cl_entities = NULL; memset (&sv, 0, sizeof(sv)); memset (&cl, 0, sizeof(cl)); } diff --git a/quakespasm/Quake/host_cmd.c b/quakespasm/Quake/host_cmd.c index 480c73cb..6d496429 100644 --- a/quakespasm/Quake/host_cmd.c +++ b/quakespasm/Quake/host_cmd.c @@ -487,7 +487,7 @@ void Host_Status_f (void) j++; if (j) print_fn ( "effects: %i/%i\n", j, MAX_PARTICLETYPES-1); - for (i = 1,j=0; i < sv.max_edicts; i++) + for (i = 1,j=1; i < sv.num_edicts; i++) if (!sv.edicts[i].free) j++; print_fn ( "entities:%i/%i\n", j, sv.max_edicts); diff --git a/quakespasm/Quake/net_dgrm.c b/quakespasm/Quake/net_dgrm.c index 0ef0eae3..e6379243 100644 --- a/quakespasm/Quake/net_dgrm.c +++ b/quakespasm/Quake/net_dgrm.c @@ -48,7 +48,7 @@ static int droppedDatagrams; //we additionally look for 'DarkPlaces-Quake' servers too, because we can, but most of those servers will be using dpp7 and will (safely) not respond to our ccreq_server_info requests. //we are not visible to DarkPlaces users - dp does not support fitz666 so that's not a viable option, at least by default, feel free to switch the order if you also change sv_protocol back to 15. cvar_t sv_reportheartbeats = {"sv_reportheartbeats", "0"}; -cvar_t sv_public = {"sv_public", "0"}; +cvar_t sv_public = {"sv_public", NULL}; cvar_t com_protocolname = {"com_protocolname", "FTE-Quake DarkPlaces-Quake"}; cvar_t net_masters[] = { @@ -1441,7 +1441,7 @@ static void _Datagram_ServerControlPacket (sys_socket_t acceptsock, struct qsock if (s->disconnected) continue; ret = dfunc.AddrCompare(clientaddr, &s->addr); - if (ret >= 0) + if (ret == 0) { int i; diff --git a/quakespasm/Quake/net_main.c b/quakespasm/Quake/net_main.c index 7729e046..c5aa666a 100644 --- a/quakespasm/Quake/net_main.c +++ b/quakespasm/Quake/net_main.c @@ -186,7 +186,10 @@ const char *NET_QSocketGetMaskedAddressString (const qsocket_t *s) } qboolean NET_QSocketGetProQuakeAngleHack(const qsocket_t *s) { - return s->proquake_angle_hack; + if (s && !s->disconnected) + return s->proquake_angle_hack; + else + return false; //happens with demos } void NET_QSocketSetMSS(qsocket_t *s, int mss) { diff --git a/quakespasm/Quake/net_udp.c b/quakespasm/Quake/net_udp.c index d9017fb2..82695a13 100644 --- a/quakespasm/Quake/net_udp.c +++ b/quakespasm/Quake/net_udp.c @@ -536,6 +536,12 @@ int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) ((struct sockaddr_in6 *)addr2)->sin6_port) return 1; + if (((struct sockaddr_in6 *)addr1)->sin6_scope_id && + ((struct sockaddr_in6 *)addr2)->sin6_scope_id && + ((struct sockaddr_in6 *)addr1)->sin6_scope_id != + ((struct sockaddr_in6 *)addr2)->sin6_scope_id) //the ipv6 scope id is for use with link-local addresses, to identify the specific interface. + return 1; + return 0; } else diff --git a/quakespasm/Quake/pr_cmds.c b/quakespasm/Quake/pr_cmds.c index 31b73b45..df2dfdc1 100644 --- a/quakespasm/Quake/pr_cmds.c +++ b/quakespasm/Quake/pr_cmds.c @@ -1095,6 +1095,31 @@ static void PF_precache_sound (void) PR_RunError ("PF_precache_sound: overflow"); } +int SV_Precache_Model(const char *s) +{ + size_t i; + for (i = 0; i < MAX_MODELS; i++) + { + if (!sv.model_precache[i]) + { + if (sv.state != ss_loading) + { + //let existing clients know about it + MSG_WriteByte(&sv.reliable_datagram, svcdp_precache); + MSG_WriteShort(&sv.reliable_datagram, i|0x8000); + MSG_WriteString(&sv.reliable_datagram, s); + } + + sv.model_precache[i] = s; + sv.models[i] = Mod_ForName (s, i==1); + return i; + } + if (!strcmp(sv.model_precache[i], s)) + return i; + } + return 0; +} + static void PF_precache_model (void) { const char *s; @@ -1553,9 +1578,9 @@ static void PF_WriteEntity (void) static void PF_makestatic (void) { + eval_t *val; + entity_state_t *st; edict_t *ent; - int i; - int bits = 0; //johnfitz -- PROTOCOL_FITZQUAKE ent = G_EDICT(OFS_PARM0); @@ -1566,56 +1591,29 @@ static void PF_makestatic (void) } //johnfitz - //johnfitz -- PROTOCOL_FITZQUAKE - if (sv.protocol == PROTOCOL_NETQUAKE) - { - if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00 || (int)(ent->v.frame) & 0xFF00) - { - ED_Free (ent); - return; //can't display the correct model & frame, so don't show it at all - } - } + if (sv.num_statics == sv.max_statics) + PR_RunError ("PF_makestatic: Too many static entities"); + st = &sv.static_entities[sv.num_statics]; + memset(st, 0, sizeof(*st)); + VectorCopy(ent->v.origin, st->origin); + VectorCopy(ent->v.angles, st->angles); + st->modelindex = SV_ModelIndex(PR_GetString(ent->v.model)); //o.O Why does QuakeSpasm use model instead of modelindex? + st->frame = ent->v.frame; + st->effects = ent->v.effects; + st->colormap = ent->v.colormap; + st->skin = ent->v.skin; + if ((val = GetEdictFieldValue(ent, pr_extfields.alpha))) + st->alpha = ENTALPHA_ENCODE(val->_float); else - { - if (SV_ModelIndex(PR_GetString(ent->v.model)) & 0xFF00) - bits |= B_LARGEMODEL; - if ((int)(ent->v.frame) & 0xFF00) - bits |= B_LARGEFRAME; - if (ent->alpha != ENTALPHA_DEFAULT) - bits |= B_ALPHA; - } - - if (bits) - { - MSG_WriteByte (&sv.signon, svc_spawnstatic2); - MSG_WriteByte (&sv.signon, bits); - } - else - MSG_WriteByte (&sv.signon, svc_spawnstatic); - - if (bits & B_LARGEMODEL) - MSG_WriteShort (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model))); - else - MSG_WriteByte (&sv.signon, SV_ModelIndex(PR_GetString(ent->v.model))); - - if (bits & B_LARGEFRAME) - MSG_WriteShort (&sv.signon, ent->v.frame); - else - MSG_WriteByte (&sv.signon, ent->v.frame); - //johnfitz - - MSG_WriteByte (&sv.signon, ent->v.colormap); - MSG_WriteByte (&sv.signon, ent->v.skin); - for (i = 0; i < 3; i++) - { - MSG_WriteCoord(&sv.signon, ent->v.origin[i], sv.protocolflags); - MSG_WriteAngle(&sv.signon, ent->v.angles[i], sv.protocolflags); - } - - //johnfitz -- PROTOCOL_FITZQUAKE - if (bits & B_ALPHA) - MSG_WriteByte (&sv.signon, ent->alpha); - //johnfitz + st->alpha = ent->alpha; +// st->pmovetype = ent->v.pmovetype; + if ((val = GetEdictFieldValue(ent, pr_extfields.traileffectnum))) + st->traileffectnum = val->_float; + if ((val = GetEdictFieldValue(ent, pr_extfields.emiteffectnum))) + st->emiteffectnum = val->_float; +// VectorScale(ent->v.velocity, 8, st->velocity); +// st->eflags = ent->v.eflags; + sv.num_statics++; // throw the entity away now ED_Free (ent); @@ -1669,6 +1667,25 @@ void PF_Fixme (void); // PR_RunError ("unimplemented builtin"); //} +void PR_spawnfunc_misc_model(edict_t *self) +{ + eval_t *val; + if (!self->v.model && (val = GetEdictFieldValue(self, ED_FindFieldOffset("mdl")))) + self->v.model = val->string; + if (!*PR_GetString(self->v.model)) //must have a model, because otherwise various things will assume its not valid at all. + self->v.model = PR_SetEngineString("*null"); + + if (self->v.angles[1] < 0) //mimic AD. shame there's no avelocity clientside. + self->v.angles[1] = (rand()*(360.0f/RAND_MAX)); + + //make sure the model is precached, to avoid errors. + G_INT(OFS_PARM0) = self->v.model; + PF_precache_model(); + + //and lets just call makestatic instead of worrying if it'll interfere with the rest of the qc. + G_INT(OFS_PARM0) = EDICT_TO_PROG(self); + PF_makestatic(); +} static builtin_t pr_builtin[] = { diff --git a/quakespasm/Quake/pr_edict.c b/quakespasm/Quake/pr_edict.c index 8205d0a1..a9f8e51d 100644 --- a/quakespasm/Quake/pr_edict.c +++ b/quakespasm/Quake/pr_edict.c @@ -835,6 +835,7 @@ const char *ED_ParseEdict (const char *data, edict_t *ent) char keyname[256]; qboolean anglehack, init; int n; + eval_t *val; init = false; @@ -896,11 +897,26 @@ const char *ED_ParseEdict (const char *data, edict_t *ent) ent->alpha = ENTALPHA_ENCODE(atof(com_token)); //johnfitz + //spike -- hacks to support func_illusionary with all sorts of mdls, and various particle effects + if (!strcmp(keyname, "model") && sv.state == ss_loading) + /*ent->v.modelindex = */SV_Precache_Model(com_token); + //spike + key = ED_FindField (keyname); if (!key) { + if (!strcmp(keyname, "traileffect") && sv.state == ss_loading) + { + if ((val = GetEdictFieldValue(ent, pr_extfields.traileffectnum))) + val->_float = PF_SV_ForceParticlePrecache(com_token); + } + else if (!strcmp(keyname, "emiteffect") && sv.state == ss_loading) + { + if ((val = GetEdictFieldValue(ent, pr_extfields.emiteffectnum))) + val->_float = PF_SV_ForceParticlePrecache(com_token); + } //johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc - if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha")) + else if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha")) Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf continue; } @@ -1006,9 +1022,15 @@ void ED_LoadFromFile (const char *data) if (!func) { - Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf - ED_Print (ent); - ED_Free (ent); + const char *classname = PR_GetString(ent->v.classname); + if (!strcmp(classname, "misc_model")) + PR_spawnfunc_misc_model(ent); + else + { + Con_SafePrintf ("No spawn function for:\n"); //johnfitz -- was Con_Printf + ED_Print (ent); + ED_Free (ent); + } continue; } @@ -1111,18 +1133,25 @@ void PR_LoadProgs (void) pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } + for (i = 0; i < progs->numglobals; i++) + ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); + //spike: detect extended fields from progs pr_extfields.items2 = ED_FindFieldOffset("items2"); pr_extfields.gravity = ED_FindFieldOffset("gravity"); pr_extfields.alpha = ED_FindFieldOffset("alpha"); pr_extfields.movement = ED_FindFieldOffset("movement"); pr_extfields.traileffectnum = ED_FindFieldOffset("traileffectnum"); + pr_extfields.emiteffectnum = ED_FindFieldOffset("emiteffectnum"); pr_extfields.viewmodelforclient = ED_FindFieldOffset("viewmodelforclient"); - for (i = 0; i < progs->numglobals; i++) - ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); + i = progs->entityfields; + if (pr_extfields.emiteffectnum < 0) + pr_extfields.emiteffectnum = i++; + if (pr_extfields.traileffectnum < 0) + pr_extfields.traileffectnum = i++; - pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t); + pr_edict_size = i * 4 + sizeof(edict_t) - sizeof(entvars_t); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned diff --git a/quakespasm/Quake/pr_ext.c b/quakespasm/Quake/pr_ext.c index 6378be87..0c1e3d8f 100644 --- a/quakespasm/Quake/pr_ext.c +++ b/quakespasm/Quake/pr_ext.c @@ -2125,9 +2125,20 @@ static qboolean QC_FixFileName(const char *name, const char **result, const char return true; } -static struct +//small note on access modes: +//when reading, we fopen files inside paks, for compat with (crappy non-zip-compatible) filesystem code +//when writing, we directly fopen the file such that it can never be inside a pak. +//this means that we need to take care when reading in order to detect EOF properly. +//writing doesn't need anything like that, so it can just dump stuff out, but we do need to ensure that the modes don't get mixed up, because trying to read from a writable file will not do what you would expect. +//even libc mandates a seek between reading+writing, so no great loss there. +static struct qcfile_s { + char cache[1024]; + int cacheoffset, cachesize; FILE *file; + int fileoffset; + int filesize; + int filebase; //the offset of the file inside a pak int mode; } *qcfiles; static size_t qcfiles_max; @@ -2140,6 +2151,7 @@ static void PF_fopen(void) FILE *file; size_t i; char name[MAX_OSPATH]; + int filesize = 0; G_FLOAT(OFS_RETURN) = -1; //assume failure @@ -2155,9 +2167,9 @@ static void PF_fopen(void) switch(fmode) { case 0: //read - COM_FOpenFile (fname, &file, NULL); + filesize = COM_FOpenFile (fname, &file, NULL); if (!file && fallback) - COM_FOpenFile (fallback, &file, NULL); + filesize = COM_FOpenFile (fallback, &file, NULL); break; case 1: //append q_snprintf (name, sizeof(name), "%s/%s", com_gamedir, fname); @@ -2185,8 +2197,13 @@ static void PF_fopen(void) if (!qcfiles[i].file) break; } + qcfiles[i].filebase = ftell(file); qcfiles[i].file = file; qcfiles[i].mode = fmode; + //reading needs size info + qcfiles[i].filesize = filesize; + //clear the read cache. + qcfiles[i].fileoffset = qcfiles[i].cacheoffset = qcfiles[i].cachesize = 0; G_FLOAT(OFS_RETURN) = i+QC_FILE_BASE; } @@ -2198,20 +2215,45 @@ static void PF_fgets(void) Con_Warning("PF_fgets: invalid file handle\n"); else if (!qcfiles[fileid].file) Con_Warning("PF_fgets: file not open\n"); + else if (qcfiles[fileid].mode != 0) + Con_Warning("PF_fgets: file not open for reading\n"); else { + struct qcfile_s *f = &qcfiles[fileid]; char *ret = PR_GetTempString(); - char *end; - if (fgets(ret, STRINGTEMP_LENGTH, qcfiles[fileid].file)) + char *s = ret; + char *end = ret+STRINGTEMP_LENGTH; + for (;;) { - //strip any \r\n chars on the end. - end = ret+strlen(ret); - if (end>ret && end[-1] == '\n') - *--end = 0; - if (end>ret && end[-1] == '\r') - *--end = 0; - G_INT(OFS_RETURN) = PR_SetEngineString(ret); + if (!f->cachesize) + { + //figure out how much we can try to cache. + int sz = f->filesize - f->fileoffset; + if (sz < 0 || f->fileoffset < 0) //... maybe we shouldn't have implemented seek support. + sz = 0; + else if ((size_t)sz > sizeof(f->cache)) + sz = sizeof(f->cache); + //read a chunk + f->cacheoffset = 0; + f->cachesize = fread(f->cache, 1, sz, f->file); + f->fileoffset += f->cachesize; + if (!f->cachesize) + { + //classic eof... + break; + } + } + *s = f->cache[f->cacheoffset++]; + if (*s == '\n') //new line, yay! + break; + s++; + if (s == end) + s--; //rewind if we're overflowing, such that we truncate the string. } + if (s > ret && s[-1] == '\r') + s--; //terminate it on the \r of a \r\n pair. + *s = 0; //terminate it + G_INT(OFS_RETURN) = PR_SetEngineString(ret); } } static void PF_fputs(void) @@ -2222,6 +2264,8 @@ static void PF_fputs(void) Con_Warning("PF_fputs: invalid file handle\n"); else if (!qcfiles[fileid].file) Con_Warning("PF_fputs: file not open\n"); + else if (qcfiles[fileid].mode == 0) + Con_Warning("PF_fgets: file not open for writing\n"); else fputs(str, qcfiles[fileid].file); } @@ -2248,9 +2292,16 @@ static void PF_fseek(void) Con_Warning("PF_fread: file not open\n"); else { - G_INT(OFS_RETURN) = ftell(qcfiles[fileid].file); + if (qcfiles[fileid].mode == 0) + G_INT(OFS_RETURN) = qcfiles[fileid].fileoffset; //when we're reading, use the cached read offset + else + G_INT(OFS_RETURN) = ftell(qcfiles[fileid].file)-qcfiles[fileid].filebase; if (pr_argc>1) - fseek(qcfiles[fileid].file, G_INT(OFS_PARM1), SEEK_SET); + { + qcfiles[fileid].fileoffset = G_INT(OFS_PARM1); + fseek(qcfiles[fileid].file, qcfiles[fileid].filebase+qcfiles[fileid].fileoffset, SEEK_SET); + qcfiles[fileid].cachesize = qcfiles[fileid].cacheoffset = 0; + } } } #if 0 @@ -2301,6 +2352,11 @@ static void PF_fsize(void) Con_Warning("PF_fread: invalid file handle\n"); else if (!qcfiles[fileid].file) Con_Warning("PF_fread: file not open\n"); + else if (qcfiles[fileid].mode == 0) + { + G_INT(OFS_RETURN) = qcfiles[fileid].filesize; + //can't truncate if we're reading. + } else { long curpos = ftell(qcfiles[fileid].file); @@ -3410,7 +3466,7 @@ static void PF_void_stub(void) #ifdef PSET_SCRIPT //for compat with dpp7 protocols, and mods that cba to precache things. -static void COM_Effectinfo_Enumerate(void (*cb)(const char *pname)) +static void COM_Effectinfo_Enumerate(int (*cb)(const char *pname)) { int i; char *f, *e, *buf; @@ -3472,7 +3528,7 @@ static void COM_Effectinfo_Enumerate(void (*cb)(const char *pname)) } free(buf); } -static void PF_SV_ForceParticlePrecache(const char *s) +int PF_SV_ForceParticlePrecache(const char *s) { unsigned int i; for (i = 1; i < MAX_PARTICLETYPES; i++) @@ -3488,11 +3544,12 @@ static void PF_SV_ForceParticlePrecache(const char *s) } sv.particle_precache[i] = strcpy(Hunk_Alloc(strlen(s)+1), s); //weirdness to avoid issues with tempstrings - return; + return i; } if (!strcmp(sv.particle_precache[i], s)) - return; + return i; } + return 0; } static void PF_sv_particleeffectnum(void) { @@ -3862,7 +3919,7 @@ static const char *extnames[] = "DP_QC_STRFTIME", "DP_QC_STRING_CASE_FUNCTIONS", "DP_QC_STRINGBUFFERS", -// "DP_QC_STRINGCOLORFUNCTIONS", //the functions are implemented... the colour codes are nor +// "DP_QC_STRINGCOLORFUNCTIONS", //the functions are provided only as stubs. the client has absolutely no support. "DP_QC_STRREPLACE", "DP_QC_TOKENIZEBYSEPARATOR", "DP_QC_TRACEBOX", @@ -3883,7 +3940,7 @@ static const char *extnames[] = "DP_TE_BLOOD", "DP_TE_STANDARDEFFECTBUILTINS", "EXT_BITSHIFT", - //"FRIK_FILE", //lacks the file part, but does have the strings part. + "FRIK_FILE", //lacks the file part, but does have the strings part. #ifdef PSET_SCRIPT "FTE_PART_SCRIPT", "FTE_PART_NAMESPACES", @@ -4219,14 +4276,39 @@ void PR_DumpPlatform_f(void) //extra fields fprintf(f, "\n\n//Supported Extension fields\n"); fprintf(f, ".float gravity;\n"); //used by hipnotic - fprintf(f, "//.float items2;\n"); //used by both mission packs. *REPLACES* serverflags if defined, so lets try not to define it. - fprintf(f, ".float alpha;\n"); //entity alpha. woot. + fprintf(f, "//.float items2; /*if defined, overrides serverflags for displaying runes on the hud*/\n"); //used by both mission packs. *REPLACES* serverflags if defined, so lets try not to define it. + fprintf(f, ".float alpha; /*entity opacity*/\n"); //entity alpha. woot. + fprintf(f, ".float traileffectnum; /*can also be set with 'traileffect' from a map editor*/\n"); + fprintf(f, ".float emiteffectnum; /*can also be set with 'traileffect' from a map editor*/\n"); + fprintf(f, ".vector movement; /*describes which forward/right/up keys the player is holidng*/\n"); + fprintf(f, ".entity viewmodelforclient; /*attaches this entity to the specified player's view. invisible to other players*/\n"); //extra constants fprintf(f, "\n\n//Supported Extension Constants\n"); - fprintf(f, "const float MOVETYPE_FOLLOW\t= "STRINGIFY(MOVETYPE_EXT_FOLLOW)";\n"); - fprintf(f, "const float SOLID_CORPSE\t= "STRINGIFY(SOLID_EXT_CORPSE)";\n"); + fprintf(f, "const float MOVETYPE_FOLLOW = "STRINGIFY(MOVETYPE_EXT_FOLLOW)";\n"); + fprintf(f, "const float SOLID_CORPSE = "STRINGIFY(SOLID_EXT_CORPSE)";\n"); + fprintf(f, "const float FILE_READ = "STRINGIFY(0)";\n"); + fprintf(f, "const float FILE_APPEND = "STRINGIFY(1)";\n"); + fprintf(f, "const float FILE_WRITE = "STRINGIFY(2)";\n"); + + fprintf(f, "const float CLIENTTYPE_DISCONNECT = "STRINGIFY(0)";\n"); + fprintf(f, "const float CLIENTTYPE_REAL = "STRINGIFY(1)";\n"); + fprintf(f, "const float CLIENTTYPE_BOT = "STRINGIFY(2)";\n"); + fprintf(f, "const float CLIENTTYPE_NOTCLIENT = "STRINGIFY(3)";\n"); + + fprintf(f, "const float EF_NOSHADOW = "STRINGIFY(0x1000)";\n"); + + fprintf(f, "const float MSG_MULTICAST = "STRINGIFY(4)";\n"); + fprintf(f, "const float MULTICAST_ALL = "STRINGIFY(MULTICAST_ALL_U)";\n"); +// fprintf(f, "const float MULTICAST_PHS = "STRINGIFY(MULTICAST_PHS_U)";\n"); + fprintf(f, "const float MULTICAST_PVS = "STRINGIFY(MULTICAST_PVS_U)";\n"); + fprintf(f, "const float MULTICAST_ONE = "STRINGIFY(MULTICAST_ONE_U)";\n"); + fprintf(f, "const float MULTICAST_ALL_R = "STRINGIFY(MULTICAST_ALL_R)";\n"); +// fprintf(f, "const float MULTICAST_PHS_R = "STRINGIFY(MULTICAST_PHS_R)";\n"); + fprintf(f, "const float MULTICAST_PVS_R = "STRINGIFY(MULTICAST_PVS_R)";\n"); + fprintf(f, "const float MULTICAST_ONE_R = "STRINGIFY(MULTICAST_ONE_R)";\n"); + fprintf(f, "const float MULTICAST_INIT = "STRINGIFY(MULTICAST_INIT)";\n"); for (j = 0; j < 2; j++) { diff --git a/quakespasm/Quake/progdefs.q1 b/quakespasm/Quake/progdefs.q1 old mode 100644 new mode 100755 diff --git a/quakespasm/Quake/progs.h b/quakespasm/Quake/progs.h index d01a1e55..4fc12fa6 100644 --- a/quakespasm/Quake/progs.h +++ b/quakespasm/Quake/progs.h @@ -79,6 +79,10 @@ void PR_EnableExtensions(ddef_t *pr_globaldefs); //adds in the extra builtins et void PR_AutoCvarChanged(cvar_t *var); //updates the autocvar_ globals when their cvar is changed void PR_ShutdownExtensions(void); //nooooes! void PR_DumpPlatform_f(void); //console command: writes out a qsextensions.qc file +//special hacks... +int PF_SV_ForceParticlePrecache(const char *s); +int SV_Precache_Model(const char *s); +void PR_spawnfunc_misc_model(edict_t *self); //from pr_edict, for pr_ext. reflection is messy. qboolean ED_ParseEpair (void *base, ddef_t *key, const char *s); @@ -178,6 +182,7 @@ extern struct pr_extfields_s int movement; int viewmodelforclient; int traileffectnum; + int emiteffectnum; } pr_extfields; #endif /* _QUAKE_PROGS_H */ diff --git a/quakespasm/Quake/protocol.h b/quakespasm/Quake/protocol.h index 1ada61e0..61992261 100644 --- a/quakespasm/Quake/protocol.h +++ b/quakespasm/Quake/protocol.h @@ -362,15 +362,16 @@ typedef struct vec3_t angles; unsigned short modelindex; //johnfitz -- was int unsigned short frame; //johnfitz -- was int + unsigned int effects; unsigned char colormap; //johnfitz -- was int unsigned char skin; //johnfitz -- was int unsigned char alpha; //johnfitz -- added unsigned char pmovetype; //spike unsigned short traileffectnum; //spike -- for qc-defined particle trails. typically evilly used for things that are not trails. + unsigned short emiteffectnum; //spike -- for qc-defined particle trails. typically evilly used for things that are not trails. short velocity[3]; //spike -- the player's velocity. - unsigned short effects; unsigned char eflags; - unsigned char pad; +// unsigned char pad; } entity_state_t; #define EFLAGS_STEP 1 //#define EFLAGS_GLOWTRAIL 2 @@ -379,7 +380,7 @@ typedef struct //#define EFLAGS_ 16 //#define EFLAGS_COLOURMAPPED 32 //.colormap=1024|(top<<4)|bottom), instead of a player number //#define EFLAGS_ 64 -#define EFLAGS_ONGROUND 128 +#define EFLAGS_ONGROUND 128 //for bobbing more than anything else. *sigh*. typedef struct { diff --git a/quakespasm/Quake/r_part_fte.c b/quakespasm/Quake/r_part_fte.c index 00a8a9ee..35b8f9ec 100644 --- a/quakespasm/Quake/r_part_fte.c +++ b/quakespasm/Quake/r_part_fte.c @@ -128,7 +128,7 @@ static float psintable[256]; int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typenum, trailstate_t **tsk); int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec3_t axis[3], trailstate_t **tsk); -static qboolean P_LoadParticleSet(char *name, qboolean implicit); +static qboolean P_LoadParticleSet(char *name, qboolean implicit, qboolean showwarning); static void R_Particles_KillAllEffects(void); static void buildsintable(void) @@ -200,7 +200,7 @@ typedef struct skytris_s { vec3_t x; vec3_t y; float area; - float nexttime; + double nexttime; int ptype; struct msurface_s *face; } skytris_t; @@ -430,9 +430,6 @@ static beamseg_t *free_beams; static beamseg_t *beams; static int r_numbeams; -static skytriblock_t *skytrimem; -static skytris_t *skytris; - static clippeddecal_t *free_decals; static clippeddecal_t *decals; static int r_numdecals; @@ -764,11 +761,11 @@ typedef struct associatedeffect_s struct associatedeffect_s *next; char mname[MAX_QPATH]; char pname[MAX_QPATH]; + unsigned int flags; enum { AE_TRAIL, AE_EMIT, - AE_REPLACE } type; } associatedeffect_t; static associatedeffect_t *associatedeffect; @@ -776,16 +773,28 @@ static void PScript_AssociateEffect_f(void) { const char *modelname = Cmd_Argv(1); const char *effectname = Cmd_Argv(2); - int type = atoi(Cmd_Argv(3)); + unsigned int flags = 0; + int type; associatedeffect_t *ae; + int i; + if (!strcmp(Cmd_Argv(0), "r_trail")) type = AE_TRAIL; else { - if (type) - type = AE_REPLACE; - else - type = AE_EMIT; + type = AE_EMIT; + for (i = 3; i < Cmd_Argc(); i++) + { + const char *fn = Cmd_Argv(i); + if (!strcmp(fn, "replace") || !strcmp(fn, "1")) + flags |= MOD_EMITREPLACE; + else if (!strcmp(fn, "forwards") || !strcmp(fn, "forward")) + flags |= MOD_EMITFORWARDS; + else if (!strcmp(fn, "0")) + ; //1 or 0 are legacy, meaning replace or not + else + Con_DPrintf("%s %s: unknown flag %s\n", Cmd_Argv(0), modelname, fn); + } } if ( @@ -796,6 +805,7 @@ static void PScript_AssociateEffect_f(void) strstr(modelname, ".bsp") || strstr(modelname, "turr")) { + //there is a very real possibility of attaching 'large' effects to models so that they become more visible (eg: a stream of particles passing through walls showing you the entity that they're eminating from) Con_Printf("Sorry: Not allowed to attach effects to model \"%s\"\n", modelname); return; } @@ -808,20 +818,18 @@ static void PScript_AssociateEffect_f(void) { if (!strcmp(ae->mname, modelname)) if ((ae->type==AE_TRAIL) == (type==AE_TRAIL)) - { - strcpy(ae->pname, effectname); break; - } } if (!ae) { ae = Z_Malloc(sizeof(*ae)); - ae->type = type; strcpy(ae->mname, modelname); - strcpy(ae->pname, effectname); ae->next = associatedeffect; associatedeffect = ae; } + strcpy(ae->pname, effectname); + ae->type = type; + ae->flags = flags; r_plooksdirty = true; } @@ -888,11 +896,8 @@ void PScript_UpdateModelEffects(qmodel_t *mod) break; case AE_EMIT: mod->emiteffect = PScript_FindParticleType(ae->pname); - mod->flags &= ~MOD_EMITREPLACE; - break; - case AE_REPLACE: - mod->emiteffect = PScript_FindParticleType(ae->pname); - mod->flags |= MOD_EMITREPLACE; + mod->flags &= ~(MOD_EMITREPLACE|MOD_EMITFORWARDS); + mod->flags |= ae->flags; break; } } @@ -1098,7 +1103,7 @@ int PScript_FindParticleType(const char *fullname) } } if (*cfg) - if (P_LoadParticleSet(cfg, true)) + if (P_LoadParticleSet(cfg, true, true)) return PScript_FindParticleType(fullname); /* if (fallback) @@ -1244,6 +1249,13 @@ static void P_LoadTexture(part_type_t *ptype, qboolean warn) } ptype->looks.texture = thetex; } + else if (strstr(ptype->texname, "classicparticle")) + { + extern gltexture_t *particletexture1; + ptype->looks.texture = particletexture1; + ptype->s2 = 0.5; + ptype->t2 = 0.5; + } else if (strstr(ptype->texname, "glow") || strstr(ptype->texname, "ball") || ptype->looks.type == PT_TEXTUREDSPARK) //sparks and special names get a nice circular texture. { static gltexture_t *thetex; @@ -1400,9 +1412,32 @@ static void P_ResetToDefaults(part_type_t *ptype) ptype->t2 = 1; } +char *PScript_ReadLine(char *buffer, size_t buffersize, const char *filedata, size_t filesize, size_t *offset) +{ + const char *start = filedata + *offset; + const char *f = start; + const char *e = filedata+filesize; + if (f >= e) + return NULL; //eof + while (f < e) + { + if (*f++ == '\n') + break; + } + + *offset = f-filedata; + + buffersize--; + if (buffersize >= (size_t)(f-start)) + buffersize = f-start; + memcpy(buffer, start, buffersize); + buffer[buffersize] = 0; //null terminate it + + return buffer; +} //This is the function that loads the effect descriptions. -void PScript_ParseParticleEffectFile(const char *config, qboolean part_parseweak, FILE *context) +void PScript_ParseParticleEffectFile(const char *config, qboolean part_parseweak, char *context, size_t filesize) { const char *var, *value; char *buf; @@ -1415,14 +1450,15 @@ void PScript_ParseParticleEffectFile(const char *config, qboolean part_parseweak char line[512]; char part_parsenamespace[MAX_QPATH]; - byte *palrgba = (byte *)d_8to24table; + byte *palrgba = (byte *)d_8to24table; + size_t offset = 0; q_strlcpy(part_parsenamespace, config, sizeof(part_parsenamespace)); config = part_parsenamespace; nexteffect: - if (!fgets(line, sizeof(line), context)) + if (!PScript_ReadLine(line, sizeof(line), context, filesize, &offset)) return; //eof reparse: @@ -1465,7 +1501,7 @@ reparse: goto nexteffect; } - buf = fgets(line, sizeof(line), context); + buf = PScript_ReadLine(line, sizeof(line), context, filesize, &offset); if (!buf) return; //eof while (*buf && *buf <= ' ') @@ -1489,7 +1525,7 @@ reparse: int depth = 1; while(1) { - buf = fgets(line, sizeof(line), context); + buf = PScript_ReadLine(line, sizeof(line), context, filesize, &offset); if (!buf) return; @@ -1561,13 +1597,13 @@ reparse: while(1) { - buf = fgets(line, sizeof(line), context); + buf = PScript_ReadLine(line, sizeof(line), context, filesize, &offset); if (!buf) { Con_Printf("Unexpected end of buffer with effect %s\n", ptype->name); return; } - +skipread: while (*buf && *buf <= ' ') buf++; //no whitespace please. if (*buf == '}') @@ -1586,11 +1622,16 @@ reparse: } else #endif -#if UNSUPPORTED if (!strcmp(var, "shader")) { q_strlcpy(ptype->texname, ptype->name, sizeof(ptype->texname)); - buf = Cbuf_GetNext(Cmd_ExecLevel, true); + +#if UNSUPPORTED + Con_DPrintf("%s.%s: shaders are not supported in this build\n", ptype->config, ptype->name); +#endif + buf = PScript_ReadLine(line, sizeof(line), context, filesize, &offset); + if (!buf) + continue; while (*buf && *buf <= ' ') buf++; //no leading whitespace please. if (*buf == '{') @@ -1603,8 +1644,8 @@ reparse: str[2] = 0; while(nest) { - buf = Cbuf_GetNext(Cmd_ExecLevel, true); - if (!*buf) + buf = PScript_ReadLine(line, sizeof(line), context, filesize, &offset); + if (!buf) { Con_Printf("Unexpected end of buffer with effect %s\n", ptype->name); break; @@ -1621,15 +1662,15 @@ reparse: str[slen++] = '\n'; } str[slen] = 0; +#if UNSUPPORTED R_RegisterShader(ptype->texname, SUF_NONE, str); +#endif Z_Free(str); } else - Cbuf_InsertText(buf, Cmd_ExecLevel, true); + goto skipread; } - else -#endif - if (!strcmp(var, "texture") || !strcmp(var, "linear_texture") || !strcmp(var, "nearest_texture") || !strcmp(var, "nearesttexture")) + else if (!strcmp(var, "texture") || !strcmp(var, "linear_texture") || !strcmp(var, "nearest_texture") || !strcmp(var, "nearesttexture")) { q_strlcpy(ptype->texname, value, sizeof(ptype->texname)); ptype->looks.nearest = !strncmp(var, "nearest", 7); @@ -1802,7 +1843,7 @@ reparse: #endif else if (!strcmp(var, "randomvel")) - { + { //shortcut for velwrand (and velbias for z bias) ptype->velbias[0] = ptype->velbias[1] = 0; ptype->velwrand[0] = ptype->velwrand[1] = atof(value); if (Cmd_Argc()>3) @@ -1845,18 +1886,19 @@ reparse: ptype->orgbias[1] = atof(Cmd_Argv(2)); ptype->orgbias[2] = atof(Cmd_Argv(3)); } - else if (!strcmp(var, "velbias")) - { - ptype->velbias[0] = atof(value); - ptype->velbias[1] = atof(Cmd_Argv(2)); - ptype->velbias[2] = atof(Cmd_Argv(3)); - } else if (!strcmp(var, "orgwrand")) { ptype->orgwrand[0] = atof(value); ptype->orgwrand[1] = atof(Cmd_Argv(2)); ptype->orgwrand[2] = atof(Cmd_Argv(3)); } + + else if (!strcmp(var, "velbias")) + { + ptype->velbias[0] = atof(value); + ptype->velbias[1] = atof(Cmd_Argv(2)); + ptype->velbias[2] = atof(Cmd_Argv(3)); + } else if (!strcmp(var, "velwrand")) { ptype->velwrand[0] = atof(value); @@ -1942,9 +1984,9 @@ parsefluid: ptype->flags |= PT_TROVERWATER; goto parsefluid; } -#if UNSUPPORTED else if (!strcmp(var, "model")) { +#if UNSUPPORTED partmodels_t *mod; char *e; @@ -2029,8 +2071,10 @@ parsefluid: else mod->traileffect = P_INVALID; } - } +#else + Con_DPrintf("%s.%s: model particles are not supported in this build\n", ptype->config, ptype->name); #endif + } else if (!strcmp(var, "sound")) { const char *e; @@ -2221,6 +2265,7 @@ parsefluid: ptype->stainonimpact = atof(value); else if (!strcmp(var, "blend")) { + //small note: use premultiplied alpha where possible. this reduces the required state switches. ptype->looks.premul = false; if (!strcmp(value, "adda") || !strcmp(value, "add")) ptype->looks.blendmode = BM_ADDA; @@ -2234,7 +2279,7 @@ parsefluid: ptype->looks.blendmode = BM_INVMODC; else if (!strcmp(value, "blendcolour") || !strcmp(value, "blendcolor")) ptype->looks.blendmode = BM_BLENDCOLOUR; - else if (!strcmp(value, "blendalpha")) + else if (!strcmp(value, "blendalpha") || !strcmp(value, "blend")) ptype->looks.blendmode = BM_BLEND; else if (!strcmp(value, "premul_subtract")) { @@ -2252,7 +2297,10 @@ parsefluid: ptype->looks.blendmode = BM_PREMUL; } else + { + Con_DPrintf("%s.%s: uses unknown blend type '%s', assuming legacy 'blendalpha'\n", ptype->config, ptype->name, value); ptype->looks.blendmode = BM_BLEND; //fallback + } } else if (!strcmp(var, "spawnmode")) { @@ -2280,8 +2328,13 @@ parsefluid: } else if (!strcmp(value, "distball")) ptype->spawnmode = SM_DISTBALL; - else + else if (!strcmp(value, "box")) ptype->spawnmode = SM_BOX; + else + { + Con_DPrintf("%s.%s: uses unknown spawn type '%s', assuming 'box'\n", ptype->config, ptype->name, value); + ptype->spawnmode = SM_BOX; + } if (Cmd_Argc()>2) { @@ -2304,8 +2357,13 @@ parsefluid: ptype->looks.type = PT_CDECAL; else if (!strcmp(value, "udecal")) ptype->looks.type = PT_UDECAL; - else + else if (!strcmp(value, "normal")) ptype->looks.type = PT_NORMAL; + else + { + Con_DPrintf("%s.%s: uses unknown render type '%s', assuming 'normal'\n", ptype->config, ptype->name, value); + ptype->looks.type = PT_NORMAL; //fallback + } settype = true; } else if (!strcmp(var, "clippeddecal")) //mask, match @@ -2419,7 +2477,10 @@ parsefluid: /* else if (!strcmp(var, "spawnparam3")) ptype->spawnparam3 = atof(value); */ else if (!strcmp(var, "up")) + { ptype->orgbias[2] = atof(value); + Con_DPrintf("%s.%s: up is deprecated, use orgbias 0 0 Z\n", ptype->config, ptype->name); + } #endif else if (!strcmp(var, "rampmode")) @@ -2437,8 +2498,13 @@ parsefluid: ptype->rampmode = RAMP_NEAREST; else if (!strcmp(value, "lerp")) //don't use the name 'linear'. ramps are there to avoid linear... ptype->rampmode = RAMP_LERP; - else //if (!strcmp(value, "delta")) + else if (!strcmp(value, "delta")) ptype->rampmode = RAMP_DELTA; + else + { + Con_DPrintf("%s.%s: uses unknown ramp mode '%s', assuming 'delta'\n", ptype->config, ptype->name, value); + ptype->rampmode = RAMP_DELTA; + } } else if (!strcmp(var, "rampindexlist")) { // better not use this with delta ramps... @@ -2523,7 +2589,13 @@ parsefluid: ptype->rampindexes++; } else if (!strcmp(var, "viewspace")) + { +#if UNSUPPORTED ptype->viewspacefrac = (Cmd_Argc()>1)?atof(value):1; +#else + Con_DPrintf("%s.%s: viewspace particles are not supported in this build\n", ptype->config, ptype->name); +#endif + } else if (!strcmp(var, "perframe")) ptype->flags |= PT_INVFRAMETIME; else if (!strcmp(var, "averageout")) @@ -2573,16 +2645,18 @@ parsefluid: ptype->dl_scales[1] = atof(Cmd_Argv(2)); ptype->dl_scales[2] = atof(Cmd_Argv(3)); } -#if UNSUPPORTED else if (!strcmp(var, "spawnstain")) { +#if UNSUPPORTED ptype->stain_radius = atof(value); ptype->stain_rgb[0] = atof(Cmd_Argv(2)); ptype->stain_rgb[1] = atof(Cmd_Argv(3)); ptype->stain_rgb[2] = atof(Cmd_Argv(4)); - } +#else + Con_DPrintf("%s.%s: spawnstain is not supported in this build\n", ptype->config, ptype->name); #endif - else + } + else if (Cmd_Argc()) Con_DPrintf("%s.%s: %s is not a recognised particle type field\n", ptype->config, ptype->name, var); } ptype->loaded = part_parseweak?1:2; @@ -2847,7 +2921,7 @@ static void P_ImportEffectInfo(const char *config, char *line, qboolean part_par { int i; - FILE *file; + char *file; const char *line; char linebuf[1024]; //default assumes 8*8 grid, but we allow more @@ -2859,10 +2933,11 @@ static void P_ImportEffectInfo(const char *config, char *line, qboolean part_par teximages[i][3] = 1/8.0 * (i>>3); } - COM_FOpenFile("particles/particlefont.txt", &file, NULL); + file = (char*)COM_LoadMallocFile("particles/particlefont.txt", NULL); if (file) { - while (fgets(linebuf, sizeof(linebuf), file)) + size_t offset = 0; + while (PScript_ReadLine(linebuf, sizeof(linebuf), file, com_filesize, &offset)) { float s1,s2,t1,t2; line = COM_Parse(linebuf); @@ -2883,7 +2958,7 @@ static void P_ImportEffectInfo(const char *config, char *line, qboolean part_par teximages[i][3] = t1; } } - fclose(file); + free(file); } } @@ -3318,10 +3393,32 @@ void PScript_InitParticles (void) //#endif } +void PScript_ClearSurfaceParticles(qmodel_t *mod) +{ + mod->skytime = 0; + mod->skytris = NULL; + while(mod->skytrimem) + { + void *f = mod->skytrimem; + mod->skytrimem = mod->skytrimem->next; + Z_Free(f); + } +} +static void PScript_ClearAllSurfaceParticles(void) +{ //make sure we hit all models, even ones from the previous map. maybe this is overkill + extern qmodel_t mod_known[]; + extern int mod_numknown; + int i; + for (i = 0; i < mod_numknown; i++) + PScript_ClearSurfaceParticles(&mod_known[i]); +} + void PScript_Shutdown (void) { Cvar_SetCallback(&r_particledesc, NULL); + CL_ClearTrailStates(); + // if (fallback) // fallback->ShutdownParticles(); @@ -3364,13 +3461,7 @@ void PScript_Shutdown (void) free_decals = NULL; free_beams = NULL; - skytris = NULL; - while(skytrimem) - { - void *f = skytrimem; - skytrimem = skytrimem->next; - Z_Free(f); - } + PScript_ClearAllSurfaceParticles(); r_numparticles = 0; r_numdecals = 0; @@ -3425,78 +3516,80 @@ qboolean PScript_Startup (void) void PScript_RecalculateSkyTris (void) { - skytris = NULL; - while(skytrimem) - { - void *f = skytrimem; - skytrimem = skytrimem->next; - Z_Free(f); - } + qmodel_t *m = cl.worldmodel; + size_t modidx; - if (cl.worldmodel && !cl.worldmodel->needload && cl.worldmodel->type == mod_brush) - { - qmodel_t *m = cl.worldmodel; - int t; - int i; - int ptype; - msurface_t *surf; - char key[128]; - const char *data = COM_Parse(cl.worldmodel->entities); - int *remaps; - remaps = malloc(sizeof(*remaps)*m->numtextures); - for (t = 0; t < m->numtextures; t++) - remaps[t] = P_INVALID; + PScript_ClearAllSurfaceParticles(); - //parse the worldspawn entity fields for "_texpart_FOO" keys to give texture "FOO" particles from the effect specified by the value - if (data && com_token[0] == '{') + for (modidx = 0; modidx < MAX_MODELS; modidx++) + { + m = cl.model_precache[modidx]; + + if (m && !m->needload && m->type == mod_brush) { - while (1) + int t; + int i; + int ptype; + msurface_t *surf; + char key[128]; + const char *data = COM_Parse(m->entities); + int *remaps; + remaps = malloc(sizeof(*remaps)*m->numtextures); + for (t = 0; t < m->numtextures; t++) + remaps[t] = P_INVALID; + + //parse the worldspawn entity fields for "_texpart_FOO" keys to give texture "FOO" particles from the effect specified by the value + if (data && com_token[0] == '{') { - data = COM_Parse(data); - if (!data) - break; // error - if (com_token[0] == '}') - break; // end of worldspawn - if (com_token[0] == '_') - strcpy(key, com_token + 1); - else - strcpy(key, com_token); - while (key[strlen(key)-1] == ' ') // remove trailing spaces - key[strlen(key)-1] = 0; - data = COM_Parse(data); - if (!data) - break; // error - if (!q_strncasecmp("texpart_", key, 8)) + while (1) { - for (t = 0; t < m->numtextures; t++) + data = COM_Parse(data); + if (!data) + break; // error + if (com_token[0] == '}') + break; // end of worldspawn + if (com_token[0] == '_') + strcpy(key, com_token + 1); + else + strcpy(key, com_token); + while (key[strlen(key)-1] == ' ') // remove trailing spaces + key[strlen(key)-1] = 0; + data = COM_Parse(data); + if (!data) + break; // error + if (!q_strncasecmp("texpart_", key, 8)) { - if (!q_strcasecmp(key+8, m->textures[t]->name)) - remaps[t] = PScript_FindParticleType(com_token); + /*in quakespasm there are always two textures added on the end (rather than pointing to textures outside the model)*/ + for (t = 0; t < m->numtextures-2; t++) + { + if (!q_strcasecmp(key+8, m->textures[t]->name)) + remaps[t] = PScript_FindParticleType(com_token); + } } } } - } - for (t = 0; t < m->numtextures; t++) - { - ptype = remaps[t]; - if (ptype == P_INVALID) - ptype = PScript_FindParticleType(va("tex_%s", m->textures[t]->name)); - - if (ptype >= 0) + for (t = 0; t < m->numtextures; t++) { - for (i=0; inummodelsurfaces; i++) + ptype = remaps[t]; + if (ptype == P_INVALID) + ptype = PScript_FindParticleType(va("tex_%s", m->textures[t]->name)); + + if (ptype >= 0) { - surf = m->surfaces + i + m->firstmodelsurface; - if (surf->texinfo->texture == m->textures[t]) + for (i=0; inummodelsurfaces; i++) { - /*FIXME: it would be a good idea to determine the surface's (midpoint) pvs cluster so that we're not spamming for the entire map*/ - PScript_EmitSkyEffectTris(m, surf, ptype); + surf = m->surfaces + i + m->firstmodelsurface; + if (surf->texinfo->texture == m->textures[t]) + { + /*FIXME: it would be a good idea to determine the surface's (midpoint) pvs cluster so that we're not spamming for the entire map*/ + PScript_EmitSkyEffectTris(m, surf, ptype); + } } } } + free(remaps); } - free(remaps); } } /* @@ -3546,19 +3639,15 @@ void PScript_ClearParticles (void) part_type[i].beams = NULL; } - skytris = NULL; - while(skytrimem) - { - void *f = skytrimem; - skytrimem = skytrimem->next; - Z_Free(f); - } + PScript_ClearAllSurfaceParticles(); r_plooksdirty = true; + + CL_ClearTrailStates(); } -static qboolean P_LoadParticleSet(char *name, qboolean implicit) +static qboolean P_LoadParticleSet(char *name, qboolean implicit, qboolean showwarning) { - FILE *file; + char *file; pcfg_t *cfg; if (!*name) @@ -3591,13 +3680,13 @@ static qboolean P_LoadParticleSet(char *name, qboolean implicit) return true; } - COM_FOpenFile(va("particles/%s.cfg", name), &file, NULL); + file = (char*)COM_LoadMallocFile(va("particles/%s.cfg", name), NULL); if (!file) - COM_FOpenFile(va("%s.cfg", name), &file, NULL); + file = (char*)COM_LoadMallocFile(va("%s.cfg", name), NULL); if (file) { - PScript_ParseParticleEffectFile(name, implicit, file); - fclose(file); + PScript_ParseParticleEffectFile(name, implicit, file, com_filesize); + free(file); } else { @@ -3609,15 +3698,10 @@ static qboolean P_LoadParticleSet(char *name, qboolean implicit) P_ImportEffectInfo_Name(name); return true; } - - if (P_LoadParticleSet("high", true)) - Con_Printf(CON_WARNING "Couldn't find particle description %s, loading 'high' instead\n", name); - else #endif - { + if (showwarning) Con_Printf(CON_WARNING "Couldn't find particle description %s\n", name); - return false; - } + return false; } return true; } @@ -3664,50 +3748,40 @@ static void R_ParticleDesc_Callback(struct cvar_s *var) for (c = var->string; (c=COM_Parse(c)); ) { if (*com_token) - P_LoadParticleSet(com_token, false); + P_LoadParticleSet(com_token, false, true); + } + + if (cls.state == ca_connected && cl.model_precache[1]) + { + //per-map configs. because we can. + memcpy(com_token, "map_", 4); + COM_FileBase(cl.model_precache[1]->name, com_token+4, sizeof(com_token)-4); + P_LoadParticleSet(com_token, false, false); } //make sure nothing is stale. CL_RegisterParticles(); } -static void P_AddRainParticles(void) +static void P_AddRainParticles(qmodel_t *mod, vec3_t axis[3], vec3_t eorg, int visframe, float contribution) { float x; float y; - static float skipped; - static float lastrendered; part_type_t *type; - vec3_t org, vdist; + vec3_t org, vdist, worg, wnorm; skytris_t *st; - - if (!r_part_rain.value || !r_part_rain_quantity.value) - { - skipped = true; + if (!r_part_rain_quantity.value) return; - } - if (lastrendered < particletime - 0.5) - skipped = true; //we've gone for half a sec without any new rain. This would cause some strange effects, so reset times. + mod->skytime += contribution; - if (skipped) + for (st = mod->skytris; st; st = st->next) { - for (st = skytris; st; st = st->next) + if (st->face->visframe != visframe) { - st->nexttime = particletime; - } - } - skipped = false; - - lastrendered = particletime; - - for (st = skytris; st; st = st->next) - { - if (st->face->visframe != r_visframecount) - { - st->nexttime = particletime; + st->nexttime = mod->skytime; continue; } @@ -3717,46 +3791,46 @@ static void P_AddRainParticles(void) if (!type->loaded) //woo, batch skipping. continue; - while (st->nexttime < particletime) + while (st->nexttime < mod->skytime) { if (!free_particles) return; - st->nexttime += 10000/(st->area*r_part_rain_quantity.value*type->rainfrequency); + st->nexttime += 10000.0/(st->area*r_part_rain_quantity.value*type->rainfrequency); x = frandom()*frandom(); y = frandom() * (1-x); VectorMA(st->org, x, st->x, org); VectorMA(org, y, st->y, org); + worg[0] = DotProduct(org, axis[0]) + eorg[0]; + worg[1] = -DotProduct(org, axis[1]) + eorg[1]; + worg[2] = DotProduct(org, axis[2]) + eorg[2]; - VectorSubtract(org, r_refdef.vieworg, vdist); - + //ignore it if its too far away + VectorSubtract(worg, r_refdef.vieworg, vdist); if (VectorLength(vdist) > (1024+512)*frandom()) continue; if (st->face->flags & SURF_PLANEBACK) - VectorMA(org, -0.5, st->face->plane->normal, org); + VectorScale(st->face->plane->normal, -1, vdist); else - VectorMA(org, 0.5, st->face->plane->normal, org); + VectorCopy(st->face->plane->normal, vdist); - if (!(CL_PointContentsMask(org) & FTECONTENTS_SOLID)) //should be paranoia + wnorm[0] = DotProduct(vdist, axis[0]); + wnorm[1] = -DotProduct(vdist, axis[1]); + wnorm[2] = DotProduct(vdist, axis[2]); + + VectorMA(worg, 0.5, wnorm, worg); + if (!(CL_PointContentsMask(worg) & FTECONTENTS_SOLID)) //should be paranoia, at least for the world. { - if (st->face->flags & SURF_PLANEBACK) - { - vdist[0] = -st->face->plane->normal[0]; - vdist[1] = -st->face->plane->normal[1]; - vdist[2] = -st->face->plane->normal[2]; - PScript_RunParticleEffectState(org, vdist, 1, st->ptype, NULL); - } - else - PScript_RunParticleEffectState(org, st->face->plane->normal, 1, st->ptype, NULL); + PScript_RunParticleEffectState(worg, wnorm, 1, st->ptype, NULL); } } } } -static void R_Part_SkyTri(float *v1, float *v2, float *v3, msurface_t *surf, int ptype) +static void R_Part_SkyTri(qmodel_t *mod, float *v1, float *v2, float *v3, msurface_t *surf, int ptype) { float dot; float xm; @@ -3767,13 +3841,13 @@ static void R_Part_SkyTri(float *v1, float *v2, float *v3, msurface_t *surf, int skytris_t *st; - skytriblock_t *mem = skytrimem; + skytriblock_t *mem = mod->skytrimem; if (!mem || mem->count == sizeof(mem->tris)/sizeof(mem->tris[0])) { - skytrimem = Z_Malloc(sizeof(*skytrimem)); - skytrimem->next = mem; - skytrimem->count = 0; - mem = skytrimem; + mod->skytrimem = Z_Malloc(sizeof(*mod->skytrimem)); + mod->skytrimem->next = mem; + mod->skytrimem->count = 0; + mem = mod->skytrimem; } st = &mem->tris[mem->count]; @@ -3793,7 +3867,7 @@ static void R_Part_SkyTri(float *v1, float *v2, float *v3, msurface_t *surf, int dot = DotProduct(xd, yd); theta = acos(dot/(xm*ym)); st->area = sin(theta)*xm*ym; - st->nexttime = particletime; + st->nexttime = mod->skytime; st->face = surf; st->ptype = ptype; @@ -3801,8 +3875,8 @@ static void R_Part_SkyTri(float *v1, float *v2, float *v3, msurface_t *surf, int return;//bummer. mem->count++; - st->next = skytris; - skytris = st; + st->next = mod->skytris; + mod->skytris = st; } @@ -3846,7 +3920,7 @@ void PScript_EmitSkyEffectTris(qmodel_t *mod, msurface_t *fa, int ptype) v2 = 1; for (v3 = 2; v3 < numverts; v3++) { - R_Part_SkyTri(verts[v1], verts[v2], verts[v3], fa, ptype); + R_Part_SkyTri(mod, verts[v1], verts[v2], verts[v3], fa, ptype); v2 = v3; } @@ -3866,7 +3940,7 @@ static void P_CleanTrailstate(trailstate_t *ts) memset(ts, 0, sizeof(trailstate_t)); } -static void PScript_DelinkTrailstate(trailstate_t **tsk) +void PScript_DelinkTrailstate(trailstate_t **tsk) { trailstate_t *ts; trailstate_t *assoc; @@ -5335,8 +5409,17 @@ int PScript_RunParticleEffectState (vec3_t org, vec3_t dir, float count, int typ // maintain run list if (!(ptype->state & PS_INRUNLIST) && (ptype->particles || ptype->clippeddecals)) { - ptype->nexttorun = part_run_list; - part_run_list = ptype; + if (part_run_list) + { + //insert after, to try to avoid edge-case weirdness + ptype->nexttorun = part_run_list->nexttorun; + part_run_list->nexttorun = ptype; + } + else + { + ptype->nexttorun = part_run_list; + part_run_list = ptype; + } ptype->state |= PS_INRUNLIST; } @@ -6220,7 +6303,6 @@ int PScript_ParticleTrail (vec3_t startpos, vec3_t end, int type, int dlkey, vec } static vec3_t pright, pup; -static float pframetime; static void R_AddFanSparkParticle(scenetris_t *t, particle_t *p, plooks_t *type) { @@ -6761,7 +6843,7 @@ static void R_AddTexturedParticle(scenetris_t *t, particle_t *p, plooks_t *type) t->numidx += 6; } -static void PScript_DrawParticleTypes (void) +static void PScript_DrawParticleTypes (float pframetime) { #if UNSUPPORTED float viewtranslation[16]; @@ -6788,7 +6870,6 @@ static void PScript_DrawParticleTypes (void) int traces=r_particle_tracelimit.value; int rampind; - static float oldtime; static float flurrytime; qboolean doflurry; int batchflags; @@ -6821,11 +6902,6 @@ static void PScript_DrawParticleTypes (void) PScript_RecalculateSkyTris(); } - pframetime = cl.time - oldtime; - if (pframetime < 0) - pframetime = 0; - oldtime = cl.time; - VectorScale (vup, 1.5, pup); VectorScale (vright, 1.5, pright); @@ -7516,7 +7592,7 @@ static void PScript_DrawParticleTypes (void) { VectorAdd(stop, oldorg, stop); VectorScale(stop, 0.5, stop); -#ifdef UNSUPPORTED +#if UNSUPPORTED RQ_AddDistReorder(bdraw, b, type->slooks, stop); #endif } @@ -7548,8 +7624,10 @@ endtype: { if (!lastvalidtype) part_run_list = type->nexttorun; - else + else if (lastvalidtype->nexttorun == type) lastvalidtype->nexttorun = type->nexttorun; + else + lastvalidtype->nexttorun->nexttorun = type->nexttorun; type->state &= ~PS_INRUNLIST; } else @@ -7641,6 +7719,7 @@ endtype: glDisable(GL_BLEND); glShadeModel(GL_FLAT); glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_PolygonOffset (OFFSET_NONE); cl_numstris = 0; @@ -7655,9 +7734,38 @@ R_DrawParticles */ void PScript_DrawParticles (void) { - P_AddRainParticles(); + int i; + entity_t *ent; + vec3_t axis[3]; + float pframetime; + static float oldtime; + + pframetime = cl.time - oldtime; + if (pframetime < 0) + pframetime = 0; + if (pframetime > 1) + pframetime = 1; + oldtime = cl.time; - PScript_DrawParticleTypes(); + if (r_part_rain.value) + { + for (i = 0; i < cl.num_entities; i++) + { + ent = &cl_entities[i]; + if (!ent->model || ent->model->needload) + continue; + if (!ent->model->skytris) + continue; + AngleVectors(ent->angles, axis[0], axis[1], axis[2]); + //this timer, as well as the per-tri timer, are unable to deal with certain rates+sizes. it would be good to fix that... + //it would also be nice to do mdls too... + P_AddRainParticles(ent->model, axis, ent->origin, ((i==0)?r_visframecount:0), pframetime); + } + + //FIXME: static entities too! + } + + PScript_DrawParticleTypes(pframetime); // if (fallback) // fallback->DrawParticles(); diff --git a/quakespasm/Quake/server.h b/quakespasm/Quake/server.h index 7aacd37d..2e33086d 100644 --- a/quakespasm/Quake/server.h +++ b/quakespasm/Quake/server.h @@ -80,6 +80,10 @@ typedef struct byte multicast_buf[MAX_DATAGRAM]; const char *particle_precache[MAX_PARTICLETYPES]; // NULL terminated + + entity_state_t *static_entities; + int num_statics; + int max_statics; } server_t; diff --git a/quakespasm/Quake/sv_main.c b/quakespasm/Quake/sv_main.c index 256c4aa1..c0bbe87a 100644 --- a/quakespasm/Quake/sv_main.c +++ b/quakespasm/Quake/sv_main.c @@ -148,7 +148,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to bits |= UF_PREDINFO|UF_MOVETYPE; /* if (from->weaponframe != to->weaponframe) bits |= UF_PREDINFO|UF_WEAPONFRAME_OLD; -*/ if (to->pmovetype) +*/// if (to->pmovetype) //we don't support prediction, but we still need to network the player's velocity for bob etc. { if (SVFTE_DeltaPredCalcBits(from, to)) bits |= UF_PREDINFO; @@ -224,7 +224,7 @@ static unsigned int SVFTE_DeltaCalcBits(entity_state_t *from, entity_state_t *to // if (to->light[0] != from->light[0] || to->light[1] != from->light[1] || to->light[2] != from->light[2] || to->light[3] != from->light[3] || to->lightstyle != from->lightstyle || to->lightpflags != from->lightpflags) // bits |= UF_LIGHT; - if (to->traileffectnum != from->traileffectnum) + if (to->traileffectnum != from->traileffectnum || to->emiteffectnum != from->emiteffectnum) bits |= UF_TRAILEFFECT; // if (to->modelindex2 != from->modelindex2) @@ -493,7 +493,15 @@ static void SVFTE_WriteEntityUpdate(unsigned int bits, entity_state_t *state, si MSG_WriteByte (msg, state->lightpflags); } */ if (bits & UF_TRAILEFFECT) - MSG_WriteShort(msg, state->traileffectnum); + { + if (state->emiteffectnum) + { //3 spare bits. so that's nice (this is guarenteed to be 14 bits max due to precaches using the upper two bits). + MSG_WriteShort(msg, (state->traileffectnum&0x3fff)|0x8000); + MSG_WriteShort(msg, state->emiteffectnum&0x3fff); + } + else + MSG_WriteShort(msg, state->traileffectnum&0x3fff); + } /* if (bits & UF_COLORMOD) { @@ -879,6 +887,7 @@ void SVFTE_BuildSnapshotForClient (client_t *client) struct entity_num_state_s *ents = snapshot_entstate; size_t numents = 0; size_t maxents = snapshot_maxents; + int emiteffect; // find the client's PVS VectorAdd (clent->v.origin, clent->v.view_ofs, org); @@ -892,10 +901,11 @@ void SVFTE_BuildSnapshotForClient (client_t *client) for (e=1 ; e_float; if (ent != clent) // clent is ALLWAYS sent { // ignore ents without visible models - if (!ent->v.modelindex || !PR_GetString(ent->v.model)[0]) + if ((!ent->v.modelindex || !PR_GetString(ent->v.model)[0]) && !emiteffect) continue; //johnfitz -- don't send model>255 entities if protocol is 15 @@ -907,7 +917,7 @@ void SVFTE_BuildSnapshotForClient (client_t *client) eflags |= EFLAGS_VIEWMODEL; else if (val && val->edict) continue; - else + else if (ent->num_leafs) { // ignore if not touching a PV leaf for (i=0 ; i < ent->num_leafs ; i++) @@ -958,6 +968,7 @@ void SVFTE_BuildSnapshotForClient (client_t *client) ents[numents].state.traileffectnum = val->_float; else ents[numents].state.traileffectnum = 0; + ents[numents].state.emiteffectnum = emiteffect; ents[numents].state.effects = ent->v.effects; if (!ent->v.movetype || ent->v.movetype == MOVETYPE_STEP) eflags |= EFLAGS_STEP; @@ -1090,6 +1101,10 @@ void SV_Init (void) Cvar_RegisterVariable (&pr_checkextension); Cvar_RegisterVariable (&sv_altnoclip); //johnfitz + if (isDedicated) + sv_public.string = "1"; + else + sv_public.string = "0"; Cvar_RegisterVariable (&sv_public); Cvar_RegisterVariable (&sv_reportheartbeats); Cvar_RegisterVariable (&com_protocolname); @@ -2242,7 +2257,7 @@ qboolean SV_SendClientDatagram (client_t *client) // send the datagram if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) { - SV_DropClient (true);// if the message couldn't send, kick off + SV_DropClient (false);// if the message couldn't send, kick off return false; } @@ -2308,7 +2323,7 @@ void SV_SendNop (client_t *client) MSG_WriteChar (&msg, svc_nop); if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) - SV_DropClient (true); // if the message couldn't send, kick off + SV_DropClient (false); // if the message couldn't send, kick off client->last_message = realtime; } @@ -2332,6 +2347,85 @@ int SV_SendPrespawnParticlePrecaches(int idx) return -1; return idx; } +int SV_SendPrespawnStatics(int idx) +{ + int i; + entity_state_t *svent; + int maxsize = host_client->message.maxsize - 128; //we can go quite large + + while (1) + { + if (idx >= sv.num_statics) + return -1; + svent = &sv.static_entities[idx]; + + if (host_client->message.cursize > maxsize) + break; + idx++; + + if (svent->modelindex >= host_client->limit_models) + continue; + if (memcmp(&nullentitystate, svent, sizeof(nullentitystate))) + { + if (host_client->protocol_pext2 & PEXT2_REPLACEMENTDELTAS) + { + MSG_WriteByte(&host_client->message, svcfte_spawnstatic2); + SVFTE_WriteEntityUpdate(SVFTE_DeltaCalcBits(&nullentitystate, svent), svent, &host_client->message, host_client->protocol_pext2); + } + else + { + //johnfitz -- PROTOCOL_FITZQUAKE + int bits = 0; + if (sv.protocol == PROTOCOL_FITZQUAKE) //still want to send baseline in PROTOCOL_NETQUAKE, so reset these values + { + if (svent->modelindex & 0xFF00) + bits |= B_LARGEMODEL; + if (svent->frame & 0xFF00) + bits |= B_LARGEFRAME; + if (svent->alpha != ENTALPHA_DEFAULT) + bits |= B_ALPHA; + } + else if (svent->frame > 0xff) + continue; //can't send these with the vanilla protcol (yay pext). + + if (bits) + MSG_WriteByte (&host_client->message, svc_spawnstatic2); + else + MSG_WriteByte (&host_client->message, svc_spawnstatic); + //johnfitz + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits) + MSG_WriteByte (&host_client->message, bits); + + if (bits & B_LARGEMODEL) + MSG_WriteShort (&host_client->message, svent->modelindex); + else + MSG_WriteByte (&host_client->message, svent->modelindex); + + if (bits & B_LARGEFRAME) + MSG_WriteShort (&host_client->message, svent->frame); + else + MSG_WriteByte (&host_client->message, svent->frame); + //johnfitz + + MSG_WriteByte (&host_client->message, svent->colormap); + MSG_WriteByte (&host_client->message, svent->skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&host_client->message, svent->origin[i], sv.protocolflags); + MSG_WriteAngle(&host_client->message, svent->angles[i], sv.protocolflags); + } + + //johnfitz -- PROTOCOL_FITZQUAKE + if (bits & B_ALPHA) + MSG_WriteByte (&host_client->message, svent->alpha); + //johnfitz + } + } + } + return idx; +} int SV_SendPrespawnBaselines(int idx) { int i; @@ -2466,6 +2560,15 @@ void SV_SendClientMessages (void) } } if (host_client->sendsignon == 4) + { + host_client->signonidx = SV_SendPrespawnStatics(host_client->signonidx); + if (host_client->signonidx < 0) + { + host_client->signonidx = 0; + host_client->sendsignon++; + } + } + if (host_client->sendsignon == 5) { if (host_client->message.cursize+sv.signon.cursize+2 < host_client->message.maxsize) { @@ -2482,8 +2585,8 @@ void SV_SendClientMessages (void) // changes level if (host_client->message.overflowed) { - SV_DropClient (true); - host_client->message.overflowed = false; + SZ_Clear(&host_client->message); + SV_DropClient (false); continue; } @@ -2501,7 +2604,7 @@ void SV_SendClientMessages (void) { if (NET_SendMessage (host_client->netconnection , &host_client->message) == -1) - SV_DropClient (true); // if the message couldn't send, kick off + SV_DropClient (false); // if the message couldn't send, kick off SZ_Clear (&host_client->message); host_client->last_message = realtime; if (host_client->sendsignon == true) @@ -2720,6 +2823,9 @@ void SV_SpawnServer (const char *server) sv.max_edicts = CLAMP (MIN_EDICTS,(int)max_edicts.value,MAX_EDICTS); //johnfitz -- max_edicts cvar sv.edicts = (edict_t *) malloc (sv.max_edicts*pr_edict_size); // ericw -- sv.edicts switched to use malloc() + sv.max_statics = MAX_STATIC_ENTITIES; + sv.static_entities = Hunk_Alloc(sv.max_statics * sizeof(*sv.static_entities)); + sv.datagram.maxsize = sizeof(sv.datagram_buf); sv.datagram.cursize = 0; sv.datagram.data = sv.datagram_buf; diff --git a/weather.cfg b/weather.cfg new file mode 100755 index 00000000..6793d94a --- /dev/null +++ b/weather.cfg @@ -0,0 +1,116 @@ +//lame example weather particles by Spike +//move to id1/particles/weather.cfg +// +//to use from qc, r_particledesc "weather classic" or call particleeffecnum("weather.te_rain") so the engine knows which config to use, then use the particle[rain|snow] builtins as normal. +//without qc changes option 1) use a texture called skyrain or skysnow, in addition to the r_particledesc thing so that this config is actually used (this is more for people to add stuff to existing maps). +//without qc changes option 2) add a worldspawn field called "_texpart_TEXTURENAME" with value "weather.tex_skysnow" or "weather.tex_skyrain" +//without qc changes option 3) an equivelent console command: r_partredirect tex_TEXTURENAME "weather.tex_skysnow" +//note that without qc, you need to restart the map for it to take effect. +//on the other hand, if you wanted to emit particles from models, use r_effect (which can optionally hide those models too). +//to override trails defined by model flags, you can use the r_trail command. +//weather effects that leave decals are probably overkill +//one option is to spawn a particle from qc that emits other particles that leave trails. emitting such trail emitting emitters from surfaces is definitely overkill. + +//generic rain for the qc builtin +//create another called te_rain_12 or whatever for alternative versions of rain (going by the specified palette) +r_part te_rain +{ + texture ball + scalefactor 1 + count 1 + alpha 0.4 + rgb 255 255 255 + die 2 + veladd 2 + scale 2 + stretchfactor -40 + type texturedspark + cliptype weather.rainsplash + clipbounce 100 + clipcount 5 +} + +//internal splash effect for rain +r_part weather.rainsplash +{ + randomvel 50 50 + count 1 + texture ball + scalefactor 1 + alpha 0.1 + rgb 255 255 255 + die 0.4 + scale 50 + stretchfactor -2.5 + veladd 1 + scale 1 + type texturedspark + gravity 800 +} + +//generic snow for the qc builtin +//naming itself causes it to bounce +r_part te_snow +{ + texture ball + scalefactor 1 + count 1 + alpha 1 + rgb 255 255 255 + die 2 + veladd 1 + scale 5 + flurry 40 + gravity 400 + friction 5 + + //settle + clipbounce 0 +} + +//rain effect to be emitted from textures +//the base direction points away from the surface, so veladd is the speed to move away from said surface. +//this isn't very useful for rain, because that vector is quite often horizontal (where the sky surrounds the player) +//that said, sitting in a box of such rain surfaces gives an interesting laser-field effect... +//anyway, that's why we can't reuse the qc effects, because qc gives a velocity that is actually meant to be usable. +r_part tex_skyrain +{ + texture ball + scalefactor 1 + rainfrequency 10 + count 1 + alpha 0.1 + rgb 255 255 255 + die 2 + veladd 0 + velbias -200 -200 -2000 //move sideways slightly in the same direction as the sky + scale 1 + stretchfactor -40 + type texturedspark + cliptype weather.rainsplash + clipbounce 100 + clipcount 5 +} + +//snow from sky surfaces is often within a box +//this means we don't want the snow to ever settle. +//we also have no volume, so make the snow fall a little further. +r_part tex_skysnow +{ + texture ball + scalefactor 1 + rainfrequency 2 + count 1 + alpha 1 + rgb 255 255 255 + die 8 + veladd 0 + velbias 0 0 -100 + scale 5 + flurry 40 + gravity 400 + friction 5 + + cliptype tex_skysnow + clipbounce 0 +}