X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fclient%2FView.qc;h=b64fe3660946dbdead13ac4d1f0a7289feba20d6;hp=a5858bd49882fff3f2da7f8238c5ba4d28ccce2f;hb=fbec40012e84855d10d0f99f2ead025aca3153c6;hpb=6491d84c152f73b11edbd0c5a74317461b0045cb diff --git a/qcsrc/client/View.qc b/qcsrc/client/View.qc index a5858bd498..b64fe36609 100644 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@ -78,30 +78,6 @@ void Porto_Draw() } } -/** - * Checks whether the server initiated a map restart (stat_game_starttime changed) - * - * TODO: Use a better solution where a common shared entitiy is used that contains - * timelimit, fraglimit and game_starttime! Requires engine changes (remove STAT_TIMELIMIT - * and STAT_FRAGLIMIT to be auto-sent) - */ -void CheckForGamestartChange() { - float startTime; - startTime = getstatf(STAT_GAMESTARTTIME); - if (previous_game_starttime != startTime) { - if ((time + 5.0) < startTime) { - //if connecting to server while restart was active don't always play prepareforbattle - sound(world, CH_INFO, strcat("announcer/", autocvar_cl_announcer, "/prepareforbattle.wav"), VOL_BASEVOICE, ATTN_NONE); - } - if (time < startTime) { - restartAnnouncer = spawn(); - restartAnnouncer.think = restartAnnouncer_Think; - restartAnnouncer.nextthink = startTime - floor(startTime - time); //synchronize nextthink to startTime - } - } - previous_game_starttime = startTime; -} - void Porto_Init() { porto = spawn(); @@ -114,7 +90,8 @@ float drawtime; float avgspeed; vector GetCurrentFov(float fov) { - float zoomsensitivity, zoomspeed, zoomfactor, zoomdir, velocityzoom; + float zoomsensitivity, zoomspeed, zoomfactor, zoomdir; + float velocityzoom, curspeed; zoomsensitivity = autocvar_cl_zoomsensitivity; zoomfactor = autocvar_cl_zoomfactor; @@ -127,7 +104,7 @@ vector GetCurrentFov(float fov) zoomdir = button_zoom; if(hud == HUD_NORMAL) - if((getstati(STAT_ACTIVEWEAPON) == WEP_NEX && nex_scope) || (getstati(STAT_ACTIVEWEAPON) == WEP_RIFLE && rifle_scope)) // do NOT use switchweapon here + if((activeweapon == WEP_NEX && nex_scope) || (activeweapon == WEP_RIFLE && rifle_scope)) // do NOT use switchweapon here zoomdir += button_attack2; if(spectatee_status > 0 || isdemo()) { @@ -177,13 +154,23 @@ vector GetCurrentFov(float fov) setsensitivityscale(pow(current_viewzoom, 1 - zoomsensitivity)); else setsensitivityscale(1); + + makevectors(view_angles); - if (autocvar_cl_velocityzoom) + if(autocvar_cl_velocityzoom) { - velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoomtime), 1); - avgspeed = avgspeed * (1 - velocityzoom) + (vlen(pmove_vel) / 1000) * velocityzoom; + switch(autocvar_cl_velocityzoom_type) + { + case 3: curspeed = max(0, v_forward * pmove_vel); break; + case 2: curspeed = (v_forward * pmove_vel); break; + case 1: default: curspeed = vlen(pmove_vel); break; + } + + velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoom_time), 1); // speed at which the zoom adapts to player velocity + avgspeed = avgspeed * (1 - velocityzoom) + (curspeed / autocvar_cl_velocityzoom_speed) * velocityzoom; velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom / 1) * 1); - //print(ftos(avgspeed), " avgspeed, ", ftos(autocvar_cl_velocityzoom), " cvar, ", ftos(velocityzoom), " return\n"); // for debugging + + //print(ftos(avgspeed), " avgspeed, ", ftos(curspeed), " curspeed, ", ftos(velocityzoom), " return\n"); // for debugging } else velocityzoom = 1; @@ -348,6 +335,7 @@ void CSQC_RAPTOR_HUD(); vector freeze_org, freeze_ang; entity nightvision_noise, nightvision_noise2; +#define MAX_TIME_DIFF 5 float pickup_crosshair_time, pickup_crosshair_size; float hit_time, typehit_time; float nextsound_hit_time, nextsound_typehit_time; @@ -398,6 +386,7 @@ void CSQC_UpdateView(float w, float h) CHECKFAIL_ASSERT(3, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{111}\{118}\{101}\{114}\{100}\{114}\{97}\{119}", 0); CHECKFAIL_ASSERT(4, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{108}\{105}\{103}\{104}\{116}", 0); CHECKFAIL_ASSERT(5, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{115}\{104}\{97}\{100}\{111}\{119}\{118}\{111}\{108}\{117}\{109}\{101}\{115}", 0); + CHECKFAIL_ASSERT(6, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{111}\{118}\{101}\{114}\{100}\{114}\{97}\{119}", 0); vf_size = R_SetView3fv(VF_SIZE); vf_min = R_SetView3fv(VF_MIN); @@ -416,22 +405,14 @@ void CSQC_UpdateView(float w, float h) ticrate = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE); - if(autocvar_cl_lockview || (autocvar__hud_configure && spectatee_status <= 0) || intermission > 1) - { - R_SetView(VF_ORIGIN, freeze_org); - R_SetView(VF_ANGLES, freeze_ang); - } - else - { - freeze_org = R_SetView3fv(VF_ORIGIN); - freeze_ang = R_SetView3fv(VF_ANGLES); - } - // event chase camera if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped { if(spectatee_status >= 0 && (autocvar_cl_eventchase_death && getstati(STAT_HEALTH) <= 0 && !intermission) || intermission) { + // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.) + vector current_view_origin = R_SetView3fv(VF_ORIGIN); + // We must enable chase_active to get a third person view (weapon viewmodel hidden and own player model showing). // Ideally, there should be another way to enable third person cameras, such as through R_SetView() if(!autocvar_chase_active) @@ -446,13 +427,12 @@ void CSQC_UpdateView(float w, float h) vector eventchase_target_origin; makevectors(view_angles); // pass 1, used to check where the camera would go and obtain the trace_fraction - eventchase_target_origin = freeze_org - v_forward * eventchase_current_distance; - - WarpZone_TraceLine(freeze_org, eventchase_target_origin, MOVE_WORLDONLY, self); + eventchase_target_origin = current_view_origin - v_forward * eventchase_current_distance; + WarpZone_TraceLine(current_view_origin, eventchase_target_origin, MOVE_WORLDONLY, self); // pass 2, also multiplying view_forward with trace_fraction, to prevent the camera from going through walls // The 0.1 subtraction is to not limit the camera precisely at the wall surface, as that allows the view to poke through - eventchase_target_origin = freeze_org - v_forward * eventchase_current_distance * (trace_fraction - 0.1); - WarpZone_TraceLine(freeze_org, eventchase_target_origin, MOVE_WORLDONLY, self); + eventchase_target_origin = current_view_origin - v_forward * eventchase_current_distance * (trace_fraction - 0.1); + WarpZone_TraceLine(current_view_origin, eventchase_target_origin, MOVE_WORLDONLY, self); R_SetView(VF_ORIGIN, trace_endpos); R_SetView(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles)); @@ -463,6 +443,18 @@ void CSQC_UpdateView(float w, float h) eventchase_current_distance = 0; // start from 0 next time } } + + // do lockview after event chase camera so that it still applies whenever necessary. + if(autocvar_cl_lockview || intermission > 1) + { + R_SetView(VF_ORIGIN, freeze_org); + R_SetView(VF_ANGLES, freeze_ang); + } + else + { + freeze_org = R_SetView3fv(VF_ORIGIN); + freeze_ang = R_SetView3fv(VF_ANGLES); + } WarpZone_FixView(); //WarpZone_FixPMove(); @@ -510,16 +502,15 @@ void CSQC_UpdateView(float w, float h) PostInit(); if(intermission && !isdemo() && !(calledhooks & HOOK_END)) + { if(calledhooks & HOOK_START) { localcmd("\ncl_hook_gameend\n"); calledhooks |= HOOK_END; } - - CheckForGamestartChange(); - serverAnnouncer(); - maptimeAnnouncer(); - carrierAnnouncer(); + } + + Announcer(); fov = autocvar_fov; if(fov <= 59.5) @@ -540,7 +531,16 @@ void CSQC_UpdateView(float w, float h) } ColorTranslateMode = autocvar_cl_stripcolorcodes; - activeweapon = getstati(STAT_SWITCHWEAPON); + + // next WANTED weapon (for HUD) + switchweapon = getstati(STAT_SWITCHWEAPON); + + // currently switching-to weapon (for crosshair) + switchingweapon = getstati(STAT_SWITCHINGWEAPON); + + // actually active weapon (for zoom) + activeweapon = getstati(STAT_ACTIVEWEAPON); + f = (serverflags & SERVERFLAG_TEAMPLAY); if(f != teamplay) { @@ -548,9 +548,12 @@ void CSQC_UpdateView(float w, float h) HUD_InitScores(); } - if(last_weapon != activeweapon) { + if(last_switchweapon != switchweapon) { weapontime = time; - last_weapon = activeweapon; + last_switchweapon = switchweapon; + } + if(last_activeweapon != activeweapon) { + last_activeweapon = activeweapon; e = get_weaponinfo(activeweapon); if(e.netname != "") @@ -702,7 +705,7 @@ void CSQC_UpdateView(float w, float h) else if(activeweapon == WEP_NEX && button_attack2 || activeweapon == WEP_RIFLE && button_attack2) reticle_type = 2; // nex zoom - if (reticle_type) + if(reticle_type && autocvar_cl_reticle) { if(autocvar_cl_reticle_stretch) { @@ -801,8 +804,7 @@ void CSQC_UpdateView(float w, float h) } } - if(autocvar_hud_damage && !autocvar_chase_active) - + if(autocvar_hud_damage) { splash_size_x = max(vid_conwidth, vid_conheight); splash_size_y = max(vid_conwidth, vid_conheight); @@ -850,24 +852,31 @@ void CSQC_UpdateView(float w, float h) myhealth_prev = myhealth; - if(autocvar_cl_gentle_damage || autocvar_cl_gentle) + // IDEA: change damage color/picture based on player model for robot/alien species? + // pro: matches model better + // contra: it's not red because blood is red, but because red is an alarming color, so red should stay + // maybe different reddish pics? + if(autocvar_chase_active >= 0) // not while the event chase camera is active { - if(autocvar_cl_gentle_damage == 2) + if(autocvar_cl_gentle_damage || autocvar_cl_gentle) { - if(myhealth_flash < pain_threshold) // only randomize when the flash is gone + if(autocvar_cl_gentle_damage == 2) { - myhealth_gentlergb = eX * random() + eY * random() + eZ * random(); + if(myhealth_flash < pain_threshold) // only randomize when the flash is gone + { + myhealth_gentlergb = eX * random() + eY * random() + eZ * random(); + } } + else + myhealth_gentlergb = stov(autocvar_hud_damage_gentle_color); + + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL); } else - myhealth_gentlergb = stov(autocvar_hud_damage_gentle_color); - - drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL); + drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL); } - else - drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL); - if(autocvar_hud_postprocessing) + if(autocvar_hud_postprocessing) // we still need to set this anyway even when chase_active is set, this way it doesn't get stuck on. { if(autocvar_hud_damage_blur && myhealth_flash_temp) { @@ -884,17 +893,13 @@ void CSQC_UpdateView(float w, float h) } } - if(autocvar_hud_postprocessing) + if(autocvar_hud_postprocessing) // TODO: Remove this code and re-do the postprocess handling in the engine, where it properly belongs. { - // all of this should be done in the engine eventually - // enable or disable rendering types if they are used or not - if(cvar("r_glsl_postprocess_uservec1_enable") != (cvar("hud_postprocessing_maxbluralpha") != 0)) - cvar_set("r_glsl_postprocess_uservec1_enable", ftos(cvar("hud_postprocessing_maxbluralpha") != 0)); - if(cvar("r_glsl_postprocess_uservec2_enable") != (cvar("hud_powerup") != 0)) - cvar_set("r_glsl_postprocess_uservec2_enable", ftos(cvar("hud_powerup") != 0)); - - // lets apply the postprocess effects from the previous two functions if needed + if(cvar("r_glsl_postprocess_uservec1_enable") != (autocvar_hud_postprocessing_maxbluralpha != 0)) { cvar_set("r_glsl_postprocess_uservec1_enable", ftos(autocvar_hud_postprocessing_maxbluralpha != 0)); } + if(cvar("r_glsl_postprocess_uservec2_enable") != (autocvar_hud_powerup != 0)) { cvar_set("r_glsl_postprocess_uservec2_enable", ftos(autocvar_hud_powerup != 0)); } + + // blur postprocess handling done first (used by hud_damage and hud_contents) if((damage_blurpostprocess_x || content_blurpostprocess_x) && autocvar_chase_active >= 0) // not while the event chase camera is active { float blurradius = bound(0, damage_blurpostprocess_y + content_blurpostprocess_y, autocvar_hud_postprocessing_maxblurradius); @@ -913,19 +918,18 @@ void CSQC_UpdateView(float w, float h) old_bluralpha = 0; } - float sharpen_intensity; - if (getstatf(STAT_STRENGTH_FINISHED) - time > 0) - sharpen_intensity += (getstatf(STAT_STRENGTH_FINISHED) - time); - if (getstatf(STAT_INVINCIBLE_FINISHED) - time > 0) - sharpen_intensity += (getstatf(STAT_INVINCIBLE_FINISHED) - time); - + // edge detection postprocess handling done second (used by hud_powerup) + float sharpen_intensity, strength_finished = getstatf(STAT_STRENGTH_FINISHED), invincible_finished = getstatf(STAT_INVINCIBLE_FINISHED); + if (strength_finished - time > 0) { sharpen_intensity += (strength_finished - time); } + if (invincible_finished - time > 0) { sharpen_intensity += (invincible_finished - time); } + + sharpen_intensity = bound(0, ((getstati(STAT_HEALTH) > 0) ? sharpen_intensity : 0), 5); // Check to see if player is alive (if not, set 0) - also bound to fade out starting at 5 seconds. + if(autocvar_hud_powerup && sharpen_intensity > 0 && autocvar_chase_active >= 0) // not while the event chase camera is active { - sharpen_intensity = bound(0, sharpen_intensity, 5); // powerup warning time is 5 seconds, so fade the effect from there - if(sharpen_intensity != old_sharpen_intensity) // reduce cvar_set spam as much as possible { - cvar_set("r_glsl_postprocess_uservec2", strcat("0 ", ftos(-sharpen_intensity * cvar("hud_powerup")), " 0 0")); + cvar_set("r_glsl_postprocess_uservec2", strcat(ftos((sharpen_intensity / 5) * autocvar_hud_powerup), " ", ftos(-sharpen_intensity * autocvar_hud_powerup), " 0 0")); old_sharpen_intensity = sharpen_intensity; } } @@ -957,13 +961,17 @@ void CSQC_UpdateView(float w, float h) hit_time = getstatf(STAT_HIT_TIME); if(hit_time > nextsound_hit_time && autocvar_cl_hitsound) { - sound(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE); + if(time - hit_time < MAX_TIME_DIFF) // don't play the sound if it's too old. + sound(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE); + nextsound_hit_time = time + autocvar_cl_hitsound_antispam_time; } typehit_time = getstatf(STAT_TYPEHIT_TIME); - if(typehit_time > nextsound_typehit_time) + if(typehit_time > nextsound_typehit_time) { - sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE); + if(time - typehit_time < MAX_TIME_DIFF) // don't play the sound if it's too old. + sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE); + nextsound_typehit_time = time + autocvar_cl_hitsound_antispam_time; } @@ -1028,7 +1036,7 @@ void CSQC_UpdateView(float w, float h) float wcross_scale, wcross_blur; if (autocvar_crosshair_per_weapon || autocvar_crosshair_color_per_weapon) { - e = get_weaponinfo(activeweapon); + e = get_weaponinfo(switchingweapon); if (e && e.netname != "") { wcross_wep = e.netname; @@ -1051,7 +1059,7 @@ void CSQC_UpdateView(float w, float h) wcross_color = stov(cvar_string(strcat("crosshair_", wcross_wep, "_color"))); else if(autocvar_crosshair_color_by_health) { - local float x = getstati(STAT_HEALTH); + float x = getstati(STAT_HEALTH); //x = red //y = green @@ -1110,10 +1118,14 @@ void CSQC_UpdateView(float w, float h) if(autocvar_crosshair_pickup) { - if(pickup_crosshair_time < getstatf(STAT_LAST_PICKUP)) + float stat_pickup_time = getstatf(STAT_LAST_PICKUP); + + if(pickup_crosshair_time < stat_pickup_time) { - pickup_crosshair_size = 1; - pickup_crosshair_time = getstatf(STAT_LAST_PICKUP); + if(time - stat_pickup_time < MAX_TIME_DIFF) // don't trigger the animation if it's too old + pickup_crosshair_size = 1; + + pickup_crosshair_time = stat_pickup_time; } if(pickup_crosshair_size > 0) @@ -1124,13 +1136,14 @@ void CSQC_UpdateView(float w, float h) wcross_scale += sin(pickup_crosshair_size) * autocvar_crosshair_pickup; } - vector hitindication_color; if(autocvar_crosshair_hitindication) { - hitindication_color = stov(autocvar_crosshair_hitindication_color); + vector hitindication_color = stov(autocvar_crosshair_hitindication_color); if(hitindication_crosshair_time < hit_time) { - hitindication_crosshair_size = 1; + if(time - hit_time < MAX_TIME_DIFF) // don't trigger the animation if it's too old + hitindication_crosshair_size = 1; + hitindication_crosshair_time = hit_time; } @@ -1152,7 +1165,7 @@ void CSQC_UpdateView(float w, float h) f = autocvar_crosshair_effect_speed; if(f < 0) - f *= -2 * g_weaponswitchdelay; + f *= -2 * g_weaponswitchdelay; // anim starts when weapon has been lowered and new weapon comes up if(wcross_scale != wcross_scale_goal_prev || wcross_alpha != wcross_alpha_goal_prev || wcross_color != wcross_color_goal_prev) { wcross_changedonetime = time + f; @@ -1275,6 +1288,14 @@ void CSQC_UpdateView(float w, float h) ring_image = "gfx/crosshair_ring.tga"; } + // if in weapon switch animation, fade ring out/in + if(g_weaponswitchdelay > 0) + { + f = (time - wcross_name_changestarttime) / g_weaponswitchdelay; + if(f > 0 && f < 2) + ring_alpha *= fabs(1 - f); + } + if (autocvar_crosshair_ring_inner && ring_inner_value) // lets draw a ring inside a ring so you can ring while you ring DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_inner_image, ring_inner_value, ring_inner_rgb, wcross_alpha * ring_inner_alpha, DRAWFLAG_ADDITIVE); @@ -1418,7 +1439,7 @@ void CSQC_common_hud(void) if(acc_color_levels) strunzone(acc_color_levels); acc_color_levels = strzone(autocvar_accuracy_color_levels); - acc_levels = tokenize(acc_color_levels); + acc_levels = tokenize_console(acc_color_levels); if (acc_levels > MAX_ACCURACY_LEVELS) acc_levels = MAX_ACCURACY_LEVELS; @@ -1485,8 +1506,8 @@ void CSQC_Demo_Camera() if(autocvar_camera_look_player) { - local vector dir; - local float n; + vector dir; + float n; dir = normalize(view_origin - current_position); n = mouse_angles_z;