From: Mario Date: Thu, 13 Nov 2014 19:22:25 +0000 (+1100) Subject: Merge branch 'master' into Mario/vehicles X-Git-Tag: xonotic-v0.8.2~2059^2~19^2~1 X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=0f444e0d57db660b27b5a54a263a61bc5da41004;hp=-c;p=xonotic%2Fxonotic-data.pk3dir.git Merge branch 'master' into Mario/vehicles Conflicts: qcsrc/common/constants.qh qcsrc/server/cl_weapons.qc qcsrc/server/progs.src --- 0f444e0d57db660b27b5a54a263a61bc5da41004 diff --combined qcsrc/client/Main.qc index 419416791,c0e37ae62..22c983c63 --- a/qcsrc/client/Main.qc +++ b/qcsrc/client/Main.qc @@@ -87,6 -87,9 +87,9 @@@ void CSQC_Init(void registercvar("hud_usecsqc", "1"); registercvar("scoreboard_columns", "default"); + registercvar("cl_nade_type", "3"); + registercvar("cl_pokenade_type", "zombie"); + gametype = 0; // hud_fields uses strunzone on the titles! @@@ -104,12 -107,12 +107,13 @@@ // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterVehicles); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); WaypointSprite_Load(); @@@ -123,6 -126,7 +127,6 @@@ GibSplash_Precache(); Casings_Precache(); DamageInfo_Precache(); - Vehicles_Precache(); turrets_precache(); Tuba_Precache(); CSQCPlayer_Precache(); @@@ -214,7 -218,7 +218,7 @@@ float SetTeam(entity o, float Team default: if(GetTeam(Team, false) == world) { - printf(_("trying to switch to unsupported team %d\n"), Team); + dprintf("trying to switch to unsupported team %d\n", Team); Team = NUM_SPECTATOR; } break; @@@ -230,7 -234,7 +234,7 @@@ default: if(GetTeam(Team, false) == world) { - printf(_("trying to switch to unsupported team %d\n"), Team); + dprintf("trying to switch to unsupported team %d\n", Team); Team = NUM_SPECTATOR; } break; @@@ -830,6 -834,7 +834,7 @@@ void CSQC_Ent_Update(float bIsNewEntity case ENT_CLIENT_SPAWNPOINT: Ent_ReadSpawnPoint(bIsNewEntity); break; case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break; case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break; + case ENT_CLIENT_HEALING_ORB: ent_healer(); break; default: //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype)); diff --combined qcsrc/client/View.qc index 8f289e55c,a069faa46..9dd944660 --- a/qcsrc/client/View.qc +++ b/qcsrc/client/View.qc @@@ -366,6 -366,8 +366,6 @@@ const float CAMERA_FREE = 1 const float CAMERA_CHASE = 2; float reticle_type; string NextFrameCommand; -void CSQC_SPIDER_HUD(); -void CSQC_RAPTOR_HUD(); vector freeze_org, freeze_ang; entity nightvision_noise, nightvision_noise2; @@@ -490,7 -492,8 +490,8 @@@ void CSQC_UpdateView(float w, float h // event chase camera if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped { - if(((spectatee_status >= 0 && (autocvar_cl_eventchase_death && is_dead)) || intermission) && !autocvar_cl_orthoview) + WepSet weapons_stat = WepSet_GetFromStat(); + if(((spectatee_status >= 0 && (autocvar_cl_eventchase_death && is_dead)) || intermission) && !autocvar_cl_orthoview || (autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(weapons_stat & WepSet_FromWeapon(WEP_PORTO)))) { // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.) vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org); @@@ -1152,15 -1155,20 +1153,20 @@@ //else { - if(gametype == MAPINFO_TYPE_FREEZETAG) + if(getstati(STAT_FROZEN)) + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + else if (getstatf(STAT_HEALING_ORB)>time) + drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, Nade_Color(NADE_TYPE_HEAL), autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE); + if(!intermission) + if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death { - if(getstati(STAT_FROZEN)) - drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); - if(getstatf(STAT_REVIVE_PROGRESS)) - { - DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); - drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL); - } + DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_NADE_TIMER), '0.25 0.90 1' + ('1 0 0' * getstatf(STAT_NADE_TIMER)) - ('0 1 1' * getstatf(STAT_NADE_TIMER)), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL); + } + else if(getstatf(STAT_REVIVE_PROGRESS)) + { + DrawCircleClippedPic(eX * 0.5 * vid_conwidth + eY * 0.6 * vid_conheight, 0.1 * vid_conheight, "gfx/crosshair_ring.tga", getstatf(STAT_REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE); + drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), eX * vid_conwidth + eY * 0.025 * vid_conheight, '1 1 1', 1, DRAWFLAG_NORMAL); } if(autocvar_r_letterbox == 0) @@@ -1632,7 -1640,18 +1638,7 @@@ HUD_Panel_Mouse(); if(hud && !intermission) - { - if(hud == HUD_SPIDERBOT) - CSQC_SPIDER_HUD(); - else if(hud == HUD_WAKIZASHI) - CSQC_WAKIZASHI_HUD(); - else if(hud == HUD_RAPTOR) - CSQC_RAPTOR_HUD(); - else if(hud == HUD_BUMBLEBEE) - CSQC_BUMBLE_HUD(); - else if(hud == HUD_BUMBLEBEE_GUN) - CSQC_BUMBLE_GUN_HUD(); - } + VEH_ACTION(hud, VR_HUD); cl_notice_run(); diff --combined qcsrc/client/autocvars.qh index a052708cf,28ef157e5..8adf749ad --- a/qcsrc/client/autocvars.qh +++ b/qcsrc/client/autocvars.qh @@@ -73,6 -73,9 +73,6 @@@ var float autocvar_cl_spawnzoom = 1 var float autocvar_cl_spawnzoom_speed = 1; var float autocvar_cl_spawnzoom_factor = 2; float autocvar_cl_stripcolorcodes; -var float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6; -var float autocvar_cl_vehicle_spiderbot_cross_size = 1; -var float autocvar_cl_vehicles_hud_tactical = 1; float autocvar_cl_velocityzoom; var float autocvar_cl_velocityzoom_type = 3; float autocvar_cl_velocityzoom_speed; @@@ -265,6 -268,7 +265,7 @@@ float autocvar_hud_panel_notify_fadetim float autocvar_hud_panel_notify_flip; float autocvar_hud_panel_notify_fontsize; float autocvar_hud_panel_notify_time; + float autocvar_hud_panel_notify_icon_aspect; float autocvar_hud_panel_physics; float autocvar_hud_panel_physics_acceleration_progressbar_mode; float autocvar_hud_panel_physics_acceleration_progressbar_scale; @@@ -287,6 -291,8 +288,8 @@@ float autocvar_hud_panel_powerups_baral float autocvar_hud_panel_powerups_flip; float autocvar_hud_panel_powerups_iconalign; float autocvar_hud_panel_powerups_progressbar; + float autocvar_hud_panel_buffs; + //float autocvar_hud_panel_buffs_iconalign; string autocvar_hud_panel_powerups_progressbar_shield; string autocvar_hud_panel_powerups_progressbar_strength; string autocvar_hud_panel_powerups_progressbar_superweapons; @@@ -407,6 -413,7 +410,7 @@@ float autocvar_viewsize float autocvar_cl_hitsound; float autocvar_cl_hitsound_antispam_time; var float autocvar_cl_eventchase_death = 1; + var float autocvar_cl_eventchase_nexball = 1; var float autocvar_cl_eventchase_distance = 140; var float autocvar_cl_eventchase_speed = 1.3; var vector autocvar_cl_eventchase_maxs = '12 12 8'; @@@ -436,3 -443,4 +440,4 @@@ string autocvar__cl_playermodel float autocvar_cl_deathglow; float autocvar_developer_csqcentities; float autocvar_g_jetpack_attenuation; + float autocvar_cl_nade_timer; diff --combined qcsrc/client/progs.src index 51eecd64a,86a8b4339..3e32ee235 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@@ -8,6 -8,7 +8,7 @@@ sys-post.q Defs.qc ../dpdefs/keycodes.qc ../common/constants.qh + ../common/stats.qh ../warpzonelib/anglestransform.qh ../warpzonelib/mathlib.qh @@@ -16,6 -17,8 +17,8 @@@ ../common/teams.qh ../common/util.qh + ../common/nades.qh + ../common/buffs.qh ../common/test.qh ../common/counting.qh ../common/items.qh @@@ -51,7 -54,7 +54,7 @@@ tturrets.q ../server/tturrets/include/turrets_early.qh ../server/movelib.qc main.qh -vehicles/vehicles.qh +../common/vehicles/vehicles_include.qh ../common/csqcmodel_settings.qh ../csqcmodellib/common.qh ../csqcmodellib/cl_model.qh @@@ -87,7 -90,8 +90,7 @@@ modeleffects.q tuba.qc target_music.qc -vehicles/vehicles.qc -../server/vehicles/bumblebee.qc +../common/vehicles/vehicles_include.qc shownames.qh shownames.qc @@@ -116,6 -120,9 +119,9 @@@ command/cl_cmd.q ../common/monsters/monsters.qc + ../common/nades.qc + ../common/buffs.qc + ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc ../warpzonelib/common.qc diff --combined qcsrc/client/waypointsprites.qc index 76c86a48d,7ee34672c..cc115e104 --- a/qcsrc/client/waypointsprites.qc +++ b/qcsrc/client/waypointsprites.qc @@@ -241,6 -241,7 +241,7 @@@ vector spritelookupcolor(string s, vect } string spritelookuptext(string s) { + if(substring(s, 0, 5) == "buff-") { return Buff_PrettyName(Buff_Type_FromSprite(s)); } switch(s) { case "as-push": return _("Push"); @@@ -277,6 -278,7 +278,7 @@@ case "race-finish": return _("Finish"); case "race-start": return _("Start"); case "race-start-finish": return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start"); + case "goal": return _("Goal"); case "nb-ball": return _("Ball"); case "ka-ball": return _("Ball"); case "ka-ballcarrier": return _("Ball carrier"); @@@ -308,10 -310,9 +310,10 @@@ case "item-shield": return _("Shield"); case "item-fuelregen": return _("Fuel regen"); case "item-jetpack": return _("Jet Pack"); - case "freezetag_frozen": return _("Frozen!"); + case "frozen": return _("Frozen!"); case "tagged-target": return _("Tagged"); case "vehicle": return _("Vehicle"); + case "intruder": return _("Intruder!"); default: return s; } } diff --combined qcsrc/common/constants.qh index cd0a2dfd7,fb6d781c0..38ad4d60e --- a/qcsrc/common/constants.qh +++ b/qcsrc/common/constants.qh @@@ -78,6 -78,7 +78,6 @@@ const float ENT_CLIENT_MAPVOTE = 17 const float ENT_CLIENT_CLIENTDATA = 18; const float ENT_CLIENT_RANDOMSEED = 19; const float ENT_CLIENT_WALL = 20; -const float ENT_CLIENT_SPIDERBOT = 21; const float ENT_CLIENT_MODELEFFECT = 22; const float ENT_CLIENT_TUBANOTE = 23; const float ENT_CLIENT_WARPZONE = 24; @@@ -100,6 -101,8 +100,8 @@@ const float ENT_CLIENT_TURRET = 40 const float ENT_CLIENT_AUXILIARYXHAIR = 50; const float ENT_CLIENT_VEHICLE = 60; + const float ENT_CLIENT_HEALING_ORB = 80; + const float SPRITERULE_DEFAULT = 0; const float SPRITERULE_TEAMPLAY = 1; @@@ -138,82 -141,18 +140,12 @@@ const float CVAR_READONLY = 4 /////////////////////////// // csqc communication stuff - const float STAT_KH_KEYS = 32; - const float STAT_CTF_STATE = 33; - const float STAT_WEAPONS = 35; - const float STAT_SWITCHWEAPON = 36; - const float STAT_GAMESTARTTIME = 37; - const float STAT_STRENGTH_FINISHED = 38; - const float STAT_INVINCIBLE_FINISHED = 39; - const float STAT_PRESSED_KEYS = 42; - const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config - const float STAT_FUEL = 44; - const float STAT_NB_METERSTART = 45; - const float STAT_SHOTORG = 46; // compressShotOrigin - const float STAT_LEADLIMIT = 47; - const float STAT_WEAPON_CLIPLOAD = 48; - const float STAT_WEAPON_CLIPSIZE = 49; - const float STAT_NEX_CHARGE = 50; - const float STAT_LAST_PICKUP = 51; - const float STAT_HUD = 52; - const float STAT_NEX_CHARGEPOOL = 53; - const float STAT_HIT_TIME = 54; - const float STAT_TYPEHIT_TIME = 55; - const float STAT_LAYED_MINES = 56; - const float STAT_HAGAR_LOAD = 57; - const float STAT_SWITCHINGWEAPON = 58; - const float STAT_SUPERWEAPONS_FINISHED = 59; - - const float STAT_VEHICLESTAT_HEALTH = 60; - const float STAT_VEHICLESTAT_SHIELD = 61; - const float STAT_VEHICLESTAT_ENERGY = 62; - const float STAT_VEHICLESTAT_AMMO1 = 63; - const float STAT_VEHICLESTAT_RELOAD1 = 64; - const float STAT_VEHICLESTAT_AMMO2 = 65; - const float STAT_VEHICLESTAT_RELOAD2 = 66; - const float STAT_VEHICLESTAT_W2MODE = 67; - - const float STAT_SECRETS_TOTAL = 70; - const float STAT_SECRETS_FOUND = 71; - - const float STAT_RESPAWN_TIME = 72; - const float STAT_ROUNDSTARTTIME = 73; - - const float STAT_WEAPONS2 = 74; - const float STAT_WEAPONS3 = 75; - - const float STAT_MONSTERS_TOTAL = 76; - const float STAT_MONSTERS_KILLED = 77; - - // mod stats (1xx) - const float STAT_REDALIVE = 100; - const float STAT_BLUEALIVE = 101; - const float STAT_YELLOWALIVE = 102; - const float STAT_PINKALIVE = 103; - - // freeze tag - const float STAT_FROZEN = 104; - const float STAT_REVIVE_PROGRESS = 105; - - // domination - const float STAT_DOM_TOTAL_PPS = 100; - const float STAT_DOM_PPS_RED = 101; - const float STAT_DOM_PPS_BLUE = 102; - const float STAT_DOM_PPS_PINK = 103; - const float STAT_DOM_PPS_YELLOW = 104; - - // see DP source, quakedef.h - const float STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW = 222; - const float STAT_MOVEVARS_AIRSTRAFEACCEL_QW = 223; - const float STAT_MOVEVARS_MAXSPEED = 244; - const float STAT_MOVEVARS_AIRACCEL_QW = 254; - const float CTF_STATE_ATTACK = 1; const float CTF_STATE_DEFEND = 2; const float CTF_STATE_COMMANDER = 3; const float HUD_NORMAL = 0; -const float HUD_VEHICLE_FIRST = 10; -const float HUD_SPIDERBOT = 10; -const float HUD_WAKIZASHI = 11; -const float HUD_RAPTOR = 12; -const float HUD_BUMBLEBEE = 13; -const float HUD_BUMBLEBEE_GUN = 14; -const float HUD_VEHICLE_LAST = 14; +const float HUD_BUMBLEBEE_GUN = 25; const vector eX = '1 0 0'; const vector eY = '0 1 0'; @@@ -221,7 -160,7 +153,7 @@@ const vector eZ = '0 0 1' // moved that here so the client knows the max. // # of maps, I'll use arrays for them :P - #define MAPVOTE_COUNT 10 + #define MAPVOTE_COUNT 30 /** * Lower scores are better (e.g. suicides) @@@ -271,23 -210,6 +203,6 @@@ #define SP_SCORE 3 // game mode specific indices are not in common/, but in server/scores_rules.qc! - #ifdef COMPAT_XON010_CHANNELS - const float CH_INFO = 0; // only on world and csqc - const float CH_TRIGGER = 0; // only on players; compat: FALSELY CONTROLLED BY "Info" - const float CH_WEAPON_A = 1; // only on players and entities - const float CH_WEAPON_SINGLE = 5; // only on players and entities - const float CH_VOICE = 2; // only on players - const float CH_BGM_SINGLE = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice" - const float CH_AMBIENT = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice" - const float CH_TRIGGER_SINGLE = 3; // only on players, entities, csqc - const float CH_SHOTS = 4; // only on players, entities, csqc - const float CH_SHOTS_SINGLE = 4; // only on players, entities, csqc - const float CH_WEAPON_B = 5; // only on players and entities - const float CH_PAIN = 6; // only on players and csqc - const float CH_PAIN_SINGLE = 6; // only on players and csqc - const float CH_PLAYER = 7; // only on players and entities - const float CH_TUBA = 5; // only on csqc - #else const float CH_INFO = 0; const float CH_TRIGGER = -3; const float CH_WEAPON_A = -1; @@@ -302,8 -224,8 +217,8 @@@ const float CH_WEAPON_B = -1 const float CH_PAIN = -6; const float CH_PAIN_SINGLE = 6; const float CH_PLAYER = -7; - const float CH_TUBA = 5; - #endif + const float CH_PLAYER_SINGLE = 7; + const float CH_TUBA_SINGLE = 5; const float ATTEN_NONE = 0; const float ATTEN_MIN = 0.015625; @@@ -351,17 -273,6 +266,6 @@@ const float PROJECTILE_BUMBLE_BEAM = 31 const float PROJECTILE_MAGE_SPIKE = 32; const float PROJECTILE_SHAMBLER_LIGHTNING = 33; - const float PROJECTILE_NADE_RED = 50; - const float PROJECTILE_NADE_RED_BURN = 51; - const float PROJECTILE_NADE_BLUE = 52; - const float PROJECTILE_NADE_BLUE_BURN = 53; - const float PROJECTILE_NADE_YELLOW = 54; - const float PROJECTILE_NADE_YELLOW_BURN = 55; - const float PROJECTILE_NADE_PINK = 56; - const float PROJECTILE_NADE_PINK_BURN = 57; - const float PROJECTILE_NADE = 58; - const float PROJECTILE_NADE_BURN = 59; - const float SPECIES_HUMAN = 0; const float SPECIES_ROBOT_SOLID = 1; const float SPECIES_ALIEN = 2; @@@ -446,3 -357,8 +350,8 @@@ noref var vector autocvar_sv_player_hea #define URI_GET_UPDATENOTIFICATION 33 #define URI_GET_URLLIB 128 #define URI_GET_URLLIB_END 191 + + // gametype votes + #define GTV_AVAILABLE 0 + // for later use in per-map gametype filtering + #define GTV_FORBIDDEN 2 diff --combined qcsrc/common/notifications.qh index 33716fc11,60cc622fa..96c4ffe87 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@@ -360,7 -360,11 +360,11 @@@ void Send_Notification_WOCOVA MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FIRE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"), _("^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_LAVA, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_lava", _("^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_MONSTER, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was pushed infront of a monster by ^BG%s^K1%s%s"), "") \ - MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_NAPALM, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_napalm", _("^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"), _("^BG%s%s^K1 got too close to a napalm explosion%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_ICE_FREEZE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_ice", _("^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_NADE_HEAL, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_nade_heal", _("^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SHOOTING_STAR, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_shootingstar", _("^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SLIME, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was slimed by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_SWAMP, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_slime", _("^BG%s%s^K1 was preserved by ^BG%s^K1%s%s"), "") \ @@@ -378,6 -382,7 +382,7 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_DEATH, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_GUN, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_ROCKET, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VENGEANCE, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_death", _("^BG%s%s^K1 was destroyed by the vengeful ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VOID, 3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1", "notify_void", _("^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_AUTOTEAMCHANGE, 2, 1, "s1 s2loc death_team", "", "", _("^BG%s^K1 was moved into the %s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_BETRAYAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_teamkill_red", _("^BG%s^K1 became enemies with the Lord of Teamplay%s%s"), "") \ @@@ -389,7 -394,6 +394,6 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_FIRE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 became a bit too crispy%s%s"), _("^BG%s^K1 felt a little hot%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_GENERIC, 2, 1, "s1 s2loc spree_lost", "s1", "notify_selfkill", _("^BG%s^K1 died%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_LAVA, 2, 1, "s1 s2loc spree_lost", "s1", "notify_lava", _("^BG%s^K1 turned into hot slag%s%s"), _("^BG%s^K1 found a hot place%s%s")) \ - MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_MAGE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was exploded by a Mage%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_CLAW, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1's innards became outwards by a Shambler%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_SHAMBLER_SMASH, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was smashed by a Shambler%s%s"), "") \ @@@ -398,6 -402,11 +402,11 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_WYVERN, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was fireballed by a Wyvern%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 joins the Zombies%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 was given kung fu lessons by a Zombie%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_NAPALM, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_napalm", _("^BG%s^K1 was burned to death by their own Napalm Nade%s%s"), _("^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 mastered the art of self-nading%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_ICE_FREEZE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_ice", _("^BG%s^K1 was frozen to death by their own Ice Nade%s%s"), _("^BG%s^K1 felt a little chilly%s%s")) \ + MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NADE_HEAL, 2, 1, "s1 s2loc spree_lost", "s1", "notify_nade_heal", _("^BG%s^K1's Healing Nade didn't quite heal them%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_NOAMMO, 2, 1, "s1 s2loc spree_lost", "s1", "notify_outofammo", _("^BG%s^K1 died%s%s. What's the point of living without ammo?"), _("^BG%s^K1 ran out of ammo%s%s")) \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_ROT, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 rotted away%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_SHOOTING_STAR, 2, 1, "s1 s2loc spree_lost", "s1", "notify_shootingstar", _("^BG%s^K1 became a shooting star%s%s"), "") \ @@@ -429,9 -438,11 +438,11 @@@ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VH_WAKI_ROCKET, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"), "") \ MSG_INFO_NOTIF(1, INFO_DEATH_SELF_VOID, 2, 1, "s1 s2loc spree_lost", "s1", "notify_void", _("^BG%s^K1 was in the wrong place%s%s"), "") \ MULTITEAM_INFO(1, INFO_DEATH_TEAMKILL_, 4, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "") \ + MSG_INFO_NOTIF(1, INFO_DOMINATION_CAPTURE_TIME, 2, 2, "s1 s2 f1 f2", "", "", _("^BG%s^BG%s^BG (%s points every %s seconds)"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_FREEZE, 2, 0, "s1 s2", "", "", _("^BG%s^K1 was frozen by ^BG%s"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED, 2, 0, "s1 s2", "", "", _("^BG%s^K3 was revived by ^BG%s"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_FALL, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by falling"), "") \ + MSG_INFO_NOTIF(1, INFO_FREEZETAG_REVIVED_NADE, 1, 0, "s1", "", "", _("^BG%s^K3 was revived by their Nade explosion"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_AUTO_REVIVED, 1, 1, "s1 f1", "", "", _("^BG%s^K3 was automatically revived after %s second(s)"), "") \ MULTITEAM_INFO(1, INFO_ROUND_TEAM_WIN_, 4, 0, 0, "", "", "", _("^TC^TT^BG team wins the round"), "") \ MSG_INFO_NOTIF(1, INFO_ROUND_PLAYER_WIN, 1, 0, "s1", "", "", _("^BG%s^BG wins the round"), "") \ @@@ -439,6 -450,10 +450,10 @@@ MSG_INFO_NOTIF(1, INFO_ROUND_OVER, 0, 0, "", "", "", _("^BGRound over, there's no winner"), "") \ MSG_INFO_NOTIF(1, INFO_FREEZETAG_SELF, 1, 0, "s1", "", "", _("^BG%s^K1 froze themself"), "") \ MSG_INFO_NOTIF(1, INFO_GODMODE_OFF, 0, 1, "f1", "", "", _("^BGGodmode saved you %s units of damage, cheater!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG got the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_LOST, 1, 1, "s1 item_buffname", "", "", _("^BG%s^BG lost the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_DROP, 0, 1, "item_buffname", "", "", _("^BGYou dropped the %s^BG Buff!"), "") \ + MSG_INFO_NOTIF(1, INFO_ITEM_BUFF_GOT, 0, 1, "item_buffname", "", "", _("^BGYou got the %s^BG Buff!"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", "", "", _("^BGYou do not have the ^F1%s"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", "", "", _("^BGYou dropped the ^F1%s^BG%s"), "") \ MSG_INFO_NOTIF(0, INFO_ITEM_WEAPON_GOT, 0, 1, "item_wepname", "", "", _("^BGYou got the ^F1%s"), "") \ @@@ -580,6 -595,7 +595,7 @@@ MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, 1, 4, "spree_cen s1 frag_stats", NO_CPID, "0 0", _("^K1%sYou were typefragged by ^BG%s^BG%s"), _("^K1%sYou were scored against by ^BG%s^K1 while typing^BG%s")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, 1, 2, "spree_cen s1 frag_ping", NO_CPID, "0 0", _("^K1%sYou typefragged ^BG%s^BG%s"), _("^K1%sYou scored against ^BG%s^K1 while they were typing^BG%s")) \ MSG_CENTER_NOTIF(1, CENTER_NADE_THROW, 0, 0, "", CPID_NADES, "0 0", _("^BGPress ^F2DROPWEAPON^BG again to toss the nade!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_NADE_BONUS, 0, 0, "", CPID_NADES, "0 0", _("^F2You got a ^K1BONUS GRENADE^F2!"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_AUTOTEAMCHANGE, 0, 1, "death_team", NO_CPID, "0 0", _("^BGYou have been moved into a different team\nYou are now on: %s"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_BETRAYAL, 0, 0, "", NO_CPID, "0 0", _("^K1Don't shoot your team mates!"), _("^K1Don't go against your team mates!")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_CAMP, 0, 0, "", NO_CPID, "0 0", _("^K1Die camper!"), _("^K1Reconsider your tactics, camper!")) \ @@@ -592,6 -608,9 +608,9 @@@ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_LAVA, 0, 0, "", NO_CPID, "0 0", _("^K1You couldn't stand the heat!"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_MONSTER, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed by a monster!"), _("^K1You need to watch out for monsters!")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE, 0, 0, "", NO_CPID, "0 0", _("^K1You forgot to put the pin back in!"), _("^K1Tastes like chicken!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_NAPALM, 0, 0, "", NO_CPID, "0 0", _("^K1Hanging around a napalm explosion is bad!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_ICE_FREEZE, 0, 0, "", NO_CPID, "0 0", _("^K1You got a little bit too cold!"), _("^K1You felt a little chilly!")) \ + MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NADE_HEAL, 0, 0, "", NO_CPID, "0 0", _("^K1Your Healing Nade is a bit defective"), "") \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_NOAMMO, 0, 0, "", NO_CPID, "0 0", _("^K1You were killed for running out of ammo..."), _("^K1You are respawning for running out of ammo...")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_ROT, 0, 0, "", NO_CPID, "0 0", _("^K1You grew too old without taking your medicine"), _("^K1You need to preserve your health")) \ MSG_CENTER_NOTIF(1, CENTER_DEATH_SELF_SHOOTING_STAR, 0, 0, "", NO_CPID, "0 0", _("^K1You became a shooting star!"), "") \ @@@ -619,7 -638,7 +638,7 @@@ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FREEZE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You froze ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_FROZEN, 1, 0, "s1", NO_CPID, "0 0", _("^K1You were frozen by ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE, 1, 0, "s1", NO_CPID, "0 0", _("^K3You revived ^BG%s"), "") \ - MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_FALL, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \ + MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_SELF, 0, 0, "", NO_CPID, "0 0", _("^K3You revived yourself"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVED, 1, 0, "s1", NO_CPID, "0 0", _("^K3You were revived by ^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_AUTO_REVIVED, 0, 1, "f1", NO_CPID, "0 0", _("^K3You were automatically revived after %s second(s)"), "") \ MULTITEAM_CENTER(1, CENTER_ROUND_TEAM_WIN_, 4, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "") \ @@@ -627,6 -646,8 +646,8 @@@ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SELF, 0, 0, "", NO_CPID, "0 0", _("^K1You froze yourself"), "") \ MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SPAWN_LATE, 0, 0, "", NO_CPID, "0 0", _("^K1Round already started, you spawn as frozen"), "") \ MSG_CENTER_NOTIF(1, CENTER_INVASION_SUPERMONSTER, 1, 0, "s1", NO_CPID, "0 0", _("^K1A %s has arrived!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_DROP, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG Buff!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_ITEM_BUFF_GOT, 0, 1, "item_buffname", CPID_ITEM, "item_centime 0", _("^BGYou got the %s^BG Buff!"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DONTHAVE, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_DROP, 1, 1, "item_wepname item_wepammo", CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "") \ MSG_CENTER_NOTIF(1, CENTER_ITEM_WEAPON_GOT, 0, 1, "item_wepname", CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%s"), "") \ @@@ -637,6 -658,7 +658,7 @@@ MSG_CENTER_NOTIF(1, CENTER_JOIN_PREVENT, 0, 0, "", CPID_PREVENT_JOIN, "0 0", _("^K1You may not join the game at this time.\nThe player limit reached maximum capacity."), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_DROPPED, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has dropped the ball!"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_PICKUP, 1, 0, "s1", CPID_KEEPAWAY, "0 0", _("^BG%s^BG has picked up the ball!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_PICKUP_SELF, 0, 0, "", CPID_KEEPAWAY, "0 0", _("^BGYou picked up the ball"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEEPAWAY_WARN, 0, 0, "", CPID_KEEPAWAY_WARN, "0 0", _("^BGKilling people while you don't have the ball gives no points!"), "") \ MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_HELP, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nHelp the key carriers to meet!"), "") \ MULTITEAM_CENTER(1, CENTER_KEYHUNT_INTERFERE_, 4, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in ^TC^TT team^BG's hands!\nInterfere ^F4NOW^BG!"), "") \ @@@ -674,12 -696,7 +696,12 @@@ MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SPECTATE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Spectating in ^COUNT"), "") \ MSG_CENTER_NOTIF(1, CENTER_TEAMCHANGE_SUICIDE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Suicide in ^COUNT"), "") \ MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_BEGINNING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout begins in ^COUNT"), "") \ - MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "") + MSG_CENTER_NOTIF(1, CENTER_TIMEOUT_ENDING, 0, 1, "", CPID_TIMEOUT, "1 f1", _("^F4Timeout ends in ^COUNT"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter/exit the vehicle"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER_GUNNER, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to enter the vehicle gunner"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_ENTER_STEAL, 0, 0, "pass_key", CPID_VEHICLES, "0 0", _("^BGPress ^F2DROPFLAG%s^BG to steal this vehicle"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_STEAL, 0, 0, "", CPID_VEHICLES_OTHER, "0 0", _("^F2The enemy is stealing one of your vehicles!\n^F4Stop them!"), "") \ + MSG_CENTER_NOTIF(1, CENTER_VEHICLE_STEAL_SELF, 0, 0, "", CPID_VEHICLES_OTHER, "4 0", _("^F2You have stolen the enemy's vehicle, you are now visible on their radar!"), "") #define MULTITEAM_MULTI2(default,prefix,anncepre,infopre,centerpre) \ MSG_MULTI_NOTIF(default, prefix##RED, anncepre##RED, infopre##RED, centerpre##RED) \ @@@ -704,6 -721,10 +726,10 @@@ MSG_MULTI_NOTIF(1, DEATH_MURDER_LAVA, NO_MSG, INFO_DEATH_MURDER_LAVA, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_MONSTER, NO_MSG, INFO_DEATH_MURDER_MONSTER, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE, NO_MSG, INFO_DEATH_MURDER_NADE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_NAPALM, NO_MSG, INFO_DEATH_MURDER_NADE_NAPALM, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_MURDER_NADE_ICE_FREEZE, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_NADE_HEAL, NO_MSG, INFO_DEATH_MURDER_NADE_HEAL, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SHOOTING_STAR, NO_MSG, INFO_DEATH_MURDER_SHOOTING_STAR, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SLIME, NO_MSG, INFO_DEATH_MURDER_SLIME, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_SWAMP, NO_MSG, INFO_DEATH_MURDER_SWAMP, NO_MSG) \ @@@ -721,6 -742,7 +747,7 @@@ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_DEATH, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_GUN, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_MURDER_VH_WAKI_ROCKET, NO_MSG) \ + MSG_MULTI_NOTIF(1, DEATH_MURDER_VENGEANCE, NO_MSG, INFO_DEATH_MURDER_VENGEANCE, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID, NO_MSG, INFO_DEATH_MURDER_VOID, NO_MSG) \ MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE, NO_MSG, INFO_DEATH_SELF_AUTOTEAMCHANGE, CENTER_DEATH_SELF_AUTOTEAMCHANGE) \ MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL, NO_MSG, INFO_DEATH_SELF_BETRAYAL, CENTER_DEATH_SELF_BETRAYAL) \ @@@ -741,6 -763,10 +768,10 @@@ MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_JUMP, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_JUMP, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_SELF_MON_ZOMBIE_MELEE, NO_MSG, INFO_DEATH_SELF_MON_ZOMBIE_MELEE, CENTER_DEATH_SELF_MONSTER) \ MSG_MULTI_NOTIF(1, DEATH_SELF_NADE, NO_MSG, INFO_DEATH_SELF_NADE, CENTER_DEATH_SELF_NADE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_NAPALM, NO_MSG, INFO_DEATH_SELF_NADE_NAPALM, CENTER_DEATH_SELF_NADE_NAPALM) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE, NO_MSG, INFO_DEATH_SELF_NADE_ICE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_ICE_FREEZE, NO_MSG, INFO_DEATH_SELF_NADE_ICE_FREEZE, CENTER_DEATH_SELF_NADE_ICE_FREEZE) \ + MSG_MULTI_NOTIF(1, DEATH_SELF_NADE_HEAL, NO_MSG, INFO_DEATH_SELF_NADE_HEAL, CENTER_DEATH_SELF_NADE_HEAL) \ MSG_MULTI_NOTIF(1, DEATH_SELF_NOAMMO, NO_MSG, INFO_DEATH_SELF_NOAMMO, CENTER_DEATH_SELF_NOAMMO) \ MSG_MULTI_NOTIF(1, DEATH_SELF_ROT, NO_MSG, INFO_DEATH_SELF_ROT, CENTER_DEATH_SELF_ROT) \ MSG_MULTI_NOTIF(1, DEATH_SELF_SHOOTING_STAR, NO_MSG, INFO_DEATH_SELF_SHOOTING_STAR, CENTER_DEATH_SELF_SHOOTING_STAR) \ @@@ -771,6 -797,8 +802,8 @@@ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_DEATH, NO_MSG, INFO_DEATH_SELF_VH_WAKI_DEATH, CENTER_DEATH_SELF_VH_WAKI_DEATH) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VH_WAKI_ROCKET, NO_MSG, INFO_DEATH_SELF_VH_WAKI_ROCKET, CENTER_DEATH_SELF_VH_WAKI_ROCKET) \ MSG_MULTI_NOTIF(1, DEATH_SELF_VOID, NO_MSG, INFO_DEATH_SELF_VOID, CENTER_DEATH_SELF_VOID) \ + MSG_MULTI_NOTIF(1, ITEM_BUFF_DROP, NO_MSG, INFO_ITEM_BUFF_DROP, CENTER_ITEM_BUFF_DROP) \ + MSG_MULTI_NOTIF(1, ITEM_BUFF_GOT, NO_MSG, INFO_ITEM_BUFF_GOT, CENTER_ITEM_BUFF_GOT) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DONTHAVE, NO_MSG, INFO_ITEM_WEAPON_DONTHAVE, CENTER_ITEM_WEAPON_DONTHAVE) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_DROP, NO_MSG, INFO_ITEM_WEAPON_DROP, CENTER_ITEM_WEAPON_DROP) \ MSG_MULTI_NOTIF(1, ITEM_WEAPON_GOT, NO_MSG, INFO_ITEM_WEAPON_GOT, CENTER_ITEM_WEAPON_GOT) \ @@@ -938,6 -966,7 +971,7 @@@ var float autocvar_notification_show_sp item_wepname: return full name of a weapon from weaponid item_wepammo: ammo display for weapon from string item_centime: amount of time to display weapon message in centerprint + item_buffname: return full name of a buff from buffid death_team: show the full name of the team a player is switching from */ @@@ -990,6 -1019,7 +1024,7 @@@ string arg_slot[NOTIF_MAX_ARGS] ARG_CASE(ARG_CS_SV, "spree_end", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \ ARG_CASE(ARG_CS_SV, "spree_lost", (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \ ARG_CASE(ARG_CS_SV, "item_wepname", W_Name(f1)) \ + ARG_CASE(ARG_CS_SV, "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buff_Color(f1)), Buff_PrettyName(f1))) \ ARG_CASE(ARG_CS_SV, "item_wepammo", (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \ ARG_CASE(ARG_DC, "item_centime", ftos(autocvar_notification_item_centerprinttime)) \ ARG_CASE(ARG_SV, "death_team", Team_ColoredFullName(f1)) \ diff --combined qcsrc/common/vehicles/cl_vehicles.qc index f15829d57,000000000..9a2598f82 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/cl_vehicles.qc +++ b/qcsrc/common/vehicles/cl_vehicles.qc @@@ -1,300 -1,0 +1,126 @@@ +#define hud_bg "gfx/vehicles/frame.tga" +#define hud_sh "gfx/vehicles/vh-shield.tga" + +#define hud_hp_bar "gfx/vehicles/bar_up_left.tga" +#define hud_hp_ico "gfx/vehicles/health.tga" +#define hud_sh_bar "gfx/vehicles/bar_dwn_left.tga" +#define hud_sh_ico "gfx/vehicles/shield.tga" + +#define hud_ammo1_bar "gfx/vehicles/bar_up_right.tga" +#define hud_ammo1_ico "gfx/vehicles/bullets.tga" +#define hud_ammo2_bar "gfx/vehicles/bar_dwn_right.tga" +#define hud_ammo2_ico "gfx/vehicles/rocket.tga" +#define hud_energy "gfx/vehicles/energy.tga" + +entity dropmark; +var float autocvar_cl_vehicles_hudscale = 0.5; +var float autocvar_cl_vehicles_hudalpha = 0.75; + - void CSQC_BUMBLE_GUN_HUD(); - +const float MAX_AXH = 4; +entity AuxiliaryXhair[MAX_AXH]; + +.string axh_image; +.float axh_fadetime; +.float axh_drawflag; +.float axh_scale; + - #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" - +float alarm1time; +float alarm2time; + +void vehicle_alarm(entity e, float ch, string s0und) +{ + if(!autocvar_cl_vehicles_alarm) + return; + + sound(e, ch, s0und, VOL_BASEVOICE, ATTEN_NONE); +} + +void AuxiliaryXhair_Draw2D() +{ + vector loc, psize; + + 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)) + { + loc_z = 0; + psize_z = 0; + drawpic(loc, self.axh_image, psize, self.colormod, self.alpha, self.axh_drawflag); + } + + if(time - self.cnt > self.axh_fadetime) + self.draw2d = func_null; +} + +void Net_AuXair2(float bIsNew) +{ + float 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.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() +{ + float i; + + float 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) + { + 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; + } + - VEH_ACTION(hud_id, VR_SETUP); - + 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; + } - } - - void CSQC_BUMBLE_GUN_HUD() - { - - if(autocvar_r_letterbox) - return; - - vector picsize, hudloc = '0 0 0', pic2size, picloc; - - // Fetch health & ammo stats - HUD_GETVEHICLESTATS - - picsize = draw_getimagesize(hud_bg) * autocvar_cl_vehicles_hudscale; - hudloc_y = vid_conheight - picsize_y; - hudloc_x = vid_conwidth * 0.5 - picsize_x * 0.5; - - drawpic(hudloc, hud_bg, picsize, '1 1 1', autocvar_cl_vehicles_hudalpha, DRAWFLAG_NORMAL); - - shield *= 0.01; - vh_health *= 0.01; - energy *= 0.01; - reload1 *= 0.01; - - pic2size = draw_getimagesize(bumb_gun_ico) * (autocvar_cl_vehicles_hudscale * 0.8); - picloc = picsize * 0.5 - pic2size * 0.5; - - if(vh_health < 0.25) - drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, bumb_gun_ico, pic2size, '1 1 1' * vh_health + '1 0 0' * (1 - vh_health), 1, DRAWFLAG_NORMAL); - - drawpic(hudloc + picloc, bumb_gun_gun, pic2size, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL); - drawpic(hudloc + picloc, hud_sh, pic2size, '1 1 1', shield, DRAWFLAG_NORMAL); - - // Health bar - picsize = draw_getimagesize(hud_hp_bar) * autocvar_cl_vehicles_hudscale; - picloc = '69 69 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - vh_health)), 0, vid_conwidth, vid_conheight); - drawpic(hudloc + picloc, hud_hp_bar, picsize, '1 1 1', 1 , DRAWFLAG_NORMAL); - drawresetcliparea(); - // .. and icon - picsize = draw_getimagesize(hud_hp_ico) * autocvar_cl_vehicles_hudscale; - picloc = '37 65 0' * autocvar_cl_vehicles_hudscale; - if(vh_health < 0.25) - { - if(alarm1time < time) - { - alarm1time = time + 2; - vehicle_alarm(self, CH_PAIN_SINGLE, "vehicles/alarm.wav"); - } - - drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - } - else - { - drawpic(hudloc + picloc, hud_hp_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - if(alarm1time) - { - vehicle_alarm(self, CH_PAIN_SINGLE, "misc/null.wav"); - alarm1time = 0; - } - } - - // Shield bar - picsize = draw_getimagesize(hud_sh_bar) * autocvar_cl_vehicles_hudscale; - picloc = '69 140 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x + (picsize_x * (1 - shield)), 0, vid_conwidth, vid_conheight); - drawpic(hudloc + picloc, hud_sh_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawresetcliparea(); - // .. and icon - picloc = '40 136 0' * autocvar_cl_vehicles_hudscale; - picsize = draw_getimagesize(hud_sh_ico) * autocvar_cl_vehicles_hudscale; - if(shield < 0.25) - { - if(alarm2time < time) - { - alarm2time = time + 1; - vehicle_alarm(self, CH_TRIGGER_SINGLE, "vehicles/alarm_shield.wav"); - } - drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - } - else - { - drawpic(hudloc + picloc, hud_sh_ico, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - if(alarm2time) - { - vehicle_alarm(self, CH_TRIGGER_SINGLE, "misc/null.wav"); - alarm2time = 0; - } - } - - // Gun bar - picsize = draw_getimagesize(hud_ammo1_bar) * autocvar_cl_vehicles_hudscale; - picloc = '450 69 0' * autocvar_cl_vehicles_hudscale; - drawsetcliparea(hudloc_x + picloc_x, picloc_y, picsize_x * energy, vid_conheight); - drawpic(hudloc + picloc, hud_ammo1_bar, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - drawresetcliparea(); - - // .. and icon - picsize = 1.5 * draw_getimagesize(hud_energy) * autocvar_cl_vehicles_hudscale; - picloc = '664 60 0' * autocvar_cl_vehicles_hudscale; - if(energy < 0.2) - drawpic(hudloc + picloc, hud_energy, picsize, '1 0 0' + '0 1 1' * sin(time * 8), 1, DRAWFLAG_NORMAL); - else - drawpic(hudloc + picloc, hud_energy, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - - if (scoreboard_showscores) - HUD_DrawScoreboard(); - /* - else - { - picsize = draw_getimagesize(waki_xhair); - picsize_x *= 0.5; - picsize_y *= 0.5; - - - drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), waki_xhair, picsize, '1 1 1', 1, DRAWFLAG_NORMAL); - } - */ - } - - void 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; ++ else { VEH_ACTION(hud_id, VR_SETUP); } +} diff --combined qcsrc/common/vehicles/sv_vehicles.qc index 3369fef9a,000000000..bcfbf8875 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/sv_vehicles.qc +++ b/qcsrc/common/vehicles/sv_vehicles.qc @@@ -1,1245 -1,0 +1,1260 @@@ +// ========================= +// SVQC Vehicle Properties +// ========================= + + +float SendAuxiliaryXhair(entity to, float 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, float 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, float 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; + float 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))) + trace_ent = world; + - if(trace_ent.alpha <= 0.5) ++ if(trace_ent.alpha <= 0.5 && trace_ent.alpha) + 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, float 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, 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, + float _deahtype, float _projtype, float _health, + float _cull, float _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); + + + 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); + 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, float _burn, float _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; +} + +float vehicle_addplayerslot( entity _owner, + entity _slot, + float _hud, + string _hud_model, + float() _framefunc, + void(float) _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); + + 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"); - vehicles_setreturn(self); - vehicles_reset_colors(); ++ 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, float deathtype, vector hitloc, vector force) +{ + self.dmg_time = time; + + if(DEATH_ISWEAPON(deathtype, WEP_NEX)) + damage *= autocvar_g_vehicles_nex_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_UZI)) + damage *= autocvar_g_vehicles_uzi_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_RIFLE)) + damage *= autocvar_g_vehicles_rifle_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_MINSTANEX)) + damage *= autocvar_g_vehicles_minstanex_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_SEEKER)) + damage *= autocvar_g_vehicles_tag_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)) + return TRUE; + + if(e.flags & FL_MONSTER) + 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(float 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; + + 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; + + _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)) + 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) != 0) + 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); +} + +void vehicles_enter(entity pl, entity veh) +{ + // Remove this when bots know how to use vehicles + if (IS_BOT_CLIENT(pl)) + if (autocvar_g_vehicles_allow_bots) + dprint("Bot enters vehicle\n"); // This is where we need to disconnect (some, all?) normal bot AI and hand over to vehicle's _aiframe() + else + return; + + if(!IS_PLAYER(pl)) + return; + + if(veh.phase > time) + return; + - if(pl.freezetag_frozen) ++ if(pl.frozen) + return; + + if(pl.deadflag != DEAD_NO) + return; + + if(pl.vehicle) + return; + + if(autocvar_g_vehicles_enter) // skip if we're using regular touch code + if(veh.vehicle_flags & VHF_MULTISLOT) + if(veh.owner) + { + entity oldself = self; + self = veh; + other = pl; // TODO: fix + + if(!veh.gunner1) + if(veh.gun1.phase <= time) + if(veh.gun1.vehicle_enter) + if(veh.gun1.vehicle_enter()) + { + self = oldself; + return; + } + + if(!veh.gunner2) + if(veh.gun2.phase <= time) + 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; + + // 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); + + 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); + + 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(); +} + +float vehicle_initialize(float vehicle_id, float 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) ++ 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; + + setmodel(self, veh.model); + + 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(autocvar_g_vehicles_delayspawn) ++ 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 --combined qcsrc/common/vehicles/sv_vehicles.qh index 36b7880e1,000000000..2e8fb4b56 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/sv_vehicles.qh +++ b/qcsrc/common/vehicles/sv_vehicles.qh @@@ -1,102 -1,0 +1,103 @@@ +// #define VEHICLES_USE_ODE + +// vehicle cvars +float autocvar_g_vehicles; +float autocvar_g_vehicles_enter; +float autocvar_g_vehicles_enter_radius; +float autocvar_g_vehicles_steal; +float autocvar_g_vehicles_steal_show_waypoint; +float autocvar_g_vehicles_crush_dmg; +float autocvar_g_vehicles_crush_force; +float autocvar_g_vehicles_delayspawn; +float autocvar_g_vehicles_delayspawn_jitter; +float autocvar_g_vehicles_allow_bots; +float autocvar_g_vehicles_teams; ++//float autocvar_g_vehicles_teleportable; +var float autocvar_g_vehicles_nex_damagerate = 0.5; +var float autocvar_g_vehicles_uzi_damagerate = 0.5; +var float autocvar_g_vehicles_rifle_damagerate = 0.75; +var float autocvar_g_vehicles_minstanex_damagerate = 0.001; +var float autocvar_g_vehicles_tag_damagerate = 5; + +// vehicle definitions +.entity gun1; +.entity gun2; +.entity gun3; +.entity vehicle_shieldent; /// Entity to disply the shild effect on damage +.entity vehicle; +.entity vehicle_viewport; +.entity vehicle_hudmodel; +.entity vehicle_controller; + +.entity gunner1; +.entity gunner2; + +.float vehicle_health; /// If self is player this is 0..100 indicating precentage of health left on vehicle. If self is vehile, this is the real health value. +.float vehicle_energy; /// If self is player this is 0..100 indicating precentage of energy left on vehicle. If self is vehile, this is the real energy value. +.float vehicle_shield; /// If self is player this is 0..100 indicating precentage of shield left on vehicle. If self is vehile, this is the real shield value. + +.float vehicle_ammo1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo1 value. +.float vehicle_reload1; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload1 value. +.float vehicle_ammo2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real ammo2 value. +.float vehicle_reload2; /// If self is player this field's use depends on the individual vehile. If self is vehile, this is the real reload2 value. + +.float sound_nexttime; +#define VOL_VEHICLEENGINE 1 + +const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05 +const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A +const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80 + +#define VHSF_NORMAL 0 +#define VHSF_FACTORY 2 + +.float hud; +.float dmg_time; + +.float volly_counter; + +const float MAX_AXH = 4; +.entity AuxiliaryXhair[MAX_AXH]; + +.entity wps_intruder; + +.entity lock_target; +.float lock_strength; +.float lock_time; +.float lock_soundtime; +const float DAMAGE_TARGETDRONE = 10; + +float force_fromtag_power; +float force_fromtag_normpower; +vector force_fromtag_origin; + +float vehicles_exit_running; + +#ifdef VEHICLES_USE_ODE +void(entity e, float physics_enabled) physics_enable = #540; // enable or disable physics on object +void(entity e, vector force, vector force_pos) physics_addforce = #541; // apply a force from certain origin, length of force vector is power of force +void(entity e, vector torque) physics_addtorque = #542; // add relative torque +#endif // VEHICLES_USE_ODE + +// functions used outside the vehicle code +void vehicles_exit(float eject); +void vehicles_enter(entity pl, entity veh); + +// vehicle functions +.void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns +.float(float _imp) vehicles_impulse; +.float vehicle_weapon2mode; +.void(float exit_flags) vehicle_exit; +.float() vehicle_enter; +const float VHEF_NORMAL = 0; /// User pressed exit key +const float VHEF_EJECT = 1; /// User pressed exit key 3 times fast (not implemented) or vehile is dying +const float VHEF_RELEASE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented) + +// macros +#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \ + ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 + +#define vehicles_sweap_collision(orig,vel,dt,acm,mult) \ + traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \ + if(trace_fraction != 1) \ + acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult) diff --combined qcsrc/common/vehicles/unit/bumblebee.qc index 0184e4f0d,000000000..d994c3590 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/bumblebee.qc +++ b/qcsrc/common/vehicles/unit/bumblebee.qc @@@ -1,1261 -1,0 +1,1388 @@@ +#ifdef REGISTER_VEHICLE +REGISTER_VEHICLE( +/* VEH_##id */ BUMBLEBEE, +/* function */ v_bumblebee, +/* spawnflags */ VHF_DMGSHAKE, +/* mins,maxs */ '-245 -130 -130', '230 130 130', +/* model */ "models/vehicles/bumblebee_body.dpm", +/* head_model */ "", +/* hud_model */ "models/vehicles/spiderbot_cockpit.dpm", +/* tags */ "", "", "tag_viewport", +/* netname */ "bumblebee", +/* fullname */ _("Bumblebee") +); +#else + +const float BRG_SETUP = 2; +const float BRG_START = 4; +const float BRG_END = 8; + +#ifdef SVQC +float autocvar_g_vehicle_bumblebee_speed_forward; +float autocvar_g_vehicle_bumblebee_speed_strafe; +float autocvar_g_vehicle_bumblebee_speed_up; +float autocvar_g_vehicle_bumblebee_speed_down; +float autocvar_g_vehicle_bumblebee_turnspeed; +float autocvar_g_vehicle_bumblebee_pitchspeed; +float autocvar_g_vehicle_bumblebee_pitchlimit; +float autocvar_g_vehicle_bumblebee_friction; + +float autocvar_g_vehicle_bumblebee_energy; +float autocvar_g_vehicle_bumblebee_energy_regen; +float autocvar_g_vehicle_bumblebee_energy_regen_pause; + +float autocvar_g_vehicle_bumblebee_health; +float autocvar_g_vehicle_bumblebee_health_regen; +float autocvar_g_vehicle_bumblebee_health_regen_pause; + +float autocvar_g_vehicle_bumblebee_shield; +float autocvar_g_vehicle_bumblebee_shield_regen; +float autocvar_g_vehicle_bumblebee_shield_regen_pause; + +float autocvar_g_vehicle_bumblebee_cannon_cost; +float autocvar_g_vehicle_bumblebee_cannon_damage; +float autocvar_g_vehicle_bumblebee_cannon_radius; +float autocvar_g_vehicle_bumblebee_cannon_refire; +float autocvar_g_vehicle_bumblebee_cannon_speed; +float autocvar_g_vehicle_bumblebee_cannon_spread; +float autocvar_g_vehicle_bumblebee_cannon_force; + +float autocvar_g_vehicle_bumblebee_cannon_ammo; +float autocvar_g_vehicle_bumblebee_cannon_ammo_regen; +float autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause; + +var float autocvar_g_vehicle_bumblebee_cannon_lock = 0; + +float autocvar_g_vehicle_bumblebee_cannon_turnspeed; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down; +float autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_in; +float autocvar_g_vehicle_bumblebee_cannon_turnlimit_out; + + +float autocvar_g_vehicle_bumblebee_raygun_turnspeed; +float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_down; +float autocvar_g_vehicle_bumblebee_raygun_pitchlimit_up; +float autocvar_g_vehicle_bumblebee_raygun_turnlimit_sides; + +float autocvar_g_vehicle_bumblebee_raygun_range; +float autocvar_g_vehicle_bumblebee_raygun_dps; +float autocvar_g_vehicle_bumblebee_raygun_aps; +float autocvar_g_vehicle_bumblebee_raygun_fps; + +float autocvar_g_vehicle_bumblebee_raygun; +float autocvar_g_vehicle_bumblebee_healgun_hps; +float autocvar_g_vehicle_bumblebee_healgun_hmax; +float autocvar_g_vehicle_bumblebee_healgun_aps; +float autocvar_g_vehicle_bumblebee_healgun_amax; +float autocvar_g_vehicle_bumblebee_healgun_sps; +float autocvar_g_vehicle_bumblebee_healgun_locktime; + +float autocvar_g_vehicle_bumblebee_respawntime; + +float autocvar_g_vehicle_bumblebee_blowup_radius; +float autocvar_g_vehicle_bumblebee_blowup_coredamage; +float autocvar_g_vehicle_bumblebee_blowup_edgedamage; +float autocvar_g_vehicle_bumblebee_blowup_forceintensity; +var vector autocvar_g_vehicle_bumblebee_bouncepain; + +var float autocvar_g_vehicle_bumblebee = 0; + + +float bumble_raygun_send(entity to, float sf); + +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(teamplay) + { + if(trace_ent.team != gunner.team) + { + gun.enemy = trace_ent; + gun.lock_time = time + 5; + } + } + else + { + gun.enemy = trace_ent; + gun.lock_time = time + 5; + } + } + } + + if(gun.enemy) + { + float distance, impact_time; + + vector vf = real_origin(gun.enemy); + vector _vel = gun.enemy.velocity; + if(gun.enemy.movetype == MOVETYPE_WALK) + _vel_z *= 0.1; + + + ad = vf; + distance = vlen(ad - gunner.origin); + impact_time = distance / autocvar_g_vehicle_bumblebee_cannon_speed; + ad = vf + _vel * impact_time; + trace_endpos = ad; + + + UpdateAuxiliaryXhair(gunner, ad, '1 0 1', 1); + vehicle_aimturret(vehic, trace_endpos, gun, "fire", + autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + + } + else + vehicle_aimturret(vehic, _ct, gun, "fire", + autocvar_g_vehicle_bumblebee_cannon_pitchlimit_down * -1, autocvar_g_vehicle_bumblebee_cannon_pitchlimit_up, + _out * -1, _in, autocvar_g_vehicle_bumblebee_cannon_turnspeed); + + if(!forbidWeaponUse(gunner)) + if(gunner.BUTTON_ATCK) + if(time > gun.attack_finished_single) + if(gun.vehicle_energy >= autocvar_g_vehicle_bumblebee_cannon_cost) + { + gun.vehicle_energy -= autocvar_g_vehicle_bumblebee_cannon_cost; + bumblebee_fire_cannon(gun, "fire", gunner); + gun.delay = time; + gun.attack_finished_single = time + autocvar_g_vehicle_bumblebee_cannon_refire; + } + + VEHICLE_UPDATE_PLAYER(gunner, health, bumblebee); + + if(vehic.vehicle_flags & VHF_HASSHIELD) + VEHICLE_UPDATE_PLAYER(gunner, shield, bumblebee); + + ad = gettaginfo(gun, gettagindex(gun, "fire")); + traceline(ad, ad + v_forward * MAX_SHOT_DISTANCE, MOVE_NORMAL, gun); + + UpdateAuxiliaryXhair(gunner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), 0); + + if(vehic.owner) + UpdateAuxiliaryXhair(vehic.owner, trace_endpos, ('1 0 0' * gunner.vehicle_reload1) + ('0 1 0' *(1 - gunner.vehicle_reload1)), ((gunner == vehic.gunner1) ? 1 : 2)); + + vehic.solid = SOLID_BBOX; + gunner.BUTTON_ATCK = gunner.BUTTON_ATCK2 = gunner.BUTTON_CROUCH = 0; + gunner.vehicle_energy = (gun.vehicle_energy / autocvar_g_vehicle_bumblebee_cannon_ammo) * 100; + + self = gunner; + return 1; +} + +void bumblebee_gunner_exit(float _exitflag) +{ + if(IS_REAL_CLIENT(self)) + { + msg_entity = self; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, self); + + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, 0); + WriteAngle(MSG_ONE, self.vehicle.angles_y); + WriteAngle(MSG_ONE, 0); + } + + CSQCVehicleSetup(self, HUD_NORMAL); + setsize(self, PL_MIN, PL_MAX); + + self.takedamage = DAMAGE_AIM; + self.solid = SOLID_SLIDEBOX; + self.movetype = MOVETYPE_WALK; + self.effects &= ~EF_NODRAW; + self.alpha = 1; + self.PlayerPhysplug = func_null; + self.view_ofs = PL_VIEW_OFS; + self.event_damage = PlayerDamage; + self.hud = HUD_NORMAL; + self.teleportable = TELEPORT_NORMAL; + self.switchweapon = self.vehicle.switchweapon; + + vh_player = self; + vh_vehicle = self.vehicle; + MUTATOR_CALLHOOK(VehicleExit); + self = vh_player; + self.vehicle = vh_vehicle; + + self.vehicle.vehicle_hudmodel.viewmodelforclient = self.vehicle; + + fixedmakevectors(self.vehicle.owner.angles); + + if(self == self.vehicle.owner.gunner1) + { + self.vehicle.owner.gunner1 = world; + } + else if(self == self.vehicle.owner.gunner2) + { + self.vehicle.owner.gunner2 = world; + v_right *= -1; + } + else + dprint("^1self != gunner1 or gunner2, this is a BIG PROBLEM, tell tZork this happend.\n"); + + vector spot = self.vehicle.owner.origin + + v_up * 128 + v_right * 300; + spot = vehicles_findgoodexit(spot); + //setorigin(self , spot); + + self.velocity = 0.75 * self.vehicle.owner.velocity + normalize(spot - self.vehicle.owner.origin) * 200; + self.velocity_z += 10; + + self.vehicle.phase = time + 5; + self.vehicle = world; +} + +float bumblebee_gunner_enter() +{ + RemoveGrapplingHook(other); + entity _gun, _gunner; + if(!self.gunner1) + { + _gun = self.gun1; + _gunner = self.gunner1; + self.gunner1 = other; + } + else if(!self.gunner2) + { + _gun = self.gun2; + _gunner = self.gunner2; + self.gunner2 = other; + } + else + { + dprint("^1ERROR:^7Tried to enter a fully occupied vehicle!\n"); + return FALSE; + } + + _gunner = other; + _gunner.vehicle = _gun; + _gun.switchweapon = other.switchweapon; + _gun.vehicle_exit = bumblebee_gunner_exit; + + other.angles = self.angles; + other.takedamage = DAMAGE_NO; + other.solid = SOLID_NOT; + other.movetype = MOVETYPE_NOCLIP; + other.alpha = -1; + other.event_damage = func_null; + other.view_ofs = '0 0 0'; + other.hud = _gun.hud; + other.teleportable = FALSE; + other.PlayerPhysplug = _gun.PlayerPhysplug; + other.vehicle_ammo1 = self.vehicle_ammo1; + other.vehicle_ammo2 = self.vehicle_ammo2; + other.vehicle_reload1 = self.vehicle_reload1; + other.vehicle_reload2 = self.vehicle_reload2; + other.vehicle_energy = self.vehicle_energy; + other.PlayerPhysplug = bumblebee_gunner_frame; + other.flags &= ~FL_ONGROUND; + + if(IS_REAL_CLIENT(other)) + { + msg_entity = other; + WriteByte(MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, _gun.vehicle_viewport); + WriteByte(MSG_ONE, SVC_SETVIEWANGLES); + WriteAngle(MSG_ONE, _gun.angles_x + self.angles_x); // tilt + WriteAngle(MSG_ONE, _gun.angles_y + self.angles_y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + + _gun.vehicle_hudmodel.viewmodelforclient = other; + + CSQCVehicleSetup(other, other.hud); + + vh_player = other; + vh_vehicle = _gun; + MUTATOR_CALLHOOK(VehicleEnter); + other = vh_player; + _gun = vh_vehicle; + + return TRUE; +} + +float vehicles_valid_pilot() +{ + if (!IS_PLAYER(other)) + return FALSE; + + if(other.deadflag != DEAD_NO) + return FALSE; + + if(other.vehicle != world) + return FALSE; + + if (!IS_REAL_CLIENT(other)) + if(!autocvar_g_vehicles_allow_bots) + return FALSE; + + if(teamplay && other.team != self.team) + 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()) + { + if(self.gun1.phase <= time) + if(bumblebee_gunner_enter()) + return; + + if(self.gun2.phase <= time) + if(bumblebee_gunner_enter()) + return; + } + + vehicles_touch(); +} + +void bumblebee_regen() +{ + if(self.gun1.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time) + self.gun1.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo, + self.gun1.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime); + + if(self.gun2.delay + autocvar_g_vehicle_bumblebee_cannon_ammo_regen_pause < time) + self.gun2.vehicle_energy = min(autocvar_g_vehicle_bumblebee_cannon_ammo, + self.gun2.vehicle_energy + autocvar_g_vehicle_bumblebee_cannon_ammo_regen * frametime); + + if(self.vehicle_flags & VHF_SHIELDREGEN) + vehicles_regen(self.dmg_time, vehicle_shield, autocvar_g_vehicle_bumblebee_shield, autocvar_g_vehicle_bumblebee_shield_regen_pause, autocvar_g_vehicle_bumblebee_shield_regen, frametime, TRUE); + + 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) + { - if(trace_ent.health <= trace_ent.tur_health && autocvar_g_vehicle_bumblebee_healgun_hps) - trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * frametime, trace_ent.tur_health); ++ 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, + autocvar_g_vehicle_bumblebee_blowup_forceintensity, + DEATH_VH_BUMB_DEATH, world); + + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); + pointparticles(particleeffectnum("explosion_big"), (self.origin + '0 0 100') + (randomvec() * 80), '0 0 0', 1); + + if(self.owner.deadflag == DEAD_DYING) + self.owner.deadflag = DEAD_DEAD; + + remove(self); +} + +void bumblebee_diethink() +{ + if(time >= self.wait) + self.think = bumblebee_blowup; + + if(random() < 0.1) + { + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); + pointparticles(particleeffectnum("explosion_small"), randomvec() * 80 + (self.origin + '0 0 100'), '0 0 0', 1); + } + + self.nextthink = time + 0.1; +} + +float bumble_raygun_send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_BUMBLE_RAYGUN); + + WriteByte(MSG_ENTITY, sf); + if(sf & BRG_SETUP) + { + WriteByte(MSG_ENTITY, num_for_edict(self.realowner)); + WriteByte(MSG_ENTITY, self.realowner.team); + WriteByte(MSG_ENTITY, self.cnt); + } + + if(sf & BRG_START) + { + WriteCoord(MSG_ENTITY, self.hook_start_x); + WriteCoord(MSG_ENTITY, self.hook_start_y); + WriteCoord(MSG_ENTITY, self.hook_start_z); + } + + if(sf & BRG_END) + { + WriteCoord(MSG_ENTITY, self.hook_end_x); + WriteCoord(MSG_ENTITY, self.hook_end_y); + WriteCoord(MSG_ENTITY, self.hook_end_z); + } + + return TRUE; +} + +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); + + 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; + + 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); ++ } ++ */ ++} ++ +void bumble_raygun_draw() +{ + float _len; + vector _dir; + vector _vtmp1, _vtmp2; + + _len = vlen(self.origin - self.move_origin); + _dir = normalize(self.move_origin - self.origin); + + if(self.total_damages < time) + { + boxparticles(self.traileffect, self, self.origin, self.origin + _dir * -64, _dir * -_len , _dir * -_len, 1, PARTICLES_USEALPHA); + boxparticles(self.lip, self, self.move_origin, self.move_origin + _dir * -64, _dir * -200 , _dir * -200, 1, PARTICLES_USEALPHA); + self.total_damages = time + 0.1; + } + + float i, df, sz, al; + for(i = -0.1; i < 0.2; i += 0.1) + { + df = DRAWFLAG_NORMAL; //((random() < 0.5) ? DRAWFLAG_ADDITIVE : DRAWFLAG_SCREEN); + sz = 5 + random() * 5; + al = 0.25 + random() * 0.5; + _vtmp1 = self.origin + _dir * _len * (0.25 + i); + _vtmp1 += (randomvec() * (_len * 0.2) * (frametime * 2)); //self.raygun_l1; + Draw_CylindricLine(self.origin, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + _vtmp2 = self.origin + _dir * _len * (0.5 + i); + _vtmp2 += (randomvec() * (_len * 0.2) * (frametime * 5)); //self.raygun_l2; + Draw_CylindricLine(_vtmp1, _vtmp2, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + _vtmp1 = self.origin + _dir * _len * (0.75 + i); + _vtmp1 += randomvec() * (_len * 0.2) * (frametime * 10); //self.raygun_l3; + Draw_CylindricLine(_vtmp2, _vtmp1, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + + Draw_CylindricLine(_vtmp1, self.move_origin + randomvec() * 32, sz, "gfx/colors/white.tga", 1, 1, self.colormod, al, df, view_origin); + } +} + +void bumble_raygun_read(float bIsNew) +{ + float sf = ReadByte(); + + 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); + } + return TRUE; + } + case VR_SETUP: + { - // Raygun-locked ++ // raygun-locked + AuxiliaryXhair[0].axh_image = "gfx/vehicles/axh-bracket.tga"; + AuxiliaryXhair[0].axh_scale = 0.5; + + // Gunner1 + AuxiliaryXhair[1].axh_image = "gfx/vehicles/axh-target.tga"; + AuxiliaryXhair[1].axh_scale = 0.75; + + // Gunner2 + AuxiliaryXhair[2].axh_image = "gfx/vehicles/axh-target.tga"; + AuxiliaryXhair[2].axh_scale = 0.75; + return TRUE; + } + 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 // CSQC +#endif // REGISTER_VEHICLE diff --combined qcsrc/common/vehicles/unit/racer.qc index 445f37fb4,000000000..b70121c7c mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/racer.qc +++ b/qcsrc/common/vehicles/unit/racer.qc @@@ -1,909 -1,0 +1,909 @@@ +#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 +float 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_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; + ++var 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; + +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; + + if(pointcontents(self.origin - '0 0 64') == CONTENT_WATER) + 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 - autocvar_g_vehicle_racer_upforcedamper * _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 + } + + if(pointcontents(self.origin - '0 0 32') == CONTENT_WATER) + 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", + 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 + 5; ++ 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); + + player.BUTTON_ZOOM = player.BUTTON_CROUCH = 0; + + crosshair_trace(player); + + racer.angles_x *= -1; + + // Yaw + ftmp = autocvar_g_vehicle_racer_turnspeed * frametime; + 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; + + // Pitch + ftmp = autocvar_g_vehicle_racer_pitchspeed * frametime; + ftmp = bound(-ftmp, shortangle_f(player.v_angle_x - racer.angles_x, racer.angles_x), ftmp); + racer.angles_x = bound(-30, anglemods(racer.angles_x + ftmp), 30); + + makevectors(racer.angles); + racer.angles_x *= -1; + + //ftmp = racer.velocity_z; + df = racer.velocity * -autocvar_g_vehicle_racer_friction; + //racer.velocity_z = ftmp; + + if(vlen(player.movement) != 0) + { + if(pointcontents(racer.origin) == CONTENT_WATER) + { + 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); } + } + + 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); + } + } + 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); + } + } + + // Afterburn + if (player.BUTTON_JUMP && racer.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * frametime)) + { + if(time - racer.wait > 0.2) + pointparticles(particleeffectnum("wakizashi_booster_smoke"), self.origin - v_forward * 32, v_forward * vlen(self.velocity), 1); + + racer.wait = time; + + if(pointcontents(racer.origin) == CONTENT_WATER) + { + racer.vehicle_energy -= autocvar_g_vehicle_racer_waterburn_cost * frametime; + df += (v_forward * autocvar_g_vehicle_racer_waterburn_speed); + } + else + { + racer.vehicle_energy -= autocvar_g_vehicle_racer_afterburn_cost * frametime; + df += (v_forward * autocvar_g_vehicle_racer_speed_afterburn); + } + + 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); + } + } + else + { + racer.strength_finished = 0; + sound (racer.tur_head, CH_TRIGGER_SINGLE, "misc/null.wav", VOL_VEHICLEENGINE, ATTEN_NORM); + } + + df -= v_up * (vlen(racer.velocity) * autocvar_g_vehicle_racer_downforce); + player.movement = racer.velocity += df * frametime; + + 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); + 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_reload1 = 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; + 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); + + if(pointcontents(self.origin - '0 0 64') == CONTENT_WATER) + self.velocity_z += 200; + + self.velocity += df * pushdeltatime; + if(self.velocity_z > 0) + self.velocity_z *= 1 - autocvar_g_vehicle_racer_upforcedamper * 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, + 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) +{ + switch(req) + { + case VR_IMPACT: + { + 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); + return TRUE; + } + case VR_ENTER: + { + 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'); + + 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: + { + 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; + + return TRUE; + } + case VR_SETUP: + { + 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; + + return TRUE; + } + case VR_PRECACHE: + { + 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"); + 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: + { - precache_model ("models/vhshield.md3"); - precache_model ("models/vehicles/wakizashi.dpm"); - precache_model ("models/vehicles/wakizashi_cockpit.dpm"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --combined qcsrc/common/vehicles/unit/raptor.qc index e74d669f5,000000000..0a9b92167 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/raptor.qc +++ b/qcsrc/common/vehicles/unit/raptor.qc @@@ -1,1184 -1,0 +1,1222 @@@ +#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 float RSM_FIRST = 1; +const float RSM_BOMB = 1; +const float RSM_FLARE = 2; +const float RSM_LAST = 2; + +#ifdef SVQC +float 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, + 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, float 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); + + 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); + + 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); + + 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, 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); + } + 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 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 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); + + 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 + + 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) + { + 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); + } + + 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; + 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"); - + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --combined qcsrc/common/vehicles/unit/spiderbot.qc index 5e5720f68,000000000..aaa9f6dc5 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/unit/spiderbot.qc +++ b/qcsrc/common/vehicles/unit/spiderbot.qc @@@ -1,1083 -1,0 +1,1079 @@@ +#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 float SBRM_FIRST = 1; +const float SBRM_VOLLY = 1; +const float SBRM_GUIDE = 2; +const float SBRM_ARTILLERY = 3; +const float SBRM_LAST = 3; + +#ifdef SVQC +float 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_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; + +float autocvar_g_vehicle_spiderbot_health; +float autocvar_g_vehicle_spiderbot_health_regen; +float autocvar_g_vehicle_spiderbot_health_regen_pause; + +float 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; +float autocvar_g_vehicle_spiderbot_minigun_ammo_cost; +float autocvar_g_vehicle_spiderbot_minigun_ammo_max; +float 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 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) + { + 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 && 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; + player.BUTTON_JUMP = 0; + spider.velocity = v_forward * 700 + v_up * 600; + spider.frame = 4; + } + else + { + if(vlen(player.movement) == 0) + { + 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; + spider.frame = 0; + } + else if(player.movement_x < 0) + { + player.movement_x = -1; + spider.frame = 1; + } + player.movement_y = 0; + movelib_move_simple(normalize(v_forward * player.movement_x),autocvar_g_vehicle_spiderbot_speed_walk,autocvar_g_vehicle_spiderbot_movement_inertia); + + 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; + spider.frame = 2; + } + else if(player.movement_y > 0) + { + player.movement_y = 1; + spider.frame = 3; + } + movelib_move_simple(normalize(v_right * player.movement_y),autocvar_g_vehicle_spiderbot_speed_strafe,autocvar_g_vehicle_spiderbot_movement_inertia); + 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; + + mod(spider.misc_bulletcounter, 2) ? gun = spider.gun1 : gun = 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; + + 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); + } + 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); + } + 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, 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; +} + +float spiderbot_impulse(float _imp) +{ + switch(_imp) + { + 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 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 +var float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6; +var 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; + + 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 + { + 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; + } + } + + // 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); + } + + 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; + + 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"); + return TRUE; + } + } + + return TRUE; +} + +#endif // CSQC +#endif // REGISTER_VEHICLE diff --combined qcsrc/common/vehicles/vehicles.qc index f9271ef10,000000000..81aca27c2 mode 100644,000000..100644 --- a/qcsrc/common/vehicles/vehicles.qc +++ b/qcsrc/common/vehicles/vehicles.qc @@@ -1,88 -1,0 +1,87 @@@ +#include "all.qh" + +// 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(); - func(VR_PRECACHE); + #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 --combined qcsrc/server/cl_client.qc index eac1c5c7a,b3c6b6577..093f8f8c9 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@@ -1,6 -1,3 +1,3 @@@ - void race_send_recordtime(float msg); - void race_SendRankings(float pos, float prevpos, float del, float msg); - void send_CSQC_teamnagger() { WriteByte(MSG_BROADCAST, SVC_TEMPENTITY); WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER); @@@ -140,7 -137,6 +137,6 @@@ void PutObserverInServer (void { entity spot; self.hud = HUD_NORMAL; - race_PreSpawnObserver(); spot = SelectSpawnPoint (TRUE); if(!spot) @@@ -154,20 -150,14 +150,14 @@@ WriteEntity(MSG_ONE, self); } - if((g_race && g_race_qualifying) || g_cts) - { - if(PlayerScore_Add(self, SP_RACE_FASTEST, 0)) - self.frags = FRAGS_LMS_LOSER; - else - self.frags = FRAGS_SPECTATOR; - } - else - self.frags = FRAGS_SPECTATOR; + self.frags = FRAGS_SPECTATOR; MUTATOR_CALLHOOK(MakePlayerObserver); Portal_ClearAll(self); + Unfreeze(self); + if(self.alivetime) { if(!warmup_stage) @@@ -176,7 -166,7 +166,7 @@@ } if(self.vehicle) - vehicles_exit(VHEF_RELESE); + vehicles_exit(VHEF_RELEASE); WaypointSprite_PlayerDead(); @@@ -239,6 -229,7 +229,7 @@@ self.angles_z = 0; self.fixangle = TRUE; self.crouch = FALSE; + self.revival_time = 0; setorigin (self, (spot.origin + PL_VIEW_OFS)); // offset it so that the spectator spawns higher off the ground, looks better this way self.prevorigin = self.origin; @@@ -283,7 -274,7 +274,7 @@@ void FixPlayermodel( if(teamplay) { string s; - s = Team_ColorName_Lower(self.team); + s = Static_Team_ColorName_Lower(self.team); if(s != "neutral") { defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s)); @@@ -391,8 -382,6 +382,6 @@@ void PutClientInServer (void if(self.team < 0) JoinBestTeam(self, FALSE, TRUE); - race_PreSpawn(); - spot = SelectSpawnPoint (FALSE); if(!spot) { @@@ -402,6 -391,9 +391,6 @@@ RemoveGrapplingHook(self); // Wazat's Grappling Hook - if(self.vehicle) - vehicles_exit(VHEF_RELESE); - self.classname = "player"; self.wasplayer = TRUE; self.iscreature = TRUE; @@@ -516,11 -508,15 +505,15 @@@ self.punchvector = '0 0 0'; self.oldvelocity = self.velocity; self.fire_endtime = -1; + self.revival_time = 0; entity spawnevent = spawn(); spawnevent.owner = self; Net_LinkEntity(spawnevent, FALSE, 0.5, SpawnEvent_Send); + // Cut off any still running player sounds. + stopsound(self, CH_PLAYER_SINGLE); + self.model = ""; FixPlayermodel(); self.drawonlytoclient = world; @@@ -559,8 -555,6 +552,6 @@@ self.speedrunning = FALSE; - race_PostSpawn(spot); - //stuffcmd(self, "chase_active 0"); //stuffcmd(self, "set viewsize $tmpviewsize \n"); @@@ -589,6 -583,8 +580,8 @@@ activator = world; self = oldself; + Unfreeze(self); + spawn_spot = spot; MUTATOR_CALLHOOK(PlayerSpawn); @@@ -767,7 -763,7 +760,7 @@@ void ClientKill_Now( { if(self.vehicle) { - vehicles_exit(VHEF_RELESE); + vehicles_exit(VHEF_RELEASE); if(!self.killindicator_teamchange) { self.vehicle_health = -1; @@@ -938,7 -934,7 +931,7 @@@ void ClientKill (void { if(gameover) return; if(self.player_blocked) return; - if(self.freezetag_frozen) return; + if(self.frozen) return; ClientKill_TeamChange(0); } @@@ -1054,8 -1050,6 +1047,6 @@@ void ClientConnect (void anticheat_init(); - race_PreSpawnObserver(); - // identify the right forced team if(autocvar_g_campaign) { @@@ -1206,27 -1200,7 +1197,7 @@@ else self.hitplotfh = -1; - if(g_race || g_cts) { - string rr; - if(g_cts) - rr = CTS_RECORD; - else - rr = RACE_RECORD; - - msg_entity = self; - race_send_recordtime(MSG_ONE); - race_send_speedaward(MSG_ONE); - - speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"))); - speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"))); - race_send_speedaward_alltimebest(MSG_ONE); - - float i; - for (i = 1; i <= RANKINGS_CNT; ++i) { - race_SendRankings(i, 0, 0, MSG_ONE); - } - } - else if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca) // teamnagger is currently bad for ca + if(autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1)) && !g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts send_CSQC_teamnagger(); CheatInitClient(); @@@ -1252,7 -1226,7 +1223,7 @@@ void ReadyCount() void ClientDisconnect (void) { if(self.vehicle) - vehicles_exit(VHEF_RELESE); + vehicles_exit(VHEF_RELEASE); if (!IS_CLIENT(self)) { @@@ -1289,6 -1263,8 +1260,8 @@@ Portal_ClearAll(self); + Unfreeze(self); + RemoveGrapplingHook(self); // Here, everything has been done that requires this player to be a client. @@@ -1422,7 -1398,7 +1395,7 @@@ void player_powerups (void // add a way to see what the items were BEFORE all of these checks for the mutator hook olditems = self.items; - if((self.items & IT_USING_JETPACK) && !self.deadflag) + if((self.items & IT_USING_JETPACK) && !self.deadflag && !gameover) self.modelflags |= MF_ROCKET; else self.modelflags &= ~MF_ROCKET; @@@ -1582,17 -1558,27 +1555,27 @@@ float CalcRotRegen(float current, floa void player_regen (void) { + float max_mod, regen_mod, rot_mod, limit_mod; + max_mod = regen_mod = rot_mod = limit_mod = 1; + regen_mod_max = max_mod; + regen_mod_regen = regen_mod; + regen_mod_rot = rot_mod; + regen_mod_limit = limit_mod; if(!MUTATOR_CALLHOOK(PlayerRegen)) + if(!self.frozen) { - float minh, mina, maxh, maxa, limith, limita, max_mod, regen_mod, rot_mod, limit_mod; + float minh, mina, maxh, maxa, limith, limita; maxh = autocvar_g_balance_health_rotstable; maxa = autocvar_g_balance_armor_rotstable; minh = autocvar_g_balance_health_regenstable; mina = autocvar_g_balance_armor_regenstable; limith = autocvar_g_balance_health_limit; limita = autocvar_g_balance_armor_limit; - - max_mod = regen_mod = rot_mod = limit_mod = 1; + + max_mod = regen_mod_max; + regen_mod = regen_mod_regen; + rot_mod = regen_mod_rot; + limit_mod = regen_mod_limit; maxh = maxh * max_mod; minh = minh * max_mod; @@@ -1606,11 -1592,7 +1589,11 @@@ // if player rotted to death... die! // check this outside above checks, as player may still be able to rot to death if(self.health < 1) + { + if(self.vehicle) + vehicles_exit(VHEF_RELEASE); self.event_damage(self, self, 1, DEATH_ROT, self.origin, '0 0 0'); + } if (!(self.items & IT_UNLIMITED_WEAPON_AMMO)) { @@@ -1732,6 -1714,8 +1715,8 @@@ void SpectateCopy(entity spectatee) self.dmg_inflictor = spectatee.dmg_inflictor; self.v_angle = spectatee.v_angle; self.angles = spectatee.v_angle; + self.frozen = spectatee.frozen; + self.revive_progress = spectatee.revive_progress; if(!self.BUTTON_USE) self.fixangle = TRUE; setorigin(self, spectatee.origin); @@@ -1937,6 -1921,7 +1922,7 @@@ void LeaveSpectatorMode( if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) { self.classname = "player"; + nades_RemoveBonus(self); if(autocvar_g_campaign || autocvar_g_balance_teams) { JoinBestTeam(self, FALSE, TRUE); } @@@ -2140,7 -2125,6 +2126,7 @@@ void SpectatorThink( self.flags |= FL_CLIENT | FL_NOTARGET; } +void vehicles_enter (entity pl, entity veh); void PlayerUseKey() { if (!IS_PLAYER(self)) @@@ -2148,41 -2132,8 +2134,41 @@@ if(self.vehicle) { - vehicles_exit(VHEF_NORMAL); - return; + if(!gameover) + { + vehicles_exit(VHEF_NORMAL); + return; + } + } + else if(autocvar_g_vehicles_enter) + { - if(!self.freezetag_frozen) ++ if(!self.frozen) + if(self.deadflag == DEAD_NO) + if(!gameover) + { + entity head, closest_target = world; + head = WarpZone_FindRadius(self.origin, autocvar_g_vehicles_enter_radius, TRUE); + + while(head) // find the closest acceptable target to enter + { + if(head.vehicle_flags & VHF_ISVEHICLE) + if(head.deadflag == DEAD_NO) + if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, self))) + if(head.takedamage != DAMAGE_NO) + { + if(closest_target) + { + if(vlen(self.origin - head.origin) < vlen(self.origin - closest_target.origin)) + { closest_target = head; } + } + else { closest_target = head; } + } + + head = head.chain; + } + + if(closest_target) { vehicles_enter(self, closest_target); return; } + } } // a use key was pressed; call handlers @@@ -2199,7 -2150,6 +2185,7 @@@ Called every frame for each client befo .float usekeypressed; void() nexball_setstatus; .float items_added; +.float last_vehiclecheck; void PlayerPreThink (void) { WarpZone_PlayerPhysics_FixVAngle(); @@@ -2277,32 -2227,32 +2263,56 @@@ return; #endif + if(self.frozen == 2) + { + self.revive_progress = bound(0, self.revive_progress + frametime * self.revive_speed, 1); + self.health = max(1, self.revive_progress * start_health); + self.iceblock.alpha = bound(0.2, 1 - self.revive_progress, 1); + + if(self.revive_progress >= 1) + Unfreeze(self); + } + else if(self.frozen == 3) + { + self.revive_progress = bound(0, self.revive_progress - frametime * self.revive_speed, 1); + self.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * self.revive_progress ); + + if(self.health < 1) + { + if(self.vehicle) - vehicles_exit(VHEF_RELESE); ++ vehicles_exit(VHEF_RELEASE); + self.event_damage(self, self.frozen_by, 1, DEATH_NADE_ICE_FREEZE, self.origin, '0 0 0'); + } + else if ( self.revive_progress <= 0 ) + Unfreeze(self); + } + MUTATOR_CALLHOOK(PlayerPreThink); + if(autocvar_g_vehicles_enter) + if(time > self.last_vehiclecheck) + if(IS_PLAYER(self)) + if(!gameover) - if(!self.freezetag_frozen) ++ if(!self.frozen) + if(!self.vehicle) + if(self.deadflag == DEAD_NO) + { + entity veh; + for(veh = world; (veh = findflags(veh, vehicle_flags, VHF_ISVEHICLE)); ) + if(vlen(veh.origin - self.origin) < autocvar_g_vehicles_enter_radius) + if(veh.deadflag == DEAD_NO) + if(veh.takedamage != DAMAGE_NO) + if((veh.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(veh.owner, self)) + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER); + else if(!veh.owner) + if(!veh.team || SAME_TEAM(self, veh)) + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_VEHICLE_ENTER); + else if(autocvar_g_vehicles_steal) + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL); + + self.last_vehiclecheck = time + 1; + } + if(!self.cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button { if(self.BUTTON_USE && !self.usekeypressed) @@@ -2425,7 -2375,7 +2435,7 @@@ do_crouch = 0; if(self.vehicle) do_crouch = 0; - if(self.freezetag_frozen) + if(self.frozen) do_crouch = 0; if(self.weapon == WEP_SHOTGUN && self.weaponentity.wframe == WFRAME_FIRE2 && time < self.weapon_nextthink) do_crouch = 0; @@@ -2515,8 -2465,6 +2525,6 @@@ if(self.spectatee_status != oldspectatee_status) { ClientData_Touch(self); - if(g_race || g_cts) - race_InitSpectator(); } if(self.teamkill_soundtime) @@@ -2675,22 -2623,5 +2683,5 @@@ void PlayerPostThink (void playerdemo_write(); - if((g_cts || g_race) && self.cvar_cl_allow_uidtracking == 1 && self.cvar_cl_allow_uid2name == 1) - { - if (!self.stored_netname) - self.stored_netname = strzone(uid2name(self.crypto_idfp)); - if(self.stored_netname != self.netname) - { - db_put(ServerProgsDB, strcat("/uid2name/", self.crypto_idfp), self.netname); - strunzone(self.stored_netname); - self.stored_netname = strzone(self.netname); - } - } - - /* - if(g_race) - dprintf("%f %.6f\n", time, race_GetFractionalLapCount(self)); - */ - CSQCMODEL_AUTOUPDATE(); } diff --combined qcsrc/server/cl_weapons.qc index f501f0f07,41cdd2b05..f37d3b7d8 --- a/qcsrc/server/cl_weapons.qc +++ b/qcsrc/server/cl_weapons.qc @@@ -301,8 -301,6 +301,6 @@@ float W_IsWeaponThrowable(float w return 0; if (g_weaponarena) return 0; - if (g_cts) - return 0; if (g_nexball && w == WEP_GRENADE_LAUNCHER) return 0; if(w == 0) @@@ -330,6 -328,8 +328,8 @@@ void W_ThrowWeapon(vector velo, vector w = self.weapon; if (w == 0) return; // just in case + if(self.frozen) + return; if(MUTATOR_CALLHOOK(ForbidThrowCurrentWeapon)) return; if(!autocvar_g_weapon_throwable) @@@ -350,15 -350,15 +350,15 @@@ Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w); } -float forbidWeaponUse() +float forbidWeaponUse(entity player) { if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return 1; if(round_handler_IsActive() && !round_handler_IsRoundStarted()) return 1; - if(self.player_blocked) + if(player.player_blocked) return 1; - if(player.freezetag_frozen) + if(self.frozen) return 1; return 0; } @@@ -373,7 -373,7 +373,7 @@@ void W_WeaponFrame( if (!self.weaponentity || self.health < 1) return; // Dead player can't use weapons and injure impulse commands - if(forbidWeaponUse()) + if(forbidWeaponUse(self)) if(self.weaponentity.state != WS_CLEAR) { w_ready(); diff --combined qcsrc/server/g_damage.qc index d144498d6,47443e6d7..fb393ba11 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@@ -549,6 -549,86 +549,86 @@@ void Obituary(entity attacker, entity i if(targ.killcount) { targ.killcount = 0; } } + void Ice_Think() + { + if(!self.owner.frozen || self.owner.iceblock != self) + { + remove(self); + return; + } + setorigin(self, self.owner.origin - '0 0 16'); + self.nextthink = time; + } + + void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint) + { + if(!IS_PLAYER(targ) && !(targ.flags & FL_MONSTER)) // only specified entities can be freezed + return; + + if(targ.frozen) + return; + + float targ_maxhealth = ((targ.flags & FL_MONSTER) ? targ.max_health : start_health); + + targ.frozen = frozen_type; + targ.revive_progress = ((frozen_type == 3) ? 1 : 0); + targ.health = ((frozen_type == 3) ? targ_maxhealth : 1); + targ.revive_speed = freeze_time; + + entity ice, head; + ice = spawn(); + ice.owner = targ; + ice.classname = "ice"; + ice.scale = targ.scale; + ice.think = Ice_Think; + ice.nextthink = time; + ice.frame = floor(random() * 21); // ice model has 20 different looking frames + setmodel(ice, "models/ice/ice.md3"); + ice.alpha = 1; + ice.colormod = Team_ColorRGB(targ.team); + ice.glowmod = ice.colormod; + targ.iceblock = ice; + targ.revival_time = 0; + + entity oldself; + oldself = self; + self = ice; + Ice_Think(); + self = oldself; + + RemoveGrapplingHook(targ); + + FOR_EACH_PLAYER(head) + if(head.hook.aiment == targ) + RemoveGrapplingHook(head); + + // add waypoint + if(show_waypoint) + WaypointSprite_Spawn("frozen", 0, 0, targ, '0 0 64', world, targ.team, targ, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1'); + } + + void Unfreeze (entity targ) + { + if(targ.frozen && targ.frozen != 3) // only reset health if target was frozen + targ.health = ((IS_PLAYER(targ)) ? start_health : targ.max_health); + + entity head; + targ.frozen = 0; + targ.revive_progress = 0; + targ.revival_time = time; + + WaypointSprite_Kill(targ.waypointsprite_attached); + + FOR_EACH_PLAYER(head) + if(head.hook.aiment == targ) + RemoveGrapplingHook(head); + + // remove the ice block + if(targ.iceblock) + remove(targ.iceblock); + targ.iceblock = world; + } + // these are updated by each Damage call for use in button triggering and such entity damage_targ; entity damage_inflictor; @@@ -595,7 -675,7 +675,7 @@@ void Damage (entity targ, entity inflic { // exit the vehicle before killing (fixes a crash) if(IS_PLAYER(targ) && targ.vehicle) - vehicles_exit(VHEF_RELESE); + vehicles_exit(VHEF_RELEASE); // These are ALWAYS lethal // No damage modification here @@@ -690,7 -770,63 +770,63 @@@ mirrordamage = frag_mirrordamage; force = frag_force; - if (!g_minstagib) + if(targ.frozen) + if(deathtype != DEATH_HURTTRIGGER && deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_AUTOTEAMCHANGE) + { + if(autocvar_g_freezetag_revive_falldamage > 0) + if(deathtype == DEATH_FALL) + if(damage >= autocvar_g_freezetag_revive_falldamage) + { + Unfreeze(targ); + targ.health = autocvar_g_freezetag_revive_falldamage_health; + pointparticles(particleeffectnum("iceorglass"), targ.origin, '0 0 0', 3); + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname); + Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF); + } + + damage = 0; + force *= autocvar_g_freezetag_frozen_force; + } + + if(targ.frozen && deathtype == DEATH_HURTTRIGGER && !autocvar_g_freezetag_frozen_damage_trigger) + { + pointparticles(particleeffectnum("teleport"), targ.origin, '0 0 0', 1); + + entity oldself = self; + self = targ; + entity spot = SelectSpawnPoint (FALSE); + + if(spot) + { + damage = 0; + self.deadflag = DEAD_NO; + + self.angles = spot.angles; + + self.effects = 0; + self.effects |= EF_TELEPORT_BIT; + + self.angles_z = 0; // never spawn tilted even if the spot says to + self.fixangle = TRUE; // turn this way immediately + self.velocity = '0 0 0'; + self.avelocity = '0 0 0'; + self.punchangle = '0 0 0'; + self.punchvector = '0 0 0'; + self.oldvelocity = self.velocity; + + self.spawnorigin = spot.origin; + setorigin (self, spot.origin + '0 0 1' * (1 - self.mins_z - 24)); + // don't reset back to last position, even if new position is stuck in solid + self.oldorigin = self.origin; + self.prevorigin = self.origin; + + pointparticles(particleeffectnum("teleport"), self.origin, '0 0 0', 1); + } + + self = oldself; + } + + if(!g_minstagib) { // apply strength multiplier if (attacker.items & IT_STRENGTH) @@@ -713,12 -849,7 +849,7 @@@ } if (targ == attacker) - { - if(g_cts && !autocvar_g_cts_selfdamage) - damage = 0; - else - damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself - } + damage = damage * autocvar_g_balance_selfdamagepercent; // Partial damage if the attacker hits himself // count the damage if(attacker) @@@ -1200,7 -1331,7 +1331,7 @@@ void Fire_ApplyDamage(entity e e.fire_endtime = 0; // ice stops fire - if(e.freezetag_frozen) + if(e.frozen) e.fire_endtime = 0; t = min(frametime, e.fire_endtime - time); @@@ -1217,6 -1348,7 +1348,7 @@@ e.fire_hitsound = TRUE; if (!IS_INDEPENDENT_PLAYER(e)) + if(!e.frozen) FOR_EACH_PLAYER(other) if(e != other) { if(IS_PLAYER(other)) diff --combined qcsrc/server/g_hook.qc index 14b7834f8,4e1b63400..b62c43add --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@@ -299,7 -299,7 +299,7 @@@ void FireGrapplingHook (void float s; vector vs; - if(forbidWeaponUse()) return; + if(forbidWeaponUse(self)) return; if(self.vehicle) return; makevectors(self.v_angle); @@@ -383,7 -383,7 +383,7 @@@ void GrapplingHookFrame( // offhand hook controls if(self.BUTTON_HOOK) { - if (!(self.hook || (self.hook_state & HOOK_WAITING_FOR_RELEASE))) + if (!(self.hook || (self.hook_state & HOOK_WAITING_FOR_RELEASE)) && (time > self.hook_refire)) { self.hook_state |= HOOK_FIRING; self.hook_state |= HOOK_WAITING_FOR_RELEASE; @@@ -426,6 -426,7 +426,7 @@@ RemoveGrapplingHook(self); FireGrapplingHook(); self.hook_state &= ~HOOK_FIRING; + self.hook_refire = max(self.hook_refire, time + autocvar_g_balance_grapplehook_refire * W_WeaponRateFactor()); } else if(self.hook_state & HOOK_REMOVING) { diff --combined qcsrc/server/g_world.qc index 892f999b7,a1460ded8..9b50378f8 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@@ -55,7 -55,6 +55,6 @@@ const float SPAWNFLAG_NO_WAYPOINTS_FOR_ string redirection_target; float world_initialized; - string GetMapname(); string GetGametype(); void GotoNextMap(float reinit); void ShuffleMaplist(); @@@ -216,7 -215,6 +215,6 @@@ void cvar_changes_init( // private BADCVAR("developer"); BADCVAR("log_dest_udp"); - BADCVAR("log_file"); BADCVAR("net_address"); BADCVAR("net_address_ipv6"); BADCVAR("port"); @@@ -237,6 -235,7 +235,7 @@@ BADPREFIX("g_playerstats_"); BADPREFIX("g_respawn_ghosts"); BADPREFIX("g_voice_flood_"); + BADPREFIX("log_file"); BADPREFIX("rcon_"); BADPREFIX("sv_allowdownloads"); BADPREFIX("sv_autodemo"); @@@ -542,11 -541,11 +541,12 @@@ void spawnfunc___init_dedicated_server( // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterVehicles); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); MapInfo_Enumerate(); MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0); @@@ -592,11 -591,11 +592,12 @@@ void spawnfunc_worldspawn (void // needs to be done so early because of the constants they create CALL_ACCUMULATED_FUNCTION(RegisterWeapons); + CALL_ACCUMULATED_FUNCTION(RegisterVehicles); CALL_ACCUMULATED_FUNCTION(RegisterMonsters); CALL_ACCUMULATED_FUNCTION(RegisterGametypes); CALL_ACCUMULATED_FUNCTION(RegisterNotifications); CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes); + CALL_ACCUMULATED_FUNCTION(RegisterBuffs); ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid)); @@@ -796,6 -795,10 +797,10 @@@ addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load); + // freeze attacks + addstat(STAT_FROZEN, AS_INT, frozen); + addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress); + // g_movementspeed hack addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw); addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed); @@@ -898,7 -901,6 +903,6 @@@ string GetGametype( return MapInfo_Type_ToString(MapInfo_LoadedGametype); } - string getmapname_stored; string GetMapname() { return mapname; @@@ -1223,13 -1225,27 +1227,27 @@@ float DoNextMapOverride(float reinit return TRUE; } if(autocvar_nextmap != "") - if(MapInfo_CheckMap(autocvar_nextmap)) + { + string m; + m = GameTypeVote_MapInfo_FixName(autocvar_nextmap); + cvar_set("nextmap",m); + + if(!m || gametypevote) + return FALSE; + if(autocvar_sv_vote_gametype) + { + Map_Goto_SetStr(m); + return FALSE; + } + + if(MapInfo_CheckMap(m)) { - Map_Goto_SetStr(autocvar_nextmap); + Map_Goto_SetStr(m); Map_Goto(reinit); alreadychangedlevel = TRUE; return TRUE; } + } if(!reinit && autocvar_lastlevel) { cvar_settemp_restore(); @@@ -1266,9 -1282,6 +1284,6 @@@ When the player presses attack or jump ============ */ .float autoscreenshot; - void() MapVote_Start; - void() MapVote_Think; - float mapvote_initialized; void IntermissionThink() { FixIntermissionClient(self); @@@ -1578,7 -1591,7 +1593,7 @@@ float InitiateSuddenDeath( // - for this timelimit_overtime needs to be >0 of course // - also check the winning condition calculated in the previous frame and only add normal overtime // again, if at the point at which timelimit would be extended again, still no winner was found - if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) + if (!autocvar_g_campaign && (checkrules_overtimesadded >= 0) && (checkrules_overtimesadded < autocvar_timelimit_overtimes || autocvar_timelimit_overtimes < 0) && autocvar_timelimit_overtime && !(g_race && !g_race_qualifying)) { return 1; // need to call InitiateOvertime later } @@@ -2033,17 -2046,6 +2048,6 @@@ void CheckRules_World( SetDefaultAlpha(); - /* - MapVote_Think should now do that part - if (intermission_running) - if (time >= intermission_exittime + 60) - { - if(!DoNextMapOverride()) - GotoNextMap(); - return; - } - */ - if (gameover) // someone else quit the game already { if(player_count == 0) // Nobody there? Then let's go to the next map @@@ -2205,517 -2207,14 +2209,14 @@@ } } - float mapvote_nextthink; - float mapvote_initialized; - float mapvote_keeptwotime; - float mapvote_timeout; - string mapvote_message; - #define MAPVOTE_SCREENSHOT_DIRS_COUNT 4 - string mapvote_screenshot_dirs[MAPVOTE_SCREENSHOT_DIRS_COUNT]; - float mapvote_screenshot_dirs_count; - - float mapvote_count; - float mapvote_count_real; - string mapvote_maps[MAPVOTE_COUNT]; - float mapvote_maps_screenshot_dir[MAPVOTE_COUNT]; - string mapvote_maps_pakfile[MAPVOTE_COUNT]; - float mapvote_maps_suggested[MAPVOTE_COUNT]; - string mapvote_suggestions[MAPVOTE_COUNT]; - float mapvote_suggestion_ptr; - float mapvote_voters; - float mapvote_selections[MAPVOTE_COUNT]; - float mapvote_run; - float mapvote_detail; - float mapvote_abstain; - .float mapvote; - - void MapVote_ClearAllVotes() - { - FOR_EACH_CLIENT(other) - other.mapvote = 0; - } - - string MapVote_Suggest(string m) + string GotoMap(string m) { - float i; - if(m == "") - return "That's not how to use this command."; - if(!autocvar_g_maplist_votable_suggestions) - return "Suggestions are not accepted on this server."; - if(mapvote_initialized) - return "Can't suggest - voting is already in progress!"; - m = MapInfo_FixName(m); + m = GameTypeVote_MapInfo_FixName(m); if (!m) return "The map you suggested is not available on this server."; - if(!autocvar_g_maplist_votable_suggestions_override_mostrecent) - if(Map_IsRecent(m)) - return "This server does not allow for recent maps to be played again. Please be patient for some rounds."; - + if (!autocvar_sv_vote_gametype) if(!MapInfo_CheckMap(m)) return "The map you suggested does not support the current game mode."; - for(i = 0; i < mapvote_suggestion_ptr; ++i) - if(mapvote_suggestions[i] == m) - return "This map was already suggested."; - if(mapvote_suggestion_ptr >= MAPVOTE_COUNT) - { - i = floor(random() * mapvote_suggestion_ptr); - } - else - { - i = mapvote_suggestion_ptr; - mapvote_suggestion_ptr += 1; - } - if(mapvote_suggestions[i] != "") - strunzone(mapvote_suggestions[i]); - mapvote_suggestions[i] = strzone(m); - if(autocvar_sv_eventlog) - GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid))); - return strcat("Suggestion of ", m, " accepted."); - } - - void MapVote_AddVotable(string nextMap, float isSuggestion) - { - float j, i, o; - string pakfile, mapfile; - - if(nextMap == "") - return; - for(j = 0; j < mapvote_count; ++j) - if(mapvote_maps[j] == nextMap) - return; - // suggestions might be no longer valid/allowed after gametype switch! - if(isSuggestion) - if(!MapInfo_CheckMap(nextMap)) - return; - mapvote_maps[mapvote_count] = strzone(nextMap); - mapvote_maps_suggested[mapvote_count] = isSuggestion; - - pakfile = string_null; - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - { - mapfile = strcat(mapvote_screenshot_dirs[i], "/", mapvote_maps[i]); - pakfile = whichpack(strcat(mapfile, ".tga")); - if(pakfile == "") - pakfile = whichpack(strcat(mapfile, ".jpg")); - if(pakfile == "") - pakfile = whichpack(strcat(mapfile, ".png")); - if(pakfile != "") - break; - } - if(i >= mapvote_screenshot_dirs_count) - i = 0; // FIXME maybe network this error case, as that means there is no mapshot on the server? - for(o = strstr(pakfile, "/", 0)+1; o > 0; o = strstr(pakfile, "/", 0)+1) - pakfile = substring(pakfile, o, -1); - - mapvote_maps_screenshot_dir[mapvote_count] = i; - mapvote_maps_pakfile[mapvote_count] = strzone(pakfile); - - mapvote_count += 1; - } - - void MapVote_Spawn(); - void MapVote_Init() - { - float i; - float nmax, smax; - - MapVote_ClearAllVotes(); - - mapvote_count = 0; - mapvote_detail = !autocvar_g_maplist_votable_nodetail; - mapvote_abstain = autocvar_g_maplist_votable_abstain; - - if(mapvote_abstain) - nmax = min(MAPVOTE_COUNT - 1, autocvar_g_maplist_votable); - else - nmax = min(MAPVOTE_COUNT, autocvar_g_maplist_votable); - smax = min3(nmax, autocvar_g_maplist_votable_suggestions, mapvote_suggestion_ptr); - - // we need this for AddVotable, as that cycles through the screenshot dirs - mapvote_screenshot_dirs_count = tokenize_console(autocvar_g_maplist_votable_screenshot_dir); - if(mapvote_screenshot_dirs_count == 0) - mapvote_screenshot_dirs_count = tokenize_console("maps levelshots"); - mapvote_screenshot_dirs_count = min(mapvote_screenshot_dirs_count, MAPVOTE_SCREENSHOT_DIRS_COUNT); - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - mapvote_screenshot_dirs[i] = strzone(argv(i)); - - if(mapvote_suggestion_ptr) - for(i = 0; i < 100 && mapvote_count < smax; ++i) - MapVote_AddVotable(mapvote_suggestions[floor(random() * mapvote_suggestion_ptr)], TRUE); - - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), FALSE); - - if(mapvote_count == 0) - { - bprint( "Maplist contains no single playable map! Resetting it to default map list.\n" ); - cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags())); - if(autocvar_g_maplist_shuffle) - ShuffleMaplist(); - localcmd("\nmenu_cmd sync\n"); - for(i = 0; i < 100 && mapvote_count < nmax; ++i) - MapVote_AddVotable(GetNextMap(), FALSE); - } - - mapvote_count_real = mapvote_count; - if(mapvote_abstain) - MapVote_AddVotable("don't care", 0); - - //dprint("mapvote count is ", ftos(mapvote_count), "\n"); - - mapvote_keeptwotime = time + autocvar_g_maplist_votable_keeptwotime; - mapvote_timeout = time + autocvar_g_maplist_votable_timeout; - if(mapvote_count_real < 3 || mapvote_keeptwotime <= time) - mapvote_keeptwotime = 0; - mapvote_message = "Choose a map and press its key!"; - - MapVote_Spawn(); - } - - void MapVote_SendPicture(float id) - { - msg_entity = self; - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_PICTURE); - WriteByte(MSG_ONE, id); - WritePicture(MSG_ONE, strcat(mapvote_screenshot_dirs[mapvote_maps_screenshot_dir[id]], "/", mapvote_maps[id]), 3072); - } - - float MapVote_GetMapMask() - { - float mask, i, power; - mask = 0; - for(i = 0, power = 1; i < mapvote_count; ++i, power *= 2) - if(mapvote_maps[i] != "") - mask |= power; - return mask; - } - - entity mapvote_ent; - float MapVote_SendEntity(entity to, float sf) - { - float i; - - if(sf & 1) - sf &= ~2; // if we send 1, we don't need to also send 2 - - WriteByte(MSG_ENTITY, ENT_CLIENT_MAPVOTE); - WriteByte(MSG_ENTITY, sf); - - if(sf & 1) - { - // flag 1 == initialization - for(i = 0; i < mapvote_screenshot_dirs_count; ++i) - WriteString(MSG_ENTITY, mapvote_screenshot_dirs[i]); - WriteString(MSG_ENTITY, ""); - WriteByte(MSG_ENTITY, mapvote_count); - WriteByte(MSG_ENTITY, mapvote_abstain); - WriteByte(MSG_ENTITY, mapvote_detail); - WriteCoord(MSG_ENTITY, mapvote_timeout); - if(mapvote_count <= 8) - WriteByte(MSG_ENTITY, MapVote_GetMapMask()); - else - WriteShort(MSG_ENTITY, MapVote_GetMapMask()); - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - if(mapvote_abstain && i == mapvote_count - 1) - { - WriteString(MSG_ENTITY, ""); // abstain needs no text - WriteString(MSG_ENTITY, ""); // abstain needs no pack - WriteByte(MSG_ENTITY, 0); // abstain needs no screenshot dir - } - else - { - WriteString(MSG_ENTITY, mapvote_maps[i]); - WriteString(MSG_ENTITY, mapvote_maps_pakfile[i]); - WriteByte(MSG_ENTITY, mapvote_maps_screenshot_dir[i]); - } - } - } - - if(sf & 2) - { - // flag 2 == update of mask - if(mapvote_count <= 8) - WriteByte(MSG_ENTITY, MapVote_GetMapMask()); - else - WriteShort(MSG_ENTITY, MapVote_GetMapMask()); - } - - if(sf & 4) - { - if(mapvote_detail) - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - WriteByte(MSG_ENTITY, mapvote_selections[i]); - - WriteByte(MSG_ENTITY, to.mapvote); - } - - return TRUE; - } - - void MapVote_Spawn() - { - Net_LinkEntity(mapvote_ent = spawn(), FALSE, 0, MapVote_SendEntity); - } - - void MapVote_TouchMask() - { - mapvote_ent.SendFlags |= 2; - } - - void MapVote_TouchVotes(entity voter) - { - mapvote_ent.SendFlags |= 4; - } - - float MapVote_Finished(float mappos) - { - string result; - float i; - float didntvote; - - if(autocvar_sv_eventlog) - { - result = strcat(":vote:finished:", mapvote_maps[mappos]); - result = strcat(result, ":", ftos(mapvote_selections[mappos]), "::"); - didntvote = mapvote_voters; - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - didntvote -= mapvote_selections[i]; - if(i != mappos) - { - result = strcat(result, ":", mapvote_maps[i]); - result = strcat(result, ":", ftos(mapvote_selections[i])); - } - } - result = strcat(result, ":didn't vote:", ftos(didntvote)); - - GameLogEcho(result); - if(mapvote_maps_suggested[mappos]) - GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos])); - } - - FOR_EACH_REALCLIENT(other) - FixClientCvars(other); - - Map_Goto_SetStr(mapvote_maps[mappos]); - Map_Goto(0); - alreadychangedlevel = TRUE; - return TRUE; - } - void MapVote_CheckRules_1() - { - float i; - - for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "") - { - //dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n"); - mapvote_selections[i] = 0; - } - - mapvote_voters = 0; - FOR_EACH_REALCLIENT(other) - { - ++mapvote_voters; - if(other.mapvote) - { - i = other.mapvote - 1; - //dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n"); - mapvote_selections[i] = mapvote_selections[i] + 1; - } - } - } - - float MapVote_CheckRules_2() - { - float i; - float firstPlace, secondPlace; - float firstPlaceVotes, secondPlaceVotes; - float mapvote_voters_real; - string result; - - if(mapvote_count_real == 1) - return MapVote_Finished(0); - - mapvote_voters_real = mapvote_voters; - if(mapvote_abstain) - mapvote_voters_real -= mapvote_selections[mapvote_count - 1]; - - RandomSelection_Init(); - for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "") - RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); - firstPlace = RandomSelection_chosen_float; - firstPlaceVotes = RandomSelection_best_priority; - //dprint("First place: ", ftos(firstPlace), "\n"); - //dprint("First place votes: ", ftos(firstPlaceVotes), "\n"); - - RandomSelection_Init(); - for(i = 0; i < mapvote_count_real; ++i) if(mapvote_maps[i] != "") - if(i != firstPlace) - RandomSelection_Add(world, i, string_null, 1, mapvote_selections[i]); - secondPlace = RandomSelection_chosen_float; - secondPlaceVotes = RandomSelection_best_priority; - //dprint("Second place: ", ftos(secondPlace), "\n"); - //dprint("Second place votes: ", ftos(secondPlaceVotes), "\n"); - - if(firstPlace == -1) - error("No first place in map vote... WTF?"); - - if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters_real - firstPlaceVotes) < firstPlaceVotes) - return MapVote_Finished(firstPlace); - - if(mapvote_keeptwotime) - if(time > mapvote_keeptwotime || (mapvote_voters_real - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes) - { - float didntvote; - MapVote_TouchMask(); - mapvote_message = "Now decide between the TOP TWO!"; - mapvote_keeptwotime = 0; - result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]); - result = strcat(result, ":", ftos(firstPlaceVotes)); - result = strcat(result, ":", mapvote_maps[secondPlace]); - result = strcat(result, ":", ftos(secondPlaceVotes), "::"); - didntvote = mapvote_voters; - for(i = 0; i < mapvote_count; ++i) - if(mapvote_maps[i] != "") - { - didntvote -= mapvote_selections[i]; - if(i != firstPlace) - if(i != secondPlace) - { - result = strcat(result, ":", mapvote_maps[i]); - result = strcat(result, ":", ftos(mapvote_selections[i])); - if(i < mapvote_count_real) - { - strunzone(mapvote_maps[i]); - mapvote_maps[i] = ""; - strunzone(mapvote_maps_pakfile[i]); - mapvote_maps_pakfile[i] = ""; - } - } - } - result = strcat(result, ":didn't vote:", ftos(didntvote)); - if(autocvar_sv_eventlog) - GameLogEcho(result); - } - - return FALSE; - } - void MapVote_Tick() - { - float keeptwo; - float totalvotes; - - keeptwo = mapvote_keeptwotime; - MapVote_CheckRules_1(); // count - if(MapVote_CheckRules_2()) // decide - return; - - totalvotes = 0; - FOR_EACH_REALCLIENT(other) - { - // hide scoreboard again - if(other.health != 2342) - { - other.health = 2342; - other.impulse = 0; - if(IS_REAL_CLIENT(other)) - { - msg_entity = other; - WriteByte(MSG_ONE, SVC_FINALE); - WriteString(MSG_ONE, ""); - } - } - - // clear possibly invalid votes - if(mapvote_maps[other.mapvote - 1] == "") - other.mapvote = 0; - // use impulses as new vote - if(other.impulse >= 1 && other.impulse <= mapvote_count) - if(mapvote_maps[other.impulse - 1] != "") - { - other.mapvote = other.impulse; - MapVote_TouchVotes(other); - } - other.impulse = 0; - - if(other.mapvote) - ++totalvotes; - } - - MapVote_CheckRules_1(); // just count - } - void MapVote_Start() - { - if(mapvote_run) - return; - - // wait for stats to be sent first - if(!playerstats_waitforme) - return; - - MapInfo_Enumerate(); - if(MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) - mapvote_run = TRUE; - } - void MapVote_Think() - { - if(!mapvote_run) - return; - - if(alreadychangedlevel) - return; - - if(time < mapvote_nextthink) - return; - //dprint("tick\n"); - - mapvote_nextthink = time + 0.5; - - if(!mapvote_initialized) - { - if(autocvar_rescan_pending == 1) - { - cvar_set("rescan_pending", "2"); - localcmd("fs_rescan\nrescan_pending 3\n"); - return; - } - else if(autocvar_rescan_pending == 2) - { - return; - } - else if(autocvar_rescan_pending == 3) - { - // now build missing mapinfo files - if(!MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1)) - return; - - // we're done, start the timer - cvar_set("rescan_pending", "0"); - } - - mapvote_initialized = TRUE; - if(DoNextMapOverride(0)) - return; - if(!autocvar_g_maplist_votable || player_count <= 0) - { - GotoNextMap(0); - return; - } - MapVote_Init(); - } - - MapVote_Tick(); - } - - string GotoMap(string m) - { - if(!MapInfo_CheckMap(m)) - return "The map you chose is not available on this server."; cvar_set("nextmap", m); cvar_set("timelimit", "-1"); if(mapvote_initialized || alreadychangedlevel) @@@ -2732,6 -2231,8 +2233,8 @@@ void EndFrame() { + anticheat_endframe(); + float altime; FOR_EACH_REALCLIENT(self) { diff --combined qcsrc/server/mutators/gamemode_assault.qc index 7b6135de6,1eb2b77cb..63f065298 --- a/qcsrc/server/mutators/gamemode_assault.qc +++ b/qcsrc/server/mutators/gamemode_assault.qc @@@ -212,31 -212,8 +212,31 @@@ void assault_wall_think( // trigger new round // reset objectives, toggle spawnpoints, reset triggers, ... +void vehicles_clearreturn(entity veh); +void vehicles_spawn(); void assault_new_round() { + entity oldself; + //bprint("ASSAULT: new round\n"); + + oldself = self; + // Eject players from vehicles + FOR_EACH_PLAYER(self) + { + if(self.vehicle) + vehicles_exit(VHEF_RELEASE); + } + + self = findchainflags(vehicle_flags, VHF_ISVEHICLE); + while(self) + { + vehicles_clearreturn(self); + vehicles_spawn(); + self = self.chain; + } + + self = oldself; + // up round counter self.winning = self.winning + 1; @@@ -588,7 -565,7 +588,7 @@@ MUTATOR_DEFINITION(gamemode_assault MUTATOR_HOOK(PlayerSpawn, assault_PlayerSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(TurretSpawn, assault_TurretSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(VehicleSpawn, assault_VehicleSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(HavocBot_ChooseRule, assault_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(HavocBot_ChooseRole, assault_BotRoles, CBC_ORDER_ANY); MUTATOR_ONADD { diff --combined qcsrc/server/mutators/gamemode_ctf.qc index cf4fc29de,967d8d656..e1cf56b86 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@@ -257,17 -257,8 +257,17 @@@ void ctf_Handle_Retrieve(entity flag, e flag.owner.flagcarried = flag; // reset flag - setattachment(flag, player, ""); - setorigin(flag, FLAG_CARRY_OFFSET); + if(player.vehicle) + { + setattachment(flag, player.vehicle, ""); + setorigin(flag, VEHICLE_FLAG_OFFSET); + flag.scale = VEHICLE_FLAG_SCALE; + } + else + { + setattachment(flag, player, ""); + setorigin(flag, FLAG_CARRY_OFFSET); + } flag.movetype = MOVETYPE_NONE; flag.takedamage = DAMAGE_NO; flag.solid = SOLID_NOT; @@@ -397,6 -388,8 +397,8 @@@ void ctf_Handle_Capture(entity flag, en if (!player) { return; } // without someone to give the reward to, we can't possibly cap + nades_GiveBonus(player, autocvar_g_nades_bonus_score_high ); + // messages and sounds Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_ENT_2(enemy_flag, CENTER_CTF_CAPTURE_)); ctf_CaptureRecord(enemy_flag, player); @@@ -457,6 -450,8 +459,8 @@@ void ctf_Handle_Return(entity flag, ent { PlayerTeamScore_AddScore(player, autocvar_g_ctf_score_return); // reward for return PlayerScore_Add(player, SP_CTF_RETURNS, 1); // add to count of returns + + nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium); } TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it @@@ -480,17 -475,8 +484,17 @@@ void ctf_Handle_Pickup(entity flag, ent // attach the flag to the player flag.owner = player; player.flagcarried = flag; - setattachment(flag, player, ""); - setorigin(flag, FLAG_CARRY_OFFSET); + if(player.vehicle) + { + setattachment(flag, player.vehicle, ""); + setorigin(flag, VEHICLE_FLAG_OFFSET); + flag.scale = VEHICLE_FLAG_SCALE; + } + else + { + setattachment(flag, player, ""); + setorigin(flag, FLAG_CARRY_OFFSET); + } // flag setup flag.movetype = MOVETYPE_NONE; @@@ -518,6 -504,7 +522,7 @@@ // scoring PlayerScore_Add(player, SP_CTF_PICKUPS, 1); + nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor); switch(pickuptype) { case PICKUP_BASE: @@@ -674,7 -661,7 +679,7 @@@ void ctf_FlagThink( if(self.mins != FLAG_MIN || self.maxs != FLAG_MAX) { // reset the flag boundaries in case it got squished dprint("wtf the flag got squashed?\n"); tracebox(self.origin, FLAG_MIN, FLAG_MAX, self.origin, MOVE_NOMONSTERS, self); - if(!trace_startsolid) // can we resize it without getting stuck? + if(!trace_startsolid || self.noalign) // can we resize it without getting stuck? setsize(self, FLAG_MIN, FLAG_MAX); } switch(self.ctf_status) // reset flag angles in case warpzones adjust it @@@ -809,7 -796,8 +814,8 @@@ void ctf_FlagTouch( } // special touch behaviors - if(toucher.vehicle_flags & VHF_ISVEHICLE) + if(toucher.frozen) { return; } + else if(toucher.vehicle_flags & VHF_ISVEHICLE) { if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner) toucher = toucher.owner; // the player is actually the vehicle owner, not other @@@ -896,9 -884,6 +902,9 @@@ void ctf_RespawnFlag(entity flag ctf_FakeTimeLimit(flag.owner, -1); } + if((flag.owner) && (flag.owner.vehicle)) + flag.scale = FLAG_SCALE; + if((flag.ctf_status == FLAG_DROPPED) && (flag.wps_flagdropped)) { WaypointSprite_Kill(flag.wps_flagdropped); } @@@ -2203,7 -2188,7 +2209,7 @@@ MUTATOR_DEFINITION(gamemode_ctf MUTATOR_HOOK(VehicleEnter, ctf_VehicleEnter, CBC_ORDER_ANY); MUTATOR_HOOK(VehicleExit, ctf_VehicleExit, CBC_ORDER_ANY); MUTATOR_HOOK(AbortSpeedrun, ctf_AbortSpeedrun, CBC_ORDER_ANY); - MUTATOR_HOOK(HavocBot_ChooseRule, ctf_BotRoles, CBC_ORDER_ANY); + MUTATOR_HOOK(HavocBot_ChooseRole, ctf_BotRoles, CBC_ORDER_ANY); MUTATOR_ONADD { diff --combined qcsrc/server/mutators/mutator_nades.qc index 024a5f130,da75e25ac..ddfbf6a0e --- a/qcsrc/server/mutators/mutator_nades.qc +++ b/qcsrc/server/mutators/mutator_nades.qc @@@ -1,31 -1,20 +1,20 @@@ + .entity nade_spawnloc; + void nade_timer_think() { self.skin = 8 - (self.owner.wait - time) / (autocvar_g_nades_nade_lifetime / 10); self.nextthink = time; if(!self.owner || wasfreed(self.owner)) remove(self); - } void nade_burn_spawn(entity _nade) { - float p; - - switch(_nade.realowner.team) - { - case NUM_TEAM_1: p = PROJECTILE_NADE_RED_BURN; break; - case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE_BURN; break; - case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW_BURN; break; - case NUM_TEAM_4: p = PROJECTILE_NADE_PINK_BURN; break; - default: p = PROJECTILE_NADE_BURN; break; - } - - CSQCProjectile(_nade, TRUE, p, TRUE); + CSQCProjectile(_nade, TRUE, Nade_ProjectileFromID(_nade.nade_type, TRUE), TRUE); } void nade_spawn(entity _nade) { - float p; entity timer = spawn(); setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3"); setattachment(timer, _nade, ""); @@@ -38,47 -27,529 +27,529 @@@ timer.owner = _nade; timer.skin = 10; - switch(_nade.realowner.team) + _nade.effects |= EF_LOWPRECISION; + + CSQCProjectile(_nade, TRUE, Nade_ProjectileFromID(_nade.nade_type, FALSE), TRUE); + } + + void napalm_damage(float dist, float damage, float edgedamage, float burntime) + { + entity e; + float d; + vector p; + + if ( damage < 0 ) + return; + + RandomSelection_Init(); + for(e = WarpZone_FindRadius(self.origin, dist, TRUE); e; e = e.chain) + if(e.takedamage == DAMAGE_AIM) + if(self.realowner != e || autocvar_g_nades_napalm_selfdamage) + if(!IS_PLAYER(e) || !self.realowner || DIFF_TEAM(e, self)) + if(!e.frozen) + { + p = e.origin; + p_x += e.mins_x + random() * (e.maxs_x - e.mins_x); + p_y += e.mins_y + random() * (e.maxs_y - e.mins_y); + p_z += e.mins_z + random() * (e.maxs_z - e.mins_z); + d = vlen(WarpZone_UnTransformOrigin(e, self.origin) - p); + if(d < dist) + { + e.fireball_impactvec = p; + RandomSelection_Add(e, 0, string_null, 1 / (1 + d), !Fire_IsBurning(e)); + } + } + if(RandomSelection_chosen_ent) { - case NUM_TEAM_1: p = PROJECTILE_NADE_RED; break; - case NUM_TEAM_2: p = PROJECTILE_NADE_BLUE; break; - case NUM_TEAM_3: p = PROJECTILE_NADE_YELLOW; break; - case NUM_TEAM_4: p = PROJECTILE_NADE_PINK; break; - default: p = PROJECTILE_NADE; break; + d = vlen(WarpZone_UnTransformOrigin(RandomSelection_chosen_ent, self.origin) - RandomSelection_chosen_ent.fireball_impactvec); + d = damage + (edgedamage - damage) * (d / dist); + Fire_AddDamage(RandomSelection_chosen_ent, self.realowner, d * burntime, burntime, self.projectiledeathtype | HITTYPE_BOUNCE); + //trailparticles(self, particleeffectnum("fireball_laser"), self.origin, RandomSelection_chosen_ent.fireball_impactvec); + pointparticles(particleeffectnum("fireball_laser"), self.origin, RandomSelection_chosen_ent.fireball_impactvec - self.origin, 1); } + } - CSQCProjectile(_nade, TRUE, p, TRUE); + void napalm_ball_think() + { + if(round_handler_IsActive()) + if(!round_handler_IsRoundStarted()) + { + remove(self); + return; + } + + if(time > self.pushltime) + { + remove(self); + return; + } + + vector midpoint = ((self.absmin + self.absmax) * 0.5); + if(pointcontents(midpoint) == CONTENT_WATER) + { + self.velocity = self.velocity * 0.5; + + if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER) + { self.velocity_z = 200; } + } + + self.angles = vectoangles(self.velocity); + + napalm_damage(autocvar_g_nades_napalm_ball_radius,autocvar_g_nades_napalm_ball_damage, + autocvar_g_nades_napalm_ball_damage,autocvar_g_nades_napalm_burntime); + + self.nextthink = time + 0.1; + } + + + void nade_napalm_ball() + { + entity proj; + vector kick; + + spamsound(self, CH_SHOTS, "weapons/fireball_fire.wav", VOL_BASE, ATTEN_NORM); + + proj = spawn (); + proj.owner = self.owner; + proj.realowner = self.realowner; + proj.team = self.owner.team; + proj.classname = "grenade"; + proj.bot_dodge = TRUE; + proj.bot_dodgerating = autocvar_g_nades_napalm_ball_damage; + proj.movetype = MOVETYPE_BOUNCE; + proj.projectiledeathtype = DEATH_NADE_NAPALM; + PROJECTILE_MAKETRIGGER(proj); + setmodel(proj, "null"); + proj.scale = 1;//0.5; + setsize(proj, '-4 -4 -4', '4 4 4'); + setorigin(proj, self.origin); + proj.think = napalm_ball_think; + proj.nextthink = time; + proj.damageforcescale = autocvar_g_nades_napalm_ball_damageforcescale; + proj.effects = EF_LOWPRECISION | EF_FLAME; + + kick_x =(random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread; + kick_y = (random() - 0.5) * 2 * autocvar_g_nades_napalm_ball_spread; + kick_z = (random()/2+0.5) * autocvar_g_nades_napalm_ball_spread; + proj.velocity = kick; + + proj.pushltime = time + autocvar_g_nades_napalm_ball_lifetime; + + proj.angles = vectoangles(proj.velocity); + proj.flags = FL_PROJECTILE; + proj.missile_flags = MIF_SPLASH | MIF_PROXY | MIF_ARC; + + //CSQCProjectile(proj, TRUE, PROJECTILE_NAPALM_FIRE, TRUE); + } + + + void napalm_fountain_think() + { + + if(round_handler_IsActive()) + if(!round_handler_IsRoundStarted()) + { + remove(self); + return; + } + + if(time >= self.ltime) + { + remove(self); + return; + } + + vector midpoint = ((self.absmin + self.absmax) * 0.5); + if(pointcontents(midpoint) == CONTENT_WATER) + { + self.velocity = self.velocity * 0.5; + + if(pointcontents(midpoint + '0 0 16') == CONTENT_WATER) + { self.velocity_z = 200; } + + UpdateCSQCProjectile(self); + } + + napalm_damage(autocvar_g_nades_napalm_fountain_radius, autocvar_g_nades_napalm_fountain_damage, + autocvar_g_nades_napalm_fountain_edgedamage, autocvar_g_nades_napalm_burntime); + + self.nextthink = time + 0.1; + if(time >= self.nade_special_time) + { + self.nade_special_time = time + autocvar_g_nades_napalm_fountain_delay; + nade_napalm_ball(); + } + } + + void nade_napalm_boom() + { + entity fountain; + local float c; + for (c = 0; c < autocvar_g_nades_napalm_ball_count; c ++) + nade_napalm_ball(); + + + fountain = spawn(); + fountain.owner = self.owner; + fountain.realowner = self.realowner; + fountain.origin = self.origin; + setorigin(fountain, fountain.origin); + fountain.think = napalm_fountain_think; + fountain.nextthink = time; + fountain.ltime = time + autocvar_g_nades_napalm_fountain_lifetime; + fountain.pushltime = fountain.ltime; + fountain.team = self.team; + fountain.movetype = MOVETYPE_TOSS; + fountain.projectiledeathtype = DEATH_NADE_NAPALM; + fountain.bot_dodge = TRUE; + fountain.bot_dodgerating = autocvar_g_nades_napalm_fountain_damage; + fountain.nade_special_time = time; + setsize(fountain, '-16 -16 -16', '16 16 16'); + CSQCProjectile(fountain, TRUE, PROJECTILE_NAPALM_FOUNTAIN, TRUE); + } + + void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time) + { + frost_target.frozen_by = freezefield.realowner; + pointparticles(particleeffectnum("electro_impact"), frost_target.origin, '0 0 0', 1); + Freeze(frost_target, 1/freeze_time, 3, FALSE); + if(frost_target.ballcarried) + if(g_keepaway) { ka_DropEvent(frost_target); } + else { DropBall(frost_target.ballcarried, frost_target.origin, frost_target.velocity);} + if(frost_target.flagcarried) { ctf_Handle_Throw(frost_target, world, DROP_THROW); } + if(frost_target.nade) { toss_nade(frost_target, '0 0 0', time + 0.05); } + + kh_Key_DropAll(frost_target, FALSE); + } + + void nade_ice_think() + { + + if(round_handler_IsActive()) + if(!round_handler_IsRoundStarted()) + { + remove(self); + return; + } + + if(time >= self.ltime) + { + if ( autocvar_g_nades_ice_explode ) + { + string expef; + switch(self.realowner.team) + { + case NUM_TEAM_1: expef = "nade_red_explode"; break; + case NUM_TEAM_2: expef = "nade_blue_explode"; break; + case NUM_TEAM_3: expef = "nade_yellow_explode"; break; + case NUM_TEAM_4: expef = "nade_pink_explode"; break; + default: expef = "nade_neutral_explode"; break; + } + pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1); + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); + + RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, + autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy); + Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, + autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self); + } + remove(self); + return; + } + + + self.nextthink = time+0.1; + + // gaussian + float randomr; + randomr = random(); + randomr = exp(-5*randomr*randomr)*autocvar_g_nades_nade_radius; + float randomw; + randomw = random()*M_PI*2; + vector randomp; + randomp_x = randomr*cos(randomw); + randomp_y = randomr*sin(randomw); + randomp_z = 1; + pointparticles(particleeffectnum("electro_muzzleflash"), self.origin + randomp, '0 0 0', 1); + + if(time >= self.nade_special_time) + { + self.nade_special_time = time+0.7; + + + pointparticles(particleeffectnum("electro_impact"), self.origin, '0 0 0', 1); + pointparticles(particleeffectnum("icefield"), self.origin, '0 0 0', 1); + } + + + float current_freeze_time = self.ltime - time - 0.1; + + entity e; + for(e = findradius(self.origin, autocvar_g_nades_nade_radius); e; e = e.chain) + if(e != self) + if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(e, self.realowner) || e == self.realowner)) + if(e.takedamage && e.deadflag == DEAD_NO) + if(e.health > 0) + if(!e.revival_time || ((time - e.revival_time) >= 1.5)) + if(!e.frozen) + if(current_freeze_time > 0) + nade_ice_freeze(self, e, current_freeze_time); + } + + void nade_ice_boom() + { + entity fountain; + fountain = spawn(); + fountain.owner = self.owner; + fountain.realowner = self.realowner; + fountain.origin = self.origin; + setorigin(fountain, fountain.origin); + fountain.think = nade_ice_think; + fountain.nextthink = time; + fountain.ltime = time + autocvar_g_nades_ice_freeze_time; + fountain.pushltime = fountain.wait = fountain.ltime; + fountain.team = self.team; + fountain.movetype = MOVETYPE_TOSS; + fountain.projectiledeathtype = DEATH_NADE_ICE; + fountain.bot_dodge = FALSE; + setsize(fountain, '-16 -16 -16', '16 16 16'); + fountain.nade_special_time = time+0.3; + fountain.angles = self.angles; + + if ( autocvar_g_nades_ice_explode ) + { + setmodel(fountain, "models/grenademodel.md3"); + entity timer = spawn(); + setmodel(timer, "models/ok_nade_counter/ok_nade_counter.md3"); + setattachment(timer, fountain, ""); + timer.classname = "nade_timer"; + timer.colormap = self.colormap; + timer.glowmod = self.glowmod; + timer.think = nade_timer_think; + timer.nextthink = time; + timer.wait = fountain.ltime; + timer.owner = fountain; + timer.skin = 10; + } + else + setmodel(fountain, "null"); + } + + void nade_translocate_boom() + { + if(self.realowner.vehicle) + return; + + vector locout = self.origin + '0 0 1' * (1 - self.realowner.mins_z - 24); + tracebox(locout, self.realowner.mins, self.realowner.maxs, locout, MOVE_NOMONSTERS, self.realowner); + locout = trace_endpos; + + makevectors(self.realowner.angles); + + entity oldself = self; + self = self.realowner; + MUTATOR_CALLHOOK(PortalTeleport); + self.realowner = self; + self = oldself; + + TeleportPlayer(self, self.realowner, locout, self.realowner.mangle, v_forward * vlen(self.realowner.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER); + } + + void nade_spawn_boom() + { + entity spawnloc = spawn(); + setorigin(spawnloc, self.origin); + setsize(spawnloc, self.realowner.mins, self.realowner.maxs); + spawnloc.movetype = MOVETYPE_NONE; + spawnloc.solid = SOLID_NOT; + spawnloc.drawonlytoclient = self.realowner; + spawnloc.effects = EF_STARDUST; + spawnloc.cnt = autocvar_g_nades_spawn_count; + + if(self.realowner.nade_spawnloc) + { + remove(self.realowner.nade_spawnloc); + self.realowner.nade_spawnloc = world; + } + + self.realowner.nade_spawnloc = spawnloc; + } + + void nade_heal_think() + { + if(time >= self.ltime) + { + remove(self); + return; + } + + self.nextthink = time; + + if(time >= self.nade_special_time) + { + self.nade_special_time = time+0.25; + self.nade_show_particles = 1; + } + else + self.nade_show_particles = 0; + } + + void nade_heal_touch() + { + float maxhealth; + float health_factor; + if(IS_PLAYER(other) || (other.flags & FL_MONSTER)) + if(other.deadflag == DEAD_NO) + if(!other.frozen) + { + health_factor = autocvar_g_nades_heal_rate*frametime/2; + if ( other != self.realowner ) + { + if ( SAME_TEAM(other,self) ) + health_factor *= autocvar_g_nades_heal_friend; + else + health_factor *= autocvar_g_nades_heal_foe; + } + if ( health_factor > 0 ) + { + maxhealth = (other.flags & FL_MONSTER) ? other.max_health : g_pickup_healthmega_max; + if ( other.health < maxhealth ) + { + if ( self.nade_show_particles ) + pointparticles(particleeffectnum("healing_fx"), other.origin, '0 0 0', 1); + other.health = min(other.health+health_factor, maxhealth); + } + other.pauserothealth_finished = max(other.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot); + } + else if ( health_factor < 0 ) + { + Damage(other,self,self.realowner,-health_factor,DEATH_NADE_HEAL,other.origin,'0 0 0'); + } + + } + + if ( IS_REAL_CLIENT(other) || (other.vehicle_flags & VHF_ISVEHICLE) ) + { + entity show_red = (other.vehicle_flags & VHF_ISVEHICLE) ? other.owner : other; + show_red.stat_healing_orb = time+0.1; + show_red.stat_healing_orb_alpha = 0.75 * (self.ltime - time) / self.healer_lifetime; + } + } + + void nade_heal_boom() + { + entity healer; + healer = spawn(); + healer.owner = self.owner; + healer.realowner = self.realowner; + setorigin(healer, self.origin); + healer.healer_lifetime = autocvar_g_nades_heal_time; // save the cvar + healer.ltime = time + healer.healer_lifetime; + healer.team = self.realowner.team; + healer.bot_dodge = FALSE; + healer.solid = SOLID_TRIGGER; + healer.touch = nade_heal_touch; + + setmodel(healer, "models/ctf/shield.md3"); + healer.healer_radius = autocvar_g_nades_nade_radius; + vector size = '1 1 1' * healer.healer_radius / 2; + setsize(healer,-size,size); + + Net_LinkEntity(healer, TRUE, 0, healer_send); + + healer.think = nade_heal_think; + healer.nextthink = time; + healer.SendFlags |= 1; + } + + void nade_monster_boom() + { + entity e = spawnmonster(self.pokenade_type, 0, self.realowner, self.realowner, self.origin, FALSE, FALSE, 1); + + if(autocvar_g_nades_pokenade_monster_lifetime > 0) + e.monster_lifetime = time + autocvar_g_nades_pokenade_monster_lifetime; + e.monster_skill = MONSTER_SKILL_INSANE; } void nade_boom() { string expef; + float nade_blast = 1; - switch(self.realowner.team) + switch ( self.nade_type ) { - case NUM_TEAM_1: expef = "nade_red_explode"; break; - case NUM_TEAM_2: expef = "nade_blue_explode"; break; - case NUM_TEAM_3: expef = "nade_yellow_explode"; break; - case NUM_TEAM_4: expef = "nade_pink_explode"; break; - default: expef = "nade_explode"; break; + case NADE_TYPE_NAPALM: + nade_blast = autocvar_g_nades_napalm_blast; + expef = "explosion_medium"; + break; + case NADE_TYPE_ICE: + nade_blast = 0; + expef = "electro_combo"; // hookbomb_explode electro_combo bigplasma_impact + break; + case NADE_TYPE_TRANSLOCATE: + nade_blast = 0; + expef = ""; + break; + case NADE_TYPE_MONSTER: + case NADE_TYPE_SPAWN: + nade_blast = 0; + switch(self.realowner.team) + { + case NUM_TEAM_1: expef = "spawn_event_red"; break; + case NUM_TEAM_2: expef = "spawn_event_blue"; break; + case NUM_TEAM_3: expef = "spawn_event_yellow"; break; + case NUM_TEAM_4: expef = "spawn_event_pink"; break; + default: expef = "spawn_event_neutral"; break; + } + break; + case NADE_TYPE_HEAL: + nade_blast = 0; + expef = "spawn_event_red"; + break; + + default: + case NADE_TYPE_NORMAL: + switch(self.realowner.team) + { + case NUM_TEAM_1: expef = "nade_red_explode"; break; + case NUM_TEAM_2: expef = "nade_blue_explode"; break; + case NUM_TEAM_3: expef = "nade_yellow_explode"; break; + case NUM_TEAM_4: expef = "nade_pink_explode"; break; + default: expef = "nade_neutral_explode"; break; + } } - sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM); - sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); pointparticles(particleeffectnum(expef), self.origin + '0 0 1', '0 0 0', 1); - Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self); + sound(self, CH_SHOTS_SINGLE, "misc/null.wav", VOL_BASE, ATTEN_NORM); + sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTEN_NORM); self.takedamage = DAMAGE_NO; - RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, + + if(nade_blast) + { + RadiusDamage(self, self.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, self, autocvar_g_nades_nade_force, self.projectiledeathtype, self.enemy); + Damage_DamageInfo(self.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, self.projectiledeathtype, 0, self); + } + + switch ( self.nade_type ) + { + case NADE_TYPE_NAPALM: nade_napalm_boom(); break; + case NADE_TYPE_ICE: nade_ice_boom(); break; + case NADE_TYPE_TRANSLOCATE: nade_translocate_boom(); break; + case NADE_TYPE_SPAWN: nade_spawn_boom(); break; + case NADE_TYPE_HEAL: nade_heal_boom(); break; + case NADE_TYPE_MONSTER: nade_monster_boom(); break; + } remove(self); } void nade_touch() { + if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; } PROJECTILE_TOUCH; //setsize(self, '-2 -2 -2', '2 2 2'); //UpdateCSQCProjectile(self); @@@ -101,6 -572,9 +572,9 @@@ void nade_beep( void nade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { + if(self.nade_type == NADE_TYPE_TRANSLOCATE || self.nade_type == NADE_TYPE_SPAWN) + return; + if(DEATH_ISWEAPON(deathtype, WEP_LASER)) return; @@@ -113,14 -587,14 +587,14 @@@ if(DEATH_ISWEAPON(deathtype, WEP_UZI)) damage = self.max_health * 0.1; - if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && !(deathtype & HITTYPE_SECONDARY)) - damage = self.max_health * 1.1; - - if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN) && (deathtype & HITTYPE_SECONDARY)) + if(DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) + if(deathtype & HITTYPE_SECONDARY) { damage = self.max_health * 0.1; - force *= 15; + force *= 10; } + else + damage = self.max_health * 1.1; self.velocity += force; @@@ -134,8 -608,10 +608,10 @@@ self.think = nade_beep; } - self.health -= damage; - self.realowner = attacker; + self.health -= damage; + + if ( self.nade_type != NADE_TYPE_HEAL || IS_PLAYER(attacker) ) + self.realowner = attacker; if(self.health <= 0) W_PrepareExplosionByDamage(attacker, nade_boom); @@@ -145,6 -621,9 +621,9 @@@ void toss_nade(entity e, vector _velocity, float _time) { + if(e.nade == world) + return; + entity _nade = e.nade; e.nade = world; @@@ -157,10 -636,9 +636,9 @@@ Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_NADES); - //setorigin(_nade, CENTER_OR_VIEWOFS(e) + (v_right * 10) * -1); setorigin(_nade, w_shotorg + (v_right * 25) * -1); - setmodel(_nade, "models/weapons/v_ok_grenade.md3"); - setattachment(_nade, world, ""); + //setmodel(_nade, "models/weapons/v_ok_grenade.md3"); + //setattachment(_nade, world, ""); PROJECTILE_MAKETRIGGER(_nade); setsize(_nade, '-16 -16 -16', '16 16 16'); _nade.movetype = MOVETYPE_BOUNCE; @@@ -177,12 -655,16 +655,16 @@@ _nade.velocity = _velocity; else _nade.velocity = W_CalculateProjectileVelocity(e.velocity, _velocity, TRUE); - + _nade.touch = nade_touch; _nade.health = autocvar_g_nades_nade_health; _nade.max_health = _nade.health; _nade.takedamage = DAMAGE_AIM; _nade.event_damage = nade_damage; + _nade.customizeentityforclient = func_null; + _nade.exteriormodeltoclient = world; + _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP; + _nade.traileffectnum = 0; _nade.teleportable = TRUE; _nade.pushable = TRUE; _nade.gravity = 1; @@@ -190,6 -672,9 +672,9 @@@ _nade.damagedbycontents = TRUE; _nade.angles = vectoangles(_nade.velocity); _nade.flags = FL_PROJECTILE; + _nade.projectiledeathtype = DEATH_NADE; + _nade.toss_time = time; + _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX); nade_spawn(_nade); @@@ -200,6 -685,56 +685,56 @@@ } e.nade_refire = time + autocvar_g_nades_nade_refire; + e.nade_timer = 0; + } + + void nades_GiveBonus(entity player, float score) + { + if (autocvar_g_nades) + if (autocvar_g_nades_bonus) + if (IS_REAL_CLIENT(player)) + if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max) + if (player.frozen == 0) + if (player.deadflag == DEAD_NO) + { + if ( player.bonus_nade_score < 1 ) + player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max; + + if ( player.bonus_nade_score >= 1 ) + { + Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS); + play2(player,"kh/alarm.wav"); + player.bonus_nades++; + player.bonus_nade_score -= 1; + } + } + } + + void nades_RemoveBonus(entity player) + { + player.bonus_nades = player.bonus_nade_score = 0; + } + + float nade_customize() + { + //if(IS_SPEC(other)) { return FALSE; } + if(other == self.realowner || (IS_SPEC(other) && other.enemy == self.realowner)) + { + // somewhat hide the model, but keep the glow + //self.effects = 0; + if(self.traileffectnum) + self.traileffectnum = 0; + self.alpha = -1; + } + else + { + //self.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION; + if(!self.traileffectnum) + self.traileffectnum = particleeffectnum(Nade_TrailEffect(Nade_ProjectileFromID(self.nade_type, FALSE), self.team)); + self.alpha = 1; + } + + return TRUE; } void nade_prime() @@@ -210,29 -745,53 +745,53 @@@ if(self.fake_nade) remove(self.fake_nade); - self.nade = spawn(); - setmodel(self.nade, "null"); - setattachment(self.nade, self, "bip01 l hand"); - self.nade.classname = "nade"; - self.nade.realowner = self; - self.nade.colormap = self.colormap; - self.nade.glowmod = self.glowmod; - self.nade.wait = time + autocvar_g_nades_nade_lifetime; - self.nade.lifetime = time; - self.nade.think = nade_beep; - self.nade.nextthink = max(self.nade.wait - 3, time); - self.nade.projectiledeathtype = DEATH_NADE; - - self.fake_nade = spawn(); - setmodel(self.fake_nade, "models/weapons/h_ok_grenade.iqm"); - setattachment(self.fake_nade, self.weaponentity, ""); - self.fake_nade.classname = "fake_nade"; - //self.fake_nade.viewmodelforclient = self; - self.fake_nade.realowner = self.fake_nade.owner = self; - self.fake_nade.colormap = self.colormap; - self.fake_nade.glowmod = self.glowmod; - self.fake_nade.think = SUB_Remove; - self.fake_nade.nextthink = self.nade.wait; + entity n = spawn(), fn = spawn(); + + n.classname = "nade"; + fn.classname = "fake_nade"; + + if(self.items & IT_STRENGTH && autocvar_g_nades_bonus_onstrength) + n.nade_type = self.nade_type; + else if (self.bonus_nades >= 1) + { + n.nade_type = self.nade_type; + n.pokenade_type = self.pokenade_type; + self.bonus_nades -= 1; + } + else + { + n.nade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_nade_type : autocvar_g_nades_nade_type); + n.pokenade_type = ((autocvar_g_nades_client_select) ? self.cvar_cl_pokenade_type : autocvar_g_nades_pokenade_monster_type); + } + + n.nade_type = bound(1, n.nade_type, NADE_TYPE_LAST); + + setmodel(n, "models/weapons/v_ok_grenade.md3"); + //setattachment(n, self, "bip01 l hand"); + n.exteriormodeltoclient = self; + n.customizeentityforclient = nade_customize; + n.traileffectnum = particleeffectnum(Nade_TrailEffect(Nade_ProjectileFromID(n.nade_type, FALSE), self.team)); + n.colormod = Nade_Color(n.nade_type); + n.realowner = self; + n.colormap = self.colormap; + n.glowmod = self.glowmod; + n.wait = time + autocvar_g_nades_nade_lifetime; + n.lifetime = time; + n.think = nade_beep; + n.nextthink = max(n.wait - 3, time); + n.projectiledeathtype = DEATH_NADE; + + setmodel(fn, "models/weapons/h_ok_grenade.iqm"); + setattachment(fn, self.weaponentity, ""); + fn.realowner = fn.owner = self; + fn.colormod = Nade_Color(n.nade_type); + fn.colormap = self.colormap; + fn.glowmod = self.glowmod; + fn.think = SUB_Remove; + fn.nextthink = n.wait; + + self.nade = n; + self.fake_nade = fn; } float CanThrowNade() @@@ -249,7 -808,7 +808,7 @@@ if (!autocvar_g_nades) return FALSE; // allow turning them off mid match - if(forbidWeaponUse()) + if(forbidWeaponUse(self)) return FALSE; if (!IS_PLAYER(self)) @@@ -285,21 -844,55 +844,55 @@@ void nades_CheckThrow( } } + void nades_Clear(entity player) + { + if(player.nade) + remove(player.nade); + if(player.fake_nade) + remove(player.fake_nade); + + player.nade = player.fake_nade = world; + player.nade_timer = 0; + } + + MUTATOR_HOOKFUNCTION(nades_CheckThrow) + { + if(MUTATOR_RETURNVALUE) { nades_CheckThrow(); } + return FALSE; + } + MUTATOR_HOOKFUNCTION(nades_VehicleEnter) { - if(other.nade) - toss_nade(other, '0 0 100', max(other.nade.wait, time + 0.05)); + if(vh_player.nade) + toss_nade(vh_player, '0 0 100', max(vh_player.nade.wait, time + 0.05)); return FALSE; } MUTATOR_HOOKFUNCTION(nades_PlayerPreThink) { - float key_pressed = ((g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || (weaponsInMap & WEPSET_HOOK)) ? self.button16 : self.BUTTON_HOOK); + if(!IS_PLAYER(self)) { return FALSE; } + + float key_pressed = self.BUTTON_HOOK; + float time_score; + if(g_grappling_hook || client_hasweapon(self, WEP_HOOK, FALSE, FALSE) || (weaponsInMap & WEPSET_HOOK) || g_jetpack || self.items & IT_JETPACK) + key_pressed = self.button16; // if hook/jetpack is enabled, use an alternate key + if(self.nade) - if(self.nade.wait - 0.1 <= time) - toss_nade(self, '0 0 0', time + 0.05); + { + self.nade_timer = bound(0, (time - self.nade.lifetime) / autocvar_g_nades_nade_lifetime, 1); + //print(sprintf("%d %d\n", self.nade_timer, time - self.nade.lifetime)); + makevectors(self.angles); + self.nade.velocity = self.velocity; + + setorigin(self.nade, self.origin + self.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0); + self.nade.angles_y = self.angles_y; + } + + if(self.nade) + if(self.nade.wait - 0.1 <= time) + toss_nade(self, '0 0 0', time + 0.05); if(CanThrowNade()) if(self.nade_refire < time) @@@ -322,6 -915,88 +915,88 @@@ } } + if(IS_PLAYER(self)) + { + if ( autocvar_g_nades_bonus && autocvar_g_nades ) + { + entity key; + float key_count = 0; + FOR_EACH_KH_KEY(key) if(key.owner == self) { ++key_count; } + + if(self.flagcarried || self.ballcarried) // this player is important + time_score = autocvar_g_nades_bonus_score_time_flagcarrier; + else + time_score = autocvar_g_nades_bonus_score_time; + + if(key_count) + time_score = autocvar_g_nades_bonus_score_time_flagcarrier * key_count; // multiply by the number of keys the player is holding + + if(autocvar_g_nades_bonus_client_select) + { + self.nade_type = self.cvar_cl_nade_type; + self.pokenade_type = self.cvar_cl_pokenade_type; + } + else + { + self.nade_type = autocvar_g_nades_bonus_type; + self.pokenade_type = autocvar_g_nades_pokenade_monster_type; + } + + self.nade_type = bound(1, self.nade_type, NADE_TYPE_LAST); + + if(self.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max) + nades_GiveBonus(self, time_score / autocvar_g_nades_bonus_score_max); + } + else + { + self.bonus_nades = self.bonus_nade_score = 0; + } + } + + float n = 0; + entity o = world; + if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout) + n = -1; + else + { + vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size; + n = 0; + FOR_EACH_PLAYER(other) if(self != other) + { + if(other.deadflag == DEAD_NO) + if(other.frozen == 0) + if(SAME_TEAM(other, self)) + if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax)) + { + if(!o) + o = other; + if(self.frozen == 1) + other.reviving = TRUE; + ++n; + } + } + } + + if(n && self.frozen == 3) // OK, there is at least one teammate reviving us + { + self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1); + self.health = max(1, self.revive_progress * start_health); + + if(self.revive_progress >= 1) + { + Unfreeze(self); + + Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname); + Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname); + } + + FOR_EACH_PLAYER(other) if(other.reviving) + { + other.revive_progress = self.revive_progress; + other.reviving = FALSE; + } + } + return FALSE; } @@@ -332,24 -1007,113 +1007,113 @@@ MUTATOR_HOOKFUNCTION(nades_PlayerSpawn else self.nade_refire = time + autocvar_g_nades_nade_refire; + if(autocvar_g_nades_bonus_client_select) + self.nade_type = self.cvar_cl_nade_type; + + self.nade_timer = 0; + + if(self.nade_spawnloc) + { + setorigin(self, self.nade_spawnloc.origin); + self.nade_spawnloc.cnt -= 1; + + if(self.nade_spawnloc.cnt <= 0) + { + remove(self.nade_spawnloc); + self.nade_spawnloc = world; + } + } + return FALSE; } MUTATOR_HOOKFUNCTION(nades_PlayerDies) { - if(self.nade) - toss_nade(self, '0 0 100', max(self.nade.wait, time + 0.05)); + if(frag_target.nade) + if(!frag_target.frozen || !autocvar_g_freezetag_revive_nade) + toss_nade(frag_target, '0 0 100', max(frag_target.nade.wait, time + 0.05)); + + float killcount_bonus = ((frag_attacker.killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * frag_attacker.killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor); + + if(IS_PLAYER(frag_attacker)) + { + if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target) + nades_RemoveBonus(frag_attacker); + else if(frag_target.flagcarried) + nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_medium); + else if(autocvar_g_nades_bonus_score_spree && frag_attacker.killcount > 1) + { + #define SPREE_ITEM(counta,countb,center,normal,gentle) \ + case counta: { nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_spree); break; } + switch(frag_attacker.killcount) + { + KILL_SPREE_LIST + default: nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); break; + } + #undef SPREE_ITEM + } + else + nades_GiveBonus(frag_attacker, killcount_bonus); + } + + nades_RemoveBonus(frag_target); + + return FALSE; + } + + MUTATOR_HOOKFUNCTION(nades_PlayerDamage) + { + if(frag_target.frozen) + if(autocvar_g_freezetag_revive_nade) + if(frag_attacker == frag_target) + if(frag_deathtype == DEATH_NADE) + if(time - frag_inflictor.toss_time <= 0.1) + { + Unfreeze(frag_target); + frag_target.health = autocvar_g_freezetag_revive_nade_health; + pointparticles(particleeffectnum("iceorglass"), frag_target.origin, '0 0 0', 3); + frag_damage = 0; + frag_force = '0 0 0'; + Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED_NADE, frag_target.netname); + Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF); + } + + return FALSE; + } + + MUTATOR_HOOKFUNCTION(nades_MonsterDies) + { + if(IS_PLAYER(frag_attacker)) + if(DIFF_TEAM(frag_attacker, self)) + if(!(self.spawnflags & MONSTERFLAG_SPAWNED)) + nades_GiveBonus(frag_attacker, autocvar_g_nades_bonus_score_minor); return FALSE; } MUTATOR_HOOKFUNCTION(nades_RemovePlayer) { - if(self.nade) - remove(self.nade); + nades_Clear(self); + nades_RemoveBonus(self); + return FALSE; + } - if(self.fake_nade) - remove(self.fake_nade); + MUTATOR_HOOKFUNCTION(nades_SpectateCopy) + { + self.nade_timer = other.nade_timer; + self.nade_type = other.nade_type; + self.pokenade_type = other.pokenade_type; + self.bonus_nades = other.bonus_nades; + self.bonus_nade_score = other.bonus_nade_score; + self.stat_healing_orb = other.stat_healing_orb; + self.stat_healing_orb_alpha = other.stat_healing_orb_alpha; + return FALSE; + } + + MUTATOR_HOOKFUNCTION(nades_GetCvars) + { + GetCvars_handleFloat(get_cvars_s, get_cvars_f, cvar_cl_nade_type, "cl_nade_type"); + GetCvars_handleString(get_cvars_s, get_cvars_f, cvar_cl_pokenade_type, "cl_pokenade_type"); return FALSE; } @@@ -366,31 -1130,50 +1130,50 @@@ MUTATOR_HOOKFUNCTION(nades_BuildMutator return FALSE; } + void nades_Initialize() + { + addstat(STAT_NADE_TIMER, AS_FLOAT, nade_timer); + addstat(STAT_NADE_BONUS, AS_FLOAT, bonus_nades); + addstat(STAT_NADE_BONUS_TYPE, AS_INT, nade_type); + addstat(STAT_NADE_BONUS_SCORE, AS_FLOAT, bonus_nade_score); + addstat(STAT_HEALING_ORB, AS_FLOAT, stat_healing_orb); + addstat(STAT_HEALING_ORB_ALPHA, AS_FLOAT, stat_healing_orb_alpha); + + precache_model("models/ok_nade_counter/ok_nade_counter.md3"); + precache_model("models/weapons/h_ok_grenade.iqm"); + precache_model("models/weapons/v_ok_grenade.md3"); + precache_model("models/ctf/shield.md3"); + + precache_sound("weapons/rocket_impact.wav"); + precache_sound("weapons/grenade_bounce1.wav"); + precache_sound("weapons/grenade_bounce2.wav"); + precache_sound("weapons/grenade_bounce3.wav"); + precache_sound("weapons/grenade_bounce4.wav"); + precache_sound("weapons/grenade_bounce5.wav"); + precache_sound("weapons/grenade_bounce6.wav"); + precache_sound("overkill/grenadebip.ogg"); + } + MUTATOR_DEFINITION(mutator_nades) { + MUTATOR_HOOK(ForbidThrowCurrentWeapon, nades_CheckThrow, CBC_ORDER_LAST); MUTATOR_HOOK(VehicleEnter, nades_VehicleEnter, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, nades_PlayerPreThink, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerSpawn, nades_PlayerSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerDies, nades_PlayerDies, CBC_ORDER_LAST); + MUTATOR_HOOK(PlayerDamage_Calculate, nades_PlayerDamage, CBC_ORDER_ANY); + MUTATOR_HOOK(MonsterDies, nades_MonsterDies, CBC_ORDER_ANY); MUTATOR_HOOK(MakePlayerObserver, nades_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(ClientDisconnect, nades_RemovePlayer, CBC_ORDER_ANY); + MUTATOR_HOOK(SpectateCopy, nades_SpectateCopy, CBC_ORDER_ANY); + MUTATOR_HOOK(GetCvars, nades_GetCvars, CBC_ORDER_ANY); + MUTATOR_HOOK(reset_map_global, nades_RemovePlayer, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsString, nades_BuildMutatorsString, CBC_ORDER_ANY); MUTATOR_HOOK(BuildMutatorsPrettyString, nades_BuildMutatorsPrettyString, CBC_ORDER_ANY); MUTATOR_ONADD { - precache_model("models/ok_nade_counter/ok_nade_counter.md3"); - - precache_model("models/weapons/h_ok_grenade.iqm"); - precache_model("models/weapons/v_ok_grenade.md3"); - precache_sound("weapons/rocket_impact.wav"); - precache_sound("weapons/grenade_bounce1.wav"); - precache_sound("weapons/grenade_bounce2.wav"); - precache_sound("weapons/grenade_bounce3.wav"); - precache_sound("weapons/grenade_bounce4.wav"); - precache_sound("weapons/grenade_bounce5.wav"); - precache_sound("weapons/grenade_bounce6.wav"); - precache_sound("overkill/grenadebip.ogg"); + nades_Initialize(); } return FALSE; diff --combined qcsrc/server/progs.src index 3b5bce687,288b24775..820ddbd2f --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@@ -13,8 -13,11 +13,11 @@@ sys-post.q ../warpzonelib/server.qh ../common/constants.qh + ../common/stats.qh ../common/teams.qh ../common/util.qh + ../common/nades.qh + ../common/buffs.qh ../common/test.qh ../common/counting.qh ../common/items.qh @@@ -37,24 -40,11 +40,12 @@@ defs.qh // Should rename this, it has ../common/notifications.qh // must be after autocvars ../common/deathtypes.qh // must be after notifications +../common/vehicles/vehicles_include.qh + - mutators/base.qh - mutators/mutators.qh - mutators/gamemode_assault.qh - mutators/gamemode_ca.qh - mutators/gamemode_ctf.qh - mutators/gamemode_domination.qh - mutators/gamemode_keyhunt.qh // TODO fix this - mutators/gamemode_keepaway.qh - mutators/gamemode_nexball.qh - mutators/gamemode_lms.qh - mutators/gamemode_invasion.qh - mutators/mutator_dodging.qh - mutators/mutator_nades.qh + mutators/mutators_include.qh //// tZork Turrets //// tturrets/include/turrets_early.qh -vehicles/vehicles_def.qh campaign.qh ../common/campaign_common.qh @@@ -89,6 -79,8 +80,8 @@@ scores.q spawnpoints.qh + mapvoting.qh + ipban.qh race.qh @@@ -107,6 -99,8 +100,8 @@@ scores_rules.q miscfunctions.qc + mutators/mutators.qc + waypointsprites.qc bot/bot.qc @@@ -132,6 -126,8 +127,8 @@@ pathlib/pathlib.q g_world.qc g_casings.qc + mapvoting.qc + t_jumppads.qc t_teleporters.qc @@@ -201,6 -197,7 +198,6 @@@ race.q //// tZork Turrets //// tturrets/include/turrets.qh -vehicles/vehicles.qh scores.qc @@@ -214,8 -211,10 +211,10 @@@ target_music.q ../common/items.qc +../common/vehicles/vehicles_include.qc + ../common/nades.qc + ../common/buffs.qc - accuracy.qc ../csqcmodellib/sv_model.qc csqcprojectile.qc @@@ -235,38 -234,7 +234,7 @@@ round_handler.q ../common/monsters/spawn.qc - mutators/base.qc - mutators/gamemode_assault.qc - mutators/gamemode_ca.qc - mutators/gamemode_ctf.qc - mutators/gamemode_domination.qc - mutators/gamemode_freezetag.qc - mutators/gamemode_keyhunt.qc - mutators/gamemode_keepaway.qc - mutators/gamemode_nexball.qc - mutators/gamemode_onslaught.qc - mutators/gamemode_lms.qc - mutators/gamemode_invasion.qc - mutators/mutator_invincibleproj.qc - mutators/mutator_new_toys.qc - mutators/mutator_nix.qc - mutators/mutator_dodging.qc - mutators/mutator_rocketflying.qc - mutators/mutator_vampire.qc - mutators/mutator_spawn_near_teammate.qc - mutators/mutator_physical_items.qc - mutators/sandbox.qc - mutators/mutator_superspec.qc - mutators/mutator_minstagib.qc - mutators/mutator_touchexplode.qc - mutators/mutator_pinata.qc - mutators/mutator_midair.qc - mutators/mutator_bloodloss.qc - mutators/mutator_random_gravity.qc - mutators/mutator_multijump.qc - mutators/mutator_melee_only.qc - mutators/mutator_nades.qc - mutators/mutator_campcheck.qc + mutators/mutators_include.qc ../warpzonelib/anglestransform.qc ../warpzonelib/mathlib.qc