From: TimePath Date: Sun, 3 May 2015 05:00:21 +0000 (+1000) Subject: Cleanup vehicle #includes X-Git-Tag: xonotic-v0.8.1~61^2~15 X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=commitdiff_plain;h=fc82c845c5bcd6b0c837ed82db072b0b7eba0239 Cleanup vehicle #includes --- diff --git a/qcsrc/Makefile b/qcsrc/Makefile index abbd25ffd8..f53707e829 100644 --- a/qcsrc/Makefile +++ b/qcsrc/Makefile @@ -15,8 +15,13 @@ QCCFLAGS ?= \ -Werror -fno-bail-on-werror -Wall \ -fftepp -fftepp-predefs -Wcpp -futf8 \ $(QCCFLAGS_WTFS) \ + $(QCCFLAGS_FEATURES) \ $(QCCFLAGS_EXTRA) $(QCCFLAGS_WATERMARK) +QCCFLAGS_FEATURES ?= \ + -DVEHICLES_ENABLED=1 \ + -DVEHICLES_USE_ODE=0 + # xonotic build system overrides this by command line argument to turn off the update-cvarcount step XON_BUILDSYSTEM = diff --git a/qcsrc/common/command/generic.qc b/qcsrc/common/command/generic.qc index dac268d7ed..f0b6d0de5a 100644 --- a/qcsrc/common/command/generic.qc +++ b/qcsrc/common/command/generic.qc @@ -20,6 +20,8 @@ #include "../../server/command/cmd.qh" #include "../../server/command/common.qh" #include "../../server/command/sv_cmd.qh" + + #include "../../common/weapons/config.qh" #endif // ========================================================= diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index 225c00fde9..3ff926bf61 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -15,7 +15,7 @@ #include "../deathtypes.qh" #include "../../server/mutators/mutators_include.qh" #include "../../server/tturrets/include/turrets_early.qh" - #include "../../server/vehicles/vehicles_def.qh" + #include "../../server/vehicles/vehicle.qh" #include "../../server/campaign.qh" #include "../../server/command/common.qh" #include "../../server/command/cmd.qh" diff --git a/qcsrc/common/weapons/all.inc b/qcsrc/common/weapons/all.inc new file mode 100644 index 0000000000..4f4cd2b3d8 --- /dev/null +++ b/qcsrc/common/weapons/all.inc @@ -0,0 +1,29 @@ +// ONLY EVER ADD NEW WEAPONS AT THE END. IF YOU REMOVE ONE, PUT THE LAST ONE ON +// ITS PLACE. THIS IS TO AVOID UNNECESSARY RENUMBERING OF WEAPON IMPULSES. +// IF YOU DISREGARD THIS NOTICE, I'LL KILL YOU WITH THE @!#%'N TUBA + +// core weapons +#include "w_blaster.qc" +#include "w_shotgun.qc" +#include "w_machinegun.qc" +#include "w_mortar.qc" +#include "w_minelayer.qc" +#include "w_electro.qc" +#include "w_crylink.qc" +#include "w_vortex.qc" +#include "w_hagar.qc" +#include "w_devastator.qc" + +// other weapons +#include "w_porto.qc" +#include "w_vaporizer.qc" +#include "w_hook.qc" +#include "w_hlac.qc" +#include "w_tuba.qc" +#include "w_rifle.qc" +#include "w_fireball.qc" +#include "w_seeker.qc" +#include "w_shockwave.qc" +#include "w_arc.qc" +#include "w_hmg.qc" +#include "w_rpc.qc" diff --git a/qcsrc/common/weapons/all.qh b/qcsrc/common/weapons/all.qh deleted file mode 100644 index b4ee1e25d9..0000000000 --- a/qcsrc/common/weapons/all.qh +++ /dev/null @@ -1,42 +0,0 @@ -// TODO: include once -//#ifndef WEAPONS_ALL_H -//#define WEAPONS_ALL_H - -#include "../util.qh" - -#ifdef SVQC -# include "config.qh" -# include "../../server/bot/aim.qh" -#endif - -// ONLY EVER ADD NEW WEAPONS AT THE END. IF YOU REMOVE ONE, PUT THE LAST ONE ON -// ITS PLACE. THIS IS TO AVOID UNNECESSARY RENUMBERING OF WEAPON IMPULSES. -// IF YOU DISREGARD THIS NOTICE, I'LL KILL YOU WITH THE @!#%'N TUBA - -// core weapons -#include "w_blaster.qc" -#include "w_shotgun.qc" -#include "w_machinegun.qc" -#include "w_mortar.qc" -#include "w_minelayer.qc" -#include "w_electro.qc" -#include "w_crylink.qc" -#include "w_vortex.qc" -#include "w_hagar.qc" -#include "w_devastator.qc" - -// other weapons -#include "w_porto.qc" -#include "w_vaporizer.qc" -#include "w_hook.qc" -#include "w_hlac.qc" -#include "w_tuba.qc" -#include "w_rifle.qc" -#include "w_fireball.qc" -#include "w_seeker.qc" -#include "w_shockwave.qc" -#include "w_arc.qc" -#include "w_hmg.qc" -#include "w_rpc.qc" - -//#endif diff --git a/qcsrc/common/weapons/weapons.qc b/qcsrc/common/weapons/weapons.qc index 3ab584fc1e..58fdbaed44 100644 --- a/qcsrc/common/weapons/weapons.qc +++ b/qcsrc/common/weapons/weapons.qc @@ -54,7 +54,7 @@ #ifndef MENUQC #include "calculations.qc" #endif -#include "all.qh" +#include "all.inc" // WEAPON PLUGIN SYSTEM entity weapon_info[WEP_MAXCOUNT]; diff --git a/qcsrc/common/weapons/weapons.qh b/qcsrc/common/weapons/weapons.qh index 593a40e3e8..5f17ccb8f1 100644 --- a/qcsrc/common/weapons/weapons.qh +++ b/qcsrc/common/weapons/weapons.qh @@ -5,6 +5,10 @@ #include "calculations.qh" #endif +#include "../util.qh" +#ifdef SVQC +#include "../../server/bot/aim.qh" +#endif const int MAX_SHOT_DISTANCE = 32768; // weapon pickup ratings for bot logic @@ -199,7 +203,7 @@ void register_weapons_done(); REGISTER_WEAPON_2(WEP_##id,WEPSET_##id,function,ammotype,impulse,flags,rating,color,modelname,simplemdl,crosshair,wepimg,refname,wepname) #endif -#include "all.qh" +#include "all.inc" #undef WEP_ADD_CVAR_MO_PRI #undef WEP_ADD_CVAR_MO_SEC diff --git a/qcsrc/server/antilag.qc b/qcsrc/server/antilag.qc index f9829960d4..f4fe2058b9 100644 --- a/qcsrc/server/antilag.qc +++ b/qcsrc/server/antilag.qc @@ -3,7 +3,7 @@ #elif defined(SVQC) #include "../dpdefs/progsdefs.qh" #include "../dpdefs/dpextensions.qh" - #include "vehicles/vehicles_def.qh" + #include "vehicles/vehicle.qh" #include "antilag.qh" #endif diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 61565b7674..259b7e260c 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -28,7 +28,7 @@ #include "bot/bot.qh" #include "bot/navigation.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "weapons/hitplot.qh" #include "weapons/weaponsystem.qh" diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc index 8b40f9cf94..2169139c1a 100644 --- a/qcsrc/server/cl_impulse.qc +++ b/qcsrc/server/cl_impulse.qc @@ -10,7 +10,7 @@ #include "weapons/selection.qh" #include "weapons/tracing.qh" #include "weapons/weaponsystem.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "waypointsprites.qh" #include "../common/weapons/weapons.qh" diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index 13bf15e88a..eadb8ecff4 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -16,7 +16,9 @@ #include "../mutators/mutators_include.qh" -#include "../vehicles/vehicles_def.qh" +#ifdef SVQC + #include "../vehicles/vehicle.qh" +#endif #include "../../common/constants.qh" #include "../../common/deathtypes.qh" diff --git a/qcsrc/server/g_damage.qc b/qcsrc/server/g_damage.qc index beed2e1b3e..42bce3e619 100644 --- a/qcsrc/server/g_damage.qc +++ b/qcsrc/server/g_damage.qc @@ -8,7 +8,7 @@ #include "spawnpoints.qh" #include "tturrets/include/turrets_early.qh" #include "t_items.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "weapons/accuracy.qh" #include "weapons/csqcprojectile.qh" #include "weapons/selection.qh" diff --git a/qcsrc/server/g_damage.qh b/qcsrc/server/g_damage.qh index b98693de6c..49f495bc4a 100644 --- a/qcsrc/server/g_damage.qh +++ b/qcsrc/server/g_damage.qh @@ -22,7 +22,7 @@ #include "../common/deathtypes.qh" #include "mutators/mutators_include.qh" #include "tturrets/include/turrets_early.qh" - #include "vehicles/vehicles_def.qh" + #include "vehicles/vehicle.qh" #include "../csqcmodellib/sv_model.qh" #include "../common/playerstats.qh" #include "g_hook.qh" diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc index 1c6c3a7d86..3445b65c5f 100644 --- a/qcsrc/server/g_hook.qc +++ b/qcsrc/server/g_hook.qc @@ -9,7 +9,7 @@ #include "t_teleporters.qh" #include "command/common.qh" #include "round_handler.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "../common/constants.qh" #include "../common/util.qh" #include "../common/weapons/weapons.qh" diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 4a0139080c..970c051c12 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -4,6 +4,7 @@ #include "antilag.qh" #include "command/common.qh" #include "constants.qh" +#include "g_hook.qh" #include "ipban.qh" #include "mutators/mutators_include.qh" #include "tturrets/include/turrets_early.qh" @@ -1461,7 +1462,6 @@ float SUB_NoImpactCheck() #define SUB_OwnerCheck() (other && (other == self.owner)) -void RemoveGrapplingHook(entity pl); void W_Crylink_Dequeue(entity e); float WarpZone_Projectile_Touch_ImpactFilter_Callback() { diff --git a/qcsrc/server/mutators/gamemode_ctf.qc b/qcsrc/server/mutators/gamemode_ctf.qc index d40263fb72..99a85d11e8 100644 --- a/qcsrc/server/mutators/gamemode_ctf.qc +++ b/qcsrc/server/mutators/gamemode_ctf.qc @@ -3,7 +3,9 @@ #include "gamemode.qh" -#include "../vehicles/vehicles_def.qh" +#ifdef SVQC +#include "../vehicles/vehicle.qh" +#endif #include "../../warpzonelib/common.qh" #include "../../warpzonelib/mathlib.qh" diff --git a/qcsrc/server/mutators/mutators_include.qc b/qcsrc/server/mutators/mutators_include.qc index 350f10a72a..4c591446b7 100644 --- a/qcsrc/server/mutators/mutators_include.qc +++ b/qcsrc/server/mutators/mutators_include.qc @@ -46,7 +46,7 @@ #include "../../common/deathtypes.qh" #include "mutators_include.qh" #include "../tturrets/include/turrets_early.qh" - #include "../vehicles/vehicles_def.qh" + #include "../vehicles/vehicle.qh" #include "../campaign.qh" #include "../../common/campaign_common.qh" #include "../../common/mapinfo.qh" @@ -77,7 +77,7 @@ #include "../secret.qh" #include "../pathlib/pathlib.qh" #include "../tturrets/include/turrets.qh" - #include "../vehicles/vehicles.qh" + #include "../vehicles/all.qh" #endif #include "base.qc" diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 6b93a92b72..9d86a375f9 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -83,6 +83,8 @@ pathlib/movenode.qc pathlib/path_waypoint.qc pathlib/utility.qc +vehicles/all.qc + weapons/accuracy.qc weapons/common.qc weapons/csqcprojectile.qc // TODO diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc index 5779a511db..b52c2d7db9 100644 --- a/qcsrc/server/sv_main.qc +++ b/qcsrc/server/sv_main.qc @@ -10,7 +10,7 @@ #include "command/common.qh" #include "mutators/mutators_include.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "weapons/csqcprojectile.qh" #include "../common/constants.qh" diff --git a/qcsrc/server/t_halflife.qc b/qcsrc/server/t_halflife.qc index 754c52b49a..299db79734 100644 --- a/qcsrc/server/t_halflife.qc +++ b/qcsrc/server/t_halflife.qc @@ -1,7 +1,7 @@ #include "_.qh" #include "../warpzonelib/util_server.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" .float ladder_time; .entity ladder_entity; diff --git a/qcsrc/server/t_items.qh b/qcsrc/server/t_items.qh index 143395ba86..ef5813c6ba 100644 --- a/qcsrc/server/t_items.qh +++ b/qcsrc/server/t_items.qh @@ -63,13 +63,6 @@ const int ISF_SIZE = 128; .int ItemStatus; -void spawnfunc_item_strength(); -void spawnfunc_item_invincible(); -void spawnfunc_item_armor_small(); -void spawnfunc_item_shells(); -void spawnfunc_item_bullets(); -void spawnfunc_item_rockets(); - #ifdef CSQC float autocvar_cl_animate_items = 1; @@ -91,6 +84,13 @@ void ItemRead(float _IsNew); #endif #ifdef SVQC +void spawnfunc_item_strength(); +void spawnfunc_item_invincible(); +void spawnfunc_item_armor_small(); +void spawnfunc_item_shells(); +void spawnfunc_item_bullets(); +void spawnfunc_item_rockets(); + float autocvar_sv_simple_items; bool ItemSend(entity to, int sf); diff --git a/qcsrc/server/t_teleporters.qc b/qcsrc/server/t_teleporters.qc index b3266f38d6..e9f381d317 100644 --- a/qcsrc/server/t_teleporters.qc +++ b/qcsrc/server/t_teleporters.qc @@ -6,7 +6,7 @@ #include "g_hook.qh" #include "bot/waypoints.qh" #include "tturrets/include/turrets_early.qh" -#include "vehicles/vehicles_def.qh" +#include "vehicles/vehicle.qh" #include "weapons/csqcprojectile.qh" #include "../common/constants.qh" #include "../common/deathtypes.qh" diff --git a/qcsrc/server/vehicles/all.qc b/qcsrc/server/vehicles/all.qc new file mode 100644 index 0000000000..33e0c710c3 --- /dev/null +++ b/qcsrc/server/vehicles/all.qc @@ -0,0 +1,11 @@ +#if VEHICLES_ENABLED +# include "vehicle.qc" + +# include "racer.qc" +# include "raptor.qc" +# include "spiderbot.qc" + +# ifndef VEHICLES_NO_UNSTABLE +# include "bumblebee.qc" +# endif +#endif diff --git a/qcsrc/server/vehicles/all.qh b/qcsrc/server/vehicles/all.qh new file mode 100644 index 0000000000..c675c9cbfd --- /dev/null +++ b/qcsrc/server/vehicles/all.qh @@ -0,0 +1,14 @@ +#ifndef VEHICLES_H +#define VEHICLES_H + +#if VEHICLES_ENABLED +# include "racer.qh" +# include "raptor.qh" +# include "spiderbot.qh" + +# ifndef VEHICLES_NO_UNSTABLE +# include "bumblebee.qh" +# endif +#endif + +#endif diff --git a/qcsrc/server/vehicles/bumblebee.qc b/qcsrc/server/vehicles/bumblebee.qc index dfbcd4c36e..3fd45ee7c4 100644 --- a/qcsrc/server/vehicles/bumblebee.qc +++ b/qcsrc/server/vehicles/bumblebee.qc @@ -1,3 +1,4 @@ +#include "vehicle.qh" #include "bumblebee.qh" #ifdef SVQC diff --git a/qcsrc/server/vehicles/racer.qc b/qcsrc/server/vehicles/racer.qc index 49cebfc46b..545e309e4f 100644 --- a/qcsrc/server/vehicles/racer.qc +++ b/qcsrc/server/vehicles/racer.qc @@ -1,3 +1,4 @@ +#include "vehicle.qh" #include "racer.qh" #ifdef SVQC diff --git a/qcsrc/server/vehicles/raptor.qc b/qcsrc/server/vehicles/raptor.qc index 74d3c7a689..5c14fb7935 100644 --- a/qcsrc/server/vehicles/raptor.qc +++ b/qcsrc/server/vehicles/raptor.qc @@ -1,3 +1,4 @@ +#include "vehicle.qh" #include "raptor.qh" #ifdef SVQC diff --git a/qcsrc/server/vehicles/spiderbot.qc b/qcsrc/server/vehicles/spiderbot.qc index 10ab353ec8..c2a59fd183 100644 --- a/qcsrc/server/vehicles/spiderbot.qc +++ b/qcsrc/server/vehicles/spiderbot.qc @@ -1,3 +1,4 @@ +#include "vehicle.qh" #include "spiderbot.qh" #ifdef SVQC diff --git a/qcsrc/server/vehicles/vehicle.qc b/qcsrc/server/vehicles/vehicle.qc new file mode 100644 index 0000000000..b7ec7685cf --- /dev/null +++ b/qcsrc/server/vehicles/vehicle.qc @@ -0,0 +1,1434 @@ +#include "vehicle.qh" + +#include "../_.qh" +#include "../cl_player.qh" +#include "../../common/constants.qh" +#include "../waypointsprites.qh" + +#include "../bot/waypoints.qh" + +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_vortex_damagerate = 0.5; +float autocvar_g_vehicles_machinegun_damagerate = 0.5; +float autocvar_g_vehicles_rifle_damagerate = 0.75; +float autocvar_g_vehicles_vaporizer_damagerate = 0.001; +float autocvar_g_vehicles_tag_damagerate = 5; + +float autocvar_g_vehicles; + +void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force); +void vehicles_return(); +void vehicles_enter(); +void vehicles_reset_colors(); +void vehicles_clearreturn(); +void vehicles_setreturn(); + + +/** AuxiliaryXhair* + Send additional points of interest to be drawn, to vehicle owner +**/ +const float MAX_AXH = 4; +.entity AuxiliaryXhair[MAX_AXH]; + +float SendAuxiliaryXhair(entity to, int sf) +{ + + WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR); + + WriteByte(MSG_ENTITY, self.cnt); + + WriteCoord(MSG_ENTITY, self.origin.x); + WriteCoord(MSG_ENTITY, self.origin.y); + WriteCoord(MSG_ENTITY, self.origin.z); + + WriteByte(MSG_ENTITY, rint(self.colormod.x * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod.y * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod.z * 255)); + + return true; +} + +void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id) +{ + if (!IS_REAL_CLIENT(own)) + return; + + entity axh; + + axh_id = bound(0, axh_id, MAX_AXH); + axh = own.(AuxiliaryXhair[axh_id]); + + if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) + { + axh = spawn(); + axh.cnt = axh_id; + axh.drawonlytoclient = own; + axh.owner = own; + Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair); + } + + setorigin(axh, loc); + axh.colormod = clr; + axh.SendFlags = 0x01; + own.(AuxiliaryXhair[axh_id]) = axh; +} + +/* +// SVC_TEMPENTITY based, horrible with even 50 ping. hm. +// WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates. +void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id) +{ + msgexntity = own; + + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR); + + WriteByte(MSG_ONE, axh_id); + + WriteCoord(MSG_ONE, loc_x); + WriteCoord(MSG_ONE, loc_y); + WriteCoord(MSG_ONE, loc_z); + + WriteByte(MSG_ONE, rint(clr_x * 255)); + WriteByte(MSG_ONE, rint(clr_y * 255)); + WriteByte(MSG_ONE, rint(clr_z * 255)); + +} +*/ +// End AuxiliaryXhair + +/** + Notifies the client that he enterd a vehicle, and sends + realavent data. + + only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT) +**/ +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); + if(vehicle_id != 0) + WriteByte(MSG_ONE, vehicle_id); + else + WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST); +} + + +const float DAMAGE_TARGETDRONE = 10; + +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; +} + +#if 0 +void targetdrone_think(); +void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force); +void targetdrone_renwe() +{ + self.think = targetdrone_think; + self.nextthink = time + 0.1; + setorigin(self, targetdrone_getnewspot()); + self.health = 200; + self.takedamage = DAMAGE_TARGETDRONE; + self.event_damage = targetdrone_damage; + self.solid = SOLID_BBOX; + setmodel(self, "models/runematch/rune.mdl"); + self.effects = EF_LOWPRECISION; + self.scale = 10; + self.movetype = MOVETYPE_BOUNCEMISSILE; + setsize(self, '-100 -100 -100', '100 100 100'); + +} +void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + self.health -= damage; + if(self.health <= 0) + { + pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1); + + if(!self.cnt) + remove(self); + else + { + self.think = targetdrone_renwe; + self.nextthink = time + 1 + random() * 2; + self.solid = SOLID_NOT; + setmodel(self, ""); + } + } +} +entity targetdrone_getfear() +{ + entity fear; + float i; + + for(i = 64; i <= 1024; i += 64) + { + fear = findradius(self.origin, i); + while(fear) + { + if(fear.bot_dodge) + return fear; + + fear = fear.chain; + } + } + + return world; +} +void targetdrone_think() +{ + self.nextthink = time + 0.1; + + if(self.wp00) + if(self.wp00.deadflag != DEAD_NO) + self.wp00 = targetdrone_getfear(); + + if(!self.wp00) + self.wp00 = targetdrone_getfear(); + + vector newdir; + + if(self.wp00) + newdir = steerlib_push(self.wp00.origin) + randomvec() * 0.75; + else + newdir = randomvec() * 0.75; + + newdir = newdir * 0.5 + normalize(self.velocity) * 0.5; + + if(self.wp00) + self.velocity = normalize(newdir) * (500 + (1024 / min(vlen(self.wp00.origin - self.origin), 1024)) * 700); + else + self.velocity = normalize(newdir) * 750; + + tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 2, MOVE_NORMAL, self); + if(trace_fraction != 1.0) + self.velocity = self.velocity * -1; + + //normalize((normalize(self.velocity) * 0.5 + newdir * 0.5)) * 750; +} + +void targetdrone_spawn(vector _where, float _autorenew) +{ + entity drone = spawn(); + setorigin(drone, _where); + drone.think = targetdrone_renwe; + drone.nextthink = time + 0.1; + drone.cnt = _autorenew; +} +#endif + +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(teamplay && trace_ent.team == self.team) + 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.takedamage == DAMAGE_TARGETDRONE) + )) { trace_ent = world; } + } + + 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; + } +} + + +#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) + +// Hover movement support +float force_fromtag_power; +vector force_fromtag_origin; +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; +} + +// Experimental hovermode wich uses attraction/repulstion from surface insted of gravity/repulsion +// Can possibly be use to move abt any surface (inclusing walls/celings) +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; +} + +// Generic vehile projectile system +void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + // Ignore damage from oterh projectiles from my owner (dont mess up volly's) + if(inflictor.owner == self.owner) + return; + + self.health -= damage; + self.velocity += force; + if(self.health < 1) + { + self.takedamage = DAMAGE_NO; + self.event_damage = func_null; + self.think = self.use; + self.nextthink = time; + } +} + +void vehicles_projectile_explode() +{ + if(self.owner && other != world) + { + if(other == self.owner.vehicle) + return; + + if(other == self.owner.vehicle.tur_head) + return; + } + + PROJECTILE_TOUCH; + + self.event_damage = func_null; + RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other); + + remove (self); +} + +entity vehicles_projectile(string _mzlfx, string _mzlsound, + vector _org, vector _vel, + float _dmg, float _radi, float _force, float _size, + 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; +} +// End generic vehile projectile system + +void vehicles_reset() +{ + if(self.owner) + { + entity oldself = self; + self = self.owner; + vehicles_exit(VHEF_RELESE); + self = oldself; + } + 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'; + self.event_damage = func_null; + self.solid = SOLID_NOT; + self.deadflag = DEAD_NO; + + self.touch = func_null; + self.nextthink = 0; + vehicles_setreturn(); +} + +/** vehicles_spawn + Exetuted for all vehicles on (re)spawn. + Sets defaults for newly spawned units. +**/ +void vehicles_spawn() +{ + dprint("Spawning vehicle: ", self.netname, "\n"); + + // De-own & reset + self.vehicle_hudmodel.viewmodelforclient = self; + + self.owner = world; + self.touch = vehicles_touch; + self.event_damage = vehicles_damage; + self.reset = vehicles_reset; + 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'; + + // 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 + '0 0 0'); + // Show it + pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1); + + if(self.vehicle_controller) + self.team = self.vehicle_controller.team; + + vehicles_reset_colors(); + self.vehicle_spawn(VHSF_NORMAL); +} + +// Better way of determening whats crushable needed! (fl_crushable?) +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"); + } + } +} + +void vehicles_touch() +{ + if(MUTATOR_CALLHOOK(VehicleTouch)) + return; + + // Vehicle currently in use + if(self.owner) + { + if(other != world) + 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) + if(self.vehicle_impact) + self.vehicle_impact(); + + return; + } + + if (!IS_PLAYER(other)) + return; + + if(other.deadflag != DEAD_NO) + return; + + if(other.vehicle != world) + return; + + vehicles_enter(); +} +.float monster_attack; +void vehicles_enter() +{ + // Remove this when bots know how to use vehicles + + if (IS_BOT_CLIENT(other)) + 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(self.phase > time) + return; + if(other.frozen) + return; + if(other.vehicle) + return; + if(other.deadflag != DEAD_NO) + return; + + if(teamplay) + if(self.team) + if(self.team != other.team) + return; + + RemoveGrapplingHook(other); + + self.vehicle_ammo1 = 0; + self.vehicle_ammo2 = 0; + self.vehicle_reload1 = 0; + self.vehicle_reload2 = 0; + self.vehicle_energy = 0; + + self.owner = other; + self.switchweapon = other.switchweapon; + + // .viewmodelforclient works better. + //self.vehicle_hudmodel.drawonlytoclient = self.owner; + + self.vehicle_hudmodel.viewmodelforclient = self.owner; + + self.event_damage = vehicles_damage; + self.nextthink = 0; + self.owner.angles = self.angles; + self.owner.takedamage = DAMAGE_NO; + self.owner.solid = SOLID_NOT; + self.owner.movetype = MOVETYPE_NOCLIP; + self.owner.alpha = -1; + self.owner.vehicle = self; + self.owner.event_damage = func_null; + self.owner.view_ofs = '0 0 0'; + self.colormap = self.owner.colormap; + if(self.tur_head) + self.tur_head.colormap = self.owner.colormap; + + self.owner.hud = self.hud; + self.owner.PlayerPhysplug = self.PlayerPhysplug; + + self.owner.vehicle_ammo1 = self.vehicle_ammo1; + self.owner.vehicle_ammo2 = self.vehicle_ammo2; + self.owner.vehicle_reload1 = self.vehicle_reload1; + self.owner.vehicle_reload2 = self.vehicle_reload2; + + // Cant do this, hides attached objects too. + //self.exteriormodeltoclient = self.owner; + //self.tur_head.exteriormodeltoclient = self.owner; + + other.flags &= ~FL_ONGROUND; + self.flags &= ~FL_ONGROUND; + + self.team = self.owner.team; + self.flags -= FL_NOTARGET; + self.monster_attack = true; + + if (IS_REAL_CLIENT(other)) + { + msg_entity = other; + WriteByte (MSG_ONE, SVC_SETVIEWPORT); + WriteEntity(MSG_ONE, self.vehicle_viewport); + + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + if(self.tur_head) + { + WriteAngle(MSG_ONE, self.tur_head.angles.x + self.angles.x); // tilt + WriteAngle(MSG_ONE, self.tur_head.angles.y + self.angles.y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + else + { + WriteAngle(MSG_ONE, self.angles.x * -1); // tilt + WriteAngle(MSG_ONE, self.angles.y); // yaw + WriteAngle(MSG_ONE, 0); // roll + } + } + + vehicles_clearreturn(); + + CSQCVehicleSetup(self.owner, self.hud); + + vh_player = other; + vh_vehicle = self; + MUTATOR_CALLHOOK(VehicleEnter); + other = vh_player; + self = vh_vehicle; + + self.vehicle_enter(); + antilag_clear(other); +} + +/** vehicles_findgoodexit + Locates a valid location for the player to exit the vehicle. + Will first try prefer_spot, then up 100 random spots arround the vehicle + wich are in direct line of sight and empty enougth to hold a players bbox +**/ +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; +} + +/** vehicles_exit + Standarrd vehicle release fucntion. + custom code goes in self.vehicle_exit +**/ +float vehicles_exit_running; +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.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; + + 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; + + 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.monster_attack = false; + + _vehicle.vehicle_exit(eject); + + vehicles_setreturn(); + vehicles_reset_colors(); + _vehicle.owner = world; + self = _oldself; + + vehicles_exit_running = false; +} + + +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.tur_health); + + self.(regen_field) = min(self.(regen_field) + regen * delta_time, field_max); + + if (self.owner) + self.owner.(regen_field) = (self.(regen_field) / field_max) * 100; + } +} + +void shieldhit_think() +{ + self.alpha -= 0.1; + if (self.alpha <= 0) + { + //setmodel(self, ""); + self.alpha = -1; + self.effects |= EF_NODRAW; + } + else + { + self.nextthink = time + 0.1; + } +} + +void vehicles_painframe() +{ + if(self.owner.vehicle_health <= 50) + if(self.pain_frame < time) + { + float _ftmp; + _ftmp = self.owner.vehicle_health / 50; + self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp); + pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1); + + if(self.vehicle_flags & VHF_DMGSHAKE) + self.velocity += randomvec() * 30; + + if(self.vehicle_flags & VHF_DMGROLL) + if(self.vehicle_flags & VHF_DMGHEADROLL) + self.tur_head.angles += randomvec(); + else + self.angles += randomvec(); + + } +} + +void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) +{ + self.dmg_time = time; + + // WEAPONTODO + if(DEATH_ISWEAPON(deathtype, WEP_VORTEX)) + damage *= autocvar_g_vehicles_vortex_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN)) + damage *= autocvar_g_vehicles_machinegun_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_RIFLE)) + damage *= autocvar_g_vehicles_rifle_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER)) + damage *= autocvar_g_vehicles_vaporizer_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_SEEKER)) + damage *= autocvar_g_vehicles_tag_damagerate; + + self.enemy = attacker; + + 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_RELESE); + + + antilag_clear(self); + + self.vehicle_die(); + vehicles_setreturn(); + } +} + +void vehicles_clearreturn() +{ + entity ret; + // Remove "return helper", if any. + ret = findchain(classname, "vehicle_return"); + while(ret) + { + if(ret.wp00 == self) + { + 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_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 ret; + + vehicles_clearreturn(); + + ret = spawn(); + ret.classname = "vehicle_return"; + ret.wp00 = self; + ret.team = self.team; + ret.think = vehicles_showwp; + + if(self.deadflag != DEAD_NO) + { + ret.cnt = max(game_starttime, time) + self.vehicle_respawntime; + ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 5); + } + else + ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 1); + + setmodel(ret, "null"); + setorigin(ret, self.pos1 + '0 0 96'); +} + +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; + } + + 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 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) + { + dprint("^3Eat shit yall!\n"); + vehicles_setreturn(); + vehicles_reset_colors(); + } + else if(self.active == ACTIVE_NOT && self.deadflag != DEAD_NO) + { + + } +} + +float vehicle_addplayerslot( entity _owner, + entity _slot, + float _hud, + string _hud_model, + float() _framefunc, + void(float) _exitfunc) +{ + if (!(_owner.vehicle_flags & VHF_MULTISLOT)) + _owner.vehicle_flags |= VHF_MULTISLOT; + + _slot.PlayerPhysplug = _framefunc; + _slot.vehicle_exit = _exitfunc; + _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; +} + +float vehicle_initialize(string net_name, + string bodymodel, + string topmodel, + string hudmodel, + string toptag, + string hudtag, + string viewtag, + float vhud, + vector min_s, + vector max_s, + float nodrop, + void(float _spawnflag) spawnproc, + float _respawntime, + float() physproc, + void() enterproc, + void(float extflag) exitfunc, + void() dieproc, + void() thinkproc, + float use_csqc, + float _max_health, + float _max_shield) +{ + if(!autocvar_g_vehicles) + return false; + + if(self.targetname) + { + self.vehicle_controller = find(world, target, self.targetname); + if(!self.vehicle_controller) + { + bprint("^1WARNING: ^7Vehicle with invalid .targetname\n"); + } + 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; + } + } + } + + 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_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); + + if(bodymodel == "") + error("vehicles: missing bodymodel!"); + + if(hudmodel == "") + error("vehicles: missing hudmodel!"); + + if(net_name == "") + self.netname = self.classname; + else + self.netname = net_name; + + if(self.team && !teamplay) + self.team = 0; + + self.vehicle_flags |= VHF_ISVEHICLE; + + setmodel(self, bodymodel); + + self.vehicle_viewport = spawn(); + self.vehicle_hudmodel = spawn(); + self.tur_head = spawn(); + self.tur_head.owner = self; + self.takedamage = DAMAGE_AIM; + self.bot_attack = true; + self.iscreature = true; + self.teleportable = false; // no teleporting for vehicles, too buggy + self.damagedbycontents = true; + self.hud = vhud; + self.tur_health = _max_health; + self.tur_head.tur_health = _max_shield; + self.vehicle_die = dieproc; + self.vehicle_exit = exitfunc; + self.vehicle_enter = enterproc; + self.PlayerPhysplug = physproc; + self.event_damage = func_null; + self.touch = vehicles_touch; + self.think = vehicles_spawn; + self.vehicle_spawn = spawnproc; + self.vehicle_respawntime = max(0, _respawntime); + self.effects = EF_NODRAW; + self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; + if(!autocvar_g_vehicles_delayspawn || !self.vehicle_respawntime) + self.nextthink = time; + else + self.nextthink = max(time, game_starttime) + max(0, self.vehicle_respawntime + ((random() * 2 - 1) * autocvar_g_vehicles_delayspawn_jitter)); + + if(autocvar_g_playerclip_collisions) + self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; + + if(autocvar_g_nodepthtestplayers) + self.effects = self.effects | EF_NODEPTHTEST; + + if(autocvar_g_fullbrightplayers) + self.effects = self.effects | EF_FULLBRIGHT; + + setmodel(self.vehicle_hudmodel, hudmodel); + setmodel(self.vehicle_viewport, "null"); + + if(topmodel != "") + { + setmodel(self.tur_head, topmodel); + setattachment(self.tur_head, self, toptag); + setattachment(self.vehicle_hudmodel, self.tur_head, hudtag); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); + } + else + { + setattachment(self.tur_head, self, ""); + setattachment(self.vehicle_hudmodel, self, hudtag); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); + } + + setsize(self, min_s, max_s); + if (!nodrop) + { + setorigin(self, self.origin); + tracebox(self.origin + '0 0 100', min_s, max_s, 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; + + if(MUTATOR_CALLHOOK(VehicleSpawn)) + return false; + + 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_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; +} + +/* +vector predict_target(entity _targ, vector _from, float _shot_speed) +{ + float i; // loop + float _distance; // How far to target + float _impact_time; // How long untill projectile impacts + vector _predict_pos; // Predicted enemy location + vector _original_origin;// Where target is before predicted + + _original_origin = real_origin(_targ); // Typicaly center of target BBOX + + _predict_pos = _original_origin; + for(i = 0; i < 4; ++i) // Loop a few times to increase prediction accuracy (increase loop count if accuracy is to low) + { + _distance = vlen(_predict_pos - _from); // Get distance to previos predicted location + _impact_time = _distance / _shot_speed; // Calculate impact time + _predict_pos = _original_origin + _targ.velocity * _impact_time; // Calculate new predicted location + } + + return _predict_pos; +} +*/ diff --git a/qcsrc/server/vehicles/vehicle.qh b/qcsrc/server/vehicles/vehicle.qh new file mode 100644 index 0000000000..3b9368bf11 --- /dev/null +++ b/qcsrc/server/vehicles/vehicle.qh @@ -0,0 +1,197 @@ +#ifndef VEHICLE_H +#define VEHICLE_H + +#include "../_.qh" + +#include "../antilag.qh" +#include "../cl_player.qh" +#include "../g_damage.qh" +#include "../g_hook.qh" +#include "../g_subs.qh" +#include "../movelib.qh" + +#include "../bot/bot.qh" + +#include "../command/common.qh" + +#include "../tturrets/include/turrets_early.qh" + +#include "../weapons/tracing.qh" + +#include "../../common/deathtypes.qh" +#include "../../common/stats.qh" + +#include "../../warpzonelib/anglestransform.qh" +#include "../../warpzonelib/server.qh" + +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); + +vector vehicles_findgoodexit(vector prefer_spot); + + + +/** vehicles_locktarget + + Generic target locking. + + Figure out if what target is "locked" (if any), for missile tracking as such. + + after calling, "if(self.lock_target != world && self.lock_strength == 1)" mean + you have a locked in target. + + Exspects a crosshair_trace() or equivalent to be + dont before calling. + +**/ +.entity lock_target; +.float lock_strength; +.float lock_time; +.float lock_soundtime; + +void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id); + +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); + +#define VEHICLE_UPDATE_PLAYER(ply,fld,vhname) \ +ply.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 + +void CSQCVehicleSetup(entity own, float vehicle_id); + +.float() PlayerPhysplug; + +float autocvar_g_vehicles_allow_bots = 0; + +void vehicles_touch(); + +void vehicles_regen(float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time, float _healthscale); + +float shortangle_f(float ang1, float ang2); +float anglemods(float v); + +entity vehicle_tossgib(entity _template, vector _vel, string _tag, float _burn, float _explode, float _maxtime, vector _rot); + +void vehicles_impact(float _minspeed, float _speedfac, float _maxpain); + +void shieldhit_think(); + +float vehicle_addplayerslot( entity _owner, + entity _slot, + float _hud, + string _hud_model, + float() _framefunc, + void(float) _exitfunc); + +.void() vehicle_impact; + +float vehicle_initialize(string net_name, + string bodymodel, + string topmodel, + string hudmodel, + string toptag, + string hudtag, + string viewtag, + float vhud, + vector min_s, + vector max_s, + float nodrop, + void(float _spawnflag) spawnproc, + float _respawntime, + float() physproc, + void() enterproc, + void(float extflag) exitfunc, + void() dieproc, + void() thinkproc, + float use_csqc, + float _max_health, + float _max_shield); + +float force_fromtag_normpower; + +void vehicles_painframe(); + +void vehicles_locktarget(float incr, float decr, float _lock_time); + +vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power); + +vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power); + +void vehicles_projectile_explode(); + +#if VEHICLES_ENABLED + +.int vehicle_flags; +const int VHF_ISVEHICLE = 2; /// Indicates vehicle +const int VHF_HASSHIELD = 4; /// Vehicle has shileding +const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates +const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates +const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates +const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage +const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound +const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound +const int VHF_MOVE_FLY = 512; /// Vehicle is airborn +const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50% +const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50% +const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50% +const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots +const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle + +.entity 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; +const float VOL_VEHICLEENGINE = 1; + +.float hud; +.float dmg_time; +.float vehicle_respawntime; +//.void() vehicle_spawn; + +void vehicles_exit(float eject); +.void(float exit_flags) vehicle_exit; +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_RELESE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented) + +const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05 +const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A +const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80 + +.void() vehicle_enter; /// Vehicles custom funciton to be executed when owner exit it +.void() vehicle_die; /// Vehicles custom function to be executed when vehile die +const float VHSF_NORMAL = 0; +const float VHSF_FACTORY = 2; +.void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns +.float(float _imp) vehicles_impulse; +.float vehicle_weapon2mode; + +#if 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 +#endif // VEHICLES_ENABLED +#endif diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc deleted file mode 100644 index 3778b04055..0000000000 --- a/qcsrc/server/vehicles/vehicles.qc +++ /dev/null @@ -1,1455 +0,0 @@ -#include "vehicles.qh" - -#include "../cl_player.qh" -#include "../waypointsprites.qh" - -#include "../bot/waypoints.qh" - -.float() PlayerPhysplug; - -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_vortex_damagerate = 0.5; -float autocvar_g_vehicles_machinegun_damagerate = 0.5; -float autocvar_g_vehicles_rifle_damagerate = 0.75; -float autocvar_g_vehicles_vaporizer_damagerate = 0.001; -float autocvar_g_vehicles_tag_damagerate = 5; - -float autocvar_g_vehicles; - -void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force); -void vehicles_return(); -void vehicles_enter(); -void vehicles_touch(); -void vehicles_reset_colors(); -void vehicles_clearreturn(); -void vehicles_setreturn(); - - -/** AuxiliaryXhair* - Send additional points of interest to be drawn, to vehicle owner -**/ -const float MAX_AXH = 4; -.entity AuxiliaryXhair[MAX_AXH]; - -float SendAuxiliaryXhair(entity to, int sf) -{ - - WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR); - - WriteByte(MSG_ENTITY, self.cnt); - - WriteCoord(MSG_ENTITY, self.origin.x); - WriteCoord(MSG_ENTITY, self.origin.y); - WriteCoord(MSG_ENTITY, self.origin.z); - - WriteByte(MSG_ENTITY, rint(self.colormod.x * 255)); - WriteByte(MSG_ENTITY, rint(self.colormod.y * 255)); - WriteByte(MSG_ENTITY, rint(self.colormod.z * 255)); - - return true; -} - -void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, int axh_id) -{ - if (!IS_REAL_CLIENT(own)) - return; - - entity axh; - - axh_id = bound(0, axh_id, MAX_AXH); - axh = own.(AuxiliaryXhair[axh_id]); - - if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) - { - axh = spawn(); - axh.cnt = axh_id; - axh.drawonlytoclient = own; - axh.owner = own; - Net_LinkEntity(axh, false, 0, SendAuxiliaryXhair); - } - - setorigin(axh, loc); - axh.colormod = clr; - axh.SendFlags = 0x01; - own.(AuxiliaryXhair[axh_id]) = axh; -} - -/* -// SVC_TEMPENTITY based, horrible with even 50 ping. hm. -// WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates. -void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id) -{ - msgexntity = own; - - WriteByte(MSG_ONE, SVC_TEMPENTITY); - WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR); - - WriteByte(MSG_ONE, axh_id); - - WriteCoord(MSG_ONE, loc_x); - WriteCoord(MSG_ONE, loc_y); - WriteCoord(MSG_ONE, loc_z); - - WriteByte(MSG_ONE, rint(clr_x * 255)); - WriteByte(MSG_ONE, rint(clr_y * 255)); - WriteByte(MSG_ONE, rint(clr_z * 255)); - -} -*/ -// End AuxiliaryXhair - -/** - Notifies the client that he enterd a vehicle, and sends - realavent data. - - only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT) -**/ -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); - if(vehicle_id != 0) - WriteByte(MSG_ONE, vehicle_id); - else - WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST); -} - -/** vehicles_locktarget - - Generic target locking. - - Figure out if what target is "locked" (if any), for missile tracking as such. - - after calling, "if(self.lock_target != world && self.lock_strength == 1)" mean - you have a locked in target. - - Exspects a crosshair_trace() or equivalent to be - dont before calling. - -**/ -.entity lock_target; -.float lock_strength; -.float lock_time; -.float lock_soundtime; -const float DAMAGE_TARGETDRONE = 10; - -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; -} - -#if 0 -void targetdrone_think(); -void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force); -void targetdrone_renwe() -{ - self.think = targetdrone_think; - self.nextthink = time + 0.1; - setorigin(self, targetdrone_getnewspot()); - self.health = 200; - self.takedamage = DAMAGE_TARGETDRONE; - self.event_damage = targetdrone_damage; - self.solid = SOLID_BBOX; - setmodel(self, "models/runematch/rune.mdl"); - self.effects = EF_LOWPRECISION; - self.scale = 10; - self.movetype = MOVETYPE_BOUNCEMISSILE; - setsize(self, '-100 -100 -100', '100 100 100'); - -} -void targetdrone_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) -{ - self.health -= damage; - if(self.health <= 0) - { - pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1); - - if(!self.cnt) - remove(self); - else - { - self.think = targetdrone_renwe; - self.nextthink = time + 1 + random() * 2; - self.solid = SOLID_NOT; - setmodel(self, ""); - } - } -} -entity targetdrone_getfear() -{ - entity fear; - float i; - - for(i = 64; i <= 1024; i += 64) - { - fear = findradius(self.origin, i); - while(fear) - { - if(fear.bot_dodge) - return fear; - - fear = fear.chain; - } - } - - return world; -} -void targetdrone_think() -{ - self.nextthink = time + 0.1; - - if(self.wp00) - if(self.wp00.deadflag != DEAD_NO) - self.wp00 = targetdrone_getfear(); - - if(!self.wp00) - self.wp00 = targetdrone_getfear(); - - vector newdir; - - if(self.wp00) - newdir = steerlib_push(self.wp00.origin) + randomvec() * 0.75; - else - newdir = randomvec() * 0.75; - - newdir = newdir * 0.5 + normalize(self.velocity) * 0.5; - - if(self.wp00) - self.velocity = normalize(newdir) * (500 + (1024 / min(vlen(self.wp00.origin - self.origin), 1024)) * 700); - else - self.velocity = normalize(newdir) * 750; - - tracebox(self.origin, self.mins, self.maxs, self.origin + self.velocity * 2, MOVE_NORMAL, self); - if(trace_fraction != 1.0) - self.velocity = self.velocity * -1; - - //normalize((normalize(self.velocity) * 0.5 + newdir * 0.5)) * 750; -} - -void targetdrone_spawn(vector _where, float _autorenew) -{ - entity drone = spawn(); - setorigin(drone, _where); - drone.think = targetdrone_renwe; - drone.nextthink = time + 0.1; - drone.cnt = _autorenew; -} -#endif - -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(teamplay && trace_ent.team == self.team) - 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.takedamage == DAMAGE_TARGETDRONE) - )) { trace_ent = world; } - } - - 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; - } -} - -#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) - -// Hover movement support -float force_fromtag_power; -float force_fromtag_normpower; -vector force_fromtag_origin; -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; -} - -// Experimental hovermode wich uses attraction/repulstion from surface insted of gravity/repulsion -// Can possibly be use to move abt any surface (inclusing walls/celings) -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; -} - -// Generic vehile projectile system -void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) -{ - // Ignore damage from oterh projectiles from my owner (dont mess up volly's) - if(inflictor.owner == self.owner) - return; - - self.health -= damage; - self.velocity += force; - if(self.health < 1) - { - self.takedamage = DAMAGE_NO; - self.event_damage = func_null; - self.think = self.use; - self.nextthink = time; - } -} - -void vehicles_projectile_explode() -{ - if(self.owner && other != world) - { - if(other == self.owner.vehicle) - return; - - if(other == self.owner.vehicle.tur_head) - return; - } - - PROJECTILE_TOUCH; - - self.event_damage = func_null; - RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, world, self.shot_force, self.totalfrags, other); - - remove (self); -} - -entity vehicles_projectile(string _mzlfx, string _mzlsound, - vector _org, vector _vel, - float _dmg, float _radi, float _force, float _size, - 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; -} -// End generic vehile projectile system - -void vehicles_reset() -{ - if(self.owner) - { - entity oldself = self; - self = self.owner; - vehicles_exit(VHEF_RELESE); - self = oldself; - } - 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'; - self.event_damage = func_null; - self.solid = SOLID_NOT; - self.deadflag = DEAD_NO; - - self.touch = func_null; - self.nextthink = 0; - vehicles_setreturn(); -} - -/** vehicles_spawn - Exetuted for all vehicles on (re)spawn. - Sets defaults for newly spawned units. -**/ -void vehicles_spawn() -{ - dprint("Spawning vehicle: ", self.netname, "\n"); - - // De-own & reset - self.vehicle_hudmodel.viewmodelforclient = self; - - self.owner = world; - self.touch = vehicles_touch; - self.event_damage = vehicles_damage; - self.reset = vehicles_reset; - 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'; - - // 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 + '0 0 0'); - // Show it - pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1); - - if(self.vehicle_controller) - self.team = self.vehicle_controller.team; - - vehicles_reset_colors(); - self.vehicle_spawn(VHSF_NORMAL); -} - -// Better way of determening whats crushable needed! (fl_crushable?) -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"); - } - } -} - -.void() vehicle_impact; -void vehicles_touch() -{ - if(MUTATOR_CALLHOOK(VehicleTouch)) - return; - - // Vehicle currently in use - if(self.owner) - { - if(other != world) - 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) - if(self.vehicle_impact) - self.vehicle_impact(); - - return; - } - - if (!IS_PLAYER(other)) - return; - - if(other.deadflag != DEAD_NO) - return; - - if(other.vehicle != world) - return; - - vehicles_enter(); -} -float autocvar_g_vehicles_allow_bots = 0; -void vehicles_enter() -{ - // Remove this when bots know how to use vehicles - - if (IS_BOT_CLIENT(other)) - 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(self.phase > time) - return; - if(other.frozen) - return; - if(other.vehicle) - return; - if(other.deadflag != DEAD_NO) - return; - - if(teamplay) - if(self.team) - if(self.team != other.team) - return; - - RemoveGrapplingHook(other); - - self.vehicle_ammo1 = 0; - self.vehicle_ammo2 = 0; - self.vehicle_reload1 = 0; - self.vehicle_reload2 = 0; - self.vehicle_energy = 0; - - self.owner = other; - self.switchweapon = other.switchweapon; - - // .viewmodelforclient works better. - //self.vehicle_hudmodel.drawonlytoclient = self.owner; - - self.vehicle_hudmodel.viewmodelforclient = self.owner; - - self.event_damage = vehicles_damage; - self.nextthink = 0; - self.owner.angles = self.angles; - self.owner.takedamage = DAMAGE_NO; - self.owner.solid = SOLID_NOT; - self.owner.movetype = MOVETYPE_NOCLIP; - self.owner.alpha = -1; - self.owner.vehicle = self; - self.owner.event_damage = func_null; - self.owner.view_ofs = '0 0 0'; - self.colormap = self.owner.colormap; - if(self.tur_head) - self.tur_head.colormap = self.owner.colormap; - - self.owner.hud = self.hud; - self.owner.PlayerPhysplug = self.PlayerPhysplug; - - self.owner.vehicle_ammo1 = self.vehicle_ammo1; - self.owner.vehicle_ammo2 = self.vehicle_ammo2; - self.owner.vehicle_reload1 = self.vehicle_reload1; - self.owner.vehicle_reload2 = self.vehicle_reload2; - - // Cant do this, hides attached objects too. - //self.exteriormodeltoclient = self.owner; - //self.tur_head.exteriormodeltoclient = self.owner; - - other.flags &= ~FL_ONGROUND; - self.flags &= ~FL_ONGROUND; - - self.team = self.owner.team; - self.flags -= FL_NOTARGET; - self.monster_attack = true; - - if (IS_REAL_CLIENT(other)) - { - msg_entity = other; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity(MSG_ONE, self.vehicle_viewport); - - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); - if(self.tur_head) - { - WriteAngle(MSG_ONE, self.tur_head.angles.x + self.angles.x); // tilt - WriteAngle(MSG_ONE, self.tur_head.angles.y + self.angles.y); // yaw - WriteAngle(MSG_ONE, 0); // roll - } - else - { - WriteAngle(MSG_ONE, self.angles.x * -1); // tilt - WriteAngle(MSG_ONE, self.angles.y); // yaw - WriteAngle(MSG_ONE, 0); // roll - } - } - - vehicles_clearreturn(); - - CSQCVehicleSetup(self.owner, self.hud); - - vh_player = other; - vh_vehicle = self; - MUTATOR_CALLHOOK(VehicleEnter); - other = vh_player; - self = vh_vehicle; - - self.vehicle_enter(); - antilag_clear(other); -} - -/** vehicles_findgoodexit - Locates a valid location for the player to exit the vehicle. - Will first try prefer_spot, then up 100 random spots arround the vehicle - wich are in direct line of sight and empty enougth to hold a players bbox -**/ -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; -} - -/** vehicles_exit - Standarrd vehicle release fucntion. - custom code goes in self.vehicle_exit -**/ -float vehicles_exit_running; -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.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; - - 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; - - 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.monster_attack = false; - - _vehicle.vehicle_exit(eject); - - vehicles_setreturn(); - vehicles_reset_colors(); - _vehicle.owner = world; - self = _oldself; - - vehicles_exit_running = false; -} - - -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.tur_health); - - self.(regen_field) = min(self.(regen_field) + regen * delta_time, field_max); - - if (self.owner) - self.owner.(regen_field) = (self.(regen_field) / field_max) * 100; - } -} - -void shieldhit_think() -{ - self.alpha -= 0.1; - if (self.alpha <= 0) - { - //setmodel(self, ""); - self.alpha = -1; - self.effects |= EF_NODRAW; - } - else - { - self.nextthink = time + 0.1; - } -} - -void vehicles_painframe() -{ - if(self.owner.vehicle_health <= 50) - if(self.pain_frame < time) - { - float _ftmp; - _ftmp = self.owner.vehicle_health / 50; - self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp); - pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1); - - if(self.vehicle_flags & VHF_DMGSHAKE) - self.velocity += randomvec() * 30; - - if(self.vehicle_flags & VHF_DMGROLL) - if(self.vehicle_flags & VHF_DMGHEADROLL) - self.tur_head.angles += randomvec(); - else - self.angles += randomvec(); - - } -} - -void vehicles_damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) -{ - self.dmg_time = time; - - // WEAPONTODO - if(DEATH_ISWEAPON(deathtype, WEP_VORTEX)) - damage *= autocvar_g_vehicles_vortex_damagerate; - - if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN)) - damage *= autocvar_g_vehicles_machinegun_damagerate; - - if(DEATH_ISWEAPON(deathtype, WEP_RIFLE)) - damage *= autocvar_g_vehicles_rifle_damagerate; - - if(DEATH_ISWEAPON(deathtype, WEP_VAPORIZER)) - damage *= autocvar_g_vehicles_vaporizer_damagerate; - - if(DEATH_ISWEAPON(deathtype, WEP_SEEKER)) - damage *= autocvar_g_vehicles_tag_damagerate; - - self.enemy = attacker; - - 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_RELESE); - - - antilag_clear(self); - - self.vehicle_die(); - vehicles_setreturn(); - } -} - -void vehicles_clearreturn() -{ - entity ret; - // Remove "return helper", if any. - ret = findchain(classname, "vehicle_return"); - while(ret) - { - if(ret.wp00 == self) - { - 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_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 ret; - - vehicles_clearreturn(); - - ret = spawn(); - ret.classname = "vehicle_return"; - ret.wp00 = self; - ret.team = self.team; - ret.think = vehicles_showwp; - - if(self.deadflag != DEAD_NO) - { - ret.cnt = max(game_starttime, time) + self.vehicle_respawntime; - ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 5); - } - else - ret.nextthink = max(game_starttime, time) + max(0, self.vehicle_respawntime - 1); - - setmodel(ret, "null"); - setorigin(ret, self.pos1 + '0 0 96'); -} - -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; - } - - 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 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) - { - dprint("^3Eat shit yall!\n"); - vehicles_setreturn(); - vehicles_reset_colors(); - } - else if(self.active == ACTIVE_NOT && self.deadflag != DEAD_NO) - { - - } -} - -float vehicle_addplayerslot( entity _owner, - entity _slot, - float _hud, - string _hud_model, - float() _framefunc, - void(float) _exitfunc) -{ - if (!(_owner.vehicle_flags & VHF_MULTISLOT)) - _owner.vehicle_flags |= VHF_MULTISLOT; - - _slot.PlayerPhysplug = _framefunc; - _slot.vehicle_exit = _exitfunc; - _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; -} - -float vehicle_initialize(string net_name, - string bodymodel, - string topmodel, - string hudmodel, - string toptag, - string hudtag, - string viewtag, - float vhud, - vector min_s, - vector max_s, - float nodrop, - void(float _spawnflag) spawnproc, - float _respawntime, - float() physproc, - void() enterproc, - void(float extflag) exitfunc, - void() dieproc, - void() thinkproc, - float use_csqc, - float _max_health, - float _max_shield) -{ - if(!autocvar_g_vehicles) - return false; - - if(self.targetname) - { - self.vehicle_controller = find(world, target, self.targetname); - if(!self.vehicle_controller) - { - bprint("^1WARNING: ^7Vehicle with invalid .targetname\n"); - } - 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; - } - } - } - - 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_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); - - if(bodymodel == "") - error("vehicles: missing bodymodel!"); - - if(hudmodel == "") - error("vehicles: missing hudmodel!"); - - if(net_name == "") - self.netname = self.classname; - else - self.netname = net_name; - - if(self.team && !teamplay) - self.team = 0; - - self.vehicle_flags |= VHF_ISVEHICLE; - - setmodel(self, bodymodel); - - self.vehicle_viewport = spawn(); - self.vehicle_hudmodel = spawn(); - self.tur_head = spawn(); - self.tur_head.owner = self; - self.takedamage = DAMAGE_AIM; - self.bot_attack = true; - self.iscreature = true; - self.teleportable = false; // no teleporting for vehicles, too buggy - self.damagedbycontents = true; - self.hud = vhud; - self.tur_health = _max_health; - self.tur_head.tur_health = _max_shield; - self.vehicle_die = dieproc; - self.vehicle_exit = exitfunc; - self.vehicle_enter = enterproc; - self.PlayerPhysplug = physproc; - self.event_damage = func_null; - self.touch = vehicles_touch; - self.think = vehicles_spawn; - self.vehicle_spawn = spawnproc; - self.vehicle_respawntime = max(0, _respawntime); - self.effects = EF_NODRAW; - self.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; - if(!autocvar_g_vehicles_delayspawn || !self.vehicle_respawntime) - self.nextthink = time; - else - self.nextthink = max(time, game_starttime) + max(0, self.vehicle_respawntime + ((random() * 2 - 1) * autocvar_g_vehicles_delayspawn_jitter)); - - if(autocvar_g_playerclip_collisions) - self.dphitcontentsmask |= DPCONTENTS_PLAYERCLIP; - - if(autocvar_g_nodepthtestplayers) - self.effects = self.effects | EF_NODEPTHTEST; - - if(autocvar_g_fullbrightplayers) - self.effects = self.effects | EF_FULLBRIGHT; - - setmodel(self.vehicle_hudmodel, hudmodel); - setmodel(self.vehicle_viewport, "null"); - - if(topmodel != "") - { - setmodel(self.tur_head, topmodel); - setattachment(self.tur_head, self, toptag); - setattachment(self.vehicle_hudmodel, self.tur_head, hudtag); - setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); - } - else - { - setattachment(self.tur_head, self, ""); - setattachment(self.vehicle_hudmodel, self, hudtag); - setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); - } - - setsize(self, min_s, max_s); - if (!nodrop) - { - setorigin(self, self.origin); - tracebox(self.origin + '0 0 100', min_s, max_s, 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; - - if(MUTATOR_CALLHOOK(VehicleSpawn)) - return false; - - 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_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; -} - -/* -vector predict_target(entity _targ, vector _from, float _shot_speed) -{ - float i; // loop - float _distance; // How far to target - float _impact_time; // How long untill projectile impacts - vector _predict_pos; // Predicted enemy location - vector _original_origin;// Where target is before predicted - - _original_origin = real_origin(_targ); // Typicaly center of target BBOX - - _predict_pos = _original_origin; - for(i = 0; i < 4; ++i) // Loop a few times to increase prediction accuracy (increase loop count if accuracy is to low) - { - _distance = vlen(_predict_pos - _from); // Get distance to previos predicted location - _impact_time = _distance / _shot_speed; // Calculate impact time - _predict_pos = _original_origin + _targ.velocity * _impact_time; // Calculate new predicted location - } - - return _predict_pos; -} -*/ diff --git a/qcsrc/server/vehicles/vehicles.qh b/qcsrc/server/vehicles/vehicles.qh deleted file mode 100644 index ec152d7f7b..0000000000 --- a/qcsrc/server/vehicles/vehicles.qh +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef VEHICLES_H -#define VEHICLES_H - -#ifdef VEHICLES_ENABLED -# include "vehicles.qc" - -# include "racer.qc" -# include "raptor.qc" -# include "spiderbot.qc" - -# ifndef VEHICLES_NO_UNSTABLE -# include "bumblebee.qc" -# endif -#endif - -#endif diff --git a/qcsrc/server/vehicles/vehicles_def.qh b/qcsrc/server/vehicles/vehicles_def.qh deleted file mode 100644 index 20f7ade398..0000000000 --- a/qcsrc/server/vehicles/vehicles_def.qh +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef VEHICLES_DEF_H -#define VEHICLES_DEF_H - -#include "../tturrets/include/turrets_early.qh" - -// #define VEHICLES_USE_ODE -#define VEHICLES_ENABLED -#ifdef VEHICLES_ENABLED - -.int vehicle_flags; -const int VHF_ISVEHICLE = 2; /// Indicates vehicle -const int VHF_HASSHIELD = 4; /// Vehicle has shileding -const int VHF_SHIELDREGEN = 8; /// Vehicles shield regenerates -const int VHF_HEALTHREGEN = 16; /// Vehicles health regenerates -const int VHF_ENERGYREGEN = 32; /// Vehicles energy regenerates -const int VHF_DEATHEJECT = 64; /// Vehicle ejects pilot upon fatal damage -const int VHF_MOVE_GROUND = 128; /// Vehicle moves on gound -const int VHF_MOVE_HOVER = 256; /// Vehicle hover close to gound -const int VHF_MOVE_FLY = 512; /// Vehicle is airborn -const int VHF_DMGSHAKE = 1024; /// Add random velocity each frame if health < 50% -const int VHF_DMGROLL = 2048; /// Add random angles each frame if health < 50% -const int VHF_DMGHEADROLL = 4096; /// Add random head angles each frame if health < 50% -const int VHF_MULTISLOT = 8192; /// Vehicle has multiple player slots -const int VHF_PLAYERSLOT = 16384; /// This ent is a player slot on a multi-person vehicle - -.entity 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; -const float VOL_VEHICLEENGINE = 1; - -.float hud; -.float dmg_time; -.float vehicle_respawntime; -//.void() vehicle_spawn; - -void vehicles_exit(float eject); -.void(float exit_flags) vehicle_exit; -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_RELESE = 2; /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented) - -const float SVC_SETVIEWPORT = 5; // Net.Protocol 0x05 -const float SVC_SETVIEWANGLES = 10; // Net.Protocol 0x0A -const float SVC_UPDATEENTITY = 128; // Net.Protocol 0x80 - -.void() vehicle_enter; /// Vehicles custom funciton to be executed when owner exit it -.void() vehicle_die; /// Vehicles custom function to be executed when vehile die -const float VHSF_NORMAL = 0; -const float VHSF_FACTORY = 2; -.void(float _spawnflag) vehicle_spawn; /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns -.float(float _imp) vehicles_impulse; -.float vehicle_weapon2mode; - -#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 -#endif // VEHICLES_ENABLED -#endif diff --git a/qcsrc/test/compilationunit.sh b/qcsrc/test/compilationunit.sh index 09539c6d7e..784784f3b1 100755 --- a/qcsrc/test/compilationunit.sh +++ b/qcsrc/test/compilationunit.sh @@ -8,6 +8,10 @@ declare -a NOWARN=( '-Wno-unused-variable' '-Wno-implicit-function-pointer' ) +declare -a FEATURES=( + '-DVEHICLES_ENABLED=1' + '-DVEHICLES_USE_ODE=0' +) declare QCC=../../../gmqcc/gmqcc function check() { @@ -15,7 +19,7 @@ function check() { declare -la predefs=("${!2}") find "$base" -type f -name '*.qc' -print0 | sort -z | while IFS= read -r -d '' file; do echo "$file" - ${QCC} -std=gmqcc -fftepp -fftepp-predefs -Werror -Wall "${NOWARN[@]}" -futf8 -O3 "${predefs[@]}" "$file" >/dev/null + ${QCC} -std=gmqcc -fftepp -fftepp-predefs -Werror -Wall "${NOWARN[@]}" "${FEATURES[@]}" -futf8 -O3 "${predefs[@]}" "$file" >/dev/null done }