From: Rudolf Polzer Date: Thu, 22 Apr 2010 18:35:20 +0000 (+0200) Subject: Merge commit 'origin/tzork/pathlib' into divVerent/bastet X-Git-Tag: xonotic-v0.1.0preview~612^2~20^2~2 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=754318827b2a4ada55012a89b62c0251850b689a;hp=54e0ccd220df67e999e1987086a0e2d8bc0ad10d Merge commit 'origin/tzork/pathlib' into divVerent/bastet --- diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..fb9e9b14c2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,179 @@ +*.7z -crlf -diff +*.aft crlf=input +*.aliases crlf=input +all crlf=input +*.animinfo crlf=input +*.aps -crlf -diff +*.ase -crlf +*.bat -crlf +*.bgs crlf=input +*.blend -crlf -diff +*.bmp -crlf -diff +branch-manager crlf=input +BSDmakefile crlf=input +bsp2ent crlf=input +*.bsp -crlf -diff +*.cache -crlf -diff +*.cbp -crlf +*.cbp -crlf -diff +*.c crlf=input +*.cfg crlf=input +*.cg crlf=input +ChangeLog crlf=input +CHANGES crlf=input +COMPILING crlf=input +*.conf crlf=input +CONTRIBUTORS crlf=input +COPYING crlf=input +*.cpp crlf=input +*.css crlf=input +Current -crlf -diff +*.cvsignore crlf=input +*.cvswrappers crlf=input +*.db -crlf -diff +*.default crlf=input +*.def crlf=input +*.dem -crlf -diff +*.dev -crlf +*.dll -crlf -diff +DOCS -crlf -diff +*.dot crlf=input +DoxyConfig crlf=input +Doxyfile crlf=input +*.doxygen crlf=input +*.dpm -crlf -diff +*.dsp -crlf +*.dsw -crlf +*.dtd crlf=input +*.dylib -crlf -diff +*.EncoderPlugin crlf=input +*.ent -crlf +*.form crlf=input +*.framegroups crlf=input +*.game crlf=input +gendox crlf=input +gendoxfunctions crlf=input +genDoxyfile crlf=input +*.gif -crlf -diff +*.gitattributes crlf=input +git-branch-manager crlf=input +git-filter-index crlf=input +git-filter-repository crlf=input +*.gitignore crlf=input +git-pullall crlf=input +git-split-repository crlf=input +git-svn-checkout crlf=input +git-svn-update crlf=input +git-update-octopus crlf=input +*.glp crlf=input +*.glsl crlf=input +GPL crlf=input +*.hardwired crlf=input +*.h crlf=input +*.hs crlf=input +*.html crlf=input +*.html-part crlf=input +*.icns -crlf -diff +*.ico -crlf -diff +*.idsoftware crlf=input +*.inc crlf=input +*.instantaction crlf=input +*.java crlf=input +*.jhm crlf=input +*.jnlp crlf=input +*.jpg -crlf -diff +*.jsmooth crlf=input +LGPL crlf=input +LICENSE crlf=input +*.lmp -crlf -diff +*.loaders crlf=input +*.lso -crlf -diff +makefile crlf=input +Makefile crlf=input +*.makespr32 crlf=input +makespr32 crlf=input +*.map -crlf +*.mapinfo crlf=input +*.m crlf=input +*.md3 -crlf -diff +*.md5anim -crlf +*.md5mesh -crlf +*.mdl -crlf -diff +*.med crlf=input +*.mf crlf=input +*.mid -crlf -diff +*.mk crlf=input +*.mmpz -crlf -diff +*.modinfo crlf=input +*.modules crlf=input +nexuiz-map-compiler crlf=input +nexuiz-osx-agl crlf=input +nexuiz-osx-sdl crlf=input +*.nib -crlf +*.obj -crlf +OFFSETS -crlf -diff +*.ogg -crlf -diff +*.options crlf=input +pangorc crlf=input +*.patch crlf=input +*.patchsets crlf=input +*.pcx -crlf -diff +*.pk3 -crlf -diff +PkgInfo crlf=input +*.pl crlf=input +*.plist crlf=input +*.pm crlf=input +*.png -crlf -diff +POSITIONS -crlf -diff +*.proj -crlf +*.properties crlf=input +*.psd -crlf -diff +*.py crlf=input +*.q3map1 crlf=input +*.qc crlf=input +*.qdt crlf=input +*.qh crlf=input +*.rb crlf=input +*.rc2 crlf=input +*.rc -crlf +*.readme crlf=input +README crlf=input +*.rtlights -crlf -diff +SCHEMA crlf=input +*.scm crlf=input +SDL -crlf -diff +SDLMain.m crlf=input +*.shader crlf=input +*.sh crlf=input +*.skin crlf=input +*.sln -crlf +*.sounds crlf=input +*.sp2 -crlf -diff +*.spr32 -crlf -diff +*.spr -crlf -diff +*.src crlf=input +*.strings crlf=input +*.strip crlf=input +strip crlf=input +*.svg -crlf -diff +*.TAB -crlf -diff +*.tga -crlf -diff +TMAP -crlf -diff +todo crlf=input +TODO crlf=input +*.ttf -crlf -diff +*.TTF -crlf -diff +*.txt crlf=input +*.TXT crlf=input +*.vcproj -crlf +*.wav -crlf -diff +*.waypoints -crlf -diff +*.width crlf=input +*.workspace -crlf +*.xcf -crlf -diff +*.xlink crlf=input +*.xml crlf=input +*.xpm crlf=input +*.zip -crlf -diff +zipdiff crlf=input +*.zym -crlf -diff diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..c3e14d318e --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +csprogs.dat +menu.dat +progs.dat +qcsrc/client/fteqcc.log +qcsrc/menu/fteqcc.log +qcsrc/server/fteqcc.log diff --git a/balance25.cfg b/balance25.cfg index c13ec4487c..11cc3a40ba 100644 --- a/balance25.cfg +++ b/balance25.cfg @@ -3,6 +3,7 @@ // use g_start_weapon_* to also replace the on-startup weapons! // example: g_weaponreplace_nex "nex minstanex", then Nexes become MinstaNexes 50% of the times // set the cvars to "0" to totally disable a weapon +set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping uzi and shotgun" set g_weaponreplace_laser "" set g_weaponreplace_shotgun "" set g_weaponreplace_uzi "" diff --git a/common-spog.pk3 b/common-spog.pk3 deleted file mode 100644 index 3696bbb3a9..0000000000 Binary files a/common-spog.pk3 and /dev/null differ diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg index 9b2d45be7f..0c44f8ef8a 100644 --- a/defaultXonotic.cfg +++ b/defaultXonotic.cfg @@ -319,7 +319,7 @@ set sv_fragmessage_information_typefrag 1 "Enable typefrag display information, // use default physics set sv_friction_on_land 0 -exec physics26.cfg +exec physicsNoQWBunny.cfg set sv_player_viewoffset "0 0 35" "view offset of the player model" set sv_player_mins "-16 -16 -24" "playermodel mins" @@ -516,10 +516,10 @@ set g_dodging 0 "set to 1 to enable dodging in games" seta cl_dodging_timeout 0.2 "determines how long apart (in seconds) two taps on the same direction key are considered a dodge. use 0 to disable" -set sv_dodging_wall_dodging 1 "set to 1 to allow dodging off walls. 0 to disable" +set sv_dodging_wall_dodging 0 "set to 1 to allow dodging off walls. 0 to disable" set sv_dodging_delay 0.5 "determines how long a player has to wait to be able to dodge again after dodging" set sv_dodging_up_speed 200 "the jump velocity of the dodge" -set sv_dodging_horiz_speed 350 "the horizontal velocity of the dodge" +set sv_dodging_horiz_speed 400 "the horizontal velocity of the dodge" set sv_dodging_ramp_time 0.1 "a ramp so that the horizontal part of the dodge is added smoothly (seconds)" set sv_dodging_height_threshold 10 "the maximum height above ground where to allow dodging" set sv_dodging_wall_distance_threshold 10 "the maximum distance from a wall that still allows dodging" @@ -1160,8 +1160,6 @@ set g_chat_flood_lmax_tell 2 "private chat: maximum number of lines per chat mes set g_chat_flood_burst_tell 2 "private chat: allow bursts of so many chat lines" set g_chat_flood_notify_flooder 1 "when 0, the flooder still can see his own message" set g_chat_teamcolors 0 "colorize nicknames in team color for chat" -set g_voice_flood_spv 4 "normal voices: seconds between voices to not count as flooding" -set g_voice_flood_spv_team 2 "team voices: seconds between voices to not count as flooding" set g_nick_flood_timeout 120 "time after which nick flood protection resets (set to 0 to disable nick flood checking)" set g_nick_flood_penalty 0.5 "duration of the nick flood penalty" set g_nick_flood_penalty_yellow 3 "number of changes to allow before warning and movement blocking" @@ -1479,6 +1477,7 @@ seta cl_weaponpriority6 "" "use impulse 206 for prev gun from this list, 216 for seta cl_weaponpriority7 "" "use impulse 207 for prev gun from this list, 217 for best gun, 227 for next gun" seta cl_weaponpriority8 "" "use impulse 208 for prev gun from this list, 218 for best gun, 228 for next gun" seta cl_weaponpriority9 "" "use impulse 209 for prev gun from this list, 219 for best gun, 229 for next gun" +seta cl_weaponimpulsemode 0 "0: only cycle between currently usable weapons in weapon priority order; 1: cycle between all possible weapons on a key in weapon priority order" seta sv_status_privacy 1 "hide IP addresses from \"status\" replies shown to clients" @@ -1789,3 +1788,13 @@ seta _cl_userid "" "player ID (e.g. for tournaments)" // FIXME workaround for engine bug sv_gameplayfix_nudgeoutofsolid 0 // to div0: remove this once 5b7ac1706712977bbc0297d2d53294e73574c7cd (svn r9537) is in the stable branch of the engine again + +// otherwise, antilag breaks +sv_gameplayfix_consistentplayerprethink 1 + +// support Q1BSP maps +mod_q1bsp_polygoncollisions 1 + +// improve some minor details +sv_gameplayfix_gravityunaffectedbyticrate 1 +sv_gameplayfix_nogravityonground 1 diff --git a/effectinfo.txt b/effectinfo.txt index 8ab688d8f4..2885afb563 100644 --- a/effectinfo.txt +++ b/effectinfo.txt @@ -1348,8 +1348,8 @@ airfriction 12 // electro trail // glowing vapor trail -// used in qcsrc/client/projectile.qc: trailparticles(self, particleeffectnum("TR_XONOTICPLASMA"), from, to) -effect TR_XONOTICPLASMA +// used in qcsrc/client/projectile.qc: trailparticles(self, particleeffectnum("TR_NEXUIZPLASMA"), from, to) +effect TR_NEXUIZPLASMA trailspacing 1 type static color 0x283880 0x283880 @@ -1362,7 +1362,7 @@ lighttime 0 lightcolor 1.5 3 6 velocitymultiplier -0.1 // bright sparks -effect TR_XONOTICPLASMA +effect TR_NEXUIZPLASMA trailspacing 6 count 3 type snow diff --git a/font-dejavu.pk3dir/font-dejavu.cfg b/font-dejavu.pk3dir/font-dejavu.cfg deleted file mode 100644 index 4b3200f21d..0000000000 --- a/font-dejavu.pk3dir/font-dejavu.cfg +++ /dev/null @@ -1,13 +0,0 @@ -// must be loaded AFTER config.cfg -utf8_enable 1 -r_font_disable_freetype 0 -r_font_size_snapping 2 -loadfont console fonts/DejaVuSansMono,gfx/conchars $con_textsize -loadfont notify fonts/DejaVuSans-Bold,gfx/vera-sans $con_notifysize -loadfont chat fonts/DejaVuSans-Bold,gfx/vera-sans $con_chatsize -loadfont centerprint fonts/DejaVuSansMono,gfx/conchars 9 -loadfont infobar fonts/DejaVuSansMono,gfx/conchars 8 -loadfont user0 fonts/DejaVuSans-Bold,gfx/vera-sans 9.6 12 12.8 16 -loadfont user1 fonts/DejaVuSans-Bold,gfx/vera-sans 8 10 14 $sbar_fontsize $scr_centersize // csqc font -loadfont user2 fonts/DejaVuSans-Bold,gfx/vera-sans 16 24 32 // csqc bigfont -sbar_columns_set diff --git a/font-dejavu.pk3dir/fonts/DejaVuSans-Bold.ttf b/font-dejavu.pk3dir/fonts/DejaVuSans-Bold.ttf deleted file mode 100644 index b8f6c3efec..0000000000 Binary files a/font-dejavu.pk3dir/fonts/DejaVuSans-Bold.ttf and /dev/null differ diff --git a/font-dejavu.pk3dir/fonts/DejaVuSansMono.ttf b/font-dejavu.pk3dir/fonts/DejaVuSansMono.ttf deleted file mode 100644 index af80fb7973..0000000000 Binary files a/font-dejavu.pk3dir/fonts/DejaVuSansMono.ttf and /dev/null differ diff --git a/models/monsters/zombie.dpm.framegroups b/models/monsters/zombie.dpm.framegroups index 4bd49bd370..3d56cdb2f4 100644 --- a/models/monsters/zombie.dpm.framegroups +++ b/models/monsters/zombie.dpm.framegroups @@ -1,31 +1,31 @@ -1 56 30 0 // zombie attackleap 1 -57 41 60 1 // zombie attackrun1 2 -98 41 60 1 // zombie attackrun2 3 -139 41 60 1 // zombie attackrun3 4 -180 41 30 1 // zombie attackstanding1 5 -221 35 30 1 // zombie attackstanding2 6 -256 41 30 1 // zombie attackstanding3 7 -297 21 60 1 // zombie blockend 8 -318 21 60 0 // zombie blockstart 9 -339 96 30 0 // zombie deathback1 10 -435 67 30 0 // zombie deathback2 11 -502 71 30 0 // zombie deathback3 12 -573 61 30 0 // zombie deathfront1 13 -634 66 30 0 // zombie deathfront2 14 -700 96 30 0 // zombie deathfront3 15 -796 96 30 0 // zombie deathleft1 16 -892 71 30 0 // zombie deathleft2 17 -963 66 30 0 // zombie deathright1 18 -1029 86 30 0 // zombie deathright2 19 -1115 121 10 1 // zombie idle 20 -1236 11 30 0 // zombie painback1 21 -1247 11 30 0 // zombie painback2 22 -1258 11 30 0 // zombie painfront1 23 -1269 11 30 0 // zombie painfront2 24 -1280 41 60 1 // zombie runbackwards 25 -1321 41 60 1 // zombie runbackwardsleft 26 -1362 41 60 1 // zombie runbackwardsright 27 -1403 41 60 1 // zombie runforward 28 -1444 41 60 1 // zombie runforwardleft 29 -1485 41 60 1 // zombie runforwardright 30 -1526 61 30 0 // zombie spawn 31 +1 56 30 0 // zombie attackleap 1 +57 41 60 1 // zombie attackrun1 2 +98 41 60 1 // zombie attackrun2 3 +139 41 60 1 // zombie attackrun3 4 +180 41 30 1 // zombie attackstanding1 5 +221 35 30 1 // zombie attackstanding2 6 +256 41 30 1 // zombie attackstanding3 7 +297 21 60 1 // zombie blockend 8 +318 21 60 0 // zombie blockstart 9 +339 96 30 0 // zombie deathback1 10 +435 67 30 0 // zombie deathback2 11 +502 71 30 0 // zombie deathback3 12 +573 61 30 0 // zombie deathfront1 13 +634 66 30 0 // zombie deathfront2 14 +700 96 30 0 // zombie deathfront3 15 +796 96 30 0 // zombie deathleft1 16 +892 71 30 0 // zombie deathleft2 17 +963 66 30 0 // zombie deathright1 18 +1029 86 30 0 // zombie deathright2 19 +1115 121 10 1 // zombie idle 20 +1236 11 30 0 // zombie painback1 21 +1247 11 30 0 // zombie painback2 22 +1258 11 30 0 // zombie painfront1 23 +1269 11 30 0 // zombie painfront2 24 +1280 41 60 1 // zombie runbackwards 25 +1321 41 60 1 // zombie runbackwardsleft 26 +1362 41 60 1 // zombie runbackwardsright 27 +1403 41 60 1 // zombie runforward 28 +1444 41 60 1 // zombie runforwardleft 29 +1485 41 60 1 // zombie runforwardright 30 +1526 61 30 0 // zombie spawn 31 diff --git a/models/turrets/walker_body.md3.framegroups b/models/turrets/walker_body.md3.framegroups index 590155efb1..050d79cd8e 100644 --- a/models/turrets/walker_body.md3.framegroups +++ b/models/turrets/walker_body.md3.framegroups @@ -1,12 +1,12 @@ -1 1 1 0 // ANIM_NO -35 55 20 1 // ANIM_TURN -5 25 20 1 // ANIM_WALK -5 25 40 1 // ANIM_RUN -35 55 20 1 // ANIM_STRAFE_L -65 85 20 1 // ANIM_STRAFE_R -95 100 20 0 // ANIM_JUMP -100 107 20 0 // ANIM_LAND -90 95 20 0 // ANIM_PAIN -123 140 40 0 // ANIM_MEELE -146 151 20 1 // ANIM_SWIM -5 25 20 1 // ANIM_ROAM +1 1 1 0 // ANIM_NO +35 55 20 1 // ANIM_TURN +5 25 20 1 // ANIM_WALK +5 25 40 1 // ANIM_RUN +35 55 20 1 // ANIM_STRAFE_L +65 85 20 1 // ANIM_STRAFE_R +95 100 20 0 // ANIM_JUMP +100 107 20 0 // ANIM_LAND +90 95 20 0 // ANIM_PAIN +123 140 40 0 // ANIM_MEELE +146 151 20 1 // ANIM_SWIM +5 25 20 1 // ANIM_ROAM diff --git a/models/vehicles/raptor.dpm b/models/vehicles/raptor.dpm new file mode 100644 index 0000000000..83518c5c62 Binary files /dev/null and b/models/vehicles/raptor.dpm differ diff --git a/models/vehicles/raptor_bomb.dpm b/models/vehicles/raptor_bomb.dpm new file mode 100644 index 0000000000..7fcc713d75 Binary files /dev/null and b/models/vehicles/raptor_bomb.dpm differ diff --git a/models/vehicles/raptor_cockpit.dpm b/models/vehicles/raptor_cockpit.dpm new file mode 100644 index 0000000000..332b2d7bfc Binary files /dev/null and b/models/vehicles/raptor_cockpit.dpm differ diff --git a/models/vehicles/raptor_gun.dpm b/models/vehicles/raptor_gun.dpm new file mode 100644 index 0000000000..fdc2791782 Binary files /dev/null and b/models/vehicles/raptor_gun.dpm differ diff --git a/models/vehicles/spiderbot.dpm.framegroups b/models/vehicles/spiderbot.dpm.framegroups index 3ea278df30..f9db7221e4 100644 --- a/models/vehicles/spiderbot.dpm.framegroups +++ b/models/vehicles/spiderbot.dpm.framegroups @@ -1,6 +1,6 @@ -1 30 20 1 // forward -32 30 20 1 // backward -63 30 20 1 // left -94 30 20 1 // right -125 30 20 0 // jump -0 1 20 0 // idle +1 30 20 1 // forward +32 30 20 1 // backward +63 30 20 1 // left +94 30 20 1 // right +125 30 20 0 // jump +0 1 20 0 // idle diff --git a/monster_zombie.cfg b/monster_zombie.cfg index 89eba2b28d..65d9e71a3f 100644 --- a/monster_zombie.cfg +++ b/monster_zombie.cfg @@ -1,21 +1,21 @@ -set g_monster_zombie_respawntime 2 -set g_monster_zombie_movespeed 350 -set g_monster_zombie_health 275 -set g_monster_zombie_stopspeed 90 -set g_monster_zombie_turnspeed 360 -set g_monster_zombie_idle_timer_min 5 -set g_monster_zombie_idle_timer_max 10 -set g_monster_zombie_targetrange 2048 - -set g_monster_zombie_attack_run_range 128 -set g_monster_zombie_attack_run_hitrange 96 -set g_monster_zombie_attack_run_delay 0.35 -set g_monster_zombie_attack_run_damage 30 -set g_monster_zombie_attack_run_force 300 - -set g_monster_zombie_attack_stand_range 64 -set g_monster_zombie_attack_stand_hitrange 64 -set g_monster_zombie_attack_stand_delay 0.25 -set g_monster_zombie_attack_stand_damage 60 -set g_monster_zombie_attack_stand_force 250 - +set g_monster_zombie_respawntime 2 +set g_monster_zombie_movespeed 350 +set g_monster_zombie_health 275 +set g_monster_zombie_stopspeed 90 +set g_monster_zombie_turnspeed 360 +set g_monster_zombie_idle_timer_min 5 +set g_monster_zombie_idle_timer_max 10 +set g_monster_zombie_targetrange 2048 + +set g_monster_zombie_attack_run_range 128 +set g_monster_zombie_attack_run_hitrange 96 +set g_monster_zombie_attack_run_delay 0.35 +set g_monster_zombie_attack_run_damage 30 +set g_monster_zombie_attack_run_force 300 + +set g_monster_zombie_attack_stand_range 64 +set g_monster_zombie_attack_stand_hitrange 64 +set g_monster_zombie_attack_stand_delay 0.25 +set g_monster_zombie_attack_stand_damage 60 +set g_monster_zombie_attack_stand_force 250 + diff --git a/physicsSamual.cfg b/physicsSamual.cfg index f4a184044c..ce1d1d8c1f 100644 --- a/physicsSamual.cfg +++ b/physicsSamual.cfg @@ -1,27 +1,27 @@ -sv_gravity 880 -sv_maxspeed 420 -sv_maxairspeed 235 -sv_stopspeed 200 -sv_accelerate 6 -sv_airaccelerate 6 -sv_friction 4 -edgefriction 0 -sv_stepheight 34 -sv_jumpvelocity 330 -sv_wateraccelerate -1 -sv_waterfriction -1 -sv_airaccel_sideways_friction 0.3 -sv_airaccel_qw 0.93 -sv_airstopaccelerate 0 -sv_airstrafeaccelerate 0 -sv_maxairstrafespeed 0 -sv_aircontrol 0 -sv_warsowbunny_turnaccel 0 -sv_warsowbunny_accel 0.1593 -sv_warsowbunny_topspeed 925 -sv_warsowbunny_backtosideratio 0.8 -sv_friction_on_land 0 -sv_doublejump 0 +sv_gravity 880 +sv_maxspeed 420 +sv_maxairspeed 235 +sv_stopspeed 200 +sv_accelerate 6 +sv_airaccelerate 6 +sv_friction 4 +edgefriction 0 +sv_stepheight 34 +sv_jumpvelocity 330 +sv_wateraccelerate -1 +sv_waterfriction -1 +sv_airaccel_sideways_friction 0.3 +sv_airaccel_qw 0.93 +sv_airstopaccelerate 0 +sv_airstrafeaccelerate 0 +sv_maxairstrafespeed 0 +sv_aircontrol 0 +sv_warsowbunny_turnaccel 0 +sv_warsowbunny_accel 0.1593 +sv_warsowbunny_topspeed 925 +sv_warsowbunny_backtosideratio 0.8 +sv_friction_on_land 0 +sv_doublejump 0 sv_jumpspeedcap_min "" sv_jumpspeedcap_max "" sv_jumpspeedcap_max_disable_on_ramps 0 diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index c42512a1ca..9bb7661430 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -341,6 +341,8 @@ float view_set; float camera_mode; string NextFrameCommand; void CSQC_SPIDER_HUD(); +void CSQC_RAPTOR_HUD(); + void CSQC_UpdateView(float w, float h) { entity e; @@ -596,6 +598,8 @@ void CSQC_UpdateView(float w, float h) } else if(hud == HUD_WAKIZASHI) CSQC_WAKIZASHI_HUD(); + else if(hud == HUD_RAPTOR) + CSQC_RAPTOR_HUD(); else { if(cvar("r_letterbox") == 0) @@ -857,13 +861,13 @@ void Sbar_Draw(); void CSQC_SPIDER_HUD() { - float rockets, reload, heat, hp, shield, i; + float rockets, reload, heat, hp, shield; vector picsize, hudloc; // Fetch health & ammo stats hp = bound(0,getstatf(STAT_VEHICLESTAT_HEALTH), 1); shield = bound(0,getstatf(STAT_VEHICLESTAT_SHIELD), 1); - heat = min(getstatf(STAT_VEHICLESTAT_RELOAD1), 1); + heat = min(getstatf(STAT_VEHICLESTAT_RELOAD1), 2); rockets = getstati(STAT_VEHICLESTAT_AMMO2); reload = min(getstatf(STAT_VEHICLESTAT_RELOAD2), 1); @@ -882,10 +886,8 @@ void CSQC_SPIDER_HUD() picsize = drawgetimagesize(spider_a2) * 0.5; drawpic(hudloc + '120 96 0', spider_a2, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawstring(hudloc + '145 19 0', strcat(ftos(rint(hp * 100)), "%"),'15 15 0','0 1 0', 1, DRAWFLAG_NORMAL); drawstring(hudloc + '175 34 0', strcat(ftos(rint(shield * 100)), "%"),'15 15 0','0 0 1', 1, DRAWFLAG_NORMAL); - drawstring(hudloc + '136 102 0', strcat(ftos(100 - rint(heat * 100)), "%"),'14 14 0','1 1 0', 1, DRAWFLAG_NORMAL); picsize = drawgetimagesize(spider_a1) * 0.85; @@ -964,6 +966,76 @@ void CSQC_SPIDER_HUD() } +#define raptor_h "gfx/vehicles/hud_bg.tga" +#define raptor_b "gfx/vehicles/raptor.tga" +#define raptor_g1 "gfx/vehicles/raptor_guns.tga" +#define raptor_g2 "gfx/vehicles/raptor_bombs.tga" +#define raptor_s "gfx/vehicles/shiled.tga" + +#define spider_a1 "gfx/hud/sb_rocket.tga" +#define spider_a2 "gfx/sb_bullets.tga" + +void CSQC_RAPTOR_HUD() +{ + float rockets, reload, heat, hp, shield, energy; + vector picsize, hudloc; + + // Fetch health & ammo stats + hp = bound(0,getstatf(STAT_VEHICLESTAT_HEALTH), 1); + shield = bound(0,getstatf(STAT_VEHICLESTAT_SHIELD), 1); + reload = min(getstatf(STAT_VEHICLESTAT_RELOAD1), 1); + energy = min(getstatf(STAT_VEHICLESTAT_ENERGY), 1); + + // Draw the crosshairs + picsize = drawgetimagesize(SPIDER_CROSS); + picsize_x *= cvar_or("cl_vehicle_spiderbot_cross_size", 1); + picsize_y *= cvar_or("cl_vehicle_spiderbot_cross_size", 1); + drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), SPIDER_CROSS, picsize, '1 1 1', cvar_or("cl_vehicle_spiderbot_cross_alpha",0.6), DRAWFLAG_NORMAL); + + hudloc_y = 4; + hudloc_x = 4; + + picsize = drawgetimagesize(raptor_h) * 0.5; + drawpic(hudloc, raptor_h, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + + picsize = drawgetimagesize(spider_a2) * 0.5; + drawpic(hudloc + '120 96 0', spider_a2, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + + drawstring(hudloc + '145 19 0', strcat(ftos(rint(hp * 100)), "%"),'15 15 0','0 1 0', 1, DRAWFLAG_NORMAL); + drawstring(hudloc + '175 34 0', strcat(ftos(rint(shield * 100)), "%"),'15 15 0','0 0 1', 1, DRAWFLAG_NORMAL); + drawstring(hudloc + '136 102 0', strcat(ftos(rint(energy * 100)), "%"),'15 15 0','0.5 0.5 1', 1, DRAWFLAG_NORMAL); + + + picsize = drawgetimagesize(spider_a1) * 0.85; + if(reload == 1) + { + drawpic(hudloc + '132 54 0', spider_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawstring(hudloc + '179 69 0', strcat(ftos(rint(reload * 100)), "%"),'14 14 0','0 1 0', 0.5, DRAWFLAG_NORMAL); + } + else + { + drawpic(hudloc + '132 54 0', spider_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawstring(hudloc + '179 69 0', strcat(ftos(rint(reload * 100)), "%"),'14 14 0','0 0 1', 1, DRAWFLAG_NORMAL); + } + + picsize = drawgetimagesize(raptor_b) * 0.5; + hudloc_y = 10.5; + hudloc_x = 10.5; + + drawpic(hudloc, raptor_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL); + drawpic(hudloc, raptor_b, picsize, '0 1 0' * hp + '1 0 0' * (1 - hp), 1, DRAWFLAG_NORMAL); + drawpic(hudloc, raptor_g1, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); + drawpic(hudloc, raptor_g2, picsize, '1 1 1' * reload + '1 0 0' * (1 - reload), 1, DRAWFLAG_NORMAL); + + + if (sb_showscores) + { + Sbar_DrawScoreboard(); + Sbar_DrawCenterPrint(); + } + +} + #define waki_h "gfx/vehicles/hud_bg.tga" #define waki_b "gfx/vehicles/waki.tga" #define waki_e "gfx/vehicles/waki_e.tga" diff --git a/qcsrc/client/projectile.qc b/qcsrc/client/projectile.qc index 97debdfacd..2730a322d2 100644 --- a/qcsrc/client/projectile.qc +++ b/qcsrc/client/projectile.qc @@ -249,14 +249,14 @@ void Ent_Projectile() self.traileffect = 0; switch(self.cnt) { - case PROJECTILE_ELECTRO: setmodel(self, "models/ebomb.mdl");self.traileffect = particleeffectnum("TR_XONOTICPLASMA"); break; + case PROJECTILE_ELECTRO: setmodel(self, "models/ebomb.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break; case PROJECTILE_ROCKET: setmodel(self, "models/rocket.md3");self.traileffect = particleeffectnum("TR_ROCKET"); self.scale = 2; break; case PROJECTILE_BULLET: setmodel(self, "models/tracer.mdl");self.traileffect = particleeffectnum("tr_bullet"); break; case PROJECTILE_BULLET_GLOWING: setmodel(self, "models/tracer.mdl");self.traileffect = particleeffectnum("tr_bullet"); break; case PROJECTILE_BULLET_GLOWING_TRACER: setmodel(self, "models/tracer.mdl");self.traileffect = particleeffectnum("tr_rifle"); break; case PROJECTILE_CRYLINK: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum("TR_CRYLINKPLASMA"); break; case PROJECTILE_CRYLINK_BOUNCING: setmodel(self, "models/plasmatrail.mdl");self.traileffect = particleeffectnum("TR_CRYLINKPLASMA"); break; - case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_XONOTICPLASMA"); break; + case PROJECTILE_ELECTRO_BEAM: setmodel(self, "models/elaser.mdl");self.traileffect = particleeffectnum("TR_NEXUIZPLASMA"); break; case PROJECTILE_GRENADE: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break; case PROJECTILE_GRENADE_BOUNCING: setmodel(self, "models/grenademodel.md3");self.traileffect = particleeffectnum("TR_GRENADE"); break; case PROJECTILE_LASER: setmodel(self, "models/laser.mdl");self.traileffect = particleeffectnum(""); break; diff --git a/qcsrc/common/constants.qh b/qcsrc/common/constants.qh index cdd3a3185b..92ef9844eb 100644 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@ -285,6 +285,7 @@ const float STAT_HUD = 50; const float HUD_NORMAL = 0; const float HUD_SPIDERBOT = 10; const float HUD_WAKIZASHI = 11; +const float HUD_RAPTOR = 12; const float STAT_VEHICLESTAT_HEALTH = 60; const float STAT_VEHICLESTAT_SHIELD = 61; diff --git a/qcsrc/menu/anim/keyframe.c b/qcsrc/menu/anim/keyframe.c index 39e1fd8b42..d32f196184 100644 --- a/qcsrc/menu/anim/keyframe.c +++ b/qcsrc/menu/anim/keyframe.c @@ -1,5 +1,6 @@ #ifdef INTERFACE CLASS(Keyframe) EXTENDS(Animation) + METHOD(Keyframe, addEasing, entity(entity, float, float, float(float, float, float, float))) METHOD(Keyframe, addAnim, void(entity, entity)) METHOD(Keyframe, calcValue, float(entity, float, float, float, float)) ATTRIB(Keyframe, currentChild, entity, NULL) @@ -8,6 +9,9 @@ CLASS(Keyframe) EXTENDS(Animation) ENDCLASS(Animation) entity makeHostedKeyframe(entity, void(entity, float), float, float, float); entity makeKeyframe(entity, void(entity, float), float, float, float); +float getNewChildStart(entity); +float getNewChildDuration(entity, float); +float getNewChildValue(entity); #endif #ifdef IMPLEMENTATION @@ -27,6 +31,40 @@ entity makeKeyframe(entity obj, void(entity, float) setter, float duration, floa return me; } +entity addEasingKeyframe(entity me, float durationTime, float end, float(float, float, float, float) func) +{ + entity other; + other = makeEasing(me.object, me.setter, func, getNewChildStart(me), getNewChildDuration(me, durationTime), getNewChildValue(me), end); + me.addAnim(me, other); + return other; +} + +float getNewChildStart(entity me) +{ + if (me.lastChild) + return (me.lastChild.startTime + me.lastChild.duration); + else + return 0; +} + +float getNewChildDuration(entity me, float durationTime) +{ + float dura, maxDura; + maxDura = me.duration; + if (me.lastChild) maxDura = maxDura - (me.lastChild.startTime + me.lastChild.duration); + dura = durationTime; + if (0 >= dura || dura > maxDura) dura = maxDura; + return dura; +} + +float getNewChildValue(entity me) +{ + if (me.lastChild) + return (me.lastChild.startValue + me.lastChild.delta); + else + return me.startValue; +} + void addAnimKeyframe(entity me, entity other) { if(other.parent) diff --git a/qcsrc/qc-client.cbp b/qcsrc/qc-client.cbp new file mode 100644 index 0000000000..056b98ef27 --- /dev/null +++ b/qcsrc/qc-client.cbp @@ -0,0 +1,92 @@ + + + + + + diff --git a/qcsrc/qc-common.cbp b/qcsrc/qc-common.cbp new file mode 100644 index 0000000000..95f1ba836e --- /dev/null +++ b/qcsrc/qc-common.cbp @@ -0,0 +1,65 @@ + + + + + + diff --git a/qcsrc/qc-server.cbp b/qcsrc/qc-server.cbp new file mode 100644 index 0000000000..00912bea33 --- /dev/null +++ b/qcsrc/qc-server.cbp @@ -0,0 +1,212 @@ + + + + + + diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index c8fee27ae7..ef83ef6354 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -13,10 +13,13 @@ void Announce(string snd) { } void AnnounceTo(entity e, string snd) { - msg_entity = e; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE); - WriteString(MSG_ONE, snd); + if (clienttype(e) == CLIENTTYPE_REAL) + { + msg_entity = e; + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE); + WriteString(MSG_ONE, snd); + } } float ClientData_Send(entity to, float sf) @@ -405,6 +408,7 @@ string CheckPlayerModel(string plyermodel) { { if(substring(plyermodel,-4,4) != ".zym") if(substring(plyermodel,-4,4) != ".dpm") + if(substring(plyermodel,-4,4) != ".iqm") if(substring(plyermodel,-4,4) != ".md3") if(substring(plyermodel,-4,4) != ".psk") return FallbackPlayerModel; diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index 33cc475cf1..8925f17134 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -885,14 +885,20 @@ void UpdateSelectedPlayer() } .float muted; // to be used by prvm_edictset server playernumber muted 1 -void Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol) +float Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol) +// message "": do not say, just test flood control +// return value: +// 1 = accept +// 0 = reject +// -1 = fake accept { string msgstr, colorstr, cmsgstr, namestr, fullmsgstr, sourcemsgstr, fullcmsgstr, sourcecmsgstr, privatemsgprefix; float flood, privatemsgprefixlen; entity head; + float ret; if(Ban_MaybeEnforceBan(source)) - return; + return 0; if(!teamsay && !privatesay) if(substring(msgin, 0, 1) == " ") @@ -900,9 +906,6 @@ void Say(entity source, float teamsay, entity privatesay, string msgin, float fl msgin = formatmessage(msgin); - if(msgin == "") - return; - if(source.classname != "player") colorstr = "^0"; // black for spectators else if(teams_matter) @@ -913,9 +916,8 @@ void Say(entity source, float teamsay, entity privatesay, string msgin, float fl if(intermission_running) teamsay = FALSE; - msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin); - if(msgin == "") - return; + if(msgin != "") + msgin = trigger_magicear_processmessage_forallears(source, teamsay, privatesay, msgin); /* * using bprint solves this... me stupid @@ -933,29 +935,36 @@ void Say(entity source, float teamsay, entity privatesay, string msgin, float fl else namestr = source.netname; - if(privatesay) + if(msgin != "") { - msgstr = strcat("\{1}\{13}* ^3", namestr, "^3 tells you: ^7"); - privatemsgprefixlen = strlen(msgstr); - msgstr = strcat(msgstr, msgin); - cmsgstr = strcat(colorstr, "^3", namestr, "^3 tells you:\n^7", msgin); - if(cvar("g_chat_teamcolors")) - privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7"); + if(privatesay) + { + msgstr = strcat("\{1}\{13}* ^3", namestr, "^3 tells you: ^7"); + privatemsgprefixlen = strlen(msgstr); + msgstr = strcat(msgstr, msgin); + cmsgstr = strcat(colorstr, "^3", namestr, "^3 tells you:\n^7", msgin); + if(cvar("g_chat_teamcolors")) + privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", playername(privatesay), ": ^7"); + else + privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", privatesay.netname, ": ^7"); + } + else if(teamsay) + { + msgstr = strcat("\{1}\{13}", colorstr, "(^3", namestr, colorstr, ") ^7", msgin); + cmsgstr = strcat(colorstr, "(^3", namestr, colorstr, ")\n^7", msgin); + } else - privatemsgprefix = strcat("\{1}\{13}* ^3You tell ", privatesay.netname, ": ^7"); - } - else if(teamsay) - { - msgstr = strcat("\{1}\{13}", colorstr, "(^3", namestr, colorstr, ") ^7", msgin); - cmsgstr = strcat(colorstr, "(^3", namestr, colorstr, ")\n^7", msgin); + { + msgstr = strcat("\{1}", namestr, "^7: ", msgin); + cmsgstr = ""; + } + msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint } else { - msgstr = strcat("\{1}", namestr, "^7: ", msgin); - cmsgstr = ""; + msgstr = cmsgstr = ""; } - msgstr = strcat(strreplace("\n", " ", msgstr), "\n"); // newlines only are good for centerprint fullmsgstr = msgstr; fullcmsgstr = cmsgstr; @@ -993,37 +1002,47 @@ void Say(entity source, float teamsay, entity privatesay, string msgin, float fl // to match explanation in default.cfg, a value of 3 must allow three-line bursts and not four! // do flood control for the default line size - getWrappedLine_remaining = msgstr; - msgstr = ""; - lines = 0; - while(getWrappedLine_remaining && (!flood_lmax || lines <= flood_lmax)) + if(msgstr != "") { - msgstr = strcat(msgstr, " ", getWrappedLineLen(82.4289758859709, strlennocol)); // perl averagewidth.pl < gfx/vera-sans.width - ++lines; - } - msgstr = substring(msgstr, 1, strlen(msgstr) - 1); + getWrappedLine_remaining = msgstr; + msgstr = ""; + lines = 0; + while(getWrappedLine_remaining && (!flood_lmax || lines <= flood_lmax)) + { + msgstr = strcat(msgstr, " ", getWrappedLineLen(82.4289758859709, strlennocol)); // perl averagewidth.pl < gfx/vera-sans.width + ++lines; + } + msgstr = substring(msgstr, 1, strlen(msgstr) - 1); - if(getWrappedLine_remaining != "") - { - msgstr = strcat(msgstr, "\n"); - flood = 2; - } + if(getWrappedLine_remaining != "") + { + msgstr = strcat(msgstr, "\n"); + flood = 2; + } - if(time >= source.flood_field) - { - source.flood_field = max(time - flood_burst * flood_spl, source.flood_field) + lines * flood_spl; + if(time >= source.flood_field) + { + source.flood_field = max(time - flood_burst * flood_spl, source.flood_field) + lines * flood_spl; + } + else + { + flood = 1; + msgstr = fullmsgstr; + } } else { - flood = 1; - msgstr = fullmsgstr; + if(time >= source.flood_field) + source.flood_field = max(time - flood_burst * flood_spl, source.flood_field) + flood_spl; + else + flood = 1; } } if (timeoutStatus == 2) //when game is paused, no flood protection source.flood_field = flood = 0; - if(flood == 2) + if(flood == 2) // cannot happen for empty msgstr { if(cvar("g_chat_flood_notify_flooder")) { @@ -1060,57 +1079,70 @@ void Say(entity source, float teamsay, entity privatesay, string msgin, float fl if(source.muted) { // always fake the message - sprint(source, sourcemsgstr); - if(cmsgstr != "" && !privatesay) - centerprint(source, sourcecmsgstr); + ret = -1; } else if(flood == 1) { if(cvar("g_chat_flood_notify_flooder")) - sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.flood_field - time), "^3 seconds\n")); - else { - sprint(source, sourcemsgstr); - if(cmsgstr != "" && !privatesay) - centerprint(source, sourcecmsgstr); + sprint(source, strcat("^3FLOOD CONTROL: ^7wait ^1", ftos(source.flood_field - time), "^3 seconds\n")); + ret = 0; } + else + ret = -1; } - else if(privatesay) - { - sprint(source, sourcemsgstr); - sprint(privatesay, msgstr); - if(cmsgstr != "") - centerprint(privatesay, cmsgstr); - } - else if(teamsay > 0) - { - sprint(source, sourcemsgstr); - if(sourcecmsgstr != "") - centerprint(source, sourcecmsgstr); - FOR_EACH_REALPLAYER(head) if(head.team == source.team) - if(head != source) - { - sprint(head, msgstr); - if(cmsgstr != "") - centerprint(head, cmsgstr); - } - } - else if(teamsay < 0) + else { - sprint(source, sourcemsgstr); - FOR_EACH_REALCLIENT(head) if(head.classname != "player") - if(head != source) - sprint(head, msgstr); + ret = 1; } - else if(sourcemsgstr != msgstr) + + if(sourcemsgstr != "" && ret != 0) { - sprint(source, sourcemsgstr); - FOR_EACH_REALCLIENT(head) - if(head != source) - sprint(head, msgstr); + if(ret < 0) // fake + { + sprint(source, sourcemsgstr); + if(sourcecmsgstr != "" && !privatesay) + centerprint(source, sourcecmsgstr); + } + else if(privatesay) + { + sprint(source, sourcemsgstr); + sprint(privatesay, msgstr); + if(cmsgstr != "") + centerprint(privatesay, cmsgstr); + } + else if(teamsay > 0) + { + sprint(source, sourcemsgstr); + if(sourcecmsgstr != "") + centerprint(source, sourcecmsgstr); + FOR_EACH_REALPLAYER(head) if(head.team == source.team) + if(head != source) + { + sprint(head, msgstr); + if(cmsgstr != "") + centerprint(head, cmsgstr); + } + } + else if(teamsay < 0) + { + sprint(source, sourcemsgstr); + FOR_EACH_REALCLIENT(head) if(head.classname != "player") + if(head != source) + sprint(head, msgstr); + } + else if(sourcemsgstr != msgstr) + { + sprint(source, sourcemsgstr); + FOR_EACH_REALCLIENT(head) + if(head != source) + sprint(head, msgstr); + } + else + bprint(msgstr); } - else - bprint(msgstr); + + return ret; } float GetVoiceMessageVoiceType(string type) @@ -1242,6 +1274,81 @@ void UpdatePlayerSounds() LoadPlayerSounds(strcat(self.model, ".sounds"), 0); } +void FakeGlobalSound(string sample, float chan, float voicetype) +{ + float n; + float tauntrand; + + if(sample == "") + return; + + tokenize_console(sample); + n = stof(argv(1)); + if(n > 0) + sample = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization + else + sample = strcat(argv(0), ".wav"); // randomization + + switch(voicetype) + { + case VOICETYPE_LASTATTACKER_ONLY: + break; + case VOICETYPE_LASTATTACKER: + if(self.pusher) + { + msg_entity = self; + if(clienttype(msg_entity) == CLIENTTYPE_REAL) + soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE); + } + break; + case VOICETYPE_TEAMRADIO: + msg_entity = self; + if(msg_entity.cvar_cl_voice_directional == 1) + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + else + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + break; + case VOICETYPE_AUTOTAUNT: + if(!sv_autotaunt) + break; + if(!sv_taunt) + break; + if(sv_gentle) + break; + tauntrand = random(); + msg_entity = self; + if (tauntrand < msg_entity.cvar_cl_autotaunt) + { + if (msg_entity.cvar_cl_voice_directional >= 1) + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); + else + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + } + break; + case VOICETYPE_TAUNT: + if(self.classname == "player") + if(self.deadflag == DEAD_NO) + setanim(self, self.anim_taunt, FALSE, TRUE, TRUE); + if(!sv_taunt) + break; + if(sv_gentle) + break; + msg_entity = self; + if (msg_entity.cvar_cl_voice_directional >= 1) + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, bound(ATTN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTN_MAX)); + else + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); + break; + case VOICETYPE_PLAYERSOUND: + msg_entity = self; + soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NORM); + break; + default: + backtrace("Invalid voice type!"); + break; + } +} + void GlobalSound(string sample, float chan, float voicetype) { float n; @@ -1261,34 +1368,32 @@ void GlobalSound(string sample, float chan, float voicetype) { case VOICETYPE_LASTATTACKER_ONLY: if(self.pusher) - if(self.pusher.team == self.team) + { + msg_entity = self.pusher; + if(clienttype(msg_entity) == CLIENTTYPE_REAL) { - msg_entity = self.pusher; - if(clienttype(msg_entity) == CLIENTTYPE_REAL) - { - if(msg_entity.cvar_cl_voice_directional == 1) - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); - } + if(msg_entity.cvar_cl_voice_directional == 1) + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + else + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); } + } break; case VOICETYPE_LASTATTACKER: if(self.pusher) - if(self.pusher.team == self.team) + { + msg_entity = self.pusher; + if(clienttype(msg_entity) == CLIENTTYPE_REAL) { - msg_entity = self.pusher; - if(clienttype(msg_entity) == CLIENTTYPE_REAL) - { - if(msg_entity.cvar_cl_voice_directional == 1) - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); - else - soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); - } - msg_entity = self; - if(clienttype(msg_entity) == CLIENTTYPE_REAL) - soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE); + if(msg_entity.cvar_cl_voice_directional == 1) + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_MIN); + else + soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); } + msg_entity = self; + if(clienttype(msg_entity) == CLIENTTYPE_REAL) + soundto(MSG_ONE, self, chan, sample, VOL_BASE, ATTN_NONE); + } break; case VOICETYPE_TEAMRADIO: FOR_EACH_REALCLIENT(msg_entity) @@ -1332,6 +1437,7 @@ void GlobalSound(string sample, float chan, float voicetype) else soundto(MSG_ONE, self, chan, sample, VOL_BASEVOICE, ATTN_NONE); } + break; case VOICETYPE_PLAYERSOUND: sound(self, chan, sample, VOL_BASE, ATTN_NORM); break; @@ -1343,15 +1449,14 @@ void GlobalSound(string sample, float chan, float voicetype) void PlayerSound(.string samplefield, float chan, float voicetype) { - string sample; - sample = self.samplefield; - GlobalSound(sample, chan, voicetype); + GlobalSound(self.samplefield, chan, voicetype); } void VoiceMessage(string type, string msg) { var .string sample; - var float voicetype, ownteam; + float voicetype, ownteam; + float flood; sample = GetVoiceMessageSampleField(type); if(GetPlayerSoundSampleField_notFound) @@ -1363,35 +1468,12 @@ void VoiceMessage(string type, string msg) voicetype = GetVoiceMessageVoiceType(type); ownteam = (voicetype == VOICETYPE_TEAMRADIO); - float flood; - float flood_spv; - var .float flood_field; - - flood = 0; - if(ownteam) - { - flood_spv = cvar("g_voice_flood_spv_team"); - flood_field = floodcontrol_voiceteam; - } - else - { - flood_spv = cvar("g_voice_flood_spv"); - flood_field = floodcontrol_voice; - } - - if(time >= self.flood_field) - self.flood_field = max(time, self.flood_field) + flood_spv; - else - flood = 1; - - if (timeoutStatus == 2) //when game is paused, no flood protection - self.flood_field = flood = 0; - - if (msg != "") - Say(self, ownteam, world, msg, 0); + flood = Say(self, ownteam, world, msg, 1); - if (!flood) - PlayerSound(sample, CHAN_VOICE, voicetype); + if (flood > 0) + GlobalSound(self.sample, CHAN_VOICE, voicetype); + else if (flood < 0) + FakeGlobalSound(self.sample, CHAN_VOICE, voicetype); } void MoveToTeam(entity client, float team_colour, float type, float show_message) diff --git a/qcsrc/server/cl_weapons.qc b/qcsrc/server/cl_weapons.qc index 788a67e517..b5e245db63 100644 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@ -12,6 +12,8 @@ void W_SwitchWeapon(float imp) { if (client_hasweapon(self, imp, TRUE, TRUE)) W_SwitchWeapon_Force(self, imp); + else + self.selectweapon = imp; // update selectweapon ANYWAY } else { @@ -20,7 +22,7 @@ void W_SwitchWeapon(float imp) }; .float weaponcomplainindex; -float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain) +float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, float complain, float skipmissing) { // We cannot tokenize in this function, as GiveItems calls this // function. Thus we must use car/cdr. @@ -28,6 +30,12 @@ float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, floa string rest; switchtonext = switchtolast = 0; first_valid = prev_valid = 0; + float weaponcur; + + if(skipmissing || pl.selectweapon == 0) + weaponcur = pl.switchweapon; + else + weaponcur = pl.selectweapon; if(dir == 0) switchtonext = 1; @@ -44,13 +52,13 @@ float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, floa ++c; - if(client_hasweapon(pl, weaponwant, TRUE, FALSE)) + if(!skipmissing || client_hasweapon(pl, weaponwant, TRUE, FALSE)) { if(switchtonext) return weaponwant; if(!first_valid) first_valid = weaponwant; - if(weaponwant == pl.switchweapon) + if(weaponwant == weaponcur) { if(dir >= 0) switchtonext = 1; @@ -96,7 +104,7 @@ float W_GetCycleWeapon(entity pl, string weaponorder, float dir, float imp, floa void W_CycleWeapon(string weaponorder, float dir) { float w; - w = W_GetCycleWeapon(self, weaponorder, dir, -1, 1); + w = W_GetCycleWeapon(self, weaponorder, dir, -1, 1, TRUE); if(w > 0) W_SwitchWeapon(w); } @@ -104,7 +112,7 @@ void W_CycleWeapon(string weaponorder, float dir) void W_NextWeaponOnImpulse(float imp) { float w; - w = W_GetCycleWeapon(self, self.cvar_cl_weaponpriority, +1, imp, 1); + w = W_GetCycleWeapon(self, self.cvar_cl_weaponpriority, +1, imp, 1, (self.cvar_cl_weaponimpulsemode == 0)); if(w > 0) W_SwitchWeapon(w); } @@ -145,7 +153,7 @@ string W_FixWeaponOrder_ForceComplete(string order) float w_getbestweapon(entity e) { - return W_GetCycleWeapon(e, e.cvar_cl_weaponpriority, 0, -1, 0); + return W_GetCycleWeapon(e, e.cvar_cl_weaponpriority, 0, -1, FALSE, TRUE); }; // generic weapons table diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc index e7bfc69d05..f1e9bf70e9 100644 --- a/qcsrc/server/cl_weaponsystem.qc +++ b/qcsrc/server/cl_weaponsystem.qc @@ -36,6 +36,7 @@ void W_SwitchWeapon_Force(entity e, float w) { e.cnt = e.switchweapon; e.switchweapon = w; + e.selectweapon = w; } .float antilag_debug; diff --git a/qcsrc/server/defs.qh b/qcsrc/server/defs.qh index e80025a676..b487e3de77 100644 --- a/qcsrc/server/defs.qh +++ b/qcsrc/server/defs.qh @@ -505,6 +505,7 @@ void UpdatePlayerSounds(); void ClearPlayerSounds(); void PlayerSound(.string samplefield, float channel, float voicetype); void GlobalSound(string samplestring, float channel, float voicetype); +void FakeGlobalSound(string samplestring, float channel, float voicetype); void VoiceMessage(string type, string message); // autotaunt system @@ -637,3 +638,6 @@ string deathmessage; .float cvar_cl_accuracy_data_share; .float cvar_cl_accuracy_data_receive; + +.float cvar_cl_weaponimpulsemode; +.float selectweapon; // last selected weapon of the player diff --git a/qcsrc/server/extensions.qh b/qcsrc/server/extensions.qh index f73259cf9c..e5df457c15 100644 --- a/qcsrc/server/extensions.qh +++ b/qcsrc/server/extensions.qh @@ -177,7 +177,7 @@ float EF_RED = 128; //DP_EF_RESTARTANIM_BIT //idea: id software -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //effects bit: float EF_RESTARTANIM_BIT = 1048576; //description: @@ -195,7 +195,7 @@ float EF_STARDUST = 2048; //DP_EF_TELEPORT_BIT //idea: id software -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //effects bit: float EF_TELEPORT_BIT = 2097152; //description: @@ -517,7 +517,7 @@ void(entity e, entity tagentity, string tagname) setattachment = #443; // attach //DP_NULL_MODEL //idea: Chris -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //definitions: //string dp_null_model = "null"; //description: @@ -561,8 +561,8 @@ float(float a) tan = #475; // returns tangent value (which is simply sin(a)/cos( //note: atan2 can take unnormalized vectors (just like vectoyaw), and the function was included only for completeness (more often you want vectoyaw or vectoangles), atan2(v_x,v_y) * RAD2DEG gives the same result as vectoyaw(v) //DP_QC_AUTOCVARS -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //description: //allows QC variables to be bound to cvars //(works for float, string, vector types) @@ -615,8 +615,8 @@ string(string s) cvar_defstring = #482; //returns the default value of a cvar, as a tempstring. //DP_QC_CVAR_DESCRIPTION -//idea: div0 -//DarkPlaces implementation: div0 +//idea: divVerent +//DarkPlaces implementation: divVerent //builtin definitions: string(string name) cvar_description = #518; //description: @@ -631,8 +631,8 @@ string(string s) cvar_string = #448; //returns the value of a cvar, as a tempstring. //DP_QC_CVAR_TYPE -//idea: div0 -//DarkPlaces implementation: div0 +//idea: divVerent +//DarkPlaces implementation: divVerent //builtin definitions: float(string name) cvar_type = #495; float CVAR_TYPEFLAG_EXISTS = 1; @@ -694,8 +694,8 @@ string(entity ent) etos = #65; //prints "entity 1" or similar into a string. (this was a Q2 builtin) //DP_QC_EXTRESPONSEPACKET -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: string(void) getextresponse = #624; //description: @@ -713,8 +713,8 @@ entity(.string fld, string match) findchain = #402; //similar to find() but returns a chain of entities like findradius. //DP_QC_FINDCHAIN_TOFIELD -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: entity(.string fld, float match, .entity tofield) findradius_tofield = #22; entity(.string fld, string match, .entity tofield) findchain_tofield = #402; @@ -806,12 +806,13 @@ float SPA_LIGHTMAP0_TEXCOORDS = 5; float SPA_LIGHTMAP0_COLOR = 6; //builtin definitions: vector(entity e, float s, float n, float a) getsurfacepointattribute = #486; + //description: //function to query extended information about a point on a certain surface //DP_QC_GETSURFACETRIANGLE -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: float(entity e, float s) getsurfacenumtriangles = #628; vector(entity e, float s, float n) getsurfacetriangle = #629; @@ -830,7 +831,7 @@ vector(entity ent, float tagindex) gettaginfo = #452; //DP_QC_GETTAGINFO_BONEPROPERTIES //idea: daemon -//DarkPlaces implementation: div0 +//DarkPlaces implementation: divVerent //global definitions: float gettaginfo_parent; string gettaginfo_name; @@ -846,7 +847,7 @@ vector gettaginfo_up; //DP_QC_GETTIME //idea: tZork -//darkplaces implementation: tZork, div0 +//darkplaces implementation: tZork, divVerent //constant definitions: float GETTIME_FRAMESTART = 0; // time of start of frame float GETTIME_REALTIME = 1; // current time (may be OS specific) @@ -858,15 +859,15 @@ float(float tmr) gettime = #519; //some timers to query... //DP_QC_GETTIME_CDTRACK -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //constant definitions: float GETTIME_CDTRACK = 4; //description: //returns the playing time of the current cdtrack when passed to gettime() //DP_QC_LOG -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //builtin definitions: float log(float f) = #532; //description: @@ -937,8 +938,8 @@ float(float a, float b) pow = #97; //useful math functions, sine of val, cosine of val, square root of val, and raise a to power b, respectively. //DP_QC_SPRINTF -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: string(string format, ...) sprintf = #627; //description: @@ -955,6 +956,7 @@ string(string format, ...) sprintf = #627; // ouxXc take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to an unsigned int // eEfFgG take a float if no length is specified or h is, and an int/entity if l is specified as length, and cast it to a double // s takes a string +// vV takes a vector, and processes the three components as if it were a gG for all three components, separated by space // For conversions s and c, the flag # makes precision and width interpreted // as byte count, by default it is interpreted as character count in UTF-8 // enabled engines. No other conversions can create wide characters, and # @@ -1011,8 +1013,8 @@ float(string s, string separator1, ...) tokenizebyseparator = #479; //possibly useful for parsing IPv4 addresses (such as "1.2.3.4") and IPv6 addresses (such as "[1234:5678:9abc:def0:1234:5678:9abc:def0]:26000") //DP_QC_TOKENIZE_CONSOLE -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: float(string s) tokenize_console = #514; float(float i) argv_start_index = #515; @@ -1055,7 +1057,7 @@ float MOVE_WORLDONLY = 3; //allows traces to hit only world (ignoring all entities, unlike MOVE_NOMONSTERS which hits all bmodels), use as the nomonsters parameter to trace functions //DP_QC_UNLIMITEDTEMPSTRINGS -//idea: div0 +//idea: divVerent //darkplaces implementation: LordHavoc //description: //this extension alters Quake behavior such that instead of reusing a single @@ -1097,23 +1099,23 @@ void(vector dir) vectorvectors = #432; //creates v_forward, v_right, and v_up vectors given a forward vector, similar to makevectors except it takes a forward direction vector instead of angles. //DP_QC_WHICHPACK -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: string(string filename) whichpack = #503; //description: //returns the name of the pak/pk3/whatever containing the given file, in the same path space as FRIK_FILE functions use (that is, possibly with a path name prefix) //DP_QC_URI_ESCAPE -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //URI::Escape's functionality string(string in) uri_escape = #510; string(string in) uri_unescape = #511; //DP_QC_URI_GET -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //loads text from an URL into a string //returns 1 on success of initiation, 0 if there are too many concurrent //connections already or if the URL is invalid @@ -1133,8 +1135,8 @@ float(string url, float id) uri_get = #513; //this extension indicates that FTE_CSQC_SKELETONOBJECTS functionality is available in server QC (as well as CSQC). //DP_SV_SPAWNFUNC_PREFIX -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //Make functions whose name start with spawnfunc_ take precedence as spawn function for loading entities. //Useful if you have a field ammo_shells (required in any Quake mod) but want to support spawn functions called ammo_shells (like in Q3A). //Optionally, you can declare a global "float require_spawnfunc_prefix;" which will require ANY spawn function to start with that prefix. @@ -1372,8 +1374,8 @@ void(vector origin, string sample, float volume, float attenuation) pointsound = // To mimic the engine's default behavior, simply call remove(self). //DP_SV_ONENTITYPREPOSTSPAWNFUNCTION -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //engine-called QC prototypes: //void() SV_OnEntityPreSpawnFunction; //void() SV_OnEntityPostSpawnFunction; @@ -1494,8 +1496,8 @@ void(string s, ...) print = #339; // same number as in EXT_CSQC //this extension allows precache_model and precache_sound (and any variants) to be used during the game (with automatic messages to clients to precache the new model/sound indices), also setmodel/sound/ambientsound can be called without precaching first (they will cause an automatic precache). //DP_SV_QCSTATUS -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //1. A global variable string worldstatus; //Its content is set as "qcstatus" field in the rules. @@ -1535,8 +1537,8 @@ void(entity ent, float colors) setcolor = #401; //range is 0 to infinite, recommended values to try are 0.1 (very slow, 10% speed), 1 (normal speed), 5 (500% speed). //DP_SV_WRITEPICTURE -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //builtin definitions: void(float to, string s, float sz) WritePicture = #501; //description: @@ -1865,12 +1867,14 @@ float FILE_WRITE = 2; //idea: Spike, LordHavoc //darkplaces implementation: LordHavoc //builtin definitions: -float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex. +// all skeleton numbers are 1-based (0 being no skeleton) +// all bone numbers are 1-based (0 being invalid) +float(float modlindex) skel_create = #263; // create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex, as the skeleton uses the hierarchy from the model. float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure -float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton -string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring) -float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) -float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex +float(float skel) skel_get_numbones = #265; // returns how many bones exist in the created skeleton, 0 if skeleton does not exist +string(float skel, float bonenum) skel_get_bonename = #266; // returns name of bone (as a tempstring), "" if invalid bonenum (< 1 for example) or skeleton does not exist +float(float skel, float bonenum) skel_get_boneparent = #267; // returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this) +float(float skel, string tagname) skel_find_bone = #268; // get number of bone with specified name, 0 on failure, bonenum (1-based) on success, same as using gettagindex but takes modelindex instead of entity vector(float skel, float bonenum) skel_get_bonerel = #269; // get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone) vector(float skel, float bonenum) skel_get_boneabs = #270; // get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity) void(float skel, float bonenum, vector org) skel_set_bone = #271; // set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone) @@ -2070,8 +2074,8 @@ string(float n) argv = #442; //description: //when a savegame is loaded, this function is called -//XONOTIC_PLAYERMODEL -//idea: Xonotic +//NEXUIZ_PLAYERMODEL +//idea: Nexuiz //darkplaces implementation: Black //console commands: //playermodel - FIXME: EXAMPLE NEEDED @@ -2080,7 +2084,7 @@ string(float n) argv = #442; .string playermodel; // name of player model sent by client .string playerskin; // name of player skin sent by client //description: -//these client properties are used by Xonotic. +//these client properties are used by Nexuiz. //NXQ_GFX_LETTERBOX //idea: nxQuake @@ -2140,7 +2144,7 @@ float PFLAGS_FULLDYNAMIC = 128; // light enable (without this set no light is pr //FTE_QC_CHECKPVS //idea: Urre -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //builtin definitions: float checkpvs(vector viewpos, entity viewee) = #240; //description: @@ -2177,7 +2181,7 @@ float(string s1, string s2, float len) strncasecmp = #230; // same as strcasecmp //DP_CON_BESTWEAPON //idea: many -//darkplaces implementation: div0 +//darkplaces implementation: divVerent //description: //allows QC to register weapon properties for use by the bestweapon command, for mods that change required ammo count or type for the weapons //it is done using console commands sent via stuffcmd: @@ -2212,8 +2216,8 @@ float(float bufhandle, string str, float order) bufstr_add = #468; void(float bufhandle, float string_index) bufstr_free = #469; //DP_QC_STRINGBUFFERS_CVARLIST -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //functions to list cvars and store their names into a stringbuffer //cvars that start with pattern but not with antipattern will be stored into the buffer void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517; @@ -2229,15 +2233,15 @@ string(string search, string replace, string subject) strireplace = #485; //strireplace does the same but uses case-insensitive matching of the 'search' term // //DP_QC_CRC16 -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //Some hash function to build hash tables with. This has to be be the CRC-16-CCITT that is also required for the QuakeWorld download protocol. //When caseinsensitive is set, the CRC is calculated of the lower cased string. float(float caseinsensitive, string s, ...) crc16 = #494; //DP_SV_SHUTDOWN -//idea: div0 -//darkplaces implementation: div0 +//idea: divVerent +//darkplaces implementation: divVerent //A function that gets called just before progs exit. To save persistent data from. //It is not called on a crash or error. //void SV_Shutdown(); @@ -2263,17 +2267,24 @@ void(float pause) setpause = #531; - - +// EXPERIMENTAL (not finalized) EXTENSIONS: //DP_PHYSICS +//idea: LordHavoc +//darkplaces implementation: LordHavoc, divVerent +//constant definitions: float SOLID_PHYSICS_BOX = 32; float SOLID_PHYSICS_SPHERE = 33; float SOLID_PHYSICS_CAPSULE = 34; float MOVETYPE_PHYSICS = 32; +float JOINTTYPE_POINT = 1; // point; uses origin (anchor) +float JOINTTYPE_HINGE = 2; // hinge; uses origin (anchor) and angles (axis) +float JOINTTYPE_SLIDER = 3; // slider; uses angles (axis) +float JOINTTYPE_UNIVERSAL = 4; // universal; uses origin (anchor) and angles (forward is axis1, up is axis2) +float JOINTTYPE_HINGE2 = 5; // hinge2; uses origin (anchor), angles (axis1), velocity (axis2) +//field definitions: .float mass; - -.float jointtype; +.float jointtype; // see JOINTTYPE_ definitions above // common joint properties: // .entity aiment, enemy; // connected objects // .vector movedir; @@ -2286,28 +2297,6 @@ float MOVETYPE_PHYSICS = 32; // movedir_y = -1 * max motor force to use // movedir_z = stop position (+/-), set to 0 for no stop // note that ODE does not support both in one anyway -// motor properties only make sense for hinge and slider! - -float JOINTTYPE_POINT = 1; -// .vector origin; // point anchor - -float JOINTTYPE_HINGE = 2; -// .vector origin; // hinge anchor -// .vector angles; // hinge axis - -float JOINTTYPE_SLIDER = 3; -// .vector angles; // slider axis - -float JOINTTYPE_UNIVERSAL = 4; -// .vector origin; // universal anchor -// .vector angles; // universal axis1 and axis2 (axis1 is forward, axis2 is up) - -float JOINTTYPE_HINGE2 = 5; -// .vector origin; // hinge2 anchor -// .vector angles; // hinge2 first axis (as angles) -// .vector velocity; // hinge2 second axis (as vector) - - - - - +//description: +//various physics properties can be defined in an entity and are executed via +//ODE diff --git a/qcsrc/server/g_tetris.qc b/qcsrc/server/g_tetris.qc index 5c65847ead..0782073bc0 100644 --- a/qcsrc/server/g_tetris.qc +++ b/qcsrc/server/g_tetris.qc @@ -8,6 +8,7 @@ compile with -DTETRIS #ifdef TETRIS +float autocvar_g_bastet; .vector tet_org; float tet_vs_current_id; @@ -26,7 +27,9 @@ float tet_vs_current_timeout; var float tet_high_score = 0; -float TET_LINES = 20; +vector TET_START_PIECE_POS = '5 1 0'; +float TET_LINES = 22; +float TET_DISPLAY_LINES = 20; float TET_WIDTH = 10; //character values float TET_BORDER = 139; @@ -48,7 +51,7 @@ float PIECES = 7; .float line1, line2, line3, line4, line5, line6, line7, line8, line9, line10, line11, line12, line13, line14, line15, -line16, line17, line18, line19, line20; +line16, line17, line18, line19, line20, line21, line22; float SVC_CENTERPRINTa = 26; @@ -112,6 +115,10 @@ void SetLine(float ln, float vl) self.line19 = vl; else if (ln == 20) self.line20 = vl; + else if (ln == 21) + self.line21 = vl; + else if (ln == 22) + self.line22 = vl; }; float GetLine(float ln) @@ -156,6 +163,10 @@ float GetLine(float ln) return self.line19; else if (ln == 20) return self.line20; + else if (ln == 21) + return self.line21; + else if (ln == 22) + return self.line22; else return 0; }; @@ -230,13 +241,13 @@ void SetSquare(float x, float y, float val) vector PieceShape(float pc) { if (pc == 1) - return '5 5 0'; // O + return '20 20 0'; // O else if (pc == 2) return '1 21 0'; // J else if (pc == 3) - return '21 1 0'; // L + return '16 21 0'; // L else if (pc == 4) - return '85 0 0'; // I + return '0 85 0'; // I else if (pc == 5) return '5 20 0'; // Z else if (pc == 6) @@ -246,17 +257,35 @@ vector PieceShape(float pc) else return '0 0 0'; } - +vector PieceSize(float pc) +{ + if (pc == 1) + return '2 2 0'; // O + else if (pc == 2) + return '3 2 0'; // J + else if (pc == 3) + return '3 2 0'; // L + else if (pc == 4) + return '4 1 0'; // I + else if (pc == 5) + return '3 2 0'; // Z + else if (pc == 6) + return '3 2 0'; // S + else if (pc == 7) + return '3 2 0'; // T + else + return '0 0 0'; +} vector PieceCenter(float pc) { if(pc == 1) - return '1.5 1.5 0'; // O + return '2.5 1.5 0'; // O else if (pc == 2) return '2 2 0'; // J else if (pc == 3) - return '2 1 0'; // L + return '2 2 0'; // L else if (pc == 4) - return '2.5 1.5 0'; // I + return '2.5 2.5 0'; // I else if (pc == 5) return '2 2 0'; // Z else if (pc == 6) @@ -271,12 +300,10 @@ vector PieceCenter(float pc) float PieceMetric(float x, float y, float rot, float pc) { float t; - vector piece_dat; - float wid; + vector ce; // return bits of a piece - wid = piece_dat_z + 1; - piece_dat = PieceCenter(pc); + ce = PieceCenter(pc); if (rot == 1) // 90 degrees { // x+cx, y+cy -> -y+cx, x+cy @@ -284,13 +311,13 @@ float PieceMetric(float x, float y, float rot, float pc) // x = X-cx // y = Y-cy t = y; - y = x - piece_dat_x + piece_dat_y; - x = -t + piece_dat_x + piece_dat_y; + y = x - ce_x + ce_y; + x = -t + ce_x + ce_y; } else if (rot == 2)//180 { - x = 2 * piece_dat_x - x; - y = 2 * piece_dat_y - y; + x = 2 * ce_x - x; + y = 2 * ce_y - y; } else if (rot == 3) // 270 { @@ -299,19 +326,104 @@ float PieceMetric(float x, float y, float rot, float pc) // x = X-cx // y = Y-cy t = y; - y = -x + piece_dat_y + piece_dat_x; - x = t - piece_dat_y + piece_dat_x; + y = -x + ce_y + ce_x; + x = t - ce_y + ce_x; } if (x < 1 || y < 1 || x > 4 || y > 2) return 0; - piece_dat = PieceShape(pc); + ce = PieceShape(pc); if (y == 1) - return GetXBlock(x, piece_dat_x); // first row + return GetXBlock(x, ce_x); // first row else if (y == 2) - return GetXBlock(x, piece_dat_y); // second row + return GetXBlock(x, ce_y); // second row else return 0; // illegal parms }; +vector tet_piecemins; +vector tet_piecemaxs; +void PieceMinsMaxs(float rot, float pc) +{ + vector sz, ce; + float t; + vector v; + + sz = PieceSize(pc); + ce = PieceCenter(pc); + // 1 = 2..2 + // 2 = 2..3 + // 3 = 1..3 + // 4 = 1..4 + tet_piecemins_x = floor(3.0 - sz_x * 0.5); + tet_piecemaxs_x = floor(2.0 + sz_x * 0.5); + if(sz_y == 1) + { + // special case for "I" + tet_piecemins_y = tet_piecemaxs_y = 2; + } + else + { + tet_piecemins_y = 1; + tet_piecemaxs_y = sz_y; + } + //print(sprintf("ce%v sz%v mi%v ma%v\n", ce, sz, tet_piecemins, tet_piecemaxs)); + if (rot == 1) // 90 degrees + { + t = tet_piecemins_y; + tet_piecemins_y = -tet_piecemins_x + ce_y + ce_x; + tet_piecemins_x = t - ce_y + ce_x; + t = tet_piecemaxs_y; + tet_piecemaxs_y = -tet_piecemaxs_x + ce_y + ce_x; + tet_piecemaxs_x = t - ce_y + ce_x; + // swap mins_y, maxs_y + t = tet_piecemins_y; + tet_piecemins_y = tet_piecemaxs_y; + tet_piecemaxs_y = t; + // TODO OPTIMIZE + } + else if (rot == 2)//180 + { + v = tet_piecemins; + tet_piecemins = 2 * ce - tet_piecemaxs; + tet_piecemaxs = 2 * ce - v; + } + else if (rot == 3) // 270 + { + t = tet_piecemins_y; + tet_piecemins_y = tet_piecemins_x - ce_x + ce_y; + tet_piecemins_x = -t + ce_x + ce_y; + t = tet_piecemaxs_y; + tet_piecemaxs_y = tet_piecemaxs_x - ce_x + ce_y; + tet_piecemaxs_x = -t + ce_x + ce_y; + // swap mins_x, maxs_x + t = tet_piecemins_x; + tet_piecemins_x = tet_piecemaxs_x; + tet_piecemaxs_x = t; + // TODO OPTIMIZE + } +#ifdef VERIFY + print(vtos(tet_piecemins), "-"); + print(vtos(tet_piecemaxs), "\n"); + if(tet_piecemins_x > tet_piecemaxs_x) + error("inconsistent mins/maxs"); + if(tet_piecemins_y > tet_piecemaxs_y) + error("inconsistent mins/maxs"); + float i, j; + vector realmins, realmaxs; + realmins = '4 4 0'; + realmaxs = '1 1 0'; + for(i = 1; i <= 4; ++i) + for(j = 1; j <= 4; ++j) + if(PieceMetric(i, j, rot, pc)) + { + realmins_x = min(realmins_x, i); + realmins_y = min(realmins_y, j); + realmaxs_x = max(realmaxs_x, i); + realmaxs_y = max(realmaxs_y, j); + } + if(realmins != tet_piecemins || realmaxs != tet_piecemaxs) + error(sprintf("incorrect mins/maxs: %v %v in %d rot %d mins %v maxs %v\n", realmins, realmaxs, rot, pc, tet_piecemins, tet_piecemaxs)); +#endif +} /* ********************************* @@ -361,7 +473,7 @@ void DrawLine(float ln) for (x = 1; x <= TET_WIDTH; x = x + 1) { - d = GetSquare(x, ln); + d = GetSquare(x, ln + TET_LINES - TET_DISPLAY_LINES); if (d) { WriteChar(MSG_ONE, '^'); @@ -408,13 +520,18 @@ void Draw_Tetris() entity head; msg_entity = self; WriteChar(MSG_ONE, SVC_CENTERPRINTa); + if(autocvar_g_bastet) + { + WriteTetrisString("NEVER GONNA GIVE YOU"); + WriteChar(MSG_ONE, 10); + } // decoration for (i = 1; i <= (TET_WIDTH + 2); i = i + 1) WriteChar(MSG_ONE, TET_BORDER); WriteTetrisString(" "); WriteUnterminatedString(MSG_ONE, TET_PADDING_RIGHT); WriteChar(MSG_ONE, 10); - for (i = 1; i <= TET_LINES; i = i + 1) + for (i = 1; i <= TET_DISPLAY_LINES; i = i + 1) { if(self.tetris_on == 2) WriteTetrisString(" GAME OVER "); @@ -423,7 +540,7 @@ void Draw_Tetris() else DrawLine(i); if (i == 1) - WriteTetrisString(" NEXT "); + WriteTetrisString(autocvar_g_bastet ? " THAT " : " NEXT "); else if (i == 3) DrawPiece(self.next_piece, 1); else if (i == 4) @@ -518,6 +635,226 @@ void Tet_GameExit() self.movetype = MOVETYPE_WALK; }; +void PrintField() +{ + float l; + float r, c; + for(r = 1; r <= TET_LINES; ++r) + { + l = GetLine(r); + print(">"); + for(c = 1; c <= TET_WIDTH; ++c) + { + print(ftos(GetXBlock(c, l))); + } + print("\n"); + } +} + +float BastetEvaluate() +{ + float height; + float score; + float occupied; + float occupied_count; + float l, lines; + float score_save, occupied_save, occupied_count_save; + float i, j, line; + + score = 0; + + // adds a bonus for each free dot above the occupied blocks profile + occupied_count = TET_WIDTH; + height = 0; + lines = 0; + for(i = 1; i <= TET_LINES; ++i) + { + l = GetLine(i); + if(l == 0) + { + height = i; + continue; + } + line = 1; + occupied_save = occupied; + occupied_count_save = occupied_count; + score_save = score; + for(j = 1; j <= TET_WIDTH; ++j) + { + if(GetXBlock(j, l)) + { + if(!GetXBlock(j, occupied)) + { + occupied = SetXBlock(j, occupied, 1); + --occupied_count; + } + } + else + line = 0; + score += 10000 * occupied_count; + } + if(line) + { + occupied = occupied_save; + occupied_count = occupied_count_save; + score = score_save + 100000000 + 10000 * TET_WIDTH + 1000; + ++lines; + } + } + + score += 1000 * height; + + return score; +} + +float CheckMetrics(float piece, float orgx, float orgy, float rot); +void ClearPiece(float piece, float orgx, float orgy, float rot); +void CementPiece(float piece, float orgx, float orgy, float rot); +float bastet_profile_evaluate_time; +float bastet_profile_checkmetrics_time; +float BastetSearch(float buf, float pc, float x, float y, float rot, float move_bias) +// returns best score, or -1 if position is impossible +{ + string r; + float b; + float s, sm; + float t1, t2; + + if(move_bias < 0) + return 0; // DO NOT WANT + + if(x < 1 || x > TET_WIDTH || y < 1 || y > TET_LINES) + return -1; // impossible + if(rot < 0) rot = 3; + if(rot > 3) rot = 0; + + // did we already try? + b = x + (TET_WIDTH+2) * (y + (TET_LINES+2) * rot); + r = bufstr_get(buf, b); + if(r != "") // already tried + return stof(r); + + bufstr_set(buf, b, "0"); // in case we READ that, not that bad - we already got that value in another branch then anyway + + + + t1 = gettime(GETTIME_HIRES); + if(CheckMetrics(pc, x, y, rot)) + { + t2 = gettime(GETTIME_HIRES); + bastet_profile_checkmetrics_time += (t2 - t1); + // try all moves + sm = 1; + s = BastetSearch(buf, pc, x-1, y, rot, move_bias - 1); if(s > sm) sm = s; + s = BastetSearch(buf, pc, x+1, y, rot, move_bias - 1); if(s > sm) sm = s; + s = BastetSearch(buf, pc, x, y, rot+1, move_bias - 1); if(s > sm) sm = s; + s = BastetSearch(buf, pc, x, y, rot-1, move_bias - 1); if(s > sm) sm = s; + + s = BastetSearch(buf, pc, x, y+1, rot, move_bias + 2); if(s > sm) sm = s; + if(s < 0) + { + //print(sprintf("MAY CEMENT AT: %d %d %d\n", x, y, rot)); + // moving down did not work - that means we can fixate the block here + t1 = gettime(GETTIME_HIRES); + + CementPiece(pc, x, y, rot); + s = BastetEvaluate(); + ClearPiece(pc, x, y, rot); + + t2 = gettime(GETTIME_HIRES); + bastet_profile_evaluate_time += (t2 - t1); + + if(s > sm) sm = s; + } + } + else + { + t2 = gettime(GETTIME_HIRES); + bastet_profile_checkmetrics_time += (t2 - t1); + sm = -1; // impassible + } + + bufstr_set(buf, b, ftos(sm)); + + return sm; +} + +float bastet_piece[7]; +float bastet_score[7]; +float bastet_piecetime[7]; +float BastetPiece() +{ + float b; + + bastet_profile_evaluate_time = 0; + bastet_profile_checkmetrics_time = 0; + var float t1 = gettime(GETTIME_HIRES); + + b = buf_create(); bastet_piece[0] = 1; bastet_score[0] = BastetSearch(b, 1, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[0]; buf_del(b); + b = buf_create(); bastet_piece[1] = 2; bastet_score[1] = BastetSearch(b, 2, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[1]; buf_del(b); + b = buf_create(); bastet_piece[2] = 3; bastet_score[2] = BastetSearch(b, 3, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[2]; buf_del(b); + b = buf_create(); bastet_piece[3] = 4; bastet_score[3] = BastetSearch(b, 4, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[3]; buf_del(b); + b = buf_create(); bastet_piece[4] = 5; bastet_score[4] = BastetSearch(b, 5, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[4]; buf_del(b); + b = buf_create(); bastet_piece[5] = 6; bastet_score[5] = BastetSearch(b, 6, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[5]; buf_del(b); + b = buf_create(); bastet_piece[6] = 7; bastet_score[6] = BastetSearch(b, 7, TET_START_PIECE_POS_x, 1+TET_START_PIECE_POS_y, TET_START_PIECE_POS_y, TET_WIDTH) + 100 * random() + bastet_piecetime[6]; buf_del(b); + + var float t2 = gettime(GETTIME_HIRES); + dprint(sprintf("Time taken: %.6f seconds (of this, ev = %.2f%%, cm = %.2f%%)\n", t2 - t1, 100 * bastet_profile_evaluate_time / (t2 - t1), 100 * bastet_profile_checkmetrics_time / (t2 - t1))); + + // sort + float i, j, k, p, s; + +/* + for(i = 0; i < 7; ++i) + { + print(sprintf("piece %s value = %d\n", substring("OJLIZST", bastet_piece[i]-1, 1), bastet_score[i])); + } +*/ + + for(i = 0; i < 7; ++i) + { + k = i; + p = bastet_piece[k]; + s = bastet_score[k]; + for(j = i + 1; j < 7; ++j) + { + if(bastet_score[j] < s) + { + k = j; + s = bastet_score[k]; + p = bastet_piece[k]; + } + } + if(k != i) + { + bastet_score[k] = bastet_score[i]; + bastet_piece[k] = bastet_piece[i]; + bastet_score[i] = s; + bastet_piece[i] = p; + } + } + + b = random(); + if(b < 0.8) + j = 0; + else if(b < 0.92) + j = 1; + else if(b < 0.98) + j = 2; + else + j = 3; + j = bastet_piece[j]; + + for(i = 0; i < 7; ++i) + { + if(i == j-1) + bastet_piecetime[i] = 0.2 * bastet_piecetime[i]; + else + bastet_piecetime[i] = 1.8 * bastet_piecetime[i] + 1000; + } + + return j; +} /* @@ -534,6 +871,7 @@ float RandomPiece() float p, q; float b; float seen; + if(self.tet_piece_bucket > 1) { p = mod(self.tet_piece_bucket, 7); @@ -574,38 +912,37 @@ float CheckMetrics(float piece, float orgx, float orgy, float rot) /*FIXDECL*/ { // check to see if the piece, if moved to the locations will overlap - float x, y; + float x, y, l; // why did I start counting from 1, damnit orgx = orgx - 1; orgy = orgy - 1; - for (y = 0; y < 5; y = y + 1) + PieceMinsMaxs(rot, piece); + if (tet_piecemins_x+orgx<1 || tet_piecemaxs_x+orgx > TET_WIDTH || tet_piecemins_y+orgy<1 || tet_piecemaxs_y+orgy> TET_LINES) + return FALSE; // ouside the level + for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1) { - for (x = 0; x < 5; x = x + 1) - { + l = GetLine(y + orgy); + if(l) + for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1) if (PieceMetric(x, y, rot, piece)) - { - if (GetSquare(x + orgx, y + orgy)) + if (GetXBlock(x + orgx, l)) return FALSE; // uhoh, gonna hit something. - if (x+orgx<1 || x+orgx > TET_WIDTH || y+orgy<1 || y+orgy> TET_LINES) - return FALSE; // ouside the level - } - } } return TRUE; } void ClearPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/ { - float x, y; // why did I start counting from 1, damnit orgx = orgx - 1; orgy = orgy - 1; - for (y = 0; y < 5; y = y + 1) + PieceMinsMaxs(rot, piece); + for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1) { - for (x = 0; x < 5; x = x + 1) + for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1) { if (PieceMetric(x, y, rot, piece)) { @@ -624,9 +961,10 @@ void CementPiece(float piece, float orgx, float orgy, float rot) /*FIXDECL*/ pcolor = mod(piece, 3) + 1; - for (y = 0; y < 5; y = y + 1) + PieceMinsMaxs(rot, piece); + for (y = tet_piecemins_y; y <= tet_piecemaxs_y; y = y + 1) { - for (x = 0; x < 5; x = x + 1) + for (x = tet_piecemins_x; x <= tet_piecemaxs_x; x = x + 1) { if (PieceMetric(x, y, rot, piece)) { @@ -725,12 +1063,21 @@ void HandleGame(float keyss) if (self.piece_type == 0) { - self.piece_pos = '5 1 0'; // that's about middle top, we count from 1 ARGH - if (self.next_piece) - self.piece_type = self.next_piece; + self.piece_pos = TET_START_PIECE_POS; // that's about middle top, we count from 1 ARGH + + if(autocvar_g_bastet) + { + self.piece_type = BastetPiece(); + self.next_piece = bastet_piece[6]; + } else - self.piece_type = RandomPiece(); - self.next_piece = RandomPiece(); + { + if (self.next_piece) + self.piece_type = self.next_piece; + else + self.piece_type = RandomPiece(); + self.next_piece = RandomPiece(); + } keyss = 0; // no movement first frame self.tet_autodown = time + 0.2; brand_new = 1; diff --git a/qcsrc/server/gamecommand.qc b/qcsrc/server/gamecommand.qc index af03b8348d..39b2665607 100644 --- a/qcsrc/server/gamecommand.qc +++ b/qcsrc/server/gamecommand.qc @@ -588,7 +588,7 @@ void EffectIndexDump() db_put(d, "TR_KNIGHTSPIKE", "1"); print("effect TR_KNIGHTSPIKE is ", ftos(particleeffectnum("TR_KNIGHTSPIKE")), "\n"); db_put(d, "TR_VORESPIKE", "1"); print("effect TR_VORESPIKE is ", ftos(particleeffectnum("TR_VORESPIKE")), "\n"); db_put(d, "TR_NEHAHRASMOKE", "1"); print("effect TR_NEHAHRASMOKE is ", ftos(particleeffectnum("TR_NEHAHRASMOKE")), "\n"); - db_put(d, "TR_XONOTICPLASMA", "1"); print("effect TR_XONOTICPLASMA is ", ftos(particleeffectnum("TR_XONOTICPLASMA")), "\n"); + db_put(d, "TR_NEXUIZPLASMA", "1"); print("effect TR_NEXUIZPLASMA is ", ftos(particleeffectnum("TR_NEXUIZPLASMA")), "\n"); db_put(d, "TR_GLOWTRAIL", "1"); print("effect TR_GLOWTRAIL is ", ftos(particleeffectnum("TR_GLOWTRAIL")), "\n"); db_put(d, "SVC_PARTICLE", "1"); print("effect SVC_PARTICLE is ", ftos(particleeffectnum("SVC_PARTICLE")), "\n"); @@ -1333,6 +1333,17 @@ void GameCommand(string command) return; } + if(argv(0) == "showtraceline") + { + vector src, dst; + src = stov(argv(1)); + dst = stov(argv(2)); + traceline(src, dst, MOVE_NORMAL, world); + trailparticles(world, particleeffectnum("TR_NEXUIZPLASMA"), src, trace_endpos); + trailparticles(world, particleeffectnum("TR_CRYLINKPLASMA"), trace_endpos, dst); + return; + } + print("Invalid command. For a list of supported commands, try sv_cmd help.\n"); } diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 479a69106f..7aa9166cf9 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -617,6 +617,7 @@ void GetCvars(float f) GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[7], "cl_weaponpriority7", W_FixWeaponOrder_AllowIncomplete); GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[8], "cl_weaponpriority8", W_FixWeaponOrder_AllowIncomplete); GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriorities[9], "cl_weaponpriority9", W_FixWeaponOrder_AllowIncomplete); + GetCvars_handleFloat(s, f, cvar_cl_weaponimpulsemode, "cl_weaponimpulsemode"); GetCvars_handleFloat(s, f, cvar_cl_autotaunt, "cl_autotaunt"); GetCvars_handleFloat(s, f, cvar_cl_noantilag, "cl_noantilag"); GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional"); diff --git a/qcsrc/server/monsters/monster_zombie.qc b/qcsrc/server/monsters/monster_zombie.qc index 0d43660aa8..9b7ad548c4 100644 --- a/qcsrc/server/monsters/monster_zombie.qc +++ b/qcsrc/server/monsters/monster_zombie.qc @@ -1,555 +1,555 @@ -//#define MONSTES_ENABLED -#ifdef MONSTES_ENABLED - -#define zombie_anim_attackleap 0 -#define zombie_anim_attackrun1 1 -#define zombie_anim_attackrun2 2 -#define zombie_anim_attackrun3 3 -#define zombie_anim_attackstanding1 4 -#define zombie_anim_attackstanding2 5 -#define zombie_anim_attackstanding3 6 -#define zombie_anim_blockend 7 -#define zombie_anim_blockstart 8 -#define zombie_anim_deathback1 9 -#define zombie_anim_deathback2 10 -#define zombie_anim_deathback3 11 -#define zombie_anim_deathfront1 12 -#define zombie_anim_deathfront2 13 -#define zombie_anim_deathfront3 14 -#define zombie_anim_deathleft1 15 -#define zombie_anim_deathleft2 16 -#define zombie_anim_deathright1 17 -#define zombie_anim_deathright2 18 -#define zombie_anim_idle 19 -#define zombie_anim_painback1 20 -#define zombie_anim_painback2 21 -#define zombie_anim_painfront1 22 -#define zombie_anim_painfront2 23 -#define zombie_anim_runbackwards 24 -#define zombie_anim_runbackwardsleft 25 -#define zombie_anim_runbackwardsright 26 -#define zombie_anim_runforward 27 -#define zombie_anim_runforwardleft 28 -#define zombie_anim_runforwardright 29 -#define zombie_anim_spawn 30 - -#define ZOMBIE_MIN '-18 -18 -25' -#define ZOMBIE_MAX '18 18 47' - -#define ZV_IDLE 10 - -#define ZV_PATH 100 -#define ZV_HUNT 200 - -#define ZV_ATTACK_FIND 10 -#define ZV_ATTACK_RUN 20 -#define ZV_ATTACK_STAND 30 - -#define ZV_PATH2 10000 - -//.entity verbs_idle; -//.entity verbs_attack; -//.entity verbs_move; - -//.float state_timeout; -//.void() monster_state; -#define MONSTERFLAG_NORESPAWN 2 - -void zombie_spawn(); - -float zombie_scoretarget(entity trg) -{ - float tmp; - vector ang1; - - if (trg.takedamage == DAMAGE_AIM) - if not (trg.flags & FL_NOTARGET) - if (trg.deadflag == DEAD_NO) - if (trg.team != self.team) - { - if((self.origin_z - trg.origin_z) < 128) - { - ang1 = normalize(self.origin - trg.origin); - tmp = vlen(ang1 - v_forward); - if(tmp > 1.5) - { - traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self); - if(trace_ent != trg) - return 0; - - return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp; - } - else if(self.enemy == trg) - return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp; - } - } - - return 0; -} - -void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - //dprint("zombie_corpse_damage\n"); - Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - - self.health -= damage; - - if(self.health < 0) - { - Violence_GibSplash(self, 1, 1, attacker); - remove(self); - } -} - -void zombie_die(vector dir) -{ - vector v; - float f; - - entity dummy; - - dummy = spawn(); - setmodel(dummy,"models/monsters/zombie.dpm"); - setorigin(dummy, self.origin); - dummy.velocity = self.velocity; - dummy.movetype = MOVETYPE_BOUNCE; - dummy.think = SUB_Remove; - dummy.nextthink = time + 3; - dummy.health = 50; - dummy.takedamage = DAMAGE_YES; - dummy.event_damage = zombie_corpse_damage; - dummy.solid = SOLID_CORPSE; - setsize(dummy,self.mins,self.maxs); - - SUB_SetFade(dummy,time + 5,2); - - - v = normalize(self.origin - dir); - f = vlen(v_forward - v) - 1; - if(f > 0.5) - dummy.frame = zombie_anim_deathfront1 + rint(random() * 2); - else if(f < 0.5) - dummy.frame = zombie_anim_deathback1 + rint(random() * 2); - else - { - f = vlen(v_right - v) - 1; - if(f > 0.5) - dummy.frame = zombie_anim_deathright1 + rint(random() * 2); - else if(f < 0.5) - dummy.frame = zombie_anim_deathleft1 + rint(random() * 2); - } - - - if(self.spawnflags & MONSTERFLAG_NORESPAWN) - { - self.think = SUB_Remove; - self.nextthink = time; - return; - } - - setmodel(self,""); - self.solid = SOLID_NOT; - self.takedamage = DAMAGE_NO; - self.event_damage = SUB_Null; - self.enemy = world; - self.think = zombie_spawn; - self.nextthink = time + cvar("g_monster_zombie_respawntime"); - self.pain_finished = self.nextthink; -} - -void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - - vector v; - float f; - - v = normalize(self.origin - hitloc); - f = vlen(v_forward - v) - 1; - - - self.health -= damage; - self.velocity = self.velocity + force; - if(self.health <= 0) - { - zombie_die(hitloc); - return; - } - - Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); - - if (damage > 50) - Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker); - if (damage > 100) - Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker); - - if (time > self.pain_finished) - { - if(f < 0.5) - { - if(random() < 0.5) - self.frame = zombie_anim_painback1; - else - self.frame = zombie_anim_painback2; - } - else - { - if(random() < 0.5) - self.frame = zombie_anim_painfront1; - else - self.frame = zombie_anim_painfront2; - } - - self.pain_finished = time + 0.36; - } -} - -.vector bvec; -.float bvec_time; - -void zombie_move() -{ - vector real_angle; - float vz, tdiff, tspeed; - - tdiff = time - self.zoomstate; - tspeed = tdiff * cvar("g_monster_zombie_turnspeed"); - vz = self.velocity_z; - self.zoomstate = time; - - if(self.bvec_time < time) - { - self.bvec_time = time + 0.2; - self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64); - } - - if(self.enemy) - self.moveto = self.enemy.origin; - else - self.moveto = self.origin + v_forward; - - self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec); - - self.angles_y = safeangle(self.angles_y); - real_angle = vectoangles(self.steerto) - self.angles; - self.angles_y += bound(-10, real_angle_y, 10); - - if(vlen(self.origin - self.moveto) > 64) - { - movelib_move_simple(v_forward ,cvar("g_monster_zombie_movespeed"),0.6); - if(time > self.pain_finished) - if(self.attack_finished_single < time) - self.frame = zombie_anim_runforward; - } - else - { - movelib_beak_simple(cvar("g_monster_zombie_stopspeed")); - if(time > self.pain_finished) - if(self.attack_finished_single < time) - self.frame = zombie_anim_idle; - } - - self.velocity_z = vz; - self.steerto = self.origin; -} - -float zombie_verb_idle_roam(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - self.moveto = v_forward * 128; - self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_idle_stand(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - self.moveto = self.origin; - self.frame = zombie_anim_idle; - self.velocity = '0 0 0'; - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_idle(float eval) -{ - switch (eval) - { - case VCM_EVAL: - - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - float t; - - t = cvar("g_monster_zombie_idle_timer_max") - cvar("g_monster_zombie_idle_timer_min"); - t = cvar("g_monster_zombie_idle_timer_min") + (random() * t); - - if(random() < 0.5) - verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self); - else - verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -float zombie_verb_attack_findtarget(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if(self.enemy) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - - entity trg, best_trg; - float trg_score, best_trg_score; - - trg = findradius(self.origin,cvar("g_monster_zombie_targetrange")); - while(trg) - { - trg_score = zombie_scoretarget(trg); - if(trg_score > best_trg_score) - { - best_trg = trg; - best_trg_score = trg_score; - } - - trg = trg.chain; - } - - if(best_trg) - { - self.enemy = best_trg; - dprint("Selected: ",best_trg.netname, " as target.\n"); - } - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_runattack_damage() -{ - entity oldself; - oldself = self; - self = self.owner; - - if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_hitrange")) - return; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) - return; - - Damage(self.enemy, self, self, cvar("g_monster_zombie_attack_run_damage"), DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * cvar("g_monster_zombie_attack_run_force")); - - self = oldself; - self.think = SUB_Remove; - self.nextthink = time; -} - -float zombie_verb_attack_run(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if not (self.enemy) - return VS_CALL_NO; - - if(self.attack_finished_single > time) - return VS_CALL_NO; - - if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_range")) - return VS_CALL_NO; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - entity pain; - pain = spawn(); - pain.owner = self; - pain.think = zombie_runattack_damage; - pain.nextthink = time + cvar("g_monster_zombie_attack_run_delay"); - - self.attack_finished_single = time + 0.7; - self.frame = zombie_anim_attackrun1 + rint(random() * 2); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_standattack_damage() -{ - //entity oldself; - //oldself = self; - //self = self.owner; - - setorigin(self,self.owner.origin + v_forward * 32); - RadiusDamage(self, self.owner, cvar("g_monster_zombie_attack_stand_damage"),cvar("g_monster_zombie_attack_stand_damage"),16,self, cvar("g_monster_zombie_attack_stand_force"),DEATH_TURRET,world); - //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity) - - - //self = oldself; - self.think = SUB_Remove; - self.nextthink = time; -} - -float zombie_verb_attack_stand(float eval) -{ - switch (eval) - { - case VCM_EVAL: - if not (self.enemy) - return VS_CALL_NO; - - if(self.attack_finished_single > time) - return VS_CALL_NO; - - if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_stand_range")) - return VS_CALL_NO; - - if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8) - return VS_CALL_NO; - - return verb.verb_static_value; - - case VCM_DO: - entity pain; - pain = spawn(); - pain.owner = self; - pain.think = zombie_runattack_damage; - pain.nextthink = time + cvar("g_monster_zombie_attack_stand_delay"); - - self.attack_finished_single = time + 0.7; - self.frame = zombie_anim_attackstanding1 + rint(random() * 1); - dprint("frame:",ftos(self.frame),"\n"); - - return VS_CALL_YES_DOING; - } - - return VS_CALL_YES_DONE; -} - -void zombie_think() -{ - self.angles_x *= -1; - makevectors(self.angles); - self.angles_x *= -1; - - if (zombie_scoretarget(self.enemy) == 0) - self.enemy = world; - - verbstack_pop(self.verbs_attack); - //verbstack_pop(self.verbs_move); - - if not (self.enemy) - verbstack_pop(self.verbs_idle); - - zombie_move(); - - if(self.enemy) - self.nextthink = time; - else - self.nextthink = time + 0.2; -} - -void zombie_spawn() -{ - setmodel(self,"models/monsters/zombie.dpm"); - - self.solid = SOLID_BBOX; - self.takedamage = DAMAGE_AIM; - self.event_damage = zombie_damage; - self.enemy = world; - self.frame = zombie_anim_spawn; - self.think = zombie_think; - self.nextthink = time + 2.1; - self.pain_finished = self.nextthink; - self.movetype = MOVETYPE_WALK; - self.health = cvar("g_monster_zombie_health"); - self.velocity = '0 0 0'; - self.angles = self.pos2; - self.moveto = self.origin; - self.flags = FL_MONSTER; - - setorigin(self,self.pos1); - setsize(self,ZOMBIE_MIN,ZOMBIE_MAX); -} - - -void spawnfunc_monster_zombie() -{ - if not(cvar("g_monsters")) - { - remove(self); - return; - } - - precache_model("models/monsters/zombie.dpm"); - - - self.verbs_idle = spawn(); - self.verbs_attack = spawn(); - - self.verbs_idle.owner = self; - self.verbs_attack.owner = self; - - self.think = zombie_spawn; - self.nextthink = time + 2; - - traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self); - - self.pos1 = trace_endpos; - self.pos2 = self.angles; - self.team = MAX_SHOT_DISTANCE -1; - - verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self); - - verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self); - verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self); - verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self); - -} - -#endif // MONSTES_ENABLED +//#define MONSTES_ENABLED +#ifdef MONSTES_ENABLED + +#define zombie_anim_attackleap 0 +#define zombie_anim_attackrun1 1 +#define zombie_anim_attackrun2 2 +#define zombie_anim_attackrun3 3 +#define zombie_anim_attackstanding1 4 +#define zombie_anim_attackstanding2 5 +#define zombie_anim_attackstanding3 6 +#define zombie_anim_blockend 7 +#define zombie_anim_blockstart 8 +#define zombie_anim_deathback1 9 +#define zombie_anim_deathback2 10 +#define zombie_anim_deathback3 11 +#define zombie_anim_deathfront1 12 +#define zombie_anim_deathfront2 13 +#define zombie_anim_deathfront3 14 +#define zombie_anim_deathleft1 15 +#define zombie_anim_deathleft2 16 +#define zombie_anim_deathright1 17 +#define zombie_anim_deathright2 18 +#define zombie_anim_idle 19 +#define zombie_anim_painback1 20 +#define zombie_anim_painback2 21 +#define zombie_anim_painfront1 22 +#define zombie_anim_painfront2 23 +#define zombie_anim_runbackwards 24 +#define zombie_anim_runbackwardsleft 25 +#define zombie_anim_runbackwardsright 26 +#define zombie_anim_runforward 27 +#define zombie_anim_runforwardleft 28 +#define zombie_anim_runforwardright 29 +#define zombie_anim_spawn 30 + +#define ZOMBIE_MIN '-18 -18 -25' +#define ZOMBIE_MAX '18 18 47' + +#define ZV_IDLE 10 + +#define ZV_PATH 100 +#define ZV_HUNT 200 + +#define ZV_ATTACK_FIND 10 +#define ZV_ATTACK_RUN 20 +#define ZV_ATTACK_STAND 30 + +#define ZV_PATH2 10000 + +//.entity verbs_idle; +//.entity verbs_attack; +//.entity verbs_move; + +//.float state_timeout; +//.void() monster_state; +#define MONSTERFLAG_NORESPAWN 2 + +void zombie_spawn(); + +float zombie_scoretarget(entity trg) +{ + float tmp; + vector ang1; + + if (trg.takedamage == DAMAGE_AIM) + if not (trg.flags & FL_NOTARGET) + if (trg.deadflag == DEAD_NO) + if (trg.team != self.team) + { + if((self.origin_z - trg.origin_z) < 128) + { + ang1 = normalize(self.origin - trg.origin); + tmp = vlen(ang1 - v_forward); + if(tmp > 1.5) + { + traceline(self.origin + '0 0 47',trg.origin + '0 0 32',MOVE_NORMAL,self); + if(trace_ent != trg) + return 0; + + return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp; + } + else if(self.enemy == trg) + return (cvar("g_monster_zombie_targetrange") - vlen(self.origin - trg.origin)) * tmp; + } + } + + return 0; +} + +void zombie_corpse_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + //dprint("zombie_corpse_damage\n"); + Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); + + self.health -= damage; + + if(self.health < 0) + { + Violence_GibSplash(self, 1, 1, attacker); + remove(self); + } +} + +void zombie_die(vector dir) +{ + vector v; + float f; + + entity dummy; + + dummy = spawn(); + setmodel(dummy,"models/monsters/zombie.dpm"); + setorigin(dummy, self.origin); + dummy.velocity = self.velocity; + dummy.movetype = MOVETYPE_BOUNCE; + dummy.think = SUB_Remove; + dummy.nextthink = time + 3; + dummy.health = 50; + dummy.takedamage = DAMAGE_YES; + dummy.event_damage = zombie_corpse_damage; + dummy.solid = SOLID_CORPSE; + setsize(dummy,self.mins,self.maxs); + + SUB_SetFade(dummy,time + 5,2); + + + v = normalize(self.origin - dir); + f = vlen(v_forward - v) - 1; + if(f > 0.5) + dummy.frame = zombie_anim_deathfront1 + rint(random() * 2); + else if(f < 0.5) + dummy.frame = zombie_anim_deathback1 + rint(random() * 2); + else + { + f = vlen(v_right - v) - 1; + if(f > 0.5) + dummy.frame = zombie_anim_deathright1 + rint(random() * 2); + else if(f < 0.5) + dummy.frame = zombie_anim_deathleft1 + rint(random() * 2); + } + + + if(self.spawnflags & MONSTERFLAG_NORESPAWN) + { + self.think = SUB_Remove; + self.nextthink = time; + return; + } + + setmodel(self,""); + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + self.event_damage = SUB_Null; + self.enemy = world; + self.think = zombie_spawn; + self.nextthink = time + cvar("g_monster_zombie_respawntime"); + self.pain_finished = self.nextthink; +} + +void zombie_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + + vector v; + float f; + + v = normalize(self.origin - hitloc); + f = vlen(v_forward - v) - 1; + + + self.health -= damage; + self.velocity = self.velocity + force; + if(self.health <= 0) + { + zombie_die(hitloc); + return; + } + + Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, self, attacker); + + if (damage > 50) + Violence_GibSplash_At(hitloc, force * -0.1, 3, 1, self, attacker); + if (damage > 100) + Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, self, attacker); + + if (time > self.pain_finished) + { + if(f < 0.5) + { + if(random() < 0.5) + self.frame = zombie_anim_painback1; + else + self.frame = zombie_anim_painback2; + } + else + { + if(random() < 0.5) + self.frame = zombie_anim_painfront1; + else + self.frame = zombie_anim_painfront2; + } + + self.pain_finished = time + 0.36; + } +} + +.vector bvec; +.float bvec_time; + +void zombie_move() +{ + vector real_angle; + float vz, tdiff, tspeed; + + tdiff = time - self.zoomstate; + tspeed = tdiff * cvar("g_monster_zombie_turnspeed"); + vz = self.velocity_z; + self.zoomstate = time; + + if(self.bvec_time < time) + { + self.bvec_time = time + 0.2; + self.bvec = steerlib_beamsteer(steerlib_attract2(self.moveto,0.5,500,0.95),512,32,34,64); + } + + if(self.enemy) + self.moveto = self.enemy.origin; + else + self.moveto = self.origin + v_forward; + + self.steerto = normalize(steerlib_attract2(self.moveto,0.5,500,0.95) + self.bvec); + + self.angles_y = safeangle(self.angles_y); + real_angle = vectoangles(self.steerto) - self.angles; + self.angles_y += bound(-10, real_angle_y, 10); + + if(vlen(self.origin - self.moveto) > 64) + { + movelib_move_simple(v_forward ,cvar("g_monster_zombie_movespeed"),0.6); + if(time > self.pain_finished) + if(self.attack_finished_single < time) + self.frame = zombie_anim_runforward; + } + else + { + movelib_beak_simple(cvar("g_monster_zombie_stopspeed")); + if(time > self.pain_finished) + if(self.attack_finished_single < time) + self.frame = zombie_anim_idle; + } + + self.velocity_z = vz; + self.steerto = self.origin; +} + +float zombie_verb_idle_roam(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + self.moveto = v_forward * 128; + self.steerto = v_forward; //steerlib_beamsteer(v_forward,512,32,34,64); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_idle_stand(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + self.moveto = self.origin; + self.frame = zombie_anim_idle; + self.velocity = '0 0 0'; + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_idle(float eval) +{ + switch (eval) + { + case VCM_EVAL: + + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + float t; + + t = cvar("g_monster_zombie_idle_timer_max") - cvar("g_monster_zombie_idle_timer_min"); + t = cvar("g_monster_zombie_idle_timer_min") + (random() * t); + + if(random() < 0.5) + verbstack_push(self.verbs_idle, zombie_verb_idle_roam, ZV_IDLE + 1, t, self); + else + verbstack_push(self.verbs_idle, zombie_verb_idle_stand, ZV_IDLE + 1, 0.1, self); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +float zombie_verb_attack_findtarget(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if(self.enemy) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + + entity trg, best_trg; + float trg_score, best_trg_score; + + trg = findradius(self.origin,cvar("g_monster_zombie_targetrange")); + while(trg) + { + trg_score = zombie_scoretarget(trg); + if(trg_score > best_trg_score) + { + best_trg = trg; + best_trg_score = trg_score; + } + + trg = trg.chain; + } + + if(best_trg) + { + self.enemy = best_trg; + dprint("Selected: ",best_trg.netname, " as target.\n"); + } + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_runattack_damage() +{ + entity oldself; + oldself = self; + self = self.owner; + + if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_hitrange")) + return; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) + return; + + Damage(self.enemy, self, self, cvar("g_monster_zombie_attack_run_damage"), DEATH_TURRET, self.enemy.origin, normalize(self.enemy.origin - self.origin) * cvar("g_monster_zombie_attack_run_force")); + + self = oldself; + self.think = SUB_Remove; + self.nextthink = time; +} + +float zombie_verb_attack_run(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if not (self.enemy) + return VS_CALL_NO; + + if(self.attack_finished_single > time) + return VS_CALL_NO; + + if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_run_range")) + return VS_CALL_NO; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.6) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + entity pain; + pain = spawn(); + pain.owner = self; + pain.think = zombie_runattack_damage; + pain.nextthink = time + cvar("g_monster_zombie_attack_run_delay"); + + self.attack_finished_single = time + 0.7; + self.frame = zombie_anim_attackrun1 + rint(random() * 2); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_standattack_damage() +{ + //entity oldself; + //oldself = self; + //self = self.owner; + + setorigin(self,self.owner.origin + v_forward * 32); + RadiusDamage(self, self.owner, cvar("g_monster_zombie_attack_stand_damage"),cvar("g_monster_zombie_attack_stand_damage"),16,self, cvar("g_monster_zombie_attack_stand_force"),DEATH_TURRET,world); + //float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity) + + + //self = oldself; + self.think = SUB_Remove; + self.nextthink = time; +} + +float zombie_verb_attack_stand(float eval) +{ + switch (eval) + { + case VCM_EVAL: + if not (self.enemy) + return VS_CALL_NO; + + if(self.attack_finished_single > time) + return VS_CALL_NO; + + if(vlen(self.origin - self.enemy.origin) > cvar("g_monster_zombie_attack_stand_range")) + return VS_CALL_NO; + + if(vlen(normalize(self.origin - self.enemy.origin) - v_forward) < 1.8) + return VS_CALL_NO; + + return verb.verb_static_value; + + case VCM_DO: + entity pain; + pain = spawn(); + pain.owner = self; + pain.think = zombie_runattack_damage; + pain.nextthink = time + cvar("g_monster_zombie_attack_stand_delay"); + + self.attack_finished_single = time + 0.7; + self.frame = zombie_anim_attackstanding1 + rint(random() * 1); + dprint("frame:",ftos(self.frame),"\n"); + + return VS_CALL_YES_DOING; + } + + return VS_CALL_YES_DONE; +} + +void zombie_think() +{ + self.angles_x *= -1; + makevectors(self.angles); + self.angles_x *= -1; + + if (zombie_scoretarget(self.enemy) == 0) + self.enemy = world; + + verbstack_pop(self.verbs_attack); + //verbstack_pop(self.verbs_move); + + if not (self.enemy) + verbstack_pop(self.verbs_idle); + + zombie_move(); + + if(self.enemy) + self.nextthink = time; + else + self.nextthink = time + 0.2; +} + +void zombie_spawn() +{ + setmodel(self,"models/monsters/zombie.dpm"); + + self.solid = SOLID_BBOX; + self.takedamage = DAMAGE_AIM; + self.event_damage = zombie_damage; + self.enemy = world; + self.frame = zombie_anim_spawn; + self.think = zombie_think; + self.nextthink = time + 2.1; + self.pain_finished = self.nextthink; + self.movetype = MOVETYPE_WALK; + self.health = cvar("g_monster_zombie_health"); + self.velocity = '0 0 0'; + self.angles = self.pos2; + self.moveto = self.origin; + self.flags = FL_MONSTER; + + setorigin(self,self.pos1); + setsize(self,ZOMBIE_MIN,ZOMBIE_MAX); +} + + +void spawnfunc_monster_zombie() +{ + if not(cvar("g_monsters")) + { + remove(self); + return; + } + + precache_model("models/monsters/zombie.dpm"); + + + self.verbs_idle = spawn(); + self.verbs_attack = spawn(); + + self.verbs_idle.owner = self; + self.verbs_attack.owner = self; + + self.think = zombie_spawn; + self.nextthink = time + 2; + + traceline(self.origin + '0 0 10', self.origin - '0 0 32', MOVE_WORLDONLY, self); + + self.pos1 = trace_endpos; + self.pos2 = self.angles; + self.team = MAX_SHOT_DISTANCE -1; + + verbstack_push(self.verbs_idle, zombie_verb_idle, ZV_IDLE,0 , self); + + verbstack_push(self.verbs_attack, zombie_verb_attack_findtarget, ZV_ATTACK_FIND,0 , self); + verbstack_push(self.verbs_attack, zombie_verb_attack_run, ZV_ATTACK_RUN,0 , self); + verbstack_push(self.verbs_attack, zombie_verb_attack_stand, ZV_ATTACK_STAND,0 , self); + +} + +#endif // MONSTES_ENABLED diff --git a/qcsrc/server/mutators/mutator_dodging.qc b/qcsrc/server/mutators/mutator_dodging.qc index ba8e021eab..d3b8e6d64e 100644 --- a/qcsrc/server/mutators/mutator_dodging.qc +++ b/qcsrc/server/mutators/mutator_dodging.qc @@ -19,6 +19,11 @@ // set to 1 to indicate dodging has started.. reset by physics hook after dodge has been done.. .float dodging_action; +// This is the velocity gain to be added over the ramp time. +// It will decrease from frame to frame during dodging_action = 1 +// until it's 0. +.float dodging_velocity_gain; + // the jump part of the dodge cannot be ramped .float dodging_single_action; @@ -31,6 +36,7 @@ void dodging_Initialize() { self.last_LEFT_KEY_time = 0; self.last_dodging_time = 0; self.dodging_action = 0; + self.dodging_velocity_gain = 0; self.dodging_single_action = 0; self.dodging_direction_x = 0; self.dodging_direction_y = 0; @@ -45,10 +51,26 @@ MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) { // print("dodging_PlayerPhysics\n"); float common_factor; + float new_velocity_gain; + float velocity_difference; + float clean_up_and_do_nothing; + + new_velocity_gain = 0; + clean_up_and_do_nothing = 0; - // is dodging enabled at all? if not, do nothing.. if (g_dodging == 0) + clean_up_and_do_nothing = 1; + + // when swimming, no dodging allowed.. + if (self.waterlevel >= WATERLEVEL_SWIMMING) + clean_up_and_do_nothing = 1; + + if (clean_up_and_do_nothing != 0) { + self.dodging_action = 0; + self.dodging_direction_x = 0; + self.dodging_direction_y = 0; return 0; + } // make sure v_up, v_right and v_forward are sane makevectors(self.angles); @@ -62,6 +84,11 @@ MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) { if (common_factor > 1) common_factor = 1; + new_velocity_gain = self.dodging_velocity_gain - (common_factor * cvar("sv_dodging_horiz_speed")); + if (new_velocity_gain < 0) + new_velocity_gain = 0; + + velocity_difference = self.dodging_velocity_gain - new_velocity_gain; // ramp up dodging speed by adding some velocity each frame.. TODO: do it! :D if (self.dodging_action == 1) { @@ -70,12 +97,16 @@ MUTATOR_HOOKFUNCTION(dodging_PlayerPhysics) { self.velocity = self.velocity - + (common_factor * (self.dodging_direction_y * cvar("sv_dodging_horiz_speed")) * v_right) - + (common_factor * (self.dodging_direction_x * cvar("sv_dodging_horiz_speed")) * v_forward); + + ((self.dodging_direction_y * velocity_difference) * v_right) + + ((self.dodging_direction_x * velocity_difference) * v_forward); + + self.dodging_velocity_gain = self.dodging_velocity_gain - velocity_difference; } // the up part of the dodge is a single shot action if (self.dodging_single_action == 1) { + self.flags &~= FL_ONGROUND; + self.velocity = self.velocity + (cvar("sv_dodging_up_speed") * v_up); @@ -135,20 +166,7 @@ float check_close_to_wall(float threshold) { } float check_close_to_ground(float threshold) { - vector trace_start; - vector trace_end; - - // determine height above ground is below a threshold - trace_start = self.origin; - trace_end = self.origin - (1000*v_up); - - tracebox(trace_start, self.mins, self.maxs, trace_end, TRUE, self); - - // check if the trace hit anything at all - if (trace_fraction > 1) - return 0; - - if(self.origin_z - trace_endpos_z < threshold) + if (self.flags & FL_ONGROUND) return 1; return 0; @@ -159,16 +177,18 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { // print("dodging_PlayerPhysics\n"); float length; + float tap_direction_x; + float tap_direction_y; + + tap_direction_x = 0; + tap_direction_y = 0; + float dodge_detected; if (g_dodging == 0) return 0; dodge_detected = 0; - // no dodging and jumping at the same time.. - if (self.BUTTON_JUMP) - return 0; - // first check if the last dodge is far enough back in time so we can dodge again if ((time - self.last_dodging_time) < cvar("sv_dodging_delay")) return 0; @@ -181,8 +201,8 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { // is this a state change? if (!(self.pressedkeys & KEY_FORWARD)) { if ((time - self.last_FORWARD_KEY_time) < self.cvar_cl_dodging_timeout) { + tap_direction_x = 1.0; dodge_detected = 1; - self.dodging_direction_x = 1.0; } self.last_FORWARD_KEY_time = time; } @@ -191,9 +211,9 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { if (self.movement_x < 0) { // is this a state change? if (!(self.pressedkeys & KEY_BACKWARD)) { + tap_direction_x = -1.0; if ((time - self.last_BACKWARD_KEY_time) < self.cvar_cl_dodging_timeout) { dodge_detected = 1; - self.dodging_direction_x = -1.0; } self.last_BACKWARD_KEY_time = time; } @@ -202,9 +222,9 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { if (self.movement_y > 0) { // is this a state change? if (!(self.pressedkeys & KEY_RIGHT)) { + tap_direction_y = 1.0; if ((time - self.last_RIGHT_KEY_time) < self.cvar_cl_dodging_timeout) { dodge_detected = 1; - self.dodging_direction_y = 1.0; } self.last_RIGHT_KEY_time = time; } @@ -213,9 +233,9 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { if (self.movement_y < 0) { // is this a state change? if (!(self.pressedkeys & KEY_LEFT)) { + tap_direction_y = -1.0; if ((time - self.last_LEFT_KEY_time) < self.cvar_cl_dodging_timeout) { dodge_detected = 1; - self.dodging_direction_y = -1.0; } self.last_LEFT_KEY_time = time; } @@ -224,14 +244,16 @@ MUTATOR_HOOKFUNCTION(dodging_GetPressedKeys) { if (dodge_detected == 1) { - if (self.movement_z > 0) - self.movement_z = 0; - self.last_dodging_time = time; self.dodging_action = 1; self.dodging_single_action = 1; + self.dodging_velocity_gain = cvar("sv_dodging_horiz_speed"); + + self.dodging_direction_x = tap_direction_x; + self.dodging_direction_y = tap_direction_y; + // normalize the dodging_direction vector.. (unlike UT99) XD length = length + self.dodging_direction_x * self.dodging_direction_x; length = length + self.dodging_direction_y * self.dodging_direction_y; diff --git a/qcsrc/server/teamplay.qc b/qcsrc/server/teamplay.qc index 805711a4bc..0798b29b29 100644 --- a/qcsrc/server/teamplay.qc +++ b/qcsrc/server/teamplay.qc @@ -625,7 +625,11 @@ void CheckAllowedTeams (entity for_whom) c1 = c2 = c3 = c4 = -1; cb1 = cb2 = cb3 = cb4 = 0; - if(g_onslaught) + if(cvar("g_campaign") && for_whom && clienttype(for_whom) == CLIENTTYPE_REAL) + { + c1 = 0; // only allow RED team for player joining + } + else if(g_onslaught) { // onslaught is special head = findchain(classname, "onslaught_generator"); @@ -800,7 +804,9 @@ float FindSmallestTeam(entity pl, float ignore_pl) if(totalteams <= 1) { - if(g_domination) + if(cvar("g_campaign") && pl && clienttype(pl) == CLIENTTYPE_REAL) + return 1; // special case for campaign and player joining + else if(g_domination) error("Too few teams available for domination\n"); else if(g_ctf) error("Too few teams available for ctf\n"); @@ -847,9 +853,9 @@ float FindSmallestTeam(entity pl, float ignore_pl) { // 1: use team count, if equal prefer own team if(c1 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM1) / 512.0); - if(c2 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM2) / 512.0); - if(c3 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM3) / 512.0); - if(c4 >= 0) RandomSelection_Add(world, 1, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM4) / 512.0); + if(c2 >= 0) RandomSelection_Add(world, 2, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM2) / 512.0); + if(c3 >= 0) RandomSelection_Add(world, 3, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM3) / 512.0); + if(c4 >= 0) RandomSelection_Add(world, 4, string_null, 1, (maxc - c1) + (self.team == COLOR_TEAM4) / 512.0); } else if(balance_type == 3) { diff --git a/qcsrc/server/vehicles/racer.qc b/qcsrc/server/vehicles/racer.qc index 3e36dc807b..b929c425f3 100644 --- a/qcsrc/server/vehicles/racer.qc +++ b/qcsrc/server/vehicles/racer.qc @@ -22,6 +22,8 @@ float racer_turnroll; float racer_speed_forward; float racer_speed_strafe; +float racer_afterburn_cost; + float jetfromtag_power; float jetfromtag_normpower; vector jetfromtag_origin; @@ -41,6 +43,8 @@ void racer_loadsettings() racer_speed_forward = cvar("g_vehicle_racer_speed_forward"); racer_speed_strafe = cvar("g_vehicle_racer_speed_strafe"); + racer_afterburn_cost = cvar("g_vehicle_racer_afterburn_cost"); + racer_healthmax = cvar("g_vehicle_racer_health"); racer_shieldmax = cvar("g_vehicle_racer_shield"); racer_energymax = cvar("g_vehicle_racer_energy"); @@ -203,7 +207,6 @@ void racer_fire_cannon(string tagname) // FIXME this uses prydon cursor v = normalize(self.owner.cursor_trace_endpos - bolt.origin); v_forward_z = v_z * 0.5; - //v_forward_z *= 0.5; bolt.velocity = v_forward * cvar("g_vehicle_racer_laser_speed"); @@ -355,7 +358,6 @@ float racer_pplug() float ftmp, ftmp2; vector df; - if(cvar("g_vehicle_racer_reload")) { racer_loadsettings(); @@ -395,13 +397,13 @@ float racer_pplug() ftmp = racer_turnspeed * sys_frametime; ftmp2 = ftmp * -1; - ftmp = bound(ftmp2,shortangle_f(player.v_angle_y - racer.angles_y,racer.angles_y),ftmp); + ftmp = bound(ftmp2, shortangle_f(player.v_angle_y - racer.angles_y, racer.angles_y), ftmp); ftmp2 = safeangle(racer.angles_y + ftmp); // Roll - ftmp = bound(-45,shortangle_f(player.v_angle_z + ((racer.angles_y - ftmp2) * racer_turnroll), racer.angles_z),45); + ftmp = bound(-45, shortangle_f(player.v_angle_z + ((racer.angles_y - ftmp2) * racer_turnroll), racer.angles_z), 45); ftmp = safeangle(racer.angles_z + ftmp); - racer.angles_z = bound(-85,ftmp,85); + racer.angles_z = bound(-85, ftmp, 85); // Turn racer.angles_y = ftmp2; @@ -414,7 +416,7 @@ float racer_pplug() racer.angles_x = safeangle(racer.angles_x + ftmp); racer.angles_x *= -1; - df = racer.velocity * -1; + df = racer.velocity * -0.5; if(player.movement_x != 0) { @@ -438,12 +440,11 @@ float racer_pplug() // Afterburn - //if (jetfromtag_groundcontact) if (player.BUTTON_JUMP) - if(racer.vehicle_energy >= (cvar("g_vehicle_racer_speed_afterburn_cost") * frametime)) + if(racer.vehicle_energy >= (racer_afterburn_cost * frametime)) { racer.wait = time + cvar("g_vehicle_racer_energy_usepause"); - racer.vehicle_energy -= cvar("g_vehicle_racer_speed_afterburn_cost") * frametime; + racer.vehicle_energy -= racer_afterburn_cost * frametime; df += (v_forward * cvar("g_vehicle_racer_speed_afterburn")); } @@ -494,8 +495,6 @@ float racer_pplug() } player.vehicle_reload1 = (time - racer.lip) / (racer.delay-racer.lip); - //player.vehicle_energy = racer.vehicle_energy; - vehicle_stdproc_shiledregen(racer_shieldmax, frametime); vehicle_stdproc_healthregen(racer_healthmax, frametime); @@ -715,16 +714,6 @@ void racer_touch() racer_enter(); } -/* -float racer_customizeentityforclient() -{ - if(self.deadflag == DEAD_DEAD) - return FALSE; - - return TRUE; -} -*/ - void racer_spawn() { self.think = racer_spawnthink; diff --git a/qcsrc/server/vehicles/raptor.qc b/qcsrc/server/vehicles/raptor.qc new file mode 100644 index 0000000000..d7f4de67aa --- /dev/null +++ b/qcsrc/server/vehicles/raptor.qc @@ -0,0 +1,892 @@ +#define RAPTOR_MIN '-40 -40 0' +#define RAPTOR_MAX '40 40 40' + +float raptor_movestyle; +float raptor_turnspeed; +float raptor_turnroll; +float raptor_pitchspeed; +float raptor_speed_forward; +float raptor_speed_strafe; +float raptor_speed_up; +float raptor_speed_down; + +float raptor_bomblet_waves; +float raptor_bomblet_wavefirst; +float raptor_bomblet_wavenext; +float raptor_bomblet_wawespread; +float raptor_bomblets; +float raptor_bomblet_damage; +float raptor_bomblet_edgedamage; +float raptor_bomblet_radius; +float raptor_bomblet_force; +float raptor_bombs_refire; + +float raptor_beam_dps; +float raptor_beam_fops; +float raptor_beam_aps; +float raptor_beam_size; +float raptor_beam_leangth; +float raptor_beam_refire; + +float raptor_shield_max; +float raptor_shield_regen; + +float raptor_health_max; +float raptor_health_regen; + +float raptor_energy_max; +float raptor_energy_regen; + +void raptor_spawn(); +void raptor_return(); +float raptor_pplug(); +float raptor_takeoff(); +float raptor_land(); + +.entity bomb1; +.entity bomb2; + +float raptor_altitude(float amax) +{ + tracebox(self.origin, self.mins, self.maxs, '0 0 -1' * amax, TRUE, self); + if(trace_fraction == 1) + return amax+1; + else + return vlen(self.origin - trace_endpos); +} + +void raptor_loadsettings() +{ + raptor_movestyle = CCVAR("_movestyle"); + raptor_turnspeed = CCVAR("_turnspeed"); + raptor_turnroll = CCVAR("_turnroll"); + raptor_pitchspeed = CCVAR("_pitchspeed"); + raptor_speed_forward = CCVAR("_speed_forward"); + raptor_speed_strafe = CCVAR("_speed_strafe"); + raptor_speed_up = CCVAR("_speed_up"); + raptor_speed_down = CCVAR("_speed_down"); + + raptor_bomblet_waves = CCVAR("_bomblet_waves "); + raptor_bomblet_wavefirst = CCVAR("_bomblet_wavefirst"); + raptor_bomblet_wavenext = CCVAR("_bomblet_wavenext"); + raptor_bomblet_wawespread = CCVAR("_bomblet_wawespread"); + raptor_bomblets = CCVAR("_bomblets"); + raptor_bomblet_damage = CCVAR("_bomblet_damage"); + raptor_bomblet_edgedamage = CCVAR("_bomblet_edgedamage"); + raptor_bomblet_radius = CCVAR("_bomblet_radius"); + raptor_bomblet_force = CCVAR("_bomblet_force "); + raptor_bombs_refire = CCVAR("_bombs_refire"); + + raptor_beam_dps = CCVAR("_beam_dps"); + raptor_beam_fops = CCVAR("_beam_fops"); + raptor_beam_aps = CCVAR("_beam_aps"); + raptor_beam_size = CCVAR("_beam_size"); + raptor_beam_leangth = CCVAR("_beam_length"); + raptor_beam_refire = CCVAR("_beam_refire"); + + raptor_shield_max = CCVAR("_shield_max"); + raptor_shield_regen = CCVAR("_shield_regen"); + + raptor_health_max = CCVAR("_health_max"); + raptor_health_regen = CCVAR("_health_regen"); + + raptor_energy_max = CCVAR("_energy_max"); + raptor_energy_regen = CCVAR("_energy_regen"); +} + +void raptor_bombs_return() +{ + self.owner.bomb1.alpha = 1; + self.owner.bomb2.alpha = 1; + remove(self); +} + +void raptor_bomblet_boom() +{ + if(other.enemy == self.enemy) + return; + + pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1); + RadiusDamage (self, self.enemy, raptor_bomblet_damage, raptor_bomblet_edgedamage, raptor_bomblet_radius, world, raptor_bomblet_force, DEATH_SBROCKET, world); + remove(self); +} + +void raptor_bomb_burst() +{ + self.angles = vectoangles(self.velocity); + + if(self.cnt < time) + { + entity bomblet; + float i,v; + vector d; + + makevectors(self.angles); + v = vlen(self.velocity) + random(); + d = normalize(self.velocity); + pointparticles(particleeffectnum("rocket_explode"), self.origin, '0 0 0', 1); + + for(i = 0; i < raptor_bomblets; ++i) + { + + bomblet = spawn(); + setorigin(bomblet,self.origin); + + setmodel(bomblet,"models/vehicles/raptor_bomb.dpm"); + bomblet.scale = 0.5; + + bomblet.owner = self.owner; + bomblet.enemy = self.enemy; + + bomblet.solid = SOLID_TRIGGER; + bomblet.movetype = MOVETYPE_BOUNCE; + bomblet.touch = raptor_bomblet_boom; + + bomblet.think = raptor_bomblet_boom; + bomblet.nextthink = time + 5; + + //bomblet.modelflags = MF_ROCKET; + bomblet.modelflags = MF_GRENADE; + + bomblet.velocity = normalize(d + randomvec() * raptor_bomblet_wawespread) * v; + + bomblet.angles = vectoangles(bomblet.velocity); + } + + self.wait -= 1; + if(self.wait <= 0) + { + remove(self); + return; + } + + self.cnt = time + raptor_bomblet_wavenext; + } + + self.nextthink = time; +} + +void raptor_bomb_touch() +{ + raptor_bomb_burst(); +} + +void raptor_bombdrop() +{ + entity bomb_1, bomb_2; + + self.bomb1.alpha = 0.25; + self.bomb2.alpha = 0.25; + + bomb_1 = spawn(); + bomb_2 = spawn(); + + setmodel(bomb_1,"models/vehicles/raptor_bomb.dpm"); + setmodel(bomb_2,"models/vehicles/raptor_bomb.dpm"); + + setorigin(bomb_1, gettaginfo(self, gettagindex(self, "bombmount_left"))); + setorigin(bomb_2, gettaginfo(self, gettagindex(self, "bombmount_right"))); + + bomb_1.movetype = bomb_2.movetype = MOVETYPE_TOSS; + bomb_1.velocity = bomb_2.velocity = self.velocity; + bomb_1.touch = bomb_2.touch = raptor_bomb_touch; + bomb_1.think = bomb_2.think = raptor_bomb_burst; + bomb_1.nextthink = bomb_2.nextthink = time; + bomb_1.cnt = bomb_2.cnt = time + raptor_bomblet_wavefirst; + bomb_1.wait = bomb_2.wait = raptor_bomblet_waves; + + bomb_1.avelocity = bomb_2.avelocity = '0 0 180'; + bomb_1.owner = bomb_2.owner = self; + bomb_1.enemy = bomb_2.enemy = self.owner; + bomb_1.angles = bomb_2.angles = self.angles; + bomb_1.solid = bomb_2.solid = SOLID_BBOX; + + bomb_1 = spawn(); + bomb_1.owner = self; + bomb_1.think = raptor_bombs_return; + bomb_1.nextthink = time + raptor_bombs_refire; +} + +void raptor_animator_think() +{ + self.owner.frame += 1; + if(self.owner.frame == self.cnt) + remove(self); + else + self.nextthink = time + self.wait; +} + +void raptor_setanim(float start, float end, float length) +{ + entity ani; + if(self.tur_head.enemy) + ani = self.tur_head.enemy; + else + ani = spawn(); + + self.tur_head.enemy = ani; + ani.owner = self; + self.frame = start; + ani.cnt = end; + ani.wait = sys_frametime / length; + ani.think = raptor_animator_think; + ani.nextthink = time + ani.wait; +} + +void raptor_beam (vector start, vector end, vector smin, vector smax, float bforce, float f_dmg, float deathtype) + +{ + vector hitloc, force, endpoint, dir; + entity ent; + + dir = normalize(end - start); + force = dir * bforce; + + // go a little bit into the wall because we need to hit this wall later + end = end + dir; + + // trace multiple times until we hit a wall, each obstacle will be made unsolid. + // note down which entities were hit so we can damage them later + while (1) + { + tracebox(start, smin, smax, end, FALSE, world); + + // if it is world we can't hurt it so stop now + if (trace_ent == world || trace_fraction == 1) + break; + + if (trace_ent.solid == SOLID_BSP) + break; + + // make the entity non-solid so we can hit the next one + trace_ent.railgunhit = TRUE; + trace_ent.railgunhitloc = end; + trace_ent.railgunhitsolidbackup = trace_ent.solid; + + // make the entity non-solid + trace_ent.solid = SOLID_NOT; + } + + endpoint = trace_endpos; + + // find all the entities the railgun hit and hurt them + ent = findchainfloat(railgunhit, TRUE); + while (ent) + { + // get the details we need to call the damage function + ent.solid = ent.railgunhitsolidbackup; + hitloc = ent.railgunhitloc; + ent.railgunhitloc = '0 0 0'; + ent.railgunhitsolidbackup = SOLID_NOT; + ent.railgunhit = FALSE; + + // apply the damage + if (ent.takedamage) + Damage (ent, self, self, f_dmg, deathtype, hitloc, force); + + ent = ent.chain; + } + trace_endpos = endpoint; +} + + +void raptor_enter() +{ + // Remove this when bots know how to use vehicles + if (clienttype(other) != CLIENTTYPE_REAL) + return; + + if(teamplay) + if(self.team) + if(self.team != other.team) + return; + + self.owner = other; + self.switchweapon = other.switchweapon; + + self.event_damage = vehicle_stdproc_damage; + self.colormap = self.owner.colormap; + self.vehicle_hudmodel.viewmodelforclient = self.owner; + self.nextthink = 0; + self.owner.angles = self.angles; + self.owner.takedamage = DAMAGE_NO; + self.owner.solid = SOLID_NOT; + self.owner.movetype = MOVETYPE_NOCLIP; + self.owner.alpha = -1; + self.owner.PlayerPhysplug = raptor_takeoff; + self.owner.vehicle = self; + self.owner.event_damage = SUB_Null; + self.owner.hud = HUD_RAPTOR; + self.owner.vehicle_health = self.vehicle_health / raptor_health_max; + self.owner.vehicle_shield = self.vehicle_shield / raptor_shield_max; + self.owner.view_ofs = '0 0 1'; + self.owner.vehicle_ammo1 = self.vehicle_ammo1; + self.owner.vehicle_ammo2 = self.vehicle_ammo2; + self.owner.vehicle_reload1 = self.vehicle_reload1; + self.owner.vehicle_reload2 = self.vehicle_reload2; + + other.flags &~= FL_ONGROUND; + self.flags &~= FL_ONGROUND; + + self.frame = 0; + raptor_setanim(0, 25, 1); + + self.team = self.owner.team; + self.flags -= FL_NOTARGET; + + self.velocity = '0 0 1'; + + setorigin(other,self.origin + '0 0 32'); + other.velocity = self.velocity; + + other.flags &~= FL_ONGROUND; + msg_entity = other; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity( MSG_ONE, self.vehicle_viewport); + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES + WriteAngle(MSG_ONE, self.angles_x * -1); // tilt + WriteAngle(MSG_ONE, self.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll +} + +void raptor_exit(float eject) +{ + self.colormap = 1024; + self.flags = FL_NOTARGET; + + if not (self.owner) + return; + + msg_entity = self.owner; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity( MSG_ONE, self.owner); + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES + WriteAngle(MSG_ONE, 0); // tilt + WriteAngle(MSG_ONE, self.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + + if (self.deadflag == DEAD_NO) + { + //self.think = racer_exitthink; + self.nextthink = time; + } + + self.owner.takedamage = DAMAGE_AIM; + self.owner.solid = SOLID_SLIDEBOX; + self.owner.movetype = MOVETYPE_WALK; + + setsize(self.owner,PL_MIN,PL_MAX); + + self.owner.effects &~= EF_NODRAW; + self.owner.alpha = 1; + self.owner.PlayerPhysplug = SUB_Null; + self.owner.vehicle = world; + self.owner.view_ofs = PL_VIEW_OFS; + self.owner.event_damage = PlayerDamage; + self.owner.hud = HUD_NORMAL; + //self.exteriormodeltoclient = self; + + self.vehicle_hudmodel.viewmodelforclient = self; + + if(eject) + { + makevectors(self.angles); + setorigin(self.owner,self.origin + v_forward * 100); + self.owner.velocity = (v_up + v_forward * 0.25) * 750; + } + else + { + self.owner.velocity = (v_forward) * -150; + setorigin(self.owner,self.origin - v_forward * 128); + } + + self.owner = world; + + if (self.deadflag != DEAD_NO) + { + entity ret; + ret = spawn(); + ret.enemy = self; + ret.think = raptor_return; + ret.nextthink = time + cvar("g_vehicle_racer_respawntime"); + } +} + + +float raptor_pplug() +{ + entity player, vhic; + float ftmp, ftmp2, energy_used; + vector df; + + + if(cvar("g_vehicle_raptor_reload")) + { + raptor_loadsettings(); + cvar_set("g_vehicle_raptor_reload","0"); + } + + player = self; + vhic = self.vehicle; + self = vhic; + + if(player.BUTTON_USE) + { + self = vhic; + raptor_exit(0); + self = player; + return 0; + } + + if(vhic.deadflag != DEAD_NO) + { + self = player; + player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; + return 1; + } + + vhic.angles_x *= -1; + // Rotate Body + ftmp = raptor_turnspeed * sys_frametime; + + ftmp = bound(-ftmp, shortangle_f(player.v_angle_y - vhic.angles_y, vhic.angles_y), ftmp); + + // Roll + //ftmp = bound(-90,shortangle_f(player.v_angle_z + ((vhic.angles_y - ftmp2) * raptor_turnroll), vhic.angles_z),90); + //ftmp = safeangle(vhic.angles_z + ftmp); + //vhic.angles_z = ftmp; + + // Turn + vhic.angles_y = safeangle(vhic.angles_y + ftmp); + + // Pitch Body + ftmp = raptor_pitchspeed * sys_frametime; + + ftmp = bound(-ftmp, shortangle_f(player.v_angle_x - vhic.angles_x,vhic.angles_x), ftmp); + + vhic.angles_x = bound(-60,safeangle(vhic.angles_x + ftmp),60); + vhic.angles_x *= -1; + + if(raptor_movestyle == 1) + { + ftmp = vhic.angles_z; + vhic.angles_z = 0; + ftmp2 = vhic.angles_x; + vhic.angles_x = 0; + fixedmakevectors(vhic.angles); + vhic.angles_z = ftmp; + vhic.angles_x = ftmp2; + } + else + fixedmakevectors(vhic.angles); + + df = vhic.velocity * -1; + + if(player.movement_x != 0) + { + if(player.movement_x > 0) + df += v_forward * raptor_speed_forward; + else if(player.movement_x < 0) + df -= v_forward * raptor_speed_forward; + } + + if(player.movement_y != 0) + { + if(player.movement_y < 0) + df -= v_right * raptor_speed_strafe; + else if(player.movement_y > 0) + df += v_right * raptor_speed_strafe; + + vhic.angles_z = bound(-30,vhic.angles_z + (player.movement_y / raptor_speed_strafe),30); + } + else + { + vhic.angles_z *= 0.95; + if(vhic.angles_z >= -1 && vhic.angles_z <= -1) + vhic.angles_z = 0; + } + + if(player.BUTTON_CROUCH) + df -= v_up * raptor_speed_down; + else if (player.BUTTON_JUMP) + df += v_up * raptor_speed_up; + //else + //df_z = vhic.velocity_z * -1; + + vhic.velocity += df * frametime; + player.velocity = player.movement = vhic.velocity; + setorigin(player,vhic.origin + '0 0 32'); + + // Aim the gunz + vector target_angle, move_angle, org1, org2, targ; + + makevectors(player.v_angle); + + //targ = (vhic.origin + player.view_ofs) + v_forward * MAX_SHOT_DISTANCE; + targ = player.cursor_trace_endpos; + + org1 = gettaginfo(vhic.gun1,gettagindex(vhic.gun1, "fire1")); + org2 = gettaginfo(vhic.gun2,gettagindex(vhic.gun2, "fire1")); + + traceline(vhic.origin + player.view_ofs, targ, FALSE, vhic); + targ = trace_endpos; + + // Find the direction + target_angle = vectoangles(normalize(targ - org1)); // And make a angle + + // Find the diffrence between where we currently aim and where we want to aim + move_angle = target_angle - (vhic.angles + vhic.gun1.angles); + move_angle = shortangle_vxy(move_angle,(vhic.angles + vhic.gun1.angles)); + vhic.gun1.angles_x = bound(-10, move_angle_x + vhic.gun1.angles_x, 10); + vhic.gun1.angles_y = bound(-15, move_angle_y + vhic.gun1.angles_y, 15); + + // Find the direction + target_angle = vectoangles(normalize(targ - org2)); // And make a angle + + move_angle = target_angle - (vhic.angles + vhic.gun2.angles); + move_angle = shortangle_vxy(move_angle,(vhic.angles + vhic.gun2.angles)); + vhic.gun2.angles_x = bound(-15,move_angle_x + vhic.gun2.angles_x,15); + vhic.gun2.angles_y = bound(-20,move_angle_y + vhic.gun2.angles_y,20); + + if(player.BUTTON_ATCK) + if(vhic.vehicle_energy > (raptor_beam_aps * sys_frametime)) + { + vector start; + self = player; + + start = gettaginfo(vhic.gun1, gettagindex(vhic.gun1, "fire1")); + traceline(start, start + v_forward * MAX_SHOT_DISTANCE, TRUE, player); + te_lightning1(vhic.gun1, start, trace_endpos); + raptor_beam(start, trace_endpos, '-1 -1 -1' * raptor_beam_size, '1 1 1' * raptor_beam_size, raptor_beam_fops * sys_frametime, raptor_beam_dps * sys_frametime, DEATH_SBROCKET); + + + start = gettaginfo(vhic.gun2, gettagindex(vhic.gun2, "fire1")); + traceline(start, start + v_forward * MAX_SHOT_DISTANCE, TRUE, player); + te_lightning1(vhic.gun2, start, trace_endpos); + raptor_beam(start, trace_endpos, '-1 -1 -1' * raptor_beam_size, '1 1 1' * raptor_beam_size, raptor_beam_fops * sys_frametime, raptor_beam_dps * sys_frametime, DEATH_SBROCKET); + + self = vhic; + + vhic.vehicle_energy -= raptor_beam_aps * sys_frametime; + vhic.cnt = time + 1; + } + + if(vhic.cnt < time) + vhic.vehicle_energy = min(vhic.vehicle_energy += raptor_energy_regen * frametime, raptor_energy_max); + + player.vehicle_energy = vhic.vehicle_energy / raptor_energy_max; + + + if(player.BUTTON_ATCK2) + if(time > vhic.delay) + { + raptor_bombdrop(); + vhic.delay = time + raptor_bombs_refire; + } + + player.BUTTON_ATCK = player.BUTTON_ATCK2 = player.BUTTON_CROUCH = 0; + vehicle_stdproc_shiledregen(raptor_shield_max, frametime); + vehicle_stdproc_healthregen(raptor_health_max, frametime); + + self = player; + + return 1; +} + +float raptor_takeoff() +{ + entity player, vhic; + + if(self.vehicle.frame < 25) + return 1; + + player = self; + vhic = self.vehicle; + self = vhic; + + if(raptor_altitude(512) <= 256) + { + vhic.velocity_z = min(vhic.velocity_z * 1.5, 256); + } + else + { + player.PlayerPhysplug = raptor_pplug; + } + + player.BUTTON_CROUCH = player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; + self = player; + + return 1; +} + +float raptor_land() +{ + return 0; +} + +void raptor_return() +{ + pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1); + self.enemy.think = raptor_spawn; + self.enemy.nextthink = time; + remove(self); +} + +void raptor_think() +{ +} + +void raptor_touch() +{ + if(self.owner) + { + if(vlen(self.velocity) == 0) + return; + + if(other.classname != "player") + return; + + return; + } + + if(other.classname != "player") + return; + + if(other.deadflag != DEAD_NO) + return; + + if(other.vehicle != world) + return; + + raptor_enter(); +} + +void raptor_die() +{ + self.health = 0; + self.event_damage = SUB_Null; + self.iscreature = FALSE; + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + //self.touch = racer_dietouch; + self.deadflag = DEAD_DYING; + self.movetype = MOVETYPE_BOUNCE; + self.wait = time; + + pointparticles(particleeffectnum("rocket_explode"), findbetterlocation (self.origin, 16), '0 0 0', 1); + + self.velocity += '0 0 128'; + + if(random() < 0.5) + self.avelocity_z = 45; + else + self.avelocity_z = -45; + + self.colormod = '-0.5 -0.5 -0.5'; + + self.think = raptor_spawn; + self.nextthink = time + 5; +} + +void raptor_spawn() +{ + self.flags = FL_NOTARGET; + self.effects = 0; + + self.vehicle_health = raptor_health_max; + self.vehicle_shield = raptor_shield_max; + + self.event_damage = vehicle_stdproc_damage; + self.touch = raptor_touch; + + self.iscreature = TRUE; + self.movetype = MOVETYPE_FLY; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + + self.alpha = 1; + self.colormap = 1024; + self.deadflag = DEAD_NO; + self.bot_attack = TRUE; + + self.colormod = '1 1 1'; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + + self.vehicle_energy = 1; + self.vehicle_hudmodel.viewmodelforclient = self; + + setorigin(self, self.pos1); + self.angles = self.pos2; + + setsize(self,RAPTOR_MIN ,RAPTOR_MAX ); + pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1); + self.delay = time; +} + +float raptor_customizeentityforclient() +{ + if(self.deadflag == DEAD_DEAD) + return FALSE; + + /* + if(other == self.owner) + self.alpha = -1; + else + self.alpha = 1; + */ + + return TRUE; +} + +void raptor_dinit() +{ + + if (self.netname == "") + self.netname = "Raptor"; + + setorigin(self, self.origin); + + self.frame = 0; + + setmodel(self,"models/vehicles/raptor.dpm"); + + self.bomb1 = spawn(); + self.bomb2 = spawn(); + + setmodel(self.bomb1,"models/vehicles/raptor_bomb.dpm"); + setmodel(self.bomb2,"models/vehicles/raptor_bomb.dpm"); + + setattachment(self.bomb1, self,"bombmount_left"); + setattachment(self.bomb2, self,"bombmount_right"); + + + if not (self.vehicle_hudmodel) + { + self.vehicle_hudmodel = spawn(); + setmodel(self.vehicle_hudmodel, "models/vehicles/raptor_cockpit.dpm"); + //setattachment(self.vehicle_hudmodel, self, "tag_viewport"); + setattachment(self.vehicle_hudmodel, self, "tag_hud"); + } + + if not (self.vehicle_viewport) + { + self.vehicle_viewport = spawn(); + setmodel (self.vehicle_viewport, "null"); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, "tag_camera"); + } + + if not (self.gun1) + { + self.gun1 = spawn(); + setmodel(self.gun1, "models/vehicles/raptor_gun.dpm"); + setattachment(self.gun1, self, "gunmount_left"); + } + + if not (self.gun2) + { + self.gun2 = spawn(); + setmodel(self.gun2, "models/vehicles/raptor_gun.dpm"); + setattachment(self.gun2, self, "gunmount_right"); + } + + self.tur_head = spawn(); + self.pos1 = self.origin; + self.pos2 = self.angles; + + self.vehicle_hudmodel.viewmodelforclient = self; + self.customizeentityforclient = raptor_customizeentityforclient; + + self.vehicle_die = raptor_die; + self.vehicle_exit = raptor_exit; + + + entity spinner; + spinner = spawn(); + spinner.owner = self; + setmodel(spinner,"models/vehicles/spinner.dpm"); + setattachment(spinner, self, "engine_left"); + spinner.movetype = MOVETYPE_NOCLIP; + spinner.avelocity = '0 90 0'; + + spinner = spawn(); + spinner.owner = self; + setmodel(spinner,"models/vehicles/spinner.dpm"); + setattachment(spinner, self, "engine_right"); + spinner.movetype = MOVETYPE_NOCLIP; + spinner.avelocity = '0 -90 0'; + + addstat(STAT_HUD, AS_INT, hud); + addstat(STAT_VEHICLESTAT_HEALTH, AS_FLOAT, vehicle_health); + addstat(STAT_VEHICLESTAT_SHIELD, AS_FLOAT, vehicle_shield); + addstat(STAT_VEHICLESTAT_ENERGY, AS_FLOAT, vehicle_energy); + + addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1); + addstat(STAT_VEHICLESTAT_RELOAD1, AS_FLOAT, vehicle_reload1); + + addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); + addstat(STAT_VEHICLESTAT_RELOAD2, AS_FLOAT, vehicle_reload2); + + raptor_spawn(); +} + +void spawnfunc_vehicle_raptor2() +{ + self.cvar_basename = "g_vehicle_raptor"; + raptor_loadsettings(); + + self.vehicle_flags = VHF_HASSHIELD | VHF_SHIELDREGEN; + + traceline(self.origin, self.origin - '0 0 2048', MOVE_WORLDONLY, self); + if(trace_startsolid) + { + dprint("WARNING: vehicle_raptor placed in solid\n"); + traceline(self.origin + '0 0 512' ,self.origin - '0 0 2048',MOVE_WORLDONLY,self); + if(trace_startsolid || trace_fraction == 1.0) + { + dprint("ERROR: vehicle_raptor placed in more then 512 units into solid\n"); + remove(self); + return; + } + } + + if(trace_fraction != 1.0) + setorigin(self,trace_endpos + '0 0 8'); + else + dprint("WARNING: vehicle_racer placed more then 2048 units above ground.\n"); + + precache_model ("models/vehicles/raptor.dpm"); + precache_model ("models/vehicles/raptor_gun.dpm"); + precache_model ("models/vehicles/spinner.dpm"); + precache_model ("models/vehicles/raptor_cockpit.dpm"); + precache_model ("models/vehicles/raptor_bomb.dpm"); + + + self.think = raptor_dinit; + self.nextthink = time + 1; +} + + +void spawnfunc_vehicle_raptor() +{ + entity iqm,dpm,md3; + + precache_model ("models/vehicles/test.iqm"); + precache_model ("models/vehicles/test.dpm"); + precache_model ("models/vehicles/test.md3"); + + iqm = spawn(); + dpm = spawn(); + md3 = spawn(); + iqm.scale = md3.scale = dpm.scale = 10; + + //setmodel(iqm,"models/vehicles/test.iqm"); + //setmodel(dpm,"models/vehicles/test.dpm"); + setmodel(md3,"models/vehicles/test.md3"); + + setorigin(iqm, self.origin + '0 0 16'); + setorigin(dpm, self.origin + '0 20 32'); + setorigin(iqm, self.origin + '0 40 48'); +} diff --git a/qcsrc/server/vehicles/spiderbot.qc b/qcsrc/server/vehicles/spiderbot.qc index 56caf6ff37..32049c8626 100644 --- a/qcsrc/server/vehicles/spiderbot.qc +++ b/qcsrc/server/vehicles/spiderbot.qc @@ -50,55 +50,43 @@ void spiderbot_rocket_touch() spiderbot_rocket_explode(); } -void spiderbot_rocket_guided() +void spiderbot_rocket_unguided() { vector newdir,olddir; self.nextthink = time; - if (self.owner.deadflag != DEAD_NO || self.cnt < time) - { - spiderbot_rocket_explode(); - return; - } - if not (self.owner.vehicle) - { - UpdateCSQCProjectile(self); - return; - } olddir = normalize(self.velocity); - crosshair_trace(self.owner); - newdir = normalize(trace_endpos - self.origin) + randomvec() * cvar("g_vehicle_spiderbot_rocket_noise"); + newdir = normalize(self.pos1 - self.origin) + randomvec() * cvar("g_vehicle_spiderbot_rocket_noise"); self.velocity = normalize(olddir + newdir * cvar("g_vehicle_spiderbot_rocket_turnrate")) * cvar("g_vehicle_spiderbot_rocket_speed"); UpdateCSQCProjectile(self); + + if (self.owner.deadflag != DEAD_NO || self.cnt < time) + spiderbot_rocket_explode(); + } -void spiderbot_rocket_unguided() +void spiderbot_rocket_guided() { - vector newdir,olddir; + vector newdir, olddir; self.nextthink = time; - if (self.owner.deadflag != DEAD_NO || self.cnt < time) - { - spiderbot_rocket_explode(); - return; - } if not (self.owner.vehicle) - { - UpdateCSQCProjectile(self); - return; - } + self.think = spiderbot_rocket_unguided; + crosshair_trace(self.owner); olddir = normalize(self.velocity); - newdir = normalize(self.pos1 - self.origin) + randomvec() * cvar("g_vehicle_spiderbot_rocket_noise"); + newdir = normalize(trace_endpos - self.origin) + randomvec() * cvar("g_vehicle_spiderbot_rocket_noise"); self.velocity = normalize(olddir + newdir * cvar("g_vehicle_spiderbot_rocket_turnrate")) * cvar("g_vehicle_spiderbot_rocket_speed"); UpdateCSQCProjectile(self); -} + if (self.owner.deadflag != DEAD_NO || self.cnt < time) + spiderbot_rocket_explode(); +} void spiderbot_rocket_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { @@ -311,13 +299,6 @@ void spiderbot_miniguns_do() return; } } -#define SBS_IDLE 0 -#define SBS_JUMP 1 -#define SBS_WALK 2 -#define SBS_BACK 3 -#define SBS_LEFT 4 -#define SBS_RIGHT 5 -.float state; float spiderbot_pplug() { @@ -325,6 +306,10 @@ float spiderbot_pplug() entity player,spider; float ftmp; + if not (self.owner) + { + } + player = self; spider = self.vehicle; @@ -366,8 +351,9 @@ float spiderbot_pplug() self = spider; if(spider.flags & FL_ONGROUND) { - if(player.BUTTON_JUMP) + if(player.BUTTON_JUMP && self.tur_head.wait < time) { + self.tur_head.wait = time + 2; player.BUTTON_JUMP = 0; spider.velocity = v_forward * 700 + v_up * 600; spider.frame = 4; @@ -432,7 +418,6 @@ float spiderbot_pplug() else player.vehicle_reload2 = 1 - ((spider.gun2.cnt - time) / spider.attack_finished_single); - //setorigin(spider,spider.origin); setorigin(player,spider.origin + '0 0 64'); player.velocity = spider.velocity; @@ -444,10 +429,7 @@ float spiderbot_pplug() void spiderbot_think() { if(self.flags & FL_ONGROUND) - { movelib_beak_simple(cvar("g_vehicle_spiderbot_speed_stop")); - //movelib_groundalign4point(300,100); - } self.nextthink = time; } @@ -648,6 +630,7 @@ void spiderbot_spawn() setsize(self,spiderbot_MIN,spiderbot_MAX); + self.owner = world; self.velocity = '0 0 0'; self.vehicle_health = CCVAR("_health"); self.vehicle_shield = CCVAR("_shield"); diff --git a/qcsrc/server/vehicles/vehicles.qh b/qcsrc/server/vehicles/vehicles.qh index ea2d440688..192d83f6da 100644 --- a/qcsrc/server/vehicles/vehicles.qh +++ b/qcsrc/server/vehicles/vehicles.qh @@ -36,8 +36,8 @@ float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80 .entity vehicle_viewport; .entity vehicle_hudmodel; -.float anim_start; -.float anim_end; +//.float anim_start; +//.float anim_end; .float dmg_time; @@ -51,7 +51,9 @@ var .void() vehicle_spawn; //var .float(float message) vehicle_message; #include "vehicles.qc" + #include "spiderbot.qc" #include "racer.qc" +#include "raptor.qc" #endif diff --git a/qcsrc/server/w_campingrifle.qc b/qcsrc/server/w_campingrifle.qc index 39e271886d..e831376963 100644 --- a/qcsrc/server/w_campingrifle.qc +++ b/qcsrc/server/w_campingrifle.qc @@ -239,84 +239,3 @@ float w_campingrifle(float req) return TRUE; }; #endif -Ç[Kg|º^fÆ,9Þ@ª w_deathtypestring = "sniped themself somehow"; - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - { - if(w_deathtype & HITTYPE_BOUNCE) - w_deathtypestring = "failed to hide from #'s bullet hail"; - else - w_deathtypestring = "died in #'s bullet hail"; - } - else - { - if(w_deathtype & HITTYPE_BOUNCE) - { - // TODO special headshot message here too? - w_deathtypestring = "failed to hide from #'s rifle"; - } - else - { - if(w_deathtype & HITTYPE_HEADSHOT) - w_deathtypestring = "got hit in the head by #"; - else - w_deathtypestring = "was sniped by #"; - } - } - } - else if (req == WR_RELOAD) - { - W_CampingRifle_Reload(); - } - else if (req == WR_RESETPLAYER) - { - self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime"); - self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity"); - W_CampingRifle_CheckMaxBullets(FALSE); - } - return TRUE; -}; -#endif -tì‡{³ ío¸?~á…Ñ w_deathtypestring = "sniped themself somehow"; - } - else if (req == WR_KILLMESSAGE) - { - if(w_deathtype & HITTYPE_SECONDARY) - { - if(w_deathtype & HITTYPE_BOUNCE) - w_deathtypestring = "failed to hide from #'s bullet hail"; - else - w_deathtypestring = "died in #'s bullet hail"; - } - else - { - if(w_deathtype & HITTYPE_BOUNCE) - { - // TODO special headshot message here too? - w_deathtypestring = "failed to hide from #'s rifle"; - } - else - { - if(w_deathtype & HITTYPE_HEADSHOT) - w_deathtypestring = "got hit in the head by #"; - else - w_deathtypestring = "was sniped by #"; - } - } - } - else if (req == WR_RELOAD) - { - W_CampingRifle_Reload(); - } - else if (req == WR_RESETPLAYER) - { - self.campingrifle_accumulator = time - cvar("g_balance_campingrifle_bursttime"); - self.campingrifle_bulletcounter = cvar("g_balance_campingrifle_magazinecapacity"); - W_CampingRifle_CheckMaxBullets(FALSE); - } - return TRUE; -}; -#endif - \ No newline at end of file diff --git a/qcsrc/xonotic-gamecode.workspace b/qcsrc/xonotic-gamecode.workspace new file mode 100644 index 0000000000..3f4a59a303 --- /dev/null +++ b/qcsrc/xonotic-gamecode.workspace @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/scripts/entities.def b/scripts/entities.def deleted file mode 100644 index 8e6b9b5bfa..0000000000 --- a/scripts/entities.def +++ /dev/null @@ -1,1777 +0,0 @@ -/*QUAKED _skybox (0.77 0.88 1.0) (-4 -4 -4) (4 4 4) -Compiler-only entity that specifies a the origin of a sky box (a wholly contained, separate area of the map), similar to some games' portal skies. When compiled with Q3Map2, the sky box surfaces will be visible from any place where sky is normally visible. It will cast shadows on the normal parts of the map, and can be used with cloud layers and other effects. As it is compiler-only, it can't "scale up" entities in its box. -To use this, carve a small box in some larger structure on your map, place this entity inside that box hole, and make a small version on what should be seen in the sky there. --------- KEYS -------- -angle: rotation angle of the sky surfaces. -angles: Individual control of PITCH, YAW, and ROLL (default 0 0 0). -_scale: scaling factor (default 64), good values are between 50 and 300, depending on the map. -*/ - -/*QUAKED dom_controlpoint (.3 .3 1) (-16 -16 -16) (16 16 16) -Domination control point -In order to get Domination working well in your map, you need to place dom_team and dom_controlpoint entities. You *must* have at least 3 dom_team entities - 2 minimum teams and one blank one (empty netname and no team). You can have up to 4 teams (5 dom_team entities). --------- KEYS -------- -message: message to be displayed to all players when this point is captured, preceded by the team's name. This defaults to " has captured a control point". You can specify different names for each point, for example " has captured the Lava Room". -wait: How often this point gives its controlling team frags. -frags: How many frags this point gives each wait cycle. --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -zbqry="zbqryf/qbzvangvba/qbz_hapynvzrq.zq3" - -*/ - -/*QUAKED dom_team (.3 .3 1) (-16 -16 -16) (16 16 16) -Domination team. -In order to get Domination working well in your map, you need to place dom_team and dom_controlpoint entities. You *must* have at least 3 dom_team entities - 2 minimum teams and one blank one (empty netname and no team). You can have up to 4 teams (5 dom_team entities). --------- KEYS -------- -netname: name of team (Red Team). Set to "" or don't define for the required blank team. -cnt: color of the team. See the "Helpful Extras" section for info. -model: When this team captures control points, the points turn to this model. If this is the neutral team, points start out as this model. -noise: Sound to be played on the control point when it's captured. Only players nearby will hear it. -noise1: Sound to be played to all players when the control point is captured. Also good for an announcer voice ("Red Team has captured a control point") -*/ - -/*QUAKED func_assault_destructible (.5 0 .5) ? - - - - - - - - NOSPLASH -This is a brush model which can be damaged. Once triggered it's active and will happily receive damage players inflict upon it. Once all health is consumed it'll disappear and trigger the targeted entity/entities. As damage is received the brush model will be tinted in an increasingly visible flavor of red to give visible feedback. --------- KEYS -------- -health: The damage this trigger can take -target: The entity/entities to be triggered once this entity gets invisible -targetname: The name other entities can use to target this entity -mdl: particle effect name to show when destroyed -count: particle effect multiplier -mdl_dead: optional replacement model to show when destroyed -debris: names of debris models to show when destroyed, separated by spaces -noise: sound to play when destroyed -dmg: damage to deal to the environment when destroyed -dmg_edge: edge damage to deal to the environment when destroyed -dmg_radius: damage radius -dmg_force: damage force -message: death message when a player gets hit by the explosion -message2: death message when someone gets pushed into this (default: "was pushed into an explosion by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -debrismovetype: way in which the debris moves: one of 1 = ANGLENOCLIP, 2 = ANGLECLIP, 3 = WALK, 4 = STEP, 5 = FLY, 6 = TOSS, 7 = PUSH, 8 = NOCLIP, 9 = FLYMISSILE, 10 = BOUNCE, 11 = BOUNCEMISSILE -debrissolid: solidity of the debris: one of 0 = NOT, 1 = TRIGGER, 2 = BBOX, 3 = SLIDEBOX, 4 = BSP, 5 = CORPSE -debrisvelocity: initial velocity vector of the debris (static part) -debrisvelocityjitter: initial velocity vector of the debris (random part) -debrisavelocityjitter: initial angular velocity vector of the debris (random part) -debristime: time till the debris fades (average) -debristimejitter: time till the debris fades (random part) -debrisfadetime: how long debris takes to fade -debrisdamageforcescale: how much debris is affected by damage force (e.g. explosions) -debrisskin: skin number of debris --------- SPAWNFLAGS -------- -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED func_assault_wall (.5 0 .5) ? -Brush model that will disappear once the targeted target_objective is fulfilled. This can be used to restrict access to parts of the map until a certain objective has been conquered. --------- KEYS -------- -target: targetname of a target_objective -*/ - -/*QUAKED func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS -Solid entity that oscillates back and forth in a linear motion. By default, it will have an amount of displacement in either direction equal to the dimension of the brush in the axis in which it's bobbing. Entity bobs on the Z axis (up-down) by default. It can also emit sound if the "noise" key is set. Will crush the player when blocked. --------- KEYS -------- -speed: amount of time in seconds for one complete oscillation cycle (default 4). -height: sets the amount of travel of the oscillation movement (default 32). -phase: sets the start offset of the oscillation cycle. Values must be 0 < phase < 1. Any integer phase value is the same as no offset (default 0). -noise: path/name of .wav or .ogg file to play. Use looping sounds only (e.g. sound/world/drone6.wav - See Notes). -dmg: damage a player who gets crushed by it receives -dmgtime: interval to apply dmg to a player who is s in the way -message: death message when a player gets crushed -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) --------- SPAWNFLAGS -------- -X_AXIS: entity will bob along the X axis. -Y_AXIS: entity will bob along the Y axis. -*/ - -/*QUAKED func_button (0 .5 .8) ? - - - - - - - - NOSPLASH -When a button is touched by a player, it moves in the direction set by the "angle" key, triggers all its targets, stays pressed by an amount of time set by the "wait" key, then returns to it's original position where it can be operated again. --------- KEYS -------- -angle: determines the direction in which the button will move (up = -1, down = -2). -target: all entities with a matching targetname will be triggered. -target2: all entities with a matching targetname will be triggered. -target3: all entities with a matching targetname will be triggered. -target4: all entities with a matching targetname will be triggered. -speed: speed of button's displacement (default 40). -wait: number of seconds button stays pressed (default 1, -1 = return immediately). -lip: lip remaining at end of move (default 4 units). -health: (default 0) if set to any non-zero value, the button must take damage (any amount) to activate. --------- SPAWNFLAGS -------- -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED func_door (0 .5 .8) ? START_OPEN - DOOR_DONT_LINK - - TOGGLE - - NOSPLASH -Normal sliding door entity. By default, the door will activate when player walks close to it or when damage is inflicted to it. -If DOOR_DONT_LINK is not set, the door will be linked with all doors it touches. Note however that for linked doors to work properly, it is necessary that ALL linked doors have SOME volume of common area (that is, there must be a point that is part of ALL doors). --------- KEYS -------- -message: is printed when the door is touched if it is a trigger door and it hasn't been fired yet, or death message if dmg is set -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -angle: determines the opening direction -targetname: if set, no touch field will be spawned and a remote button or trigger field activates the door. -health: if set, door must be shot open -speed: movement speed (100 default) -wait: wait before returning (3 default, -1 = never return) -lip: lip remaining at end of move (8 default) -dmg: damage to inflict when blocked (when triggered and someone is in the way) -sounds: when 1, use default door sounds -noise1: sound when the door opens -noise2: sound when the door closes --------- SPAWNFLAGS -------- -START_OPEN: causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or damage triggered doors). -DOOR_DONT_LINK: the door won't link with another door it touches -TOGGLE: causes the door to wait in both the start and end states for a trigger event. -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED func_door_rotating (0 .5 .8) ? START_OPEN BIDIR DOOR_DONT_LINK BIDIR_IN_DOWN - TOGGLE X_AXIS Y_AXIS NOSPLASH -Normal rotating door entity that opens by rotating around an axis (default: Z). Use an origin brush to specify the rotation axis. -By default, the door will activate when player walks close to it or when damage is inflicted to it. -If DOOR_DONT_LINK is not set, the door will be linked with all doors it touches. -BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor. -The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction -must have set trigger_reverse to 1. -BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side. --------- KEYS -------- -message: is printed when the door is touched if it is a trigger door and it hasn't been fired yet, or death message if dmg is set -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -angle: determines the destination angle for opening. negative values reverse the direction (90 default) -targetname: if set, no touch field will be spawned and a remote button or trigger field activates the door. -health: if set, door must be shot open -speed: speed to rotate (in degrees per second) -wait: wait before returning (3 default, -1 = never return) -dmg: damage to inflict when blocked (when triggered and someone is in the way) -sounds: when 1, use default door sounds -noise1: sound when the door opens -noise2: sound when the door closes --------- SPAWNFLAGS -------- -START_OPEN: causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or damage triggered doors). -DOOR_DONT_LINK: the door won't link with another door it touches -TOGGLE: causes the door to wait in both the start and end states for a trigger event. -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED func_door_secret (0 .5 .8) ? OPEN_ONCE 1ST_LEFT 1ST_DOWN NO_SHOOT ALWAYS_SHOOT -Basic secret door. Slides back, then to the side. Angle determines direction. Opens when targeted or when shot; does not create its own trigger field like func_door does. --------- KEYS -------- -wait: # of seconds before coming back -key1: first entity key with one-line description -key2: second entity key with one-line description -t_width: override WIDTH to move back (or height if going down) -t_length: override LENGTH to move sideways -dmg: damage to inflict when blocked (2 default) -message: text to display when activating the door, or death message if dmg is set -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -noise1: sound when opening backwards or closing -noise2: sound when opening sideways -noise3: sound when stopping --------- SPAWNFLAGS -------- -OPEN_ONCE: only work once, then stay open -1ST_LEFT: 1st move is left of arrow -1ST_DOWN: 1st move is down from arrow -NO_SHOOT: never respond to shots -ALWAYS_SHOOT: even if targetname is set, respond to shots -*/ - -/*QUAKED func_group (0 .5 .8) ? -This is not an entity as such. It is strictly an editor utility to group world brushes and patches together for convenience (selecting, moving, copying, etc). You cannot group entities with this. --------- Q3MAP2 KEYS -------- -_lightmapscale: light map resolution factor -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. --------- KEYS -------- -_indexmap: Path/name for the TGA file used to guide the mapping of textures on the terrain surface. -_layers: number of unique root shaders that will be use on the terrain. -_shader: Path to the metashader used to assign textures to the terrain entity. Note: Omit the "textures/" prefix. -_offsets: space separated list of height offsets for the index map -*/ - -/*QUAKED func_ladder (0 .5 .8) ? -a ladder, need i say no more -grab a trigger brush and put it in front of the part that you want the player to climb -*/ - -/*QUAKED func_plat (0 .5 .8) ? - - CRUSH -Rising platform the player can ride to reach higher places. Plats must always be drawn in the raised position, so they will operate and be lighted correctly but they spawn in the lowered position. The plat will stay in the raised position until the player steps off. --------- KEYS -------- -speed: determines how fast the plat moves (default 150). -lip: lip remaining at end of move (default 16). Has no effect if "height" is set. -height: if set, this will determine the total amount of vertical travel of the plat. -dmg: damage to inflict on player when he blocks operation of plat. Plat will reverse direction when blocked. -targetname: if set, the trigger that points to this will lower the plat each time it fires. The plat lowers and lifts someone up later. -sounds: 2 for alternate sound set, -1 for silence, or use the fields below -sound1: platform starts moving sound -sound2: platform stop sound -message: kill message, when someone gets killed by this plat -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) --------- SPAWNFLAGS -------- -CRUSH: crush players hit by the platform instantly --------- NOTES -------- -By default, the total amount of vertical travel of a platform is implicitly determined by the overall vertical size of the brushes of which it's made minus the lip value. But if the "height" key is used, then the total amount of vertical travel of the plat will be exactly that value regardless of the shape and size of the plat and regardless of the value of the "lip" key. Using the "height" key is the best method for any kind of platforms and the only possible one for thin plats which need to travel vertical distances many times their own thickness. Setting the origin key is simply an alternate method to using an origin brush. When using the model2 key, the origin point of the model will correspond to the origin point defined by either the origin brush or the origin coordinate value. -*/ - -/*QUAKED func_rain (0 .5 .8) ? -This is an invisible area like a trigger, which rain falls inside of. --------- KEYS -------- -velocity: falling direction (should be something like '0 0 -700', use the X and Y velocity for wind) -cnt: sets color of rain in the Quake palette (default 12 - white) -count: adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000 -*/ - -/*QUAKED func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS -Brush entity that spins in place on one axis (default Z). Use an origin brush to specify the rotation axis. -To rotate around another axis, make a func_wall with an explicit avelocity given. --------- KEYS -------- -speed: speed to rotate (in degrees per second) -noise: path/name of looping .wav file to play. -dmg: Do this much dmg every .dmgtime interval when blocked -dmgtime: See above. (0.25s default) -message: kill message when crushed by this -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) --------- SPAWNFLAGS -------- -X_AXIS: rotate around the X axis -Y_AXIS: rotate around the Y axis -*/ - -/*QUAKED func_snow (0 .5 .8) ? -This is an invisible area like a trigger, which snow falls inside of. --------- KEYS -------- -velocity: falling direction (should be something like '0 0 -300', use the X and Y velocity for wind) -cnt: sets color of snow in the Quake palette (default 12 - white) -count: adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000 -*/ - -/*QUAKED func_stardust (.5 .5 .5) (-8 -8 -8) (8 8 8) -Point entity with EF_STARDUST applied. This will spawn a particle cloud with mostly golden particles. Used as eye-candy. -*/ - -/*QUAKED func_train (0 .5 .8) ? -Trains are moving solids that follow a cycle of path_corner entities. Origin brushes are NOT supported; they use the "mins" corner as reference (that is, lowest x, y, and z coordinates). -At each node, the train's mins corner hits exactly the path_corner. -Trains always start on in the game. -Trains do not damage the played when blocked. -Trains cannot emit sound. -Trains are not trigger-able or toggle-able. -Trains cannot be block-stopped just by getting in their way, the player must be wedged between the train and another obstacle to block it. --------- KEYS -------- -speed: default/initial speed of train (default 100 or overridden by speed value of targeted path_corner) -target: targetname of first path_corner to move to at the default speed; ideally, this path_corner shall be exactly where the train starts -noise: path/name of .wav or .ogg file to play while moving. Use looping sounds only (e.g. sound/world/drone6.wav - See Notes). -dmg: damage a player who gets crushed by it receives -dmgtime: interval to apply dmg to a player who is s in the way -message: death message when a player gets crushed -message2: death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -*/ - -/*QUAKED info_location (1 1 0) (-8 -8 -8) (8 8 8) -Location for use by the %l escape in "say" messages. -The closest "visible" info_location entity is chosen to find the right location name for a point. --------- KEYS -------- -netname: name of location, possibly with color codes -*/ - -/*QUAKED info_notnull (0 .5 0) (-8 -8 -8) (8 8 8) -Entity that does nothing, but may be targeted (e.g. to use its position) --------- KEYS -------- -targetname: must match the target key of entity that uses this for pointing. -*/ - -/*QUAKED info_null (0 .5 0) (-8 -8 -8) (8 8 8) -Aiming target for q3map2-internal entities like _decal or light. Removes itself when loaded, so it can NOT be used for in-game stuff! --------- KEYS -------- -targetname: the entity that requires an aiming direction points to this. -*/ - -/*QUAKED info_player_attacker (1 0.5 0) (-16 -16 -24) (16 16 45) -Attacking team's player spawning location in Assault. Should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -target: this should point to a target_objective to decide when this spawning point is active. -target2: trigger all entities with this targetname when someone spawns -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_deathmatch (0 1 0) (-16 -16 -24) (16 16 45) -Normal player spawning location in game types without team spawns. Should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -target: trigger all entities with this targetname when someone spawns -targetname: when targeted by a func_button, pressing the button will assign the spawn point to the team of the activator as an additional spawn point, or reassign it if it was already assigned. Also used to assign spawn points to Onslaught control points. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_defender (.5 .5 .5) (-16 -16 -24) (16 16 45) -Defending team's player spawning location in Assault. Should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -target: this should point to a target_objective to decide when this spawning point is active. -target2: trigger all entities with this targetname when someone spawns -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_team1 (1 0 0) (-16 -16 -24) (16 16 45) -Red team's player spawning location in e.g. CTF and Onslaught. Should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -target: trigger all entities with this targetname when someone spawns -targetname: when targeted by a func_button, pressing the button will reassign the spawn point to the team of the activator. If a team has no more spawn point left, it immediately loses. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_team2 (0 0 1) (-16 -16 -24) (16 16 45) -Blue team's player spawning location in e.g. CTF and Onslaught. Should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -target: trigger all entities with this targetname when someone spawns -targetname: when targeted by a func_button, pressing the button will reassign the spawn point to the team of the activator. If a team has no more spawn point left, it immediately loses. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_team3 (1 1 0) (-16 -16 -24) (16 16 45) -Yellow team's player spawning location, but there is no game mode to use this yet. Anyway, should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -target: trigger all entities with this targetname when someone spawns -targetname: when targeted by a func_button, pressing the button will reassign the spawn point to the team of the activator. If a team has no more spawn point left, it immediately loses. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED info_player_team4 (1 0 1) (-16 -16 -24) (16 16 45) -Pink team's player spawning location, but there is no game mode to use this yet. Anyway, should touch the floor, but not the walls, and should point where the player should look when he spawns there. --------- KEYS -------- -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -target: trigger all entities with this targetname when someone spawns -targetname: when targeted by a func_button, pressing the button will reassign the spawn point to the team of the activator. If a team has no more spawn point left, it immediately loses. -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED item_armor_large (.4 .8 .4) (-30 -30 0) (30 30 32) FLOATING -Large Armor (default 100 armor points) --------- KEYS -------- -respawntime: time till it respawns (default: 30) -armorvalue: amount of armor it gives (default: 100 (g_pickup_armorlarge)) -max_armorvalue: max of armor it increases to (default: 999 (g_pickup_armorlarge_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_a25.md3" -*/ - -/*QUAKED item_armor_big (.4 .8 .4) (-30 -30 0) (30 30 32) FLOATING -Big Armor (default 50 armor points) --------- KEYS -------- -respawntime: time till it respawns (default: 20) -armorvalue: amount of armor it gives (default: 50 (g_pickup_armorlarge)) -max_armorvalue: max of armor it increases to (default: 999 (g_pickup_armorlarge_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_a50.md3" -*/ - -/*QUAKED item_armor_medium (.4 .8 .4) (-30 -30 0) (30 30 32) FLOATING -Medium Armor (default 25 armor points) --------- KEYS -------- -respawntime: time till it respawns (default: 20) -armorvalue: amount of armor it gives (default: 25 (g_pickup_armormedium)) -max_armorvalue: max of armor it increases to (default: 999 (g_pickup_armormedium_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_armormedium.md3" -*/ - -/*QUAKED item_armor_small (.4 .8 .4) (-30 -30 0) (30 30 32) FLOATING -Small Armor (default 5 armor points) --------- KEYS -------- -respawntime: time till it respawns (default: 15) -armorvalue: amount of armor it gives (default: 5 (g_pickup_armorsmall)) -max_armorvalue: max of armor it increases to (default: 999 (g_pickup_armorsmall_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_a1.md3" -*/ - -/*QUAKED item_bullets (.3 .3 1) (-30 -30 0) (30 30 32) FLOATING -Machine Gun ammo --------- KEYS -------- -ammo_nails: bullets gained by this item (if unset, g_pickup_nails is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/a_bullets.md3" -*/ - -/*QUAKED item_cells (.3 .3 1) (-30 -30 0) (30 30 32) FLOATING -Nex, Electro and Crylink ammo --------- KEYS -------- -ammo_cells: cells gained by this item (if unset, g_pickup_cells is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/a_cells.md3" -*/ - -/*QUAKED item_flag_team1 (1 0 0) (-32 -32 0) (32 32 74) -CTF flag for team one (Red). Use more than one if you really insist. --------- KEYS -------- -model: model to use -scale: scaling factor (DO set this when using your own model!) -noise: sound played when flag is picked up -noise1: sound played when flag is returned -noise2: sound played when flag is captured -noise3: sound played when flag is lost in the field and respawns itself --------- ZBQRY SBE ENQVNAG BAYL - QB ABG FRG GUVF NF N XRL -------- -zbqry="zbqryf/pgs/enqvnag/synt_erq_enqvnag.zq3" -*/ - -/*QUAKED item_flag_team2 (0 0 1) (-32 -32 0) (32 32 74) -CTF flag for team two (Blue). Use more than one if you really insist. --------- KEYS -------- -model: model to use -scale: scaling factor (DO set this when using your own model!) -noise: sound played when flag is picked up -noise1: sound played when flag is returned -noise2: sound played when flag is captured -noise3: sound played when flag is lost in the field and respawns itself --------- ZBQRY SBE ENQVNAG BAYL - QB ABG FRG GUVF NF N XRL -------- -zbqry="zbqryf/pgs/enqvnag/synt_oyhr_enqvnag.zq3" -*/ - -/*QUAKED item_health_large (.9 .3 .3) (-30 -30 0) (30 30 48) FLOATING -Large Health (default 50 health points) --------- KEYS -------- -respawntime: time till it respawns (default: 20) -health: amount of health it gives (default: 50 (g_pickup_healthlarge)) -max_health: max of health it increases to (default: 999 (g_pickup_healthlarge_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_h50.md3" -*/ - -/*QUAKED item_health_medium (.9 .3 .3) (-30 -30 0) (30 30 48) FLOATING -Medium Health (default 25 health points) --------- KEYS -------- -respawntime: time till it respawns (default: 15) -health: amount of health it gives (default: 25 (g_pickup_healthmedium)) -max_health: max of health it increases to (default: 999 (g_pickup_healthmedium_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_h25.md3" -*/ - -/*QUAKED item_health_mega (.9 .3 .3) (-30 -30 0) (30 30 48) FLOATING -Mega Health (default 100 health points) -In Minstagib, this randomly turns into either an invisibility, an extra lives or a speed power-up with a default respawn time of 120. --------- KEYS -------- -respawntime: time till it respawns (default: 30) -health: amount of health it gives (default: 100 (g_pickup_healthmega)) -max_health: max of health it increases to (default: 999 (g_pickup_healthmega_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_h100.md3" -*/ - -/*QUAKED item_health_small (.9 .3 .3) (-30 -30 0) (30 30 48) FLOATING -Small Health (default 5 health points) --------- KEYS -------- -respawntime: time till it respawns (default: 15) -health: amount of health it gives (default: 5 (g_pickup_healthsmall)) -max_health: max of health it increases to (default: 5 (g_pickup_healthsmall_max)) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_h1.md3" -*/ - -/*QUAKED item_invincible (.3 .3 1) (-30 -30 0) (30 30 48) FLOATING -Strong Shield -In Minstagib, this randomly turns into either an invisibility, an extra lives or a speed power-up with a default respawn time of 120. --------- KEYS -------- -respawntime: time till it respawns (default: 120) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_invincible.md3" -*/ - -/*QUAKED item_minst_cells (.3 .3 1) (-30 -30 0) (30 30 32) FLOATING -Minstagib ammo. -Always contains 5 (g_minstagib_ammo_drop) shots. -It only appears when playing Minstagib and prevents auto-replacement of weapon_nex & weapon_rocketlauncher when used. --------- KEYS -------- -respawntime: time till it respawns (default: 45) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/a_cells.md3" -*/ - -/*QUAKED item_rockets (.3 .3 1) (-30 -30 0) (30 30 32) FLOATING -Rocket Launcher, Hagar and Mortar ammo --------- KEYS -------- -ammo_rockets: rockets gained by this item (if unset, g_pickup_rockets is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/a_rockets.md3" -*/ - -/*QUAKED item_shells (.3 .3 1) (-30 -30 0) (30 30 32) FLOATING -Shotgun ammo --------- KEYS -------- -ammo_shells: shells gained by this item (if unset, g_pickup_shells is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/a_shells.md3" -*/ - -/*QUAKED item_strength (.3 .3 1) (-30 -30 0) (30 30 48) FLOATING -Strength aka Quad damage -In Minstagib, this randomly turns into either an invisibility, an extra lives or a speed power-up with a default respawn time of 120. --------- KEYS -------- -respawntime: time till it respawns (default: 120) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/items/g_strength.md3" -*/ - -/*QUAKED light (.65 .65 1) (-8 -8 -8) (8 8 8) LINEAR NOANGLE - - NOGRIDLIGHT -Non-displayed point light source. The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights. -Maximum intensity (in a radius 16 sphere around the light): regular lights have light/256, linear lights have light/8000-16*fade. -Falloff radius to a negligible light amount: regular lights have light have 16*sqrt(light), linear lights have light/(fade*8000). -By this you see that you HAVE to specify fade for a linear light... use values below 0.01 there. --------- KEYS -------- -light: intensity factor (default: 300). A linear -_color: weighted RGB value of light color (default white - 1.0 1.0 1.0). -target: Lights pointed at a target will be spotlights. -radius: radius of a spotlight at the target point (default: 64) -_anglescale: scales angle attenuation -fade: Fade factor of light attenuation of linear lights. Linear lights completely vanish at distance light/(fade*8000), so if you want the light to vanish at distance X, specify light/(8000*X) here. -_filterradius: filter radius for this light, similar to -light -filter -_sun: if 1, this light is an infinite sun light -_samples: number of samples to use to get soft shadows from a light -_deviance: position deviance of the samples of a regular light (distributes the light samples in a cube of side length 2*_deviance around the origin), or angle deviance of the sun light samples in radians --------- SPAWNFLAGS -------- -LINEAR: Use a linear falloff. Default is inverse distance squared (more realistic). -NOANGLE: Ignore angle attenuation. -NOGRIDLIGHT: Do not affect the light grid (dynamic entity lighting). -*/ - -/*QUAKED lightJunior (.65 .65 1) (-8 -8 -8) (8 8 8) LINEAR NOANGLE -Non-displayed point light source that JUST APPLIES TO THE LIGHT GRID. No idea what this is good for. The -pointscale and -scale arguments to Q3Map2 affect the brightness of these lights. The -skyscale argument affects brightness of entity sun lights. -Maximum intensity (in a radius 16 sphere around the light): regular lights have light/256, linear lights have light/8000-16*fade. -Falloff radius to a negligible light amount: regular lights have light have 16*sqrt(light), linear lights have light/(fade*8000). -By this you see that you HAVE to specify fade for a linear light... use values below 0.01 there. --------- KEYS -------- -light: intensity factor (default: 300). A linear -_color: weighted RGB value of light color (default white - 1.0 1.0 1.0). -target: Lights pointed at a target will be spotlights. -radius: radius of a spotlight at the target point (default: 64) -_anglescale: scales angle attenuation -fade: Fade factor of light attenuation of linear lights. Linear lights completely vanish at distance light/(fade*8000), so if you want the light to vanish at distance X, specify light/(8000*X) here. -_filterradius: filter radius for this light, similar to -light -filter -_sun: if 1, this light is an infinite sun light -_samples: number of samples to use to get soft shadows from a light -_deviance: position deviance of the samples of a regular light (distributes the light samples in a cube of side length 2*_deviance around the origin), or angle deviance of the sun light samples in radians --------- SPAWNFLAGS -------- -LINEAR: Use a linear falloff. Default is inverse distance squared (more realistic). -NOANGLE: Ignore angle attenuation. -*/ - -/*QUAKED misc_laser (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON FINITE -Laser beam emitter. Note that for the laser to be deadly, it has to start OUTSIDE the player's collision box. To ensure this, you may want to put this entity inside the walls (or directly on their surface), or cover it with a playerclip brush. --------- KEYS -------- -target: target_position the laser targets (may be another entity, preferably target_position, possibly controlled by misc_follow) -mdl: name of particle effect for the beam end point (see effectinfo.txt; default is laser_deadly if dmg is set, and none if not) -colormod: color of the laser beam (default: red, that is, 1 0 0) -dmg: damage inflicted by the beam per second, or -1 for an instant-death ray -targetname: name to target this (then its state is toggled) -alpha: when set, makes a dark laser of the given strength; may be combined with colormod -scale: scales the beam thickness (default 1) -modelscale: scales the dynamic light radius at the endpoint (default 1, -1 to turn off) --------- SPAWNFLAGS -------- -START_ON: when targeted, the laser will start switched on -FINITE: the laser does not extend over its target like light would do, but stops there (takes more bandwidth) --------- NOTES -------- -Use trigger_monoflop if you want the laser to turn off for a while, then turn back on. -When the laser's target has itself target set, its targets are triggered when someone enters or leaves the laser. -*/ - -/*QUAKED misc_model (1 .5 .25) (-16 -16 -16) (16 16 16) - SOLID - EXTRUDE_NORMALS EXTRUDE_TERRAIN COLOR_TO_ALPHA -Generic placeholder for inserting MD3 models in game. Requires compilation of map geometry to be added to level. If the map is compiled with Q3Map2, then ASE, 3DS, OBJ and other model formats are supported. --------- Q3MAP2 KEYS -------- -model: file name of model to include -_frame: frame of model to include -_remap: string of the form from;to specifying which texture name of the model to replace by which shader; * is allowed. Any key starting with this prefix will work, so if you need more remappings, create _remap2, etc. -angle: view direction of the model -angles: view direction of the model in PITCH YAW ROLL -modelscale: scaling factor -modelscale_vec: scaling vector for non-uniform scaling -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_lightmapscale: light map resolution factor -_celshader: the cel shader for this --------- SPAWNFLAGS -------- -SOLID: make the model solid -EXTRUDE_NORMALS: for converting triangles to clip brushes, extrude along the model normals (by default, extrusion happens in a coordinate axis direction that is decided per triangle) -EXTRUDE_TERRAIN: always extrude downwards (for terrain) -COLOR_TO_ALPHA: use the color value as alpha (for terrain blending) -*/ - -/*QUAKED misc_gamemodel (0 .5 .8) (-8 -8 -8) (8 8 8) ALIGN_ORIGIN ALIGN_BOTTOM -A way to load models from a map by the engine (e.g. self-animated zym models). -Is non-solid by default. -The keys below actually apply to most engine-loaded model entities as they are engine features; however, they are described here as they aren't overridden by game code in misc_gamemodel. Its q3map2 keys below will work on any brush entity! --------- KEYS -------- -model: when used as a point entity, file name of model to load; when used as a brush entity, do not specify that -frame: animation frame to play (for self-animated zym models) -skin: number of skin to load (when model is used) -movetype: way in which it moves: one of 0 = NONE, 1 = ANGLENOCLIP, 2 = ANGLECLIP, 3 = WALK, 4 = STEP, 5 = FLY, 6 = TOSS, 7 = PUSH, 8 = NOCLIP, 9 = FLYMISSILE, 10 = BOUNCE, 11 = BOUNCEMISSILE -solid: solidity: one of 0 = NOT, 1 = TRIGGER, 2 = BBOX, 3 = SLIDEBOX, 4 = BSP, 5 = CORPSE -avelocity: vector giving its angular velocity (useful for spinning models) -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -velocity: when movetype isn't 0, initial velocity vector -angles: initial looking direction -modelscale: scaling factor -effects: sum of 1 = BRIGHTFIELD, 4 = BRIGHTLIGHT, 8 = DIMLIGHT, 32 = ADDITIVE, 64 = BLUE, 128 = RED, 512 = FULLBRIGHT, 1024 = FLAME, 2048 = STARDUST, 4096 = NOSHADOW, 8192 = NODEPTHTEST, 32768 = DOUBLESIDED, 8388608 = NOMODELFLAGS (ignores the following coming from a model file), 16777216 = ROCKET, 33554432 = GRENADE, 67108864 = GIB, 134217728 = ROTATE, 268435456 = TRACER, 536870912 = ZOMGIB, 1073741824 = TRACER2, -2147483648 = TRACER3 -loddistance1: distance after which to show the first LOD model replacement (default: 1000) -loddistance2: distance after which to show the second LOD model replacement (default: 2000) -lodmodel1: file name of the first LOD model replacement -lodmodel2: file name of the second LOD model replacement -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. -cvarfilter: either a + sign and a space separated list of conditions, or a - sign and the same for an inverted filter. The conditions are ALWAYS combined with AND! Possible conditions are: "cvar==value", "cvar!=value", "cvarvalue", "cvar<=value", "cvar>=value", "cvar===string", "cvar!==string", "cvar", "!cvar". Ridiculous example filter: "-g_balance_health_start<150 g_balance_armor_start==0" spawns an item only if start health is at least 150 or start armor is not 0. Other ideas: "+g_campaign" and "-g_campaign" for enabling/disabling items when the map is played as part of the campaign. --------- SPAWNFLAGS -------- -ALIGN_ORIGN: align the origin to the surface below the model -ALIGN_BOTTOM: align the bottom of the model to the surface below it -*/ - -/*QUAKED func_illusionary (0 .5 .8) ? -NOTE: THIS ENTITY IS BROKEN REGARDING CLIENT AND PROJECTILE PREDICTION. DO NOT USE IT. USE NONSOLID SHADERS OR FUNC_CLIENTILLUSIONARY INSTEAD. -A non-solid brush entity. Use func_wall if you want it solid. -The keys below actually apply to most brush entities as they are engine features; however, they are described here as they aren't overridden by game code in misc_models. Its q3map2 keys below will work on any brush entity! --------- KEYS -------- -movetype: way in which it moves: one of 0 = NONE, 1 = ANGLENOCLIP, 2 = ANGLECLIP, 3 = WALK, 4 = STEP, 5 = FLY, 6 = TOSS, 7 = PUSH, 8 = NOCLIP, 9 = FLYMISSILE, 10 = BOUNCE, 11 = BOUNCEMISSILE -avelocity: vector giving its angular velocity (useful for spinning models) -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -velocity: when movetype isn't 0, initial velocity vector -angles: initial looking direction -effects: sum of 1 = BRIGHTFIELD, 4 = BRIGHTLIGHT, 8 = DIMLIGHT, 32 = ADDITIVE, 64 = BLUE, 128 = RED, 512 = FULLBRIGHT, 1024 = FLAME, 2048 = STARDUST, 4096 = NOSHADOW, 8192 = NODEPTHTEST, 32768 = DOUBLESIDED, 8388608 = NOMODELFLAGS (ignores the following coming from a model file), 16777216 = ROCKET, 33554432 = GRENADE, 67108864 = GIB, 134217728 = ROTATE, 268435456 = TRACER, 536870912 = ZOMGIB, 1073741824 = TRACER2, -2147483648 = TRACER3 -loddistance1: distance after which to show the first LOD model replacement (default: 1000) -loddistance2: distance after which to show the second LOD model replacement (default: 2000) -lodtarget1: targetname of the first LOD model entity (can be used instead of lodmodel1 to use a brush model instead) -lodtarget2: targetname of the second LOD model entity (can be used instead of lodmodel2 to use a brush model instead) -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. Works only with _shirt and _pants textures. -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. --------- Q3MAP2 KEYS -------- -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_clone: copies brushes from entity with identical _clonename. Still needs a single brush that will get replaced. -_clonename: template name so one can clone from it -min: override automatically found minimum coordinate bounds -max: override automatically found maximum coordinate bounds -targetname: if targeted by a misc_model, its brushes get inserted into this -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. -*/ - -/*QUAKED func_wall (0 .5 .8) ? -A solid brush entity. Use func_clientillusionary if you want it non-solid. -The keys below actually apply to most brush entities as they are engine features; however, they are described here as they aren't overridden by game code in misc_models. Its q3map2 keys below will work on any brush entity! --------- KEYS -------- -movetype: way in which it moves: one of 0 = NONE, 1 = ANGLENOCLIP, 2 = ANGLECLIP, 3 = WALK, 4 = STEP, 5 = FLY, 6 = TOSS, 7 = PUSH, 8 = NOCLIP, 9 = FLYMISSILE, 10 = BOUNCE, 11 = BOUNCEMISSILE -solid: solidity: one of 1 = TRIGGER, 2 = BBOX, 3 = SLIDEBOX, 4 = BSP, 5 = CORPSE (default: 4, any other value causes prediction problems and should not be used until further notice) -avelocity: vector giving its angular velocity (useful for spinning models) -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -velocity: when movetype isn't 0, initial velocity vector -angles: initial looking direction -effects: sum of 1 = BRIGHTFIELD, 4 = BRIGHTLIGHT, 8 = DIMLIGHT, 32 = ADDITIVE, 64 = BLUE, 128 = RED, 512 = FULLBRIGHT, 1024 = FLAME, 2048 = STARDUST, 4096 = NOSHADOW, 8192 = NODEPTHTEST, 32768 = DOUBLESIDED, 8388608 = NOMODELFLAGS (ignores the following coming from a model file), 16777216 = ROCKET, 33554432 = GRENADE, 67108864 = GIB, 134217728 = ROTATE, 268435456 = TRACER, 536870912 = ZOMGIB, 1073741824 = TRACER2, -2147483648 = TRACER3 -loddistance1: distance after which to show the first LOD model replacement (default: 1000) -loddistance2: distance after which to show the second LOD model replacement (default: 2000) -lodtarget1: targetname of the first LOD model entity (can be used instead of lodmodel1 to use a brush model instead) -lodtarget2: targetname of the second LOD model entity (can be used instead of lodmodel2 to use a brush model instead) -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. Works only with _shirt and _pants textures. -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. --------- Q3MAP2 KEYS -------- -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_clone: copies brushes from entity with identical _clonename. Still needs a single brush that will get replaced. -_clonename: template name so one can clone from it -min: override automatically found minimum coordinate bounds -max: override automatically found maximum coordinate bounds -targetname: if targeted by a misc_model, its brushes get inserted into this -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. -*/ - -/*QUAKED misc_clientmodel (0 .5 .8) (-8 -8 -8) (8 8 8) ALIGN_ORIGIN ALIGN_BOTTOM -A way to load models from a map by the engine (e.g. self-animated zym models) on client side. -Is non-solid by default. --------- KEYS -------- -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -angles: initial looking direction -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. Works only with _shirt and _pants textures. -bgmscript: emitter class from the BGM script (if prefixed with <, movedir is treated as an angle value) -bgmscriptattack: attack time of the effect strength (0 to 3.9) -bgmscriptdecay: decay time of the effect strength (0 to 3.9) -bgmscriptsustain: sustain level of the effect strength (0.1 to 1, set to -1 to disable sustain) -bgmscriptrelease: release time of the effect strength (0 to 3.9) -movedir: vector by which the entity moves when "pressed" by the bgmscript -lip: alpha change when "pressed" by the bgmscript (if > 0, it fades in when pressed, if < 0, it fades out when pressed) -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. --------- SPAWNFLAGS -------- -ALIGN_ORIGN: align the origin to the surface below the model -ALIGN_BOTTOM: align the bottom of the model to the surface below it -*/ - -/*QUAKED func_clientillusionary (0 .5 .8) ? -A client-side non-solid brush entity. Use func_wall if you want it solid. --------- KEYS -------- -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -angles: initial looking direction -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. Works only with _shirt and _pants textures. -bgmscript: emitter class from the BGM script -bgmscriptattack: attack time of the effect strength (0 to 3.9) -bgmscriptdecay: decay time of the effect strength (0 to 3.9) -bgmscriptsustain: sustain level of the effect strength (0.1 to 1, set to -1 to disable sustain) -bgmscriptrelease: release time of the effect strength (0 to 3.9) -movedir: vector by which the entity moves when "pressed" by the bgmscript -lip: alpha change when "pressed" by the bgmscript (if > 0, it fades in when pressed, if < 0, it fades out when pressed) -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. --------- Q3MAP2 KEYS -------- -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_clone: copies brushes from entity with identical _clonename. Still needs a single brush that will get replaced. -_clonename: template name so one can clone from it -min: override automatically found minimum coordinate bounds -max: override automatically found maximum coordinate bounds -targetname: if targeted by a misc_model, its brushes get inserted into this -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. -*/ - -/*QUAKED func_clientwall (0 .5 .8) ? -NOTE: THIS ENTITY IS IN MOST USE CASES BROKEN REGARDING CLIENT AND PROJECTILE PREDICTION. DO NOT USE IT. USE FUNC_WALL INSTEAD. -A client-side solid brush entity. Use func_clientillusionary if you want it non-solid. --------- KEYS -------- -solid: solidity: one of 1 = TRIGGER, 2 = BBOX, 3 = SLIDEBOX, 4 = BSP, 5 = CORPSE (default: 4, any other value causes prediction problems and should not be used until further notice) -scale: scale factor of the model (range: 0.0625 to 15.9375) -colormap: 1024 + 16 * pantscolor + shirtcolor -angles: initial looking direction -targetname: when invoking it by a button etc., it changes the color to the initiator of the action (e.g. the one pressing a button). In Onslaught, this can be used to color control points for team who owns them. In other game types, this can be used as a fun feature. Works only with _shirt and _pants textures. -bgmscript: emitter class from the BGM script -bgmscriptattack: attack time of the effect strength (0 to 3.9) -bgmscriptdecay: decay time of the effect strength (0 to 3.9) -bgmscriptsustain: sustain level of the effect strength (0.1 to 1, set to -1 to disable sustain) -bgmscriptrelease: release time of the effect strength (0 to 3.9) -movedir: vector by which the entity moves when "pressed" by the bgmscript -lip: alpha change when "pressed" by the bgmscript (if > 0, it fades in when pressed, if < 0, it fades out when pressed) -originjitter: a vector describing a random offset this entity will be moved on initial spawn. This corresponds to the "origin" field. Works on any non-q3map2-only entity. -anglesjitter: a vector in the order "pitch yaw roll" describing a random angles change on this entity on initial spawn. The value 180 180 180 makes the angles entirely random and uniformly distributed (among euler angles). This corresponds to the "angles" field. Works on any non-q3map2-only entity. -anglejitter: a float describing a random yaw angle change on this entity on initial spawn. The value 180 makes the yaw angle entirely random (maybe good for items). This corresponds to the "angle" field. Works on any non-q3map2-only entity. -gametypefilter: either a + sign and a comma separated list of game types or the aliases "teams" and "noteams" to ONLY show the entity in the listed game types, or a - sign and a comma separated list of game types or the aliases "teams" and "noteams" to NOT show the entity in the listed game types. The syntax is the same as in sbar_columns_set strings. Works on any non-q3map2-only entity. --------- Q3MAP2 KEYS -------- -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting. 1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_clone: copies brushes from entity with identical _clonename. Still needs a single brush that will get replaced. -_clonename: template name so one can clone from it -min: override automatically found minimum coordinate bounds -max: override automatically found maximum coordinate bounds -targetname: if targeted by a misc_model, its brushes get inserted into this -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. -*/ - -/*QUAKED misc_teleporter_dest (1 .5 .25) (-16 -16 -24) (16 16 45) -Teleport destination location point for trigger_teleport entities. Do not let it touch the floor, but place it slightly higher (like, 16 units above) for better flow when jumping through it. --------- KEYS -------- -targetname: make the trigger_teleporter point to this. -target: target to activate when a teleporter targeting this is used -angle: direction in which player will look when teleported, OR use -angles: pitch and yaw when coming out of the teleporter (also specifies the direction the player will aim when coming out) -cnt: weight for random selection, in case a teleporter points at multiple misc_teleporter_dest -speed: maximum speed cap for the teleported player (if -1, teleported players will have no speed) -*/ - -/*QUAKED onslaught_controlpoint (0 .5 .8) (-32 -32 0) (32 32 128) -Control point. Be sure to give this enough clearance so that the shootable part has room to exist -This should link to an onslaught_controlpoint entity or onslaught_generator entity. --------- KEYS -------- -targetname: name that onslaught_link entities will use to target this. -target: target any entities that are tied to this control point, such as vehicles and buildable structure entities. -message: name of this control point (should reflect the location in the map, such as "center bridge", "north tower", etc) -*/ - -/*QUAKED onslaught_generator (0 .5 .8) (-32 -32 -24) (32 32 64) -Base generator. - -onslaught_link entities can target this. --------- KEYS -------- -team: team that owns this generator (5 = red, 14 = blue, etc), MUST BE SET. -targetname: name that onslaught_link entities will use to target this. -*/ - -/*QUAKED onslaught_link (0 .5 .8) (-16 -16 -16) (16 16 16) -Link between control points. - -This entity targets two different onslaught_controlpoint or onslaught_generator entities, and suppresses shielding on both if they are owned by different teams. --------- KEYS -------- -target: first control point. -target2: second control point. -*/ - -/*QUAKED path_corner (.5 .3 0) (-8 -8 -8) (8 8 8) -Path corner entity that func_train will follow. -All path_corner entities of a train have to connect in a circular manner, while the func_train shall point to one of the path_corners (ideally the one at the train's starting point) --------- KEYS -------- -target: point to next path_corner in the path. -targetname: the train following the path or the previous path_corner in the path points to this. -speed: speed of func_train while moving to this path corner. If unset, the value from the func_train will be used. -wait: number of seconds func_train will pause on this path corner before moving to next path corner (default: 0.1; to not wait, set this to -1 -*/ - -/*QUAKED runematch_spawn_point (.3 .3 1) (-16 -16 -16) (16 16 16) -Spawn point for runes in a runematch. -Runematch can work without runes also, it then spawn runes at random safe locations. -*/ - -/*QUAKED target_assault_roundend (1 0 0) (-8 -8 -8) (8 8 8) -This entity ends the current assault round if triggered or if the timelimit is reached. -Ending a round means swapping attacker/defender teams, resetting objectives and rewarding the winning team. -Every assault map needs this entity. There should only be one per map. --------- KEYS -------- -targetname: Name to target this entity -*/ - -/*QUAKED target_assault_roundstart (.5 0 .5) (-8 -8 -8) (8 8 8) -This entity triggers its targets whenever a new assault round is started. This can be used to e.g. activate the first objective. --------- KEYS -------- -target: targetname of entities to be enabled/triggered on round start (e.g. the first target_objective) -target2: targetname of entities to be enabled/triggered on round start (e.g. the func_assault_destructibles targeting the target_objective) -target3: targetname of entities to be enabled/triggered on round start -target4: targetname of entities to be enabled/triggered on round start -*/ - -/*QUAKED target_objective (.5 0 .5) (-8 -8 -8) (8 8 8) -target_objective controls an objective. Once triggered the objective is active and has 100 "health" points. If this "health" falls below zero it is assumed this objective has been fulfilled and entities targeted will be triggered (e.g. to activate the next objective or to end this round). Use target_objective_decrease to decrease the objective health. --------- KEYS -------- -target: targetname of entities to be enabled/triggered on objective fulfilling (e.g. the next target_objective, or target_assault_roundend) -target2: targetname of entities to be enabled/triggered on objective fulfilling (e.g. the func_assault_destructibles targeting the target_objective) -target3: targetname of entities to be enabled/triggered on objective fulfilling -target4: targetname of entities to be enabled/triggered on objective fulfilling -targetname: targetname for this entity so it can be triggered by other entities. -*/ - -/*QUAKED target_objective_decrease (0 1 0) (-8 -8 -8) (8 8 8) -When triggered decreases health of the targeted target_objective by the amount specified in dmg. Remember, target_objective has 100 health points and is considered conquered if health falls below zero. -If you want e.g. two events to happen to conquer an objective you'd need two target_objective_decrease, each with a value for cnt of e.g. 51. To show attackers and defenders where to go, target_objective_decrease will show a fitting sprite ("Defend" to defenders, "Destroy"/"Push" to attackers) which can be seen through walls. --------- KEYS -------- -target: The targetname of the target_objective you want to manipulate. -targetname: Name for other entities to target this entity. -dmg: The amount of "health"-points you want to subtract from the objective health. Defaults to 101. Also used as score for triggering this objective. -*/ - -/*QUAKED target_position (0 .5 0) (-8 -8 -8) (8 8 8) -Aiming target for entities like light and trigger_push. --------- KEYS -------- -targetname: the entity that requires an aiming direction points to this. -target: target to activate when a jumppad targeting this is used -*/ - -/*QUAKED target_speaker (0 .7 .7) (-8 -8 -8) (8 8 8) -Sound generating entity that plays sound files. -If targeted, it plays the sound file every time when triggered. -If not targeted, it loops the sound file as an ambient noise. --------- KEYS -------- -noise: path/name of .wav/.ogg file to play -targetname: the activating button or trigger points to this. -atten: distance attenuation of the sound (a value from 0.1 to 3.9), default is 0.5 if targeted, 3 otherwise; set to -1 for no attenuation (global sound) -volume: volume of the sound -*/ - -/*QUAKED trigger_counter (.5 .5 .5) ? NOMESSAGE -Acts as an intermediary for an action that takes multiple inputs. -After the counter has been triggered "count" times, it will fire all of its targets and remove itself. --------- KEYS -------- -count: how many times this needs to be triggered to activate its targets -target: trigger all entities with this targetname when triggered -targetname: name that identifies this entity so it can be triggered -delay: delay the triggering by the given time -message: print this message to the player who activated the trigger -killtarget: remove all entities with this targetname when triggered --------- SPAWNFLAGS -------- -NOMESSAGE: don't print a "2 more to go..."-like message when triggered -*/ - -/*QUAKED trigger_delay (.5 .5 .5) (-8 -8 -8) (8 8 8) -Trigger that delays triggering by a given amount of time. Only one action can be waited for; if triggered again before the "wait" time expires, the timer will restart (as opposed to trigger_relay). --------- KEYS -------- -wait: delay the triggering by the given time -target: trigger all entities with this targetname when triggered -targetname: name that identifies this entity so it can be triggered -message: print this message to the player who activated the trigger -killtarget: remove all entities with this targetname when triggered -*/ - -/*QUAKED trigger_hurt (.5 .5 .5) ? -Any object touching this will be hurt. -Has the useful effect of automatically returning flags, keys and runes when they touch it. --------- KEYS -------- -dmg: amount of damage to deal (default: 1000) -message: kill message when someone gets killed by this (default: "was in the wrong place") -message2: kill message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -*/ - -/*QUAKED trigger_impulse (.5 .5 .5) ? -An accelerator/dampener/wind field. -Can be used in two ways: -"dampener field": just set strength to a value from 0 to 1. Entering the field will slow down to this factor. -"accelerator field": just set strength to a value from 1 to infinity. Entering the field will accelerate by this factor. -"wind field": set strength to the amount of velocity to add per second, and target a target_position. The field will apply force in the direction from its own origin to the target (use an origin brush to specify its own origin, or this will fail) when touched. -"gravity field": set strength to the amount of velocity to add per second at the center, and set radius to the radius of the field. Set falloff to the desired falloff characteristics. --------- KEYS -------- -target: "wind field": points to the target_position to which the player will get pushed. -strength: "wind field", "gravity field": amount of force per second to apply. "dampener/accelerator field": slowdown/speedup factor. -falloff: "gravity field": 0 means no falloff, 1 means linear falloff (zero at the outside), 2 means inverted linear falloff (zero at the inside) -*/ - -/*QUAKED trigger_multiple (.5 .5 .5) ? NOTOUCH ALLENTS - - - - - - NOSPLASH -Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. --------- KEYS -------- -health: amount of damage that has to be dealt to the trigger to activate (it then won't respond to merely touching it) -wait: prevent triggering again for this amount of time (default: 0.2, set to -1 to wait indefinitely, or -2 to not wait at all) -sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav -noise: path to sound file, if you want to play something else -target: trigger all entities with this targetname when triggered -target2: trigger all entities with this targetname when triggered -target3: trigger all entities with this targetname when triggered -target4: trigger all entities with this targetname when triggered -targetname: name that identifies this entity so it can be triggered -delay: delay the triggering by the given time -message: print this message to the player who activated the trigger -killtarget: remove all entities with this targetname when triggered --------- SPAWNFLAGS -------- -NOTOUCH: the trigger can only be triggered by other entities, not by touching or firing (you should probably use trigger_relay or trigger_delay instead) -ALLENTS: the trigger responds to all entities, not just players (useful for targetting trigger_items) -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED trigger_once (.5 .5 .5) ? NOTOUCH - - - - - - - NOSPLASH -Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time. -Basically, it's a use-once trigger_multiple. --------- KEYS -------- -health: amount of damage that has to be dealt to the trigger to activate (it then won't respond to merely touching it) -sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav -noise: path to sound file, if you want to play something else -target: trigger all entities with this targetname when triggered -targetname: name that identifies this entity so it can be triggered -delay: delay the triggering by the given time -message: print this message to the player who activated the trigger -killtarget: remove all entities with this targetname when triggered --------- SPAWNFLAGS -------- -NOTOUCH: the trigger can only be triggered by other entities, not by touching or firing (you should probably use trigger_relay or trigger_delay instead) -NOSPLASH: if set, splash damage cannot activate the door, only direct damage can (requires health to be set) -*/ - -/*QUAKED trigger_push (1 .5 0) ? - - INVERT_TEAM -Jump pad. What else? -Can be used in three ways: -Xonotic "target/height" way: put the target_position where the player should land, and tune height to get a nice jump path. A good starting value for height is 100. -Q3A "target" way: put the target_position at the apex of the jump, and hope the player will land at the right spot. Good luck. -Quake "movedir/speed" way: player will get velocity movedir * speed * 10 when using the jump pad --------- KEYS -------- -target: point the player will fly to when using the jump pad (use a target_position here) -height: if height is 0, the (player's origin at the) apex of the jump will be at the target; otherwise, the apex will be abs(height) above the higher point of player's origin and the target; if positive, the apex will be reached in the jump from initial origin to target -movedir: when target is not set, direction vector to push to -speed: speed of jump pad (default: 1000) -noise: sound to play when jump pad is used; default is misc/jumppad.wav; you can set it to "" to make the pad silent -team: team that owns this jump pad (5 = red, 14 = blue, etc) (when set, only this team can teleport) -targetname: when targeted by a func_button, pressing the button will reassign the teleporter to the team of the activator. --------- SPAWNFLAGS -------- -INVERT_TEAM: the team that owns the teleporter will NOT jump when touching this -*/ - -/*QUAKED trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8) -This fixed size trigger cannot be touched, it can only be fired by other events. It can, like any other trigger, contain killtargets, targets, delays, and messages. -One possible use is to trigger entities with more than one targetname on an action, e.g. a button. For this, set target of your button to foobar. Create two trigger_relay with targetname=foobar. Give one of the trigger_relay entities target=ent1, and give the other target=ent2. -More than one "trigger event" can be delayed at once, as opposed to trigger_delay. --------- KEYS -------- -target: trigger all entities with this targetname when triggered -target2: trigger all entities with this targetname when triggered -target3: trigger all entities with this targetname when triggered -target4: trigger all entities with this targetname when triggered -targetname: name that identifies this entity so it can be triggered -delay: delay the triggering by the given time -message: print this message to the player who activated the trigger -killtarget: remove all entities with this targetname when triggered -*/ - -/*QUAKED trigger_swamp (.5 .5 .5) ? -Players getting into the swamp will get slowed down and damaged --------- KEYS -------- -dmg: damage per interval to deal (default is 5) -swamp_interval: interval of damage when in swamp (default is 1) -swamp_slowdown: amount of slowdown caused by the swamp (default is 0.5) -*/ - -/*QUAKED trigger_teleport (.5 .5 .5) ? - - INVERT_TEAM -Touching this will teleport players to the location of the targeted misc_teleporter_dest entity. -Note that in Xonotic, teleporters preserve momentum of the player using them. --------- KEYS -------- -target: this must point to a misc_teleporter_dest entity. If it points to more than one, a destination is randomly selected on teleport. -team: team that owns this teleporter (5 = red, 14 = blue, etc) (when set, only this team can teleport) -targetname: when targeted by a func_button, pressing the button will reassign the teleporter to the team of the activator. --------- SPAWNFLAGS -------- -INVERT_TEAM: the team that owns the teleporter will NOT teleport when touching this -*/ - -/*QUAKED weapon_crylink (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Crylink --------- KEYS -------- -ammo_cells: initial cells of the weapon (if unset, g_pickup_cells is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_crylink.md3" -*/ - -/*QUAKED weapon_electro (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Electro --------- KEYS -------- -ammo_cells: initial cells of the weapon (if unset, g_pickup_cells is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_electro.md3" -*/ - -/*QUAKED weapon_grenadelauncher (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Mortar --------- KEYS -------- -ammo_rockets: initial rockets of the weapon (if unset, g_pickup_rockets is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_gl.md3" -*/ - -/*QUAKED weapon_hagar (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Hagar --------- KEYS -------- -ammo_rockets: initial rockets of the weapon (if unset, g_pickup_rockets is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_hagar.md3" -*/ - -/*QUAKED weapon_laser (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Laser. Note that unless you use - settemp_for_type all g_start_weapon_laser 0 -in your mapinfo file, everyone will already spawn with one, making this pickup useless. --------- KEYS -------- -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_laser.md3" -*/ - -/*QUAKED weapon_nex (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Nex -In Minstagib, this turns into an item_minst_cells if no explicit item_minst_cells have been placed. --------- KEYS -------- -ammo_cells: initial cells of the weapon (if unset, g_pickup_cells is used) -respawntime: time till it respawns (default: 15 * g_balance_nex_respawntime_modifier) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_nex.md3" -*/ - -/*QUAKED weapon_rocketlauncher (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Rocket Launcher -In Minstagib, this turns into an item_minst_cells if no explicit item_minst_cells have been placed. --------- KEYS -------- -ammo_rockets: initial rockets of the weapon (if unset, g_pickup_rockets is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_rl.md3" -*/ - -/*QUAKED weapon_shotgun (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Shotgun. Note that unless you use - settemp_for_type all g_start_weapon_shotgun 0 -in your mapinfo file, everyone will already spawn with one, making this pickup useless. --------- KEYS -------- -ammo_shells: initial shells of the weapon (if unset, g_pickup_shells is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_shotgun.md3" -*/ - -/*QUAKED weapon_uzi (1 0 .5) (-30 -30 0) (30 30 32) FLOATING -the Machine Gun --------- KEYS -------- -ammo_nails: initial bullets of the weapon (if unset, g_pickup_nails is used) -respawntime: time till it respawns (default: 15) -team: out of items with the same value here, only one (random one) will spawn. Useful to put multiple items on one spot. -cnt: weight of this item for random selection using "team". Set to a lower value for items you want to see less likely. --------- SPAWNFLAGS -------- -FLOATING: the item will float in air, instead of aligning to the floor by falling --------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY -------- -model="models/weapons/g_uzi.md3" -*/ - -/*QUAKED worldspawn (0 0 0) ? -The world. -If you see this, the currently selected brush is not of an entity. --------- KEYS -------- -fog: fog parameters of the map (density red green blue alpha mindist maxdist); works just like the "fog" console command -author: name of the author of the map, if not specified in "message". Will get copied to the "author" entry of the mapinfo file when none is present. -message: text to print at user logon. Used for name of level. Ideally: "NAMEOFLEVEL by AUTHOR". Will get copied to the "title" and "author" entries of the mapinfo file when none is present. -_description: one-line description of the map. Will get copied to the "description" entry of the mapinfo file when none is present. --------- Q3MAP2 KEYS -------- -_blocksize: vector specifying the automatic vis subdivision block size (default: 1024 1024 1024) -gridsize: lightgrid granularity vector (default: 64 64 128) -_color: color of the global light parameters -_ambient: light added to all surfaces -_mingridlight: minimum grid light -_minlight: minimum light value on both surfaces and lightgrid -_keepLights: do not remove light entities from the map (useful e.g. for realtime lighting) -_floodlight: flood light parameters (red green blue distance intensity), start with 240 240 255 1024 128 -_farplanedist: range after which everything is completely invisible by fog (when fog is being used) -_noshadersun: turn off sun defined by shaders (useful if you defined your own light entity to be a sun) -_ignoreleaks: ignore leaks when compiling -_lightmapscale: light map resolution factor -_castshadows: Allows per-entity control over shadow casting. Defaults to 0 on entities, 1 on world. 0 = no shadow casting.1 = cast shadows on world. > 1 = cast shadows on entities with _rs (or _receiveshadows) with the corresponding value, AND world. Negative values imply same, but DO NOT cast shadows on world. -_receiveshadows: Allows per-entity control over shadow reception. Defaults to 1 on everything (world shadows). 0 = receives NO shadows. > 1 = receive shadows only from corresponding keyed entities (see above) and world. < 1 = receive shadows ONLY from corresponding keyed entities. -_celshader: Sets the cel shader used for this geometry. Note: omit the "textures/" prefix. -*/ - -/*QUAKED trigger_race_checkpoint (0 1 0) ? NOTOUCH STRICTTRIGGER CRUSH FINISH -A checkpoint, for the race game mode. Be sure to make them quite long, so they actually catch a player reliably! --------- KEYS -------- -cnt: Number of the checkpoint. 0 for start/finish line, and at least two other checkpoints have to exist. They MUST be touched in sequential order! -message: Death message, when touching checkpoints in the wrong order. -message2: Death message when someone gets pushed into this (default: "was thrown into a world of hurt by"). The # character is replaced by the attacker name if present (and it instead does not get appended to the end) -targetname: Name of the checkpoint. info_player_race can target this to assign a spawn to a checkpoint. Also used for triggering a checkpoint by an event. -target: when the checkpoint is passed, these entities are triggered. Useful for forcing items in certain areas using trigger_items -race_penalty: when set, this penalty time is given if passing this checkpoint, and the checkpoint does not show up with a sprite. Useful for invisible checkpoints to detect driving around the intended checkpoint -race_penalty_reason: reason to display when the penalty time is imposed. Default: "missing a checkpoint" --------- SPAWNFLAGS -------- -NOTOUCH: the checkpoint will not become active when touched, it HAS to be targeted -STRICTTRIGGER: only trigger the targets when the checkpoint actually was reached in a valid way (that is, not when going back) -CRUSH: the checkpoint kills when used at the wrong time -FINISH: when set on the last checkpoint (i.e. the one with highest cnt), it is marked as finish line and the CP with cnt=0 is the start line -*/ - -/*QUAKED trigger_race_penalty (0 1 0) ? NOTOUCH -A penalty trigger. --------- KEYS -------- -race_penalty: this penalty time is given if passing this trigger -race_penalty_reason: reason to display when the penalty time is imposed. Default: "leaving the track" --------- SPAWNFLAGS -------- -NOTOUCH: the trigger will not become active when touched, it HAS to be targeted -*/ - -/*QUAKED info_player_race (1 0.5 0) (-16 -16 -24) (16 16 45) -Race spawn point. -NOTE for race_place: when the race starts after the qualifying, the player with the fastest lap ends up at the info_player_race with race_place 1, and so on. If there are too many players, or if someone comes in later, he will spawn at an info_player_race with highest race_place. If someone dies after reaching the the starting checkpoint, he will spawn at race_place 0. So for each trigger_race_checkpoint, there must be at least one corresponding info_player_race with race_place NOT set. --------- KEYS -------- -target: this should point to a trigger_race_checkpoint to decide when this spawning point is active. The checkpoint has to be AFTER this spawn. -target2: trigger all entities with this targetname when someone spawns -cnt: weight of spawn point for random selection. Set to a lower value if you have many spawn points close together. Default value is 1. -race_place: if target points to the trigger_race_checkpoint with cnt 0 (finish line), this sets which place the spawn corresponds to; the special value 0 stands for spawns for players who died in game, and -1 marks the spawnpoint for qualifying mode only; any race map must have spawnpoints with race_place being 1, 2, 3 or it gets marked as a frustrating map -restriction: when 1, only bots can spawn here; when 2, only humans can spawn here (be careful with these, or the game will crash because someone cannot spawn) -*/ - -/*QUAKED func_pointparticles (.5 .5 .5) ? START_ON IMPULSE -A brush that emits particles. --------- KEYS -------- -mdl: particle effect name from effectinfo.txt -impulse: when positive, number of particles to emit per second; when negative; number of particles to emit per second and 64^3 block -velocity: particle direction and speed -waterlevel: extra velocity jitter amount -count: particle count multiplier (per spawned particle) -movedir: when set, trace direction (particles will then be emitted from the surface the trace hits); the length of the vector is used as strength of taking the normal of the trace into account -noise: sound to play when the particle is emitted -atten: distance attenuation of the sound (a value from 0.1 to 3.9), default is 0.5; set to -1 for no attenuation (global sound) -volume: volume of the sound -targetname: name to target this (then its state is toggled) -bgmscript: emitter class from the BGM script -bgmscriptattack: attack time of the effect strength (0 to 3.9) -bgmscriptdecay: decay time of the effect strength (0 to 3.9) -bgmscriptsustain: sustain level of the effect strength (0.1 to 1, set to -1 to disable sustain) -bgmscriptrelease: release time of the effect strength (0 to 3.9) --------- SPAWNFLAGS -------- -START_ON: when targeted, the particle emitter will start switched on -IMPULSE: only send the full amount of impulse particles when the entity is triggered --------- NOTES -------- -Use trigger_monoflop if you want the particles to turn off for a while, then turn back on. -A BGM script is a .bgs file named like the map, in the maps directory. Its format is lines of the form -