]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/vehicles/vehicles.qc
Merge branch 'master' into Mario/classname_checks
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / vehicles / vehicles.qc
index b0eb99a8682bd6e2db035e6cd3369d4b82b21417..db57f65a1ff94f4516a9dfe023a37b522acd8abb 100644 (file)
@@ -2,14 +2,14 @@ float autocvar_g_vehicles_crush_dmg;
 float autocvar_g_vehicles_crush_force;
 float autocvar_g_vehicles_delayspawn;
 float autocvar_g_vehicles_delayspawn_jitter;
-float autocvar_g_vehicles_allow_flagcarry;
 
-float autocvar_g_vehicles_nex_damagerate = 0.5;
-float autocvar_g_vehicles_uzi_damagerate = 0.5;
-float autocvar_g_vehicles_rifle_damagerate = 0.75;
-float autocvar_g_vehicles_minstanex_damagerate = 0.001;
-float autocvar_g_vehicles_tag_damagerate = 5;
+var float autocvar_g_vehicles_nex_damagerate = 0.5;
+var float autocvar_g_vehicles_uzi_damagerate = 0.5;
+var float autocvar_g_vehicles_rifle_damagerate = 0.75;
+var float autocvar_g_vehicles_minstanex_damagerate = 0.001;
+var float autocvar_g_vehicles_tag_damagerate = 5;
 
+float autocvar_g_vehicles;
 
 void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);
 void vehicles_return();
@@ -46,7 +46,7 @@ float SendAuxiliaryXhair(entity to, float sf)
 
 void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id)
 {
-    if (clienttype(own) != CLIENTTYPE_REAL)
+    if not(IS_REAL_CLIENT(own))
         return;
 
     entity axh;
@@ -101,7 +101,7 @@ void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id)
 **/
 void CSQCVehicleSetup(entity own, float vehicle_id)
 {
-    if (clienttype(own) != CLIENTTYPE_REAL)
+    if not(IS_REAL_CLIENT(own))
         return;
        
        msg_entity = own;
@@ -377,7 +377,7 @@ void vehicles_projectile_damage(entity inflictor, entity attacker, float damage,
     if(self.health < 1)
     {
         self.takedamage = DAMAGE_NO;
-        self.event_damage = SUB_Null;
+        self.event_damage = func_null;
         self.think = self.use;
         self.nextthink = time;
     }
@@ -396,7 +396,7 @@ void vehicles_projectile_explode()
 
        PROJECTILE_TOUCH;
 
-       self.event_damage = SUB_Null;
+       self.event_damage = func_null;
     RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, self.shot_force, self.totalfrags, other);
 
     remove (self);
@@ -471,6 +471,7 @@ void vehicles_spawn()
     self.touch              = vehicles_touch;
     self.event_damage       = vehicles_damage;
     self.iscreature         = TRUE;
+    self.teleportable       = FALSE; // no teleporting for vehicles, too buggy
     self.damagedbycontents     = TRUE;
     self.movetype           = MOVETYPE_WALK;
     self.solid              = SOLID_SLIDEBOX;
@@ -502,11 +503,11 @@ void vehicles_spawn()
 // Better way of determening whats crushable needed! (fl_crushable?)
 float vehicles_crushable(entity e)
 {
-    if(e.classname == "player")
+    if(IS_PLAYER(e))
         return TRUE;
 
-    if(e.classname == "monster_zombie")
-        return TRUE;
+    if(e.flags & FL_MONSTER)
+        return TRUE; // more bitflags for everyone!
 
     return FALSE;
 }
@@ -543,7 +544,7 @@ void vehicles_touch()
         if(vehicles_crushable(other))
         {
             if(vlen(self.velocity) != 0)
-                Damage(other, self, self.owner, autocvar_g_vehicles_crush_dmg, DEATH_VHCRUSH, '0 0 0', normalize(other.origin - self.origin) * autocvar_g_vehicles_crush_force);
+                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".
         }
@@ -555,7 +556,7 @@ void vehicles_touch()
         return;
     }
 
-    if(other.classname != "player")
+    if not(IS_PLAYER(other))
         return;
 
     if(other.deadflag != DEAD_NO)
@@ -571,7 +572,7 @@ void vehicles_enter()
 {
    // Remove this when bots know how to use vehicles
    
-    if (clienttype(other) == CLIENTTYPE_BOT)    
+    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
@@ -609,7 +610,7 @@ void vehicles_enter()
     self.owner.movetype       = MOVETYPE_NOCLIP;
     self.owner.alpha          = -1;
     self.owner.vehicle        = self;
-    self.owner.event_damage   = SUB_Null;
+    self.owner.event_damage   = func_null;
     self.owner.view_ofs       = '0 0 0';
     self.colormap             = self.owner.colormap;
     if(self.tur_head)
@@ -633,7 +634,7 @@ void vehicles_enter()
     self.team                 = self.owner.team;
     self.flags               -= FL_NOTARGET;
     
-    if (clienttype(other) == CLIENTTYPE_REAL)
+    if (IS_REAL_CLIENT(other))
     {
         msg_entity = other;
         WriteByte (MSG_ONE, SVC_SETVIEWPORT);
@@ -657,18 +658,12 @@ void vehicles_enter()
     vehicles_clearrturn();
 
     CSQCVehicleSetup(self.owner, self.hud);
-
-    if(other.flagcarried)
-    {
-        if(!autocvar_g_vehicles_allow_flagcarry)
-            DropFlag(other.flagcarried, world, world);
-        else
-        {
-            other.flagcarried.scale = 1;
-            setattachment(other.flagcarried, self, "");
-            setorigin(other, '0 0 96');
-        }
-    }
+    
+    vh_player = other;
+    vh_vehicle = self;
+    MUTATOR_CALLHOOK(VehicleEnter);
+    other = vh_player;
+    self = vh_vehicle;
 
     self.vehicle_enter();
     antilag_clear(other);
@@ -688,7 +683,7 @@ vector vehicles_findgoodexit(vector prefer_spot)
     if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid)
         return prefer_spot;
 
-    mysize = vlen(self.maxs - self.mins);
+    mysize = 1.5 * vlen(self.maxs - self.mins);
     float i;
     vector v, v2;
     v2 = 0.5 * (self.absmin + self.absmax);
@@ -744,7 +739,8 @@ void vehicles_exit(float eject)
         return;
     }
     
-    if(self.flags & FL_CLIENT)
+    vehicles_exit_running = TRUE;
+    if(IS_CLIENT(self))
     {
         _vehicle = self.vehicle;
             
@@ -752,6 +748,7 @@ void vehicles_exit(float eject)
         {
             _vehicle.vehicle_exit(eject);
             self = _oldself;
+            vehicles_exit_running = FALSE;
             return;            
         }
     }
@@ -764,9 +761,7 @@ void vehicles_exit(float eject)
 
     if (_player)
     {
-        dprint("^3Player exits\n");
-        
-        if (clienttype(_player) == CLIENTTYPE_REAL)
+        if (IS_REAL_CLIENT(_player))
         {
             msg_entity = _player;
             WriteByte (MSG_ONE, SVC_SETVIEWPORT);
@@ -785,25 +780,15 @@ void vehicles_exit(float eject)
         _player.movetype       = MOVETYPE_WALK;
         _player.effects        &~= EF_NODRAW;
         _player.alpha          = 1;
-        _player.PlayerPhysplug = SUB_Null;
+        _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;
 
-        if(_player.flagcarried)
-        {
-            _player.flagcarried.scale = 0.6;
-            setattachment(_player.flagcarried, _player, "");
-            setorigin(_player.flagcarried, FLAG_CARRY_POS);
-        }
-
         CSQCVehicleSetup(_player, HUD_NORMAL);
     }
-    
-
-    dprint("^1Pilot exits\n");
     _vehicle.flags |= FL_NOTARGET;
     
     if(_vehicle.deadflag == DEAD_NO)
@@ -814,8 +799,14 @@ void vehicles_exit(float eject)
     if(!teamplay)
         _vehicle.team = 0;
     else
-        _vehicle.team = _vehicle.tur_head.team;
-    
+
+    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, ATTN_NORM);
     _vehicle.vehicle_hudmodel.viewmodelforclient = _vehicle;   
@@ -827,13 +818,15 @@ void vehicles_exit(float eject)
     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)
+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(self.timer + rpause < time)
+    if(timer + rpause < time)
     {
         if(_healthscale)
             regen = regen * (self.vehicle_health / self.tur_health);
@@ -947,8 +940,11 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
         if(sound_allowed(MSG_BROADCAST, attacker))
             spamsound (self, CH_PAIN, "onslaught/ons_hit2.wav", VOL_BASE, ATTN_NORM);  // FIXME: PLACEHOLDER
     }
-
-    self.velocity += force; // * (vlen(force) / self.mass);
+    
+       if(self.damageforcescale < 1 && self.damageforcescale > 0)
+               self.velocity += force * self.damageforcescale;
+       else
+               self.velocity += force;
 
     if(self.vehicle_health <= 0)
     {
@@ -958,7 +954,9 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat
             else
                 vehicles_exit(VHEF_RELESE);
 
+
         antilag_clear(self);
+
         self.vehicle_die();
         vehicles_setreturn();
     }
@@ -1010,7 +1008,7 @@ void vehicles_showwp_goaway()
 
 void vehicles_showwp()
 {
-    entity oldself;
+    entity oldself = world;
     vector rgb;
 
     if(self.cnt)
@@ -1035,7 +1033,7 @@ void vehicles_showwp()
     }
 
     if(teamplay && self.team)
-           rgb = TeamColor(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);
@@ -1081,11 +1079,11 @@ void vehicles_setreturn()
 void vehicles_reset_colors()
 {
     entity e;
-    float _effects, _colormap;
+    float _effects = 0, _colormap;
     vector _glowmod, _colormod;
 
     if(autocvar_g_nodepthtestplayers)
-        _effects = EF_NODEPTHTEST;
+        _effects |= EF_NODEPTHTEST;
 
     if(autocvar_g_fullbrightplayers)
         _effects |= EF_FULLBRIGHT;
@@ -1193,8 +1191,12 @@ float vehicle_initialize(string  net_name,
                          void() dieproc,
                          void() thinkproc,
                          float  use_csqc,
-                         float _max_health)
+                         float _max_health,
+                         float _max_shield)
 {
+       if(!autocvar_g_vehicles)
+               return FALSE;
+       
     if(self.targetname)
     {
         self.vehicle_controller = find(world, target, self.targetname);
@@ -1217,6 +1219,10 @@ float vehicle_initialize(string  net_name,
         }
     }
     
+    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);
@@ -1253,14 +1259,16 @@ float vehicle_initialize(string  net_name,
     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        = vehicles_damage;
+    self.event_damage        = func_null;
     self.touch               = vehicles_touch;
     self.think               = vehicles_spawn;
     self.nextthink           = time;
@@ -1311,20 +1319,90 @@ float vehicle_initialize(string  net_name,
     return TRUE;
 }
 
-void vehicle_aimturret(entity _vehic, vector _target, entity _turrret, string _tagname, 
+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;
+    vector vtmp, vtag;
     float ftmp;
-    
-    vtmp = vectoangles(normalize(_target - gettaginfo(_turrret, gettagindex(_turrret, _tagname))));
+    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 * sys_frametime;
+    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);    
+    _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, ATTN_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;
+}
+*/