X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fvehicles%2Fvehicles.qc;h=e23cc702cc706cdb912cf0e6602d0c5ce351aa82;hb=233bf6ea697790944da89272cd06af796052ff22;hp=39c50a924c6438839e3403dbd8227bfc1d067558;hpb=97ee6130a24f5452a61eec2310bd14f8390ceb4f;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/vehicles/vehicles.qc b/qcsrc/server/vehicles/vehicles.qc index 39c50a924..e23cc702c 100644 --- a/qcsrc/server/vehicles/vehicles.qc +++ b/qcsrc/server/vehicles/vehicles.qc @@ -2,13 +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; +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(); @@ -73,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); @@ -318,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); \ @@ -376,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; } @@ -395,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); @@ -405,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; @@ -427,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; @@ -470,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; @@ -490,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?) @@ -539,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". } @@ -605,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) @@ -634,7 +639,7 @@ void vehicles_enter() msg_entity = other; WriteByte (MSG_ONE, SVC_SETVIEWPORT); WriteEntity(MSG_ONE, self.vehicle_viewport); - + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); if(self.tur_head) { @@ -653,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); @@ -684,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); @@ -727,85 +726,107 @@ 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; + + _player = _vehicle.owner; + + self = _vehicle; - self.flags |= FL_NOTARGET; - - if (self.owner) + if (_player) { - if (clienttype(self.owner) == CLIENTTYPE_REAL) + if (clienttype(_player) == CLIENTTYPE_REAL) { - msg_entity = self.owner; + msg_entity = _player; WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity( MSG_ONE, self.owner); + WriteEntity( MSG_ONE, _player); WriteByte (MSG_ONE, SVC_SETVIEWANGLES); - WriteAngle(MSG_ONE, 0); // pich - WriteAngle(MSG_ONE, self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll + WriteAngle(MSG_ONE, 0); + WriteAngle(MSG_ONE, _vehicle.angles_y); + WriteAngle(MSG_ONE, 0); } - 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(self.owner.flagcarried) - { - self.owner.flagcarried.scale = 0.6; - setattachment(self.owner.flagcarried, self.owner, ""); - setorigin(self.owner.flagcarried, FLAG_CARRY_POS); - } - - CSQCVehicleSetup(self.owner, HUD_NORMAL); + 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); } - - 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; - + _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; + vh_player = _player; + vh_vehicle = _vehicle; + MUTATOR_CALLHOOK(VehicleExit); + _player = vh_player; + _vehicle = vh_vehicle; - 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; + _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, 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); @@ -824,6 +845,7 @@ void shieldhit_think() { //setmodel(self, ""); self.alpha = -1; + self.effects |= EF_NODRAW; } else { @@ -868,6 +890,9 @@ void vehicles_damage(entity inflictor, entity attacker, float damage, float deat 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; @@ -889,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; @@ -914,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) { @@ -925,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(); } @@ -976,7 +1008,7 @@ void vehicles_showwp_goaway() void vehicles_showwp() { - entity oldself; + entity oldself = world; vector rgb; if(self.cnt) @@ -1001,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); @@ -1044,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; @@ -1095,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, @@ -1106,7 +1183,7 @@ 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, @@ -1114,17 +1191,47 @@ 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); + 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 == "") @@ -1152,9 +1259,11 @@ 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; @@ -1165,6 +1274,12 @@ float vehicle_initialize(string net_name, 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; @@ -1175,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); @@ -1197,7 +1311,7 @@ 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; @@ -1205,30 +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 bugmenot() +void vehicles_gib_think() { - 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; + 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; +} +*/