From: Mario Date: Tue, 24 Feb 2015 05:00:12 +0000 (+1100) Subject: Merge branch 'master' into Mario/vehicles X-Git-Tag: xonotic-v0.8.2~2059^2~14 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=37903827937b44f174275a75d2dab5301b8ab53e;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into Mario/vehicles Conflicts: qcsrc/client/autocvars.qh qcsrc/client/progs.src qcsrc/client/vehicles/vehicles.qc qcsrc/client/vehicles/vehicles.qh qcsrc/common/constants.qh qcsrc/common/notifications.qh qcsrc/common/vehicles/sv_vehicles.qh qcsrc/common/vehicles/unit/bumblebee.qc qcsrc/server/cl_client.qc qcsrc/server/mutators/mutator_nades.qc qcsrc/server/progs.src qcsrc/server/vehicles/racer.qc qcsrc/server/vehicles/raptor.qc qcsrc/server/vehicles/spiderbot.qc qcsrc/server/vehicles/vehicles.qc qcsrc/server/vehicles/vehicles.qh qcsrc/server/weapons/weaponsystem.qh --- 37903827937b44f174275a75d2dab5301b8ab53e diff --cc qcsrc/client/autocvars.qh index c0e4fa464b,e35bf82dd2..ac18e9190f --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@@ -36,47 -39,50 +39,47 @@@ float autocvar_cl_effects_lightningarc_ float autocvar_cl_effects_lightningarc_drift_end; float autocvar_cl_effects_lightningarc_drift_start; float autocvar_cl_effects_lightningarc_segmentlength; - float autocvar_cl_effects_lightningarc_simple; - float autocvar_cl_gentle; - float autocvar_cl_gentle_damage; - float autocvar_cl_gentle_gibs; - float autocvar_cl_gentle_messages; - var float autocvar_cl_gibs_damageforcescale = 3.5; - var float autocvar_cl_gibs_lifetime = 14; - var float autocvar_cl_gibs_maxcount = 100; - var float autocvar_cl_gibs_sloppy = 1; - var float autocvar_cl_gibs_ticrate = 0.1; - var float autocvar_cl_gibs_velocity_random = 1; - var float autocvar_cl_gibs_velocity_scale = 1; - var float autocvar_cl_gibs_avelocity_scale = 1; + bool autocvar_cl_effects_lightningarc_simple; + int autocvar_cl_gentle; + int autocvar_cl_gentle_damage; + int autocvar_cl_gentle_gibs; + int autocvar_cl_gentle_messages; + float autocvar_cl_gibs_damageforcescale = 3.5; + float autocvar_cl_gibs_lifetime = 14; + float autocvar_cl_gibs_maxcount = 100; + bool autocvar_cl_gibs_sloppy = 1; + float autocvar_cl_gibs_ticrate = 0.1; + float autocvar_cl_gibs_velocity_random = 1; + float autocvar_cl_gibs_velocity_scale = 1; + float autocvar_cl_gibs_avelocity_scale = 1; float autocvar_cl_gibs_velocity_up; - float autocvar_cl_gunalign; - float autocvar_cl_hidewaypoints; - float autocvar_cl_lockview; - float autocvar_cl_nogibs; - float autocvar_cl_orthoview; - float autocvar_cl_orthoview_nofog; - float autocvar_cl_particlegibs; - float autocvar_cl_particles_oldvortexbeam; + int autocvar_cl_gunalign; + bool autocvar_cl_hidewaypoints; + bool autocvar_cl_lockview; + bool autocvar_cl_nogibs; + bool autocvar_cl_orthoview; + bool autocvar_cl_orthoview_nofog; + bool autocvar_cl_particlegibs; + bool autocvar_cl_particles_oldvortexbeam; float autocvar_cl_particles_quality; - float autocvar_cl_projectiles_sloppy; - float autocvar_cl_readpicture_force; - var float autocvar_cl_reticle = 1; - var float autocvar_cl_reticle_normal_alpha = 1; - var float autocvar_cl_reticle_weapon = 1; - var float autocvar_cl_reticle_weapon_alpha = 1; - float autocvar_cl_reticle_stretch; - float autocvar_cl_spawn_event_particles; - var float autocvar_cl_spawn_event_sound = 1; + bool autocvar_cl_projectiles_sloppy; + bool autocvar_cl_readpicture_force; + bool autocvar_cl_reticle = 1; + float autocvar_cl_reticle_normal_alpha = 1; + bool autocvar_cl_reticle_weapon = 1; + float autocvar_cl_reticle_weapon_alpha = 1; + bool autocvar_cl_reticle_stretch; + bool autocvar_cl_spawn_event_particles; + bool autocvar_cl_spawn_event_sound = 1; // float autocvar_cl_spawn_point_model; - float autocvar_cl_spawn_point_particles; - var float autocvar_cl_spawnzoom = 1; - var float autocvar_cl_spawnzoom_speed = 1; - var float autocvar_cl_spawnzoom_factor = 2; - float autocvar_cl_stripcolorcodes; - float autocvar_cl_velocityzoom_enabled; + bool autocvar_cl_spawn_point_particles; + bool autocvar_cl_spawnzoom = 1; + float autocvar_cl_spawnzoom_speed = 1; + float autocvar_cl_spawnzoom_factor = 2; + bool autocvar_cl_stripcolorcodes; -float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6; -float autocvar_cl_vehicle_spiderbot_cross_size = 1; -bool autocvar_cl_vehicles_hud_tactical = 1; + bool autocvar_cl_velocityzoom_enabled; float autocvar_cl_velocityzoom_factor; - var float autocvar_cl_velocityzoom_type = 3; + int autocvar_cl_velocityzoom_type = 3; float autocvar_cl_velocityzoom_speed; float autocvar_cl_velocityzoom_time; string autocvar_cl_weaponpriority; diff --cc qcsrc/client/damage.qc index 162ef6a07e,000ef8bcc9..bed41a1ca3 --- a/qcsrc/client/damage.qc +++ b/qcsrc/client/damage.qc @@@ -1,3 -1,19 +1,19 @@@ + #if defined(CSQC) + #include "../dpdefs/csprogsdefs.qh" + #include "defs.qh" + #include "../common/constants.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "autocvars.qh" + #include "../common/deathtypes.qh" + #include "damage.qh" + #include "movetypes.qh" + #include "prandom.qh" - #include "vehicles/vehicles.qh" ++ #include "../common/vehicles/cl_vehicles.qh" + #elif defined(MENUQC) + #elif defined(SVQC) + #endif + void DamageEffect_Think() { // if particle distribution is enabled, slow ticrate by total number of damages diff --cc qcsrc/client/main.qc index 0000000000,13f9545faa..cabb13e16a mode 000000,100644..100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@@ -1,0 -1,1319 +1,1318 @@@ + #include "mapvoting.qh" + #include "modeleffects.qh" + #include "particles.qh" + #include "scoreboard.qh" + #include "shownames.qh" + #include "target_music.qh" + #include "tturrets.qh" + #include "tuba.qh" + #include "wall.qh" + #include "waypointsprites.qh" + -#include "vehicles/vehicles.qh" - -#include "../server/vehicles/bumblebee.qh" ++#include "../common/vehicles/vehicles.qh" ++#include "../common/vehicles/cl_vehicles.qh" + + #include "../common/net_notice.qh" + + #include "../common/monsters/monsters.qh" + + #include "../warpzonelib/client.qh" + + // -------------------------------------------------------------------------- + // BEGIN REQUIRED CSQC FUNCTIONS + //include "main.qh" + + entity clearentity_ent; + void clearentity(entity e) + { + if (!clearentity_ent) + { + clearentity_ent = spawn(); + clearentity_ent.classname = "clearentity"; + } + int n = e.entnum; + copyentity(clearentity_ent, e); + e.entnum = n; + } + + #define DP_CSQC_ENTITY_REMOVE_IS_B0RKED + void menu_show_error() + { + drawstring('0 200 0', _("ERROR - MENU IS VISIBLE BUT NO MENU WAS DEFINED!"), '8 8 0', '1 0 0', 1, 0); + } + + // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load) + // Useful for precaching things + + void menu_sub_null() + { + } + + string forcefog; + void WaypointSprite_Load(); + void ConsoleCommand_macro_init(); + void CSQC_Init(void) + { + prvm_language = cvar_string("prvm_language"); + + #ifdef WATERMARK + dprintf("^4CSQC Build information: ^1%s\n", WATERMARK); + #endif + + int i; + + binddb = db_create(); + tempdb = db_create(); + ClientProgsDB = db_load("client.db"); + compressShortVector_init(); + + draw_endBoldFont(); + menu_visible = false; + menu_show = menu_show_error; + menu_action = func_null; + + for(i = 0; i < 255; ++i) + if(getplayerkeyvalue(i, "viewentity") == "") + break; + maxclients = i; + + //registercommand("hud_configure"); + //registercommand("hud_save"); + //registercommand("menu_action"); + + ConsoleCommand_macro_init(); + + registercvar("hud_usecsqc", "1"); + registercvar("scoreboard_columns", "default"); + + registercvar("cl_nade_type", "3"); + registercvar("cl_pokenade_type", "zombie"); + + gametype = 0; + + // hud_fields uses strunzone on the titles! + for(i = 0; i < MAX_HUD_FIELDS; ++i) + hud_title[i] = strzone("(null)"); + + Cmd_HUD_SetFields(0); + + postinit = false; + + calledhooks = 0; + + teams = Sort_Spawn(); + players = Sort_Spawn(); + + GetTeam(NUM_SPECTATOR, true); // add specs first + + // needs to be done so early because of the constants they create + CALL_ACCUMULATED_FUNCTION(RegisterWeapons); ++ CALL_ACCUMULATED_FUNCTION(RegisterVehicles); + CALL_ACCUMULATED_FUNCTION(RegisterMonsters); + CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + CALL_ACCUMULATED_FUNCTION(RegisterNotifications); + CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); + + WaypointSprite_Load(); + + // precaches + precache_model("null"); + precache_sound("misc/hit.wav"); + precache_sound("misc/typehit.wav"); + + Projectile_Precache(); + Hook_Precache(); + GibSplash_Precache(); + Casings_Precache(); - Vehicles_Precache(); + turrets_precache(); + Tuba_Precache(); + CSQCPlayer_Precache(); + + if(autocvar_cl_reticle) + { + precache_pic("gfx/reticle_normal"); + // weapon reticles are precached in weapon files + } + + get_mi_min_max_texcoords(1); // try the CLEVER way first + minimapname = strcat("gfx/", mi_shortname, "_radar.tga"); + shortmapname = mi_shortname; + + if(precache_pic(minimapname) == "") + { + // but maybe we have a non-clever minimap + minimapname = strcat("gfx/", mi_shortname, "_mini.tga"); + if(precache_pic(minimapname) == "") + minimapname = ""; // FAIL + else + get_mi_min_max_texcoords(0); // load new texcoords + } + + mi_center = (mi_min + mi_max) * 0.5; + mi_scale = mi_max - mi_min; + minimapname = strzone(minimapname); + + WarpZone_Init(); + + hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin)); + hud_configure_prev = -1; + + draw_currentSkin = strzone(strcat("gfx/menu/", cvar_string("menu_skin"))); + } + + // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc) + void Shutdown(void) + { + WarpZone_Shutdown(); + + remove(teams); + remove(players); + db_close(binddb); + db_close(tempdb); + if(autocvar_cl_db_saveasdump) + db_dump(ClientProgsDB, "client.db"); + else + db_save(ClientProgsDB, "client.db"); + db_close(ClientProgsDB); + + if(camera_active) + cvar_set("chase_active",ftos(chase_active_backup)); + + // unset the event chasecam's chase_active + if(autocvar_chase_active < 0) + cvar_set("chase_active", "0"); + + if (!isdemo()) + { + if (!(calledhooks & HOOK_START)) + localcmd("\n_cl_hook_gamestart nop\n"); + if (!(calledhooks & HOOK_END)) + localcmd("\ncl_hook_gameend\n"); + } + } + + .float has_team; + float SetTeam(entity o, int Team) + { + entity tm; + if(teamplay) + { + switch(Team) + { + case -1: + case NUM_TEAM_1: + case NUM_TEAM_2: + case NUM_TEAM_3: + case NUM_TEAM_4: + break; + default: + if(GetTeam(Team, false) == world) + { + dprintf("trying to switch to unsupported team %d\n", Team); + Team = NUM_SPECTATOR; + } + break; + } + } + else + { + switch(Team) + { + case -1: + case 0: + break; + default: + if(GetTeam(Team, false) == world) + { + dprintf("trying to switch to unsupported team %d\n", Team); + Team = NUM_SPECTATOR; + } + break; + } + } + if(Team == -1) // leave + { + if(o.has_team) + { + tm = GetTeam(o.team, false); + tm.team_size -= 1; + o.has_team = 0; + return true; + } + } + else + { + if (!o.has_team) + { + o.team = Team; + tm = GetTeam(Team, true); + tm.team_size += 1; + o.has_team = 1; + return true; + } + else if(Team != o.team) + { + tm = GetTeam(o.team, false); + tm.team_size -= 1; + o.team = Team; + tm = GetTeam(Team, true); + tm.team_size += 1; + return true; + } + } + return false; + } + + void Playerchecker_Think() + { + int i; + entity e; + for(i = 0; i < maxclients; ++i) + { + e = playerslots[i]; + if(GetPlayerName(i) == "") + { + if(e.sort_prev) + { + // player disconnected + SetTeam(e, -1); + RemovePlayer(e); + e.sort_prev = world; + //e.gotscores = 0; + } + } + else + { + if (!e.sort_prev) + { + // player connected + if (!e) + playerslots[i] = e = spawn(); + e.sv_entnum = i; + e.ping = 0; + e.ping_packetloss = 0; + e.ping_movementloss = 0; + //e.gotscores = 0; // we might already have the scores... + SetTeam(e, GetPlayerColor(i)); // will not hurt; later updates come with HUD_UpdatePlayerTeams + RegisterPlayer(e); + HUD_UpdatePlayerPos(e); + } + } + } + self.nextthink = time + 0.2; + } + + void Porto_Init(); + void TrueAim_Init(); + void PostInit(void) + { + entity playerchecker; + playerchecker = spawn(); + playerchecker.think = Playerchecker_Think; + playerchecker.nextthink = time + 0.2; + + Porto_Init(); + TrueAim_Init(); + + postinit = true; + } + + // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client. + // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine. + // All keys are in ascii. + // bInputType = 0 is key pressed, 1 is key released, 2 and 3 are mouse input. + // In the case of keyboard input, nPrimary is the ascii code, and nSecondary is 0. + // In the case of mouse input, nPrimary is xdelta, nSecondary is ydelta. + // In the case of mouse input after a setcursormode(1) call, nPrimary is xpos, nSecondary is ypos. + float CSQC_InputEvent(float bInputType, float nPrimary, float nSecondary) + { + float bSkipKey; + bSkipKey = false; + + if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary)) + return true; + + if (MapVote_InputEvent(bInputType, nPrimary, nSecondary)) + return true; + + if(menu_visible && menu_action) + if(menu_action(bInputType, nPrimary, nSecondary)) + return true; + + return bSkipKey; + } + + // END REQUIRED CSQC FUNCTIONS + // -------------------------------------------------------------------------- + + // -------------------------------------------------------------------------- + // BEGIN OPTIONAL CSQC FUNCTIONS + void Ent_RemoveEntCS() + { + entcs_receiver[self.sv_entnum] = world; + } + void Ent_ReadEntCS() + { + int sf; + InterpolateOrigin_Undo(); + + self.classname = "entcs_receiver"; + sf = ReadByte(); + + if(sf & 1) + self.sv_entnum = ReadByte(); + if(sf & 2) + { + self.origin_x = ReadShort(); + self.origin_y = ReadShort(); + self.origin_z = ReadShort(); + setorigin(self, self.origin); + } + if(sf & 4) + { + self.angles_y = ReadByte() * 360.0 / 256; + self.angles_x = self.angles_z = 0; + } + if(sf & 8) + self.healthvalue = ReadByte() * 10; + if(sf & 16) + self.armorvalue = ReadByte() * 10; + + entcs_receiver[self.sv_entnum] = self; + self.entremove = Ent_RemoveEntCS; + self.iflags |= IFLAG_ORIGIN; + + InterpolateOrigin_Note(); + } + + void Ent_Remove(); + + void Ent_RemovePlayerScore() + { + if(self.owner) { + SetTeam(self.owner, -1); + self.owner.gotscores = 0; + for(int i = 0; i < MAX_SCORE; ++i) { + self.owner.(scores[i]) = 0; // clear all scores + } + } + } + + void Ent_ReadPlayerScore() + { + int i, n; + bool isNew; + entity o; + + // damnit -.- don't want to go change every single .sv_entnum in hud.qc AGAIN + // (no I've never heard of M-x replace-string, sed, or anything like that) + isNew = !self.owner; // workaround for DP bug + n = ReadByte()-1; + + #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED + if(!isNew && n != self.sv_entnum) + { + //print("A CSQC entity changed its owner!\n"); + printf("A CSQC entity changed its owner! (edict: %d, classname: %s)\n", num_for_edict(self), self.classname); + isNew = true; + Ent_Remove(); + self.enttype = ENT_CLIENT_SCORES; + } + #endif + + self.sv_entnum = n; + + if (!(playerslots[self.sv_entnum])) + playerslots[self.sv_entnum] = spawn(); + o = self.owner = playerslots[self.sv_entnum]; + o.sv_entnum = self.sv_entnum; + o.gotscores = 1; + + //if (!o.sort_prev) + // RegisterPlayer(o); + //playerchecker will do this for us later, if it has not already done so + + int sf, lf; + #if MAX_SCORE <= 8 + sf = ReadByte(); + lf = ReadByte(); + #else + sf = ReadShort(); + lf = ReadShort(); + #endif + int p; + for(i = 0, p = 1; i < MAX_SCORE; ++i, p *= 2) + if(sf & p) + { + if(lf & p) + o.(scores[i]) = ReadInt24_t(); + else + o.(scores[i]) = ReadChar(); + } + + if(o.sort_prev) + HUD_UpdatePlayerPos(o); // if not registered, we cannot do this yet! + + self.entremove = Ent_RemovePlayerScore; + } + + void Ent_ReadTeamScore() + { + int i; + entity o; + + self.team = ReadByte(); + o = self.owner = GetTeam(self.team, true); // these team numbers can always be trusted + + int sf, lf; + #if MAX_TEAMSCORE <= 8 + sf = ReadByte(); + lf = ReadByte(); + #else + sf = ReadShort(); + lf = ReadShort(); + #endif + int p; + for(i = 0, p = 1; i < MAX_TEAMSCORE; ++i, p *= 2) + if(sf & p) + { + if(lf & p) + o.(teamscores[i]) = ReadInt24_t(); + else + o.(teamscores[i]) = ReadChar(); + } + + HUD_UpdateTeamPos(o); + } + + void Ent_ClientData() + { + float newspectatee_status; + + int f = ReadByte(); + + scoreboard_showscores_force = (f & 1); + + if(f & 2) + { + newspectatee_status = ReadByte(); + if(newspectatee_status == player_localnum + 1) + newspectatee_status = -1; // observing + } + else + newspectatee_status = 0; + + spectatorbutton_zoom = (f & 4); + + if(f & 8) + { + angles_held_status = 1; + angles_held.x = ReadAngle(); + angles_held.y = ReadAngle(); + angles_held.z = 0; + } + else + angles_held_status = 0; + + if(newspectatee_status != spectatee_status) + { + // clear race stuff + race_laptime = 0; + race_checkpointtime = 0; + } + if (autocvar_hud_panel_healtharmor_progressbar_gfx) + { + if ( (spectatee_status == -1 && newspectatee_status > 0) //before observing, now spectating + || (spectatee_status > 0 && newspectatee_status > 0 && spectatee_status != newspectatee_status) //changed spectated player + ) + prev_p_health = -1; + else if(spectatee_status && !newspectatee_status) //before observing/spectating, now playing + prev_health = -1; + } + spectatee_status = newspectatee_status; + + // we could get rid of spectatee_status, and derive it from player_localentnum and player_localnum + } + + void Ent_Nagger() + { + int i, j, b, f; + + int nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS + + if(!(nags & 4)) + { + if(vote_called_vote) + strunzone(vote_called_vote); + vote_called_vote = string_null; + vote_active = 0; + } + else + { + vote_active = 1; + } + + if(nags & 64) + { + vote_yescount = ReadByte(); + vote_nocount = ReadByte(); + vote_needed = ReadByte(); + vote_highlighted = ReadChar(); + } + + if(nags & 128) + { + if(vote_called_vote) + strunzone(vote_called_vote); + vote_called_vote = strzone(ColorTranslateRGB(ReadString())); + } + + if(nags & 1) + { + for(j = 0; j < maxclients; ++j) + if(playerslots[j]) + playerslots[j].ready = 1; + for(i = 1; i <= maxclients; i += 8) + { + f = ReadByte(); + for(j = i-1, b = 1; b < 256; b *= 2, ++j) + if (!(f & b)) + if(playerslots[j]) + playerslots[j].ready = 0; + } + } + + ready_waiting = (nags & 1); + ready_waiting_for_me = (nags & 2); + vote_waiting = (nags & 4); + vote_waiting_for_me = (nags & 8); + warmup_stage = (nags & 16); + } + + void Ent_EliminatedPlayers() + { + int i, j, b, f; + + int sf = ReadByte(); + if(sf & 1) + { + for(j = 0; j < maxclients; ++j) + if(playerslots[j]) + playerslots[j].eliminated = 1; + for(i = 1; i <= maxclients; i += 8) + { + f = ReadByte(); + for(j = i-1, b = 1; b < 256; b *= 2, ++j) + if (!(f & b)) + if(playerslots[j]) + playerslots[j].eliminated = 0; + } + } + } + + void Ent_RandomSeed() + { + float s; + prandom_debug(); + s = ReadShort(); + psrandom(s); + } + + void Ent_ReadAccuracy(void) + { + int f, w; + int sf = ReadInt24_t(); + if(sf == 0) + { + for(w = 0; w <= WEP_LAST - WEP_FIRST; ++w) + weapon_accuracy[w] = -1; + return; + } + + for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w) + { + if(sf & f) + { + int b = ReadByte(); + if(b == 0) + weapon_accuracy[w] = -1; + else if(b == 255) + weapon_accuracy[w] = 1.0; // no better error handling yet, sorry + else + weapon_accuracy[w] = (b - 1.0) / 100.0; + } + if(f == 0x800000) + f = 1; + else + f *= 2; + } + } + + void Spawn_Draw(void) + { + pointparticles(self.cnt, self.origin + '0 0 28', '0 0 2', bound(0, frametime, 0.1)); + } + + void Ent_ReadSpawnPoint(float is_new) // entity for spawnpoint + { + float teamnum = (ReadByte() - 1); + vector spn_origin; + spn_origin.x = ReadShort(); + spn_origin.y = ReadShort(); + spn_origin.z = ReadShort(); + + if(is_new) + { + self.origin = spn_origin; + setsize(self, PL_MIN, PL_MAX); + droptofloor(); + + /*if(autocvar_cl_spawn_point_model) // needs a model first + { + self.mdl = "models/spawnpoint.md3"; + self.colormod = Team_ColorRGB(teamnum); + precache_model(self.mdl); + setmodel(self, self.mdl); + self.drawmask = MASK_NORMAL; + //self.movetype = MOVETYPE_NOCLIP; + //self.draw = Spawn_Draw; + }*/ + if(autocvar_cl_spawn_point_particles) + { + if((serverflags & SERVERFLAG_TEAMPLAY)) + { + switch(teamnum) + { + case NUM_TEAM_1: self.cnt = particleeffectnum("spawn_point_red"); break; + case NUM_TEAM_2: self.cnt = particleeffectnum("spawn_point_blue"); break; + case NUM_TEAM_3: self.cnt = particleeffectnum("spawn_point_yellow"); break; + case NUM_TEAM_4: self.cnt = particleeffectnum("spawn_point_pink"); break; + default: self.cnt = particleeffectnum("spawn_point_neutral"); break; + } + } + else { self.cnt = particleeffectnum("spawn_point_neutral"); } + + self.draw = Spawn_Draw; + } + } + + //printf("Ent_ReadSpawnPoint(is_new = %d); origin = %s, team = %d, effect = %d\n", is_new, vtos(self.origin), teamnum, self.cnt); + } + + void Ent_ReadSpawnEvent(float is_new) + { + // If entnum is 0, ONLY do the local spawn actions + // this way the server can disable the sending of + // spawn origin or such to clients if wanted. + float entnum = ReadByte(); + + if(entnum) + { + self.origin_x = ReadShort(); + self.origin_y = ReadShort(); + self.origin_z = ReadShort(); + + if(is_new) + { + float teamnum = GetPlayerColor(entnum - 1); + + if(autocvar_cl_spawn_event_particles) + { + switch(teamnum) + { + case NUM_TEAM_1: pointparticles(particleeffectnum("spawn_event_red"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_2: pointparticles(particleeffectnum("spawn_event_blue"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_3: pointparticles(particleeffectnum("spawn_event_yellow"), self.origin, '0 0 0', 1); break; + case NUM_TEAM_4: pointparticles(particleeffectnum("spawn_event_pink"), self.origin, '0 0 0', 1); break; + default: pointparticles(particleeffectnum("spawn_event_neutral"), self.origin, '0 0 0', 1); break; + } + } + if(autocvar_cl_spawn_event_sound) + { + sound(self, CH_TRIGGER, "misc/spawn.wav", VOL_BASE, ATTEN_NORM); + } + } + } + + // local spawn actions + if(is_new && (!entnum || (entnum == player_localentnum))) + { + zoomin_effect = 1; + current_viewzoom = (1 / bound(1, autocvar_cl_spawnzoom_factor, 16)); + + if(autocvar_cl_unpress_zoom_on_spawn) + { + localcmd("-zoom\n"); + button_zoom = false; + } + } + + //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum); + } + + // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured. + // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS. + void Ent_RadarLink(); + void Ent_Init(); + void Ent_ScoresInfo(); + void CSQC_Ent_Update(float bIsNewEntity) + { + float t; + float savetime; + t = ReadByte(); + + if(autocvar_developer_csqcentities) + printf("CSQC_Ent_Update(%d) with self=%i self.entnum=%d self.enttype=%d t=%d\n", bIsNewEntity, self, self.entnum, self.enttype, t); + + // set up the "time" global for received entities to be correct for interpolation purposes + savetime = time; + if(servertime) + { + time = servertime; + } + else + { + serverprevtime = time; + serverdeltatime = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE); + time = serverprevtime + serverdeltatime; + } + + #ifdef DP_CSQC_ENTITY_REMOVE_IS_B0RKED + if(self.enttype) + { + if(t != self.enttype || bIsNewEntity) + { + //print("A CSQC entity changed its type!\n"); + printf("A CSQC entity changed its type! (edict: %d, server: %d, type: %d -> %d)\n", num_for_edict(self), self.entnum, self.enttype, t); + Ent_Remove(); + clearentity(self); + bIsNewEntity = 1; + } + } + else + { + if(!bIsNewEntity) + { + printf("A CSQC entity appeared out of nowhere! (edict: %d, server: %d, type: %d)\n", num_for_edict(self), self.entnum, t); + bIsNewEntity = 1; + } + } + #endif + self.enttype = t; + switch(t) + { + case ENT_CLIENT_ENTCS: Ent_ReadEntCS(); break; + case ENT_CLIENT_SCORES: Ent_ReadPlayerScore(); break; + case ENT_CLIENT_TEAMSCORES: Ent_ReadTeamScore(); break; + case ENT_CLIENT_POINTPARTICLES: Ent_PointParticles(); break; + case ENT_CLIENT_RAINSNOW: Ent_RainOrSnow(); break; + case ENT_CLIENT_LASER: Ent_Laser(); break; + case ENT_CLIENT_NAGGER: Ent_Nagger(); break; + case ENT_CLIENT_ELIMINATEDPLAYERS: Ent_EliminatedPlayers(); break; + case ENT_CLIENT_WAYPOINT: Ent_WaypointSprite(); break; + case ENT_CLIENT_RADARLINK: Ent_RadarLink(); break; + case ENT_CLIENT_PROJECTILE: Ent_Projectile(); break; + case ENT_CLIENT_GIBSPLASH: Ent_GibSplash(bIsNewEntity); break; + case ENT_CLIENT_DAMAGEINFO: Ent_DamageInfo(bIsNewEntity); break; + case ENT_CLIENT_CASING: Ent_Casing(bIsNewEntity); break; + case ENT_CLIENT_INIT: Ent_Init(); break; + case ENT_CLIENT_SCORES_INFO: Ent_ScoresInfo(); break; + case ENT_CLIENT_MAPVOTE: Ent_MapVote(); break; + case ENT_CLIENT_CLIENTDATA: Ent_ClientData(); break; + case ENT_CLIENT_RANDOMSEED: Ent_RandomSeed(); break; + case ENT_CLIENT_WALL: Ent_Wall(); break; + case ENT_CLIENT_MODELEFFECT: Ent_ModelEffect(bIsNewEntity); break; + case ENT_CLIENT_TUBANOTE: Ent_TubaNote(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE: WarpZone_Read(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE_CAMERA: WarpZone_Camera_Read(bIsNewEntity); break; + case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break; + case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break; + case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break; + case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break; + case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break; + case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break; + case ENT_CLIENT_TURRET: ent_turret(); break; + case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break; + case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break; + case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break; + case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break; + case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break; + case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break; + case ENT_CLIENT_HEALING_ORB: ent_healer(); break; + + default: + //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); + error(sprintf("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n", self.enttype, num_for_edict(self), self.classname)); + break; + } + + time = savetime; + } + // Destructor, but does NOT deallocate the entity by calling remove(). Also + // used when an entity changes its type. For an entity that someone interacts + // with others, make sure it can no longer do so. + void Ent_Remove() + { + if(self.entremove) + self.entremove(); + + if(self.skeletonindex) + { + skel_delete(self.skeletonindex); + self.skeletonindex = 0; + } + + if(self.snd_looping > 0) + { + sound(self, self.snd_looping, "misc/null.wav", VOL_BASE, autocvar_g_jetpack_attenuation); + self.snd_looping = 0; + } + + self.enttype = 0; + self.classname = ""; + self.draw = menu_sub_null; + self.entremove = menu_sub_null; + // TODO possibly set more stuff to defaults + } + // CSQC_Ent_Remove : Called when the server requests a SSQC / CSQC entity to be removed. Essentially call remove(self) as well. + void CSQC_Ent_Remove() + { + if(autocvar_developer_csqcentities) + printf("CSQC_Ent_Remove() with self=%i self.entnum=%d self.enttype=%d\n", self, self.entnum, self.enttype); + + if(wasfreed(self)) + { + print("WARNING: CSQC_Ent_Remove called for already removed entity. Packet loss?\n"); + return; + } + if(self.enttype) + Ent_Remove(); + remove(self); + } + + void Gamemode_Init() + { + if (!isdemo()) + { + if(!(calledhooks & HOOK_START)) + localcmd("\n_cl_hook_gamestart ", MapInfo_Type_ToString(gametype), "\n"); + calledhooks |= HOOK_START; + } + } + // CSQC_Parse_StuffCmd : Provides the stuffcmd string in the first parameter that the server provided. To execute standard behavior, simply execute localcmd with the string. + void CSQC_Parse_StuffCmd(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_StuffCmd(\"%s\")\n", strMessage); + + localcmd(strMessage); + } + // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided. To execute standard behavior, simply execute print with the string. + void CSQC_Parse_Print(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_Print(\"%s\")\n", strMessage); + + print(ColorTranslateRGB(strMessage)); + } + + // CSQC_Parse_CenterPrint : Provides the centerprint_hud string in the first parameter that the server provided. + void CSQC_Parse_CenterPrint(string strMessage) + { + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_CenterPrint(\"%s\")\n", strMessage); + + centerprint_hud(strMessage); + } + + string notranslate_fogcmd1 = "\nfog "; + string notranslate_fogcmd2 = "\nr_fog_exp2 0\nr_drawfog 1\n"; + void Fog_Force() + { + // TODO somehow thwart prvm_globalset client ... + + if(autocvar_cl_orthoview && autocvar_cl_orthoview_nofog) + { localcmd("\nr_drawfog 0\n"); } + else if(forcefog != "") + { localcmd(strcat(notranslate_fogcmd1, forcefog, notranslate_fogcmd2)); } + } + + void Gamemode_Init(); + void Ent_ScoresInfo() + { + int i; + self.classname = "ent_client_scores_info"; + gametype = ReadInt24_t(); + HUD_ModIcons_SetFunc(); + for(i = 0; i < MAX_SCORE; ++i) + { + if(scores_label[i]) + strunzone(scores_label[i]); + scores_label[i] = strzone(ReadString()); + scores_flags[i] = ReadByte(); + } + for(i = 0; i < MAX_TEAMSCORE; ++i) + { + if(teamscores_label[i]) + strunzone(teamscores_label[i]); + teamscores_label[i] = strzone(ReadString()); + teamscores_flags[i] = ReadByte(); + } + HUD_InitScores(); + Gamemode_Init(); + } + + void Ent_Init() + { + self.classname = "ent_client_init"; + + nb_pb_period = ReadByte() / 32; //Accuracy of 1/32th + + hook_shotorigin[0] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[1] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[2] = decompressShotOrigin(ReadInt24_t()); + hook_shotorigin[3] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[0] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[1] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t()); + arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t()); + + if(forcefog) + strunzone(forcefog); + forcefog = strzone(ReadString()); + + armorblockpercent = ReadByte() / 255.0; + + g_balance_mortar_bouncefactor = ReadCoord(); + g_balance_mortar_bouncestop = ReadCoord(); + g_balance_electro_secondary_bouncefactor = ReadCoord(); + g_balance_electro_secondary_bouncestop = ReadCoord(); + + vortex_scope = !ReadByte(); + rifle_scope = !ReadByte(); + + serverflags = ReadByte(); + + minelayer_maxmines = ReadByte(); + + hagar_maxrockets = ReadByte(); + + g_trueaim_minrange = ReadCoord(); + g_balance_porto_secondary = ReadByte(); + + if(!postinit) + PostInit(); + } + + void Net_ReadRace() + { + float b; + + b = ReadByte(); + + switch(b) + { + case RACE_NET_CHECKPOINT_HIT_QUALIFYING: + race_checkpoint = ReadByte(); + race_time = ReadInt24_t(); + race_previousbesttime = ReadInt24_t(); + if(race_previousbestname) + strunzone(race_previousbestname); + race_previousbestname = strzone(ColorTranslateRGB(ReadString())); + + race_checkpointtime = time; + + if(race_checkpoint == 0 || race_checkpoint == 254) + { + race_penaltyaccumulator = 0; + race_laptime = time; // valid + } + + break; + + case RACE_NET_CHECKPOINT_CLEAR: + race_laptime = 0; + race_checkpointtime = 0; + break; + + case RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING: + race_laptime = ReadCoord(); + race_checkpointtime = -99999; + // fall through + case RACE_NET_CHECKPOINT_NEXT_QUALIFYING: + race_nextcheckpoint = ReadByte(); + + race_nextbesttime = ReadInt24_t(); + if(race_nextbestname) + strunzone(race_nextbestname); + race_nextbestname = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_CHECKPOINT_HIT_RACE: + race_mycheckpoint = ReadByte(); + race_mycheckpointtime = time; + race_mycheckpointdelta = ReadInt24_t(); + race_mycheckpointlapsdelta = ReadByte(); + if(race_mycheckpointlapsdelta >= 128) + race_mycheckpointlapsdelta -= 256; + if(race_mycheckpointenemy) + strunzone(race_mycheckpointenemy); + race_mycheckpointenemy = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT: + race_othercheckpoint = ReadByte(); + race_othercheckpointtime = time; + race_othercheckpointdelta = ReadInt24_t(); + race_othercheckpointlapsdelta = ReadByte(); + if(race_othercheckpointlapsdelta >= 128) + race_othercheckpointlapsdelta -= 256; + if(race_othercheckpointenemy) + strunzone(race_othercheckpointenemy); + race_othercheckpointenemy = strzone(ColorTranslateRGB(ReadString())); + break; + + case RACE_NET_PENALTY_RACE: + race_penaltyeventtime = time; + race_penaltytime = ReadShort(); + //race_penaltyaccumulator += race_penaltytime; + if(race_penaltyreason) + strunzone(race_penaltyreason); + race_penaltyreason = strzone(ReadString()); + break; + + case RACE_NET_PENALTY_QUALIFYING: + race_penaltyeventtime = time; + race_penaltytime = ReadShort(); + race_penaltyaccumulator += race_penaltytime; + if(race_penaltyreason) + strunzone(race_penaltyreason); + race_penaltyreason = strzone(ReadString()); + break; + + case RACE_NET_SERVER_RECORD: + race_server_record = ReadInt24_t(); + break; + case RACE_NET_SPEED_AWARD: + race_speedaward = ReadInt24_t(); + if(race_speedaward_holder) + strunzone(race_speedaward_holder); + race_speedaward_holder = strzone(ReadString()); + break; + case RACE_NET_SPEED_AWARD_BEST: + race_speedaward_alltimebest = ReadInt24_t(); + if(race_speedaward_alltimebest_holder) + strunzone(race_speedaward_alltimebest_holder); + race_speedaward_alltimebest_holder = strzone(ReadString()); + break; + case RACE_NET_SERVER_RANKINGS: + float prevpos, del; + int pos = ReadShort(); + prevpos = ReadShort(); + del = ReadShort(); + + // move other rankings out of the way + int i; + if (prevpos) { + for (i=prevpos-1;i>pos-1;--i) { + grecordtime[i] = grecordtime[i-1]; + if(grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i-1]); + } + } else if (del) { // a record has been deleted by the admin + for (i=pos-1; i<= RANKINGS_CNT-1; ++i) { + if (i == RANKINGS_CNT-1) { // clear out last record + grecordtime[i] = 0; + if (grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = string_null; + } + else { + grecordtime[i] = grecordtime[i+1]; + if (grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i+1]); + } + } + } else { // player has no ranked record yet + for (i=RANKINGS_CNT-1;i>pos-1;--i) { + grecordtime[i] = grecordtime[i-1]; + if(grecordholder[i]) + strunzone(grecordholder[i]); + grecordholder[i] = strzone(grecordholder[i-1]); + } + } + + // store new ranking + if(grecordholder[pos-1] != "") + strunzone(grecordholder[pos-1]); + grecordholder[pos-1] = strzone(ReadString()); + grecordtime[pos-1] = ReadInt24_t(); + if(grecordholder[pos-1] == GetPlayerName(player_localnum)) + race_myrank = pos; + break; + case RACE_NET_SERVER_STATUS: + race_status = ReadShort(); + if(race_status_name) + strunzone(race_status_name); + race_status_name = strzone(ReadString()); + } + } + + void Net_TeamNagger() + { + teamnagger = 1; + } + + void Net_ReadPingPLReport() + { + int e, pi, pl, ml; + e = ReadByte(); + pi = ReadShort(); + pl = ReadByte(); + ml = ReadByte(); + if (!(playerslots[e])) + return; + playerslots[e].ping = pi; + playerslots[e].ping_packetloss = pl / 255.0; + playerslots[e].ping_movementloss = ml / 255.0; + } + + void Net_WeaponComplain() + { + complain_weapon = ReadByte(); + + if(complain_weapon_name) + strunzone(complain_weapon_name); + complain_weapon_name = strzone(WEP_NAME(complain_weapon)); + + complain_weapon_type = ReadByte(); + + complain_weapon_time = time; + weapontime = time; // ping the weapon panel + + switch(complain_weapon_type) + { + case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break; + case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break; + default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break; + } + } + + // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer. + // You must ALWAYS first acquire the temporary ID, which is sent as a byte. + // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event. + float CSQC_Parse_TempEntity() + { + float bHandled; + bHandled = true; + // Acquire TE ID + float nTEID; + nTEID = ReadByte(); + + if(autocvar_developer_csqcentities) + printf("CSQC_Parse_TempEntity() with nTEID=%d\n", nTEID); + + // NOTE: Could just do return instead of break... + switch(nTEID) + { + case TE_CSQC_TARGET_MUSIC: + Net_TargetMusic(); + bHandled = true; + break; + case TE_CSQC_PICTURE: + Net_MapVote_Picture(); + bHandled = true; + break; + case TE_CSQC_RACE: + Net_ReadRace(); + bHandled = true; + break; + case TE_CSQC_VORTEXBEAMPARTICLE: + Net_ReadVortexBeamParticle(); + bHandled = true; + break; + case TE_CSQC_TEAMNAGGER: + Net_TeamNagger(); + bHandled = true; + break; + case TE_CSQC_ARC: + Net_ReadArc(); + bHandled = true; + break; + case TE_CSQC_PINGPLREPORT: + Net_ReadPingPLReport(); + bHandled = true; + break; + case TE_CSQC_WEAPONCOMPLAIN: + Net_WeaponComplain(); + bHandled = true; + break; + case TE_CSQC_VEHICLESETUP: + Net_VehicleSetup(); + bHandled = true; + break; + case TE_CSQC_SVNOTICE: + cl_notice_read(); + bHandled = true; + break; + case TE_CSQC_SHOCKWAVEPARTICLE: + Net_ReadShockwaveParticle(); + bHandled = true; + break; + default: + // No special logic for this temporary entity; return 0 so the engine can handle it + bHandled = false; + break; + } + + return bHandled; + } + + string getcommandkey(string text, string command) + { + string keys; + float n, j, k, l = 0; + + if (!autocvar_hud_showbinds) + return text; + + keys = db_get(binddb, command); + if (keys == "") + { + n = tokenize(findkeysforcommand(command, 0)); // uses '...' strings + for(j = 0; j < n; ++j) + { + k = stof(argv(j)); + if(k != -1) + { + if ("" == keys) + keys = keynumtostring(k); + else + keys = strcat(keys, ", ", keynumtostring(k)); + + ++l; + if (autocvar_hud_showbinds_limit > 0 && autocvar_hud_showbinds_limit <= l) + break; + } + + } + if (keys == "") + keys = "NO_KEY"; + db_put(binddb, command, keys); + } + + if (keys == "NO_KEY") { + if (autocvar_hud_showbinds > 1) + return sprintf(_("%s (not bound)"), text); + else + return text; + } + else if (autocvar_hud_showbinds > 1) + return sprintf("%s (%s)", text, keys); + else + return keys; + } diff --cc qcsrc/client/progs.src index 8f4475f84e,f80da18d67..7be9265062 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@@ -1,132 -1,73 +1,72 @@@ ../../csprogs.dat ../common/util-pre.qh - sys-pre.qh - ../dpdefs/csprogsdefs.qc - sys-post.qh + ../dpdefs/csprogsdefs.qh - Defs.qc - ../dpdefs/keycodes.qc - ../common/constants.qh - ../common/stats.qh - - ../warpzonelib/anglestransform.qh - ../warpzonelib/mathlib.qh - ../warpzonelib/common.qh - ../warpzonelib/client.qh - - ../common/playerstats.qh - ../common/teams.qh - ../common/util.qh - ../common/nades.qh - ../common/buffs.qh - ../common/test.qh - ../common/counting.qh - ../common/weapons/weapons.qh // TODO - ../common/mapinfo.qh - ../common/command/markup.qh - ../common/command/rpn.qh - ../common/command/generic.qh - ../common/command/shared_defs.qh - ../common/urllib.qh - ../common/animdecide.qh - command/cl_cmd.qh - - ../common/monsters/monsters.qh - - autocvars.qh - - ../common/notifications.qh // must be after autocvars - ../common/deathtypes.qh // must be after notifications - - damage.qh - - ../csqcmodellib/interpolate.qh - teamradar.qh - hud.qh - scoreboard.qh - waypointsprites.qh - movetypes.qh - prandom.qh - bgmscript.qh - noise.qh - tturrets.qh - ../server/tturrets/include/turrets_early.qh - ../server/movelib.qc - main.qh - ../common/vehicles/vehicles_include.qh - ../common/csqcmodel_settings.qh - ../csqcmodellib/common.qh - ../csqcmodellib/cl_model.qh - ../csqcmodellib/cl_player.qh - weapons/projectile.qh // TODO - player_skeleton.qh - - sortlist.qc - miscfunctions.qc - ../server/t_items.qh - ../server/t_items.qc - - teamradar.qc - hud_config.qc - hud.qc - scoreboard.qc - mapvoting.qc + announcer.qc + bgmscript.qc + casings.qc csqcmodel_hooks.qc - ../common/net_notice.qc - - rubble.qc - hook.qc - particles.qc - laser.qc - weapons/projectile.qc // TODO - gibs.qc damage.qc - casings.qc - ../csqcmodellib/cl_model.qc - ../csqcmodellib/cl_player.qc effects.qc - wall.qc + gibs.qc + hook.qc + hud_config.qc + hud.qc + laser.qc + main.qc + mapvoting.qc + miscfunctions.qc modeleffects.qc - tuba.qc + movetypes.qc + noise.qc + particles.qc + player_skeleton.qc + prandom.qc + rubble.qc + scoreboard.qc + shownames.qc + sortlist.qc target_music.qc + teamradar.qc + tturrets.qc + tuba.qc -vehicles/vehicles.qc + view.qc + wall.qc + waypointsprites.qc - ../common/vehicles/vehicles_include.qc - shownames.qh - shownames.qc + command/cl_cmd.qc - announcer.qc - Main.qc - View.qc - ../csqcmodellib/interpolate.qc - waypointsprites.qc - movetypes.qc - prandom.qc - bgmscript.qc - noise.qc + weapons/projectile.qc // TODO + ../common/animdecide.qc + ../common/buffs.qc + ../common/mapinfo.qc + ../common/nades.qc + ../common/net_notice.qc + ../common/notifications.qc + ../common/playerstats.qc ../common/test.qc + ../common/urllib.qc ../common/util.qc - ../common/playerstats.qc - ../common/notifications.qc + + ../common/command/generic.qc ../common/command/markup.qc ../common/command/rpn.qc - ../common/command/generic.qc - ../common/mapinfo.qc - ../common/weapons/weapons.qc // TODO - ../common/urllib.qc - command/cl_cmd.qc ../common/monsters/monsters.qc - ../common/nades.qc - ../common/buffs.qc + ../common/weapons/weapons.qc // TODO + + ../csqcmodellib/cl_model.qc + ../csqcmodellib/cl_player.qc + ../csqcmodellib/interpolate.qc + + ../server/movelib.qc + ../server/t_items.qc -../server/vehicles/bumblebee.qc ++../common/vehicles/vehicles_include.qc ../warpzonelib/anglestransform.qc - ../warpzonelib/mathlib.qc - ../warpzonelib/common.qc ../warpzonelib/client.qc - tturrets.qc - - player_skeleton.qc - ../common/animdecide.qc + ../warpzonelib/common.qc + ../warpzonelib/mathlib.qc diff --cc qcsrc/client/tturrets.qc index 7ce3b0fd5e,d2469851ca..88d432c0a3 --- a/qcsrc/client/tturrets.qc +++ b/qcsrc/client/tturrets.qc @@@ -248,22 -253,30 +253,22 @@@ void turret_draw2d( { // TODO: Vehicle tactical hud o = project_3d_to_2d(self.origin + '0 0 32'); - if(o_z < 0 - || o_x < (vid_conwidth * waypointsprite_edgeoffset_left) - || o_y < (vid_conheight * waypointsprite_edgeoffset_top) - || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom))) + if(o.z < 0 + || o.x < (vid_conwidth * waypointsprite_edgeoffset_left) + || o.y < (vid_conheight * waypointsprite_edgeoffset_top) + || o.x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) + || o.y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom))) return; // Dont draw wp's for turrets out of view - o_z = 0; + o.z = 0; if(hud != HUD_NORMAL) - { - switch(hud) - { - case HUD_SPIDERBOT: - case HUD_WAKIZASHI: - case HUD_RAPTOR: - case HUD_BUMBLEBEE: - if(self.turret_type == TID_EWHEEL || self.turret_type == TID_WALKER) - txt = "gfx/vehicles/vth-mover.tga"; - else - txt = "gfx/vehicles/vth-stationary.tga"; - - vector pz = drawgetimagesize(txt) * 0.25; - drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.75, DRAWFLAG_NORMAL); - break; - } + { + if(self.turret_type == TID_EWHEEL || self.turret_type == TID_WALKER) + txt = "gfx/vehicles/vth-mover.tga"; + else + txt = "gfx/vehicles/vth-stationary.tga"; + + vector pz = drawgetimagesize(txt) * 0.25; + drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.75, DRAWFLAG_NORMAL); } } diff --cc qcsrc/client/view.qc index 0000000000,ee8ef320ae..4947e9d5c6 mode 000000,100644..100644 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@@ -1,0 -1,1962 +1,1952 @@@ + #if defined(CSQC) + #include "../dpdefs/csprogsdefs.qh" + #include "defs.qh" + #include "../common/constants.qh" + #include "../common/stats.qh" + #include "../warpzonelib/mathlib.qh" + #include "../warpzonelib/common.qh" + #include "../warpzonelib/client.qh" + #include "../common/teams.qh" + #include "../common/util.qh" + #include "../common/nades.qh" + #include "../common/weapons/weapons.qh" + #include "../common/mapinfo.qh" + #include "autocvars.qh" + #include "hud.qh" + #include "scoreboard.qh" + #include "noise.qh" + #include "main.qh" + #include "../csqcmodellib/cl_player.qh" + #elif defined(MENUQC) + #elif defined(SVQC) + #endif + + entity porto; + vector polyline[16]; + void Porto_Draw() + { + vector p, dir, ang, q, nextdir; + float portal_number, portal1_idx; + + if(activeweapon != WEP_PORTO || spectatee_status || gametype == MAPINFO_TYPE_NEXBALL) + return; + if(g_balance_porto_secondary) + return; + if(intermission == 1) + return; + if(intermission == 2) + return; + if (getstati(STAT_HEALTH) <= 0) + return; + + dir = view_forward; + + if(angles_held_status) + { + makevectors(angles_held); + dir = v_forward; + } + + p = view_origin; + + polyline[0] = p; + int idx = 1; + portal_number = 0; + nextdir = dir; + + for (;;) + { + dir = nextdir; + traceline(p, p + 65536 * dir, true, porto); + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) + return; + nextdir = dir - 2 * (dir * trace_plane_normal) * trace_plane_normal; // mirror dir at trace_plane_normal + p = trace_endpos; + polyline[idx] = p; + ++idx; + if(idx >= 16) + return; + if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP) + continue; + ++portal_number; + ang = vectoangles2(trace_plane_normal, dir); + ang.x = -ang.x; + makevectors(ang); + if(!CheckWireframeBox(porto, p - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward)) + return; + if(portal_number == 1) + { + portal1_idx = idx; + if(portal_number >= 2) + break; + } + } + + while(idx >= 2) + { + p = polyline[idx-2]; + q = polyline[idx-1]; + if(idx == 2) + p = p - view_up * 16; + if(idx-1 >= portal1_idx) + { + Draw_CylindricLine(p, q, 4, "", 1, 0, '0 0 1', 0.5, DRAWFLAG_NORMAL, view_origin); + } + else + { + Draw_CylindricLine(p, q, 4, "", 1, 0, '1 0 0', 0.5, DRAWFLAG_NORMAL, view_origin); + } + --idx; + } + } + + void Porto_Init() + { + porto = spawn(); + porto.classname = "porto"; + porto.draw = Porto_Draw; + porto.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP; + } + + float drawtime; + float avgspeed; + vector GetCurrentFov(float fov) + { + float zoomsensitivity, zoomspeed, zoomfactor, zoomdir; + float velocityzoom, curspeed; + vector v; + + zoomsensitivity = autocvar_cl_zoomsensitivity; + zoomfactor = autocvar_cl_zoomfactor; + if(zoomfactor < 1 || zoomfactor > 16) + zoomfactor = 2.5; + zoomspeed = autocvar_cl_zoomspeed; + if(zoomspeed >= 0) + if(zoomspeed < 0.5 || zoomspeed > 16) + zoomspeed = 3.5; + + zoomdir = button_zoom; + if(hud == HUD_NORMAL) + if((activeweapon == WEP_VORTEX && vortex_scope) || (activeweapon == WEP_RIFLE && rifle_scope)) // do NOT use switchweapon here + zoomdir += button_attack2; + if(spectatee_status > 0 || isdemo()) + { + if(spectatorbutton_zoom) + { + if(zoomdir) + zoomdir = 0; + else + zoomdir = 1; + } + // fteqcc failed twice here already, don't optimize this + } + + if(zoomdir) { zoomin_effect = 0; } + + if(camera_active) + { + current_viewzoom = min(1, current_viewzoom + drawframetime); + } + else if(autocvar_cl_spawnzoom && zoomin_effect) + { + float spawnzoomfactor = bound(1, autocvar_cl_spawnzoom_factor, 16); + + current_viewzoom += (autocvar_cl_spawnzoom_speed * (spawnzoomfactor - current_viewzoom) * drawframetime); + current_viewzoom = bound(1 / spawnzoomfactor, current_viewzoom, 1); + if(current_viewzoom == 1) { zoomin_effect = 0; } + } + else + { + if(zoomspeed < 0) // instant zoom + { + if(zoomdir) + current_viewzoom = 1 / zoomfactor; + else + current_viewzoom = 1; + } + else + { + if(zoomdir) + current_viewzoom = 1 / bound(1, 1 / current_viewzoom + drawframetime * zoomspeed * (zoomfactor - 1), zoomfactor); + else + current_viewzoom = bound(1 / zoomfactor, current_viewzoom + drawframetime * zoomspeed * (1 - 1 / zoomfactor), 1); + } + } + + if(almost_equals(current_viewzoom, 1)) + current_zoomfraction = 0; + else if(almost_equals(current_viewzoom, 1/zoomfactor)) + current_zoomfraction = 1; + else + current_zoomfraction = (current_viewzoom - 1) / (1/zoomfactor - 1); + + if(zoomsensitivity < 1) + setsensitivityscale(pow(current_viewzoom, 1 - zoomsensitivity)); + else + setsensitivityscale(1); + + if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too + { + if(intermission) { curspeed = 0; } + else + { + + makevectors(view_angles); + v = pmove_vel; + if(csqcplayer) + v = csqcplayer.velocity; + + switch(autocvar_cl_velocityzoom_type) + { + case 3: curspeed = max(0, v_forward * v); break; + case 2: curspeed = (v_forward * v); break; + case 1: default: curspeed = vlen(v); 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_factor / 1) * 1); + + //print(ftos(avgspeed), " avgspeed, ", ftos(curspeed), " curspeed, ", ftos(velocityzoom), " return\n"); // for debugging + } + else + velocityzoom = 1; + + float frustumx, frustumy, fovx, fovy; + frustumy = tan(fov * M_PI / 360.0) * 0.75 * current_viewzoom * velocityzoom; + frustumx = frustumy * vid_width / vid_height / vid_pixelheight; + fovx = atan2(frustumx, 1) / M_PI * 360.0; + fovy = atan2(frustumy, 1) / M_PI * 360.0; + + return '1 0 0' * fovx + '0 1 0' * fovy; + } + + vector GetOrthoviewFOV(vector ov_worldmin, vector ov_worldmax, vector ov_mid, vector ov_org) + { + float fovx, fovy; + float width = (ov_worldmax.x - ov_worldmin.x); + float height = (ov_worldmax.y - ov_worldmin.y); + float distance_to_middle_of_world = vlen(ov_mid - ov_org); + fovx = atan2(width/2, distance_to_middle_of_world) / M_PI * 360.0; + fovy = atan2(height/2, distance_to_middle_of_world) / M_PI * 360.0; + return '1 0 0' * fovx + '0 1 0' * fovy; + } + + // this function must match W_SetupShot! + float zoomscript_caught; + + vector wcross_origin; + float wcross_scale_prev, wcross_alpha_prev; + vector wcross_color_prev; + float wcross_scale_goal_prev, wcross_alpha_goal_prev; + vector wcross_color_goal_prev; + float wcross_changedonetime; + + string wcross_name_goal_prev, wcross_name_goal_prev_prev; + float wcross_resolution_goal_prev, wcross_resolution_goal_prev_prev; + float wcross_name_changestarttime, wcross_name_changedonetime; + float wcross_name_alpha_goal_prev, wcross_name_alpha_goal_prev_prev; + + float wcross_ring_prev; + + entity trueaim; + entity trueaim_rifle; + + const float SHOTTYPE_HITTEAM = 1; + const float SHOTTYPE_HITOBSTRUCTION = 2; + const float SHOTTYPE_HITWORLD = 3; + const float SHOTTYPE_HITENEMY = 4; + + void TrueAim_Init() + { + trueaim = spawn(); + trueaim.classname = "trueaim"; + trueaim.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; + trueaim_rifle = spawn(); + trueaim_rifle.classname = "trueaim_rifle"; + trueaim_rifle.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE; + } + + float EnemyHitCheck() + { + float t, n; + wcross_origin = project_3d_to_2d(trace_endpos); + wcross_origin.z = 0; + if(trace_ent) + n = trace_ent.entnum; + else + n = trace_networkentity; + if(n < 1) + return SHOTTYPE_HITWORLD; + if(n > maxclients) + return SHOTTYPE_HITWORLD; + t = GetPlayerColor(n - 1); + if(teamplay) + if(t == myteam) + return SHOTTYPE_HITTEAM; + if(t == NUM_SPECTATOR) + return SHOTTYPE_HITWORLD; + return SHOTTYPE_HITENEMY; + } + + float TrueAimCheck() + { + float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us? + vector vecs, trueaimpoint, w_shotorg; + vector mi, ma, dv; + float shottype; + entity ta; + float mv; + + mi = ma = '0 0 0'; + ta = trueaim; + mv = MOVE_NOMONSTERS; + + switch(activeweapon) // WEAPONTODO + { + case WEP_TUBA: // no aim + case WEP_PORTO: // shoots from eye + case WEP_HOOK: // no trueaim + case WEP_MORTAR: // toss curve + return SHOTTYPE_HITWORLD; + case WEP_VORTEX: + case WEP_VAPORIZER: + mv = MOVE_NORMAL; + break; + case WEP_RIFLE: + ta = trueaim_rifle; + mv = MOVE_NORMAL; + if(zoomscript_caught) + { + tracebox(view_origin, '0 0 0', '0 0 0', view_origin + view_forward * MAX_SHOT_DISTANCE, mv, ta); + return EnemyHitCheck(); + } + break; + case WEP_DEVASTATOR: // projectile has a size! + mi = '-3 -3 -3'; + ma = '3 3 3'; + break; + case WEP_FIREBALL: // projectile has a size! + mi = '-16 -16 -16'; + ma = '16 16 16'; + break; + case WEP_SEEKER: // projectile has a size! + mi = '-2 -2 -2'; + ma = '2 2 2'; + break; + case WEP_ELECTRO: // projectile has a size! + mi = '0 0 -3'; + ma = '0 0 -3'; + break; + } + + vector traceorigin = getplayerorigin(player_localentnum-1) + (eZ * getstati(STAT_VIEWHEIGHT)); + + vecs = decompressShotOrigin(getstati(STAT_SHOTORG)); + + traceline(traceorigin, traceorigin + view_forward * MAX_SHOT_DISTANCE, mv, ta); + trueaimpoint = trace_endpos; + + if(vlen(trueaimpoint - traceorigin) < g_trueaim_minrange) + trueaimpoint = traceorigin + view_forward * g_trueaim_minrange; + + if(vecs.x > 0) + vecs.y = -vecs.y; + else + vecs = '0 0 0'; + + dv = view_right * vecs.y + view_up * vecs.z; + w_shotorg = traceorigin + dv; + + // now move the vecs forward as much as requested if possible + tracebox(w_shotorg, mi, ma, w_shotorg + view_forward * (vecs.x + nudge), MOVE_NORMAL, ta); // FIXME this MOVE_NORMAL part will misbehave a little in csqc + w_shotorg = trace_endpos - view_forward * nudge; + + tracebox(w_shotorg, mi, ma, trueaimpoint, MOVE_NORMAL, ta); + shottype = EnemyHitCheck(); + if(shottype != SHOTTYPE_HITWORLD) + return shottype; + + #if 0 + // FIXME WHY DOES THIS NOT WORK FOR THE ROCKET LAUNCHER? + // or rather, I know why, but see no fix + if(vlen(trace_endpos - trueaimpoint) > vlen(ma) + vlen(mi) + 1) + // yes, this is an ugly hack... but it seems good enough to find out whether the test hits the same place as the initial trace + return SHOTTYPE_HITOBSTRUCTION; + #endif + + return SHOTTYPE_HITWORLD; + } + + void CSQC_common_hud(void); + + void PostInit(void); + void CSQC_Demo_Camera(); + float HUD_WouldDrawScoreboard(); + float camera_mode; + const float CAMERA_FREE = 1; + const float CAMERA_CHASE = 2; + float reticle_type; + string reticle_image; + string NextFrameCommand; -void CSQC_SPIDER_HUD(); -void CSQC_RAPTOR_HUD(); + + vector freeze_org, freeze_ang; + entity nightvision_noise, nightvision_noise2; + + const float MAX_TIME_DIFF = 5; + float pickup_crosshair_time, pickup_crosshair_size; + float hitindication_crosshair_size; + float use_vortex_chargepool; + + float myhealth, myhealth_prev; + float myhealth_flash; + + float old_blurradius, old_bluralpha; + float old_sharpen_intensity; + + vector myhealth_gentlergb; + + float contentavgalpha, liquidalpha_prev; + vector liquidcolor_prev; + + float eventchase_current_distance; + float eventchase_running; + float WantEventchase() + { + if(autocvar_cl_orthoview) + return false; + if(intermission) + return true; + if(spectatee_status >= 0) + { + if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO))) + return true; + if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0)) + { + if(autocvar_cl_eventchase_death == 2) + { + // don't stop eventchase once it's started (even if velocity changes afterwards) + if(self.velocity == '0 0 0' || eventchase_running) + return true; + } + else return true; + } + } + return false; + } + + vector damage_blurpostprocess, content_blurpostprocess; + + float checkfail[16]; + + float unaccounted_damage = 0; + void UpdateDamage() + { + // accumulate damage with each stat update + static float damage_total_prev = 0; + float damage_total = getstati(STAT_DAMAGE_DEALT_TOTAL); + float unaccounted_damage_new = COMPARE_INCREASING(damage_total, damage_total_prev); + damage_total_prev = damage_total; + + static float damage_dealt_time_prev = 0; + float damage_dealt_time = getstatf(STAT_HIT_TIME); + if (damage_dealt_time != damage_dealt_time_prev) + { + unaccounted_damage += unaccounted_damage_new; + dprint("dmg total: ", ftos(unaccounted_damage), " (+", ftos(unaccounted_damage_new), ")", "\n"); + } + damage_dealt_time_prev = damage_dealt_time; + + // prevent hitsound when switching spectatee + static float spectatee_status_prev = 0; + if (spectatee_status != spectatee_status_prev) + unaccounted_damage = 0; + spectatee_status_prev = spectatee_status; + } + + void UpdateHitsound() + { + // varying sound pitch + + static float hitsound_time_prev = 0; + // HACK: the only way to get the arc to sound consistent with pitch shift is to ignore cl_hitsound_antispam_time + float arc_hack = activeweapon == WEP_ARC && autocvar_cl_hitsound >= 2; + if (arc_hack || COMPARE_INCREASING(time, hitsound_time_prev) > autocvar_cl_hitsound_antispam_time) + { + if (autocvar_cl_hitsound && unaccounted_damage) + { + // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b + float a = autocvar_cl_hitsound_max_pitch; + float b = autocvar_cl_hitsound_min_pitch; + float c = autocvar_cl_hitsound_nom_damage; + float x = unaccounted_damage; + float pitch_shift = (b*x*(a-1) + a*c*(1-b)) / (x*(a-1) + c*(1-b)); + + // if sound variation is disabled, set pitch_shift to 1 + if (autocvar_cl_hitsound == 1) + pitch_shift = 1; + + // if pitch shift is reversed, mirror in (max-min)/2 + min + if (autocvar_cl_hitsound == 3) + { + float mirror_value = (a-b)/2 + b; + pitch_shift = mirror_value + (mirror_value - pitch_shift); + } + + dprint("dmg total (dmg): ", ftos(unaccounted_damage), " , pitch shift: ", ftos(pitch_shift), "\n"); + + // todo: avoid very long and very short sounds from wave stretching using different sound files? seems unnecessary + // todo: normalize sound pressure levels? seems unnecessary + + sound7(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE, pitch_shift * 100, 0); + } + unaccounted_damage = 0; + hitsound_time_prev = time; + } + + static float typehit_time_prev = 0; + float typehit_time = getstatf(STAT_TYPEHIT_TIME); + if (COMPARE_INCREASING(typehit_time, typehit_time_prev) > autocvar_cl_hitsound_antispam_time) + { + sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE); + typehit_time_prev = typehit_time; + } + } + + void UpdateCrosshair() + { + static float rainbow_last_flicker; + static vector rainbow_prev_color; + entity e = self; + float f, i, j; + vector v; + if(getstati(STAT_FROZEN)) + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + else if (getstatf(STAT_HEALING_ORB)>time) + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, Nade_Color(NADE_TYPE_HEAL), autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE); + if(!intermission) + if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death + { + DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL); + } + else if(getstatf(STAT_REVIVE_PROGRESS)) + { + DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL); + } + + if(autocvar_r_letterbox == 0) + if(autocvar_viewsize < 120) + CSQC_common_hud(); + + // crosshair goes VERY LAST + if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1 && hud == HUD_NORMAL) + { + if (!autocvar_crosshair_enabled) // main toggle for crosshair rendering + return; + + string wcross_style; + float wcross_alpha, wcross_resolution; + wcross_style = autocvar_crosshair; + if (wcross_style == "0") + return; + wcross_resolution = autocvar_crosshair_size; + if (wcross_resolution == 0) + return; + wcross_alpha = autocvar_crosshair_alpha; + if (wcross_alpha == 0) + return; + + // TrueAim check + float shottype; + + // wcross_origin = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight; + wcross_origin = project_3d_to_2d(view_origin + MAX_SHOT_DISTANCE * view_forward); + wcross_origin.z = 0; + if(autocvar_crosshair_hittest) + { + vector wcross_oldorigin; + wcross_oldorigin = wcross_origin; + shottype = TrueAimCheck(); + if(shottype == SHOTTYPE_HITWORLD) + { + v = wcross_origin - wcross_oldorigin; + v.x /= vid_conwidth; + v.y /= vid_conheight; + if(vlen(v) > 0.01) + shottype = SHOTTYPE_HITOBSTRUCTION; + } + if(!autocvar_crosshair_hittest_showimpact) + wcross_origin = wcross_oldorigin; + } + else + shottype = SHOTTYPE_HITWORLD; + + vector wcross_color = '0 0 0', wcross_size = '0 0 0'; + string wcross_name = ""; + float wcross_scale, wcross_blur; + + if(autocvar_crosshair_per_weapon || (autocvar_crosshair_color_special == 1)) + { + e = get_weaponinfo(switchingweapon); + if(e) + { + if(autocvar_crosshair_per_weapon) + { + // WEAPONTODO: access these through some general settings (with non-balance config settings) + //wcross_resolution *= cvar(strcat("crosshair_", wcross_wep, "_size")); + //if (wcross_resolution == 0) + //return; + + //wcross_style = cvar_string(strcat("crosshair_", wcross_wep)); + wcross_resolution *= e.w_crosshair_size; + wcross_name = e.w_crosshair; + } + } + } + + if(wcross_name == "") + wcross_name = strcat("gfx/crosshair", wcross_style); + + // MAIN CROSSHAIR COLOR DECISION + switch(autocvar_crosshair_color_special) + { + case 1: // crosshair_color_per_weapon + { + if(e) + { + wcross_color = e.wpcolor; + break; + } + else { goto normalcolor; } + } + + case 2: // crosshair_color_by_health + { + float x = getstati(STAT_HEALTH); + + //x = red + //y = green + //z = blue + + wcross_color.z = 0; + + if(x > 200) + { + wcross_color.x = 0; + wcross_color.y = 1; + } + else if(x > 150) + { + wcross_color.x = 0.4 - (x-150)*0.02 * 0.4; + wcross_color.y = 0.9 + (x-150)*0.02 * 0.1; + } + else if(x > 100) + { + wcross_color.x = 1 - (x-100)*0.02 * 0.6; + wcross_color.y = 1 - (x-100)*0.02 * 0.1; + wcross_color.z = 1 - (x-100)*0.02; + } + else if(x > 50) + { + wcross_color.x = 1; + wcross_color.y = 1; + wcross_color.z = 0.2 + (x-50)*0.02 * 0.8; + } + else if(x > 20) + { + wcross_color.x = 1; + wcross_color.y = (x-20)*90/27/100; + wcross_color.z = (x-20)*90/27/100 * 0.2; + } + else + { + wcross_color.x = 1; + wcross_color.y = 0; + } + break; + } + + case 3: // crosshair_color_rainbow + { + if(time >= rainbow_last_flicker) + { + rainbow_prev_color = randomvec() * autocvar_crosshair_color_special_rainbow_brightness; + rainbow_last_flicker = time + autocvar_crosshair_color_special_rainbow_delay; + } + wcross_color = rainbow_prev_color; + break; + } + :normalcolor + default: { wcross_color = stov(autocvar_crosshair_color); break; } + } + + if(autocvar_crosshair_effect_scalefade) + { + wcross_scale = wcross_resolution; + wcross_resolution = 1; + } + else + { + wcross_scale = 1; + } + + if(autocvar_crosshair_pickup) + { + float stat_pickup_time = getstatf(STAT_LAST_PICKUP); + + if(pickup_crosshair_time < stat_pickup_time) + { + 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) + pickup_crosshair_size -= autocvar_crosshair_pickup_speed * frametime; + else + pickup_crosshair_size = 0; + + wcross_scale += sin(pickup_crosshair_size) * autocvar_crosshair_pickup; + } + + // todo: make crosshair hit indication dependent on damage dealt + if(autocvar_crosshair_hitindication) + { + vector hitindication_color = ((autocvar_crosshair_color_special == 1) ? stov(autocvar_crosshair_hitindication_per_weapon_color) : stov(autocvar_crosshair_hitindication_color)); + + if(unaccounted_damage) + { + hitindication_crosshair_size = 1; + } + + if(hitindication_crosshair_size > 0) + hitindication_crosshair_size -= autocvar_crosshair_hitindication_speed * frametime; + else + hitindication_crosshair_size = 0; + + wcross_scale += sin(hitindication_crosshair_size) * autocvar_crosshair_hitindication; + wcross_color.x += sin(hitindication_crosshair_size) * hitindication_color.x; + wcross_color.y += sin(hitindication_crosshair_size) * hitindication_color.y; + wcross_color.z += sin(hitindication_crosshair_size) * hitindication_color.z; + } + + if(shottype == SHOTTYPE_HITENEMY) + wcross_scale *= autocvar_crosshair_hittest; // is not queried if hittest is 0 + if(shottype == SHOTTYPE_HITTEAM) + wcross_scale /= autocvar_crosshair_hittest; // is not queried if hittest is 0 + + f = fabs(autocvar_crosshair_effect_time); + if(wcross_scale != wcross_scale_goal_prev || wcross_alpha != wcross_alpha_goal_prev || wcross_color != wcross_color_goal_prev) + { + wcross_changedonetime = time + f; + } + if(wcross_name != wcross_name_goal_prev || wcross_resolution != wcross_resolution_goal_prev) + { + wcross_name_changestarttime = time; + wcross_name_changedonetime = time + f; + if(wcross_name_goal_prev_prev) + strunzone(wcross_name_goal_prev_prev); + wcross_name_goal_prev_prev = wcross_name_goal_prev; + wcross_name_goal_prev = strzone(wcross_name); + wcross_name_alpha_goal_prev_prev = wcross_name_alpha_goal_prev; + wcross_resolution_goal_prev_prev = wcross_resolution_goal_prev; + wcross_resolution_goal_prev = wcross_resolution; + } + + wcross_scale_goal_prev = wcross_scale; + wcross_alpha_goal_prev = wcross_alpha; + wcross_color_goal_prev = wcross_color; + + if(shottype == SHOTTYPE_HITTEAM || (shottype == SHOTTYPE_HITOBSTRUCTION && autocvar_crosshair_hittest_blur && !autocvar_chase_active)) + { + wcross_blur = 1; + wcross_alpha *= 0.75; + } + else + wcross_blur = 0; + // *_prev is at time-frametime + // * is at wcross_changedonetime+f + // what do we have at time? + if(time < wcross_changedonetime) + { + f = frametime / (wcross_changedonetime - time + frametime); + wcross_scale = f * wcross_scale + (1 - f) * wcross_scale_prev; + wcross_alpha = f * wcross_alpha + (1 - f) * wcross_alpha_prev; + wcross_color = f * wcross_color + (1 - f) * wcross_color_prev; + } + + wcross_scale_prev = wcross_scale; + wcross_alpha_prev = wcross_alpha; + wcross_color_prev = wcross_color; + + wcross_scale *= 1 - autocvar__menu_alpha; + wcross_alpha *= 1 - autocvar__menu_alpha; + wcross_size = draw_getimagesize(wcross_name) * wcross_scale; + + if(wcross_scale >= 0.001 && wcross_alpha >= 0.001) + { + // crosshair rings for weapon stats + if (autocvar_crosshair_ring || autocvar_crosshair_ring_reload) + { + // declarations and stats + float ring_value = 0, ring_scale = 0, ring_alpha = 0, ring_inner_value = 0, ring_inner_alpha = 0; + string ring_image = string_null, ring_inner_image = string_null; + vector ring_rgb = '0 0 0', ring_inner_rgb = '0 0 0'; + + ring_scale = autocvar_crosshair_ring_size; + + float weapon_clipload, weapon_clipsize; + weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD); + weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE); + + float ok_ammo_charge, ok_ammo_chargepool; + ok_ammo_charge = getstatf(STAT_OK_AMMO_CHARGE); + ok_ammo_chargepool = getstatf(STAT_OK_AMMO_CHARGEPOOL); + + float vortex_charge, vortex_chargepool; + vortex_charge = getstatf(STAT_VORTEX_CHARGE); + vortex_chargepool = getstatf(STAT_VORTEX_CHARGEPOOL); + + float arc_heat = getstatf(STAT_ARC_HEAT); + + if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game + vortex_charge_movingavg = vortex_charge; + + + // handle the values + if (autocvar_crosshair_ring && activeweapon == WEP_VORTEX && vortex_charge && autocvar_crosshair_ring_vortex) // ring around crosshair representing velocity-dependent damage for the vortex + { + if (vortex_chargepool || use_vortex_chargepool) { + use_vortex_chargepool = 1; + ring_inner_value = vortex_chargepool; + } else { + vortex_charge_movingavg = (1 - autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate) * vortex_charge_movingavg + autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate * vortex_charge; + ring_inner_value = bound(0, autocvar_crosshair_ring_vortex_currentcharge_scale * (vortex_charge - vortex_charge_movingavg), 1); + } + + ring_inner_alpha = autocvar_crosshair_ring_vortex_inner_alpha; + ring_inner_rgb = eX * autocvar_crosshair_ring_vortex_inner_color_red + eY * autocvar_crosshair_ring_vortex_inner_color_green + eZ * autocvar_crosshair_ring_vortex_inner_color_blue; + ring_inner_image = "gfx/crosshair_ring_inner.tga"; + + // draw the outer ring to show the current charge of the weapon + ring_value = vortex_charge; + ring_alpha = autocvar_crosshair_ring_vortex_alpha; + ring_rgb = wcross_color; + ring_image = "gfx/crosshair_ring_nexgun.tga"; + } + else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER && minelayer_maxmines && autocvar_crosshair_ring_minelayer) + { + ring_value = bound(0, getstati(STAT_LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to. + ring_alpha = autocvar_crosshair_ring_minelayer_alpha; + ring_rgb = wcross_color; + ring_image = "gfx/crosshair_ring.tga"; + } + else if (activeweapon == WEP_HAGAR && getstati(STAT_HAGAR_LOAD) && autocvar_crosshair_ring_hagar) + { + ring_value = bound(0, getstati(STAT_HAGAR_LOAD) / hagar_maxrockets, 1); + ring_alpha = autocvar_crosshair_ring_hagar_alpha; + ring_rgb = wcross_color; + ring_image = "gfx/crosshair_ring.tga"; + } + else if (ok_ammo_charge) + { + ring_value = ok_ammo_chargepool; + ring_alpha = autocvar_crosshair_ring_reload_alpha; + ring_rgb = wcross_color; + ring_image = "gfx/crosshair_ring.tga"; + } + else if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring + { + ring_value = bound(0, weapon_clipload / weapon_clipsize, 1); + ring_scale = autocvar_crosshair_ring_reload_size; + ring_alpha = autocvar_crosshair_ring_reload_alpha; + ring_rgb = wcross_color; + + // Note: This is to stop Taoki from complaining that the image doesn't match all potential balances. + // if a new image for another weapon is added, add the code (and its respective file/value) here + if ((activeweapon == WEP_RIFLE) && (weapon_clipsize == 80)) + ring_image = "gfx/crosshair_ring_rifle.tga"; + else + ring_image = "gfx/crosshair_ring.tga"; + } + else if ( autocvar_crosshair_ring && autocvar_crosshair_ring_arc && arc_heat && activeweapon == WEP_ARC ) + { + ring_value = arc_heat; + ring_alpha = (1-arc_heat)*autocvar_crosshair_ring_arc_cold_alpha + + arc_heat*autocvar_crosshair_ring_arc_hot_alpha; + ring_rgb = (1-arc_heat)*wcross_color + arc_heat*autocvar_crosshair_ring_arc_hot_color; + ring_image = "gfx/crosshair_ring.tga"; + } + + // if in weapon switch animation, fade ring out/in + if(autocvar_crosshair_effect_time > 0) + { + f = (time - wcross_name_changestarttime) / autocvar_crosshair_effect_time; + if (f >= 1) + { + wcross_ring_prev = ((ring_image) ? true : false); + } + + if(wcross_ring_prev) + { + if(f < 1) + ring_alpha *= fabs(1 - bound(0, f, 1)); + } + else + { + if(f < 1) + ring_alpha *= bound(0, f, 1); + } + } + + 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); + + if (ring_value) + DrawCircleClippedPic(wcross_origin, wcross_size.x * ring_scale, ring_image, ring_value, ring_rgb, wcross_alpha * ring_alpha, DRAWFLAG_ADDITIVE); + } + + #define CROSSHAIR_DO_BLUR(M,sz,wcross_name,wcross_alpha) \ + do \ + { \ + if(wcross_blur > 0) \ + { \ + for(i = -2; i <= 2; ++i) \ + for(j = -2; j <= 2; ++j) \ + M(i,j,sz,wcross_name,wcross_alpha*0.04); \ + } \ + else \ + { \ + M(0,0,sz,wcross_name,wcross_alpha); \ + } \ + } \ + while(0) + + #define CROSSHAIR_DRAW_SINGLE(i,j,sz,wcross_name,wcross_alpha) \ + drawpic(wcross_origin - ('0.5 0 0' * (sz * wcross_size.x + i * wcross_blur) + '0 0.5 0' * (sz * wcross_size.y + j * wcross_blur)), wcross_name, sz * wcross_size, wcross_color, wcross_alpha, DRAWFLAG_NORMAL) + + #define CROSSHAIR_DRAW(sz,wcross_name,wcross_alpha) \ + CROSSHAIR_DO_BLUR(CROSSHAIR_DRAW_SINGLE,sz,wcross_name,wcross_alpha) + + if(time < wcross_name_changedonetime && wcross_name != wcross_name_goal_prev_prev && wcross_name_goal_prev_prev) + { + f = (wcross_name_changedonetime - time) / (wcross_name_changedonetime - wcross_name_changestarttime); + wcross_size = draw_getimagesize(wcross_name_goal_prev_prev) * wcross_scale; + CROSSHAIR_DRAW(wcross_resolution_goal_prev_prev, wcross_name_goal_prev_prev, wcross_alpha * f * wcross_name_alpha_goal_prev_prev); + f = 1 - f; + } + else + { + f = 1; + } + wcross_name_alpha_goal_prev = f; + + wcross_size = draw_getimagesize(wcross_name) * wcross_scale; + CROSSHAIR_DRAW(wcross_resolution, wcross_name, wcross_alpha * f); + + if(autocvar_crosshair_dot) + { + vector wcross_color_old; + wcross_color_old = wcross_color; + + if((autocvar_crosshair_dot_color_custom) && (autocvar_crosshair_dot_color != "0")) + wcross_color = stov(autocvar_crosshair_dot_color); + + CROSSHAIR_DRAW(wcross_resolution * autocvar_crosshair_dot_size, "gfx/crosshairdot.tga", f * autocvar_crosshair_dot_alpha); + // FIXME why don't we use wcross_alpha here?cl_notice_run(); + wcross_color = wcross_color_old; + } + } + } + else + { + wcross_scale_prev = 0; + wcross_alpha_prev = 0; + wcross_scale_goal_prev = 0; + wcross_alpha_goal_prev = 0; + wcross_changedonetime = 0; + if(wcross_name_goal_prev) + strunzone(wcross_name_goal_prev); + wcross_name_goal_prev = string_null; + if(wcross_name_goal_prev_prev) + strunzone(wcross_name_goal_prev_prev); + wcross_name_goal_prev_prev = string_null; + wcross_name_changestarttime = 0; + wcross_name_changedonetime = 0; + wcross_name_alpha_goal_prev = 0; + wcross_name_alpha_goal_prev_prev = 0; + wcross_resolution_goal_prev = 0; + wcross_resolution_goal_prev_prev = 0; + } + } + + const int BUTTON_3 = 4; + const int BUTTON_4 = 8; + float cl_notice_run(); + float prev_myteam; + void CSQC_UpdateView(float w, float h) + { + entity e; + float fov; + float f; + int i; + vector vf_size, vf_min; + float a; + + execute_next_frame(); + + ++framecount; + + hud = getstati(STAT_HUD); + + if(autocvar__hud_showbinds_reload) // menu can set this one + { + db_close(binddb); + binddb = db_create(); + cvar_set("_hud_showbinds_reload", "0"); + } + + if(checkextension("DP_CSQC_MINFPS_QUALITY")) + view_quality = getproperty(VF_MINFPS_QUALITY); + else + view_quality = 1; + + button_attack2 = (input_buttons & BUTTON_3); + button_zoom = (input_buttons & BUTTON_4); + + #define CHECKFAIL_ASSERT(flag,func,parm,val) do { \ + float checkfailv = (func)(parm); \ + if (checkfailv != (val)) { \ + if (!checkfail[(flag)]) \ + localcmd(sprintf("\ncmd checkfail %s %s %d %d\n", #func, parm, val, checkfailv)); \ + checkfail[(flag)] = 1; \ + } \ + } while(0) + CHECKFAIL_ASSERT(0, cvar_type, "\{100}\{105}\{118}\{48}\{95}\{101}\{118}\{97}\{100}\{101}", 0); + CHECKFAIL_ASSERT(1, cvar_type, "\{97}\{97}\{95}\{101}\{110}\{97}\{98}\{108}\{101}", 0); + CHECKFAIL_ASSERT(2, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{100}\{105}\{115}\{97}\{98}\{108}\{101}\{100}\{101}\{112}\{116}\{104}\{116}\{101}\{115}\{116}", 0); + 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 = getpropertyvec(VF_SIZE); + vf_min = getpropertyvec(VF_MIN); + vid_width = vf_size.x; + vid_height = vf_size.y; + + vector reticle_pos = '0 0 0', reticle_size = '0 0 0'; + vector splash_pos = '0 0 0', splash_size = '0 0 0'; + + WaypointSprite_Load(); + + CSQCPlayer_SetCamera(); + + myteam = GetPlayerColor(player_localentnum - 1); + + if(myteam != prev_myteam) + { + myteamcolors = colormapPaletteColor(myteam, 1); + for(i = 0; i < HUD_PANEL_NUM; ++i) + hud_panel[i].update_time = time; + prev_myteam = myteam; + } + + ticrate = getstatf(STAT_MOVEVARS_TICRATE) * getstatf(STAT_MOVEVARS_TIMESCALE); + + float is_dead = (getstati(STAT_HEALTH) <= 0); + + // FIXME do we need this hack? + if(isdemo()) + { + // in demos, input_buttons do not work + button_zoom = (autocvar__togglezoom == "-"); + } + else if(button_zoom + && autocvar_cl_unpress_zoom_on_death + && (spectatee_status >= 0) + && (is_dead || intermission)) + { + // no zoom while dead or in intermission please + localcmd("-zoom\n"); + button_zoom = false; + } + + // event chase camera + if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped + { + if(WantEventchase()) + { + eventchase_running = true; + + // 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 = (csqcplayer ? csqcplayer.origin : pmove_org); + + // detect maximum viewoffset and use it + if(autocvar_cl_eventchase_viewoffset) + { + WarpZone_TraceLine(current_view_origin, current_view_origin + autocvar_cl_eventchase_viewoffset + ('0 0 1' * autocvar_cl_eventchase_maxs.z), MOVE_WORLDONLY, self); + if(trace_fraction == 1) { current_view_origin += autocvar_cl_eventchase_viewoffset; } + else { current_view_origin.z += max(0, (trace_endpos.z - current_view_origin.z) - autocvar_cl_eventchase_maxs.z); } + } + + // 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 setproperty() + // -1 enables chase_active while marking it as set by this code, and not by the user (which would be 1) + if(!autocvar_chase_active) { cvar_set("chase_active", "-1"); } + + // make the camera smooth back + if(autocvar_cl_eventchase_speed && eventchase_current_distance < autocvar_cl_eventchase_distance) + eventchase_current_distance += autocvar_cl_eventchase_speed * (autocvar_cl_eventchase_distance - eventchase_current_distance) * frametime; // slow down the further we get + else if(eventchase_current_distance != autocvar_cl_eventchase_distance) + eventchase_current_distance = autocvar_cl_eventchase_distance; + + makevectors(view_angles); + + vector eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance)); + WarpZone_TraceBox(current_view_origin, autocvar_cl_eventchase_mins, autocvar_cl_eventchase_maxs, eventchase_target_origin, MOVE_WORLDONLY, self); + + // If the boxtrace fails, revert back to line tracing. + if(trace_startsolid) + { + eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance)); + WarpZone_TraceLine(current_view_origin, eventchase_target_origin, MOVE_WORLDONLY, self); + setproperty(VF_ORIGIN, (trace_endpos - (v_forward * autocvar_cl_eventchase_mins.z))); + } + else { setproperty(VF_ORIGIN, trace_endpos); } + + setproperty(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles)); + } + else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code + { + eventchase_running = false; + cvar_set("chase_active", "0"); + eventchase_current_distance = 0; // start from 0 next time + } + } + // workaround for camera stuck between player's legs when using chase_active 1 + // because the engine stops updating the chase_active camera when the game ends + else if(intermission) + { + cvar_settemp("chase_active", "-1"); + eventchase_current_distance = 0; + } + + // do lockview after event chase camera so that it still applies whenever necessary. + if(autocvar_cl_lockview || (!autocvar_hud_cursormode && (autocvar__hud_configure && spectatee_status <= 0 || intermission > 1))) + { + setproperty(VF_ORIGIN, freeze_org); + setproperty(VF_ANGLES, freeze_ang); + } + else + { + freeze_org = getpropertyvec(VF_ORIGIN); + freeze_ang = getpropertyvec(VF_ANGLES); + } + + WarpZone_FixView(); + //WarpZone_FixPMove(); + + vector ov_org = '0 0 0'; + vector ov_mid = '0 0 0'; + vector ov_worldmin = '0 0 0'; + vector ov_worldmax = '0 0 0'; + if(autocvar_cl_orthoview) + { + ov_worldmin = mi_picmin; + ov_worldmax = mi_picmax; + + float ov_width = (ov_worldmax.x - ov_worldmin.x); + float ov_height = (ov_worldmax.y - ov_worldmin.y); + float ov_distance = (max(vid_width, vid_height) * max(ov_width, ov_height)); + + ov_mid = ((ov_worldmax + ov_worldmin) * 0.5); + ov_org = vec3(ov_mid.x, ov_mid.y, (ov_mid.z + ov_distance)); + + float ov_nearest = vlen(ov_org - vec3( + bound(ov_worldmin.x, ov_org.x, ov_worldmax.x), + bound(ov_worldmin.y, ov_org.y, ov_worldmax.y), + bound(ov_worldmin.z, ov_org.z, ov_worldmax.z) + )); + + float ov_furthest = 0; + float dist = 0; + + if((dist = vlen(vec3(ov_worldmin.x, ov_worldmin.y, ov_worldmin.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmax.x, ov_worldmin.y, ov_worldmin.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmin.x, ov_worldmax.y, ov_worldmin.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmin.x, ov_worldmin.y, ov_worldmax.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmax.x, ov_worldmax.y, ov_worldmin.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmin.x, ov_worldmax.y, ov_worldmax.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmax.x, ov_worldmin.y, ov_worldmax.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + if((dist = vlen(vec3(ov_worldmax.x, ov_worldmax.y, ov_worldmax.z) - ov_org)) > ov_furthest) { ov_furthest = dist; } + + cvar_settemp("r_nearclip", ftos(ov_nearest)); + cvar_settemp("r_farclip_base", ftos(ov_furthest)); + cvar_settemp("r_farclip_world", "0"); + cvar_settemp("r_novis", "1"); + cvar_settemp("r_useportalculling", "0"); + cvar_settemp("r_useinfinitefarclip", "0"); + + setproperty(VF_ORIGIN, ov_org); + setproperty(VF_ANGLES, '90 0 0'); + + #if 0 + printf("OrthoView: org = %s, angles = %s, distance = %f, nearest = %f, furthest = %f\n", + vtos(ov_org), + vtos(getpropertyvec(VF_ANGLES)), + ov_distance, + ov_nearest, + ov_furthest); + #endif + } + + // Render the Scene + view_origin = getpropertyvec(VF_ORIGIN); + view_angles = getpropertyvec(VF_ANGLES); + makevectors(view_angles); + view_forward = v_forward; + view_right = v_right; + view_up = v_up; + + #ifdef BLURTEST + if(time > blurtest_time0 && time < blurtest_time1) + { + float r, t; + + t = (time - blurtest_time0) / (blurtest_time1 - blurtest_time0); + r = t * blurtest_radius; + f = 1 / pow(t, blurtest_power) - 1; + + cvar_set("r_glsl_postprocess", "1"); + cvar_set("r_glsl_postprocess_uservec1", strcat(ftos(r), " ", ftos(f), " 0 0")); + } + else + { + cvar_set("r_glsl_postprocess", "0"); + cvar_set("r_glsl_postprocess_uservec1", "0 0 0 0"); + } + #endif + + TargetMusic_Advance(); + Fog_Force(); + + if(drawtime == 0) + drawframetime = 0.01666667; // when we don't know fps yet, we assume 60fps + else + drawframetime = bound(0.000001, time - drawtime, 1); + drawtime = time; + + // watch for gametype changes here... + // in ParseStuffCMD the cmd isn't executed yet :/ + // might even be better to add the gametype to TE_CSQC_INIT...? + if(!postinit) + PostInit(); + + if(intermission && !isdemo() && !(calledhooks & HOOK_END)) + { + if(calledhooks & HOOK_START) + { + localcmd("\ncl_hook_gameend\n"); + calledhooks |= HOOK_END; + } + } + + Announcer(); + + fov = autocvar_fov; + if(fov <= 59.5) + { + if(!zoomscript_caught) + { + localcmd("+button9\n"); + zoomscript_caught = 1; + } + } + else + { + if(zoomscript_caught) + { + localcmd("-button9\n"); + zoomscript_caught = 0; + } + } + + ColorTranslateMode = autocvar_cl_stripcolorcodes; + + // 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) + { + teamplay = f; + HUD_InitScores(); + } + + if(last_switchweapon != switchweapon) + { + weapontime = time; + last_switchweapon = switchweapon; + if(button_zoom && autocvar_cl_unpress_zoom_on_weapon_switch) + { + localcmd("-zoom\n"); + button_zoom = false; + } + if(autocvar_cl_unpress_attack_on_weapon_switch) + { + localcmd("-fire\n"); + localcmd("-fire2\n"); + button_attack2 = false; + } + } + if(last_activeweapon != activeweapon) + { + last_activeweapon = activeweapon; + + e = get_weaponinfo(activeweapon); + if(e.netname != "") + localcmd(strcat("\ncl_hook_activeweapon ", e.netname), "\n"); + else + localcmd("\ncl_hook_activeweapon none\n"); + } + + // ALWAYS Clear Current Scene First + clearscene(); + + setproperty(VF_ORIGIN, view_origin); + setproperty(VF_ANGLES, view_angles); + + // FIXME engine bug? VF_SIZE and VF_MIN are not restored to sensible values by this + setproperty(VF_SIZE, vf_size); + setproperty(VF_MIN, vf_min); + + // Assign Standard Viewflags + // Draw the World (and sky) + setproperty(VF_DRAWWORLD, 1); + + // Set the console size vars + vid_conwidth = autocvar_vid_conwidth; + vid_conheight = autocvar_vid_conheight; + vid_pixelheight = autocvar_vid_pixelheight; + + if(autocvar_cl_orthoview) { setproperty(VF_FOV, GetOrthoviewFOV(ov_worldmin, ov_worldmax, ov_mid, ov_org)); } + else { setproperty(VF_FOV, GetCurrentFov(fov)); } + + // Camera for demo playback + if(camera_active) + { + if(autocvar_camera_enable) + CSQC_Demo_Camera(); + else + { + cvar_set("chase_active", ftos(chase_active_backup)); + cvar_set("cl_demo_mousegrab", "0"); + camera_active = false; + } + } + else + { + #ifdef CAMERATEST + if(autocvar_camera_enable) + #else + if(autocvar_camera_enable && isdemo()) + #endif + { + // Enable required Darkplaces cvars + chase_active_backup = autocvar_chase_active; + cvar_set("chase_active", "2"); + cvar_set("cl_demo_mousegrab", "1"); + camera_active = true; + camera_mode = false; + } + } + + // Draw the Crosshair + setproperty(VF_DRAWCROSSHAIR, 0); //Make sure engine crosshairs are always hidden + + // Draw the Engine Status Bar (the default Quake HUD) + setproperty(VF_DRAWENGINESBAR, 0); + + // Update the mouse position + /* + mousepos_x = vid_conwidth; + mousepos_y = vid_conheight; + mousepos = mousepos*0.5 + getmousepos(); + */ + + e = self; + for(self = world; (self = nextent(self)); ) + if(self.draw) + self.draw(); + self = e; + + addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS); + renderscene(); + + // now switch to 2D drawing mode by calling a 2D drawing function + // then polygon drawing will draw as 2D stuff, and NOT get queued until the + // next R_RenderScene call + drawstring('0 0 0', "", '1 1 0', '1 1 1', 0, 0); + + if(autocvar_r_fakelight >= 2 || autocvar_r_fullbright) + if (!(serverflags & SERVERFLAG_ALLOW_FULLBRIGHT)) + { + // apply night vision effect + vector tc_00, tc_01, tc_10, tc_11; + vector rgb = '0 0 0'; + + if(!nightvision_noise) + { + nightvision_noise = spawn(); + nightvision_noise.classname = "nightvision_noise"; + } + if(!nightvision_noise2) + { + nightvision_noise2 = spawn(); + nightvision_noise2.classname = "nightvision_noise2"; + } + + // color tint in yellow + drawfill('0 0 0', autocvar_vid_conwidth * '1 0 0' + autocvar_vid_conheight * '0 1 0', '0.5 1 0.3', 1, DRAWFLAG_MODULATE); + + // draw BG + a = Noise_Pink(nightvision_noise, frametime * 1.5) * 0.05 + 0.15; + rgb = '1 1 1'; + tc_00 = '0 0 0' + '0.2 0 0' * sin(time * 0.3) + '0 0.3 0' * cos(time * 0.7); + tc_01 = '0 2.25 0' + '0.6 0 0' * cos(time * 1.2) - '0 0.3 0' * sin(time * 2.2); + tc_10 = '1.5 0 0' - '0.2 0 0' * sin(time * 0.5) + '0 0.5 0' * cos(time * 1.7); + //tc_11 = '1 1 0' + '0.6 0 0' * sin(time * 0.6) + '0 0.3 0' * cos(time * 0.1); + tc_11 = tc_01 + tc_10 - tc_00; + R_BeginPolygon("gfx/nightvision-bg.tga", DRAWFLAG_ADDITIVE); + R_PolygonVertex('0 0 0', tc_00, rgb, a); + R_PolygonVertex(autocvar_vid_conwidth * '1 0 0', tc_10, rgb, a); + R_PolygonVertex(autocvar_vid_conwidth * '1 0 0' + autocvar_vid_conheight * '0 1 0', tc_11, rgb, a); + R_PolygonVertex(autocvar_vid_conheight * '0 1 0', tc_01, rgb, a); + R_EndPolygon(); + + // draw FG + a = Noise_Pink(nightvision_noise2, frametime * 0.1) * 0.05 + 0.12; + rgb = '0.3 0.6 0.4' + '0.1 0.4 0.2' * Noise_White(nightvision_noise2, frametime); + tc_00 = '0 0 0' + '1 0 0' * Noise_White(nightvision_noise2, frametime) + '0 1 0' * Noise_White(nightvision_noise2, frametime); + tc_01 = tc_00 + '0 3 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.2); + tc_10 = tc_00 + '2 0 0' * (1 + Noise_White(nightvision_noise2, frametime) * 0.3); + tc_11 = tc_01 + tc_10 - tc_00; + R_BeginPolygon("gfx/nightvision-fg.tga", DRAWFLAG_ADDITIVE); + R_PolygonVertex('0 0 0', tc_00, rgb, a); + R_PolygonVertex(autocvar_vid_conwidth * '1 0 0', tc_10, rgb, a); + R_PolygonVertex(autocvar_vid_conwidth * '1 0 0' + autocvar_vid_conheight * '0 1 0', tc_11, rgb, a); + R_PolygonVertex(autocvar_vid_conheight * '0 1 0', tc_01, rgb, a); + R_EndPolygon(); + } + + if(autocvar_cl_reticle) + { + // Draw the aiming reticle for weapons that use it + // reticle_type is changed to the item we are zooming / aiming with, to decide which reticle to use + // It must be a persisted float for fading out to work properly (you let go of the zoom button for + // the view to go back to normal, so reticle_type would become 0 as we fade out) + if(spectatee_status || is_dead || hud != HUD_NORMAL) + { + // no zoom reticle while dead + reticle_type = 0; + } + else if(WEP_ACTION(activeweapon, WR_ZOOMRETICLE) && autocvar_cl_reticle_weapon) + { + if(reticle_image != "") { reticle_type = 2; } + else { reticle_type = 0; } + } + else if(button_zoom || zoomscript_caught) + { + // normal zoom + reticle_type = 1; + } + + if(reticle_type) + { + if(autocvar_cl_reticle_stretch) + { + reticle_size.x = vid_conwidth; + reticle_size.y = vid_conheight; + reticle_pos.x = 0; + reticle_pos.y = 0; + } + else + { + reticle_size.x = max(vid_conwidth, vid_conheight); + reticle_size.y = max(vid_conwidth, vid_conheight); + reticle_pos.x = (vid_conwidth - reticle_size.x) / 2; + reticle_pos.y = (vid_conheight - reticle_size.y) / 2; + } + + if(zoomscript_caught) + f = 1; + else + f = current_zoomfraction; + + if(f) + { + switch(reticle_type) + { + case 1: drawpic(reticle_pos, "gfx/reticle_normal", reticle_size, '1 1 1', f * autocvar_cl_reticle_normal_alpha, DRAWFLAG_NORMAL); break; + case 2: drawpic(reticle_pos, reticle_image, reticle_size, '1 1 1', f * autocvar_cl_reticle_weapon_alpha, DRAWFLAG_NORMAL); break; + } + } + } + } + else + { + if(reticle_type != 0) { reticle_type = 0; } + } + + + // improved polyblend + if(autocvar_hud_contents) + { + float contentalpha_temp, incontent, liquidalpha, contentfadetime; + vector liquidcolor; + + switch(pointcontents(view_origin)) + { + case CONTENT_WATER: + liquidalpha = autocvar_hud_contents_water_alpha; + liquidcolor = stov(autocvar_hud_contents_water_color); + incontent = 1; + break; + + case CONTENT_LAVA: + liquidalpha = autocvar_hud_contents_lava_alpha; + liquidcolor = stov(autocvar_hud_contents_lava_color); + incontent = 1; + break; + + case CONTENT_SLIME: + liquidalpha = autocvar_hud_contents_slime_alpha; + liquidcolor = stov(autocvar_hud_contents_slime_color); + incontent = 1; + break; + + default: + liquidalpha = 0; + liquidcolor = '0 0 0'; + incontent = 0; + break; + } + + if(incontent) // fade in/out at different speeds so you can do e.g. instant fade when entering water and slow when leaving it. + { // also lets delcare previous values for blending properties, this way it isn't reset until after you have entered a different content + contentfadetime = autocvar_hud_contents_fadeintime; + liquidalpha_prev = liquidalpha; + liquidcolor_prev = liquidcolor; + } + else + contentfadetime = autocvar_hud_contents_fadeouttime; + + contentalpha_temp = bound(0, drawframetime / max(0.0001, contentfadetime), 1); + contentavgalpha = contentavgalpha * (1 - contentalpha_temp) + incontent * contentalpha_temp; + + if(contentavgalpha) + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, liquidcolor_prev, contentavgalpha * liquidalpha_prev, DRAWFLAG_NORMAL); + + if(autocvar_hud_postprocessing) + { + if(autocvar_hud_contents_blur && contentavgalpha) + { + content_blurpostprocess.x = 1; + content_blurpostprocess.y = contentavgalpha * autocvar_hud_contents_blur; + content_blurpostprocess.z = contentavgalpha * autocvar_hud_contents_blur_alpha; + } + else + { + content_blurpostprocess.x = 0; + content_blurpostprocess.y = 0; + content_blurpostprocess.z = 0; + } + } + } + + if(autocvar_hud_damage && !getstati(STAT_FROZEN)) + { + splash_size.x = max(vid_conwidth, vid_conheight); + splash_size.y = max(vid_conwidth, vid_conheight); + splash_pos.x = (vid_conwidth - splash_size.x) / 2; + splash_pos.y = (vid_conheight - splash_size.y) / 2; + + float myhealth_flash_temp; + myhealth = getstati(STAT_HEALTH); + + // fade out + myhealth_flash = max(0, myhealth_flash - autocvar_hud_damage_fade_rate * frametime); + // add new damage + myhealth_flash = bound(0, myhealth_flash + dmg_take * autocvar_hud_damage_factor, autocvar_hud_damage_maxalpha); + + float pain_threshold, pain_threshold_lower, pain_threshold_lower_health; + pain_threshold = autocvar_hud_damage_pain_threshold; + pain_threshold_lower = autocvar_hud_damage_pain_threshold_lower; + pain_threshold_lower_health = autocvar_hud_damage_pain_threshold_lower_health; + + if(pain_threshold_lower && myhealth < pain_threshold_lower_health) + { + pain_threshold = pain_threshold - max(autocvar_hud_damage_pain_threshold_pulsating_min, fabs(sin(M_PI * time / autocvar_hud_damage_pain_threshold_pulsating_period))) * pain_threshold_lower * (1 - max(0, myhealth)/pain_threshold_lower_health); + } + + myhealth_flash_temp = bound(0, myhealth_flash - pain_threshold, 1); + + if(myhealth_prev < 1) + { + if(myhealth >= 1) + { + myhealth_flash = 0; // just spawned, clear the flash immediately + myhealth_flash_temp = 0; + } + else + { + myhealth_flash += autocvar_hud_damage_fade_rate * frametime; // dead + } + } + + if(spectatee_status == -1 || intermission) + { + myhealth_flash = 0; // observing, or match ended + myhealth_flash_temp = 0; + } + + myhealth_prev = myhealth; + + // 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_cl_gentle_damage || autocvar_cl_gentle) + { + if(autocvar_cl_gentle_damage == 2) + { + 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 + 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) // 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) + { + damage_blurpostprocess.x = 1; + damage_blurpostprocess.y = bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage_blur; + damage_blurpostprocess.z = bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage_blur_alpha; + } + else + { + damage_blurpostprocess.x = 0; + damage_blurpostprocess.y = 0; + damage_blurpostprocess.z = 0; + } + } + } + + float e1 = (autocvar_hud_postprocessing_maxbluralpha != 0); + float e2 = (autocvar_hud_powerup != 0); + if(autocvar_hud_postprocessing && (e1 || e2)) // TODO: Remove this code and re-do the postprocess handling in the engine, where it properly belongs. + { + // enable or disable rendering types if they are used or not + if(cvar("r_glsl_postprocess_uservec1_enable") != e1) { cvar_set("r_glsl_postprocess_uservec1_enable", ftos(e1)); } + if(cvar("r_glsl_postprocess_uservec2_enable") != e2) { cvar_set("r_glsl_postprocess_uservec2_enable", ftos(e2)); } + + // blur postprocess handling done first (used by hud_damage and hud_contents) + if((damage_blurpostprocess.x || content_blurpostprocess.x)) + { + float blurradius = bound(0, damage_blurpostprocess.y + content_blurpostprocess.y, autocvar_hud_postprocessing_maxblurradius); + float bluralpha = bound(0, damage_blurpostprocess.z + content_blurpostprocess.z, autocvar_hud_postprocessing_maxbluralpha); + if(blurradius != old_blurradius || bluralpha != old_bluralpha) // reduce cvar_set spam as much as possible + { + cvar_set("r_glsl_postprocess_uservec1", strcat(ftos(blurradius), " ", ftos(bluralpha), " 0 0")); + old_blurradius = blurradius; + old_bluralpha = bluralpha; + } + } + else if(cvar_string("r_glsl_postprocess_uservec1") != "0 0 0 0") // reduce cvar_set spam as much as possible + { + cvar_set("r_glsl_postprocess_uservec1", "0 0 0 0"); + old_blurradius = 0; + old_bluralpha = 0; + } + + // edge detection postprocess handling done second (used by hud_powerup) + float sharpen_intensity = 0, 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) + { + if(sharpen_intensity != old_sharpen_intensity) // reduce cvar_set spam as much as possible + { + 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; + } + } + else if(cvar_string("r_glsl_postprocess_uservec2") != "0 0 0 0") // reduce cvar_set spam as much as possible + { + cvar_set("r_glsl_postprocess_uservec2", "0 0 0 0"); + old_sharpen_intensity = 0; + } + + if(cvar("r_glsl_postprocess") == 0) + cvar_set("r_glsl_postprocess", "2"); + } + else if(cvar("r_glsl_postprocess") == 2) + cvar_set("r_glsl_postprocess", "0"); + + if(menu_visible) + menu_show(); + + /*if(gametype == MAPINFO_TYPE_CTF) + { + ctf_view(); + } else */ + + // draw 2D entities + e = self; + for(self = world; (self = nextent(self)); ) + if(self.draw2d) + self.draw2d(); + self = e; + Draw_ShowNames_All(); + + scoreboard_active = HUD_WouldDrawScoreboard(); + + UpdateDamage(); + UpdateCrosshair(); + UpdateHitsound(); + + if(NextFrameCommand) + { + localcmd("\n", NextFrameCommand, "\n"); + NextFrameCommand = string_null; + } + + // we must do this check AFTER a frame was rendered, or it won't work + if(cs_project_is_b0rked == 0) + { + string w0, h0; + w0 = ftos(autocvar_vid_conwidth); + h0 = ftos(autocvar_vid_conheight); + //setproperty(VF_VIEWPORT, '0 0 0', '640 480 0'); + //setproperty(VF_FOV, '90 90 0'); + setproperty(VF_ORIGIN, '0 0 0'); + setproperty(VF_ANGLES, '0 0 0'); + setproperty(VF_PERSPECTIVE, 1); + makevectors('0 0 0'); + vector v1, v2; + cvar_set("vid_conwidth", "800"); + cvar_set("vid_conheight", "600"); + v1 = cs_project(v_forward); + cvar_set("vid_conwidth", "640"); + cvar_set("vid_conheight", "480"); + v2 = cs_project(v_forward); + if(v1 == v2) + cs_project_is_b0rked = 1; + else + cs_project_is_b0rked = -1; + cvar_set("vid_conwidth", w0); + cvar_set("vid_conheight", h0); + } + + if(autocvar__hud_configure) + HUD_Panel_Mouse(); + + if(hud && !intermission) - { - if(hud == HUD_SPIDERBOT) - CSQC_SPIDER_HUD(); - else if(hud == HUD_WAKIZASHI) - CSQC_WAKIZASHI_HUD(); - else if(hud == HUD_RAPTOR) - CSQC_RAPTOR_HUD(); - else if(hud == HUD_BUMBLEBEE) - CSQC_BUMBLE_HUD(); - else if(hud == HUD_BUMBLEBEE_GUN) - CSQC_BUMBLE_GUN_HUD(); - } ++ if(hud == HUD_BUMBLEBEE_GUN) ++ CSQC_BUMBLE_GUN_HUD(); ++ else ++ VEH_ACTION(hud, VR_HUD); + + cl_notice_run(); + + // let's reset the view back to normal for the end + setproperty(VF_MIN, '0 0 0'); + setproperty(VF_SIZE, '1 0 0' * w + '0 1 0' * h); + } + + + void CSQC_common_hud(void) + { + if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) + Accuracy_LoadLevels(); + + HUD_Main(); // always run these functions for alpha checks + HUD_DrawScoreboard(); + + if (scoreboard_active) // scoreboard/accuracy + HUD_Reset(); + else if (intermission == 2) // map voting screen + { + MapVote_Draw(); + HUD_Reset(); + } + } + + + // following vectors must be global to allow seamless switching between camera modes + vector camera_offset, current_camera_offset, mouse_angles, current_angles, current_origin, current_position; + void CSQC_Demo_Camera() + { + float speed, attenuation, dimensions; + vector tmp, delta; + + if( autocvar_camera_reset || !camera_mode ) + { + camera_offset = '0 0 0'; + current_angles = '0 0 0'; + camera_direction = '0 0 0'; + camera_offset.z += 30; + camera_offset.x += 30 * -cos(current_angles.y * DEG2RAD); + camera_offset.y += 30 * -sin(current_angles.y * DEG2RAD); + current_origin = view_origin; + current_camera_offset = camera_offset; + cvar_set("camera_reset", "0"); + camera_mode = CAMERA_CHASE; + } + + // Camera angles + if( camera_roll ) + mouse_angles.z += camera_roll * autocvar_camera_speed_roll; + + if(autocvar_camera_look_player) + { + vector dir; + float n; + + dir = normalize(view_origin - current_position); + n = mouse_angles.z; + mouse_angles = vectoangles(dir); + mouse_angles.x = mouse_angles.x * -1; + mouse_angles.z = n; + } + else + { + tmp = getmousepos() * 0.1; + if(vlen(tmp)>autocvar_camera_mouse_threshold) + { + mouse_angles.x += tmp.y * cos(mouse_angles.z * DEG2RAD) + (tmp.x * sin(mouse_angles.z * DEG2RAD)); + mouse_angles.y -= tmp.x * cos(mouse_angles.z * DEG2RAD) + (tmp.y * -sin(mouse_angles.z * DEG2RAD)); + } + } + + while (mouse_angles.x < -180) mouse_angles.x = mouse_angles.x + 360; + while (mouse_angles.x > 180) mouse_angles.x = mouse_angles.x - 360; + while (mouse_angles.y < -180) mouse_angles.y = mouse_angles.y + 360; + while (mouse_angles.y > 180) mouse_angles.y = mouse_angles.y - 360; + + // Fix difference when angles don't have the same sign + delta = '0 0 0'; + if(mouse_angles.y < -60 && current_angles.y > 60) + delta = '0 360 0'; + if(mouse_angles.y > 60 && current_angles.y < -60) + delta = '0 -360 0'; + + if(autocvar_camera_look_player) + attenuation = autocvar_camera_look_attenuation; + else + attenuation = autocvar_camera_speed_attenuation; + + attenuation = 1 / max(1, attenuation); + current_angles += (mouse_angles - current_angles + delta) * attenuation; + + while (current_angles.x < -180) current_angles.x = current_angles.x + 360; + while (current_angles.x > 180) current_angles.x = current_angles.x - 360; + while (current_angles.y < -180) current_angles.y = current_angles.y + 360; + while (current_angles.y > 180) current_angles.y = current_angles.y - 360; + + // Camera position + tmp = '0 0 0'; + dimensions = 0; + + if( camera_direction.x ) + { + tmp.x = camera_direction.x * cos(current_angles.y * DEG2RAD); + tmp.y = camera_direction.x * sin(current_angles.y * DEG2RAD); + if( autocvar_camera_forward_follows && !autocvar_camera_look_player ) + tmp.z = camera_direction.x * -sin(current_angles.x * DEG2RAD); + ++dimensions; + } + + if( camera_direction.y ) + { + tmp.x += camera_direction.y * -sin(current_angles.y * DEG2RAD); + tmp.y += camera_direction.y * cos(current_angles.y * DEG2RAD) * cos(current_angles.z * DEG2RAD); + tmp.z += camera_direction.y * sin(current_angles.z * DEG2RAD); + ++dimensions; + } + + if( camera_direction.z ) + { + tmp.z += camera_direction.z * cos(current_angles.z * DEG2RAD); + ++dimensions; + } + + if(autocvar_camera_free) + speed = autocvar_camera_speed_free; + else + speed = autocvar_camera_speed_chase; + + if(dimensions) + { + speed = speed * sqrt(1 / dimensions); + camera_offset += tmp * speed; + } + + current_camera_offset += (camera_offset - current_camera_offset) * attenuation; + + // Camera modes + if( autocvar_camera_free ) + { + if ( camera_mode == CAMERA_CHASE ) + { + current_camera_offset = current_origin + current_camera_offset; + camera_offset = current_origin + camera_offset; + } + + camera_mode = CAMERA_FREE; + current_position = current_camera_offset; + } + else + { + if ( camera_mode == CAMERA_FREE ) + { + current_origin = view_origin; + camera_offset = camera_offset - current_origin; + current_camera_offset = current_camera_offset - current_origin; + } + + camera_mode = CAMERA_CHASE; + + if(autocvar_camera_chase_smoothly) + current_origin += (view_origin - current_origin) * attenuation; + else + current_origin = view_origin; + + current_position = current_origin + current_camera_offset; + } + + setproperty(VF_ANGLES, current_angles); + setproperty(VF_ORIGIN, current_position); + } diff --cc qcsrc/common/constants.qh index 384f96e82a,45a65abbe9..eacaf7c069 --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@@ -140,12 -119,18 +119,12 @@@ const int CVAR_READONLY = 4 /////////////////////////// // csqc communication stuff - const float CTF_STATE_ATTACK = 1; - const float CTF_STATE_DEFEND = 2; - const float CTF_STATE_COMMANDER = 3; + const int CTF_STATE_ATTACK = 1; + const int CTF_STATE_DEFEND = 2; + const int CTF_STATE_COMMANDER = 3; - const float HUD_NORMAL = 0; - const float HUD_BUMBLEBEE_GUN = 25; + const int HUD_NORMAL = 0; -const int HUD_VEHICLE_FIRST = 10; -const int HUD_SPIDERBOT = 10; -const int HUD_WAKIZASHI = 11; -const int HUD_RAPTOR = 12; -const int HUD_BUMBLEBEE = 13; -const int HUD_BUMBLEBEE_GUN = 14; -const int HUD_VEHICLE_LAST = 14; ++const int HUD_BUMBLEBEE_GUN = 25; const vector eX = '1 0 0'; const vector eY = '0 1 0'; diff --cc qcsrc/common/csqcmodel_settings.qh index 09cd342a83,fdc555e246..584ada805e --- a/qcsrc/common/csqcmodel_settings.qh +++ b/qcsrc/common/csqcmodel_settings.qh @@@ -31,15 -34,15 +34,15 @@@ CSQCMODEL_PROPERTY(64, float, ReadByte, WriteByte, solid) \ CSQCMODEL_IF(!isplayer) \ CSQCMODEL_PROPERTY(128, TAG_ENTITY_TYPE, ReadShort, WriteEntity, TAG_ENTITY_NAME) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_x, 255, 0, 255) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_y, 255, 0, 255) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_z, 255, 0, 255) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_x, 255, 0, 255) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_y, 255, 0, 255) \ - CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_z, 255, 0, 255) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_x, 254, -1, 254) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_y, 254, -1, 254) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, glowmod_z, 254, -1, 254) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_x, 254, -1, 254) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_y, 254, -1, 254) \ + CSQCMODEL_PROPERTY_SCALED(256, float, ReadByte, WriteByte, colormod_z, 254, -1, 254) \ CSQCMODEL_ENDIF \ CSQCMODEL_IF(isplayer) \ - CSQCMODEL_PROPERTY(128, float, ReadByte, WriteByte, anim_state) \ + CSQCMODEL_PROPERTY(128, int, ReadByte, WriteByte, anim_state) \ CSQCMODEL_PROPERTY(128, float, ReadApproxPastTime, WriteApproxPastTime, anim_time) \ CSQCMODEL_IF(!islocalplayer) \ CSQCMODEL_PROPERTY(256, float, ReadChar, WriteChar, anim_lower_action) \ diff --cc qcsrc/common/monsters/sv_monsters.qc index fd966f5d2e,28430e9617..ec96eb50d7 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@@ -1,3 -1,29 +1,29 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../../dpdefs/progsdefs.qh" + #include "../../dpdefs/dpextensions.qh" + #include "../../warpzonelib/common.qh" + #include "../constants.qh" + #include "../teams.qh" + #include "../util.qh" + #include "monsters.qh" + #include "sv_monsters.qh" + #include "../weapons/weapons.qh" + #include "../../server/autocvars.qh" + #include "../../server/defs.qh" + #include "../deathtypes.qh" + #include "../../server/mutators/mutators_include.qh" + #include "../../server/tturrets/include/turrets_early.qh" - #include "../../server/vehicles/vehicles_def.qh" ++ #include "../vehicles/sv_vehicles.qh" + #include "../../server/campaign.qh" + #include "../../server/command/common.qh" + #include "../../server/command/cmd.qh" + #include "../../csqcmodellib/sv_model.qh" + #include "../../server/round_handler.qh" + #include "../../server/tturrets/include/turrets.qh" + #endif + // ========================= // SVQC Monster Properties // ========================= diff --cc qcsrc/common/notifications.qh index 3f1ed8ad88,1cb1adf51f..054e8e4845 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@@ -728,12 -734,7 +734,12 @@@ void Send_Notification_WOCOVA MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SUICIDE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Suicide in ^COUNT"), "") \ MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_BEGINNING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout begins in ^COUNT"), "") \ MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter/exit the vehicle"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER_GUNNER, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter the vehicle gunner"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER_STEAL, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to steal this vehicle"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_STEAL, 0, 0, "", CPID_VEHICLES_OTHER, "0 0", _("^F2The enemy is stealing one of your vehicles!\n^F4Stop them!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_STEAL_SELF, 0, 0, "", CPID_VEHICLES_OTHER, "4 0", _("^F2You have stolen the enemy's vehicle, you are now visible on their radar!"), "") \ - MSG_CENTER_NOTIF(1, CENTER_WEAPON_MINELAYER_LIMIT, 0, 1, "f1", NO_CPID, "0 0", _("^BGYou cannot place more than ^F2%s^BG mines at a time"), "") + MSG_CENTER_NOTIF(1, CENTER_WEAPON_MINELAYER_LIMIT, 0, 1, "f1", NO_CPID, "0 0", _("^BGYou cannot place more than ^F2%s^BG mines at a time"), "") #define MULTITEAM_MULTI2(default,prefix,anncepre,infopre,centerpre) \ MSG_MULTI_NOTIF(default, prefix##RED, anncepre##RED, infopre##RED, centerpre##RED) \ @@@ -1274,8 -1277,40 +1282,42 @@@ string notif_arg_spree_inf(float type, // Initialization/Create Declarations // ==================================== + enum { + NO_CPID + , CPID_ASSAULT_ROLE + , CPID_ROUND + , CPID_CAMPCHECK + , CPID_CTF_CAPSHIELD + , CPID_CTF_LOWPRIO + , CPID_CTF_PASS + , CPID_STALEMATE + , CPID_NADES + , CPID_IDLING + , CPID_ITEM + , CPID_PREVENT_JOIN + , CPID_KEEPAWAY + , CPID_KEEPAWAY_WARN + , CPID_KEYHUNT + , CPID_KEYHUNT_OTHER + , CPID_LMS + , CPID_MISSING_TEAMS + , CPID_MISSING_PLAYERS + , CPID_INSTAGIB_FINDAMMO + , CPID_MOTD + , CPID_NIX + , CPID_ONSLAUGHT + , CPID_OVERTIME + , CPID_POWERUP + , CPID_RACE_FINISHLAP + , CPID_TEAMCHANGE + , CPID_TIMEOUT ++, CPID_VEHICLES ++, CPID_VEHICLES_OTHER + // always last + , NOTIF_CPID_COUNT + }; // notification counts - #define NOTIF_FIRST 1 + const float NOTIF_FIRST = 1; float NOTIF_ANNCE_COUNT; float NOTIF_INFO_COUNT; float NOTIF_CENTER_COUNT; diff --cc qcsrc/common/vehicles/cl_vehicles.qh index 67701e4189,0000000000..62682e262a mode 100644,000000..100644 --- a/qcsrc/common/vehicles/cl_vehicles.qh +++ b/qcsrc/common/vehicles/cl_vehicles.qh @@@ -1,15 -1,0 +1,26 @@@ ++#ifndef CL_VEHICLES_H ++#define CL_VEHICLES_H ++ +// vehicle cvars +var float autocvar_cl_vehicles_alarm = 1; +var float autocvar_cl_vehicles_hud_tactical = 1; + ++void Net_AuXair2(float bIsNew); ++void bumble_raygun_read(float bIsNew); ++void Net_VehicleSetup(); ++void CSQC_BUMBLE_GUN_HUD(); ++ +void RaptorCBShellfragDraw(); +void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang); + +#define HUD_GETVEHICLESTATS \ + local noref float vh_health = getstati(STAT_VEHICLESTAT_HEALTH); \ + local noref float shield = getstati(STAT_VEHICLESTAT_SHIELD); \ + local noref float energy = getstati(STAT_VEHICLESTAT_ENERGY); \ + local noref float ammo1 = getstati(STAT_VEHICLESTAT_AMMO1); \ + local noref float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1); \ + local noref float ammo2 = getstati(STAT_VEHICLESTAT_AMMO2); \ + local noref float reload2 = getstati(STAT_VEHICLESTAT_RELOAD2); ++ ++#endif ++ diff --cc qcsrc/common/vehicles/sv_vehicles.qh index bbb2bed32b,0000000000..c1080982b3 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/sv_vehicles.qh +++ b/qcsrc/common/vehicles/sv_vehicles.qh @@@ -1,103 -1,0 +1,110 @@@ ++#ifndef VEHICLES_DEF_H ++#define VEHICLES_DEF_H ++ ++#include "../server/tturrets/include/turrets_early.qh" ++ +// #define VEHICLES_USE_ODE + +// vehicle cvars +float autocvar_g_vehicles; +float autocvar_g_vehicles_enter; +float autocvar_g_vehicles_enter_radius; +float autocvar_g_vehicles_steal; +float autocvar_g_vehicles_steal_show_waypoint; +float autocvar_g_vehicles_crush_dmg; +float autocvar_g_vehicles_crush_force; +float autocvar_g_vehicles_delayspawn; +float autocvar_g_vehicles_delayspawn_jitter; +float autocvar_g_vehicles_allow_bots; +float autocvar_g_vehicles_teams; +float autocvar_g_vehicles_teleportable; +var float autocvar_g_vehicles_vortex_damagerate = 0.5; +var float autocvar_g_vehicles_machinegun_damagerate = 0.5; +var float autocvar_g_vehicles_rifle_damagerate = 0.75; +var float autocvar_g_vehicles_vaporizer_damagerate = 0.001; +var float autocvar_g_vehicles_tag_damagerate = 5; + +// vehicle definitions +.entity gun1; +.entity gun2; +.entity gun3; +.entity vehicle_shieldent; /// Entity to disply the shild effect on damage +.entity vehicle; +.entity vehicle_viewport; +.entity vehicle_hudmodel; +.entity vehicle_controller; + +.entity gunner1; +.entity gunner2; + +.float vehicle_health; /// If self is player this is 0..100 indicating precentage of health left on vehicle. If self is vehile, this is the real health value. +.float vehicle_energy; /// If self is player this is 0..100 indicating precentage of energy left on vehicle. If self is vehile, this is the real energy value. +.float vehicle_shield; /// If self is player this is 0..100 indicating precentage of shield left on vehicle. If self is vehile, this is the real shield value. + +.float vehicle_ammo1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo1 value. +.float vehicle_reload1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload1 value. +.float vehicle_ammo2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo2 value. +.float vehicle_reload2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload2 value. + +.float sound_nexttime; - #define VOL_VEHICLEENGINE 1 ++const float VOL_VEHICLEENGINE = 1; + +const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05 +const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A +const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80 + - #define VHSF_NORMAL 0 - #define VHSF_FACTORY 2 ++const float VHSF_NORMAL = 0; ++const float VHSF_FACTORY = 2; + - .float hud; ++.int hud; +.float dmg_time; + +.float volly_counter; + - const float MAX_AXH = 4; ++const int MAX_AXH = 4; +.entity AuxiliaryXhair[MAX_AXH]; + +.entity wps_intruder; + +.entity lock_target; +.float lock_strength; +.float lock_time; +.float lock_soundtime; +const float DAMAGE_TARGETDRONE = 10; + +float force_fromtag_power; +float force_fromtag_normpower; +vector force_fromtag_origin; + +float vehicles_exit_running; + +#ifdef VEHICLES_USE_ODE +void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object +void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force +void(entity e, vector torque) physics_addtorque = #542; // add relative torque +#endif // VEHICLES_USE_ODE + +// functions used outside the vehicle code - void vehicles_exit(float eject); ++void vehicles_exit(bool eject); +void vehicles_enter(entity pl, entity veh); + +// vehicle functions - .void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns - .float(float _imp) vehicles_impulse; ++.void(int _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns ++.int(int _imp) vehicles_impulse; +.float vehicle_weapon2mode; - .void(float exit_flags) vehicle_exit; ++.void(int exit_flags) vehicle_exit; +.float() vehicle_enter; - const float VHEF_NORMAL = 0; /// User pressed exit key - const float VHEF_EJECT = 1; /// User pressed exit key 3 times fast (not implemented) or vehile is dying - const float VHEF_RELEASE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented) ++const int VHEF_NORMAL = 0; /// User pressed exit key ++const int VHEF_EJECT = 1; /// User pressed exit key 3 times fast (not implemented) or vehile is dying ++const int VHEF_RELEASE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented) + +// macros +#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \ + ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 + +#define vehicles_sweap_collision(orig,vel,dt,acm,mult) \ + traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \ + if(trace_fraction != 1) \ + acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult) ++ ++#endif diff --cc qcsrc/common/vehicles/unit/bumblebee.qc index d01d192d3f,0000000000..17669b6169 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/bumblebee.qc +++ b/qcsrc/common/vehicles/unit/bumblebee.qc @@@ -1,1388 -1,0 +1,1386 @@@ +#ifdef REGISTER_VEHICLE +REGISTER_VEHICLE( +/* VEH_##id */ BUMBLEBEE, +/* function */ v_bumblebee, +/* spawnflags */ VHF_DMGSHAKE, +/* mins,maxs */ '-245 -130 -130', '230 130 130', +/* model */ "models/vehicles/bumblebee_body.dpm", +/* head_model */ "", +/* hud_model */ "models/vehicles/spiderbot_cockpit.dpm", +/* tags */ "", "", "tag_viewport", +/* netname */ "bumblebee", +/* fullname */ _("Bumblebee") +); +#else + +const float BRG_SETUP = 2; +const float BRG_START = 4; +const float BRG_END = 8; + +#ifdef SVQC +float autocvar_g_vehicle_bumblebee_speed_forward; +float autocvar_g_vehicle_bumblebee_speed_strafe; +float autocvar_g_vehicle_bumblebee_speed_up; +float autocvar_g_vehicle_bumblebee_speed_down; +float autocvar_g_vehicle_bumblebee_turnspeed; +float autocvar_g_vehicle_bumblebee_pitchspeed; +float autocvar_g_vehicle_bumblebee_pitchlimit; +float autocvar_g_vehicle_bumblebee_friction; + +float autocvar_g_vehicle_bumblebee_energy; +float autocvar_g_vehicle_bumblebee_energy_regen; +float autocvar_g_vehicle_bumblebee_energy_regen_pause; + +float autocvar_g_vehicle_bumblebee_health; +float autocvar_g_vehicle_bumblebee_health_regen; +float autocvar_g_vehicle_bumblebee_health_regen_pause; + +float autocvar_g_vehicle_bumblebee_shield; +float autocvar_g_vehicle_bumblebee_shield_regen; +float autocvar_g_vehicle_bumblebee_shield_regen_pause; + +float autocvar_g_vehicle_bumblebee_cannon_cost; +float autocvar_g_vehicle_bumblebee_cannon_damage; +float autocvar_g_vehicle_bumblebee_cannon_radius; +float autocvar_g_vehicle_bumblebee_cannon_refire; +float autocvar_g_vehicle_bumblebee_cannon_speed; +float autocvar_g_vehicle_bumblebee_cannon_spread; +float autocvar_g_vehicle_bumblebee_cannon_force; + +float autocvar_g_vehicle_bumblebee_cannon_ammo; +float autocvar_g_vehicle_bumblebee_cannon_ammo_regen; +float autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause; + +var float autocvar_g_vehicle_bumblebee_cannon_lock = 0; + +float autocvar_g_vehicle_bumblebee_cannon_turnspeed; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; + + +float autocvar_g_vehicle_bumblebee_raygun_turnspeed; +float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down; +float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up; +float autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides; + +float autocvar_g_vehicle_bumblebee_raygun_range; +float autocvar_g_vehicle_bumblebee_raygun_dps; +float autocvar_g_vehicle_bumblebee_raygun_aps; +float autocvar_g_vehicle_bumblebee_raygun_fps; + +float autocvar_g_vehicle_bumblebee_raygun; +float autocvar_g_vehicle_bumblebee_healgun_hps; +float autocvar_g_vehicle_bumblebee_healgun_hmax; +float autocvar_g_vehicle_bumblebee_healgun_aps; +float autocvar_g_vehicle_bumblebee_healgun_amax; +float autocvar_g_vehicle_bumblebee_healgun_sps; +float autocvar_g_vehicle_bumblebee_healgun_locktime; + +float autocvar_g_vehicle_bumblebee_respawntime; + +float autocvar_g_vehicle_bumblebee_blowup_radius; +float autocvar_g_vehicle_bumblebee_blowup_coredamage; +float autocvar_g_vehicle_bumblebee_blowup_edgedamage; +float autocvar_g_vehicle_bumblebee_blowup_forceintensity; +var vector autocvar_g_vehicle_bumblebee_bouncepain; + +var float autocvar_g_vehicle_bumblebee = 0; + - - float bumble_raygun_send(entity to, float sf); ++float bumble_raygun_send(entity to, int sf); + +void bumblebee_fire_cannon(entity _gun, string _tagname, entity _owner) +{ + vector v = gettaginfo(_gun, gettagindex(_gun, _tagname)); + vehicles_projectile("bigplasma_muzzleflash", "weapons/flacexp3.wav", + v, normalize(v_forward + randomvec() * autocvar_g_vehicle_bumblebee_cannon_spread) * autocvar_g_vehicle_bumblebee_cannon_speed, + autocvar_g_vehicle_bumblebee_cannon_damage, autocvar_g_vehicle_bumblebee_cannon_radius, autocvar_g_vehicle_bumblebee_cannon_force, 0, - DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, TRUE, TRUE, _owner); ++ DEATH_VH_BUMB_GUN, PROJECTILE_BUMBLE_GUN, 0, true, true, _owner); +} + +float bumblebee_gunner_frame() +{ + entity vehic = self.vehicle.owner; + entity gun = self.vehicle; + entity gunner = self; + self = vehic; + + vehic.solid = SOLID_NOT; + //setorigin(gunner, vehic.origin); + gunner.velocity = vehic.velocity; + + float _in, _out; + vehic.angles_x *= -1; + makevectors(vehic.angles); + vehic.angles_x *= -1; + if((gun == vehic.gun1)) + { + _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; + _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; + setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * 128); + } + else + { + _in = autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; + _out = autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; + setorigin(gunner, vehic.origin + v_up * -16 + v_forward * -16 + v_right * -128); + } + + crosshair_trace(gunner); + vector _ct = trace_endpos; + vector ad; + + if(autocvar_g_vehicle_bumblebee_cannon_lock) + { + if(gun.lock_time < time) + gun.enemy = world; + + if(trace_ent) + if(trace_ent.movetype) + if(trace_ent.takedamage) + if(!trace_ent.deadflag) + { + if(teamplay) + { + if(trace_ent.team != gunner.team) + { + gun.enemy = trace_ent; + gun.lock_time = time + 5; + } + } + else + { + gun.enemy = trace_ent; + gun.lock_time = time + 5; + } + } + } + + if(gun.enemy) + { + float distance, impact_time; + + vector vf = real_origin(gun.enemy); + vector _vel = gun.enemy.velocity; + if(gun.enemy.movetype == MOVETYPE_WALK) - _vel_z *= 0.1; ++ _vel.z *= 0.1; + + + ad = vf; + distance = vlen(ad - gunner.origin); + impact_time = distance / autocvar_g_vehicle_bumblebee_cannon_speed; + ad = vf + _vel * impact_time; + trace_endpos = ad; + + + UpdateAuxiliaryXhair(gunner, ad, '1 0 1', 1); + vehicle_aimturret(vehic, trace_endpos, gun, "fire", + autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + + } + else + vehicle_aimturret(vehic, _ct, gun, "fire", + autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + + if(!forbidWeaponUse(gunner)) + if(gunner.BUTTON_ATCK) + if(time > gun.attack_finished_single) + if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost) + { + gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost; + bumblebee_fire_cannon(gun, "fire", gunner); + gun.delay = time; + gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire; + } + + VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee); + + if(vehic.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(gunner, shield, bumblebee); + + ad = gettaginfo(gun, gettagindex(gun, "fire")); + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, gun); + + UpdateAuxiliaryXhair(gunner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), 0); + + if(vehic.owner) + UpdateAuxiliaryXhair(vehic.owner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), ((gunner == vehic.gunner1) ? 1 : 2)); + + vehic.solid = SOLID_BBOX; + gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0; + gunner.vehicle_energy = (gun.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100; + + self = gunner; + return 1; +} + +void bumblebee_gunner_exit(float _exitflag) +{ + if(IS_REAL_CLIENT(self)) + { + msg_entity = self; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, self); + + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, 0); - WriteAngle(MSG_ONE, self.vehicle.angles_y); ++ WriteAngle(MSG_ONE, self.vehicle.angles.y); + WriteAngle(MSG_ONE, 0); + } + + CSQCVehicleSetup(self, HUD_NORMAL); + setsize(self, PL_MIN, PL_MAX); + + self.takedamage = DAMAGE_AIM; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; + self.effects &= ~EF_NODRAW; + self.alpha = 1; + self.PlayerPhysplug = func_null; + self.view_ofs = PL_VIEW_OFS; + self.event_damage = PlayerDamage; + self.hud = HUD_NORMAL; + self.teleportable = TELEPORT_NORMAL; + self.switchweapon = self.vehicle.switchweapon; + + vh_player = self; + vh_vehicle = self.vehicle; + MUTATOR_CALLHOOK(VehicleExit); + self = vh_player; + self.vehicle = vh_vehicle; + + self.vehicle.vehicle_hudmodel.viewmodelforclient = self.vehicle; + + fixedmakevectors(self.vehicle.owner.angles); + + if(self == self.vehicle.owner.gunner1) + { + self.vehicle.owner.gunner1 = world; + } + else if(self == self.vehicle.owner.gunner2) + { + self.vehicle.owner.gunner2 = world; + v_right *= -1; + } + else + dprint("^1self != gunner1 or gunner2, this is a BIG PROBLEM, tell tZork this happend.\n"); + + vector spot = self.vehicle.owner.origin + + v_up * 128 + v_right * 300; + spot = vehicles_findgoodexit(spot); + //setorigin(self , spot); + + self.velocity = 0.75 * self.vehicle.owner.velocity + normalize(spot - self.vehicle.owner.origin) * 200; + self.velocity_z += 10; + + self.vehicle.phase = time + 5; + self.vehicle = world; +} + +float bumblebee_gunner_enter() +{ + RemoveGrapplingHook(other); + entity _gun, _gunner; + if(!self.gunner1) + { + _gun = self.gun1; + _gunner = self.gunner1; + self.gunner1 = other; + } + else if(!self.gunner2) + { + _gun = self.gun2; + _gunner = self.gunner2; + self.gunner2 = other; + } + else + { + dprint("^1ERROR:^7Tried to enter a fully occupied vehicle!\n"); - return FALSE; ++ return false; + } + + _gunner = other; + _gunner.vehicle = _gun; + _gun.switchweapon = other.switchweapon; + _gun.vehicle_exit = bumblebee_gunner_exit; + + other.angles = self.angles; + other.takedamage = DAMAGE_NO; + other.solid = SOLID_NOT; + other.movetype = MOVETYPE_NOCLIP; + other.alpha = -1; + other.event_damage = func_null; + other.view_ofs = '0 0 0'; + other.hud = _gun.hud; - other.teleportable = FALSE; ++ other.teleportable = false; + other.PlayerPhysplug = _gun.PlayerPhysplug; + other.vehicle_ammo1 = self.vehicle_ammo1; + other.vehicle_ammo2 = self.vehicle_ammo2; + other.vehicle_reload1 = self.vehicle_reload1; + other.vehicle_reload2 = self.vehicle_reload2; + other.vehicle_energy = self.vehicle_energy; + other.PlayerPhysplug = bumblebee_gunner_frame; + other.flags &= ~FL_ONGROUND; + + if(IS_REAL_CLIENT(other)) + { + msg_entity = other; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, _gun.vehicle_viewport); + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, _gun.angles_x + self.angles_x); // tilt + WriteAngle(MSG_ONE, _gun.angles_y + self.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } - ++ + _gun.vehicle_hudmodel.viewmodelforclient = other; + + CSQCVehicleSetup(other, other.hud); + + vh_player = other; + vh_vehicle = _gun; + MUTATOR_CALLHOOK(VehicleEnter); + other = vh_player; + _gun = vh_vehicle; + - return TRUE; ++ return true; +} + +float vehicles_valid_pilot() +{ + if (!IS_PLAYER(other)) - return FALSE; ++ return false; + + if(other.deadflag != DEAD_NO) - return FALSE; ++ return false; + + if(other.vehicle != world) - return FALSE; ++ return false; + + if (!IS_REAL_CLIENT(other)) + if(!autocvar_g_vehicles_allow_bots) - return FALSE; ++ return false; + + if(teamplay && other.team != self.team) - return FALSE; ++ return false; + - return TRUE; ++ return true; +} + +void bumblebee_touch() +{ + if(autocvar_g_vehicles_enter) { return; } + + if(self.gunner1 != world && self.gunner2 != world) + { + vehicles_touch(); + return; + } + + if(vehicles_valid_pilot()) + { + if(self.gun1.phase <= time) + if(bumblebee_gunner_enter()) + return; + + if(self.gun2.phase <= time) + if(bumblebee_gunner_enter()) + return; + } + + vehicles_touch(); +} + +void bumblebee_regen() +{ + if(self.gun1.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time) + self.gun1.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo, + self.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime); + + if(self.gun2.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time) + self.gun2.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo, + self.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime); + + if(self.vehicle_flags & VHF_SHIELDREGEN) - vehicles_regen(self.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime, TRUE); ++ vehicles_regen(self.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime, true); + + if(self.vehicle_flags & VHF_HEALTHREGEN) - vehicles_regen(self.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime, FALSE); ++ vehicles_regen(self.dmg_time, vehicle_health, autocvar_g_vehicle_bumblebee_health, autocvar_g_vehicle_bumblebee_health_regen_pause, autocvar_g_vehicle_bumblebee_health_regen, frametime, false); + + if(self.vehicle_flags & VHF_ENERGYREGEN) - vehicles_regen(self.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime, FALSE); ++ vehicles_regen(self.wait, vehicle_energy, autocvar_g_vehicle_bumblebee_energy, autocvar_g_vehicle_bumblebee_energy_regen_pause, autocvar_g_vehicle_bumblebee_energy_regen, frametime, false); + +} + +float bumblebee_pilot_frame() +{ + entity pilot, vehic; + vector newvel; + + if(intermission_running) + { + self.vehicle.velocity = '0 0 0'; + self.vehicle.avelocity = '0 0 0'; + return 1; + } + + pilot = self; + vehic = self.vehicle; + self = vehic; + + if(vehic.deadflag != DEAD_NO) + { + self = pilot; + pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = 0; + return 1; + } + + bumblebee_regen(); + + crosshair_trace(pilot); + + vector vang; + float ftmp; + + vang = vehic.angles; + newvel = vectoangles(normalize(trace_endpos - self.origin + '0 0 32')); - vang_x *= -1; - newvel_x *= -1; - if(newvel_x > 180) newvel_x -= 360; - if(newvel_x < -180) newvel_x += 360; - if(newvel_y > 180) newvel_y -= 360; - if(newvel_y < -180) newvel_y += 360; - - ftmp = shortangle_f(pilot.v_angle_y - vang_y, vang_y); ++ vang.x *= -1; ++ newvel.x *= -1; ++ if(newvel.x > 180) newvel.x -= 360; ++ if(newvel.x < -180) newvel.x += 360; ++ if(newvel.y > 180) newvel.y -= 360; ++ if(newvel.y < -180) newvel.y += 360; ++ ++ ftmp = shortangle_f(pilot.v_angle.y - vang.y, vang.y); + if(ftmp > 180) ftmp -= 360; + if(ftmp < -180) ftmp += 360; - vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity_y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed); ++ vehic.avelocity_y = bound(-autocvar_g_vehicle_bumblebee_turnspeed, ftmp + vehic.avelocity.y * 0.9, autocvar_g_vehicle_bumblebee_turnspeed); + + // Pitch + ftmp = 0; - if(pilot.movement_x > 0 && vang_x < autocvar_g_vehicle_bumblebee_pitchlimit) ++ if(pilot.movement.x > 0 && vang.x < autocvar_g_vehicle_bumblebee_pitchlimit) + ftmp = 4; - else if(pilot.movement_x < 0 && vang_x > -autocvar_g_vehicle_bumblebee_pitchlimit) ++ else if(pilot.movement.x < 0 && vang.x > -autocvar_g_vehicle_bumblebee_pitchlimit) + ftmp = -8; + - newvel_x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x , autocvar_g_vehicle_bumblebee_pitchlimit); - ftmp = vang_x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel_x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit); - vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity_x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed); ++ newvel.x = bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x , autocvar_g_vehicle_bumblebee_pitchlimit); ++ ftmp = vang.x - bound(-autocvar_g_vehicle_bumblebee_pitchlimit, newvel.x + ftmp, autocvar_g_vehicle_bumblebee_pitchlimit); ++ vehic.avelocity_x = bound(-autocvar_g_vehicle_bumblebee_pitchspeed, ftmp + vehic.avelocity.x * 0.9, autocvar_g_vehicle_bumblebee_pitchspeed); + - vehic.angles_x = anglemods(vehic.angles_x); - vehic.angles_y = anglemods(vehic.angles_y); - vehic.angles_z = anglemods(vehic.angles_z); ++ vehic.angles_x = anglemods(vehic.angles.x); ++ vehic.angles_y = anglemods(vehic.angles.y); ++ vehic.angles_z = anglemods(vehic.angles.z); + - makevectors('0 1 0' * vehic.angles_y); ++ makevectors('0 1 0' * vehic.angles.y); + newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction; + - if(pilot.movement_x != 0) ++ if(pilot.movement.x != 0) + { - if(pilot.movement_x > 0) ++ if(pilot.movement.x > 0) + newvel += v_forward * autocvar_g_vehicle_bumblebee_speed_forward; - else if(pilot.movement_x < 0) ++ else if(pilot.movement.x < 0) + newvel -= v_forward * autocvar_g_vehicle_bumblebee_speed_forward; + } + - if(pilot.movement_y != 0) ++ if(pilot.movement.y != 0) + { - if(pilot.movement_y < 0) ++ if(pilot.movement.y < 0) + newvel -= v_right * autocvar_g_vehicle_bumblebee_speed_strafe; - else if(pilot.movement_y > 0) ++ else if(pilot.movement.y > 0) + newvel += v_right * autocvar_g_vehicle_bumblebee_speed_strafe; + ftmp = newvel * v_right; + ftmp *= frametime * 0.1; - vehic.angles_z = bound(-15, vehic.angles_z + ftmp, 15); ++ vehic.angles_z = bound(-15, vehic.angles.z + ftmp, 15); + } + else + { + vehic.angles_z *= 0.95; - if(vehic.angles_z >= -1 && vehic.angles_z <= -1) ++ if(vehic.angles.z >= -1 && vehic.angles.z <= -1) + vehic.angles_z = 0; + } + + if(pilot.BUTTON_CROUCH) + newvel -= v_up * autocvar_g_vehicle_bumblebee_speed_down; + else if(pilot.BUTTON_JUMP) + newvel += v_up * autocvar_g_vehicle_bumblebee_speed_up; + + vehic.velocity += newvel * frametime; + pilot.velocity = pilot.movement = vehic.velocity; + + + if(autocvar_g_vehicle_bumblebee_healgun_locktime) + { + if(vehic.tur_head.lock_time < time || vehic.tur_head.enemy.deadflag) + vehic.tur_head.enemy = world; + + if(trace_ent) + if(trace_ent.movetype) + if(trace_ent.takedamage) + if(!trace_ent.deadflag) + { + if(teamplay) + { + if(trace_ent.team == pilot.team) + { + vehic.tur_head.enemy = trace_ent; + vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime; + } + } + else + { + vehic.tur_head.enemy = trace_ent; + vehic.tur_head.lock_time = time + autocvar_g_vehicle_bumblebee_healgun_locktime; + } + } + + if(vehic.tur_head.enemy) + { + trace_endpos = real_origin(vehic.tur_head.enemy); + UpdateAuxiliaryXhair(pilot, trace_endpos, '0 0.75 0', 0); + } + } + + vang = vehicle_aimturret(vehic, trace_endpos, self.gun3, "fire", + autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up, + autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides * -1, autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides, autocvar_g_vehicle_bumblebee_raygun_turnspeed); + + if(!forbidWeaponUse(pilot)) + if((pilot.BUTTON_ATCK || pilot.BUTTON_ATCK2) && (vehic.vehicle_energy > autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime || autocvar_g_vehicle_bumblebee_raygun == 0)) + { + vehic.gun3.enemy.realowner = pilot; + vehic.gun3.enemy.effects &= ~EF_NODRAW; + + vehic.gun3.enemy.hook_start = gettaginfo(vehic.gun3, gettagindex(vehic.gun3, "fire")); + vehic.gun3.enemy.SendFlags |= BRG_START; + + traceline(vehic.gun3.enemy.hook_start, vehic.gun3.enemy.hook_start + v_forward * autocvar_g_vehicle_bumblebee_raygun_range, MOVE_NORMAL, vehic); + + if(trace_ent) + { + if(autocvar_g_vehicle_bumblebee_raygun) + { + Damage(trace_ent, vehic, pilot, autocvar_g_vehicle_bumblebee_raygun_dps * sys_frametime, DEATH_GENERIC, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * sys_frametime); + vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * sys_frametime; + } + else + { + if(trace_ent.deadflag == DEAD_NO) + if((teamplay && trace_ent.team == pilot.team) || !teamplay) + { + + if(trace_ent.vehicle_flags & VHF_ISVEHICLE) + { + if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health) + trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * frametime, trace_ent.tur_head.max_health); + + if(autocvar_g_vehicle_bumblebee_healgun_hps) + trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health); + } + else if(IS_CLIENT(trace_ent)) + { + if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps) + trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax); + + if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps) + trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * frametime, autocvar_g_vehicle_bumblebee_healgun_amax); + + trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, autocvar_g_vehicle_bumblebee_healgun_hmax); + } + else if(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET) + { + if(trace_ent.health <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps) + trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.max_health); + //else ..hmmm what? ammo? + + trace_ent.SendFlags |= TNSF_STATUS; + } + } + } + } + + vehic.gun3.enemy.hook_end = trace_endpos; + setorigin(vehic.gun3.enemy, trace_endpos); + vehic.gun3.enemy.SendFlags |= BRG_END; + + vehic.wait = time + 1; + } + else + vehic.gun3.enemy.effects |= EF_NODRAW; + /*{ + if(vehic.gun3.enemy) + remove(vehic.gun3.enemy); + + vehic.gun3.enemy = world; + } + */ + + VEHICLE_UPDATE_PLAYER(pilot, health, bumblebee); + VEHICLE_UPDATE_PLAYER(pilot, energy, bumblebee); + + pilot.vehicle_ammo1 = (vehic.gun1.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100; + pilot.vehicle_ammo2 = (vehic.gun2.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100; + + if(vehic.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(pilot, shield, bumblebee); + + vehic.angles_x *= -1; + makevectors(vehic.angles); + vehic.angles_x *= -1; + setorigin(pilot, vehic.origin + v_up * 48 + v_forward * 160); + + pilot.BUTTON_ATCK = pilot.BUTTON_ATCK2 = pilot.BUTTON_CROUCH = 0; + self = pilot; + + return 1; +} + +void bumblebee_land() +{ + float hgt; + + hgt = raptor_altitude(512); + self.velocity = (self.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime); + self.angles_x *= 0.95; + self.angles_z *= 0.95; + + if(hgt < 16) + self.think = vehicles_think; + + self.nextthink = time; + + CSQCMODEL_AUTOUPDATE(); +} + +void bumblebee_exit(float eject) +{ + if(self.owner.vehicleid == VEH_BUMBLEBEE) + { + bumblebee_gunner_exit(eject); + return; + } + + self.touch = vehicles_touch; + + if(self.deadflag == DEAD_NO) + { + self.think = bumblebee_land; + self.nextthink = time; + } + + self.movetype = MOVETYPE_TOSS; + + if(!self.owner) + return; + + fixedmakevectors(self.angles); + vector spot; + if(vlen(self.velocity) > autocvar_g_vehicle_bumblebee_speed_forward * 0.5) + spot = self.origin + v_up * 128 + v_forward * 300; + else + spot = self.origin + v_up * 128 - v_forward * 300; + + spot = vehicles_findgoodexit(spot); + + // Hide beam + if(self.gun3.enemy || !wasfreed(self.gun3.enemy)) { + self.gun3.enemy.effects |= EF_NODRAW; + } + + self.owner.velocity = 0.75 * self.vehicle.velocity + normalize(spot - self.vehicle.origin) * 200; + self.owner.velocity_z += 10; + setorigin(self.owner, spot); + + antilag_clear(self.owner); + self.owner = world; +} + +void bumblebee_blowup() +{ + RadiusDamage(self, self.enemy, autocvar_g_vehicle_bumblebee_blowup_coredamage, + autocvar_g_vehicle_bumblebee_blowup_edgedamage, + autocvar_g_vehicle_bumblebee_blowup_radius, self, world, + autocvar_g_vehicle_bumblebee_blowup_forceintensity, + DEATH_VH_BUMB_DEATH, world); + + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); + pointparticles(particleeffectnum("explosion_big"), (self.origin + '0 0 100') + (randomvec() * 80), '0 0 0', 1); + + if(self.owner.deadflag == DEAD_DYING) + self.owner.deadflag = DEAD_DEAD; + + remove(self); +} + +void bumblebee_diethink() +{ + if(time >= self.wait) + self.think = bumblebee_blowup; + + if(random() < 0.1) + { + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); + pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); + } + + self.nextthink = time + 0.1; +} + +float bumble_raygun_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN); + + WriteByte(MSG_ENTITY, sf); + if(sf & BRG_SETUP) + { + WriteByte(MSG_ENTITY, num_for_edict(self.realowner)); + WriteByte(MSG_ENTITY, self.realowner.team); + WriteByte(MSG_ENTITY, self.cnt); + } + + if(sf & BRG_START) + { + WriteCoord(MSG_ENTITY, self.hook_start_x); + WriteCoord(MSG_ENTITY, self.hook_start_y); + WriteCoord(MSG_ENTITY, self.hook_start_z); + } + + if(sf & BRG_END) + { + WriteCoord(MSG_ENTITY, self.hook_end_x); + WriteCoord(MSG_ENTITY, self.hook_end_y); + WriteCoord(MSG_ENTITY, self.hook_end_z); + } + - return TRUE; ++ return true; +} + +void spawnfunc_vehicle_bumblebee() +{ + if(!autocvar_g_vehicle_bumblebee) { remove(self); return; } - if(!vehicle_initialize(VEH_BUMBLEBEE, FALSE)) { remove(self); return; } ++ if(!vehicle_initialize(VEH_BUMBLEBEE, false)) { remove(self); return; } +} + +float v_bumblebee(float req) +{ + switch(req) + { + case VR_IMPACT: + { + if(autocvar_g_vehicle_bumblebee_bouncepain) + vehicles_impact(autocvar_g_vehicle_bumblebee_bouncepain_x, autocvar_g_vehicle_bumblebee_bouncepain_y, autocvar_g_vehicle_bumblebee_bouncepain_z); + - return TRUE; ++ return true; + } + case VR_ENTER: + { + self.touch = bumblebee_touch; + self.nextthink = 0; + self.movetype = MOVETYPE_BOUNCEMISSILE; - return TRUE; ++ return true; + } + case VR_THINK: + { + self.angles_z *= 0.8; + self.angles_x *= 0.8; + + self.nextthink = time; + + if(!self.owner) + { + entity oldself = self; + if(self.gunner1) + { + self = self.gunner1; + oldself.gun1.vehicle_exit(VHEF_EJECT); + entity oldother = other; + other = self; + self = oldself; + self.phase = 0; + self.touch(); + other = oldother; - return TRUE; ++ return true; + } + + if(self.gunner2) + { + self = self.gunner2; + oldself.gun2.vehicle_exit(VHEF_EJECT); + entity oldother = other; + other = self; + self = oldself; + self.phase = 0; + self.touch(); + other = oldother; - return TRUE; ++ return true; + } + } + - return TRUE; ++ return true; + } + case VR_DEATH: + { + entity oldself = self; + + CSQCModel_UnlinkEntity(); + + // Hide beam + if(self.gun3.enemy || !wasfreed(self.gun3.enemy)) + self.gun3.enemy.effects |= EF_NODRAW; + + if(self.gunner1) + { + self = self.gunner1; + oldself.gun1.vehicle_exit(VHEF_EJECT); + self = oldself; + } + + if(self.gunner2) + { + self = self.gunner2; + oldself.gun2.vehicle_exit(VHEF_EJECT); + self = oldself; + } + + self.vehicle_exit(VHEF_EJECT); + + fixedmakevectors(self.angles); + vehicle_tossgib(self.gun1, self.velocity + v_right * 300 + v_up * 100 + randomvec() * 200, "cannon_right", rint(random()), rint(random()), 6, randomvec() * 200); + vehicle_tossgib(self.gun2, self.velocity + v_right * -300 + v_up * 100 + randomvec() * 200, "cannon_left", rint(random()), rint(random()), 6, randomvec() * 200); + vehicle_tossgib(self.gun3, self.velocity + v_forward * 300 + v_up * -100 + randomvec() * 200, "raygun", rint(random()), rint(random()), 6, randomvec() * 300); + + entity _body = vehicle_tossgib(self, self.velocity + randomvec() * 200, "", rint(random()), rint(random()), 6, randomvec() * 100); + + if(random() > 0.5) + _body.touch = bumblebee_blowup; + else + _body.touch = func_null; + + _body.think = bumblebee_diethink; + _body.nextthink = time; + _body.wait = time + 2 + (random() * 8); + _body.owner = self; + _body.enemy = self.enemy; + _body.scale = 1.5; + _body.angles = self.angles; + + pointparticles(particleeffectnum("explosion_medium"), findbetterlocation(self.origin, 16), '0 0 0', 1); + + self.health = 0; + self.event_damage = func_null; + self.solid = SOLID_NOT; + self.takedamage = DAMAGE_NO; + self.deadflag = DEAD_DYING; + self.movetype = MOVETYPE_NONE; + self.effects = EF_NODRAW; + self.colormod = '0 0 0'; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + self.touch = func_null; + self.nextthink = 0; + + setorigin(self, self.pos1); - return TRUE; ++ return true; + } + case VR_SPAWN: + { + if(!self.gun1) + { + // for some reason, autosizing of the shield entity refuses to work for this one so set it up in advance. + self.vehicle_shieldent = spawn(); + self.vehicle_shieldent.effects = EF_LOWPRECISION; + setmodel(self.vehicle_shieldent, "models/vhshield.md3"); + setattachment(self.vehicle_shieldent, self, ""); + setorigin(self.vehicle_shieldent, real_origin(self) - self.origin); + self.vehicle_shieldent.scale = 512 / vlen(self.maxs - self.mins); + self.vehicle_shieldent.think = shieldhit_think; + self.vehicle_shieldent.alpha = -1; + self.vehicle_shieldent.effects = EF_LOWPRECISION | EF_NODRAW; + + self.gun1 = spawn(); + self.gun2 = spawn(); + self.gun3 = spawn(); + + self.vehicle_flags |= VHF_MULTISLOT; + + self.gun1.owner = self; + self.gun2.owner = self; + self.gun3.owner = self; + + setmodel(self.gun1, "models/vehicles/bumblebee_plasma_right.dpm"); + setmodel(self.gun2, "models/vehicles/bumblebee_plasma_left.dpm"); + setmodel(self.gun3, "models/vehicles/bumblebee_ray.dpm"); + + setattachment(self.gun1, self, "cannon_right"); + setattachment(self.gun2, self, "cannon_left"); + + // Angled bones are no fun, messes up gun-aim; so work arround it. + self.gun3.pos1 = self.angles; + self.angles = '0 0 0'; + vector ofs = gettaginfo(self, gettagindex(self, "raygun")); + ofs -= self.origin; + setattachment(self.gun3, self, ""); + setorigin(self.gun3, ofs); + self.angles = self.gun3.pos1; + + vehicle_addplayerslot(self, self.gun1, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumblebee_gunner_frame, bumblebee_gunner_exit, bumblebee_gunner_enter); + vehicle_addplayerslot(self, self.gun2, HUD_BUMBLEBEE_GUN, "models/vehicles/wakizashi_cockpit.dpm", bumblebee_gunner_frame, bumblebee_gunner_exit, bumblebee_gunner_enter); + + setorigin(self.vehicle_hudmodel, '50 0 -5'); // Move cockpit forward - down. + setorigin(self.vehicle_viewport, '5 0 2'); // Move camera forward up + + //fixme-model-bones + setorigin(self.gun1.vehicle_hudmodel, '90 -27 -23'); + setorigin(self.gun1.vehicle_viewport, '-85 0 50'); + //fixme-model-bones + setorigin(self.gun2.vehicle_hudmodel, '90 27 -23'); + setorigin(self.gun2.vehicle_viewport, '-85 0 50'); + + self.scale = 1.5; + + // Raygun beam + if(self.gun3.enemy == world) + { + self.gun3.enemy = spawn(); - Net_LinkEntity(self.gun3.enemy, TRUE, 0, bumble_raygun_send); ++ Net_LinkEntity(self.gun3.enemy, true, 0, bumble_raygun_send); + self.gun3.enemy.SendFlags = BRG_SETUP; + self.gun3.enemy.cnt = autocvar_g_vehicle_bumblebee_raygun; + self.gun3.enemy.effects = EF_NODRAW | EF_LOWPRECISION; + } + } + + self.vehicle_health = autocvar_g_vehicle_bumblebee_health; + self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; + self.solid = SOLID_BBOX; + self.movetype = MOVETYPE_TOSS; + self.damageforcescale = 0.025; + + self.PlayerPhysplug = bumblebee_pilot_frame; + + setorigin(self, self.origin + '0 0 25'); - return TRUE; ++ return true; + } + case VR_SETUP: + { + if(autocvar_g_vehicle_bumblebee_energy) + if(autocvar_g_vehicle_bumblebee_energy_regen) + self.vehicle_flags |= VHF_ENERGYREGEN; + + if(autocvar_g_vehicle_bumblebee_shield) + self.vehicle_flags |= VHF_HASSHIELD; + + if(autocvar_g_vehicle_bumblebee_shield_regen) + self.vehicle_flags |= VHF_SHIELDREGEN; + + if(autocvar_g_vehicle_bumblebee_health_regen) + self.vehicle_flags |= VHF_HEALTHREGEN; + + self.vehicle_exit = bumblebee_exit; + self.respawntime = autocvar_g_vehicle_bumblebee_respawntime; + self.vehicle_health = autocvar_g_vehicle_bumblebee_health; + self.max_health = self.vehicle_health; + self.vehicle_shield = autocvar_g_vehicle_bumblebee_shield; + - return TRUE; ++ return true; + } + case VR_PRECACHE: + { + precache_model("models/vehicles/bumblebee_body.dpm"); + precache_model("models/vehicles/bumblebee_plasma_left.dpm"); + precache_model("models/vehicles/bumblebee_plasma_right.dpm"); + precache_model("models/vehicles/bumblebee_ray.dpm"); + precache_model("models/vehicles/wakizashi_cockpit.dpm"); + precache_model("models/vehicles/spiderbot_cockpit.dpm"); + precache_model("models/vehicles/raptor_cockpit.dpm"); - return TRUE; ++ return true; + } + } + - return TRUE; ++ return true; +} + +#endif // SVQC +#ifdef CSQC + +#define bumb_ico "gfx/vehicles/bumb.tga" +#define bumb_lgun "gfx/vehicles/bumb_lgun.tga" +#define bumb_rgun "gfx/vehicles/bumb_rgun.tga" + +#define bumb_gun_ico "gfx/vehicles/bumb_side.tga" +#define bumb_gun_gun "gfx/vehicles/bumb_side_gun.tga" + +void CSQC_BUMBLE_GUN_HUD() +{ - + if(autocvar_r_letterbox) + return; + + vector picsize, hudloc = '0 0 0', pic2size, picloc; + + // Fetch health & ammo stats + HUD_GETVEHICLESTATS + + picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale; + hudloc_y = vid_conheight - picsize_y; + hudloc_x = vid_conwidth * 0.5 - picsize_x * 0.5; + + drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL); + + shield *= 0.01; + vh_health *= 0.01; + energy *= 0.01; + reload1 *= 0.01; + + pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8); + picloc = picsize * 0.5 - pic2size * 0.5; + + if(vh_health < 0.25) + drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + else + drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); + + drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); + drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL); + +// Health bar + picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale; + picloc = '69 69 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - vh_health)), 0, vid_conwidth, vid_conheight); + drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL); + drawresetcliparea(); +// .. and icon + picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale; + picloc = '37 65 0' * autocvar_cl_vehicles_hudscale; + if(vh_health < 0.25) + { + if(alarm1time < time) + { + alarm1time = time + 2; + vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav"); + } + + drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + } + else + { + drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + if(alarm1time) + { + vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav"); + alarm1time = 0; + } + } + +// Shield bar + picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale; + picloc = '69 140 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - shield)), 0, vid_conwidth, vid_conheight); + drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawresetcliparea(); +// .. and icon + picloc = '40 136 0' * autocvar_cl_vehicles_hudscale; + picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale; + if(shield < 0.25) + { + if(alarm2time < time) + { + alarm2time = time + 1; + vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav"); + } + drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + } + else + { + drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + if(alarm2time) + { + vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav"); + alarm2time = 0; + } + } + +// Gun bar + picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale; + picloc = '450 69 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * energy, vid_conheight); + drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawresetcliparea(); + +// .. and icon + picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale; + picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; + if(energy < 0.2) + drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + else + drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + + if (scoreboard_showscores) + HUD_DrawScoreboard(); + /* + else + { + picsize = draw_getimagesize(waki_xhair); + picsize_x *= 0.5; + picsize_y *= 0.5; + + + drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + } + */ +} + +void bumble_raygun_draw() +{ + float _len; + vector _dir; + vector _vtmp1, _vtmp2; + + _len = vlen(self.origin - self.move_origin); + _dir = normalize(self.move_origin - self.origin); + + if(self.total_damages < time) + { + boxparticles(self.traileffect, self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA); + boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA); + self.total_damages = time + 0.1; + } + + float i, df, sz, al; + for(i = -0.1; i < 0.2; i += 0.1) + { + df = DRAWFLAG_NORMAL; //((random() < 0.5) ? DRAWFLAG_ADDITIVE : DRAWFLAG_SCREEN); + sz = 5 + random() * 5; + al = 0.25 + random() * 0.5; + _vtmp1 = self.origin + _dir * _len * (0.25 + i); + _vtmp1 += (randomvec() * (_len * 0.2) * (frametime * 2)); //self.raygun_l1; + Draw_CylindricLine(self.origin, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + _vtmp2 = self.origin + _dir * _len * (0.5 + i); + _vtmp2 += (randomvec() * (_len * 0.2) * (frametime * 5)); //self.raygun_l2; + Draw_CylindricLine(_vtmp1, _vtmp2, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + _vtmp1 = self.origin + _dir * _len * (0.75 + i); + _vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10); //self.raygun_l3; + Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + Draw_CylindricLine(_vtmp1, self.move_origin + randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + } +} + +void bumble_raygun_read(float bIsNew) +{ - float sf = ReadByte(); ++ int sf = ReadByte(); + + if(sf & BRG_SETUP) + { + self.cnt = ReadByte(); + self.team = ReadByte(); + self.cnt = ReadByte(); + + if(self.cnt) + self.colormod = '1 0 0'; + else + self.colormod = '0 1 0'; + + self.traileffect = particleeffectnum("healray_muzzleflash"); + self.lip = particleeffectnum("healray_impact"); + + self.draw = bumble_raygun_draw; + } + + + if(sf & BRG_START) + { + self.origin_x = ReadCoord(); + self.origin_y = ReadCoord(); + self.origin_z = ReadCoord(); + setorigin(self, self.origin); + } + + if(sf & BRG_END) + { + self.move_origin_x = ReadCoord(); + self.move_origin_y = ReadCoord(); + self.move_origin_z = ReadCoord(); + } +} + +float v_bumblebee(float req) +{ + switch(req) + { + case VR_HUD: + { + if(autocvar_r_letterbox) - return TRUE; ++ return true; + + vector picsize, hudloc = '0 0 0', pic2size, picloc; + + // Fetch health & ammo stats + HUD_GETVEHICLESTATS + + picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale; + hudloc_y = vid_conheight - picsize_y; + hudloc_x = vid_conwidth * 0.5 - picsize_x * 0.5; + + drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL); + + shield *= 0.01; + vh_health *= 0.01; + energy *= 0.01; + reload1 *= 0.01; + + pic2size = draw_getimagesize(bumb_ico) * (autocvar_cl_vehicles_hudscale * 0.8); + picloc = picsize * 0.5 - pic2size * 0.5; + + if(vh_health < 0.25) + drawpic(hudloc + picloc, bumb_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + else + drawpic(hudloc + picloc, bumb_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); + + drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); + drawpic(hudloc + picloc, bumb_lgun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); + drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL); + + // Health bar + picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale; + picloc = '69 69 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - vh_health)), 0, vid_conwidth, vid_conheight); + drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL); + drawresetcliparea(); + // .. and icon + picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale; + picloc = '37 65 0' * autocvar_cl_vehicles_hudscale; + if(vh_health < 0.25) + { + if(alarm1time < time) + { + alarm1time = time + 2; + vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav"); + } + + drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + } + else + { + drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + if(alarm1time) + { + vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav"); + alarm1time = 0; + } + } + + // Shield bar + picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale; + picloc = '69 140 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - shield)), 0, vid_conwidth, vid_conheight); + drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawresetcliparea(); + // .. and icon + picloc = '40 136 0' * autocvar_cl_vehicles_hudscale; + picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale; + if(shield < 0.25) + { + if(alarm2time < time) + { + alarm2time = time + 1; + vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav"); + } + drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + } + else + { + drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + if(alarm2time) + { + vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav"); + alarm2time = 0; + } + } + + ammo1 *= 0.01; + ammo2 *= 0.01; + + // Gunner1 bar + picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale; + picloc = '450 69 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * ammo1, vid_conheight); + drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawresetcliparea(); + + // Right gunner slot occupied? + if(!AuxiliaryXhair[1].draw2d) + { - shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), FALSE, '1 0 0' * picsize_y + '0 1 0' * picsize_y)); ++ shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No right gunner!"), false, '1 0 0' * picsize_y + '0 1 0' * picsize_y)); + drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL); + drawstring(hudloc + picloc + '1 0 0' * shield, _("No right gunner!"), '1 0 0' * picsize_y + '0 1 0' * picsize_y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL); + } + + // .. and icon + picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale; + picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; + if(ammo1 < 0.2) + drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + else + drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + + // Gunner2 bar + picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale; + picloc = '450 140 0' * autocvar_cl_vehicles_hudscale; + drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * ammo2, vid_conheight); + drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + drawresetcliparea(); + // Left gunner slot occupied? + if(!AuxiliaryXhair[2].draw2d) + { - shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), FALSE, '1 0 0' * picsize_y + '0 1 0' * picsize_y)); ++ shield = (picsize_x * 0.5) - (0.5 * stringwidth(_("No left gunner!"), false, '1 0 0' * picsize_y + '0 1 0' * picsize_y)); + drawfill(hudloc + picloc - '0.2 0.2 0', picsize + '0.4 0.4 0', '0.25 0.25 0.25', 0.75, DRAWFLAG_NORMAL); + drawstring(hudloc + picloc + '1 0 0' * shield, _("No left gunner!"), '1 0 0' * picsize_y + '0 1 0' * picsize_y, '1 0 0' + '0 1 1' * sin(time * 10), 1, DRAWFLAG_NORMAL); + } + + // .. and icon + picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale; + picloc = '664 130 0' * autocvar_cl_vehicles_hudscale; + if(ammo2 < 0.2) + drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); + else + drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + + if (scoreboard_showscores) + HUD_DrawScoreboard(); + else + { + picsize = draw_getimagesize(waki_xhair); + picsize_x *= 0.5; + picsize_y *= 0.5; + drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); + } - return TRUE; ++ return true; + } + case VR_SETUP: + { + // raygun-locked + AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga"; + AuxiliaryXhair[0].axh_scale = 0.5; + + // Gunner1 + AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-target.tga"; + AuxiliaryXhair[1].axh_scale = 0.75; + + // Gunner2 + AuxiliaryXhair[2].axh_image = "gfx/vehicles/axh-target.tga"; + AuxiliaryXhair[2].axh_scale = 0.75; - return TRUE; ++ return true; + } + case VR_PRECACHE: + { - return TRUE; ++ return true; + } + } + - return TRUE; ++ return true; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --cc qcsrc/common/vehicles/vehicles.qh index db5bb8ddcc,0000000000..2436c5c836 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles.qh +++ b/qcsrc/common/vehicles/vehicles.qh @@@ -1,89 -1,0 +1,94 @@@ ++#ifndef VEHICLES_H ++#define VEHICLES_H ++ +// vehicle requests +#define VR_SETUP 1 // (BOTH) setup vehicle data +#define VR_THINK 2 // (SERVER) logic to run every frame +#define VR_DEATH 3 // (SERVER) called when vehicle dies +#define VR_PRECACHE 4 // (BOTH) precaches models/sounds used by this vehicle +#define VR_ENTER 5 // (SERVER) called when a player enters this vehicle +#define VR_SPAWN 6 // (SERVER) called when the vehicle re-spawns +#define VR_IMPACT 7 // (SERVER) called when a vehicle hits something +#define VR_HUD 8 // (CLIENT) logic to run every frame + +// functions: - entity get_vehicleinfo(float id); ++entity get_vehicleinfo(int id); + +// fields: +.entity tur_head; + +// flags: - .float vehicle_flags; - const float VHF_ISVEHICLE = 2; /// Indicates vehicle - const float VHF_HASSHIELD = 4; /// Vehicle has shileding - const float VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates - const float VHF_HEALTHREGEN = 16; /// Vehicles health regenerates - const float VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates - const float VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage - const float VHF_MOVE_GROUND = 128; /// Vehicle moves on gound - const float VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound - const float VHF_MOVE_FLY = 512; /// Vehicle is airborn - const float VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50% - const float VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50% - const float VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50% - const float VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots - const float VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle ++.int vehicle_flags; ++const int VHF_ISVEHICLE = 2; /// Indicates vehicle ++const int VHF_HASSHIELD = 4; /// Vehicle has shileding ++const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates ++const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates ++const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates ++const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage ++const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound ++const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound ++const int VHF_MOVE_FLY = 512; /// Vehicle is airborn ++const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50% ++const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50% ++const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50% ++const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots ++const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle + + +// entity properties of vehicleinfo: - .float vehicleid; // VEH_... ++.int vehicleid; // VEH_... +.string netname; // short name +.string vehicle_name; // human readable name - .float(float) vehicle_func; // v_... ++.int(int) vehicle_func; // v_... +.string mdl; // currently a copy of the model +.string model; // full name of model +.string head_model; // full name of tur_head model +.string hud_model; // cockpit model +.string tag_head; // tur_head model tag +.string tag_hud; // hud model tag +.string tag_view; // cockpit model tag - .float() PlayerPhysplug; // player physics mod - .float spawnflags; ++.int() PlayerPhysplug; // player physics mod ++.int spawnflags; +.vector mins, maxs; // vehicle hitbox size + +// other useful macros +#define VEH_ACTION(vehicletype,mrequest) (get_vehicleinfo(vehicletype)).vehicle_func(mrequest) +#define VEH_NAME(vehicletype) (get_vehicleinfo(vehicletype)).vehicle_name + +// ===================== +// Vehicle Registration +// ===================== + - float v_null(float dummy); - void register_vehicle(float id, float(float) func, float vehicleflags, vector min_s, vector max_s, string modelname, string headmodelname, string hudmodelname, string headtag, string hudtag, string viewtag, string shortname, string vname); ++int v_null(int dummy); ++void register_vehicle(int id, int(int) func, float vehicleflags, vector min_s, vector max_s, string modelname, string headmodelname, string hudmodelname, string headtag, string hudtag, string viewtag, string shortname, string vname); +void register_vehicles_done(); + - const float VEH_MAXCOUNT = 24; ++const int VEH_MAXCOUNT = 24; +#define VEH_FIRST 1 - float VEH_COUNT; - float VEH_LAST; ++int VEH_COUNT; ++int VEH_LAST; + +#define REGISTER_VEHICLE_2(id,func,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname) \ - float id; \ - float func(float); \ ++ int id; \ ++ int func(int); \ + void RegisterVehicles_##id() \ + { \ + VEH_LAST = (id = VEH_FIRST + VEH_COUNT); \ + ++VEH_COUNT; \ + register_vehicle(id,func,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname); \ + } \ + ACCUMULATE_FUNCTION(RegisterVehicles, RegisterVehicles_##id) +#ifdef MENUQC +#define REGISTER_VEHICLE(id,func,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname) \ + REGISTER_VEHICLE_2(VEH_##id,v_null,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname) +#else +#define REGISTER_VEHICLE(id,func,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname) \ + REGISTER_VEHICLE_2(VEH_##id,func,vehicleflags,min_s,max_s,modelname,headmodelname,hudmodelname,headtag,hudtag,viewtag,shortname,vname) +#endif + +#include "all.qh" + +#undef REGISTER_VEHICLE +ACCUMULATE_FUNCTION(RegisterVehicles, register_vehicles_done); ++ ++#endif diff --cc qcsrc/common/vehicles/vehicles_include.qh index d37d749a4e,0000000000..409e94cb26 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles_include.qh +++ b/qcsrc/common/vehicles/vehicles_include.qh @@@ -1,8 -1,0 +1,13 @@@ ++#ifndef VEHICLES_INCLUDE_H ++#define VEHICLES_INCLUDE_H ++ +#ifdef CSQC +#include "vehicles.qh" +#include "cl_vehicles.qh" +#endif // CSQC +#ifdef SVQC +#include "vehicles.qh" +#include "sv_vehicles.qh" +#endif // SVQC ++ ++#endif diff --cc qcsrc/server/antilag.qc index c53452ab78,6f8f0f487e..69ad14cb02 --- a/qcsrc/server/antilag.qc +++ b/qcsrc/server/antilag.qc @@@ -1,7 -1,16 +1,17 @@@ - #define ANTILAG_MAX_ORIGINS 64 + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" ++ #include "../common/vehicles/vehicles.qh" + #include "antilag.qh" + #endif + + const int ANTILAG_MAX_ORIGINS = 64; .vector antilag_origins[ANTILAG_MAX_ORIGINS]; .float antilag_times[ANTILAG_MAX_ORIGINS]; - .float antilag_index; + .int antilag_index; .vector antilag_saved_origin; .float antilag_takenback; diff --cc qcsrc/server/cl_client.qc index e8595722cf,3bc5cc762f..ec9fd19b0e --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@@ -398,11 -425,14 +425,11 @@@ void PutClientInServer (void RemoveGrapplingHook(self); // Wazat's Grappling Hook - if(self.vehicle) - vehicles_exit(VHEF_RELESE); - self.classname = "player"; - self.wasplayer = TRUE; - self.iscreature = TRUE; + self.wasplayer = true; + self.iscreature = true; self.teleportable = TELEPORT_NORMAL; - self.damagedbycontents = TRUE; + self.damagedbycontents = true; self.movetype = MOVETYPE_WALK; self.solid = SOLID_SLIDEBOX; self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; @@@ -2215,8 -2234,7 +2269,8 @@@ Called every frame for each client befo */ .float usekeypressed; void() nexball_setstatus; - .float items_added; +.float last_vehiclecheck; + .int items_added; void PlayerPreThink (void) { WarpZone_PlayerPhysics_FixVAngle(); diff --cc qcsrc/server/command/cmd.qc index 898e7db18f,4a8b59eba6..d4f2a01754 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@@ -1,3 -1,32 +1,32 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../../dpdefs/progsdefs.qh" + #include "../../dpdefs/dpextensions.qh" + #include "../../warpzonelib/common.qh" + #include "../../common/constants.qh" + #include "../../common/teams.qh" + #include "../../common/util.qh" + #include "../../common/command/shared_defs.qh" + #include "../../common/monsters/monsters.qh" + #include "../../common/monsters/sv_monsters.qh" + #include "../../common/monsters/spawn.qh" + #include "../autocvars.qh" + #include "../defs.qh" + #include "../../common/notifications.qh" + #include "../../common/deathtypes.qh" + #include "../mutators/mutators_include.qh" - #include "../vehicles/vehicles_def.qh" ++ #include "../../common/vehicles/sv_vehicles.qh" + #include "../campaign.qh" + #include "../../common/mapinfo.qh" + #include "common.qh" + #include "vote.qh" + #include "cmd.qh" + #include "../cheats.qh" + #include "../scores.qh" + #include "../ipban.qh" + #endif + // ========================================================= // Server side networked commands code, reworked by Samual // Last updated: December 28th, 2011 diff --cc qcsrc/server/g_damage.qc index 4304401d55,d170cf4c02..913f3dd23d --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@@ -1,7 -1,31 +1,31 @@@ - .float dmg; - .float dmg_edge; - .float dmg_force; - .float dmg_radius; + #include "g_damage.qh" + + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../warpzonelib/common.qh" + #include "../common/constants.qh" + #include "../common/teams.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "weapons/accuracy.qh" + #include "weapons/csqcprojectile.qh" + #include "weapons/selection.qh" + #include "t_items.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/notifications.qh" + #include "../common/deathtypes.qh" + #include "mutators/mutators_include.qh" + #include "tturrets/include/turrets_early.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #include "../csqcmodellib/sv_model.qh" + #include "../common/playerstats.qh" + #include "g_hook.qh" + #include "scores.qh" + #include "spawnpoints.qh" + #endif float Damage_DamageInfo_SendEntity(entity to, float sf) { diff --cc qcsrc/server/g_damage.qh index 0000000000,4cc3f6f63e..a82a67506a mode 000000,100644..100644 --- a/qcsrc/server/g_damage.qh +++ b/qcsrc/server/g_damage.qh @@@ -1,0 -1,123 +1,123 @@@ + #ifndef G_DAMAGE_H + #define G_DAMAGE_H + + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" + #include "../warpzonelib/common.qh" + #include "../common/constants.qh" + #include "../common/teams.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "weapons/accuracy.qh" + #include "weapons/csqcprojectile.qh" + #include "weapons/selection.qh" + #include "t_items.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/notifications.qh" + #include "../common/deathtypes.qh" + #include "mutators/mutators_include.qh" + #include "tturrets/include/turrets_early.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #include "../csqcmodellib/sv_model.qh" + #include "../common/playerstats.qh" + #include "g_hook.qh" + #include "scores.qh" + #include "spawnpoints.qh" + #endif + + .float dmg; + .float dmg_edge; + .float dmg_force; + .float dmg_radius; + + float Damage_DamageInfo_SendEntity(entity to, float sf); + + void Damage_DamageInfo(vector org, float coredamage, float edgedamage, float rad, vector force, float deathtype, float bloodtype, entity dmgowner); + + float checkrules_firstblood; + + float yoda; + float damage_goodhits; + float damage_gooddamage; + + .float dmg_team; + .float teamkill_complain; + .float teamkill_soundtime; + .entity teamkill_soundsource; + .entity pusher; + .float istypefrag; + .float taunt_soundtime; + + float IsFlying(entity a); + + void UpdateFrags(entity player, float f); + + // NOTE: f=0 means still count as a (positive) kill, but count no frags for it + void W_SwitchWeapon_Force(entity e, float w); + entity GiveFrags_randomweapons; + void GiveFrags (entity attacker, entity targ, float f, float deathtype); + + string AppendItemcodes(string s, entity player); + + void LogDeath(string mode, float deathtype, entity killer, entity killed); + + void Obituary_SpecialDeath( + entity notif_target, + float murder, + float deathtype, + string s1, string s2, string s3, + float f1, float f2, float f3); + + float w_deathtype; + float Obituary_WeaponDeath( + entity notif_target, + float murder, + float deathtype, + string s1, string s2, string s3, + float f1, float f2); + + void Obituary(entity attacker, entity inflictor, entity targ, float deathtype); + + void Ice_Think(); + + void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint); + + void Unfreeze (entity targ); + + // these are updated by each Damage call for use in button triggering and such + entity damage_targ; + entity damage_inflictor; + entity damage_attacker; + + void Damage (entity targ, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force); + + float RadiusDamage_running; + float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float deathtype, entity directhitentity); + // Returns total damage applies to creatures + + float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, float deathtype, entity directhitentity); + + .float fire_damagepersec; + .float fire_endtime; + .float fire_deathtype; + .entity fire_owner; + .float fire_hitsound; + .entity fire_burner; + + void fireburner_think(); + + float Fire_IsBurning(entity e); + + float Fire_AddDamage(entity e, entity o, float d, float t, float dt); + + void Fire_ApplyDamage(entity e); + + void Fire_ApplyEffect(entity e); + + void fireburner_think(); + #endif diff --cc qcsrc/server/g_hook.qc index 8dd22db1b3,310833e436..b5cb030d07 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@@ -1,3 -1,22 +1,22 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" + #include "../warpzonelib/common.qh" + #include "../warpzonelib/server.qh" + #include "../common/constants.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #include "command/common.qh" + #include "g_hook.qh" + #include "round_handler.qh" + #endif + /*============================================ Wazat's Xonotic Grappling Hook diff --cc qcsrc/server/g_world.qc index db13fbc443,0a2708340d..5c34419ca7 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@@ -1,4 -1,41 +1,42 @@@ - #define LATENCY_THINKRATE 10 + #include "g_world.qh" + + #include "../common/buffs.qh" + + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../common/constants.qh" + #include "../common/stats.qh" + #include "../common/teams.qh" + #include "../common/util.qh" + #include "../common/monsters/sv_monsters.qh" ++ #include "../common/vehicles/vehicles.qh" + #include "../common/weapons/weapons.qh" + #include "weapons/weaponstats.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/notifications.qh" + #include "mutators/mutators_include.qh" + #include "campaign.qh" + #include "../common/mapinfo.qh" + #include "command/common.qh" + #include "command/vote.qh" + #include "command/getreplies.qh" + #include "command/sv_cmd.qh" + #include "anticheat.qh" + #include "cheats.qh" + #include "../common/playerstats.qh" + #include "g_hook.qh" + #include "scores.qh" + #include "mapvoting.qh" + #include "ipban.qh" + #include "race.qh" + #include "antilag.qh" + #include "secret.qh" + #endif + + const float LATENCY_THINKRATE = 10; .float latency_sum; .float latency_cnt; .float latency_time; diff --cc qcsrc/server/mutators/mutator_nades.qc index 47ff68c2d5,3932ce407d..10f1aec26b --- a/qcsrc/server/mutators/mutator_nades.qc +++ b/qcsrc/server/mutators/mutator_nades.qc @@@ -831,24 -831,24 +831,24 @@@ void nade_prime( float CanThrowNade() { if(self.vehicle) - return FALSE; + return false; if(gameover) - return FALSE; + return false; if(self.deadflag != DEAD_NO) - return FALSE; + return false; if (!autocvar_g_nades) - return FALSE; // allow turning them off mid match + return false; // allow turning them off mid match - if(forbidWeaponUse()) + if(forbidWeaponUse(self)) - return FALSE; + return false; if (!IS_PLAYER(self)) - return FALSE; + return false; - return TRUE; + return true; } void nades_CheckThrow() diff --cc qcsrc/server/mutators/mutators_include.qc index 0f52e34f03,a0170e4803..88fdd239f1 --- a/qcsrc/server/mutators/mutators_include.qc +++ b/qcsrc/server/mutators/mutators_include.qc @@@ -1,3 -1,85 +1,84 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../../dpdefs/progsdefs.qh" + #include "../../dpdefs/dpextensions.qh" + #include "../../warpzonelib/anglestransform.qh" + #include "../../warpzonelib/mathlib.qh" + #include "../../warpzonelib/common.qh" + #include "../../warpzonelib/util_server.qh" + #include "../../warpzonelib/server.qh" + #include "../../common/constants.qh" + #include "../../common/stats.qh" + #include "../../common/teams.qh" + #include "../../common/util.qh" + #include "../../common/nades.qh" + #include "../../common/buffs.qh" + #include "../../common/test.qh" + #include "../../common/counting.qh" + #include "../../common/urllib.qh" + #include "../../common/command/markup.qh" + #include "../../common/command/rpn.qh" + #include "../../common/command/generic.qh" + #include "../../common/command/shared_defs.qh" + #include "../../common/net_notice.qh" + #include "../../common/animdecide.qh" + #include "../../common/monsters/monsters.qh" + #include "../../common/monsters/sv_monsters.qh" + #include "../../common/monsters/spawn.qh" + #include "../../common/weapons/config.qh" + #include "../../common/weapons/weapons.qh" + #include "../weapons/accuracy.qh" + #include "../weapons/common.qh" + #include "../weapons/csqcprojectile.qh" + #include "../weapons/hitplot.qh" + #include "../weapons/selection.qh" + #include "../weapons/spawning.qh" + #include "../weapons/throwing.qh" + #include "../weapons/tracing.qh" + #include "../weapons/weaponstats.qh" + #include "../weapons/weaponsystem.qh" + #include "../t_items.qh" + #include "../autocvars.qh" + #include "../constants.qh" + #include "../defs.qh" + #include "../../common/notifications.qh" + #include "../../common/deathtypes.qh" + #include "mutators_include.qh" + #include "../tturrets/include/turrets_early.qh" - #include "../vehicles/vehicles_def.qh" ++ #include "../../common/vehicles/sv_vehicles.qh" + #include "../campaign.qh" + #include "../../common/campaign_common.qh" + #include "../../common/mapinfo.qh" + #include "../command/common.qh" + #include "../command/banning.qh" + #include "../command/radarmap.qh" + #include "../command/vote.qh" + #include "../command/getreplies.qh" + #include "../command/cmd.qh" + #include "../command/sv_cmd.qh" + #include "../../common/csqcmodel_settings.qh" + #include "../../csqcmodellib/common.qh" + #include "../../csqcmodellib/sv_model.qh" + #include "../anticheat.qh" + #include "../cheats.qh" + #include "../../common/playerstats.qh" + #include "../portals.qh" + #include "../g_hook.qh" + #include "../scores.qh" + #include "../spawnpoints.qh" + #include "../mapvoting.qh" + #include "../ipban.qh" + #include "../race.qh" + #include "../antilag.qh" + #include "../playerdemo.qh" + #include "../round_handler.qh" + #include "../item_key.qh" + #include "../secret.qh" + #include "../pathlib/pathlib.qh" + #include "../tturrets/include/turrets.qh" - #include "../vehicles/vehicles.qh" + #endif + #include "base.qc" #include "gamemode_assault.qc" #include "gamemode_ca.qc" diff --cc qcsrc/server/progs.src index 48cceca20e,85e75cda9e..9160f6f0bd --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@@ -160,100 -83,32 +83,33 @@@ weapons/throwing.q weapons/tracing.qc weapons/weaponstats.qc weapons/weaponsystem.qc - ../common/weapons/config.qc - ../common/weapons/weapons.qc // TODO - t_items.qc - cl_impulse.qc - - ent_cs.qc - - cl_player.qc - cl_client.qc - t_plats.qc - antilag.qc - - //ctf.qc - //domination.qc - //mode_onslaught.qc - //nexball.qc - g_hook.qc - - t_swamp.qc - - campaign.qc + ../common/animdecide.qc + ../common/buffs.qc ../common/campaign_file.qc ../common/campaign_setup.qc - ../common/urllib.qc - + ../common/command/generic.qc ../common/command/markup.qc ../common/command/rpn.qc - ../common/command/generic.qc - ../common/net_notice.qc - - command/common.qc - command/banning.qc - command/radarmap.qc - command/vote.qc - command/getreplies.qc - command/cmd.qc - command/sv_cmd.qc - - //assault.qc - - ipban.qc - ../common/mapinfo.qc - - t_quake3.qc - t_halflife.qc - t_quake.qc - - race.qc - - - //// tZork Turrets //// - tturrets/include/turrets.qh - - scores.qc - - spawnpoints.qc - - portals.qc - - target_spawn.qc - func_breakable.qc - target_music.qc - - ../common/vehicles/vehicles_include.qc - - ../common/nades.qc - ../common/buffs.qc - - ../csqcmodellib/sv_model.qc - - playerdemo.qc - - anticheat.qc - cheats.qc - ../common/playerstats.qc - - round_handler.qc - - ../common/monsters/sv_monsters.qc ../common/monsters/monsters.qc - ../common/monsters/spawn.qc + ../common/monsters/sv_monsters.qc + ../common/nades.qc + ../common/net_notice.qc + ../common/notifications.qc + ../common/playerstats.qc + ../common/test.qc + ../common/urllib.qc + ../common/util.qc ++../common/vehicles/vehicles_include.qc + ../common/weapons/config.qc + ../common/weapons/weapons.qc // TODO - mutators/mutators_include.qc + ../csqcmodellib/sv_model.qc ../warpzonelib/anglestransform.qc - ../warpzonelib/mathlib.qc ../warpzonelib/common.qc - ../warpzonelib/util_server.qc + ../warpzonelib/mathlib.qc ../warpzonelib/server.qc - - ../common/animdecide.qc - ../common/test.qc - ../common/util.qc - ../common/notifications.qc + ../warpzonelib/util_server.qc diff --cc qcsrc/server/sv_main.qc index b25528e164,c2d3dc7dd8..249b673826 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@@ -1,3 -1,27 +1,27 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../dpdefs/dpextensions.qh" + #include "../warpzonelib/common.qh" + #include "../warpzonelib/server.qh" + #include "../common/constants.qh" + #include "../common/util.qh" + #include "../common/weapons/weapons.qh" + #include "weapons/csqcprojectile.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/deathtypes.qh" + #include "mutators/mutators_include.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #include "../common/mapinfo.qh" + #include "command/common.qh" + #include "../csqcmodellib/sv_model.qh" + #include "anticheat.qh" + #include "g_hook.qh" + #endif + void CreatureFrame (void) { entity oldself; diff --cc qcsrc/server/t_halflife.qc index bb2254c977,681c5dc7d3..a55fbacda1 --- a/qcsrc/server/t_halflife.qc +++ b/qcsrc/server/t_halflife.qc @@@ -1,3 -1,11 +1,11 @@@ + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../dpdefs/progsdefs.qh" + #include "../warpzonelib/util_server.qh" + #include "defs.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #endif .float roomtype; .float radius; diff --cc qcsrc/server/t_teleporters.qc index 543c1cf0bb,46df0eb786..09fdc9b17a --- a/qcsrc/server/t_teleporters.qc +++ b/qcsrc/server/t_teleporters.qc @@@ -1,3 -1,24 +1,24 @@@ + #include "t_teleporters.qh" + + #if defined(CSQC) + #elif defined(MENUQC) + #elif defined(SVQC) + #include "../warpzonelib/common.qh" + #include "../warpzonelib/util_server.qh" + #include "../warpzonelib/server.qh" + #include "../common/constants.qh" + #include "../common/util.qh" + #include "weapons/csqcprojectile.qh" + #include "autocvars.qh" + #include "constants.qh" + #include "defs.qh" + #include "../common/deathtypes.qh" + #include "tturrets/include/turrets_early.qh" - #include "vehicles/vehicles_def.qh" ++ #include "../common/vehicles/sv_vehicles.qh" + #include "../common/mapinfo.qh" + #include "anticheat.qh" + #endif + void trigger_teleport_use() { if(teamplay) diff --cc qcsrc/server/weapons/weaponsystem.qh index 03dd69bbeb,bb0cea798d..86e52c89bf --- a/qcsrc/server/weapons/weaponsystem.qh +++ b/qcsrc/server/weapons/weaponsystem.qh @@@ -1,6 -1,43 +1,43 @@@ - float weaponswapping; + #ifndef WEAPONSYSTEM_H + #define WEAPONSYSTEM_H + + .float wframe; + float internalteam; + float weaponswapping; + entity weapon_dropevent_item; - void W_DropEvent(float event, entity player, float weapon_type, entity weapon_item); + // VorteX: static frame globals + const float WFRAME_DONTCHANGE = -1; + const float WFRAME_FIRE1 = 0; + const float WFRAME_FIRE2 = 1; + const float WFRAME_IDLE = 2; + const float WFRAME_RELOAD = 3; + + void CL_SpawnWeaponentity(); + + vector CL_Weapon_GetShotOrg(float wpn); -float forbidWeaponUse(); +float forbidWeaponUse(entity player); + + void W_AttachToShotorg(entity flash, vector offset); + + void W_DecreaseAmmo(float ammo_use); + + void W_DropEvent(float event, entity player, float weapon_type, entity weapon_item); + + void W_Reload(float sent_ammo_min, string sent_sound); + + void W_WeaponFrame(); + + float W_WeaponRateFactor(); + + float weapon_prepareattack(float secondary, float attacktime); + + float weapon_prepareattack_check(float secondary, float attacktime); + + float weapon_prepareattack_do(float secondary, float attacktime); + + void weapon_thinkf(float fr, float t, void() func); + + #endif