X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fvehicles%2Fvehicles.qc;h=c2d8b7709269ccc08e5ad418ec439ffe643c7e6b;hb=bf83d4469f1ac84d58e7ebae155274c4686eefea;hp=7bbf7fe26ea3f47ea4be7c923a3ec797800b2c3f;hpb=b41f7ee415c9cc35d6304ca237986a9e445ffd4c;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc index 7bbf7fe26..1b1ae3f64 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); @@ -91,11 +101,17 @@ void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id) **/ 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) @@ -144,7 +275,9 @@ 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; } @@ -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); \ @@ -244,11 +377,10 @@ 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; } - } void vehicles_projectile_explode() @@ -264,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); @@ -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?) @@ -408,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". } @@ -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; @@ -474,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) @@ -497,40 +633,37 @@ 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'); - } - } + + vh_player = other; + vh_vehicle = self; + MUTATOR_CALLHOOK(VehicleEnter); + other = vh_player; + self = vh_vehicle; self.vehicle_enter(); antilag_clear(other); @@ -550,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); @@ -593,82 +726,111 @@ 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; - if(self.flags & FL_CLIENT) + entity _vehicle; + entity _player; + entity _oldself = self; + + if(vehicles_exit_running) { - oldself = self; - self = self.vehicle; + dprint("^1vehicles_exit allready running! this is not good..\n"); + return; } - - self.flags |= FL_NOTARGET; - - if (self.owner) + + vehicles_exit_running = TRUE; + if(self.flags & FL_CLIENT) { - 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; - - CSQCVehicleSetup(self.owner, HUD_NORMAL); + _vehicle = self.vehicle; + + if (_vehicle.vehicle_flags & VHF_PLAYERSLOT) + { + _vehicle.vehicle_exit(eject); + self = _oldself; + vehicles_exit_running = FALSE; + return; + } } - - 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; - - if(!teamplay) - self.team = 0; else - self.team = self.tur_head.team; + _vehicle = self; + + _player = _vehicle.owner; + + self = _vehicle; - if(self.owner.flagcarried) + if (_player) { - self.owner.flagcarried.scale = 0.6; - setattachment(self.owner.flagcarried, self.owner, ""); - setorigin(self.owner.flagcarried, FLAG_CARRY_POS); + 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); + } + + 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; + else - sound (self, CH_TRIGGER_SINGLE, "misc/null.wav", 1, ATTN_NORM); - self.vehicle_exit(eject); - self.owner = world; - vehicles_reset_colors(); - - if(oldself) - self = oldself; + 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; + _vehicle.phase = time + 1; + + _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) +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 +845,7 @@ void shieldhit_think() { //setmodel(self, ""); self.alpha = -1; + self.effects |= EF_NODRAW; } else { @@ -715,7 +878,24 @@ void vehicles_painframe() 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 +914,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; @@ -759,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) { @@ -770,6 +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(); } @@ -782,7 +969,7 @@ void vehicles_clearrturn() ret = findchain(classname, "vehicle_return"); while(ret) { - if(ret.enemy == self) + if(ret.wp00 == self) { ret.classname = ""; ret.think = SUB_Remove; @@ -799,10 +986,10 @@ 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); @@ -821,7 +1008,7 @@ void vehicles_showwp_goaway() void vehicles_showwp() { - entity oldself; + entity oldself = world; vector rgb; if(self.cnt) @@ -837,22 +1024,22 @@ void vehicles_showwp() 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); + 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.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_Ping(self.waypointsprite_attached); @@ -870,7 +1057,7 @@ void vehicles_setreturn() ret = spawn(); ret.classname = "vehicle_return"; - ret.enemy = self; + ret.wp00 = self; ret.team = self.team; ret.think = vehicles_showwp; @@ -889,20 +1076,14 @@ void vehicles_setreturn() } -void vehicles_configcheck(string configname, float check_cvar) -{ - if(check_cvar == 0) - localcmd(strcat("exec ", configname, "\n")); -} - 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; @@ -940,6 +1121,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 +1183,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 == "") @@ -996,19 +1259,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.event_damage = func_null; self.touch = vehicles_touch; self.think = vehicles_spawn; self.nextthink = time; self.vehicle_respawntime = _respawntime; self.vehicle_spawn = spawnproc; + self.effects = EF_NODRAW; + if(!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 +1290,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 +1311,101 @@ 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; + + if(MUTATOR_CALLHOOK(VehicleSpawn)) + return FALSE; 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) { - 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; + 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, 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; +} +*/