From: Mario Date: Fri, 21 Aug 2015 08:55:37 +0000 (+1000) Subject: Merge branch 'master' into Mario/vehicles X-Git-Tag: xonotic-v0.8.2~2059^2~1 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=ae2c1407ec9a05e4f501a6604a7cce8e1030df9f;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into Mario/vehicles # Conflicts: # qcsrc/client/autocvars.qh # qcsrc/client/main.qc # qcsrc/client/tturrets.qc # qcsrc/client/vehicles/all.qc # qcsrc/server/g_world.qc # qcsrc/server/vehicles/bumblebee.qc # qcsrc/server/vehicles/racer.qc # qcsrc/server/vehicles/raptor.qc # qcsrc/server/vehicles/spiderbot.qc # qcsrc/server/vehicles/vehicle.qc # qcsrc/server/vehicles/vehicle.qh --- ae2c1407ec9a05e4f501a6604a7cce8e1030df9f diff --cc qcsrc/client/autocvars.qh index 94e7c6359,1e6d7444a..9c1a679cf --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@@ -77,6 -77,9 +77,12 @@@ bool autocvar_cl_spawnzoom = 1 float autocvar_cl_spawnzoom_speed = 1; float autocvar_cl_spawnzoom_factor = 2; bool autocvar_cl_stripcolorcodes; ++bool autocvar_cl_vehicles_alarm = true; + bool autocvar_cl_vehicles_hud_tactical = 1; + float autocvar_cl_vehicles_hudscale = 0.5; ++float autocvar_cl_vehicles_notify_time = 15; + float autocvar_cl_vehicles_crosshair_size = 0.5; ++bool autocvar__vehicles_shownchasemessage; bool autocvar_cl_velocityzoom_enabled; float autocvar_cl_velocityzoom_factor; int autocvar_cl_velocityzoom_type = 3; @@@ -423,6 -434,6 +437,9 @@@ float autocvar_vid_conheight float autocvar_vid_conwidth; float autocvar_vid_pixelheight; float autocvar_viewsize; ++bool autocvar_cl_eventchase_vehicle = 1; ++vector autocvar_cl_eventchase_vehicle_viewoffset = '0 0 80'; ++float autocvar_cl_eventchase_vehicle_distance = 250; int autocvar_cl_hitsound; float autocvar_cl_hitsound_min_pitch = 0.75; float autocvar_cl_hitsound_max_pitch = 1.5; diff --cc qcsrc/client/main.qc index a9963041e,87027c346..231dd6867 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@@ -146,7 -147,7 +148,8 @@@ void CSQC_Init(void CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); - CALL_ACCUMULATED_FUNCTION(RegisterBuffs); + CALL_ACCUMULATED_FUNCTION(RegisterEffects); ++ CALL_ACCUMULATED_FUNCTION(RegisterVehicles); WaypointSprite_Load(); diff --cc qcsrc/client/tturrets.qc index 8951b7233,c87418ea4..6fe073e27 --- a/qcsrc/client/tturrets.qc +++ b/qcsrc/client/tturrets.qc @@@ -278,14 -278,22 +278,14 @@@ void turret_draw2d( return; // Dont draw wp's for turrets out of view 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/turret_moving.tga"; - else - txt = "gfx/vehicles/turret_stationary.tga"; - - vector pz = drawgetimagesize(txt) * autocvar_cl_vehicles_crosshair_size; - drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.7, 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); ++ vector pz = drawgetimagesize(txt) * autocvar_cl_vehicles_crosshair_size; ++ drawpic(o - pz * 0.5, txt, pz , '1 1 1', 0.7, DRAWFLAG_NORMAL); } } diff --cc qcsrc/client/view.qc index 0e028bdae,2d4bff52a..67bcf4224 --- a/qcsrc/client/view.qc +++ b/qcsrc/client/view.qc @@@ -426,9 -435,11 +432,13 @@@ bool WantEventchase( return false; if(intermission) return true; + if(self.viewloc) + return true; if(spectatee_status >= 0) { - if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO))) ++ if(hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0)) ++ return true; + if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO.m_id))) return true; if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0)) { @@@ -996,6 -1007,6 +1006,8 @@@ const int BUTTON_3 = 4 const int BUTTON_4 = 8; float cl_notice_run(); float prev_myteam; ++int lasthud; ++float vh_notice_time; void CSQC_UpdateView(float w, float h) { entity e; @@@ -1011,6 -1022,6 +1023,11 @@@ hud = getstati(STAT_HUD); ++ if(hud != HUD_NORMAL && lasthud == HUD_NORMAL) ++ vh_notice_time = time + autocvar_cl_vehicles_notify_time; ++ ++ lasthud = hud; ++ if(autocvar__hud_showbinds_reload) // menu can set this one { db_close(binddb); @@@ -1087,6 -1102,6 +1108,7 @@@ // event chase camera if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped { ++ float vehicle_chase = (hud != HUD_NORMAL && (autocvar_cl_eventchase_vehicle || spectatee_status > 0)); if(WantEventchase()) { eventchase_running = true; @@@ -1095,10 -1110,10 +1117,13 @@@ vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org); // detect maximum viewoffset and use it -- if(autocvar_cl_eventchase_viewoffset) ++ vector view_offset = autocvar_cl_eventchase_viewoffset; ++ if(vehicle_chase && autocvar_cl_eventchase_vehicle_viewoffset) { view_offset = autocvar_cl_eventchase_vehicle_viewoffset; } ++ ++ if(view_offset) { -- 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; } ++ WarpZone_TraceLine(current_view_origin, current_view_origin + view_offset + ('0 0 1' * autocvar_cl_eventchase_maxs.z), MOVE_WORLDONLY, self); ++ if(trace_fraction == 1) { current_view_origin += view_offset; } else { current_view_origin.z += max(0, (trace_endpos.z - current_view_origin.z) - autocvar_cl_eventchase_maxs.z); } } @@@ -1108,10 -1123,10 +1133,13 @@@ 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; ++ float chase_distance = autocvar_cl_eventchase_distance; ++ if(vehicle_chase && autocvar_cl_eventchase_vehicle_distance) { chase_distance = autocvar_cl_eventchase_vehicle_distance; } ++ ++ if(autocvar_cl_eventchase_speed && eventchase_current_distance < chase_distance) ++ eventchase_current_distance += autocvar_cl_eventchase_speed * (chase_distance - eventchase_current_distance) * frametime; // slow down the further we get ++ else if(eventchase_current_distance != chase_distance) ++ eventchase_current_distance = chase_distance; makevectors(view_angles); diff --cc qcsrc/common/vehicles/all.qh index 45e18b732,000000000..48ff80418 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/all.qh +++ b/qcsrc/common/vehicles/all.qh @@@ -1,6 -1,0 +1,10 @@@ - #include "unit/spiderbot.qc" - #include "unit/raptor.qc" - #include "unit/racer.qc" - #ifndef VEHICLES_NO_UNSTABLE - #include "unit/bumblebee.qc" - #endif ++#if defined(SVQC) ++ #include "sv_vehicles.qh" ++#elif defined(CSQC) ++ #include "cl_vehicles.qh" ++#endif ++ ++# ifndef VEHICLES_NO_UNSTABLE ++# include "unit/bumblebee.qh" ++# include "unit/raptor.qh" ++# endif diff --cc qcsrc/common/vehicles/cl_vehicles.qc index 4edaff91b,000000000..65f050f3b mode 100644,000000..100644 --- a/qcsrc/common/vehicles/cl_vehicles.qc +++ b/qcsrc/common/vehicles/cl_vehicles.qc @@@ -1,125 -1,0 +1,379 @@@ - const string hud_bg = "gfx/vehicles/frame.tga"; - const string hud_sh = "gfx/vehicles/vh-shield.tga"; - - const string hud_hp_bar = "gfx/vehicles/bar_up_left.tga"; - const string hud_hp_ico = "gfx/vehicles/health.tga"; - const string hud_sh_bar = "gfx/vehicles/bar_dwn_left.tga"; - const string hud_sh_ico = "gfx/vehicles/shield.tga"; - - const string hud_ammo1_bar = "gfx/vehicles/bar_up_right.tga"; - const string hud_ammo1_ico = "gfx/vehicles/bullets.tga"; - const string hud_ammo2_bar = "gfx/vehicles/bar_dwn_right.tga"; - const string hud_ammo2_ico = "gfx/vehicles/rocket.tga"; - const string hud_energy = "gfx/vehicles/energy.tga"; ++const string vCROSS_BURST = "gfx/vehicles/crosshair_burst.tga"; ++const string vCROSS_DROP = "gfx/vehicles/crosshair_drop.tga"; ++const string vCROSS_GUIDE = "gfx/vehicles/crosshair_guide.tga"; ++const string vCROSS_HEAL = "gfx/vehicles/crosshair_heal.tga"; ++const string vCROSS_HINT = "gfx/vehicles/crosshair_hint.tga"; ++const string vCROSS_LOCK = "gfx/vehicles/crosshair_lock.tga"; ++const string vCROSS_RAIN = "gfx/vehicles/crosshair_rain.tga"; ++const string vCROSS_TANK = "gfx/vehicles/crosshair_tank.tga"; ++const string vCROSS_TANK2 = "gfx/vehicles/crosshair_tank2.tga"; + +entity dropmark; - float autocvar_cl_vehicles_hudscale = 0.5; - float autocvar_cl_vehicles_hudalpha = 0.75; + +const int MAX_AXH = 4; +entity AuxiliaryXhair[MAX_AXH]; + +.string axh_image; +.float axh_fadetime; +.int axh_drawflag; - .float axh_scale; + +float alarm1time; +float alarm2time; + +void vehicle_alarm(entity e, int ch, string s0und) +{ + if(!autocvar_cl_vehicles_alarm) + return; + + sound(e, ch, s0und, VOL_BASEVOICE, ATTEN_NONE); +} + +void AuxiliaryXhair_Draw2D() +{ - vector loc, psize; ++ if (scoreboard_showscores) ++ return; + - psize = self.axh_scale * draw_getimagesize(self.axh_image); - loc = project_3d_to_2d(self.move_origin) - 0.5 * psize; - if(!(loc_z < 0 || loc_x < 0 || loc_y < 0 || loc_x > vid_conwidth || loc_y > vid_conheight)) ++ vector size = draw_getimagesize(self.axh_image) * autocvar_cl_vehicles_crosshair_size; ++ vector pos = project_3d_to_2d(self.move_origin) - 0.5 * size; ++ ++ if (!(pos.z < 0 || pos.x < 0 || pos.y < 0 || pos.x > vid_conwidth || pos.y > vid_conheight)) + { - loc_z = 0; - psize_z = 0; - drawpic(loc, self.axh_image, psize, self.colormod, self.alpha, self.axh_drawflag); ++ pos.z = 0; ++ size.z = 0; ++ drawpic(pos, self.axh_image, size, self.colormod, autocvar_crosshair_alpha * self.alpha, self.axh_drawflag); + } + + if(time - self.cnt > self.axh_fadetime) + self.draw2d = func_null; +} + +void Net_AuXair2(bool bIsNew) +{ + int axh_id = bound(0, ReadByte(), MAX_AXH); + entity axh = AuxiliaryXhair[axh_id]; + + if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) + { + axh = spawn(); + axh.draw2d = func_null; + axh.drawmask = MASK_NORMAL; + axh.axh_drawflag = DRAWFLAG_ADDITIVE; + axh.axh_fadetime = 0.1; - axh.axh_image = "gfx/vehicles/axh-ring.tga"; - axh.axh_scale = 1; ++ axh.axh_image = vCROSS_HINT; + axh.alpha = 1; + AuxiliaryXhair[axh_id] = axh; + } + + axh.move_origin_x = ReadCoord(); + axh.move_origin_y = ReadCoord(); + axh.move_origin_z = ReadCoord(); + axh.colormod_x = ReadByte() / 255; + axh.colormod_y = ReadByte() / 255; + axh.colormod_z = ReadByte() / 255; + axh.cnt = time; + axh.draw2d = AuxiliaryXhair_Draw2D; +} + +void Net_VehicleSetup() +{ - int i; + int hud_id = ReadByte(); + + // hud_id == 0 means we exited a vehicle, so stop alarm sound/s + if(hud_id == 0) + { + sound(self, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE); + sound(self, CH_PAIN_SINGLE, "misc/null.wav", VOL_BASEVOICE, ATTEN_NONE); + return; + } + + // Init auxiliary crosshairs - entity axh; - for(i = 0; i < MAX_AXH; ++i) ++ for(int i = 0; i < MAX_AXH; ++i) + { - axh = AuxiliaryXhair[i]; ++ entity axh = AuxiliaryXhair[i]; ++ + if(axh != world && !wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) + remove(axh); + - axh = spawn(); - axh.draw2d = func_null; - axh.drawmask = MASK_NORMAL; - axh.axh_drawflag = DRAWFLAG_NORMAL; - axh.axh_fadetime = 0.1; - axh.axh_image = "gfx/vehicles/axh-ring.tga"; - axh.axh_scale = 1; - axh.alpha = 1; - AuxiliaryXhair[i] = axh; ++ axh = spawn(); ++ axh.draw2d = func_null; ++ axh.drawmask = MASK_NORMAL; ++ axh.axh_drawflag = DRAWFLAG_NORMAL; ++ axh.axh_fadetime = 0.1; ++ axh.axh_image = vCROSS_HINT; ++ axh.alpha = 1; ++ AuxiliaryXhair[i] = axh; + } + + if(hud_id == HUD_BUMBLEBEE_GUN) + { - // Plasma cannons - AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga"; - AuxiliaryXhair[0].axh_scale = 0.25; - // Raygun - AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-bracket.tga"; - AuxiliaryXhair[1].axh_scale = 0.25; ++ AuxiliaryXhair[0].axh_image = vCROSS_BURST; // Plasma cannons ++ AuxiliaryXhair[1].axh_image = vCROSS_BURST; // Raygun + } + else { VEH_ACTION(hud_id, VR_SETUP); } +} ++ ++void Vehicles_drawHUD( ++ string vehicle, ++ string vehicleWeapon1, ++ string vehicleWeapon2, ++ string iconAmmo1, ++ vector colorAmmo1, ++ string iconAmmo2, ++ vector colorAmmo2, ++ string crosshair) ++{ ++ if(autocvar_r_letterbox) ++ return; ++ ++ if(scoreboard_showscores) ++ return; ++ ++ // Initialize ++ vector hudSize = '0 0 0'; ++ vector hudPos = '0 0 0'; ++ vector tmpSize = '0 0 0'; ++ vector tmpPos = '0 0 0'; ++ ++ float hudAlpha = autocvar_hud_panel_fg_alpha; ++ float barAlpha = autocvar_hud_progressbar_alpha * hudAlpha; ++ float blinkValue = 0.55 + sin(time * 7) * 0.45; ++ ++ float health = getstati(STAT_VEHICLESTAT_HEALTH) * 0.01; ++ float shield = getstati(STAT_VEHICLESTAT_SHIELD) * 0.01; ++ float energy = getstati(STAT_VEHICLESTAT_ENERGY) * 0.01; ++ float ammo1 = getstati(STAT_VEHICLESTAT_AMMO1) * 0.01; ++ float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1) * 0.01; ++ float ammo2 = getstati(STAT_VEHICLESTAT_AMMO2) * 0.01; ++ float reload2 = getstati(STAT_VEHICLESTAT_RELOAD2) * 0.01; ++ ++ // HACK to deal with the inconsistent use of the vehicle stats ++ ammo1 = (ammo1) ? ammo1 : energy; ++ ++ // Frame ++ string frame = strcat(hud_skin_path, "/vehicle_frame"); ++ if (precache_pic(frame) == "") ++ frame = "gfx/hud/default/vehicle_frame"; ++ ++ hudSize = draw_getimagesize(frame) * autocvar_cl_vehicles_hudscale; ++ hudPos.x = (vid_conwidth - hudSize.x) / 2; ++ hudPos.y = vid_conheight - hudSize.y; ++ ++ if(teamplay && autocvar_hud_panel_bg_color_team) ++ drawpic(hudPos, frame, hudSize, myteamcolors * autocvar_hud_panel_bg_color_team, autocvar_hud_panel_bg_alpha, DRAWFLAG_NORMAL); ++ else ++ drawpic(hudPos, frame, hudSize, autocvar_hud_panel_bg_color, autocvar_hud_panel_bg_alpha, DRAWFLAG_NORMAL); ++ ++ if(!autocvar__vehicles_shownchasemessage && time < vh_notice_time) ++ { ++ float tmpblinkValue = 0.55 + sin(time * 3) * 0.45; ++ tmpPos.x = hudPos.x + hudSize.x * (96/256) - tmpSize.x; ++ tmpPos.y = hudPos.y; ++ tmpSize = '1 1 1' * hud_fontsize; ++ drawstring(tmpPos, sprintf(_("Press %s"), getcommandkey("dropweapon", "dropweapon")), tmpSize, '1 0 0' + '0 1 1' * tmpblinkValue, hudAlpha, DRAWFLAG_NORMAL); ++ } ++ ++ // Model ++ tmpSize.x = hudSize.x / 3; ++ tmpSize.y = hudSize.y; ++ tmpPos.x = hudPos.x + hudSize.x / 3; ++ tmpPos.y = hudPos.y; ++ ++ if(health < 0.25) ++ drawpic_skin(tmpPos, vehicle, tmpSize, '1 0 0' + '0 1 1' * blinkValue, hudAlpha, DRAWFLAG_NORMAL); ++ else ++ drawpic_skin(tmpPos, vehicle, tmpSize, '1 1 1' * health + '1 0 0' * (1 - health), hudAlpha, DRAWFLAG_NORMAL); ++ ++ if(vehicleWeapon1) ++ drawpic_skin(tmpPos, vehicleWeapon1, tmpSize, '1 1 1' * ammo1 + '1 0 0' * (1 - ammo1), hudAlpha, DRAWFLAG_NORMAL); ++ if(vehicleWeapon2) ++ drawpic_skin(tmpPos, vehicleWeapon2, tmpSize, '1 1 1' * ammo2 + '1 0 0' * (1 - ammo2), hudAlpha, DRAWFLAG_NORMAL); ++ ++ drawpic_skin(tmpPos, "vehicle_shield", tmpSize, '1 1 1' * shield + '1 0 0' * (1 - shield), hudAlpha * shield, DRAWFLAG_NORMAL); ++ ++ // Health bar ++ tmpSize.y = hudSize.y / 2; ++ tmpPos.x = hudPos.x + hudSize.x * (32/768); ++ tmpPos.y = hudPos.y; ++ ++ drawsetcliparea(tmpPos.x + (tmpSize.x * (1 - health)), tmpPos.y, tmpSize.x, tmpSize.y); ++ drawpic_skin(tmpPos, "vehicle_bar_northwest", tmpSize, autocvar_hud_progressbar_health_color, barAlpha, DRAWFLAG_NORMAL); ++ ++ // Shield bar ++ tmpPos.y = hudPos.y + hudSize.y / 2; ++ ++ drawsetcliparea(tmpPos.x + (tmpSize.x * (1 - shield)), tmpPos.y, tmpSize.x, tmpSize.y); ++ drawpic_skin(tmpPos, "vehicle_bar_southwest", tmpSize, autocvar_hud_progressbar_armor_color, barAlpha, DRAWFLAG_NORMAL); ++ ++ // Ammo1 bar ++ tmpPos.x = hudPos.x + hudSize.x * (480/768); ++ tmpPos.y = hudPos.y; ++ ++ if(ammo1) ++ drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * ammo1, tmpSize.y); ++ else ++ drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * reload1, tmpSize.y); ++ ++ drawpic_skin(tmpPos, "vehicle_bar_northeast", tmpSize, colorAmmo1, barAlpha, DRAWFLAG_NORMAL); ++ ++ // Ammo2 bar ++ tmpPos.y = hudPos.y + hudSize.y / 2; ++ ++ if(ammo2) ++ drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * ammo2, tmpSize.y); ++ else ++ drawsetcliparea(tmpPos.x, tmpPos.y, tmpSize.x * reload2, tmpSize.y); ++ ++ drawpic_skin(tmpPos, "vehicle_bar_southeast", tmpSize, colorAmmo2, barAlpha, DRAWFLAG_NORMAL); ++ drawresetcliparea(); ++ ++ // Health icon ++ tmpSize.x = hudSize.x * (80/768); ++ tmpSize.y = hudSize.y * (80/256); ++ tmpPos.x = hudPos.x + hudSize.x * (64/768); ++ tmpPos.y = hudPos.y + hudSize.y * (48/256); ++ ++ if(health < 0.25) ++ { ++ if(alarm1time < time) ++ { ++ alarm1time = time + 2; ++ vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav"); ++ } ++ drawpic_skin(tmpPos, "vehicle_icon_health", tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL); ++ } ++ else ++ { ++ if(alarm1time) ++ { ++ vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav"); ++ alarm1time = 0; ++ } ++ drawpic_skin(tmpPos, "vehicle_icon_health", tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL); ++ } ++ ++ // Shield icon ++ tmpPos.y = hudPos.y + hudSize.y / 2; ++ ++ if(shield < 0.25) ++ { ++ if(alarm2time < time) ++ { ++ alarm2time = time + 1; ++ vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav"); ++ } ++ drawpic_skin(tmpPos, "vehicle_icon_shield", tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL); ++ } ++ else ++ { ++ if(alarm2time) ++ { ++ vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav"); ++ alarm2time = 0; ++ } ++ drawpic_skin(tmpPos, "vehicle_icon_shield", tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL); ++ } ++ ++ // Ammo1 icon ++ tmpPos.x = hudPos.x + hudSize.x * (624/768); ++ tmpPos.y = hudPos.y + hudSize.y * (48/256); ++ ++ if(iconAmmo1) ++ { ++ if(ammo1) ++ drawpic_skin(tmpPos, iconAmmo1, tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL); ++ else ++ drawpic_skin(tmpPos, iconAmmo1, tmpSize, '1 1 1', hudAlpha * 0.2, DRAWFLAG_NORMAL); ++ } ++ ++ // Ammo2 icon ++ tmpPos.y = hudPos.y + hudSize.y / 2; ++ ++ if(iconAmmo2) ++ { ++ if(ammo2) ++ drawpic_skin(tmpPos, iconAmmo2, tmpSize, '1 1 1', hudAlpha, DRAWFLAG_NORMAL); ++ else ++ drawpic_skin(tmpPos, iconAmmo2, tmpSize, '1 1 1', hudAlpha * 0.2, DRAWFLAG_NORMAL); ++ } ++ ++ // Bumblebee gunner crosshairs ++ if(hud == VEH_BUMBLEBEE) ++ { ++ tmpSize = '1 1 1' * hud_fontsize; ++ tmpPos.x = hudPos.x + hudSize.x * (520/768); ++ ++ if(!AuxiliaryXhair[1].draw2d) ++ { ++ tmpPos.y = hudPos.y + hudSize.y * (96/256) - tmpSize.y; ++ drawstring(tmpPos, _("No right gunner!"), tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL); ++ } ++ ++ if(!AuxiliaryXhair[2].draw2d) ++ { ++ tmpPos.y = hudPos.y + hudSize.y * (160/256); ++ drawstring(tmpPos, _("No left gunner!"), tmpSize, '1 1 1', hudAlpha * blinkValue, DRAWFLAG_NORMAL); ++ } ++ } ++ ++ // Raptor bomb crosshair ++ if(hud == VEH_RAPTOR && weapon2mode != RSM_FLARE) ++ { ++ vector where; ++ ++ if(!dropmark) ++ { ++ dropmark = spawn(); ++ dropmark.owner = self; ++ dropmark.gravity = 1; ++ } ++ ++ if(reload2 == 1) ++ { ++ setorigin(dropmark, pmove_org); ++ dropmark.velocity = pmove_vel; ++ tracetoss(dropmark, self); ++ ++ where = project_3d_to_2d(trace_endpos); ++ ++ setorigin(dropmark, trace_endpos); ++ tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size; ++ ++ if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight)) ++ { ++ where.x -= tmpSize.x * 0.5; ++ where.y -= tmpSize.y * 0.5; ++ where.z = 0; ++ drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE); ++ drawpic(where, vCROSS_DROP, tmpSize, '0 1 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg ++ } ++ dropmark.cnt = time + 5; ++ } ++ else ++ { ++ if(dropmark.cnt > time) ++ { ++ where = project_3d_to_2d(dropmark.origin); ++ tmpSize = draw_getimagesize(vCROSS_DROP) * autocvar_cl_vehicles_crosshair_size * 1.25; ++ ++ if (!(where.z < 0 || where.x < 0 || where.y < 0 || where.x > vid_conwidth || where.y > vid_conheight)) ++ { ++ where.x -= tmpSize.x * 0.5; ++ where.y -= tmpSize.y * 0.5; ++ where.z = 0; ++ drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.9, DRAWFLAG_ADDITIVE); ++ drawpic(where, vCROSS_DROP, tmpSize, '1 0 0', autocvar_crosshair_alpha * 0.6, DRAWFLAG_NORMAL); // Ensure visibility against bright bg ++ } ++ } ++ } ++ } ++ ++ // Crosshair ++ if(crosshair) ++ { ++ tmpSize = draw_getimagesize(crosshair) * autocvar_cl_vehicles_crosshair_size; ++ tmpPos.x = (vid_conwidth - tmpSize.x) / 2; ++ tmpPos.y = (vid_conheight - tmpSize.y) / 2; ++ ++ drawpic(tmpPos, crosshair, tmpSize, '1 1 1', autocvar_crosshair_alpha, DRAWFLAG_NORMAL); ++ } ++} diff --cc qcsrc/common/vehicles/cl_vehicles.qh index f91add3f1,000000000..a495f0367 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/cl_vehicles.qh +++ b/qcsrc/common/vehicles/cl_vehicles.qh @@@ -1,24 -1,0 +1,13 @@@ +#ifndef CL_VEHICLES_H +#define CL_VEHICLES_H + - // vehicle cvars - bool autocvar_cl_vehicles_alarm = 1; - bool autocvar_cl_vehicles_hud_tactical = 1; - +void Net_AuXair2(float bIsNew); + +void Net_VehicleSetup(); + +void RaptorCBShellfragDraw(); +void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang); + - #define HUD_GETVEHICLESTATS \ - int vh_health = getstati(STAT_VEHICLESTAT_HEALTH); \ - float shield = getstati(STAT_VEHICLESTAT_SHIELD); \ - noref int energy = getstati(STAT_VEHICLESTAT_ENERGY); \ - noref float ammo1 = getstati(STAT_VEHICLESTAT_AMMO1); \ - noref float reload1 = getstati(STAT_VEHICLESTAT_RELOAD1); \ - noref int ammo2 = getstati(STAT_VEHICLESTAT_AMMO2); \ - noref int reload2 = getstati(STAT_VEHICLESTAT_RELOAD2); ++#define weapon2mode getstati(STAT_VEHICLESTAT_W2MODE) + +#endif diff --cc qcsrc/common/vehicles/sv_vehicles.qc index 58d2dd47c,000000000..b06596bbc mode 100644,000000..100644 --- a/qcsrc/common/vehicles/sv_vehicles.qc +++ b/qcsrc/common/vehicles/sv_vehicles.qc @@@ -1,1254 -1,0 +1,1303 @@@ ++#include "../effects.qh" +#include "vehicles.qh" +#include "sv_vehicles.qh" + - float SendAuxiliaryXhair(entity to, float sf) ++#if 0 ++bool vehicle_send(entity to, int sf) ++{ ++ WriteByte(MSG_ENTITY, ENT_CLIENT_VEHICLE); ++ WriteByte(MSG_ENTITY, sf); ++ ++ if(sf & VSF_SPAWN) ++ { ++ WriteByte(MSG_ENTITY, self.vehicleid); ++ } ++ ++ if(sf & VSF_SETUP) ++ { ++ // send stuff? ++ } ++ ++ if(sf & VSF_ENTER) ++ { ++ // player handles the .vehicle stuff, we need only set ourselves up for driving ++ ++ // send stuff? ++ } ++ ++ if(sf & VSF_EXIT) ++ { ++ // senf stuff? ++ } ++ ++ if(sf & VSF_PRECACHE) ++ { ++ // send stuff?! ++ } ++ ++ return true; ++} ++#endif ++ ++bool SendAuxiliaryXhair(entity to, int sf) +{ + + WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR); + + WriteByte(MSG_ENTITY, self.cnt); + + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteByte(MSG_ENTITY, rint(self.colormod_x * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod_y * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod_z * 255)); + + return true; +} + +void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id) +{ + if(!IS_REAL_CLIENT(own)) + return; + + entity axh; + + axh_id = bound(0, axh_id, MAX_AXH); + axh = own.(AuxiliaryXhair[axh_id]); + + if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) + { + axh = spawn(); + axh.cnt = axh_id; + axh.drawonlytoclient = own; + axh.owner = own; + Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair); + } + + setorigin(axh, loc); + axh.colormod = clr; + axh.SendFlags = 0x01; + own.(AuxiliaryXhair[axh_id]) = axh; +} + +void CSQCVehicleSetup(entity own, int vehicle_id) +{ + if(!IS_REAL_CLIENT(own)) + return; + + msg_entity = own; + + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP); + WriteByte(MSG_ONE, vehicle_id); +} + +vector targetdrone_getnewspot() +{ + vector spot; + int i; + for(i = 0; i < 100; ++i) + { + spot = self.origin + randomvec() * 1024; + tracebox(spot, self.mins, self.maxs, spot, MOVE_NORMAL, self); + if(trace_fraction == 1.0 && trace_startsolid == 0 && trace_allsolid == 0) + return spot; + } + return self.origin; +} + +void vehicles_locktarget(float incr, float decr, float _lock_time) +{ + if(self.lock_target && self.lock_target.deadflag != DEAD_NO) + { + self.lock_target = world; + self.lock_strength = 0; + self.lock_time = 0; + } + + if(self.lock_time > time) + { + if(self.lock_target) + if(self.lock_soundtime < time) + { + self.lock_soundtime = time + 0.5; + play2(self.owner, "vehicles/locked.wav"); + } + + return; + } + + if(trace_ent != world) + { + if(SAME_TEAM(trace_ent, self)) + trace_ent = world; + + if(trace_ent.deadflag != DEAD_NO) + trace_ent = world; + - if(!((trace_ent.vehicle_flags & VHF_ISVEHICLE) || (trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET))) ++ if(!(IS_VEHICLE(trace_ent) || IS_TURRET(trace_ent))) + trace_ent = world; + + if(trace_ent.alpha <= 0.5 && trace_ent.alpha != 0) + trace_ent = world; // invisible + } + + if(self.lock_target == world && trace_ent != world) + self.lock_target = trace_ent; + + if(self.lock_target && trace_ent == self.lock_target) + { + if(self.lock_strength != 1 && self.lock_strength + incr >= 1) + { + play2(self.owner, "vehicles/lock.wav"); + self.lock_soundtime = time + 0.8; + } + else if (self.lock_strength != 1 && self.lock_soundtime < time) + { + play2(self.owner, "vehicles/locking.wav"); + self.lock_soundtime = time + 0.3; + } + } + + // Have a locking target + // Trace hit current target + if(trace_ent == self.lock_target && trace_ent != world) + { + self.lock_strength = min(self.lock_strength + incr, 1); + if(self.lock_strength == 1) + self.lock_time = time + _lock_time; + } + else + { + if(trace_ent) + self.lock_strength = max(self.lock_strength - decr * 2, 0); + else + self.lock_strength = max(self.lock_strength - decr, 0); + + if(self.lock_strength == 0) + self.lock_target = world; + } +} + +vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power) +{ + force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name)); + v_forward = normalize(v_forward) * -1; + traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self); + + force_fromtag_power = (1 - trace_fraction) * max_power; + force_fromtag_normpower = force_fromtag_power / max_power; + + return v_forward * force_fromtag_power; +} + +vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power) +{ + + force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name)); + v_forward = normalize(v_forward) * -1; + traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self); + + // TODO - this may NOT be compatible with wall/celing movement, unhardcode 0.25 (engine count multiplier) + if(trace_fraction == 1.0) + { + force_fromtag_normpower = -0.25; + return '0 0 -200'; + } + + force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power; + force_fromtag_normpower = force_fromtag_power / max_power; + + return v_forward * force_fromtag_power; +} + +// projectile handling +void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + // Ignore damage from oterh projectiles from my owner (dont mess up volly's) + if(inflictor.owner == self.owner) + return; + + self.health -= damage; + self.velocity += force; + if(self.health < 1) + { + self.takedamage = DAMAGE_NO; + self.event_damage = func_null; + self.think = self.use; + self.nextthink = time; + } +} + +void vehicles_projectile_explode() +{ + if(self.owner && other != world) + { + if(other == self.owner.vehicle) + return; + + if(other == self.owner.vehicle.tur_head) + return; + } + + PROJECTILE_TOUCH; + + self.event_damage = func_null; + RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other); + + remove (self); +} + +entity vehicles_projectile(string _mzlfx, string _mzlsound, + vector _org, vector _vel, + float _dmg, float _radi, float _force, float _size, + int _deahtype, float _projtype, float _health, + bool _cull, bool _clianim, entity _owner) +{ + entity proj; + + proj = spawn(); + + PROJECTILE_MAKETRIGGER(proj); + setorigin(proj, _org); + + proj.shot_dmg = _dmg; + proj.shot_radius = _radi; + proj.shot_force = _force; + proj.totalfrags = _deahtype; + proj.solid = SOLID_BBOX; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.flags = FL_PROJECTILE; + proj.bot_dodge = true; + proj.bot_dodgerating = _dmg; + proj.velocity = _vel; + proj.touch = vehicles_projectile_explode; + proj.use = vehicles_projectile_explode; + proj.owner = self; + proj.realowner = _owner; + proj.think = SUB_Remove; + proj.nextthink = time + 30; + + if(_health) + { + proj.takedamage = DAMAGE_AIM; + proj.event_damage = vehicles_projectile_damage; + proj.health = _health; + } + else + proj.flags = FL_PROJECTILE | FL_NOTARGET; + + if(_mzlsound) + sound (self, CH_WEAPON_A, _mzlsound, VOL_BASE, ATTEN_NORM); + + if(_mzlfx) - pointparticles(particleeffectnum(_mzlfx), proj.origin, proj.velocity, 1); - ++ Send_Effect(_mzlfx, proj.origin, proj.velocity, 1); + + setsize (proj, '-1 -1 -1' * _size, '1 1 1' * _size); + + CSQCProjectile(proj, _clianim, _projtype, _cull); + + return proj; +} + +void vehicles_gib_explode() +{ + 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); - pointparticles(particleeffectnum("explosion_small"), self.wp00.origin + '0 0 64', '0 0 0', 1); ++ Send_Effect("explosion_small", randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); ++ Send_Effect("explosion_small", self.wp00.origin + '0 0 64', '0 0 0', 1); + remove(self); +} + +void vehicles_gib_think() +{ + self.alpha -= 0.1; + if(self.cnt >= time) + remove(self); + else + self.nextthink = time + 0.1; +} + +entity vehicle_tossgib(entity _template, vector _vel, string _tag, bool _burn, bool _explode, float _maxtime, vector _rot) +{ + entity _gib = spawn(); + setmodel(_gib, _template.model); + setorigin(_gib, gettaginfo(self, gettagindex(self, _tag))); + _gib.velocity = _vel; + _gib.movetype = MOVETYPE_TOSS; + _gib.solid = SOLID_CORPSE; + _gib.colormod = '-0.5 -0.5 -0.5'; + _gib.effects = EF_LOWPRECISION; + _gib.avelocity = _rot; + + if(_burn) + _gib.effects |= EF_FLAME; + + if(_explode) + { + _gib.think = vehicles_gib_explode; + _gib.nextthink = time + random() * _explode; + _gib.touch = vehicles_gib_explode; + } + else + { + _gib.cnt = time + _maxtime; + _gib.think = vehicles_gib_think; + _gib.nextthink = time + _maxtime - 1; + _gib.alpha = 1; + } + return _gib; +} + +bool vehicle_addplayerslot( entity _owner, + entity _slot, + int _hud, + string _hud_model, + bool() _framefunc, + void(bool) _exitfunc, float() _enterfunc) +{ + if(!(_owner.vehicle_flags & VHF_MULTISLOT)) + _owner.vehicle_flags |= VHF_MULTISLOT; + + _slot.PlayerPhysplug = _framefunc; + _slot.vehicle_exit = _exitfunc; + _slot.vehicle_enter = _enterfunc; + _slot.hud = _hud; + _slot.vehicle_flags = VHF_PLAYERSLOT; + _slot.vehicle_viewport = spawn(); + _slot.vehicle_hudmodel = spawn(); + _slot.vehicle_hudmodel.viewmodelforclient = _slot; + _slot.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT); + + setmodel(_slot.vehicle_hudmodel, _hud_model); + setmodel(_slot.vehicle_viewport, "null"); + + setattachment(_slot.vehicle_hudmodel, _slot, ""); + setattachment(_slot.vehicle_viewport, _slot.vehicle_hudmodel, ""); + + return true; +} + +vector vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname, + float _pichlimit_min, float _pichlimit_max, + float _rotlimit_min, float _rotlimit_max, float _aimspeed) +{ + vector vtmp, vtag; + float ftmp; + vtag = gettaginfo(_turrret, gettagindex(_turrret, _tagname)); + vtmp = vectoangles(normalize(_target - vtag)); + vtmp = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(_vehic.angles), AnglesTransform_FromAngles(vtmp))) - _turrret.angles; + vtmp = AnglesTransform_Normalize(vtmp, true); + ftmp = _aimspeed * frametime; + vtmp_y = bound(-ftmp, vtmp_y, ftmp); + vtmp_x = bound(-ftmp, vtmp_x, ftmp); + _turrret.angles_y = bound(_rotlimit_min, _turrret.angles_y + vtmp_y, _rotlimit_max); + _turrret.angles_x = bound(_pichlimit_min, _turrret.angles_x + vtmp_x, _pichlimit_max); + return vtag; +} + +void vehicles_reset_colors() +{ + entity e; + float _effects = 0, _colormap; + vector _glowmod, _colormod; + + if(autocvar_g_nodepthtestplayers) + _effects |= EF_NODEPTHTEST; + + if(autocvar_g_fullbrightplayers) + _effects |= EF_FULLBRIGHT; + + if(self.team) + _colormap = 1024 + (self.team - 1) * 17; + else + _colormap = 1024; + + _glowmod = '0 0 0'; + _colormod = '0 0 0'; + + // Find all ents attacked to main model and setup effects, colormod etc. + e = findchainentity(tag_entity, self); + while(e) + { + if(e != self.vehicle_shieldent) + { + e.effects = _effects; // | EF_LOWPRECISION; + e.colormod = _colormod; + e.colormap = _colormap; + e.alpha = 1; + } + e = e.chain; + } + // Also check head tags + e = findchainentity(tag_entity, self.tur_head); + while(e) + { + if(e != self.vehicle_shieldent) + { + e.effects = _effects; // | EF_LOWPRECISION; + e.colormod = _colormod; + e.colormap = _colormap; + e.alpha = 1; + } + e = e.chain; + } + + self.vehicle_hudmodel.effects = self.effects = _effects; // | EF_LOWPRECISION; + self.vehicle_hudmodel.colormod = self.colormod = _colormod; + self.vehicle_hudmodel.colormap = self.colormap = _colormap; + self.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT); + + self.alpha = 1; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + self.effects = _effects; +} + +void vehicles_clearreturn(entity veh) +{ + entity ret; + // Remove "return helper", if any. + ret = findchain(classname, "vehicle_return"); + while(ret) + { + if(ret.wp00 == veh) + { + ret.classname = ""; + ret.think = SUB_Remove; + ret.nextthink = time + 0.1; + + if(ret.waypointsprite_attached) + WaypointSprite_Kill(ret.waypointsprite_attached); + + return; + } + ret = ret.chain; + } +} + +void vehicles_spawn(); +void vehicles_return() +{ - pointparticles(particleeffectnum("teleport"), self.wp00.origin + '0 0 64', '0 0 0', 1); ++ Send_Effect("teleport", self.wp00.origin + '0 0 64', '0 0 0', 1); + + self.wp00.think = vehicles_spawn; + self.wp00.nextthink = time; + + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); + + remove(self); +} + +void vehicles_showwp_goaway() +{ + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); + + remove(self); + +} + +void vehicles_showwp() +{ + entity oldself = world; + vector rgb; + + if(self.cnt) + { + self.think = vehicles_return; + self.nextthink = self.cnt; + } + else + { + self.think = vehicles_return; + self.nextthink = time +1; + + oldself = self; + self = spawn(); + setmodel(self, "null"); + self.team = oldself.wp00.team; + self.wp00 = oldself.wp00; + setorigin(self, oldself.wp00.pos1); + + self.nextthink = time + 5; + self.think = vehicles_showwp_goaway; + } + + if(teamplay && self.team) + rgb = Team_ColorRGB(self.team); + else + rgb = '1 1 1'; + WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, true, RADARICON_POWERUP, rgb); + if(self.waypointsprite_attached) + { + WaypointSprite_UpdateRule(self.waypointsprite_attached, self.wp00.team, SPRITERULE_DEFAULT); + if(oldself == world) + WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink); + WaypointSprite_Ping(self.waypointsprite_attached); + } + + if(oldself != world) + self = oldself; +} + +void vehicles_setreturn(entity veh) +{ + entity ret; + + vehicles_clearreturn(veh); + + ret = spawn(); + ret.classname = "vehicle_return"; + ret.wp00 = veh; + ret.team = veh.team; + ret.think = vehicles_showwp; + + if(veh.deadflag != DEAD_NO) + { + ret.cnt = time + veh.respawntime; + ret.nextthink = min(time + veh.respawntime, time + veh.respawntime - 5); + } + else + { + ret.nextthink = min(time + veh.respawntime, time + veh.respawntime - 1); + } + + setmodel(ret, "null"); + setorigin(ret, veh.pos1 + '0 0 96'); + +} + +void vehicle_use() +{ + dprint("vehicle ",self.netname, " used by ", activator.classname, "\n"); + + self.tur_head.team = activator.team; + + if(self.tur_head.team == 0) + self.active = ACTIVE_NOT; + else + self.active = ACTIVE_ACTIVE; + + if(self.active == ACTIVE_ACTIVE && self.deadflag == DEAD_NO && !gameover) + { + dprint("Respawning vehicle: ", self.netname, "\n"); + if(self.effects & EF_NODRAW) + { + self.think = vehicles_spawn; + self.nextthink = time + 3; + } + else + { + vehicles_setreturn(self); + vehicles_reset_colors(); + } + } +} + +void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale) +{ + if(self.regen_field < field_max) + if(timer + rpause < time) + { + if(_healthscale) + regen = regen * (self.vehicle_health / self.max_health); + + self.regen_field = min(self.regen_field + regen * delta_time, field_max); + + if(self.owner) + self.owner.regen_field = (self.regen_field / field_max) * 100; + } +} + +void shieldhit_think() +{ + self.alpha -= 0.1; + if (self.alpha <= 0) + { + //setmodel(self, ""); + self.alpha = -1; + self.effects |= EF_NODRAW; + } + else + { + self.nextthink = time + 0.1; + } +} + +void vehicles_painframe() +{ + if(self.owner.vehicle_health <= 50) + if(self.pain_frame < time) + { + float _ftmp; + _ftmp = self.owner.vehicle_health / 50; + self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp); + pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1); + + if(self.vehicle_flags & VHF_DMGSHAKE) + self.velocity += randomvec() * 30; + + if(self.vehicle_flags & VHF_DMGROLL) + if(self.vehicle_flags & VHF_DMGHEADROLL) + self.tur_head.angles += randomvec(); + else + self.angles += randomvec(); + + } +} + +void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + self.dmg_time = time; + + // WEAPONTODO - if(DEATH_ISWEAPON(deathtype, WEP_VORTEX)) ++ if(DEATH_ISWEAPON(deathtype, WEP_VORTEX.m_id)) + damage *= autocvar_g_vehicles_vortex_damagerate; + - if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN)) ++ if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN.m_id)) + damage *= autocvar_g_vehicles_machinegun_damagerate; + - if(DEATH_ISWEAPON(deathtype, WEP_RIFLE)) ++ if(DEATH_ISWEAPON(deathtype, WEP_RIFLE.m_id)) + damage *= autocvar_g_vehicles_rifle_damagerate; + - if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER)) ++ if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER.m_id)) + damage *= autocvar_g_vehicles_vaporizer_damagerate; + - if(DEATH_ISWEAPON(deathtype, WEP_SEEKER)) ++ if(DEATH_ISWEAPON(deathtype, WEP_SEEKER.m_id)) + damage *= autocvar_g_vehicles_tag_damagerate; + + if(DEATH_WEAPONOFWEAPONDEATH(deathtype)) + damage *= autocvar_g_vehicles_weapon_damagerate; + + self.enemy = attacker; + + self.pain_finished = time; + + if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0)) + { + if (wasfreed(self.vehicle_shieldent) || self.vehicle_shieldent == world) + { + 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 = 256 / vlen(self.maxs - self.mins); + self.vehicle_shieldent.think = shieldhit_think; + } + + self.vehicle_shieldent.colormod = '1 1 1'; + self.vehicle_shieldent.alpha = 0.45; + self.vehicle_shieldent.angles = vectoangles(normalize(hitloc - (self.origin + self.vehicle_shieldent.origin))) - self.angles; + self.vehicle_shieldent.nextthink = time; + self.vehicle_shieldent.effects &= ~EF_NODRAW; + + self.vehicle_shield -= damage; + + if(self.vehicle_shield < 0) + { + self.vehicle_health -= fabs(self.vehicle_shield); + self.vehicle_shieldent.colormod = '2 0 0'; + self.vehicle_shield = 0; + self.vehicle_shieldent.alpha = 0.75; + + if(sound_allowed(MSG_BROADCAST, attacker)) + spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER + } + else + if(sound_allowed(MSG_BROADCAST, attacker)) + spamsound (self, CH_PAIN, "onslaught/electricity_explode.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER + + } + else + { + self.vehicle_health -= damage; + + if(sound_allowed(MSG_BROADCAST, attacker)) + spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTEN_NORM); // FIXME: PLACEHOLDER + } + + if(self.damageforcescale < 1 && self.damageforcescale > 0) + self.velocity += force * self.damageforcescale; + else + self.velocity += force; + + if(self.vehicle_health <= 0) + { + if(self.owner) + if(self.vehicle_flags & VHF_DEATHEJECT) + vehicles_exit(VHEF_EJECT); + else + vehicles_exit(VHEF_RELEASE); + + + antilag_clear(self); + + VEH_ACTION(self.vehicleid, VR_DEATH); + vehicles_setreturn(self); + } +} + +float vehicles_crushable(entity e) +{ + if(IS_PLAYER(e) && time >= e.vehicle_enter_delay) + return true; + - if(e.flags & FL_MONSTER) ++ if(IS_MONSTER(e)) + return true; + + return false; +} + +void vehicles_impact(float _minspeed, float _speedfac, float _maxpain) +{ + if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) + return; + + if(self.play_time < time) + { + float wc = vlen(self.velocity - self.oldvelocity); + //dprint("oldvel: ", vtos(self.oldvelocity), "\n"); + //dprint("vel: ", vtos(self.velocity), "\n"); + if(_minspeed < wc) + { + float take = min(_speedfac * wc, _maxpain); + Damage (self, world, world, take, DEATH_FALL, self.origin, '0 0 0'); + self.play_time = time + 0.25; + + //dprint("wc: ", ftos(wc), "\n"); + //dprint("take: ", ftos(take), "\n"); + } + } +} + +// vehicle enter/exit handling +vector vehicles_findgoodexit(vector prefer_spot) +{ + //vector exitspot; + float mysize; + + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return prefer_spot; + + mysize = 1.5 * vlen(self.maxs - self.mins); + float i; + vector v, v2; + v2 = 0.5 * (self.absmin + self.absmax); + for(i = 0; i < 100; ++i) + { + v = randomvec(); + v_z = 0; + v = v2 + normalize(v) * mysize; + tracebox(v2, PL_MIN, PL_MAX, v, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return v; + } + + /* + exitspot = (self.origin + '0 0 48') + v_forward * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') - v_forward * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') + v_right * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') - v_right * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + */ + + return self.origin; +} + +void vehicles_exit(bool eject) +{ + entity _vehicle; + entity _player; + entity _oldself = self; + + if(vehicles_exit_running) + { + dprint("^1vehicles_exit allready running! this is not good..\n"); + return; + } + + vehicles_exit_running = true; + if(IS_CLIENT(self)) + { + _vehicle = self.vehicle; + + if (_vehicle.vehicle_flags & VHF_PLAYERSLOT) + { + _vehicle.vehicle_exit(eject); + self = _oldself; + vehicles_exit_running = false; + return; + } + } + else + _vehicle = self; + + _player = _vehicle.owner; + + self = _vehicle; + + if (_player) + { + if (IS_REAL_CLIENT(_player)) + { + msg_entity = _player; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity( MSG_ONE, _player); + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, 0); + WriteAngle(MSG_ONE, _vehicle.angles_y); + WriteAngle(MSG_ONE, 0); + } + + setsize(_player, PL_MIN,PL_MAX); + + _player.takedamage = DAMAGE_AIM; + _player.solid = SOLID_SLIDEBOX; + _player.movetype = MOVETYPE_WALK; + _player.effects &= ~EF_NODRAW; + _player.teleportable = TELEPORT_NORMAL; + _player.alpha = 1; + _player.PlayerPhysplug = func_null; + _player.vehicle = world; + _player.view_ofs = PL_VIEW_OFS; + _player.event_damage = PlayerDamage; + _player.hud = HUD_NORMAL; + _player.switchweapon = _vehicle.switchweapon; + _player.last_vehiclecheck = time + 3; + _player.vehicle_enter_delay = time + 2; + + CSQCVehicleSetup(_player, HUD_NORMAL); + } + _vehicle.flags |= FL_NOTARGET; + + if(_vehicle.deadflag == DEAD_NO) + _vehicle.avelocity = '0 0 0'; + + _vehicle.tur_head.nodrawtoclient = world; + + if(!teamplay) + _vehicle.team = 0; + + Kill_Notification(NOTIF_ONE, _player, MSG_CENTER_CPID, CPID_VEHICLES); + Kill_Notification(NOTIF_ONE, _player, MSG_CENTER_CPID, CPID_VEHICLES_OTHER); // kill all vehicle notifications when exiting a vehicle? + + WaypointSprite_Kill(_vehicle.wps_intruder); + - vh_player = _player; - vh_vehicle = _vehicle; - MUTATOR_CALLHOOK(VehicleExit); - _player = vh_player; - _vehicle = vh_vehicle; ++ MUTATOR_CALLHOOK(VehicleExit, _player, _vehicle); + + _vehicle.team = _vehicle.tur_head.team; + + sound (_vehicle, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTEN_NORM); + _vehicle.vehicle_hudmodel.viewmodelforclient = _vehicle; + _vehicle.phase = time + 1; + + _vehicle.vehicle_exit(eject); + + vehicles_setreturn(_vehicle); + vehicles_reset_colors(); + _vehicle.owner = world; + + CSQCMODEL_AUTOINIT(); + + self = _oldself; + + vehicles_exit_running = false; +} + +void vehicles_touch() +{ - if(MUTATOR_CALLHOOK(VehicleTouch)) ++ if(MUTATOR_CALLHOOK(VehicleTouch, self, other)) + return; + + // Vehicle currently in use + if(self.owner) + { + if(!forbidWeaponUse(self.owner)) + if(other != world) + if((self.origin_z + self.maxs_z) > (other.origin_z)) + if(vehicles_crushable(other)) + { + if(vlen(self.velocity) >= 30) + Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force); + + return; // Dont do selfdamage when hitting "soft targets". + } + + if(self.play_time < time) + VEH_ACTION(self.vehicleid, VR_IMPACT); + + return; + } + + if(autocvar_g_vehicles_enter) + return; + + vehicles_enter(other, self); +} + ++bool vehicle_impulse(int imp) ++{ ++ switch(imp) ++ { ++ case 17: ++ { ++ stuffcmd(self, "\ntoggle cl_eventchase_vehicle\nset _vehicles_shownchasemessage 1\n"); ++ return true; ++ } ++ } ++ ++ return false; ++} ++ +void vehicles_enter(entity pl, entity veh) +{ + // Remove this when bots know how to use vehicles + if((IS_BOT_CLIENT(pl) && !autocvar_g_vehicles_allow_bots)) + return; + + if((!IS_PLAYER(pl)) + || (veh.phase >= time) + || (pl.vehicle_enter_delay >= time) + || (pl.frozen) + || (pl.deadflag != DEAD_NO) + || (pl.vehicle) + ) { return; } + + if(autocvar_g_vehicles_enter) // vehicle's touch function should handle this if entering via use key is disabled (TODO) + if(veh.vehicle_flags & VHF_MULTISLOT) + if(veh.owner) + { + entity oldself = self; + self = veh; + other = pl; // TODO: fix + + if(!veh.gunner1) + if(time >= veh.gun1.phase) + if(veh.gun1.vehicle_enter) + if(veh.gun1.vehicle_enter()) + { + self = oldself; + return; + } + + if(!veh.gunner2) + if(time >= veh.gun2.phase) + if(veh.gun2.vehicle_enter) + if(veh.gun2.vehicle_enter()) + { + self = oldself; + return; + } + + self = oldself; + } + + if(teamplay) + if(veh.team) + if(DIFF_TEAM(pl, veh)) + if(autocvar_g_vehicles_steal) + { + entity head; + FOR_EACH_PLAYER(head) if(SAME_TEAM(head, veh)) + Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_VEHICLE_STEAL); + + Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_VEHICLE_STEAL_SELF); + + if(autocvar_g_vehicles_steal_show_waypoint) + WaypointSprite_Spawn("intruder", 0, 0, pl, '0 0 68', world, veh.team, veh, wps_intruder, true, RADARICON_DANGER, Team_ColorRGB(pl.team)); + } + else return; + + RemoveGrapplingHook(pl); + + veh.vehicle_ammo1 = 0; + veh.vehicle_ammo2 = 0; + veh.vehicle_reload1 = 0; + veh.vehicle_reload2 = 0; + veh.vehicle_energy = 0; + + veh.owner = pl; + pl.vehicle = veh; + + // .viewmodelforclient works better. + //veh.vehicle_hudmodel.drawonlytoclient = veh.owner; + + veh.vehicle_hudmodel.viewmodelforclient = pl; + + tracebox(pl.origin, PL_MIN, PL_MAX, pl.origin, false, pl); + pl.crouch = false; + pl.view_ofs = PL_VIEW_OFS; + setsize (pl, PL_MIN, PL_MAX); + + veh.event_damage = vehicles_damage; + veh.nextthink = 0; + pl.angles = veh.angles; + pl.takedamage = DAMAGE_NO; + pl.solid = SOLID_NOT; + pl.movetype = MOVETYPE_NOCLIP; + pl.teleportable = false; + pl.alpha = -1; + pl.event_damage = func_null; + pl.view_ofs = '0 0 0'; + veh.colormap = pl.colormap; + if(veh.tur_head) + veh.tur_head.colormap = pl.colormap; + veh.switchweapon = pl.switchweapon; + pl.hud = veh.vehicleid; + pl.PlayerPhysplug = veh.PlayerPhysplug; + + pl.vehicle_ammo1 = veh.vehicle_ammo1; + pl.vehicle_ammo2 = veh.vehicle_ammo2; + pl.vehicle_reload1 = veh.vehicle_reload1; + pl.vehicle_reload2 = veh.vehicle_reload2; ++ pl.vehicle_energy = veh.vehicle_energy; + + // Cant do this, hides attached objects too. + //veh.exteriormodeltoclient = veh.owner; + //veh.tur_head.exteriormodeltoclient = veh.owner; + + pl.flags &= ~FL_ONGROUND; + veh.flags &= ~FL_ONGROUND; + + veh.team = pl.team; + veh.flags -= FL_NOTARGET; + + if (IS_REAL_CLIENT(pl)) + { + Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_VEHICLE_ENTER); + + msg_entity = pl; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, veh.vehicle_viewport); + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + if(veh.tur_head) + { + WriteAngle(MSG_ONE, veh.tur_head.angles_x + veh.angles_x); // tilt + WriteAngle(MSG_ONE, veh.tur_head.angles_y + veh.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + else + { + WriteAngle(MSG_ONE, veh.angles_x * -1); // tilt + WriteAngle(MSG_ONE, veh.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + } + + vehicles_clearreturn(veh); + + CSQCVehicleSetup(pl, veh.vehicleid); + - vh_player = pl; - vh_vehicle = veh; - MUTATOR_CALLHOOK(VehicleEnter); ++ MUTATOR_CALLHOOK(VehicleEnter, pl, veh); + + entity oldself = self; + self = veh; + CSQCModel_UnlinkEntity(); + VEH_ACTION(veh.vehicleid, VR_ENTER); + self = oldself; + + antilag_clear(pl); +} + +void vehicles_think() +{ + self.nextthink = time; + + if(self.owner) + self.owner.vehicle_weapon2mode = self.vehicle_weapon2mode; + + VEH_ACTION(self.vehicleid, VR_THINK); + + CSQCMODEL_AUTOUPDATE(); +} + +// initialization +void vehicles_spawn() +{ + dprint("Spawning vehicle: ", self.classname, "\n"); + + // disown & reset + self.vehicle_hudmodel.viewmodelforclient = self; + + self.owner = world; + self.touch = vehicles_touch; + self.event_damage = vehicles_damage; + self.iscreature = true; + self.teleportable = false; // no teleporting for vehicles, too buggy + self.damagedbycontents = true; + self.movetype = MOVETYPE_WALK; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + self.deadflag = DEAD_NO; + self.bot_attack = true; + self.flags = FL_NOTARGET; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + self.think = vehicles_think; + self.nextthink = time; + + // Reset locking + self.lock_strength = 0; + self.lock_target = world; + self.misc_bulletcounter = 0; + + // Return to spawn + self.angles = self.pos2; + setorigin(self, self.pos1); + // Show it - pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1); ++ Send_Effect("teleport", self.origin + '0 0 64', '0 0 0', 1); + + if(self.vehicle_controller) + self.team = self.vehicle_controller.team; + + entity head; // remove hooks (if any) + FOR_EACH_PLAYER(head) + if(head.hook.aiment == self) + RemoveGrapplingHook(head); + + vehicles_reset_colors(); + + VEH_ACTION(self.vehicleid, VR_SPAWN); + + CSQCMODEL_AUTOINIT(); +} + +bool vehicle_initialize(int vehicle_id, bool nodrop) +{ + if(!autocvar_g_vehicles) + return false; + + entity veh = get_vehicleinfo(vehicle_id); + + if(!veh.vehicleid) + return false; + + if(!veh.tur_head) { VEH_ACTION(vehicle_id, VR_PRECACHE); } + + if(self.targetname && self.targetname != "") + { + self.vehicle_controller = find(world, target, self.targetname); + if(!self.vehicle_controller) + { + bprint("^1WARNING: ^7Vehicle with invalid .targetname\n"); + self.active = ACTIVE_ACTIVE; + } + else + { + self.team = self.vehicle_controller.team; + self.use = vehicle_use; + + if(teamplay) + { + if(self.vehicle_controller.team == 0) + self.active = ACTIVE_NOT; + else + self.active = ACTIVE_ACTIVE; + } + } + } + else { self.active = ACTIVE_ACTIVE; } + + if(self.team && (!teamplay || !autocvar_g_vehicles_teams)) + self.team = 0; + - self.vehicle_flags |= VHF_ISVEHICLE; ++ if(self.mdl == "" || !self.mdl) ++ setmodel(self, veh.model); ++ else ++ setmodel(self, self.mdl); + - setmodel(self, veh.model); ++ self.vehicle_flags |= VHF_ISVEHICLE; + + self.vehicle_viewport = spawn(); + self.vehicle_hudmodel = spawn(); + self.tur_head = spawn(); + self.tur_head.owner = self; + self.takedamage = DAMAGE_NO; + self.bot_attack = true; + self.iscreature = true; + self.teleportable = false; // no teleporting for vehicles, too buggy + self.damagedbycontents = true; + self.vehicleid = vehicle_id; + self.PlayerPhysplug = veh.PlayerPhysplug; + self.event_damage = func_null; + self.touch = vehicles_touch; + self.think = vehicles_spawn; + self.nextthink = time; + self.effects = EF_NODRAW; + self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; + + if(autocvar_g_playerclip_collisions) + self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; + + if(autocvar_g_nodepthtestplayers) + self.effects |= EF_NODEPTHTEST; + + if(autocvar_g_fullbrightplayers) + self.effects |= EF_FULLBRIGHT; + + setmodel(self.vehicle_hudmodel, veh.hud_model); + setmodel(self.vehicle_viewport, "null"); + + if(veh.head_model != "") + { + setmodel(self.tur_head, veh.head_model); + setattachment(self.tur_head, self, veh.tag_head); + setattachment(self.vehicle_hudmodel, self.tur_head, veh.tag_hud); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, veh.tag_view); + } + else + { + setattachment(self.tur_head, self, ""); + setattachment(self.vehicle_hudmodel, self, veh.tag_hud); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, veh.tag_view); + } + + setsize(self, veh.mins, veh.maxs); + + if(!nodrop) + { + setorigin(self, self.origin); + tracebox(self.origin + '0 0 100', veh.mins, veh.maxs, self.origin - '0 0 10000', MOVE_WORLDONLY, self); + setorigin(self, trace_endpos); + } + + self.pos1 = self.origin; + self.pos2 = self.angles; + self.tur_head.team = self.team; + + VEH_ACTION(vehicle_id, VR_SETUP); + + if(self.active == ACTIVE_NOT) + self.nextthink = 0; // wait until activated + else if(autocvar_g_vehicles_delayspawn) + self.nextthink = time + self.respawntime + (random() * autocvar_g_vehicles_delayspawn_jitter); + else + self.nextthink = time + game_starttime; + + if(MUTATOR_CALLHOOK(VehicleSpawn)) + return false; + + return true; +} diff --cc qcsrc/common/vehicles/sv_vehicles.qh index 27df7fac6,000000000..0de7184fe mode 100644,000000..100644 --- a/qcsrc/common/vehicles/sv_vehicles.qh +++ b/qcsrc/common/vehicles/sv_vehicles.qh @@@ -1,108 -1,0 +1,110 @@@ +#ifndef VEHICLES_DEF_H +#define VEHICLES_DEF_H +#ifdef SVQC + +#include "../server/tturrets/include/turrets_early.qh" +#include "sv_vehicles.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; +float autocvar_g_vehicles_vortex_damagerate = 0.5; +float autocvar_g_vehicles_machinegun_damagerate = 0.5; +float autocvar_g_vehicles_rifle_damagerate = 0.75; +float autocvar_g_vehicles_vaporizer_damagerate = 0.001; +float autocvar_g_vehicles_tag_damagerate = 5; +float autocvar_g_vehicles_weapon_damagerate = 1; + +// flags: +.int vehicle_flags; + +// 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_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 vehicle_ammo1; /// If self is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already stored in vehicle_energy. If self is vehile, this is the real ammo1 value. ++.float vehicle_reload1; /// If self is player this is 0..100 indicating percentage of primary reload status. If self is vehile, this is the real reload1 value. ++.float vehicle_ammo2; /// If self is player this is 0..100 indicating percentage of secondary ammo left. If self is vehile, this is the real ammo2 value. ++.float vehicle_reload2; /// If self is player this is 0..100 indicating percentage of secondary reload status. If self is vehile, this is the real reload2 value. + +.float sound_nexttime; +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 + +const float VHSF_NORMAL = 0; +const float VHSF_FACTORY = 2; + +.int hud; +.float dmg_time; + +.int volly_counter; + +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; + +// vehicle functions +.void(int _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns +.bool(int _imp) vehicles_impulse; +.int vehicle_weapon2mode; +.void(int exit_flags) vehicle_exit; +.bool() vehicle_enter; +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) + +float force_fromtag_power; +float force_fromtag_normpower; +vector force_fromtag_origin; + +float vehicles_exit_running; + +// macros +#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \ + ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 + +.float vehicle_enter_delay; // prevent players jumping to and from vehicles instantly + +void vehicles_exit(float eject); +float vehicle_initialize(float vehicle_id, float nodrop); ++bool vehicle_impulse(int imp); ++bool vehicles_crushable(entity e); + +#endif + +#endif diff --cc qcsrc/common/vehicles/unit/all.qh index 000000000,000000000..7dfca83a2 new file mode 100644 --- /dev/null +++ b/qcsrc/common/vehicles/unit/all.qh @@@ -1,0 -1,0 +1,6 @@@ ++#include "spiderbot.qc" ++#include "raptor.qc" ++#include "racer.qc" ++#ifndef VEHICLES_NO_UNSTABLE ++ #include "bumblebee.qc" ++#endif diff --cc qcsrc/common/vehicles/unit/bumblebee.qc index cf58a8ca9,000000000..cc52716c7 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/bumblebee.qc +++ b/qcsrc/common/vehicles/unit/bumblebee.qc @@@ -1,1397 -1,0 +1,1122 @@@ +#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; + +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; +vector autocvar_g_vehicle_bumblebee_bouncepain; + +bool autocvar_g_vehicle_bumblebee = 0; + +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); +} + +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(DIFF_TEAM(trace_ent, gunner)) + { + 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; + + + 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; +} + +vector bumblebee_gunner_findgoodexit(vector prefer_spot, entity gunner, entity player) +{ + //vector exitspot; + float mysize; + + tracebox(gunner.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, player); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return prefer_spot; + + mysize = 1.5 * vlen(PL_MAX - PL_MIN); // can't use gunner's size, as they don't have a size + float i; + vector v, v2; + v2 = 0.5 * (gunner.absmin + gunner.absmax); + for(i = 0; i < 100; ++i) + { + v = randomvec(); + v_z = 0; + v = v2 + normalize(v) * mysize; + tracebox(v2, PL_MIN, PL_MAX, v, MOVE_NORMAL, player); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return v; + } + + return prefer_spot; // this should be considered a fallback?! +} + +void bumblebee_gunner_exit(int _exitflag) +{ + entity player = self; + entity gunner = player.vehicle; + entity vehic = gunner.owner; + + if(IS_REAL_CLIENT(player)) + { + msg_entity = player; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, player); + + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, 0); + WriteAngle(MSG_ONE, vehic.angles.y); + WriteAngle(MSG_ONE, 0); + } + + CSQCVehicleSetup(player, HUD_NORMAL); + setsize(player, PL_MIN, PL_MAX); + + player.takedamage = DAMAGE_AIM; + player.solid = SOLID_SLIDEBOX; + player.movetype = MOVETYPE_WALK; + player.effects &= ~EF_NODRAW; + player.alpha = 1; + player.PlayerPhysplug = func_null; + player.view_ofs = PL_VIEW_OFS; + player.event_damage = PlayerDamage; + player.hud = HUD_NORMAL; + player.teleportable = TELEPORT_NORMAL; + player.switchweapon = gunner.switchweapon; + player.vehicle_enter_delay = time + 2; + + fixedmakevectors(vehic.angles); + + if(player == vehic.gunner1) { vehic.gunner1 = world; } + if(player == vehic.gunner2) { vehic.gunner2 = world; v_right *= -1; } + + vector spot = real_origin(gunner); + spot = spot + v_up * 128 + v_forward * 300 + v_right * 150; + spot = bumblebee_gunner_findgoodexit(spot, gunner, player); + + // TODO: figure a way to move player out of the gunner + + player.velocity = 0.75 * vehic.velocity + normalize(spot - vehic.origin) * 200; + player.velocity_z += 10; + + gunner.phase = time + 5; + gunner.vehicle_hudmodel.viewmodelforclient = gunner; + - vh_player = player; - vh_vehicle = gunner; - MUTATOR_CALLHOOK(VehicleExit); - player = vh_player; - gunner = vh_vehicle; ++ MUTATOR_CALLHOOK(VehicleExit, player, gunner); + + player.vehicle = world; +} + +bool bumblebee_gunner_enter() +{ + entity vehic = self; + entity player = other; + entity gunner = world; + + if(!vehic.gunner1 && !vehic.gunner2 && ((time >= vehic.gun1.phase) + (time >= vehic.gun2.phase)) == 2) + { + // we can have some fun + if(vlen(real_origin(vehic.gun2) - player.origin) < vlen(real_origin(vehic.gun1) - player.origin)) + { + gunner = vehic.gun2; + vehic.gunner2 = player; + } + else + { + gunner = vehic.gun1; + vehic.gunner1 = player; + } + } + else if(!vehic.gunner1 && time >= vehic.gun1.phase) { gunner = vehic.gun1; vehic.gunner1 = player; } + else if(!vehic.gunner2 && time >= vehic.gun2.phase) { gunner = vehic.gun2; vehic.gunner2 = player; } + else { dprint("Vehicle is full, fail\n"); return false; } + + player.vehicle = gunner; + player.angles = vehic.angles; + player.takedamage = DAMAGE_NO; + player.solid = SOLID_NOT; + player.alpha = -1; + player.movetype = MOVETYPE_NOCLIP; + player.event_damage = func_null; + player.view_ofs = '0 0 0'; + player.hud = gunner.hud; + player.teleportable = false; + player.PlayerPhysplug = gunner.PlayerPhysplug; + player.vehicle_ammo1 = vehic.vehicle_ammo1; + player.vehicle_ammo2 = vehic.vehicle_ammo2; + player.vehicle_reload1 = vehic.vehicle_reload1; + player.vehicle_reload2 = vehic.vehicle_reload2; + player.vehicle_energy = vehic.vehicle_energy; + player.flags &= ~FL_ONGROUND; + + RemoveGrapplingHook(player); + + gunner.switchweapon = player.switchweapon; + gunner.vehicle_exit = bumblebee_gunner_exit; + gunner.vehicle_hudmodel.viewmodelforclient = player; + + if(IS_REAL_CLIENT(player)) + { + msg_entity = player; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, gunner.vehicle_viewport); + + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, gunner.angles_x + vehic.angles_x); // tilt + WriteAngle(MSG_ONE, gunner.angles_y + vehic.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + + CSQCVehicleSetup(player, player.hud); + - vh_player = player; - vh_vehicle = gunner; - MUTATOR_CALLHOOK(VehicleEnter); - player = vh_player; - gunner = vh_vehicle; ++ MUTATOR_CALLHOOK(VehicleEnter, player, gunner); + + return true; +} + +bool vehicles_valid_pilot() +{ + if(IS_BOT_CLIENT(other) && !autocvar_g_vehicles_allow_bots) + return false; + + if((!IS_PLAYER(other)) + || (other.deadflag != DEAD_NO) + || (other.vehicle) + || (DIFF_TEAM(other, self)) + ) { return false; } + + 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()) + { + float phase_time = (time >= self.gun1.phase) + (time >= self.gun2.phase); + + if(time >= other.vehicle_enter_delay && 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); + + 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); + + 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); + +} + +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); + 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); + + // Pitch + ftmp = 0; + 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) + 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); + + 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); + newvel = vehic.velocity * -autocvar_g_vehicle_bumblebee_friction; + + 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) + newvel -= v_forward * autocvar_g_vehicle_bumblebee_speed_forward; + } + + 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) + 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); + } + else + { + vehic.angles_z *= 0.95; + 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) ++ else if(IS_TURRET(trace_ent)) + { + 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); ++ Send_Effect("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); ++ Send_Effect("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; +} + +void spawnfunc_vehicle_bumblebee() +{ + if(!autocvar_g_vehicle_bumblebee) { 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; + } + case VR_ENTER: + { + self.touch = bumblebee_touch; + self.nextthink = 0; + self.movetype = MOVETYPE_BOUNCEMISSILE; + 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; + } + + 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; + } + 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); ++ Send_Effect("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; + } + 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; + + self.gun1.classname = self.gun2.classname = "vehicle_playerslot"; + + 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); + 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; + } + 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; + } + 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; +} + +#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); - } - */ ++ Vehicles_drawHUD("vehicle_gunner", "vehicle_gunner_weapon1", string_null, ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ string_null, '0 0 0', ++ string_null); +} + +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(bool bIsNew) +{ + 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; - - 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)); - 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)); - 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); - } ++ Vehicles_drawHUD("vehicle_bumble", "vehicle_bumble_weapon1", "vehicle_bumble_weapon2", ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ vCROSS_HEAL); + 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; ++ AuxiliaryXhair[0].axh_image = vCROSS_LOCK; // Raygun-locked ++ AuxiliaryXhair[1].axh_image = vCROSS_BURST; // Gunner1 ++ AuxiliaryXhair[2].axh_image = vCROSS_BURST; // Gunner2 + return true; + } + case VR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --cc qcsrc/common/vehicles/unit/racer.qc index fbcb53970,000000000..80cde0313 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/racer.qc +++ b/qcsrc/common/vehicles/unit/racer.qc @@@ -1,939 -1,0 +1,869 @@@ +#ifdef REGISTER_VEHICLE +REGISTER_VEHICLE( +/* VEH_##id */ RACER, +/* function */ v_racer, +/* spawnflags */ VHF_DMGSHAKE | VHF_DMGROLL, +/* mins,maxs */ '-120 -120 -40' * 0.5, '120 120 40' * 0.5, +/* model */ "models/vehicles/wakizashi.dpm", +/* head_model */ "null", +/* hud_model */ "models/vehicles/wakizashi_cockpit.dpm", +/* tags */ "", "", "tag_viewport", +/* netname */ "racer", +/* fullname */ _("Racer") +); +#else +#ifdef SVQC ++#include "../../effects.qh" ++#include "../../triggers/trigger/impulse.qh" ++ +bool autocvar_g_vehicle_racer; + +float autocvar_g_vehicle_racer_speed_afterburn; +float autocvar_g_vehicle_racer_afterburn_cost; + +float autocvar_g_vehicle_racer_waterburn_cost; +float autocvar_g_vehicle_racer_waterburn_speed; + +float autocvar_g_vehicle_racer_water_speed_forward; +float autocvar_g_vehicle_racer_water_speed_strafe; + +float autocvar_g_vehicle_racer_pitchlimit = 30; + +float autocvar_g_vehicle_racer_water_downforce = 0.03; +float autocvar_g_vehicle_racer_water_upforcedamper = 15; + +float autocvar_g_vehicle_racer_anglestabilizer; +float autocvar_g_vehicle_racer_downforce; + +float autocvar_g_vehicle_racer_speed_forward; +float autocvar_g_vehicle_racer_speed_strafe; +float autocvar_g_vehicle_racer_springlength; +float autocvar_g_vehicle_racer_upforcedamper; +float autocvar_g_vehicle_racer_friction; + +float autocvar_g_vehicle_racer_water_time = 5; + +float autocvar_g_vehicle_racer_hovertype; +float autocvar_g_vehicle_racer_hoverpower; + +float autocvar_g_vehicle_racer_turnroll; +float autocvar_g_vehicle_racer_turnspeed; +float autocvar_g_vehicle_racer_pitchspeed; + +float autocvar_g_vehicle_racer_energy; +float autocvar_g_vehicle_racer_energy_regen; +float autocvar_g_vehicle_racer_energy_regen_pause; + +float autocvar_g_vehicle_racer_health; +float autocvar_g_vehicle_racer_health_regen; +float autocvar_g_vehicle_racer_health_regen_pause; + +float autocvar_g_vehicle_racer_shield; +float autocvar_g_vehicle_racer_shield_regen; +float autocvar_g_vehicle_racer_shield_regen_pause; + +float autocvar_g_vehicle_racer_cannon_cost; +float autocvar_g_vehicle_racer_cannon_damage; +float autocvar_g_vehicle_racer_cannon_radius; +float autocvar_g_vehicle_racer_cannon_refire; +float autocvar_g_vehicle_racer_cannon_speed; +float autocvar_g_vehicle_racer_cannon_spread; +float autocvar_g_vehicle_racer_cannon_force; + +float autocvar_g_vehicle_racer_rocket_accel; +float autocvar_g_vehicle_racer_rocket_damage; +float autocvar_g_vehicle_racer_rocket_radius; +float autocvar_g_vehicle_racer_rocket_force; +float autocvar_g_vehicle_racer_rocket_refire; +float autocvar_g_vehicle_racer_rocket_speed; +float autocvar_g_vehicle_racer_rocket_turnrate; + +float autocvar_g_vehicle_racer_rocket_locktarget; +float autocvar_g_vehicle_racer_rocket_locking_time; +float autocvar_g_vehicle_racer_rocket_locking_releasetime; +float autocvar_g_vehicle_racer_rocket_locked_time; +float autocvar_g_vehicle_racer_rocket_locked_maxangle; +float autocvar_g_vehicle_racer_rocket_climbspeed; + +float autocvar_g_vehicle_racer_respawntime; + +float autocvar_g_vehicle_racer_blowup_radius; +float autocvar_g_vehicle_racer_blowup_coredamage; +float autocvar_g_vehicle_racer_blowup_edgedamage; +float autocvar_g_vehicle_racer_blowup_forceintensity; + +float autocvar_g_vehicle_racer_bouncefactor; +float autocvar_g_vehicle_racer_bouncestop; +vector autocvar_g_vehicle_racer_bouncepain; + +.float racer_watertime; + +var vector racer_force_from_tag(string tag_name, float spring_length, float max_power); + +void racer_align4point(float _delta) +{ + vector push_vector; + float fl_push, fr_push, bl_push, br_push; + + push_vector = racer_force_from_tag("tag_engine_fr", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower); + fr_push = force_fromtag_normpower; + //vehicles_sweap_collision(force_fromtag_origin, self.velocity, _delta, v_add, autocvar_g_vehicle_racer_collision_multiplier); + + push_vector += racer_force_from_tag("tag_engine_fl", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower); + fl_push = force_fromtag_normpower; + //vehicles_sweap_collision(force_fromtag_origin, self.velocity, _delta, v_add, autocvar_g_vehicle_racer_collision_multiplier); + + push_vector += racer_force_from_tag("tag_engine_br", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower); + br_push = force_fromtag_normpower; + //vehicles_sweap_collision(force_fromtag_origin, self.velocity, _delta, v_add, autocvar_g_vehicle_racer_collision_multiplier); + + push_vector += racer_force_from_tag("tag_engine_bl", autocvar_g_vehicle_racer_springlength, autocvar_g_vehicle_racer_hoverpower); + bl_push = force_fromtag_normpower; + //vehicles_sweap_collision(force_fromtag_origin, self.velocity, _delta, v_add, autocvar_g_vehicle_racer_collision_multiplier); + + self.velocity += push_vector * _delta; + + float uforce = autocvar_g_vehicle_racer_upforcedamper; + + int cont = pointcontents(self.origin - '0 0 64'); + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + { + uforce = autocvar_g_vehicle_racer_water_upforcedamper; + + if(self.owner.BUTTON_CROUCH && time < self.air_finished) + self.velocity_z += 30; + else + self.velocity_z += 200; + } + + + // Anti ocilation + if(self.velocity_z > 0) + self.velocity_z *= 1 - uforce * _delta; + + push_vector_x = (fl_push - bl_push); + push_vector_x += (fr_push - br_push); + push_vector_x *= 360; + + push_vector_z = (fr_push - fl_push); + push_vector_z += (br_push - bl_push); + push_vector_z *= 360; + + // Apply angle diffrance + self.angles_z += push_vector_z * _delta; + self.angles_x += push_vector_x * _delta; + + // Apply stabilizer + self.angles_x *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * _delta); + self.angles_z *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * _delta); +} + +void racer_fire_cannon(string tagname) +{ + vector v; + entity bolt; + + v = gettaginfo(self, gettagindex(self, tagname)); + bolt = vehicles_projectile("wakizashi_gun_muzzleflash", "weapons/lasergun_fire.wav", + v, normalize(v_forward + randomvec() * autocvar_g_vehicle_racer_cannon_spread) * autocvar_g_vehicle_racer_cannon_speed, + autocvar_g_vehicle_racer_cannon_damage, autocvar_g_vehicle_racer_cannon_radius, autocvar_g_vehicle_racer_cannon_force, 0, + DEATH_VH_WAKI_GUN, PROJECTILE_WAKICANNON, 0, true, true, self.owner); + + // Fix z-aim (for chase mode) + v = normalize(trace_endpos - bolt.origin); + v_forward_z = v_z * 0.5; + bolt.velocity = v_forward * autocvar_g_vehicle_racer_cannon_speed; +} + +void racer_rocket_groundhugger() +{ + vector olddir, newdir; + float oldvel, newvel; + + self.nextthink = time; + + if(self.owner.deadflag != DEAD_NO || self.cnt < time) + { + self.use(); + return; + } + + if(!self.realowner.vehicle) + { + UpdateCSQCProjectile(self); + return; + } + + olddir = normalize(self.velocity); + oldvel = vlen(self.velocity); + newvel = oldvel + self.lip; + + tracebox(self.origin, self.mins, self.maxs, self.origin + olddir * 64, MOVE_WORLDONLY,self); + if(trace_fraction <= 0.5) + { + // Hitting somethign soon, just speed ahead + self.velocity = olddir * newvel; + UpdateCSQCProjectile(self); + return; + } + + traceline(trace_endpos, trace_endpos - '0 0 64', MOVE_NORMAL, self); + if(trace_fraction != 1.0) + { + newdir = normalize(trace_endpos + '0 0 64' - self.origin) * autocvar_g_vehicle_racer_rocket_turnrate; + self.velocity = normalize(olddir + newdir) * newvel; + } + else + { + self.velocity = olddir * newvel; + self.velocity_z -= 1600 * sys_frametime; // 2x grav looks better for this one + } + + int cont = pointcontents(self.origin - '0 0 32'); + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + self.velocity_z += 200; + + UpdateCSQCProjectile(self); + return; +} + +void racer_rocket_tracker() +{ + vector olddir, newdir; + float oldvel, newvel; + + self.nextthink = time; + + if (self.owner.deadflag != DEAD_NO || self.cnt < time) + { + self.use(); + return; + } + + if(!self.realowner.vehicle) + { + UpdateCSQCProjectile(self); + return; + } + + olddir = normalize(self.velocity); + oldvel = vlen(self.velocity); + newvel = oldvel + self.lip; + makevectors(vectoangles(olddir)); + + float time_to_impact = min(vlen(self.enemy.origin - self.origin) / vlen(self.velocity), 1); + vector predicted_origin = self.enemy.origin + self.enemy.velocity * time_to_impact; + + traceline(self.origin, self.origin + v_forward * 64 - '0 0 32', MOVE_NORMAL, self); + newdir = normalize(predicted_origin - self.origin); + + //vector + float height_diff = predicted_origin_z - self.origin_z; + + if(vlen(newdir - v_forward) > autocvar_g_vehicle_racer_rocket_locked_maxangle) + { + //bprint("Target lost!\n"); + //dprint("OF:", ftos(vlen(newdir - v_forward)), "\n"); + self.think = racer_rocket_groundhugger; + return; + } + + if(trace_fraction != 1.0 && trace_ent != self.enemy) + newdir_z += 16 * sys_frametime; + + self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_racer_rocket_turnrate) * newvel; + self.velocity_z -= 800 * sys_frametime; + self.velocity_z += max(height_diff, autocvar_g_vehicle_racer_rocket_climbspeed) * sys_frametime ; + + UpdateCSQCProjectile(self); + return; +} + +void racer_fire_rocket(string tagname, entity trg) +{ + vector v = gettaginfo(self, gettagindex(self, tagname)); - entity rocket = rocket = vehicles_projectile("wakizashi_rocket_launch", "weapons/rocket_fire.wav", ++ entity rocket = vehicles_projectile("wakizashi_rocket_launch", "weapons/rocket_fire.wav", + v, v_forward * autocvar_g_vehicle_racer_rocket_speed, + autocvar_g_vehicle_racer_rocket_damage, autocvar_g_vehicle_racer_rocket_radius, autocvar_g_vehicle_racer_rocket_force, 3, + DEATH_VH_WAKI_ROCKET, PROJECTILE_WAKIROCKET, 20, false, false, self.owner); + + rocket.lip = autocvar_g_vehicle_racer_rocket_accel * sys_frametime; + rocket.wait = autocvar_g_vehicle_racer_rocket_turnrate; + rocket.nextthink = time; + rocket.enemy = trg; + rocket.cnt = time + 15; + + if(trg) + rocket.think = racer_rocket_tracker; + else + rocket.think = racer_rocket_groundhugger; +} + +float racer_frame() +{ + entity player, racer; + vector df; + float ftmp; + + if(intermission_running) + { + self.vehicle.velocity = '0 0 0'; + self.vehicle.avelocity = '0 0 0'; + return 1; + } + + player = self; + racer = self.vehicle; + self = racer; + + vehicles_painframe(); + + if(pointcontents(racer.origin) != CONTENT_WATER) + racer.air_finished = time + autocvar_g_vehicle_racer_water_time; + + if(racer.deadflag != DEAD_NO) + { + self = player; + player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; + return 1; + } + - racer_align4point(frametime); ++ racer_align4point(PHYS_INPUT_TIMELENGTH); + + player.BUTTON_ZOOM = player.BUTTON_CROUCH = 0; + + crosshair_trace(player); + + racer.angles_x *= -1; + + // Yaw - ftmp = autocvar_g_vehicle_racer_turnspeed * frametime; ++ ftmp = autocvar_g_vehicle_racer_turnspeed * PHYS_INPUT_TIMELENGTH; + ftmp = bound(-ftmp, shortangle_f(player.v_angle_y - racer.angles_y, racer.angles_y), ftmp); + racer.angles_y = anglemods(racer.angles_y + ftmp); + + // Roll - racer.angles_z += -ftmp * autocvar_g_vehicle_racer_turnroll * frametime; ++ racer.angles_z += -ftmp * autocvar_g_vehicle_racer_turnroll * PHYS_INPUT_TIMELENGTH; + + // Pitch - ftmp = autocvar_g_vehicle_racer_pitchspeed * frametime; ++ ftmp = autocvar_g_vehicle_racer_pitchspeed * PHYS_INPUT_TIMELENGTH; + ftmp = bound(-ftmp, shortangle_f(player.v_angle_x - racer.angles_x, racer.angles_x), ftmp); + racer.angles_x = bound(-autocvar_g_vehicle_racer_pitchlimit, anglemods(racer.angles_x + ftmp), autocvar_g_vehicle_racer_pitchlimit); + + makevectors(racer.angles); + racer.angles_x *= -1; + + //ftmp = racer.velocity_z; + df = racer.velocity * -autocvar_g_vehicle_racer_friction; + //racer.velocity_z = ftmp; + + int cont = pointcontents(racer.origin); + if(vlen(player.movement) != 0) + { + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + { + if(player.movement_x) { df += v_forward * ((player.movement_x > 0) ? autocvar_g_vehicle_racer_water_speed_forward : -autocvar_g_vehicle_racer_water_speed_forward); } + if(player.movement_y) { df += v_right * ((player.movement_y > 0) ? autocvar_g_vehicle_racer_water_speed_strafe : -autocvar_g_vehicle_racer_water_speed_strafe); } + } + else + { + if(player.movement_x) { df += v_forward * ((player.movement_x > 0) ? autocvar_g_vehicle_racer_speed_forward : -autocvar_g_vehicle_racer_speed_forward); } + if(player.movement_y) { df += v_right * ((player.movement_y > 0) ? autocvar_g_vehicle_racer_speed_strafe : -autocvar_g_vehicle_racer_speed_strafe); } + } + ++#ifdef SVQC + if(self.sound_nexttime < time || self.sounds != 1) + { + self.sounds = 1; + self.sound_nexttime = time + 10.922667; //soundlength("vehicles/racer_move.wav"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/racer_move.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } ++#endif + } ++#ifdef SVQC + else + { + if(self.sound_nexttime < time || self.sounds != 0) + { + self.sounds = 0; + self.sound_nexttime = time + 11.888604; //soundlength("vehicles/racer_idle.wav"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/racer_idle.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } + } ++#endif + + // Afterburn - if (player.BUTTON_JUMP && racer.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * frametime)) ++ if (PHYS_INPUT_BUTTON_JUMP(player) && racer.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * PHYS_INPUT_TIMELENGTH)) + { ++#ifdef SVQC + if(time - racer.wait > 0.2) + pointparticles(particleeffectnum("wakizashi_booster_smoke"), self.origin - v_forward * 32, v_forward * vlen(self.velocity), 1); ++#endif + + racer.wait = time; + + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + { - racer.vehicle_energy -= autocvar_g_vehicle_racer_waterburn_cost * frametime; ++ racer.vehicle_energy -= autocvar_g_vehicle_racer_waterburn_cost * PHYS_INPUT_TIMELENGTH; + df += (v_forward * autocvar_g_vehicle_racer_waterburn_speed); + } + else + { - racer.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * frametime; ++ racer.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * PHYS_INPUT_TIMELENGTH; + df += (v_forward * autocvar_g_vehicle_racer_speed_afterburn); + } + ++#ifdef SVQC + if(racer.invincible_finished < time) + { + traceline(racer.origin, racer.origin - '0 0 256', MOVE_NORMAL, self); + if(trace_fraction != 1.0) + pointparticles(particleeffectnum("smoke_small"), trace_endpos, '0 0 0', 1); + + racer.invincible_finished = time + 0.1 + (random() * 0.1); + } + + if(racer.strength_finished < time) + { + racer.strength_finished = time + 10.922667; //soundlength("vehicles/racer_boost.wav"); + sound (racer.tur_head, CH_TRIGGER_SINGLE, "vehicles/racer_boost.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } ++#endif + } + else + { + racer.strength_finished = 0; + sound (racer.tur_head, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } + + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + racer.racer_watertime = time; + + float dforce = autocvar_g_vehicle_racer_downforce; + if(time - racer.racer_watertime <= 3) + dforce = autocvar_g_vehicle_racer_water_downforce; + + df -= v_up * (vlen(racer.velocity) * dforce); - player.movement = racer.velocity += df * frametime; ++ player.movement = racer.velocity += df * PHYS_INPUT_TIMELENGTH; + ++#ifdef SVQC + if(!forbidWeaponUse(player)) + if(player.BUTTON_ATCK) + if(time > racer.attack_finished_single) + if(racer.vehicle_energy >= autocvar_g_vehicle_racer_cannon_cost) + { + racer.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost; + racer.wait = time; + + crosshair_trace(player); + if(racer.cnt) + { + racer_fire_cannon("tag_fire1"); + racer.cnt = 0; + } + else + { + racer_fire_cannon("tag_fire2"); + racer.cnt = 1; + } + racer.attack_finished_single = time + autocvar_g_vehicle_racer_cannon_refire; + } + + if(autocvar_g_vehicle_racer_rocket_locktarget) + { + vehicles_locktarget((1 / autocvar_g_vehicle_racer_rocket_locking_time) * frametime, + (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * frametime, + autocvar_g_vehicle_racer_rocket_locked_time); + + if(self.lock_target) + { + if(racer.lock_strength == 1) + UpdateAuxiliaryXhair(player, real_origin(self.lock_target), '1 0 0', 0); + else if(self.lock_strength > 0.5) + UpdateAuxiliaryXhair(player, real_origin(self.lock_target), '0 1 0', 0); + else if(self.lock_strength < 0.5) + UpdateAuxiliaryXhair(player, real_origin(self.lock_target), '0 0 1', 0); + } + } + + if(!forbidWeaponUse(player)) + if(time > racer.delay) + if(player.BUTTON_ATCK2) + { + racer.misc_bulletcounter += 1; + racer.delay = time + 0.3; + + if(racer.misc_bulletcounter == 1) ++ { + racer_fire_rocket("tag_rocket_r", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world); ++ player.vehicle_ammo2 = 50; ++ } + else if(racer.misc_bulletcounter == 2) + { + racer_fire_rocket("tag_rocket_l", (racer.lock_strength == 1 && racer.lock_target) ? racer.lock_target : world); + racer.lock_strength = 0; + racer.lock_target = world; + racer.misc_bulletcounter = 0; - + racer.delay = time + autocvar_g_vehicle_racer_rocket_refire; + racer.lip = time; ++ player.vehicle_ammo2 = 0; + } + } - player.vehicle_reload1 = bound(0, 100 * ((time - racer.lip) / (racer.delay - racer.lip)), 100); ++ else if(racer.misc_bulletcounter == 0) ++ player.vehicle_ammo2 = 100; ++ ++ player.vehicle_reload2 = bound(0, 100 * ((time - racer.lip) / (racer.delay - racer.lip)), 100); + + if(racer.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(racer.dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, frametime, true); + + if(racer.vehicle_flags & VHF_HEALTHREGEN) + vehicles_regen(racer.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, frametime, false); + + if(racer.vehicle_flags & VHF_ENERGYREGEN) + vehicles_regen(racer.wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, frametime, false); + + + VEHICLE_UPDATE_PLAYER(player, health, racer); + VEHICLE_UPDATE_PLAYER(player, energy, racer); + + if(racer.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(player, shield, racer); + + player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; ++#endif ++ + setorigin(player,racer.origin + '0 0 32'); + player.velocity = racer.velocity; + + self = player; + return 1; +} + +void racer_think() +{ + self.nextthink = time; + + float pushdeltatime = time - self.lastpushtime; + if (pushdeltatime > 0.15) pushdeltatime = 0; + self.lastpushtime = time; + if(!pushdeltatime) return; + + tracebox(self.origin, self.mins, self.maxs, self.origin - ('0 0 1' * autocvar_g_vehicle_racer_springlength), MOVE_NOMONSTERS, self); + + vector df = self.velocity * -autocvar_g_vehicle_racer_friction; + df_z += (1 - trace_fraction) * autocvar_g_vehicle_racer_hoverpower + sin(time * 2) * (autocvar_g_vehicle_racer_springlength * 2); + + float forced = autocvar_g_vehicle_racer_upforcedamper; + + int cont = pointcontents(self.origin - '0 0 64'); + if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) + { + forced = autocvar_g_vehicle_racer_water_upforcedamper; + self.velocity_z += 200; + } + + self.velocity += df * pushdeltatime; + if(self.velocity_z > 0) + self.velocity_z *= 1 - forced * pushdeltatime; + + self.angles_x *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * pushdeltatime); + self.angles_z *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * pushdeltatime); + + CSQCMODEL_AUTOUPDATE(); +} + +void racer_exit(float eject) +{ + vector spot; + + self.think = racer_think; + self.nextthink = time; + self.movetype = MOVETYPE_BOUNCE; + sound (self.tur_head, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + + if(!self.owner) + return; + + makevectors(self.angles); + if(eject) + { + spot = self.origin + v_forward * 100 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + setorigin(self.owner , spot); + self.owner.velocity = (v_up + v_forward * 0.25) * 750; + self.owner.oldvelocity = self.owner.velocity; + } + else + { + if(vlen(self.velocity) > 2 * autocvar_sv_maxairspeed) + { + self.owner.velocity = normalize(self.velocity) * autocvar_sv_maxairspeed * 2; + self.owner.velocity_z += 200; + spot = self.origin + v_forward * 32 + '0 0 32'; + spot = vehicles_findgoodexit(spot); + } + else + { + self.owner.velocity = self.velocity * 0.5; + self.owner.velocity_z += 10; + spot = self.origin - v_forward * 200 + '0 0 32'; + spot = vehicles_findgoodexit(spot); + } + self.owner.oldvelocity = self.owner.velocity; + setorigin(self.owner , spot); + } + antilag_clear(self.owner); + self.owner = world; +} + +void racer_blowup() +{ + self.deadflag = DEAD_DEAD; + self.vehicle_exit(VHEF_NORMAL); + + RadiusDamage (self, self.enemy, autocvar_g_vehicle_racer_blowup_coredamage, + autocvar_g_vehicle_racer_blowup_edgedamage, + autocvar_g_vehicle_racer_blowup_radius, world, world, + autocvar_g_vehicle_racer_blowup_forceintensity, + DEATH_VH_WAKI_DEATH, world); + + self.nextthink = time + autocvar_g_vehicle_racer_respawntime; + self.think = vehicles_spawn; + self.movetype = MOVETYPE_NONE; + self.effects = EF_NODRAW; + + self.colormod = '0 0 0'; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + + setorigin(self, self.pos1); +} + +void racer_blowup_think() +{ + self.nextthink = time; + + if(time >= self.delay) + racer_blowup(); + + CSQCMODEL_AUTOUPDATE(); +} + +void racer_deadtouch() +{ + self.avelocity_x *= 0.7; + self.cnt -= 1; + if(self.cnt <= 0) + racer_blowup(); +} + +void spawnfunc_vehicle_racer() +{ + if(!autocvar_g_vehicle_racer) { remove(self); return; } + if(!vehicle_initialize(VEH_RACER, false)) { remove(self); return; } +} + - float v_racer(float req) ++#endif // SVQC ++ ++#ifdef CSQC ++#if 0 ++void racer_draw() ++{ ++ float pushdeltatime = time - self.lastpushtime; ++ if (pushdeltatime > 0.15) pushdeltatime = 0; ++ self.lastpushtime = time; ++ if(!pushdeltatime) return; ++ ++ tracebox(self.move_origin, self.mins, self.maxs, self.move_origin - ('0 0 1' * getstatf(STAT_VEH_RACER_SPRINGLENGTH)), MOVE_NOMONSTERS, self); ++ ++ vector df = self.move_velocity * -getstatf(STAT_VEH_RACER_FRICTION); ++ df_z += (1 - trace_fraction) * getstatf(STAT_VEH_RACER_HOVERPOWER) + sin(time * 2) * (getstatf(STAT_VEH_RACER_SPRINGLENGTH) * 2); ++ ++ float forced = getstatf(STAT_VEH_RACER_UPFORCEDAMPER); ++ ++ int cont = pointcontents(self.move_origin - '0 0 64'); ++ if(cont == CONTENT_WATER || cont == CONTENT_LAVA || cont == CONTENT_SLIME) ++ { ++ forced = getstatf(STAT_VEH_RACER_WATER_UPFORCEDAMPER); ++ self.move_velocity_z += 200; ++ } ++ ++ self.move_velocity += df * pushdeltatime; ++ if(self.move_velocity_z > 0) ++ self.move_velocity_z *= 1 - forced * pushdeltatime; ++ ++ self.move_angles_x *= 1 - (getstatf(STAT_VEH_RACER_ANGLESTABILIZER) * pushdeltatime); ++ self.move_angles_z *= 1 - (getstatf(STAT_VEH_RACER_ANGLESTABILIZER) * pushdeltatime); ++ ++ Movetype_Physics_MatchServer(false); ++} ++#endif ++#endif ++ ++bool v_racer(int req) +{ + switch(req) + { + case VR_IMPACT: + { ++ #ifdef SVQC + if(autocvar_g_vehicle_racer_bouncepain) + vehicles_impact(autocvar_g_vehicle_racer_bouncepain_x, autocvar_g_vehicle_racer_bouncepain_y, autocvar_g_vehicle_racer_bouncepain_z); ++ #endif + return true; + } ++ + case VR_ENTER: + { ++ #ifdef SVQC + self.movetype = MOVETYPE_BOUNCE; + self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_racer_health) * 100; + self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_racer_shield) * 100; + + if(self.owner.flagcarried) + setorigin(self.owner.flagcarried, '-190 0 96'); ++ #elif defined(CSQC) ++ ++ self.move_movetype = MOVETYPE_BOUNCE; ++ #endif + + return true; + } - case VR_THINK: - { - return true; - } - case VR_DEATH: - { - self.health = 0; - self.event_damage = func_null; - self.solid = SOLID_CORPSE; - self.takedamage = DAMAGE_NO; - self.deadflag = DEAD_DYING; - self.movetype = MOVETYPE_BOUNCE; - self.wait = time; - self.delay = 2 + time + random() * 3; - self.cnt = 1 + random() * 2; - self.touch = racer_deadtouch; - - pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1); - - if(random() < 0.5) - self.avelocity_z = 32; - else - self.avelocity_z = -32; - - self.avelocity_x = -vlen(self.velocity) * 0.2; - self.velocity += '0 0 700'; - self.colormod = '-0.5 -0.5 -0.5'; + - self.think = racer_blowup_think; - self.nextthink = time; - - return true; - } + case VR_SPAWN: + { ++ #ifdef SVQC + if(self.scale != 0.5) + { + if(autocvar_g_vehicle_racer_hovertype != 0) + racer_force_from_tag = vehicles_force_fromtag_maglev; + else + racer_force_from_tag = vehicles_force_fromtag_hover; + + // FIXME: this be hakkz, fix the models insted (scale body, add tag_viewport to the hudmodel). + self.scale = 0.5; + setattachment(self.vehicle_hudmodel, self, ""); + setattachment(self.vehicle_viewport, self, "tag_viewport"); + + self.mass = 900; + } + + self.think = racer_think; + self.nextthink = time; + self.vehicle_health = autocvar_g_vehicle_racer_health; + self.vehicle_shield = autocvar_g_vehicle_racer_shield; + + self.movetype = MOVETYPE_TOSS; + self.solid = SOLID_SLIDEBOX; + self.delay = time; + self.scale = 0.5; + + self.PlayerPhysplug = racer_frame; + + self.bouncefactor = autocvar_g_vehicle_racer_bouncefactor; + self.bouncestop = autocvar_g_vehicle_racer_bouncestop; + self.damageforcescale = 0.5; + self.vehicle_health = autocvar_g_vehicle_racer_health; + self.vehicle_shield = autocvar_g_vehicle_racer_shield; - ++ #endif ++ return true; ++ } ++ ++ case VR_DEATH: ++ { ++ #ifdef SVQC ++ self.SendEntity = func_null; // stop networking this racer (for now) ++ self.health = 0; ++ self.event_damage = func_null; ++ self.solid = SOLID_CORPSE; ++ self.takedamage = DAMAGE_NO; ++ self.deadflag = DEAD_DYING; ++ self.movetype = MOVETYPE_BOUNCE; ++ self.wait = time; ++ self.delay = 2 + time + random() * 3; ++ self.cnt = 1 + random() * 2; ++ self.touch = racer_deadtouch; ++ ++ Send_Effect("explosion_medium", self.origin, '0 0 0', 1); ++ ++ if(random() < 0.5) ++ self.avelocity_z = 32; ++ else ++ self.avelocity_z = -32; ++ ++ self.avelocity_x = -vlen(self.velocity) * 0.2; ++ self.velocity += '0 0 700'; ++ self.colormod = '-0.5 -0.5 -0.5'; ++ ++ self.think = racer_blowup_think; ++ self.nextthink = time; ++ #endif ++ return true; ++ } ++ ++#ifdef CSQC ++ case VR_HUD: ++ { ++ Vehicles_drawHUD("vehicle_racer", "vehicle_racer_weapon1", "vehicle_racer_weapon2", ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color, ++ vCROSS_GUIDE); + return true; + } ++#endif + case VR_SETUP: + { ++ #ifdef SVQC ++ self.vehicle_exit = racer_exit; ++ #endif ++ ++ #ifdef SVQC ++ // we have no need to network energy + if(autocvar_g_vehicle_racer_energy) + if(autocvar_g_vehicle_racer_energy_regen) + self.vehicle_flags |= VHF_ENERGYREGEN; + + if(autocvar_g_vehicle_racer_shield) + self.vehicle_flags |= VHF_HASSHIELD; + + if(autocvar_g_vehicle_racer_shield_regen) + self.vehicle_flags |= VHF_SHIELDREGEN; + + if(autocvar_g_vehicle_racer_health_regen) + self.vehicle_flags |= VHF_HEALTHREGEN; - - self.vehicle_exit = racer_exit; ++ + self.respawntime = autocvar_g_vehicle_racer_respawntime; + self.vehicle_health = autocvar_g_vehicle_racer_health; + self.vehicle_shield = autocvar_g_vehicle_racer_shield; + self.max_health = self.vehicle_health; - ++ #endif ++ ++ #ifdef CSQC ++ AuxiliaryXhair[0].axh_image = vCROSS_LOCK; // Rocket ++ #endif + return true; + } ++ + case VR_PRECACHE: + { ++ #ifdef SVQC + precache_sound ("weapons/lasergun_fire.wav"); + precache_sound ("weapons/rocket_fire.wav"); + + precache_sound ("vehicles/racer_idle.wav"); + precache_sound ("vehicles/racer_move.wav"); + precache_sound ("vehicles/racer_boost.wav"); + + precache_model ("models/vhshield.md3"); ++ #endif ++ + precache_model ("models/vehicles/wakizashi.dpm"); + precache_model ("models/vehicles/wakizashi_cockpit.dpm"); + return true; + } + } + + return true; +} + - #endif // SVQC - #ifdef CSQC - - #define waki_ico "gfx/vehicles/waki.tga" - #define waki_eng "gfx/vehicles/waki_e.tga" - #define waki_gun "gfx/vehicles/waki_guns.tga" - #define waki_rkt "gfx/vehicles/waki_rockets.tga" - #define waki_xhair "gfx/vehicles/axh-special1.tga" - - float v_racer(float req) - { - switch(req) - { - case VR_HUD: - { - if(autocvar_r_letterbox) - 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(waki_ico) * (autocvar_cl_vehicles_hudscale * 0.8); - picloc = picsize * 0.5 - pic2size * 0.5; - if(vh_health < 0.25) - drawpic(hudloc + picloc, waki_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, waki_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, waki_eng, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, waki_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, waki_rkt, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 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 = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; - if(energy < 0.2) - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - - // Bomb bar - picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale; - picloc = '450 140 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x, hudloc_y + picloc_y, picsize_x * reload1, vid_conheight); - drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawresetcliparea(); - // .. and icon - pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 130 0' * autocvar_cl_vehicles_hudscale; - if(reload1 != 1) - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '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; - } - case VR_SETUP: - { - AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga"; - AuxiliaryXhair[0].axh_scale = 0.25; - return true; - } - case VR_PRECACHE: - { - return true; - } - } - - return true; - } - - #endif // CSQC +#endif // REGISTER_VEHICLE diff --cc qcsrc/common/vehicles/unit/raptor.qc index 137bdccab,000000000..bff81b7d8 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/raptor.qc +++ b/qcsrc/common/vehicles/unit/raptor.qc @@@ -1,1234 -1,0 +1,1062 @@@ +#ifdef REGISTER_VEHICLE +REGISTER_VEHICLE( +/* VEH_##id */ RAPTOR, +/* function */ v_raptor, +/* spawnflags */ VHF_DMGSHAKE | VHF_DMGROLL, +/* mins,maxs */ '-80 -80 0', '80 80 70', +/* model */ "models/vehicles/raptor.dpm", +/* head_model */ "", +/* hud_model */ "models/vehicles/raptor_cockpit.dpm", +/* tags */ "", "tag_hud", "tag_camera", +/* netname */ "raptor", +/* fullname */ _("Raptor") +); +#else + - const int RSM_FIRST = 1; - const int RSM_BOMB = 1; - const int RSM_FLARE = 2; - const int RSM_LAST = 2; - +#ifdef SVQC +bool autocvar_g_vehicle_raptor; + +float autocvar_g_vehicle_raptor_respawntime; +float autocvar_g_vehicle_raptor_takeofftime; + +float autocvar_g_vehicle_raptor_movestyle; +float autocvar_g_vehicle_raptor_turnspeed; +float autocvar_g_vehicle_raptor_pitchspeed; +float autocvar_g_vehicle_raptor_pitchlimit; + +float autocvar_g_vehicle_raptor_speed_forward; +float autocvar_g_vehicle_raptor_speed_strafe; +float autocvar_g_vehicle_raptor_speed_up; +float autocvar_g_vehicle_raptor_speed_down; +float autocvar_g_vehicle_raptor_friction; + +float autocvar_g_vehicle_raptor_bomblets; +float autocvar_g_vehicle_raptor_bomblet_alt; +float autocvar_g_vehicle_raptor_bomblet_time; +float autocvar_g_vehicle_raptor_bomblet_damage; +float autocvar_g_vehicle_raptor_bomblet_spread; +float autocvar_g_vehicle_raptor_bomblet_edgedamage; +float autocvar_g_vehicle_raptor_bomblet_radius; +float autocvar_g_vehicle_raptor_bomblet_force; +float autocvar_g_vehicle_raptor_bomblet_explode_delay; +float autocvar_g_vehicle_raptor_bombs_refire; + +float autocvar_g_vehicle_raptor_flare_refire; +float autocvar_g_vehicle_raptor_flare_lifetime; +float autocvar_g_vehicle_raptor_flare_chase; +float autocvar_g_vehicle_raptor_flare_range; + +float autocvar_g_vehicle_raptor_cannon_turnspeed; +float autocvar_g_vehicle_raptor_cannon_turnlimit; +float autocvar_g_vehicle_raptor_cannon_pitchlimit_up; +float autocvar_g_vehicle_raptor_cannon_pitchlimit_down; + +float autocvar_g_vehicle_raptor_cannon_locktarget; +float autocvar_g_vehicle_raptor_cannon_locking_time; +float autocvar_g_vehicle_raptor_cannon_locking_releasetime; +float autocvar_g_vehicle_raptor_cannon_locked_time; +float autocvar_g_vehicle_raptor_cannon_predicttarget; + +float autocvar_g_vehicle_raptor_cannon_cost; +float autocvar_g_vehicle_raptor_cannon_damage; +float autocvar_g_vehicle_raptor_cannon_radius; +float autocvar_g_vehicle_raptor_cannon_refire; +float autocvar_g_vehicle_raptor_cannon_speed; +float autocvar_g_vehicle_raptor_cannon_spread; +float autocvar_g_vehicle_raptor_cannon_force; + +float autocvar_g_vehicle_raptor_energy; +float autocvar_g_vehicle_raptor_energy_regen; +float autocvar_g_vehicle_raptor_energy_regen_pause; + +float autocvar_g_vehicle_raptor_health; +float autocvar_g_vehicle_raptor_health_regen; +float autocvar_g_vehicle_raptor_health_regen_pause; + +float autocvar_g_vehicle_raptor_shield; +float autocvar_g_vehicle_raptor_shield_regen; +float autocvar_g_vehicle_raptor_shield_regen_pause; + +float autocvar_g_vehicle_raptor_bouncefactor; +float autocvar_g_vehicle_raptor_bouncestop; +vector autocvar_g_vehicle_raptor_bouncepain; + +.entity bomb1; +.entity bomb2; + +float raptor_altitude(float amax) +{ + tracebox(self.origin, self.mins, self.maxs, self.origin - ('0 0 1' * amax), MOVE_WORLDONLY, self); + return vlen(self.origin - trace_endpos); +} + +void raptor_bomblet_boom() +{ + RadiusDamage (self, self.realowner, autocvar_g_vehicle_raptor_bomblet_damage, + autocvar_g_vehicle_raptor_bomblet_edgedamage, + autocvar_g_vehicle_raptor_bomblet_radius, world, world, + autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB, world); + remove(self); +} + +void raptor_bomblet_touch() +{ + if(other == self.owner) + return; + + PROJECTILE_TOUCH; + self.think = raptor_bomblet_boom; + self.nextthink = time + random() * autocvar_g_vehicle_raptor_bomblet_explode_delay; +} + +void raptor_bomb_burst() +{ + if(self.cnt > time) + if(autocvar_g_vehicle_raptor_bomblet_alt) + { + self.nextthink = time; + traceline(self.origin, self.origin + (normalize(self.velocity) * autocvar_g_vehicle_raptor_bomblet_alt), MOVE_NORMAL, self); + if((trace_fraction == 1.0) || (vlen(self.origin - self.owner.origin) < autocvar_g_vehicle_raptor_bomblet_radius)) + { + UpdateCSQCProjectile(self); + return; + } + } + + entity bomblet; + float i; + + Damage_DamageInfo(self.origin, 0, 0, 0, '0 0 0', DEATH_VH_RAPT_FRAGMENT, 0, self); + + for(i = 0; i < autocvar_g_vehicle_raptor_bomblets; ++i) + { + bomblet = spawn(); + setorigin(bomblet, self.origin); + + bomblet.movetype = MOVETYPE_TOSS; + bomblet.touch = raptor_bomblet_touch; + bomblet.think = raptor_bomblet_boom; + bomblet.nextthink = time + 5; + bomblet.owner = self.owner; + bomblet.realowner = self.realowner; + bomblet.velocity = normalize(normalize(self.velocity) + (randomvec() * autocvar_g_vehicle_raptor_bomblet_spread)) * vlen(self.velocity); + + PROJECTILE_MAKETRIGGER(bomblet); + CSQCProjectile(bomblet, true, PROJECTILE_RAPTORBOMBLET, true); + } + + remove(self); +} + +void raptor_bombdrop() +{ + entity bomb_1, bomb_2; + + bomb_1 = spawn(); + bomb_2 = spawn(); + + setorigin(bomb_1, gettaginfo(self, gettagindex(self, "bombmount_left"))); + setorigin(bomb_2, gettaginfo(self, gettagindex(self, "bombmount_right"))); + + bomb_1.movetype = bomb_2.movetype = MOVETYPE_BOUNCE; + bomb_1.velocity = bomb_2.velocity = self.velocity; + bomb_1.touch = bomb_2.touch = raptor_bomb_burst; + bomb_1.think = bomb_2.think = raptor_bomb_burst; + bomb_1.cnt = bomb_2.cnt = time + 10; + + if(autocvar_g_vehicle_raptor_bomblet_alt) + bomb_1.nextthink = bomb_2.nextthink = time; + else + bomb_1.nextthink = bomb_2.nextthink = time + autocvar_g_vehicle_raptor_bomblet_time; + + bomb_1.owner = bomb_2.owner = self; + bomb_1.realowner = bomb_2.realowner = self.owner; + bomb_1.solid = bomb_2.solid = SOLID_BBOX; + bomb_1.gravity = bomb_2.gravity = 1; + + PROJECTILE_MAKETRIGGER(bomb_1); + PROJECTILE_MAKETRIGGER(bomb_2); + + CSQCProjectile(bomb_1, true, PROJECTILE_RAPTORBOMB, true); + CSQCProjectile(bomb_2, true, PROJECTILE_RAPTORBOMB, true); +} + + +void raptor_fire_cannon(entity gun, string tagname) +{ + vehicles_projectile("raptor_cannon_muzzleflash", "weapons/lasergun_fire.wav", + gettaginfo(gun, gettagindex(gun, tagname)), normalize(v_forward + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed, + autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force, 0, + DEATH_VH_RAPT_CANNON, PROJECTILE_RAPTORCANNON, 0, true, true, self.owner); +} + +void raptor_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 < 128) + if(hgt > 0) + self.frame = (hgt / 128) * 25; + + self.bomb1.gun1.avelocity_y = 90 + ((self.frame / 25) * 2000); + self.bomb1.gun2.avelocity_y = -self.bomb1.gun1.avelocity_y; + + if(hgt < 16) + { + self.movetype = MOVETYPE_TOSS; + self.think = vehicles_think; + self.frame = 0; + } + + self.nextthink = time; + + CSQCMODEL_AUTOUPDATE(); +} + +void raptor_exit(float eject) +{ + vector spot; + self.tur_head.exteriormodeltoclient = world; + + if(self.deadflag == DEAD_NO) + { + self.think = raptor_land; + self.nextthink = time; + } + + if(!self.owner) + return; + + makevectors(self.angles); + if(eject) + { + spot = self.origin + v_forward * 100 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + setorigin(self.owner , spot); + self.owner.velocity = (v_up + v_forward * 0.25) * 750; + self.owner.oldvelocity = self.owner.velocity; + } + else + { + if(vlen(self.velocity) > 2 * autocvar_sv_maxairspeed) + { + self.owner.velocity = normalize(self.velocity) * autocvar_sv_maxairspeed * 2; + self.owner.velocity_z += 200; + spot = self.origin + v_forward * 32 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + } + else + { + self.owner.velocity = self.velocity * 0.5; + self.owner.velocity_z += 10; + spot = self.origin - v_forward * 200 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + } + self.owner.oldvelocity = self.owner.velocity; + setorigin(self.owner , spot); + } + + antilag_clear(self.owner); + self.owner = world; +} + +void raptor_flare_touch() +{ + remove(self); +} + +void raptor_flare_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + self.health -= damage; + if(self.health <= 0) + remove(self); +} + +void raptor_flare_think() +{ + self.nextthink = time + 0.1; + entity _missile = findchainentity(enemy, self.owner); + while(_missile) + { + if(_missile.flags & FL_PROJECTILE) + if(vlen(self.origin - _missile.origin) < autocvar_g_vehicle_raptor_flare_range) + if(random() > autocvar_g_vehicle_raptor_flare_chase) + _missile.enemy = self; + _missile = _missile.chain; + } + + if(self.tur_impacttime < time) + remove(self); +} + +float raptor_frame() +{ + entity player, raptor; + float ftmp = 0; + vector df; + + if(intermission_running) + { + self.vehicle.velocity = '0 0 0'; + self.vehicle.avelocity = '0 0 0'; + return 1; + } + + player = self; + raptor = self.vehicle; + self = raptor; + + vehicles_painframe(); + /* + ftmp = vlen(self.velocity); + if(ftmp > autocvar_g_vehicle_raptor_speed_forward) + ftmp = 1; + else + ftmp = ftmp / autocvar_g_vehicle_raptor_speed_forward; + */ + + if(self.sound_nexttime < time) + { + self.sound_nexttime = time + 7.955812; + //sound (self.tur_head, CH_TRIGGER_SINGLE, "vehicles/raptor_fly.wav", 1 - ftmp, ATTEN_NORM ); + sound (self, CH_TRIGGER_SINGLE, "vehicles/raptor_speed.wav", 1, ATTEN_NORM); + self.wait = ftmp; + } + /* + else if(fabs(ftmp - self.wait) > 0.2) + { + sound (self.tur_head, CH_TRIGGER_SINGLE, "", 1 - ftmp, ATTEN_NORM ); + sound (self, CH_TRIGGER_SINGLE, "", ftmp, ATTEN_NORM); + self.wait = ftmp; + } + */ + + if(raptor.deadflag != DEAD_NO) + { + self = player; + player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; + return 1; + } + crosshair_trace(player); + ++ //if(time - self.lastteleporttime < 1) ++ //{ ++ if(raptor.angles_z > 50 || raptor.angles_z < -50) ++ { ++ if(player.BUTTON_JUMP) ++ { ++ player.BUTTON_CROUCH = true; ++ player.BUTTON_JUMP = false; ++ } ++ } ++ //} ++ + vector vang; + vang = raptor.angles; + df = vectoangles(normalize(trace_endpos - self.origin + '0 0 32')); + vang_x *= -1; + df_x *= -1; + if(df_x > 180) df_x -= 360; + if(df_x < -180) df_x += 360; + if(df_y > 180) df_y -= 360; + if(df_y < -180) df_y += 360; + + ftmp = shortangle_f(player.v_angle_y - vang_y, vang_y); + if(ftmp > 180) ftmp -= 360; if(ftmp < -180) ftmp += 360; + raptor.avelocity_y = bound(-autocvar_g_vehicle_raptor_turnspeed, ftmp + raptor.avelocity_y * 0.9, autocvar_g_vehicle_raptor_turnspeed); + + // Pitch + ftmp = 0; + if(player.movement_x > 0 && vang_x < autocvar_g_vehicle_raptor_pitchlimit) ftmp = 5; + else if(player.movement_x < 0 && vang_x > -autocvar_g_vehicle_raptor_pitchlimit) ftmp = -20; + + df_x = bound(-autocvar_g_vehicle_raptor_pitchlimit, df_x , autocvar_g_vehicle_raptor_pitchlimit); + ftmp = vang_x - bound(-autocvar_g_vehicle_raptor_pitchlimit, df_x + ftmp, autocvar_g_vehicle_raptor_pitchlimit); + raptor.avelocity_x = bound(-autocvar_g_vehicle_raptor_pitchspeed, ftmp + raptor.avelocity_x * 0.9, autocvar_g_vehicle_raptor_pitchspeed); + + raptor.angles_x = anglemods(raptor.angles_x); + raptor.angles_y = anglemods(raptor.angles_y); + raptor.angles_z = anglemods(raptor.angles_z); + + if(autocvar_g_vehicle_raptor_movestyle == 1) + makevectors('0 1 0' * raptor.angles_y); + else + makevectors(player.v_angle); + + df = raptor.velocity * -autocvar_g_vehicle_raptor_friction; + + if(player.movement_x != 0) + { + if(player.movement_x > 0) + df += v_forward * autocvar_g_vehicle_raptor_speed_forward; + else if(player.movement_x < 0) + df -= v_forward * autocvar_g_vehicle_raptor_speed_forward; + } + + if(player.movement_y != 0) + { + if(player.movement_y < 0) + df -= v_right * autocvar_g_vehicle_raptor_speed_strafe; + else if(player.movement_y > 0) + df += v_right * autocvar_g_vehicle_raptor_speed_strafe; + + raptor.angles_z = bound(-30,raptor.angles_z + (player.movement_y / autocvar_g_vehicle_raptor_speed_strafe),30); + } + else + { + raptor.angles_z *= 0.95; + if(raptor.angles_z >= -1 && raptor.angles_z <= -1) + raptor.angles_z = 0; + } + + if(player.BUTTON_CROUCH) + df -= v_up * autocvar_g_vehicle_raptor_speed_down; + else if (player.BUTTON_JUMP) + df += v_up * autocvar_g_vehicle_raptor_speed_up; + + raptor.velocity += df * frametime; + player.velocity = player.movement = raptor.velocity; + setorigin(player, raptor.origin + '0 0 32'); + + player.vehicle_weapon2mode = raptor.vehicle_weapon2mode; + + vector vf, ad; + // Target lock & predict + if(autocvar_g_vehicle_raptor_cannon_locktarget == 2) + { + if(raptor.gun1.lock_time < time || raptor.gun1.enemy.deadflag) + raptor.gun1.enemy = world; + + if(trace_ent) + if(trace_ent.movetype) + if(trace_ent.takedamage) + if(!trace_ent.deadflag) + { + if(teamplay) + { + if(trace_ent.team != player.team) + { + raptor.gun1.enemy = trace_ent; + raptor.gun1.lock_time = time + 5; + } + } + else + { + raptor.gun1.enemy = trace_ent; + raptor.gun1.lock_time = time + 0.5; + } + } + + if(raptor.gun1.enemy) + { + float distance, impact_time; + + vf = real_origin(raptor.gun1.enemy); + UpdateAuxiliaryXhair(player, vf, '1 0 0', 1); + vector _vel = raptor.gun1.enemy.velocity; + if(raptor.gun1.enemy.movetype == MOVETYPE_WALK) + _vel_z *= 0.1; + + if(autocvar_g_vehicle_raptor_cannon_predicttarget) + { + ad = vf; + distance = vlen(ad - player.origin); + impact_time = distance / autocvar_g_vehicle_raptor_cannon_speed; + ad = vf + _vel * impact_time; + trace_endpos = ad; + } + else + trace_endpos = vf; + } + } + else if(autocvar_g_vehicle_raptor_cannon_locktarget == 1) + { + + vehicles_locktarget((1 / autocvar_g_vehicle_raptor_cannon_locking_time) * frametime, + (1 / autocvar_g_vehicle_raptor_cannon_locking_releasetime) * frametime, + autocvar_g_vehicle_raptor_cannon_locked_time); + + if(self.lock_target != world) + if(autocvar_g_vehicle_raptor_cannon_predicttarget) + if(self.lock_strength == 1) + { + float i, distance, impact_time; + + vf = real_origin(raptor.lock_target); + ad = vf; + for(i = 0; i < 4; ++i) + { + distance = vlen(ad - raptor.origin); + impact_time = distance / autocvar_g_vehicle_raptor_cannon_speed; + ad = vf + raptor.lock_target.velocity * impact_time; + } + trace_endpos = ad; + } + + if(self.lock_target) + { + if(raptor.lock_strength == 1) + UpdateAuxiliaryXhair(player, real_origin(raptor.lock_target), '1 0 0', 1); + else if(self.lock_strength > 0.5) + UpdateAuxiliaryXhair(player, real_origin(raptor.lock_target), '0 1 0', 1); + else if(self.lock_strength < 0.5) + UpdateAuxiliaryXhair(player, real_origin(raptor.lock_target), '0 0 1', 1); + } + } + + + vehicle_aimturret(raptor, trace_endpos, raptor.gun1, "fire1", + autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1, autocvar_g_vehicle_raptor_cannon_pitchlimit_up, + autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed); + + vehicle_aimturret(raptor, trace_endpos, raptor.gun2, "fire1", + autocvar_g_vehicle_raptor_cannon_pitchlimit_down * -1, autocvar_g_vehicle_raptor_cannon_pitchlimit_up, + autocvar_g_vehicle_raptor_cannon_turnlimit * -1, autocvar_g_vehicle_raptor_cannon_turnlimit, autocvar_g_vehicle_raptor_cannon_turnspeed); + + /* + ad = ad * 0.5; + v_forward = vf * 0.5; + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, raptor); + UpdateAuxiliaryXhair(player, trace_endpos, '0 1 0', 0); + */ + + if(!forbidWeaponUse(player)) + if(player.BUTTON_ATCK) + if(raptor.attack_finished_single <= time) + if(raptor.vehicle_energy > autocvar_g_vehicle_raptor_cannon_cost) + { + raptor.misc_bulletcounter += 1; + raptor.attack_finished_single = time + autocvar_g_vehicle_raptor_cannon_refire; + if(raptor.misc_bulletcounter <= 2) + raptor_fire_cannon(self.gun1, "fire1"); + else if(raptor.misc_bulletcounter == 3) + raptor_fire_cannon(self.gun2, "fire1"); + else + { + raptor.attack_finished_single = time + autocvar_g_vehicle_raptor_cannon_refire * 2; + raptor_fire_cannon(self.gun2, "fire1"); + raptor.misc_bulletcounter = 0; + } + raptor.vehicle_energy -= autocvar_g_vehicle_raptor_cannon_cost; + self.cnt = time; + } + + if(self.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(raptor.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, frametime, true); + + if(self.vehicle_flags & VHF_HEALTHREGEN) + vehicles_regen(raptor.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, frametime, false); + + if(self.vehicle_flags & VHF_ENERGYREGEN) + vehicles_regen(raptor.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, frametime, false); + + if(!forbidWeaponUse(player)) + if(raptor.vehicle_weapon2mode == RSM_BOMB) + { + if(time > raptor.lip + autocvar_g_vehicle_raptor_bombs_refire) + if(player.BUTTON_ATCK2) + { + raptor_bombdrop(); + raptor.delay = time + autocvar_g_vehicle_raptor_bombs_refire; + raptor.lip = time; + } + } + else + { + if(time > raptor.lip + autocvar_g_vehicle_raptor_flare_refire) + if(player.BUTTON_ATCK2) + { + float i; + entity _flare; + + for(i = 0; i < 3; ++i) + { + _flare = spawn(); + setmodel(_flare, "models/runematch/rune.mdl"); + _flare.effects = EF_LOWPRECISION | EF_FLAME; + _flare.scale = 0.5; + setorigin(_flare, self.origin - '0 0 16'); + _flare.movetype = MOVETYPE_TOSS; + _flare.gravity = 0.15; + _flare.velocity = 0.25 * raptor.velocity + (v_forward + randomvec() * 0.25)* -500; + _flare.think = raptor_flare_think; + _flare.nextthink = time; + _flare.owner = raptor; + _flare.solid = SOLID_CORPSE; + _flare.takedamage = DAMAGE_YES; + _flare.event_damage = raptor_flare_damage; + _flare.health = 20; + _flare.tur_impacttime = time + autocvar_g_vehicle_raptor_flare_lifetime; + _flare.touch = raptor_flare_touch; + } + raptor.delay = time + autocvar_g_vehicle_raptor_flare_refire; + raptor.lip = time; + } + } + + raptor.bomb1.alpha = raptor.bomb2.alpha = (time - raptor.lip) / (raptor.delay - raptor.lip); + player.vehicle_reload2 = bound(0, raptor.bomb1.alpha * 100, 100); ++ player.vehicle_ammo2 = (player.vehicle_reload2 == 100) ? 100 : 0; + + if(self.bomb1.cnt < time) + { + entity _missile = findchainentity(enemy, raptor); + float _incomming = 0; + while(_missile) + { + if(_missile.flags & FL_PROJECTILE) + if(MISSILE_IS_TRACKING(_missile)) + if(vlen(self.origin - _missile.origin) < 2 * autocvar_g_vehicle_raptor_flare_range) + ++_incomming; + + _missile = _missile.chain; + } + + if(_incomming) + sound(self, CH_PAIN_SINGLE, "vehicles/missile_alarm.wav", VOL_BASE, ATTEN_NONE); + + self.bomb1.cnt = time + 1; + } + + + VEHICLE_UPDATE_PLAYER(player, health, raptor); + VEHICLE_UPDATE_PLAYER(player, energy, raptor); + if(self.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(player, shield, raptor); + + player.BUTTON_ATCK = player.BUTTON_ATCK2 = player.BUTTON_CROUCH = 0; + + self = player; + return 1; +} + +float raptor_takeoff() +{ + entity player, raptor; + + player = self; + raptor = self.vehicle; + self = raptor; + + self.nextthink = time; + CSQCMODEL_AUTOUPDATE(); + self.nextthink = 0; // will this work? + + if(self.sound_nexttime < time) + { + self.sound_nexttime = time + 7.955812; //soundlength("vehicles/raptor_fly.wav"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/raptor_speed.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } + + // Takeoff sequense + if(raptor.frame < 25) + { + raptor.frame += 25 / (autocvar_g_vehicle_raptor_takeofftime / sys_frametime); + raptor.velocity_z = min(raptor.velocity_z * 1.5, 256); + self.bomb1.gun1.avelocity_y = 90 + ((raptor.frame / 25) * 25000); + self.bomb1.gun2.avelocity_y = -self.bomb1.gun1.avelocity_y; + player.BUTTON_ATCK = player.BUTTON_ATCK2 = player.BUTTON_CROUCH = 0; + + setorigin(player, raptor.origin + '0 0 32'); + } + else + player.PlayerPhysplug = raptor_frame; + + if(self.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(raptor.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, frametime, true); + + if(self.vehicle_flags & VHF_HEALTHREGEN) + vehicles_regen(raptor.dmg_time, vehicle_health, autocvar_g_vehicle_raptor_health, autocvar_g_vehicle_raptor_health_regen_pause, autocvar_g_vehicle_raptor_health_regen, frametime, false); + + if(self.vehicle_flags & VHF_ENERGYREGEN) + vehicles_regen(raptor.cnt, vehicle_energy, autocvar_g_vehicle_raptor_energy, autocvar_g_vehicle_raptor_energy_regen_pause, autocvar_g_vehicle_raptor_energy_regen, frametime, false); + + + raptor.bomb1.alpha = raptor.bomb2.alpha = (time - raptor.lip) / (raptor.delay - raptor.lip); + player.vehicle_reload2 = bound(0, raptor.bomb1.alpha * 100, 100); ++ player.vehicle_ammo2 = (player.vehicle_reload2 == 100) ? 100 : 0; + + VEHICLE_UPDATE_PLAYER(player, health, raptor); + VEHICLE_UPDATE_PLAYER(player, energy, raptor); + if(self.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(player, shield, raptor); + + player.BUTTON_ATCK = player.BUTTON_ATCK2 = player.BUTTON_CROUCH = 0; + self = player; + return 1; +} + +void raptor_blowup() +{ + self.deadflag = DEAD_DEAD; + self.vehicle_exit(VHEF_NORMAL); + RadiusDamage (self, self.enemy, 250, 15, 250, world, world, 250, DEATH_VH_RAPT_DEATH, world); + + self.alpha = -1; + self.movetype = MOVETYPE_NONE; + self.effects = EF_NODRAW; + self.colormod = '0 0 0'; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + + setorigin(self, self.pos1); + self.touch = func_null; + self.nextthink = 0; +} + +void raptor_diethink() +{ + if(time >= self.wait) + self.think = raptor_blowup; + + if(random() < 0.05) + { + 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); ++ Send_Effect("explosion_small", randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); + } + self.nextthink = time; + + CSQCMODEL_AUTOUPDATE(); +} + +// If we dont do this ever now and then, the raptors rotors +// stop working, presumably due to angle overflow. cute. +void raptor_rotor_anglefix() +{ + self.gun1.angles_y = anglemods(self.gun1.angles_y); + self.gun2.angles_y = anglemods(self.gun2.angles_y); + self.nextthink = time + 15; +} + +float raptor_impulse(float _imp) +{ + switch(_imp) + { + case 1: + case 230: + self.vehicle.vehicle_weapon2mode = RSM_BOMB; + CSQCVehicleSetup(self, 0); + return true; + case 2: + case 231: + self.vehicle.vehicle_weapon2mode = RSM_FLARE; + CSQCVehicleSetup(self, 0); + return true; + + case 10: + case 15: + case 18: + self.vehicle.vehicle_weapon2mode += 1; + if(self.vehicle.vehicle_weapon2mode > RSM_LAST) + self.vehicle.vehicle_weapon2mode = RSM_FIRST; + + CSQCVehicleSetup(self, 0); + return true; + case 11: + case 12: + case 16: + case 19: + self.vehicle.vehicle_weapon2mode -= 1; + if(self.vehicle.vehicle_weapon2mode < RSM_FIRST) + self.vehicle.vehicle_weapon2mode = RSM_LAST; + + CSQCVehicleSetup(self, 0); + return true; + + /* + case 17: // toss gun, could be used to exit? + break; + case 20: // Manual minigun reload? + break; + */ + } + return false; +} + +void spawnfunc_vehicle_raptor() +{ + if(!autocvar_g_vehicle_raptor) { remove(self); return; } + if(!vehicle_initialize(VEH_RAPTOR, false)) { remove(self); return; } +} + +float v_raptor(float req) +{ + switch(req) + { + case VR_IMPACT: + { + if(autocvar_g_vehicle_raptor_bouncepain) + vehicles_impact(autocvar_g_vehicle_raptor_bouncepain_x, autocvar_g_vehicle_raptor_bouncepain_y, autocvar_g_vehicle_raptor_bouncepain_z); + + return true; + } + case VR_ENTER: + { + self.vehicle_weapon2mode = RSM_BOMB; + self.owner.PlayerPhysplug = raptor_takeoff; + self.movetype = MOVETYPE_BOUNCEMISSILE; + self.solid = SOLID_SLIDEBOX; + self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_raptor_health) * 100; + self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_raptor_shield) * 100; + self.velocity_z = 1; // Nudge upwards to takeoff sequense can work. + self.tur_head.exteriormodeltoclient = self.owner; + + self.delay = time + autocvar_g_vehicle_raptor_bombs_refire; + self.lip = time; + + if(self.owner.flagcarried) + setorigin(self.owner.flagcarried, '-20 0 96'); + + CSQCVehicleSetup(self.owner, 0); + return true; + } + case VR_THINK: + { + return true; + } + case VR_DEATH: + { + self.health = 0; + self.event_damage = func_null; + self.solid = SOLID_CORPSE; + self.takedamage = DAMAGE_NO; + self.deadflag = DEAD_DYING; + self.movetype = MOVETYPE_BOUNCE; + self.think = raptor_diethink; + self.nextthink = time; + self.wait = time + 5 + (random() * 5); + - pointparticles(particleeffectnum("explosion_medium"), findbetterlocation (self.origin, 16), '0 0 0', 1); ++ Send_Effect("explosion_medium", findbetterlocation (self.origin, 16), '0 0 0', 1); + + self.velocity_z += 600; + + self.avelocity = '0 0.5 1' * (random() * 400); + self.avelocity -= '0 0.5 1' * (random() * 400); + + self.colormod = '-0.5 -0.5 -0.5'; + self.touch = raptor_blowup; + return true; + } + case VR_SPAWN: + { + if(!self.gun1) + { + entity spinner; + vector ofs; + + //FIXME: Camera is in a bad place in HUD model. + //setorigin(self.vehicle_viewport, '25 0 5'); + + self.vehicles_impulse = raptor_impulse; + + self.frame = 0; + + self.bomb1 = spawn(); + self.bomb2 = spawn(); + self.gun1 = spawn(); + self.gun2 = spawn(); + + setmodel(self.bomb1,"models/vehicles/clusterbomb_folded.md3"); + setmodel(self.bomb2,"models/vehicles/clusterbomb_folded.md3"); + setmodel(self.gun1, "models/vehicles/raptor_gun.dpm"); + setmodel(self.gun2, "models/vehicles/raptor_gun.dpm"); + setmodel(self.tur_head, "models/vehicles/raptor_body.dpm"); + + setattachment(self.bomb1, self, "bombmount_left"); + setattachment(self.bomb2, self, "bombmount_right"); + setattachment(self.tur_head, self,"root"); + + // FIXMODEL Guns mounts to angled bones + self.bomb1.angles = self.angles; + self.angles = '0 0 0'; + // This messes up gun-aim, so work arround it. + //setattachment(self.gun1, self, "gunmount_left"); + ofs = gettaginfo(self, gettagindex(self, "gunmount_left")); + ofs -= self.origin; + setattachment(self.gun1, self, ""); + setorigin(self.gun1, ofs); + + //setattachment(self.gun2, self, "gunmount_right"); + ofs = gettaginfo(self, gettagindex(self, "gunmount_right")); + ofs -= self.origin; + setattachment(self.gun2, self, ""); + setorigin(self.gun2, ofs); + + self.angles = self.bomb1.angles; + self.bomb1.angles = '0 0 0'; + + spinner = spawn(); + spinner.owner = self; + setmodel(spinner,"models/vehicles/spinner.dpm"); + setattachment(spinner, self, "engine_left"); + spinner.movetype = MOVETYPE_NOCLIP; + spinner.avelocity = '0 90 0'; + self.bomb1.gun1 = spinner; + + spinner = spawn(); + spinner.owner = self; + setmodel(spinner,"models/vehicles/spinner.dpm"); + setattachment(spinner, self, "engine_right"); + spinner.movetype = MOVETYPE_NOCLIP; + spinner.avelocity = '0 -90 0'; + self.bomb1.gun2 = spinner; + + // Sigh. + self.bomb1.think = raptor_rotor_anglefix; + self.bomb1.nextthink = time; + + self.mass = 1 ; + } + + self.frame = 0; + self.vehicle_health = autocvar_g_vehicle_raptor_health; + self.vehicle_shield = autocvar_g_vehicle_raptor_shield; + self.movetype = MOVETYPE_TOSS; + self.solid = SOLID_SLIDEBOX; + self.vehicle_energy = 1; + + self.PlayerPhysplug = raptor_frame; + + self.bomb1.gun1.avelocity_y = 90; + self.bomb1.gun2.avelocity_y = -90; + + self.delay = time; + + self.bouncefactor = autocvar_g_vehicle_raptor_bouncefactor; + self.bouncestop = autocvar_g_vehicle_raptor_bouncestop; + self.damageforcescale = 0.25; + self.vehicle_health = autocvar_g_vehicle_raptor_health; + self.vehicle_shield = autocvar_g_vehicle_raptor_shield; + return true; + } + case VR_SETUP: + { + if(autocvar_g_vehicle_raptor_shield) + self.vehicle_flags |= VHF_HASSHIELD; + + if(autocvar_g_vehicle_raptor_shield_regen) + self.vehicle_flags |= VHF_SHIELDREGEN; + + if(autocvar_g_vehicle_raptor_health_regen) + self.vehicle_flags |= VHF_HEALTHREGEN; + + if(autocvar_g_vehicle_raptor_energy_regen) + self.vehicle_flags |= VHF_ENERGYREGEN; + + self.vehicle_exit = raptor_exit; + self.respawntime = autocvar_g_vehicle_raptor_respawntime; + self.vehicle_health = autocvar_g_vehicle_raptor_health; + self.vehicle_shield = autocvar_g_vehicle_raptor_shield; + self.max_health = self.vehicle_health; + + return true; + } + case VR_PRECACHE: + { + precache_model ("models/vehicles/raptor.dpm"); + precache_model ("models/vehicles/raptor_gun.dpm"); + precache_model ("models/vehicles/spinner.dpm"); + precache_model ("models/vehicles/raptor_cockpit.dpm"); + precache_model ("models/vehicles/clusterbomb_folded.md3"); + precache_model ("models/vehicles/raptor_body.dpm"); + + precache_sound ("vehicles/raptor_fly.wav"); + precache_sound ("vehicles/raptor_speed.wav"); + precache_sound ("vehicles/missile_alarm.wav"); + + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC - #define raptor_ico "gfx/vehicles/raptor.tga" - #define raptor_gun "gfx/vehicles/raptor_guns.tga" - #define raptor_bomb "gfx/vehicles/raptor_bombs.tga" - #define raptor_drop "gfx/vehicles/axh-dropcross.tga" + +void RaptorCBShellfragDraw() +{ + if(wasfreed(self)) + return; + + Movetype_Physics_MatchTicrate(autocvar_cl_gibs_ticrate, autocvar_cl_gibs_sloppy); + self.move_avelocity += randomvec() * 15; + self.renderflags = 0; + + if(self.cnt < time) + self.alpha = bound(0, self.nextthink - time, 1); + + if(self.alpha < ALPHA_MIN_VISIBLE) + remove(self); +} + +void RaptorCBShellfragToss(vector _org, vector _vel, vector _ang) +{ + entity sfrag; + + sfrag = spawn(); + setmodel(sfrag, "models/vehicles/clusterbomb_fragment.md3"); + setorigin(sfrag, _org); + + sfrag.move_movetype = MOVETYPE_BOUNCE; + sfrag.gravity = 0.15; + sfrag.solid = SOLID_CORPSE; + + sfrag.draw = RaptorCBShellfragDraw; + + sfrag.move_origin = sfrag.origin = _org; + sfrag.move_velocity = _vel; + sfrag.move_avelocity = prandomvec() * vlen(sfrag.move_velocity); + sfrag.angles = self.move_angles = _ang; + + sfrag.move_time = time; + sfrag.damageforcescale = 4; + + sfrag.nextthink = time + 3; + sfrag.cnt = time + 2; + sfrag.alpha = 1; + sfrag.drawmask = MASK_NORMAL; +} + +float v_raptor(float req) +{ + switch(req) + { + case VR_HUD: + { - if(autocvar_r_letterbox) - return true; - - vector picsize, hudloc = '0 0 0', pic2size, picloc; - string raptor_xhair; - - // Fetch health & ammo stats - HUD_GETVEHICLESTATS ++ string crosshair; + - 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); - - ammo1 *= 0.01; - ammo2 *= 0.01; - shield *= 0.01; - vh_health *= 0.01; - energy *= 0.01; - reload1 = reload2 * 0.01; - //reload2 *= 0.01; - - pic2size = draw_getimagesize(raptor_ico) * (autocvar_cl_vehicles_hudscale * 0.8); - picloc = picsize * 0.5 - pic2size * 0.5; - if(vh_health < 0.25) - drawpic(hudloc + picloc, raptor_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, raptor_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, raptor_bomb, pic2size, '1 1 1' * reload1 + '1 0 0' * (1 - reload1), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, raptor_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) ++ switch(weapon2mode) + { - 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 = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; - if(energy < 0.2) - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - - // Bomb bar - picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale; - picloc = '450 140 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x, hudloc_y + picloc_y, picsize_x * reload1, vid_conheight); - drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawresetcliparea(); - // .. and icon - pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 130 0' * autocvar_cl_vehicles_hudscale; - if(reload1 != 1) - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL); - - if(getstati(STAT_VEHICLESTAT_W2MODE) == RSM_FLARE) - { - raptor_xhair = "gfx/vehicles/axh-bracket.tga"; - } - else - { - raptor_xhair = "gfx/vehicles/axh-ring.tga"; - - // Bombing crosshair - if(!dropmark) - { - dropmark = spawn(); - dropmark.owner = self; - dropmark.gravity = 1; - } - - if(reload2 == 100) - { - vector where; - - setorigin(dropmark, pmove_org); - dropmark.velocity = pmove_vel; - tracetoss(dropmark, self); - - where = project_3d_to_2d(trace_endpos); - - setorigin(dropmark, trace_endpos); - picsize = draw_getimagesize(raptor_drop) * 0.2; - - if(!(where_z < 0 || where_x < 0 || where_y < 0 || where_x > vid_conwidth || where_y > vid_conheight)) - { - where_x -= picsize_x * 0.5; - where_y -= picsize_y * 0.5; - where_z = 0; - drawpic(where, raptor_drop, picsize, '0 2 0', 1, DRAWFLAG_ADDITIVE); - } - dropmark.cnt = time + 5; - } - else - { - vector where; - if(dropmark.cnt > time) - { - where = project_3d_to_2d(dropmark.origin); - picsize = draw_getimagesize(raptor_drop) * 0.25; - - if(!(where_z < 0 || where_x < 0 || where_y < 0 || where_x > vid_conwidth || where_y > vid_conheight)) - { - where_x -= picsize_x * 0.5; - where_y -= picsize_y * 0.5; - where_z = 0; - drawpic(where, raptor_drop, picsize, '2 0 0', 1, DRAWFLAG_ADDITIVE); - } - } - } - } - - if (scoreboard_showscores) - HUD_DrawScoreboard(); - else - { - picsize = draw_getimagesize(raptor_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), raptor_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); ++ case RSM_FLARE: crosshair = vCROSS_RAIN; break; ++ case RSM_BOMB: crosshair = vCROSS_BURST; break; ++ default: crosshair = vCROSS_BURST; + } + ++ Vehicles_drawHUD("vehicle_raptor", "vehicle_raptor_weapon1", "vehicle_raptor_weapon2", ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color, ++ crosshair); + return true; + } + case VR_SETUP: + { - AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-special2.tga"; - AuxiliaryXhair[0].axh_scale = 0.5; - - AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-bracket.tga"; - AuxiliaryXhair[1].axh_scale = 0.25; ++ AuxiliaryXhair[1].axh_image = vCROSS_LOCK; + return true; + } + case VR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --cc qcsrc/common/vehicles/unit/raptor.qh index 000000000,000000000..f24939ba9 new file mode 100644 --- /dev/null +++ b/qcsrc/common/vehicles/unit/raptor.qh @@@ -1,0 -1,0 +1,9 @@@ ++#ifndef RAPTOR_H ++#define RAPTOR_H ++ ++const int RSM_FIRST = 1; ++const int RSM_BOMB = 1; ++const int RSM_FLARE = 2; ++const int RSM_LAST = 2; ++ ++#endif diff --cc qcsrc/common/vehicles/unit/spiderbot.qc index 8e0904d82,000000000..0aa2ebe79 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/spiderbot.qc +++ b/qcsrc/common/vehicles/unit/spiderbot.qc @@@ -1,1142 -1,0 +1,985 @@@ +#ifdef REGISTER_VEHICLE +REGISTER_VEHICLE( +/* VEH_##id */ SPIDERBOT, +/* function */ v_spiderbot, +/* spawnflags */ VHF_DMGSHAKE, +/* mins,maxs */ '-75 -75 10', '75 75 125', +/* model */ "models/vehicles/spiderbot.dpm", +/* head_model */ "models/vehicles/spiderbot_top.dpm", +/* hud_model */ "models/vehicles/spiderbot_cockpit.dpm", +/* tags */ "tag_head", "tag_hud", "", +/* netname */ "spiderbot", +/* fullname */ _("Spiderbot") +); +#else + +const int SBRM_FIRST = 1; +const int SBRM_VOLLY = 1; +const int SBRM_GUIDE = 2; +const int SBRM_ARTILLERY = 3; +const int SBRM_LAST = 3; + +#ifdef SVQC +bool autocvar_g_vehicle_spiderbot; + +float autocvar_g_vehicle_spiderbot_respawntime; + +float autocvar_g_vehicle_spiderbot_speed_stop; +float autocvar_g_vehicle_spiderbot_speed_strafe; +float autocvar_g_vehicle_spiderbot_speed_walk; +float autocvar_g_vehicle_spiderbot_speed_run = 700; +float autocvar_g_vehicle_spiderbot_turnspeed; +float autocvar_g_vehicle_spiderbot_turnspeed_strafe; +float autocvar_g_vehicle_spiderbot_movement_inertia; + +float autocvar_g_vehicle_spiderbot_springlength; +float autocvar_g_vehicle_spiderbot_springup; +float autocvar_g_vehicle_spiderbot_springblend; +float autocvar_g_vehicle_spiderbot_tiltlimit; + +float autocvar_g_vehicle_spiderbot_head_pitchlimit_down; +float autocvar_g_vehicle_spiderbot_head_pitchlimit_up; +float autocvar_g_vehicle_spiderbot_head_turnlimit; +float autocvar_g_vehicle_spiderbot_head_turnspeed; + +int autocvar_g_vehicle_spiderbot_health; +float autocvar_g_vehicle_spiderbot_health_regen; +float autocvar_g_vehicle_spiderbot_health_regen_pause; + +int autocvar_g_vehicle_spiderbot_shield; +float autocvar_g_vehicle_spiderbot_shield_regen; +float autocvar_g_vehicle_spiderbot_shield_regen_pause; + +float autocvar_g_vehicle_spiderbot_minigun_damage; +float autocvar_g_vehicle_spiderbot_minigun_refire; +float autocvar_g_vehicle_spiderbot_minigun_spread; +int autocvar_g_vehicle_spiderbot_minigun_ammo_cost; +int autocvar_g_vehicle_spiderbot_minigun_ammo_max; +int autocvar_g_vehicle_spiderbot_minigun_ammo_regen; +float autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause; +float autocvar_g_vehicle_spiderbot_minigun_force; +float autocvar_g_vehicle_spiderbot_minigun_solidpenetration; + +float autocvar_g_vehicle_spiderbot_rocket_damage; +float autocvar_g_vehicle_spiderbot_rocket_force; +float autocvar_g_vehicle_spiderbot_rocket_radius; +float autocvar_g_vehicle_spiderbot_rocket_speed; +float autocvar_g_vehicle_spiderbot_rocket_spread; +float autocvar_g_vehicle_spiderbot_rocket_refire; +float autocvar_g_vehicle_spiderbot_rocket_refire2; +float autocvar_g_vehicle_spiderbot_rocket_reload; +float autocvar_g_vehicle_spiderbot_rocket_health; +float autocvar_g_vehicle_spiderbot_rocket_noise; +float autocvar_g_vehicle_spiderbot_rocket_turnrate; +float autocvar_g_vehicle_spiderbot_rocket_lifetime; + +vector autocvar_g_vehicle_spiderbot_bouncepain; + +void spiderbot_rocket_artillery() +{ + self.nextthink = time; + UpdateCSQCProjectile(self); +} + +void spiderbot_rocket_unguided() +{ + vector newdir, olddir; + + self.nextthink = time; + + olddir = normalize(self.velocity); + newdir = normalize(self.pos1 - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise; + self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed; + + UpdateCSQCProjectile(self); + + if (self.owner.deadflag != DEAD_NO || self.cnt < time || vlen(self.pos1 - self.origin) < 16) + self.use(); +} + +void spiderbot_rocket_guided() +{ + vector newdir, olddir; + + self.nextthink = time; + + if(!self.realowner.vehicle) + self.think = spiderbot_rocket_unguided; + + crosshair_trace(self.realowner); + olddir = normalize(self.velocity); + newdir = normalize(trace_endpos - self.origin) + randomvec() * autocvar_g_vehicle_spiderbot_rocket_noise; + self.velocity = normalize(olddir + newdir * autocvar_g_vehicle_spiderbot_rocket_turnrate) * autocvar_g_vehicle_spiderbot_rocket_speed; + + UpdateCSQCProjectile(self); + + if (self.owner.deadflag != DEAD_NO || self.cnt < time) + self.use(); +} + +void spiderbot_guide_release() +{ + entity rkt; + rkt = findchainentity(realowner, self.owner); + if(!rkt) + return; + + crosshair_trace(self.owner); + while(rkt) + { + if(rkt.think == spiderbot_rocket_guided) + { + rkt.pos1 = trace_endpos; + rkt.think = spiderbot_rocket_unguided; + } + rkt = rkt.chain; + } +} + +float spiberbot_calcartillery_flighttime; +vector spiberbot_calcartillery(vector org, vector tgt, float ht) +{ + float grav, sdist, zdist, vs, vz, jumpheight; + vector sdir; + + grav = autocvar_sv_gravity; + zdist = tgt_z - org_z; + sdist = vlen(tgt - org - zdist * '0 0 1'); + sdir = normalize(tgt - org - zdist * '0 0 1'); + + // how high do we need to go? + jumpheight = fabs(ht); + if(zdist > 0) + jumpheight = jumpheight + zdist; + + // push so high... + vz = sqrt(2 * grav * jumpheight); // NOTE: sqrt(positive)! + + // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump! + if(ht < 0) + if(zdist < 0) + vz = -vz; + + vector solution; + solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist" + // ALWAYS solvable because jumpheight >= zdist + if(!solution_z) + solution_y = solution_x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0) + if(zdist == 0) + solution_x = solution_y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually) + + if(zdist < 0) + { + // down-jump + if(ht < 0) + { + // almost straight line type + // jump apex is before the jump + // we must take the larger one + spiberbot_calcartillery_flighttime = solution_y; + } + else + { + // regular jump + // jump apex is during the jump + // we must take the larger one too + spiberbot_calcartillery_flighttime = solution_y; + } + } + else + { + // up-jump + if(ht < 0) + { + // almost straight line type + // jump apex is after the jump + // we must take the smaller one + spiberbot_calcartillery_flighttime = solution_x; + } + else + { + // regular jump + // jump apex is during the jump + // we must take the larger one + spiberbot_calcartillery_flighttime = solution_y; + } + } + vs = sdist / spiberbot_calcartillery_flighttime; + + // finally calculate the velocity + return sdir * vs + '0 0 1' * vz; +} + +void spiderbot_rocket_do() +{ + vector v; + entity rocket = world; + + if (self.wait != -10) + { + if (self.owner.BUTTON_ATCK2 && self.vehicle_weapon2mode == SBRM_GUIDE) + { + if (self.wait == 1) + if (self.tur_head.frame == 9 || self.tur_head.frame == 1) + { + if(self.gun2.cnt < time && self.tur_head.frame == 9) + self.tur_head.frame = 1; + + return; + } + self.wait = 1; + } + else + { + if(self.wait) + spiderbot_guide_release(); + + self.wait = 0; + } + } + + if(self.gun2.cnt > time) + return; + + if (self.tur_head.frame >= 9) + { + self.tur_head.frame = 1; + self.wait = 0; + } + + if(self.wait != -10) + if(!self.owner.BUTTON_ATCK2) + return; + + if(forbidWeaponUse(self.owner)) + return; + + v = gettaginfo(self.tur_head,gettagindex(self.tur_head,"tag_fire")); + + switch(self.vehicle_weapon2mode) + { + case SBRM_VOLLY: + rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", + v, normalize(randomvec() * autocvar_g_vehicle_spiderbot_rocket_spread + v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, + autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner); + crosshair_trace(self.owner); + float _dist = (random() * autocvar_g_vehicle_spiderbot_rocket_radius) + vlen(v - trace_endpos); + _dist -= (random() * autocvar_g_vehicle_spiderbot_rocket_radius) ; + rocket.nextthink = time + (_dist / autocvar_g_vehicle_spiderbot_rocket_speed); + rocket.think = vehicles_projectile_explode; + + if(self.owner.BUTTON_ATCK2 && self.tur_head.frame == 1) + self.wait = -10; + break; + case SBRM_GUIDE: + rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", + v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, + autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, false, self.owner); + crosshair_trace(self.owner); + rocket.pos1 = trace_endpos; + rocket.nextthink = time; + rocket.think = spiderbot_rocket_guided; + + + break; + case SBRM_ARTILLERY: + rocket = vehicles_projectile("spiderbot_rocket_launch", "weapons/rocket_fire.wav", + v, normalize(v_forward) * autocvar_g_vehicle_spiderbot_rocket_speed, + autocvar_g_vehicle_spiderbot_rocket_damage, autocvar_g_vehicle_spiderbot_rocket_radius, autocvar_g_vehicle_spiderbot_rocket_force, 1, + DEATH_VH_SPID_ROCKET, PROJECTILE_SPIDERROCKET, autocvar_g_vehicle_spiderbot_rocket_health, false, true, self.owner); + + crosshair_trace(self.owner); + + rocket.pos1 = trace_endpos + randomvec() * (0.75 * autocvar_g_vehicle_spiderbot_rocket_radius); + rocket.pos1_z = trace_endpos_z; + + traceline(v, v + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self); + float h1 = 0.75 * vlen(v - trace_endpos); + + //v = trace_endpos; + traceline(v , rocket.pos1 + '0 0 1' * MAX_SHOT_DISTANCE, MOVE_WORLDONLY, self); + float h2 = 0.75 * vlen(rocket.pos1 - v); + + rocket.velocity = spiberbot_calcartillery(v, rocket.pos1, ((h1 < h2) ? h1 : h2)); + rocket.movetype = MOVETYPE_TOSS; + rocket.gravity = 1; + //rocket.think = spiderbot_rocket_artillery; + break; + } + rocket.classname = "spiderbot_rocket"; + + rocket.cnt = time + autocvar_g_vehicle_spiderbot_rocket_lifetime; + + self.tur_head.frame += 1; + if (self.tur_head.frame == 9) + self.attack_finished_single = autocvar_g_vehicle_spiderbot_rocket_reload; + else + self.attack_finished_single = ((self.vehicle_weapon2mode == SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire); + + self.gun2.cnt = time + self.attack_finished_single; +} + +.float jump_delay; +float spiderbot_frame() +{ + vector ad, vf; + entity player, spider; + float ftmp; + + if(intermission_running) + { + self.vehicle.velocity = '0 0 0'; + self.vehicle.avelocity = '0 0 0'; + return 1; + } + + player = self; + spider = self.vehicle; + self = spider; + + vehicles_painframe(); + + player.BUTTON_ZOOM = 0; + player.BUTTON_CROUCH = 0; + player.switchweapon = 0; + player.vehicle_weapon2mode = spider.vehicle_weapon2mode; + + +#if 1 // 0 to enable per-gun impact aux crosshairs + // Avarage gun impact point's -> aux cross + ad = gettaginfo(spider.tur_head, gettagindex(spider.tur_head, "tag_hardpoint01")); + vf = v_forward; + ad += gettaginfo(spider.tur_head, gettagindex(spider.tur_head, "tag_hardpoint02")); + vf += v_forward; + ad = ad * 0.5; + v_forward = vf * 0.5; + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider); + UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 0); +#else + ad = gettaginfo(spider.gun1, gettagindex(spider.gun1, "barrels")); + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider); + UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 0); + vf = ad; + ad = gettaginfo(spider.gun2, gettagindex(spider.gun2, "barrels")); + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, spider); + UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload1) + ('0 1 0' * (1 - player.vehicle_reload1)), 1); + ad = 0.5 * (ad + vf); +#endif + + crosshair_trace(player); + ad = vectoangles(normalize(trace_endpos - ad)); + ad = AnglesTransform_ToAngles(AnglesTransform_LeftDivide(AnglesTransform_FromAngles(spider.angles), AnglesTransform_FromAngles(ad))) - spider.tur_head.angles; + ad = AnglesTransform_Normalize(ad, true); + //UpdateAuxiliaryXhair(player, trace_endpos, ('1 0 0' * player.vehicle_reload2) + ('0 1 0' * (1 - player.vehicle_reload2)), 2); + + // Rotate head + ftmp = autocvar_g_vehicle_spiderbot_head_turnspeed * sys_frametime; + ad_y = bound(-ftmp, ad_y, ftmp); + spider.tur_head.angles_y = bound(autocvar_g_vehicle_spiderbot_head_turnlimit * -1, spider.tur_head.angles_y + ad_y, autocvar_g_vehicle_spiderbot_head_turnlimit); + + // Pitch head + ad_x = bound(ftmp * -1, ad_x, ftmp); + spider.tur_head.angles_x = bound(autocvar_g_vehicle_spiderbot_head_pitchlimit_down, spider.tur_head.angles_x + ad_x, autocvar_g_vehicle_spiderbot_head_pitchlimit_up); + + + //fixedmakevectors(spider.angles); + makevectors(spider.angles + '-2 0 0' * spider.angles_x); + + movelib_groundalign4point(autocvar_g_vehicle_spiderbot_springlength, autocvar_g_vehicle_spiderbot_springup, autocvar_g_vehicle_spiderbot_springblend, autocvar_g_vehicle_spiderbot_tiltlimit); + + if(spider.flags & FL_ONGROUND) + spider.jump_delay = time; // reset now so movement can begin + + //if(spider.flags & FL_ONGROUND) + { + if(spider.flags & FL_ONGROUND) + if(spider.frame == 4 && self.tur_head.wait != 0) + { + sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_land.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + spider.frame = 5; + } + + if(!player.BUTTON_JUMP) + spider.BUTTON_JUMP = 0; + + if((spider.flags & FL_ONGROUND) && player.BUTTON_JUMP && !spider.BUTTON_JUMP && self.tur_head.wait < time) + { + sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_jump.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + //dprint("spiderbot_jump:", ftos(soundlength("vehicles/spiderbot_jump.wav")), "\n"); + self.delay = 0; + + self.tur_head.wait = time + 2; + spider.jump_delay = time + 2; + spider.BUTTON_JUMP = 1; // set spider's jump + //player.BUTTON_JUMP = 0; + + vector movefix = '0 0 0'; + if(player.movement_x > 0) movefix_x = 1; + if(player.movement_x < 0) movefix_x = -1; + if(player.movement_y > 0) movefix_y = 1; + if(player.movement_y < 0) movefix_y = -1; + + vector rt = movefix_y * v_right; + vector sd = movefix_x * v_forward; + if(movefix_y == 0 && movefix_x == 0) + sd = v_forward; // always do forward + + spider.flags &= ~FL_ONGROUND; + + spider.velocity = sd * 700 + rt * 600 + v_up * 600; + spider.frame = 4; + } + else if(time >= spider.jump_delay) + { + if(vlen(player.movement) == 0) + { + if(spider.flags & FL_ONGROUND) + { + if(self.sound_nexttime < time || self.delay != 3) + { + self.delay = 3; + self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_idle.wav"); + //dprint("spiderbot_idle:", ftos(soundlength("vehicles/spiderbot_idle.wav")), "\n"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_idle.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } + movelib_beak_simple(autocvar_g_vehicle_spiderbot_speed_stop); + spider.frame = 5; + } + } + else + { + // Turn Body + if(player.movement_x == 0 && player.movement_y != 0) + ftmp = autocvar_g_vehicle_spiderbot_turnspeed_strafe * sys_frametime; + else + ftmp = autocvar_g_vehicle_spiderbot_turnspeed * sys_frametime; + + ftmp = bound(-ftmp, spider.tur_head.angles_y, ftmp); + spider.angles_y = anglemods(spider.angles_y + ftmp); + spider.tur_head.angles_y -= ftmp; + + if(player.movement_x != 0) + { + if(player.movement_x > 0) + { + player.movement_x = 1; + if(spider.flags & FL_ONGROUND) + spider.frame = 0; + } + else if(player.movement_x < 0) + { + player.movement_x = -1; + if(spider.flags & FL_ONGROUND) + spider.frame = 1; + } + player.movement_y = 0; + float oldvelz = spider.velocity_z; + movelib_move_simple(normalize(v_forward * player.movement_x),((player.BUTTON_JUMP) ? autocvar_g_vehicle_spiderbot_speed_run : autocvar_g_vehicle_spiderbot_speed_walk),autocvar_g_vehicle_spiderbot_movement_inertia); + spider.velocity_z = oldvelz; + float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1); + if(spider.velocity_z <= 20) // not while jumping + spider.velocity_z -= g * sys_frametime * autocvar_sv_gravity; + if(spider.flags & FL_ONGROUND) + if(self.sound_nexttime < time || self.delay != 1) + { + self.delay = 1; + self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_walk.wav"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_walk.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + //dprint("spiderbot_walk:", ftos(soundlength("vehicles/spiderbot_walk.wav")), "\n"); + } + } + else if(player.movement_y != 0) + { + if(player.movement_y < 0) + { + player.movement_y = -1; + if(spider.flags & FL_ONGROUND) + spider.frame = 2; + } + else if(player.movement_y > 0) + { + player.movement_y = 1; + if(spider.flags & FL_ONGROUND) + spider.frame = 3; + } + + float oldvelz = spider.velocity_z; + movelib_move_simple(normalize(v_right * player.movement_y),autocvar_g_vehicle_spiderbot_speed_strafe,autocvar_g_vehicle_spiderbot_movement_inertia); + spider.velocity_z = oldvelz; + float g = ((autocvar_sv_gameplayfix_gravityunaffectedbyticrate) ? 0.5 : 1); + if(spider.velocity_z <= 20) // not while jumping + spider.velocity_z -= g * sys_frametime * autocvar_sv_gravity; + if(spider.flags & FL_ONGROUND) + if(self.sound_nexttime < time || self.delay != 2) + { + self.delay = 2; + self.sound_nexttime = time + 6.486500; //soundlength("vehicles/spiderbot_strafe.wav"); + sound (self, CH_TRIGGER_SINGLE, "vehicles/spiderbot_strafe.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + //dprint("spiderbot_strafe:", ftos(soundlength("vehicles/spiderbot_strafe.wav")), "\n"); + } + } + } + } + } + + self.angles_x = bound(-autocvar_g_vehicle_spiderbot_tiltlimit, self.angles_x, autocvar_g_vehicle_spiderbot_tiltlimit); + self.angles_z = bound(-autocvar_g_vehicle_spiderbot_tiltlimit, self.angles_z, autocvar_g_vehicle_spiderbot_tiltlimit); + + if(!forbidWeaponUse(player)) + if(player.BUTTON_ATCK) + { + spider.cnt = time; + if(spider.vehicle_ammo1 >= autocvar_g_vehicle_spiderbot_minigun_ammo_cost && spider.tur_head.attack_finished_single <= time) + { + entity gun; + vector v; + spider.misc_bulletcounter += 1; + + self = player; + + gun = (spider.misc_bulletcounter % 2) ? spider.gun1 : spider.gun2; + + v = gettaginfo(gun, gettagindex(gun, "barrels")); + v_forward = normalize(v_forward); + v += v_forward * 50; + + fireBullet(v, v_forward, autocvar_g_vehicle_spiderbot_minigun_spread, autocvar_g_vehicle_spiderbot_minigun_solidpenetration, + autocvar_g_vehicle_spiderbot_minigun_damage, autocvar_g_vehicle_spiderbot_minigun_force, DEATH_VH_SPID_MINIGUN, 0); + + sound (gun, CH_WEAPON_A, "weapons/uzi_fire.wav", VOL_BASE, ATTEN_NORM); + //trailparticles(self, particleeffectnum("spiderbot_minigun_trail"), v, trace_endpos); + pointparticles(particleeffectnum("spiderbot_minigun_muzzleflash"), v, v_forward * 2500, 1); + + self = spider; + + spider.vehicle_ammo1 -= autocvar_g_vehicle_spiderbot_minigun_ammo_cost; + spider.tur_head.attack_finished_single = time + autocvar_g_vehicle_spiderbot_minigun_refire; + player.vehicle_ammo1 = (spider.vehicle_ammo1 / autocvar_g_vehicle_spiderbot_minigun_ammo_max) * 100; + spider.gun1.angles_z += 45; + spider.gun2.angles_z -= 45; + if(spider.gun1.angles_z >= 360) + { + spider.gun1.angles_z = 0; + spider.gun2.angles_z = 0; + } + } + } + else + vehicles_regen(spider.cnt, vehicle_ammo1, autocvar_g_vehicle_spiderbot_minigun_ammo_max, + autocvar_g_vehicle_spiderbot_minigun_ammo_regen_pause, + autocvar_g_vehicle_spiderbot_minigun_ammo_regen, frametime, false); + + + spiderbot_rocket_do(); + + if(self.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(spider.dmg_time, vehicle_shield, autocvar_g_vehicle_spiderbot_shield, autocvar_g_vehicle_spiderbot_shield_regen_pause, autocvar_g_vehicle_spiderbot_shield_regen, frametime, true); + + if(self.vehicle_flags & VHF_HEALTHREGEN) + vehicles_regen(spider.dmg_time, vehicle_health, autocvar_g_vehicle_spiderbot_health, autocvar_g_vehicle_spiderbot_health_regen_pause, autocvar_g_vehicle_spiderbot_health_regen, frametime, false); + + player.BUTTON_ATCK = player.BUTTON_ATCK2 = 0; - player.vehicle_ammo2 = spider.tur_head.frame; ++ //player.vehicle_ammo2 = spider.tur_head.frame; ++ player.vehicle_ammo2 = (9 - spider.tur_head.frame) / 8 * 100; // Percentage, like ammo1 + + if(spider.gun2.cnt <= time) + player.vehicle_reload2 = 100; + else + player.vehicle_reload2 = 100 - ((spider.gun2.cnt - time) / spider.attack_finished_single) * 100; + + setorigin(player, spider.origin + '0 0 1' * spider.maxs_z); + player.velocity = spider.velocity; + + VEHICLE_UPDATE_PLAYER(player, health, spiderbot); + + if(self.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(player, shield, spiderbot); + + self = player; + return 1; +} + +void spiderbot_exit(float eject) +{ + entity e; + vector spot; + + e = findchain(classname,"spiderbot_rocket"); + while(e) + { + if(e.owner == self.owner) + { + e.realowner = self.owner; + e.owner = world; + } + e = e.chain; + } + + self.think = vehicles_think; + self.nextthink = time; + self.frame = 5; + self.movetype = MOVETYPE_WALK; + + if(!self.owner) + return; + + makevectors(self.angles); + if(eject) + { + spot = self.origin + v_forward * 100 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + setorigin(self.owner , spot); + self.owner.velocity = (v_up + v_forward * 0.25) * 750; + self.owner.oldvelocity = self.owner.velocity; + } + else + { + if(vlen(self.velocity) > autocvar_g_vehicle_spiderbot_speed_strafe) + { + self.owner.velocity = normalize(self.velocity) * vlen(self.velocity); + self.owner.velocity_z += 200; + spot = self.origin + v_forward * 128 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + } + else + { + self.owner.velocity = self.velocity * 0.5; + self.owner.velocity_z += 10; + spot = self.origin + v_forward * 256 + '0 0 64'; + spot = vehicles_findgoodexit(spot); + } + self.owner.oldvelocity = self.owner.velocity; + setorigin(self.owner , spot); + } + + antilag_clear(self.owner); + self.owner = world; +} + +void spiderbot_headfade() +{ + self.think = spiderbot_headfade; + self.nextthink = self.fade_time; + self.alpha = 1 - (time - self.fade_time) * self.fade_rate; + + if(self.cnt < time || self.alpha < 0.1) + { + if(self.alpha > 0.1) + { + sound (self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); - pointparticles(particleeffectnum("explosion_big"), self.origin + '0 0 100', '0 0 0', 1); ++ Send_Effect("explosion_big", self.origin + '0 0 100', '0 0 0', 1); + } + remove(self); + } +} + +void spiderbot_blowup() +{ + if(self.cnt > time) + { + 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); ++ Send_Effect("explosion_small", randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); + } + self.nextthink = time + 0.1; + return; + } + + entity h, g1, g2, b; + b = spawn(); + h = spawn(); + g1 = spawn(); + g2 = spawn(); + + setmodel(b, "models/vehicles/spiderbot.dpm"); + setmodel(h, "models/vehicles/spiderbot_top.dpm"); + setmodel(g1, "models/vehicles/spiderbot_barrels.dpm"); + setmodel(g2, "models/vehicles/spiderbot_barrels.dpm"); + + setorigin(b, self.origin); + b.frame = 11; + b.angles = self.angles; + setsize(b, self.mins, self.maxs); + + setorigin(h, gettaginfo(self, gettagindex(self, "tag_head"))); + h.movetype = MOVETYPE_BOUNCE; + h.solid = SOLID_BBOX; + h.velocity = v_up * (500 + random() * 500) + randomvec() * 128; + h.modelflags = MF_ROCKET; + h.effects = EF_FLAME | EF_LOWPRECISION; + h.avelocity = randomvec() * 360; + + h.alpha = 1; + h.cnt = time + (3.5 * random()); + h.fade_rate = 1 / min(self.respawntime, 10); + h.fade_time = time; + h.think = spiderbot_headfade; + h.nextthink = time; + + setorigin(g1, gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_hardpoint01"))); + g1.movetype = MOVETYPE_TOSS; + g1.solid = SOLID_CORPSE; + g1.velocity = v_forward * 700 + (randomvec() * 32); + g1.avelocity = randomvec() * 180; + + setorigin(g2, gettaginfo(self.tur_head, gettagindex(self.tur_head, "tag_hardpoint02"))); + g2.movetype = MOVETYPE_TOSS; + g2.solid = SOLID_CORPSE; + g2.velocity = v_forward * 700 + (randomvec() * 32); + g2.avelocity = randomvec() * 180; + + h.colormod = b.colormod = g1.colormod = g2.colormod = '-2 -2 -2'; + + SUB_SetFade(b, time + 5, min(self.respawntime, 1)); + //SUB_SetFade(h, time, min(self.respawntime, 10)); + SUB_SetFade(g1, time, min(self.respawntime, 10)); + SUB_SetFade(g2, time, min(self.respawntime, 10)); + + RadiusDamage (self, self.enemy, 250, 15, 250, world, world, 250, DEATH_VH_SPID_DEATH, world); + + self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = -1; + self.movetype = MOVETYPE_NONE; + self.deadflag = DEAD_DEAD; + self.solid = SOLID_NOT; + self.tur_head.effects &= ~EF_FLAME; + self.vehicle_hudmodel.viewmodelforclient = self; +} + +bool spiderbot_impulse(int _imp) +{ + switch(_imp) + { + case 1: + case 230: + self.vehicle.vehicle_weapon2mode = SBRM_VOLLY; + CSQCVehicleSetup(self, 0); + return true; + case 2: + case 231: + self.vehicle.vehicle_weapon2mode = SBRM_GUIDE; + CSQCVehicleSetup(self, 0); + return true; + case 3: + case 232: + case 251: + self.vehicle.vehicle_weapon2mode = SBRM_ARTILLERY; + CSQCVehicleSetup(self, 0); + return true; + + case 10: + case 15: + case 18: + self.vehicle.vehicle_weapon2mode += 1; + if(self.vehicle.vehicle_weapon2mode > SBRM_LAST) + self.vehicle.vehicle_weapon2mode = SBRM_FIRST; + + //centerprint(self, strcat("Rocket mode is ", ftos(self.vehicle.vehicle_weapon2mode))); + CSQCVehicleSetup(self, 0); + return true; + case 11: + case 12: + case 16: + case 19: + self.vehicle.vehicle_weapon2mode -= 1; + if(self.vehicle.vehicle_weapon2mode < SBRM_FIRST) + self.vehicle.vehicle_weapon2mode = SBRM_LAST; + + //centerprint(self, strcat("Rocket mode is ", ftos(self.vehicle.vehicle_weapon2mode))); + CSQCVehicleSetup(self, 0); + return true; + + /* + case 17: // toss gun, could be used to exit? + break; + case 20: // Manual minigun reload? + break; + */ + } + return false; +} + +void spawnfunc_vehicle_spiderbot() +{ + if(!autocvar_g_vehicle_spiderbot) { remove(self); return; } + if(!vehicle_initialize(VEH_SPIDERBOT, false)) { remove(self); return; } +} + +float v_spiderbot(float req) +{ + switch(req) + { + case VR_IMPACT: + { + if(autocvar_g_vehicle_spiderbot_bouncepain) + vehicles_impact(autocvar_g_vehicle_spiderbot_bouncepain_x, autocvar_g_vehicle_spiderbot_bouncepain_y, autocvar_g_vehicle_spiderbot_bouncepain_z); + + return true; + } + case VR_ENTER: + { + self.vehicle_weapon2mode = SBRM_GUIDE; + self.movetype = MOVETYPE_WALK; + CSQCVehicleSetup(self.owner, 0); + self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100; + self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_spiderbot_shield) * 100; + + if(self.owner.flagcarried) + { + setattachment(self.owner.flagcarried, self.tur_head, ""); + setorigin(self.owner.flagcarried, '-20 0 120'); + } + + return true; + } + case VR_THINK: + { + if(self.flags & FL_ONGROUND) + movelib_beak_simple(autocvar_g_vehicle_spiderbot_speed_stop); + + return true; + } + case VR_DEATH: + { + self.health = 0; + self.event_damage = func_null; + self.takedamage = DAMAGE_NO; + self.touch = func_null; + self.cnt = 3.4 + time + random() * 2; + self.think = spiderbot_blowup; + self.nextthink = time; + self.deadflag = DEAD_DYING; + self.frame = 5; + self.tur_head.effects |= EF_FLAME; + self.colormod = self.tur_head.colormod = '-1 -1 -1'; + self.frame = 10; + self.movetype = MOVETYPE_TOSS; + + CSQCModel_UnlinkEntity(); // networking the death scene would be a nightmare + + return true; + } + case VR_SPAWN: + { + if(!self.gun1) + { + self.vehicles_impulse = spiderbot_impulse; + self.gun1 = spawn(); + self.gun2 = spawn(); + setmodel(self.gun1, "models/vehicles/spiderbot_barrels.dpm"); + setmodel(self.gun2, "models/vehicles/spiderbot_barrels.dpm"); + setattachment(self.gun1, self.tur_head, "tag_hardpoint01"); + setattachment(self.gun2, self.tur_head, "tag_hardpoint02"); + self.gravity = 2; + self.mass = 5000; + } + + self.frame = 5; + self.tur_head.frame = 1; + self.movetype = MOVETYPE_WALK; + self.solid = SOLID_SLIDEBOX; + self.alpha = self.tur_head.alpha = self.gun1.alpha = self.gun2.alpha = 1; + self.tur_head.angles = '0 0 0'; + self.vehicle_exit = spiderbot_exit; + + setorigin(self, self.pos1 + '0 0 128'); + self.angles = self.pos2; + self.damageforcescale = 0.03; + self.vehicle_health = autocvar_g_vehicle_spiderbot_health; + self.vehicle_shield = autocvar_g_vehicle_spiderbot_shield; + + self.PlayerPhysplug = spiderbot_frame; + + return true; + } + case VR_SETUP: + { + if(autocvar_g_vehicle_spiderbot_shield) + self.vehicle_flags |= VHF_HASSHIELD; + + if(autocvar_g_vehicle_spiderbot_shield_regen) + self.vehicle_flags |= VHF_SHIELDREGEN; + + if(autocvar_g_vehicle_spiderbot_health_regen) + self.vehicle_flags |= VHF_HEALTHREGEN; + + self.respawntime = autocvar_g_vehicle_spiderbot_respawntime; + self.vehicle_health = autocvar_g_vehicle_spiderbot_health; + self.vehicle_shield = autocvar_g_vehicle_spiderbot_shield; + self.max_health = self.vehicle_health; + self.pushable = true; // spiderbot can use jumppads + + return true; + } + case VR_PRECACHE: + { + precache_model ("models/vhshield.md3"); + precache_model ("models/vehicles/spiderbot.dpm"); + precache_model ("models/vehicles/spiderbot_top.dpm"); + precache_model ("models/vehicles/spiderbot_barrels.dpm"); + precache_model ("models/vehicles/spiderbot_cockpit.dpm"); + precache_model ( "models/uziflash.md3"); + + precache_sound ("weapons/uzi_fire.wav" ); + precache_sound ("weapons/rocket_impact.wav"); + + precache_sound ("vehicles/spiderbot_die.wav"); + precache_sound ("vehicles/spiderbot_idle.wav"); + precache_sound ("vehicles/spiderbot_jump.wav"); + precache_sound ("vehicles/spiderbot_strafe.wav"); + precache_sound ("vehicles/spiderbot_walk.wav"); + precache_sound ("vehicles/spiderbot_land.wav"); + return true; + } + } + + return true; +} + +#endif // SVQC +#ifdef CSQC +float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6; +float autocvar_cl_vehicle_spiderbot_cross_size = 1; + - #define spider_ico "gfx/vehicles/sbot.tga" - #define spider_rkt "gfx/vehicles/sbot_rpods.tga" - #define spider_mgun "gfx/vehicles/sbot_mguns.tga" - string spider_xhair; // = "gfx/vehicles/axh-special1.tga"; - +float v_spiderbot(float req) +{ + switch(req) + { + case VR_HUD: + { - if(autocvar_r_letterbox) - return true; - - vector picsize, hudloc = '0 0 0', pic2size, picloc; - float i; - - // 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); - - ammo1 *= 0.01; - shield *= 0.01; - vh_health *= 0.01; - reload2 *= 0.01; ++ string crosshair; + - pic2size = draw_getimagesize(spider_ico) * (autocvar_cl_vehicles_hudscale * 0.8); - picloc = picsize * 0.5 - pic2size * 0.5; - if(vh_health < 0.25) - drawpic(hudloc + picloc, spider_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, spider_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, spider_rkt, pic2size, '1 1 1' * reload2 + '1 0 0' * (1 - reload2), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, spider_mgun, pic2size, '1 1 1' * ammo1 + '1 0 0' * (1 - ammo1), 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 ++ switch(weapon2mode) + { - 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_PAIN_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_PAIN_SINGLE, "misc/null.wav"); - alarm2time = 0; - } ++ case SBRM_VOLLY: crosshair = vCROSS_BURST; break; ++ case SBRM_GUIDE: crosshair = vCROSS_GUIDE; break; ++ case SBRM_ARTILLERY: crosshair = vCROSS_RAIN; break; ++ default: crosshair = vCROSS_BURST; + } + - // Minigun 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(); - // .. and icon - picsize = draw_getimagesize(hud_ammo1_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; - if(ammo1 < 0.2) - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo1_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - - // Rocket ammo bar - picsize = draw_getimagesize(hud_ammo2_bar) * autocvar_cl_vehicles_hudscale; - ammo1 = picsize_x / 8; - picloc = '450 140 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x, hudloc_y + picloc_y, picsize_x * reload2, vid_conheight); - drawpic(hudloc + picloc, hud_ammo2_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawresetcliparea(); - - // .. and icons - pic2size = 0.35 * draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale; - picloc_x -= pic2size_x; - picloc_y += pic2size_y * 2.25; - if(ammo2 == 9) - { - for(i = 1; i < 9; ++i) - { - picloc_x += ammo1; - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((8 * reload2 <= i) ? '0 0 0' : '1 1 1'), 0.75, DRAWFLAG_NORMAL); - } - } - else - { - for(i = 1; i < 9; ++i) - { - picloc_x += ammo1; - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, ((i >= ammo2) ? '1 1 1' : '0 0 0'), 0.75, DRAWFLAG_NORMAL); - } - } - pic2size = draw_getimagesize(hud_ammo2_ico) * autocvar_cl_vehicles_hudscale; - picloc = '664 130 0' * autocvar_cl_vehicles_hudscale; - if(ammo2 == 9) - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_ammo2_ico, pic2size, '1 1 1', 1, DRAWFLAG_NORMAL); - - if (scoreboard_showscores) - HUD_DrawScoreboard(); - else - { - switch(getstati(STAT_VEHICLESTAT_W2MODE)) - { - case SBRM_VOLLY: - spider_xhair = "gfx/vehicles/axh-bracket.tga"; - break; - case SBRM_GUIDE: - spider_xhair = "gfx/vehicles/axh-cross.tga"; - break; - case SBRM_ARTILLERY: - spider_xhair = "gfx/vehicles/axh-tag.tga"; - break; - default: - spider_xhair= "gfx/vehicles/axh-tag.tga"; - } - - picsize = draw_getimagesize(spider_xhair); - picsize_x *= autocvar_cl_vehicle_spiderbot_cross_size; - picsize_y *= autocvar_cl_vehicle_spiderbot_cross_size; - - drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), spider_xhair, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_ADDITIVE); - } - ++ Vehicles_drawHUD("vehicle_spider", "vehicle_spider_weapon1", "vehicle_spider_weapon2", ++ "vehicle_icon_ammo1", autocvar_hud_progressbar_vehicles_ammo1_color, ++ "vehicle_icon_ammo2", autocvar_hud_progressbar_vehicles_ammo2_color, ++ crosshair); + return true; + } + case VR_SETUP: + { - // Minigun1 - AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-ring.tga"; - AuxiliaryXhair[0].axh_scale = 0.25; - // Minigun2 - AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-ring.tga"; - AuxiliaryXhair[1].axh_scale = 0.25; - // Rocket - AuxiliaryXhair[2].axh_image = "gfx/vehicles/axh-special1.tga"; - AuxiliaryXhair[2].axh_scale = 0.5; ++ AuxiliaryXhair[0].axh_image = vCROSS_HINT; // Minigun1 ++ AuxiliaryXhair[1].axh_image = vCROSS_HINT; // Minigun2 + + return true; + } + case VR_PRECACHE: + { + return true; + } + } + + return true; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --cc qcsrc/common/vehicles/vehicles.qc index 81aca27c2,000000000..e982c6f39 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles.qc +++ b/qcsrc/common/vehicles/vehicles.qc @@@ -1,87 -1,0 +1,89 @@@ - #include "all.qh" ++#include "unit/all.qh" ++ ++#include "vehicles_include.qc" + +// VEHICLE PLUGIN SYSTEM +entity vehicle_info[VEH_MAXCOUNT]; +entity dummy_vehicle_info; + +void vehicles_common_initialize() +{ +#ifdef CSQC + precache_model("models/vehicles/bomblet.md3"); + precache_model("models/vehicles/clusterbomb.md3"); + precache_model("models/vehicles/clusterbomb_fragment.md3"); + precache_model("models/vehicles/rocket01.md3"); + precache_model("models/vehicles/rocket02.md3"); + + precache_sound ("vehicles/alarm.wav"); + precache_sound ("vehicles/alarm_shield.wav"); +#endif // CSQC +#ifdef SVQC + precache_sound("onslaught/ons_hit2.wav"); + precache_sound("onslaught/electricity_explode.wav"); + + addstat(STAT_HUD, AS_INT, hud); + addstat(STAT_VEHICLESTAT_HEALTH, AS_INT, vehicle_health); + addstat(STAT_VEHICLESTAT_SHIELD, AS_INT, vehicle_shield); + addstat(STAT_VEHICLESTAT_ENERGY, AS_INT, vehicle_energy); + + addstat(STAT_VEHICLESTAT_W2MODE, AS_INT, vehicle_weapon2mode); + + addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1); + addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1); + + addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); + addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2); +#endif // SVQC +} + +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) +{ + entity e; + vehicle_info[id - 1] = e = spawn(); + e.classname = "vehicle_info"; + e.vehicleid = id; + e.netname = shortname; + e.vehicle_name = vname; + e.vehicle_func = func; + e.mdl = modelname; + e.spawnflags = vehicleflags; + e.mins = min_s; + e.maxs = max_s; + e.model = modelname; + e.head_model = headmodelname; + e.hud_model = hudmodelname; + e.tag_head = headtag; + e.tag_hud = hudtag; + e.tag_view = viewtag; + + #ifndef MENUQC + vehicles_common_initialize(); + #endif +} +float v_null(float dummy) { return 0; } +void register_vehicles_done() +{ + dummy_vehicle_info = spawn(); + dummy_vehicle_info.classname = "vehicle_info"; + dummy_vehicle_info.vehicleid = 0; // you can recognize dummies by this + dummy_vehicle_info.netname = ""; + dummy_vehicle_info.vehicle_name = "Vehicle"; + dummy_vehicle_info.vehicle_func = v_null; + dummy_vehicle_info.mdl = ""; + dummy_vehicle_info.mins = '-0 -0 -0'; + dummy_vehicle_info.maxs = '0 0 0'; + dummy_vehicle_info.model = ""; + dummy_vehicle_info.head_model = ""; + dummy_vehicle_info.hud_model = ""; +} +entity get_vehicleinfo(float id) +{ + entity m; + if(id < VEH_FIRST || id > VEH_LAST) + return dummy_vehicle_info; + m = vehicle_info[id - 1]; + if(m) + return m; + return dummy_vehicle_info; +} diff --cc qcsrc/common/vehicles/vehicles.qh index c803adeb0,000000000..b0f28b557 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles.qh +++ b/qcsrc/common/vehicles/vehicles.qh @@@ -1,95 -1,0 +1,95 @@@ +#ifndef VEHICLES_H +#define VEHICLES_H + +#include "sv_vehicles.qh" + +// vehicle requests +const int VR_SETUP = 1; // (BOTH) setup vehicle data +const int VR_THINK = 2; // (SERVER) logic to run every frame +const int VR_DEATH = 3; // (SERVER) called when vehicle dies +const int VR_PRECACHE = 4; // (BOTH) precaches models/sounds used by this vehicle +const int VR_ENTER = 5; // (SERVER) called when a player enters this vehicle +const int VR_SPAWN = 6; // (SERVER) called when the vehicle re-spawns +const int VR_IMPACT = 7; // (SERVER) called when a vehicle hits something +const int VR_HUD = 8; // (CLIENT) logic to run every frame + +// vehicle spawn flags (need them here for common registrations) +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 + +// functions: +entity get_vehicleinfo(float id); + +// fields: +.entity tur_head; + + +// entity properties of vehicleinfo: +.int vehicleid; // VEH_... +.string netname; // short name +.string vehicle_name; // human readable name +.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 +.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 +// ===================== + +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 int VEH_MAXCOUNT = 24; +#define VEH_FIRST 1 +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) \ + 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" ++#include "unit/all.qh" + +#undef REGISTER_VEHICLE +ACCUMULATE_FUNCTION(RegisterVehicles, register_vehicles_done); + +#endif diff --cc qcsrc/common/vehicles/vehicles_include.qc index ac174ae0c,000000000..1bd181d50 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles_include.qc +++ b/qcsrc/common/vehicles/vehicles_include.qc @@@ -1,10 -1,0 +1,15 @@@ ++#ifndef VEHICLES_INCLUDE_C ++#define VEHICLES_INCLUDE_C ++ +#include "vehicles_include.qh" + +#ifdef CSQC +#include "cl_vehicles.qc" +#include "vehicles.qc" +#endif // CSQC +#ifdef SVQC +#include "sv_vehicles.qc" +#include "vehicles.qc" +#endif // SVQC ++ ++#endif diff --cc qcsrc/common/vehicles/vehicles_include.qh index 4ed5b5111,000000000..26e52e481 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles_include.qh +++ b/qcsrc/common/vehicles/vehicles_include.qh @@@ -1,12 -1,0 +1,14 @@@ +#ifndef VEHICLES_INCLUDE_H +#define VEHICLES_INCLUDE_H + ++#include "all.qh" ++ +#ifdef CSQC +#include "vehicles.qh" +#include "cl_vehicles.qh" +#elif defined(SVQC) +#include "vehicles.qh" +#include "sv_vehicles.qh" +#endif // SVQC + +#endif diff --cc qcsrc/server/cl_impulse.qc index 03fdf7ede,f37e8a462..45708409c --- a/qcsrc/server/cl_impulse.qc +++ b/qcsrc/server/cl_impulse.qc @@@ -10,7 -10,7 +10,6 @@@ #include "weapons/selection.qh" #include "weapons/tracing.qh" #include "weapons/weaponsystem.qh" - #include "../common/vehicles/sv_vehicles.qh" -#include "vehicles/vehicle.qh" #include "waypointsprites.qh" #include "../common/weapons/all.qh" @@@ -71,11 -71,11 +70,15 @@@ void ImpulseCommands (void if (timeout_status == TIMEOUT_ACTIVE) //don't allow any impulses while the game is paused return; - if(self.vehicle) - if(self.vehicle.deadflag == DEAD_NO) - if(self.vehicle.vehicles_impulse) - if(self.vehicle.vehicles_impulse(imp)) - return; + if(self.vehicle) + if(self.vehicle.deadflag == DEAD_NO) - if(self.vehicle.vehicles_impulse) - if(self.vehicle.vehicles_impulse(imp)) - return; ++ { ++ if(self.vehicle.vehicles_impulse) ++ if(self.vehicle.vehicles_impulse(imp)) ++ return; ++ if(vehicle_impulse(imp)) ++ return; ++ } if(CheatImpulse(imp)) { diff --cc qcsrc/server/g_world.qc index b6d2b5e07,dcfc19eb1..da2983c4a --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@@ -560,14 -560,10 +561,11 @@@ void spawnfunc___init_dedicated_server( self.classname = "worldspawn"; // safeguard against various stuff ;) // 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(RegisterItems); - CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + static_init(); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); - CALL_ACCUMULATED_FUNCTION(RegisterBuffs); + CALL_ACCUMULATED_FUNCTION(RegisterEffects); ++ CALL_ACCUMULATED_FUNCTION(RegisterVehicles); MapInfo_Enumerate(); MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); @@@ -611,14 -608,10 +610,11 @@@ void spawnfunc_worldspawn (void server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? true : false); // 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(RegisterItems); - CALL_ACCUMULATED_FUNCTION(RegisterGametypes); + static_init(); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); - CALL_ACCUMULATED_FUNCTION(RegisterBuffs); + CALL_ACCUMULATED_FUNCTION(RegisterEffects); ++ CALL_ACCUMULATED_FUNCTION(RegisterVehicles); ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid)); diff --cc qcsrc/server/mutators/mutators_include.qc index 44af257c7,d0fe0a60a..ae13c7d02 --- a/qcsrc/server/mutators/mutators_include.qc +++ b/qcsrc/server/mutators/mutators_include.qc @@@ -76,9 -76,10 +76,9 @@@ #include "../item_key.qh" #include "../pathlib/pathlib.qh" #include "../tturrets/include/turrets.qh" - #include "../vehicles/all.qh" #endif - #include "base.qc" + #include "../../common/mutators/base.qh" #include "gamemode_assault.qc" #include "gamemode_ca.qc" #include "gamemode_ctf.qc" diff --cc qcsrc/warpzonelib/server.qc index 53d903902,53d903902..f3dd22ad3 --- a/qcsrc/warpzonelib/server.qc +++ b/qcsrc/warpzonelib/server.qc @@@ -132,6 -132,6 +132,8 @@@ float WarpZone_Teleport(entity wz, enti player.warpzone_teleport_finishtime += sys_frametime - dt; #ifndef WARPZONE_USE_FIXANGLE ++ if(IS_VEHICLE(player) && player.owner) ++ player = player.owner; // hax if(IS_PLAYER(player)) { // instead of fixangle, send the transform to the client for smoother operation diff --cc vehicles.cfg index af5f0943a,290b12d8c..b5f0178ff --- a/vehicles.cfg +++ b/vehicles.cfg @@@ -13,15 -13,10 +13,17 @@@ set g_vehicle_bumblebee set g_vehicles_crush_dmg 70 set g_vehicles_crush_force 50 + set cl_vehicles_hud_tactical 1 set cl_vehicles_hudscale 0.5 + set cl_vehicles_crosshair_size 0.5 +set g_vehicles_enter 0 "require pressing use key to enter a vehicle" +set g_vehicles_enter_radius 250 +set g_vehicles_steal 1 "allow stealing enemy vehicles in teamplay modes" +set g_vehicles_steal_show_waypoint 1 "show a waypoint above the thief" + +set g_vehicles_teams 1 "allow team specific vehicles" + set g_vehicles_delayspawn 1 set g_vehicles_delayspawn_jitter 10