X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fvehicles%2Fvehicles.qc;h=87ceecc0c61fd2688a5a6243fdf34f59d5561798;hb=e332988cce112231a09d8c9c8c88d889a5fbea83;hp=20c74d3a17e24deb0012882c634c9d527d4747d0;hpb=dbdc35464a18f62bf550a20eddac9ec16b0eacee;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc index 20c74d3a1..87ceecc0c 100644 --- a/qcsrc/server/vehicles/vehicles.qc +++ b/qcsrc/server/vehicles/vehicles.qc @@ -2,7 +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; + +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(); @@ -39,6 +46,9 @@ float SendAuxiliaryXhair(entity to, float sf) void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id) { + if (clienttype(own) != CLIENTTYPE_REAL) + return; + entity axh; axh_id = bound(0, axh_id, MAX_AXH); @@ -64,7 +74,7 @@ void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id) // 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) { - msg_entity = own; + msgexntity = own; WriteByte(MSG_ONE, SVC_TEMPENTITY); WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR); @@ -84,18 +94,24 @@ void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id) // End AuxiliaryXhair /** - Notifies the client that he enterd a vehicle, and sends + 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 (clienttype(own) != CLIENTTYPE_REAL) + return; + msg_entity = own; WriteByte(MSG_ONE, SVC_TEMPENTITY); WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP); - WriteByte(MSG_ONE, vehicle_id); + if(vehicle_id != 0) + WriteByte(MSG_ONE, vehicle_id); + else + WriteByte(MSG_ONE, 1 + own.vehicle.vehicle_weapon2mode + HUD_VEHICLE_LAST); } /** vehicles_locktarget @@ -115,6 +131,121 @@ void CSQCVehicleSetup(entity own, float vehicle_id) .float lock_strength; .float lock_time; .float lock_soundtime; +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, float 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, float 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) @@ -132,7 +263,7 @@ void vehicles_locktarget(float incr, float decr, float _lock_time) self.lock_soundtime = time + 0.5; play2(self.owner, "vehicles/locked.wav"); } - + return; } @@ -144,28 +275,30 @@ void vehicles_locktarget(float incr, float decr, float _lock_time) if(trace_ent.deadflag != DEAD_NO) trace_ent = world; - if not (trace_ent.vehicle_flags & VHF_ISVEHICLE || trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET) + if not (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_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) @@ -186,8 +319,8 @@ void vehicles_locktarget(float incr, float decr, float _lock_time) } } -#define VEHICLE_UPDATE_PLAYER(fld,vhname) \ -self.owner.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 +#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); \ @@ -237,8 +370,8 @@ void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, { // Ignore damage from oterh projectiles from my owner (dont mess up volly's) if(inflictor.owner == self.owner) - return; - + return; + self.health -= damage; self.velocity += force; if(self.health < 1) @@ -248,7 +381,6 @@ void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, self.think = self.use; self.nextthink = time; } - } void vehicles_projectile_explode() @@ -274,7 +406,7 @@ 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) + float _cull, float _clianim, entity _owner) { entity proj; @@ -296,7 +428,7 @@ entity vehicles_projectile(string _mzlfx, string _mzlsound, proj.touch = vehicles_projectile_explode; proj.use = vehicles_projectile_explode; proj.owner = self; - proj.realowner = self.owner; + proj.realowner = _owner; proj.think = SUB_Remove; proj.nextthink = time + 30; @@ -339,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; @@ -359,9 +492,12 @@ void vehicles_spawn() 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(); + self.vehicle_spawn(VHSF_NORMAL); } // Better way of determening whats crushable needed! (fl_crushable?) @@ -377,21 +513,21 @@ float vehicles_crushable(entity e) } void vehilces_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 = take = min(_speedfac * wc, _maxpain); + 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"); } @@ -409,14 +545,14 @@ void vehicles_touch() { 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); - + return; // Dont do selfdamage when hitting "soft targets". } - + if(self.play_time < time) if(self.vehicle_impact) self.vehicle_impact(); - + return; } @@ -429,18 +565,18 @@ void vehicles_touch() if(other.vehicle != world) return; - // Remove this when bots know how to use vehicles. - if (clienttype(other) != CLIENTTYPE_REAL) - return; - vehicles_enter(); } - +var float autocvar_g_vehicles_allow_bots = 0; void vehicles_enter() { // Remove this when bots know how to use vehicles - if (clienttype(other) != CLIENTTYPE_REAL) - return; + + if (clienttype(other) == CLIENTTYPE_BOT) + 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; @@ -449,7 +585,7 @@ void vehicles_enter() if(self.team) if(self.team != other.team) return; - + RemoveGrapplingHook(other); self.vehicle_ammo1 = 0; @@ -497,41 +633,34 @@ void vehicles_enter() self.team = self.owner.team; self.flags -= FL_NOTARGET; - - 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 + + if (clienttype(other) == CLIENTTYPE_REAL) { - WriteAngle(MSG_ONE, self.angles_x * -1); // tilt - WriteAngle(MSG_ONE, self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll + 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_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'); - } - } - + MUTATOR_CALLHOOK(VehicleEnter); + self.vehicle_enter(); antilag_clear(other); } @@ -545,17 +674,17 @@ 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 = 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); for(i = 0; i < 100; ++i) - { + { v = randomvec(); v_z = 0; v = v2 + normalize(v) * mysize; @@ -563,13 +692,13 @@ vector vehicles_findgoodexit(vector prefer_spot) 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) @@ -579,13 +708,13 @@ vector vehicles_findgoodexit(vector prefer_spot) 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; } @@ -593,82 +722,108 @@ vector vehicles_findgoodexit(vector prefer_spot) Standarrd vehicle release fucntion. custom code goes in self.vehicle_exit **/ +float vehicles_exit_running; void vehicles_exit(float eject) -{ - entity oldself; +{ + 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(self.flags & FL_CLIENT) { - oldself = self; - self = self.vehicle; + _vehicle = self.vehicle; + + if (_vehicle.vehicle_flags & VHF_PLAYERSLOT) + { + _vehicle.vehicle_exit(eject); + self = _oldself; + vehicles_exit_running = FALSE; + return; + } } + else + _vehicle = self; - self.flags |= FL_NOTARGET; + _player = _vehicle.owner; + + self = _vehicle; - if (self.owner) + if (_player) { - msg_entity = self.owner; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity( MSG_ONE, self.owner); - - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); - WriteAngle(MSG_ONE, 0); // pich - WriteAngle(MSG_ONE, self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll - - setsize(self.owner, PL_MIN,PL_MAX); - - self.owner.takedamage = DAMAGE_AIM; - self.owner.solid = SOLID_SLIDEBOX; - self.owner.movetype = MOVETYPE_WALK; - self.owner.effects &~= EF_NODRAW; - self.owner.alpha = 1; - self.owner.PlayerPhysplug = SUB_Null; - self.owner.vehicle = world; - self.owner.view_ofs = PL_VIEW_OFS; - self.owner.event_damage = PlayerDamage; - self.owner.hud = HUD_NORMAL; - self.owner.switchweapon = self.switchweapon; - //self.owner.BUTTON_USE = 0; + if (clienttype(_player) == CLIENTTYPE_REAL) + { + 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); + } - CSQCVehicleSetup(self.owner, HUD_NORMAL); - } - - if(self.deadflag == DEAD_NO) - self.avelocity = '0 0 0'; - - self.vehicle_hudmodel.viewmodelforclient = self; - self.tur_head.nodrawtoclient = world; - vehicles_setreturn(); - - self.phase = time + 1; + 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 = SUB_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); + } + _vehicle.flags |= FL_NOTARGET; + + if(_vehicle.deadflag == DEAD_NO) + _vehicle.avelocity = '0 0 0'; + + _vehicle.tur_head.nodrawtoclient = world; + if(!teamplay) - self.team = 0; + _vehicle.team = 0; else - self.team = self.tur_head.team; - if(self.owner.flagcarried) - { - self.owner.flagcarried.scale = 0.6; - setattachment(self.owner.flagcarried, self.owner, ""); - setorigin(self.owner.flagcarried, FLAG_CARRY_POS); - } + self.team = self.tur_head.team; + + MUTATOR_CALLHOOK(VehicleExit); - sound (self, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTN_NORM); - self.vehicle_exit(eject); - self.owner = world; - vehicles_reset_colors(); + vehicles_setreturn(); + vehicles_reset_colors(); + _vehicle.owner = world; + self = _oldself; - if(oldself) - self = oldself; + vehicles_exit_running = FALSE; } -void vehicles_regen(.float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time) +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); + self.regen_field = min(self.regen_field + regen * delta_time, field_max); if(self.owner) @@ -683,6 +838,7 @@ void shieldhit_think() { //setmodel(self, ""); self.alpha = -1; + self.effects |= EF_NODRAW; } else { @@ -691,31 +847,48 @@ void shieldhit_think() } void vehicles_painframe() -{ +{ if(self.owner.vehicle_health <= 50) if(self.pain_frame < time) - { - float _ftmp; + { + float _ftmp; _ftmp = self.owner.vehicle_health / 50; self.pain_frame = time + 0.1 + (random() * 0.5 * _ftmp); pointparticles(particleeffectnum("smoke_small"), (self.origin + (randomvec() * 80)), '0 0 0', 1); - + if(self.vehicle_flags & VHF_DMGSHAKE) self.velocity += randomvec() * 30; - + if(self.vehicle_flags & VHF_DMGROLL) if(self.vehicle_flags & VHF_DMGHEADROLL) self.tur_head.angles += randomvec(); else self.angles += randomvec(); - - } + + } } void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) { self.dmg_time = time; + + if(DEATH_ISWEAPON(deathtype, WEP_NEX)) + damage *= autocvar_g_vehicles_nex_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_UZI)) + damage *= autocvar_g_vehicles_uzi_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_RIFLE)) + damage *= autocvar_g_vehicles_rifle_damagerate; + + if(DEATH_ISWEAPON(deathtype, WEP_MINSTANEX)) + damage *= autocvar_g_vehicles_minstanex_damagerate; + if(DEATH_ISWEAPON(deathtype, WEP_SEEKER)) + damage *= autocvar_g_vehicles_tag_damagerate; + + self.enemy = attacker; + if((self.vehicle_flags & VHF_HASSHIELD) && (self.vehicle_shield > 0)) { if (wasfreed(self.vehicle_shieldent) || self.vehicle_shieldent == world) @@ -734,6 +907,7 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat 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; @@ -743,7 +917,7 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat 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, ATTN_NORM); // FIXME: PLACEHOLDER } @@ -759,8 +933,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) { @@ -770,6 +947,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(); } @@ -782,15 +962,15 @@ void vehicles_clearrturn() ret = findchain(classname, "vehicle_return"); while(ret) { - if(ret.enemy == self) + if(ret.wp00 == self) { ret.classname = ""; ret.think = SUB_Remove; - ret.nextthink = time + 0.1; - + ret.nextthink = time + 0.1; + if(ret.waypointsprite_attached) WaypointSprite_Kill(ret.waypointsprite_attached); - + return; } ret = ret.chain; @@ -799,14 +979,14 @@ void vehicles_clearrturn() void vehicles_return() { - pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1); + pointparticles(particleeffectnum("teleport"), self.wp00.origin + '0 0 64', '0 0 0', 1); - self.enemy.think = vehicles_spawn; - self.enemy.nextthink = time; + self.wp00.think = vehicles_spawn; + self.wp00.nextthink = time; if(self.waypointsprite_attached) WaypointSprite_Kill(self.waypointsprite_attached); - + remove(self); } @@ -814,50 +994,50 @@ void vehicles_showwp_goaway() { if(self.waypointsprite_attached) WaypointSprite_Kill(self.waypointsprite_attached); - + remove(self); - + } void vehicles_showwp() { entity oldself; 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.enemy.team; - self.enemy = oldself.enemy; - setorigin(self, oldself.enemy.pos1); - + 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 = TeamColor(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.enemy.team, SPRITERULE_DEFAULT); + { + WaypointSprite_UpdateRule(self.waypointsprite_attached, self.wp00.team, SPRITERULE_DEFAULT); if(oldself == world) - WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink); + WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink); WaypointSprite_Ping(self.waypointsprite_attached); - } - + } + if(oldself != world) self = oldself; } @@ -865,34 +1045,28 @@ void vehicles_showwp() void vehicles_setreturn() { entity ret; - + vehicles_clearrturn(); ret = spawn(); ret.classname = "vehicle_return"; - ret.enemy = self; + ret.wp00 = self; ret.team = self.team; ret.think = vehicles_showwp; - + if(self.deadflag != DEAD_NO) { ret.cnt = time + self.vehicle_respawntime; - ret.nextthink = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 5); - } + ret.nextthink = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 5); + } else { - ret.nextthink = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 1); + ret.nextthink = min(time + self.vehicle_respawntime, time + self.vehicle_respawntime - 1); } - + setmodel(ret, "null"); setorigin(ret, self.pos1 + '0 0 96'); - -} -void vehicles_configcheck(string configname, float check_cvar) -{ - if(check_cvar == 0) - localcmd(strcat("exec ", configname, "\n")); } void vehicles_reset_colors() @@ -940,6 +1114,57 @@ void vehicles_reset_colors() 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 not (_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, @@ -951,24 +1176,55 @@ float vehicle_initialize(string net_name, vector min_s, vector max_s, float nodrop, - void() spawnproc, + void(float _spawnflag) spawnproc, float _respawntime, float() physproc, void() enterproc, void(float extflag) exitfunc, void() dieproc, void() thinkproc, - float use_csqc) + 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_AMMO1, AS_INT, vehicle_ammo1); addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1); - addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); + addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2); if(bodymodel == "") @@ -984,9 +1240,9 @@ float vehicle_initialize(string net_name, if(self.team && !teamplay) self.team = 0; - + self.vehicle_flags |= VHF_ISVEHICLE; - + setmodel(self, bodymodel); self.vehicle_viewport = spawn(); @@ -996,19 +1252,27 @@ 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.touch = vehicles_touch; - self.think = vehicles_spawn; - self.nextthink = time; + self.think = vehicles_spawn; + self.nextthink = time; self.vehicle_respawntime = _respawntime; self.vehicle_spawn = spawnproc; + self.effects = EF_NODRAW; + if(g_assault || !autocvar_g_vehicles_delayspawn) + self.nextthink = time + 0.5; + else + self.nextthink = time + _respawntime + (random() * autocvar_g_vehicles_delayspawn_jitter); + if(autocvar_g_nodepthtestplayers) self.effects = self.effects | EF_NODEPTHTEST; @@ -1019,7 +1283,6 @@ float vehicle_initialize(string net_name, setmodel(self.vehicle_hudmodel, hudmodel); setmodel(self.vehicle_viewport, "null"); - if(topmodel != "") { setmodel(self.tur_head, topmodel); @@ -1041,19 +1304,98 @@ float vehicle_initialize(string net_name, 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; - + return TRUE; } -void bugmenot() +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() { - self.vehicle_exit = self.vehicle_exit; - self.vehicle_enter = self.vehicle_exit; - self.vehicle_die = self.vehicle_exit; - self.vehicle_spawn = self.vehicle_exit; - self.AuxiliaryXhair = self.AuxiliaryXhair; + 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; +} +*/