From: Jakob MG Date: Sun, 12 Jun 2011 15:31:02 +0000 (+0200) Subject: Merge remote branch 'origin/master' into tzork/vehicles-2 X-Git-Tag: xonotic-v0.5.0~199^2~11^2~22 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=3cd77e9863d3c7622c1d31d1b5c3686593ff09c8;p=xonotic%2Fxonotic-data.pk3dir.git Merge remote branch 'origin/master' into tzork/vehicles-2 Conflicts: qcsrc/server/vehicles/raptor.qc qcsrc/server/vehicles/spiderbot.qc --- 3cd77e9863d3c7622c1d31d1b5c3686593ff09c8 diff --cc qcsrc/server/vehicles/raptor.qc index 6d1206618,6ed8ca815..7a390e8ff --- a/qcsrc/server/vehicles/raptor.qc +++ b/qcsrc/server/vehicles/raptor.qc @@@ -144,84 -184,169 +144,85 @@@ void raptor_bombdrop( setorigin(bomb_1, gettaginfo(self, gettagindex(self, "bombmount_left"))); setorigin(bomb_2, gettaginfo(self, gettagindex(self, "bombmount_right"))); - bomb_1.movetype = bomb_2.movetype = MOVETYPE_TOSS; - bomb_1.velocity = bomb_2.velocity = self.velocity; - bomb_1.touch = bomb_2.touch = raptor_bomb_touch; - bomb_1.think = bomb_2.think = raptor_bomb_burst; - bomb_1.nextthink = bomb_2.nextthink = time; - bomb_1.cnt = bomb_2.cnt = time + raptor_bomblet_wavefirst; - bomb_1.wait = bomb_2.wait = raptor_bomblet_waves; - - bomb_1.avelocity = bomb_2.avelocity = '0 0 180'; - bomb_1.owner = bomb_2.owner = self; - bomb_1.enemy = bomb_2.enemy = self.owner; - bomb_1.angles = bomb_2.angles = self.angles; + bomb_1.movetype = bomb_2.movetype = MOVETYPE_BOUNCE; + bomb_1.velocity = bomb_2.velocity = self.velocity; + bomb_1.touch = bomb_2.touch = raptor_bomb_touch; + bomb_1.think = bomb_2.think = raptor_bomb_burst; + bomb_1.cnt = bomb_2.cnt = time + 10; + + if(autocvar_g_vehicle_raptor_bomblet_alt) + bomb_1.nextthink = bomb_2.nextthink = time; + else + bomb_1.nextthink = bomb_2.nextthink = time + autocvar_g_vehicle_raptor_bomblet_time; + + bomb_1.owner = bomb_2.owner = self; + bomb_1.realowner = bomb_2.realowner = self.owner; bomb_1.solid = bomb_2.solid = SOLID_BBOX; + bomb_1.gravity = bomb_2.gravity = 1; + + PROJECTILE_MAKETRIGGER(bomb_1); + PROJECTILE_MAKETRIGGER(bomb_2); + + CSQCProjectile(bomb_1, TRUE, PROJECTILE_RAPTORBOMB, TRUE); + CSQCProjectile(bomb_2, TRUE, PROJECTILE_RAPTORBOMB, TRUE); - bomb_1 = spawn(); - bomb_1.owner = self; - bomb_1.think = raptor_bombs_return; - bomb_1.nextthink = time + raptor_bombs_refire; } -void raptor_animator_think() + +void raptor_fire_cannon(entity gun, string tagname) { - self.owner.frame += 1; - if(self.owner.frame == self.cnt) - remove(self); - else - self.nextthink = time + self.wait; + entity bolt; + vector b_org; + b_org = gettaginfo(gun, gettagindex(gun, tagname)); + bolt = vehicles_projectile("raptor_cannon_muzzleflash", "weapons/lasergun_fire.wav", + b_org, normalize(v_forward + randomvec() * autocvar_g_vehicle_raptor_cannon_spread) * autocvar_g_vehicle_raptor_cannon_speed, + autocvar_g_vehicle_raptor_cannon_damage, autocvar_g_vehicle_raptor_cannon_radius, autocvar_g_vehicle_raptor_cannon_force, 0, + DEATH_RAPTOR_CANNON, PROJECTILE_RAPTORCANNON, 0, TRUE, TRUE); } -void raptor_setanim(float start, float end, float length) +void raptor_think() { - entity ani; - if(self.tur_head.enemy) - ani = self.tur_head.enemy; - else - ani = spawn(); - - self.tur_head.enemy = ani; - ani.owner = self; - self.frame = start; - ani.cnt = end; - ani.wait = sys_frametime / length; - ani.think = raptor_animator_think; - ani.nextthink = time + ani.wait; } -void raptor_beam (vector start, vector end, vector smin, vector smax, float bforce, float f_dmg, float deathtype) +void raptor_enter() { - vector hitloc, force, endpoint, dir; - entity ent; + self.owner.PlayerPhysplug = raptor_takeoff; + self.movetype = MOVETYPE_BOUNCEMISSILE; + self.solid = SOLID_SLIDEBOX; + self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_raptor_health); + self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_raptor_shield); + self.velocity_z = 1; // Nudge upwards to takeoff sequense can work. + self.tur_head.exteriormodeltoclient = self.owner; - dir = normalize(end - start); - force = dir * bforce; + self.delay = time + autocvar_g_vehicle_raptor_bombs_refire; + self.lip = time; - // go a little bit into the wall because we need to hit this wall later - end = end + dir; - - // trace multiple times until we hit a wall, each obstacle will be made unsolid. - // note down which entities were hit so we can damage them later - while (1) - { - tracebox(start, smin, smax, end, FALSE, world); - - // if it is world we can't hurt it so stop now - if (trace_ent == world || trace_fraction == 1) - break; - - if (trace_ent.solid == SOLID_BSP) - break; - - // make the entity non-solid so we can hit the next one - trace_ent.railgunhit = TRUE; - trace_ent.railgunhitloc = end; - trace_ent.railgunhitsolidbackup = trace_ent.solid; - - // make the entity non-solid - trace_ent.solid = SOLID_NOT; - } - - endpoint = trace_endpos; - - // find all the entities the railgun hit and hurt them - ent = findchainfloat(railgunhit, TRUE); - while (ent) - { - // get the details we need to call the damage function - ent.solid = ent.railgunhitsolidbackup; - hitloc = ent.railgunhitloc; - ent.railgunhitloc = '0 0 0'; - ent.railgunhitsolidbackup = SOLID_NOT; - ent.railgunhit = FALSE; - - // apply the damage - if (ent.takedamage) - Damage (ent, self, self, f_dmg, deathtype, hitloc, force); - - ent = ent.chain; - } - trace_endpos = endpoint; } - -void raptor_enter() +void raptor_land() { - float hgt; - // Remove this when bots know how to use vehicles - if (clienttype(other) != CLIENTTYPE_REAL) - return; - - if(teamplay) - if(self.team) - if(self.team != other.team) - return; - - self.owner = other; - self.switchweapon = other.switchweapon; - - self.event_damage = vehicle_stdproc_damage; - self.colormap = self.owner.colormap; - self.vehicle_hudmodel.viewmodelforclient = self.owner; - self.nextthink = 0; - self.owner.angles = self.angles; - self.owner.takedamage = DAMAGE_NO; - self.owner.solid = SOLID_NOT; - self.owner.movetype = MOVETYPE_NOCLIP; - self.owner.alpha = -1; - self.owner.PlayerPhysplug = raptor_takeoff; - self.owner.vehicle = self; - self.owner.event_damage = SUB_Null; - self.owner.hud = HUD_RAPTOR; - self.owner.vehicle_health = self.vehicle_health / raptor_health_max; - self.owner.vehicle_shield = self.vehicle_shield / raptor_shield_max; - self.owner.view_ofs = '0 0 1'; - self.owner.vehicle_ammo1 = self.vehicle_ammo1; - self.owner.vehicle_ammo2 = self.vehicle_ammo2; - self.owner.vehicle_reload1 = self.vehicle_reload1; - self.owner.vehicle_reload2 = self.vehicle_reload2; - - other.flags &~= FL_ONGROUND; - self.flags &~= FL_ONGROUND; - - self.frame = 0; - raptor_setanim(0, 25, 1); - self.team = self.owner.team; - self.flags -= FL_NOTARGET; ++ float hgt; ++ + hgt = raptor_altitude(512); + self.velocity = (self.velocity * 0.9) + ('0 0 -1800' * (hgt / 256) * sys_frametime); + self.angles_x *= 0.95; + self.angles_z *= 0.95; - self.velocity = '0 0 1'; + if(hgt < 128) + if(self.frame != 0) + self.frame = max(self.frame - 0.25, 0); - setorigin(other,self.origin + '0 0 32'); - other.velocity = self.velocity; + self.bomb1.gun1.avelocity_y = 90 + ((self.frame / 25) * 2000); + self.bomb1.gun2.avelocity_y = -self.bomb1.gun1.avelocity_y; - other.flags &~= FL_ONGROUND; - msg_entity = other; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity( MSG_ONE, self.vehicle_viewport); + if(hgt < 16) + { + self.movetype = MOVETYPE_TOSS; + self.think = raptor_think; + } - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES - WriteAngle(MSG_ONE, self.angles_x * -1); // tilt - WriteAngle(MSG_ONE, self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll + self.nextthink = time; } void raptor_exit(float eject) diff --cc qcsrc/server/vehicles/spiderbot.qc index 0f217f998,08b945991..3edf015e0 --- a/qcsrc/server/vehicles/spiderbot.qc +++ b/qcsrc/server/vehicles/spiderbot.qc @@@ -416,9 -424,62 +416,11 @@@ void spiderbot_think( void spiderbot_enter() { - // Remove this when bots know how to use the spiderbot - if (clienttype(other) != CLIENTTYPE_REAL) - return; - - self.colormod = self.tur_head.colormod = '0 0 0'; + - if(teamplay) - if(self.team) - if(self.team != other.team) - return; + self.movetype = MOVETYPE_WALK; + - self.owner = other; - self.switchweapon = other.switchweapon; - - self.event_damage = vehicle_stdproc_damage ; - self.colormap = self.owner.colormap; - self.tur_head.colormap = self.owner.colormap; - self.vehicle_hudmodel.viewmodelforclient = self.owner; - self.nextthink = 0; - self.owner.angles = self.angles; - self.owner.takedamage = DAMAGE_NO; - self.owner.solid = SOLID_NOT; - self.owner.movetype = MOVETYPE_NOCLIP; - self.owner.alpha = -1; - self.owner.PlayerPhysplug = spiderbot_pplug; - self.owner.vehicle = self; - self.owner.event_damage = SUB_Null; - self.owner.hud = HUD_SPIDERBOT; self.owner.vehicle_health = (self.vehicle_health / autocvar_g_vehicle_spiderbot_health); self.owner.vehicle_shield = (self.vehicle_shield / autocvar_g_vehicle_spiderbot_shield); - self.owner.view_ofs = '0 0 0'; - self.owner.vehicle_ammo1 = self.vehicle_ammo1; - self.owner.vehicle_ammo2 = self.vehicle_ammo2; - self.owner.vehicle_reload1 = self.vehicle_reload1; - self.owner.vehicle_reload2 = self.vehicle_reload2; - - //if(other.flags & FL_ONGROUND) - other.flags &~= FL_ONGROUND; - - //if(self.flags & FL_ONGROUND) - self.flags &~= FL_ONGROUND; - - self.team = self.owner.team; - self.flags -= FL_NOTARGET; - - if(clienttype(other) == CLIENTTYPE_REAL) - { - msg_entity = other; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity(MSG_ONE, self.vehicle_viewport); - - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES - 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 - } } void spiderbot_exit(float eject) @@@ -437,14 -500,53 +439,14 @@@ e = e.chain; } - self.owner.switchweapon = self.switchweapon; - - self.velocity = '0 0 0'; - if(clienttype(self.owner) == CLIENTTYPE_REAL) - { - msg_entity = self.owner; - WriteByte (MSG_ONE, SVC_SETVIEWPORT); - WriteEntity( MSG_ONE, self.owner); - - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); // 10 = SVC_SETVIEWANGLES - WriteAngle(MSG_ONE, 0); // tilt - WriteAngle(MSG_ONE, self.angles_y); // yaw - WriteAngle(MSG_ONE, 0); // roll - } - - self.think = spiderbot_think; - self.nextthink = time; - self.owner.takedamage = DAMAGE_AIM; - self.owner.solid = SOLID_SLIDEBOX; - self.owner.movetype = MOVETYPE_WALK; - - setsize(self.owner,PL_MIN,PL_MAX); - - self.owner.alpha = 1; - self.owner.PlayerPhysplug = SUB_Null; - self.owner.vehicle = world; - self.owner.view_ofs = PL_VIEW_OFS; - self.owner.hud = HUD_NORMAL; - self.owner.event_damage = PlayerDamage; - - self.colormap = 1024; - self.tur_head.colormap = 1024; - - if not (teamplay) - self.team = 0; - else - { - self.team = self.spiderbot_spawnpnt.team ; - if (self.team == COLOR_TEAM1) self.colormod = '1.4 0.8 0.8'; - if (self.team == COLOR_TEAM2) self.colormod = '0.8 0.8 1.4'; - self.tur_head.colormod = self.colormod; - } - - self.vehicle_hudmodel.viewmodelforclient = self; - self.tur_head.nodrawtoclient = self; - - setattachment(self.owner,world,""); + self.velocity = '0 0 0'; + self.think = spiderbot_think; + self.nextthink = time; + self.frame = 5; + self.movetype = MOVETYPE_WALK; - ++ + if not (self.owner) + return; makevectors(self.angles); if(eject) @@@ -593,30 -689,50 +595,31 @@@ void spiderbot_die( void vewhicle_spiderbot_dinit() { + if not (vehicle_initialize( + "Spiderbot", + "models/vehicles/spiderbot.dpm", + "models/vehicles/spiderbot_top.dpm", + "models/vehicles/spiderbot_cockpit.dpm", + "tag_head", "tag_hud", "", + HUD_SPIDERBOT, + SPIDERBOT_MIN, SPIDERBOT_MAX, + FALSE, + spiderbot_spawn, autocvar_g_vehicle_spiderbot_respawntime, + spiderbot_frame, + spiderbot_enter, spiderbot_exit, + spiderbot_die, spiderbot_think, + FALSE)) + { + remove(self); + return; + } - self.spiderbot_spawnpnt = spawn(); - self.spiderbot_spawnpnt.angles = self.angles; - - setorigin(self,self.origin); - tracebox(self.origin + '0 0 100', spiderbot_MIN, spiderbot_MAX, self.origin - '0 0 10000', MOVE_WORLDONLY, self); - setorigin(self.spiderbot_spawnpnt,trace_endpos); - - if(self.team && !teamplay) - self.team = 0; - else - self.spiderbot_spawnpnt.team = self.team; - - addstat(STAT_HUD, AS_INT, hud); - addstat(STAT_VEHICLESTAT_HEALTH, AS_FLOAT, vehicle_health); - addstat(STAT_VEHICLESTAT_SHIELD, AS_FLOAT, vehicle_shield); - addstat(STAT_VEHICLESTAT_ENERGY, AS_FLOAT, vehicle_energy); - addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1); - addstat(STAT_VEHICLESTAT_RELOAD1, AS_FLOAT, vehicle_reload1); - addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); - addstat(STAT_VEHICLESTAT_RELOAD2, AS_FLOAT, vehicle_reload2); - - if (self.netname == "") - self.netname = "spiderbot"; + - self.tur_head = spawn(); self.gun1 = spawn(); self.gun2 = spawn(); - self.vehicle_viewport = spawn(); - self.vehicle_hudmodel = spawn(); - self.vehicle_flags = VHF_HASSHIELD | VHF_SHIELDREGEN | VHF_HEALTHREGEN | VHF_DEATHEJECT; - self.cvar_basename = "g_vehicle_spiderbot"; - self.gravity = 2; - setmodel(self, "models/vehicles/spiderbot.dpm"); - setmodel(self.tur_head, "models/vehicles/spiderbot_top.dpm"); setmodel(self.gun1, "models/vehicles/spiderbot_barrels.dpm"); setmodel(self.gun2, "models/vehicles/spiderbot_barrels.dpm"); - setmodel(self.vehicle_hudmodel, "models/vehicles/spiderbot_cockpit.dpm"); - setmodel(self.vehicle_viewport, "null"); - - setattachment(self.tur_head, self, "tag_head"); - setattachment(self.vehicle_hudmodel, self.tur_head, "tag_hud"); - setattachment(self.vehicle_viewport, self.vehicle_hudmodel, ""); setattachment(self.gun1, self.tur_head, "tag_hardpoint01"); setattachment(self.gun2, self.tur_head, "tag_hardpoint02"); diff --cc qcsrc/server/vehicles/vehicles.qc index 7400dc142,7cc2949f6..0181e92d1 --- a/qcsrc/server/vehicles/vehicles.qc +++ b/qcsrc/server/vehicles/vehicles.qc @@@ -1,620 -1,44 +1,620 @@@ -void vehicle_stdproc_enter() +float autocvar_g_vehicles_crush_dmg; +float autocvar_g_vehicles_crush_force; +float autocvar_g_vehicles_delayspawn; +float autocvar_g_vehicles_delayspawn_jitter; + +void vehicles_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force); +void vehicles_return(); +void vehicles_enter(); +void vehicles_touch(); +void vehicles_reset_colors(); +void vehicles_clearrturn(); +void vehicles_setreturn(); + + +/** AuxiliaryXhair* + Send additional points of interest to be drawn, to vehicle owner +**/ +float MAX_AXH = 4; +.entity AuxiliaryXhair[MAX_AXH]; + +float SendAuxiliaryXhair(entity to, float sf) { + + WriteByte(MSG_ENTITY, ENT_CLIENT_AUXILIARYXHAIR); + + WriteByte(MSG_ENTITY, self.cnt); + + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + + WriteByte(MSG_ENTITY, rint(self.colormod_x * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod_y * 255)); + WriteByte(MSG_ENTITY, rint(self.colormod_z * 255)); + + return TRUE; } -void vehicle_stdproc_exit(float eject) +void UpdateAuxiliaryXhair(entity own, vector loc, vector clr, float axh_id) { + entity axh; + + axh_id = bound(0, axh_id, MAX_AXH); + axh = own.AuxiliaryXhair[axh_id]; + + if(axh == world || wasfreed(axh)) // MADNESS? THIS IS QQQQCCCCCCCCC (wasfreed, why do you exsist?) + { + axh = spawn(); + axh.cnt = axh_id; + axh.drawonlytoclient = own; + axh.owner = own; + Net_LinkEntity(axh, FALSE, 0, SendAuxiliaryXhair); + } + + setorigin(axh, loc); + axh.colormod = clr; + axh.SendFlags = 0x01; + own.AuxiliaryXhair[axh_id] = axh; } -void vehicle_stdproc_shiledregen(float rmax, float dt) +/* +// SVC_TEMPENTITY based, horrible with even 50 ping. hm. +// WriteByte(MSG_ONE, SVC_TEMPENTITY) uses reliable messagess, never use for thinsg that need continous updates. +void SendAuxiliaryXhair2(entity own, vector loc, vector clr, float axh_id) { - if(self.vehicle_shield < rmax) - if(self.dmg_time + CCVAR("_shield_regen_dmgpause") < time) + msg_entity = own; + + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_AUXILIARYXHAIR); + + WriteByte(MSG_ONE, axh_id); + + WriteCoord(MSG_ONE, loc_x); + WriteCoord(MSG_ONE, loc_y); + WriteCoord(MSG_ONE, loc_z); + + WriteByte(MSG_ONE, rint(clr_x * 255)); + WriteByte(MSG_ONE, rint(clr_y * 255)); + WriteByte(MSG_ONE, rint(clr_z * 255)); + +} +*/ +// End AuxiliaryXhair + +/** + Notifies the client that he enterd a vehicle, and sends + realavent data. + + only sends vehicle_id atm (wich is a HUD_* constant, ex. HUD_SPIDERBOT) +**/ +void CSQCVehicleSetup(entity own, float vehicle_id) +{ + msg_entity = own; + + WriteByte(MSG_ONE, SVC_TEMPENTITY); + WriteByte(MSG_ONE, TE_CSQC_VEHICLESETUP); + WriteByte(MSG_ONE, vehicle_id); +} + +/** vehicles_locktarget + + Generic target locking. + + Figure out if what target is "locked" (if any), for missile tracking as such. + + after calling, "if(self.lock_target != world && self.lock_strength == 1)" mean + you have a locked in target. + + Exspects a crosshair_trace() or equivalent to be + dont before calling. + +**/ +.entity lock_target; +.float lock_strength; +.float lock_time; +.float lock_soundtime; +void vehicles_locktarget(float incr, float decr, float _lock_time) +{ + if(self.lock_target && self.lock_target.deadflag != DEAD_NO) { - self.vehicle_shield = min(self.vehicle_shield + CCVAR("_shield_regen") * dt, rmax); + self.lock_target = world; + self.lock_strength = 0; + self.lock_time = 0; + } - if(self.owner) - self.owner.vehicle_shield = self.vehicle_shield / rmax; + if(self.lock_time > time) + { + if(self.lock_target) + if(self.lock_soundtime < time) + { + self.lock_soundtime = time + 0.5; + play2(self.owner, "vehicles/locked.wav"); + } + + return; + } + + if(trace_ent != world) + { - if(teams_matter && trace_ent.team == self.team) ++ if(teamplay && trace_ent.team == self.team) + trace_ent = world; + + if(trace_ent.deadflag != DEAD_NO) + trace_ent = world; + + if not (trace_ent.vehicle_flags & VHF_ISVEHICLE || trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET) + trace_ent = world; + } + + if(self.lock_target == world && trace_ent != world) + self.lock_target = trace_ent; + + if(self.lock_target && trace_ent == self.lock_target) + { + if(self.lock_strength != 1 && self.lock_strength + incr >= 1) + { + play2(self.owner, "vehicles/lock.wav"); + self.lock_soundtime = time + 0.8; + } + else if (self.lock_strength != 1 && self.lock_soundtime < time) + { + play2(self.owner, "vehicles/locking.wav"); + self.lock_soundtime = time + 0.3; + } + + } + + // Have a locking target + // Trace hit current target + if(trace_ent == self.lock_target && trace_ent != world) + { + self.lock_strength = min(self.lock_strength + incr, 1); + if(self.lock_strength == 1) + self.lock_time = time + _lock_time; } + else + { + if(trace_ent) + self.lock_strength = max(self.lock_strength - decr * 2, 0); + else + self.lock_strength = max(self.lock_strength - decr, 0); + + if(self.lock_strength == 0) + self.lock_target = world; + } +} + +#define VEHICLE_UPDATE_PLAYER(fld,vhname) \ +self.owner.vehicle_##fld = (self.vehicle_##fld / autocvar_g_vehicle_##vhname##_##fld) * 100 + +#define vehicles_sweap_collision(orig,vel,dt,acm,mult) \ +traceline(orig, orig + vel * dt, MOVE_NORMAL, self); \ +if(trace_fraction != 1) \ + acm += normalize(self.origin - trace_endpos) * (vlen(vel) * mult) + +// Hover movement support +float force_fromtag_power; +float force_fromtag_normpower; +vector force_fromtag_origin; +vector vehicles_force_fromtag_hover(string tag_name, float spring_length, float max_power) +{ + force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name)); + v_forward = normalize(v_forward) * -1; + traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self); + + force_fromtag_power = (1 - trace_fraction) * max_power; + force_fromtag_normpower = force_fromtag_power / max_power; + + return v_forward * force_fromtag_power; } -void vehicle_stdproc_healthregen(float rmax, float dt) +// Experimental hovermode wich uses attraction/repulstion from surface insted of gravity/repulsion +// Can possibly be use to move abt any surface (inclusing walls/celings) +vector vehicles_force_fromtag_maglev(string tag_name, float spring_length, float max_power) { - if(self.dmg_time + CCVAR("_health_regen_dmgpause") < time) - if(self.vehicle_health < rmax) + force_fromtag_origin = gettaginfo(self, gettagindex(self, tag_name)); + v_forward = normalize(v_forward) * -1; + traceline(force_fromtag_origin, force_fromtag_origin - (v_forward * spring_length), MOVE_NORMAL, self); + + // TODO - this may NOT be compatible with wall/celing movement, unhardcode 0.25 (engine count multiplier) + if(trace_fraction == 1.0) { - self.vehicle_health = min(self.vehicle_health + CCVAR("_health_regen") * dt, rmax); + force_fromtag_normpower = -0.25; + return '0 0 -200'; + } - if(self.owner) - self.owner.vehicle_health = self.vehicle_health / rmax; + force_fromtag_power = ((1 - trace_fraction) - trace_fraction) * max_power; + force_fromtag_normpower = force_fromtag_power / max_power; + + return v_forward * force_fromtag_power; +} + +// Generic vehile projectile system +void vehicles_projectile_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) +{ + // Ignore damage from oterh projectiles from my owner (dont mess up volly's) + if(inflictor.owner == self.owner) + return; + + self.health -= damage; + self.velocity += force; + if(self.health < 1) + { + self.takedamage = DAMAGE_NO; + self.event_damage = SUB_Null; + self.think = self.use; + self.nextthink = time; } + } -void vehicle_stdproc_energyregen(float rmax, float dt) +void vehicles_projectile_explode() { - if(self.vehicle_energy < rmax) + if(self.owner && other != world) + { + if(other == self.owner.vehicle) + return; + + if(other == self.owner.vehicle.tur_head) + return; + } + + PROJECTILE_TOUCH; + + self.event_damage = SUB_Null; + RadiusDamage (self, self.realowner, self.shot_dmg, 0, self.shot_radius, self, self.shot_force, self.totalfrags, other); + + remove (self); +} + +entity vehicles_projectile(string _mzlfx, string _mzlsound, + vector _org, vector _vel, + float _dmg, float _radi, float _force, float _size, + float _deahtype, float _projtype, float _health, + float _cull, float _clianim) +{ + entity proj; + + proj = spawn(); + + PROJECTILE_MAKETRIGGER(proj); + setorigin(proj, _org); + + proj.shot_dmg = _dmg; + proj.shot_radius = _radi; + proj.shot_force = _force; + proj.totalfrags = _deahtype; + proj.solid = SOLID_BBOX; + proj.movetype = MOVETYPE_FLYMISSILE; + proj.flags = FL_PROJECTILE; + proj.bot_dodge = TRUE; + proj.bot_dodgerating = _dmg; + proj.velocity = _vel; + proj.touch = vehicles_projectile_explode; + proj.use = vehicles_projectile_explode; + proj.owner = self; + proj.realowner = self.owner; + proj.think = SUB_Remove; + proj.nextthink = time + 30; + + if(_health) { - self.vehicle_energy = min(self.vehicle_energy + CCVAR("_energy_regen") * dt, rmax); + proj.takedamage = DAMAGE_AIM; + proj.event_damage = vehicles_projectile_damage; + proj.health = _health; + } + else + proj.flags = FL_PROJECTILE | FL_NOTARGET; + + if(_mzlsound) + sound (self, CHAN_WEAPON, _mzlsound, VOL_BASE, ATTN_NORM); + + if(_mzlfx) + pointparticles(particleeffectnum(_mzlfx), proj.origin, proj.velocity, 1); + + + setsize (proj, '-1 -1 -1' * _size, '1 1 1' * _size); + + CSQCProjectile(proj, _clianim, _projtype, _cull); + + return proj; +} +// End generic vehile projectile system + +/** vehicles_spawn + Exetuted for all vehicles on (re)spawn. + Sets defaults for newly spawned units. +**/ +void vehicles_spawn() +{ + dprint("Spawning vehicle: ", self.netname, "\n"); + + // De-own & reset + self.vehicle_hudmodel.viewmodelforclient = self; + + self.owner = world; + self.touch = vehicles_touch; + self.event_damage = vehicles_damage; + self.iscreature = TRUE; + self.movetype = MOVETYPE_WALK; + self.solid = SOLID_SLIDEBOX; + self.takedamage = DAMAGE_AIM; + self.deadflag = DEAD_NO; + self.bot_attack = TRUE; + self.flags = FL_NOTARGET; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + + // Reset locking + self.lock_strength = 0; + self.lock_target = world; + self.misc_bulletcounter = 0; + + // Return to spawn + self.angles = self.pos2; + setorigin(self, self.pos1 + '0 0 128'); + // Show it + pointparticles(particleeffectnum("teleport"), self.origin + '0 0 64', '0 0 0', 1); + + vehicles_reset_colors(); + self.vehicle_spawn(); +} + +// Better way of determening whats crushable needed! (fl_crushable?) +float vehicles_crushable(entity e) +{ + if(e.classname == "player") + return TRUE; + + if(e.classname == "monster_zombie") + return TRUE; + + return FALSE; +} + +void vehicles_touch() +{ + // Vehicle currently in use + if(self.owner) + { + // Colided with world? + if(other == world) + { + // Apply velocity based self damage here + } + else + { + if(other.vehicle_flags & VHF_ISVEHICLE) + { + //other.velocity += self.velocity * (self.mass / other.mass); + } + else 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); + } + } + return; + } + + if(other.classname != "player") + return; + + if(other.deadflag != DEAD_NO) + return; + + if(other.vehicle != world) + return; + + // Remove this when bots know how to use vehicles. + if (clienttype(other) != CLIENTTYPE_REAL) + return; + + vehicles_enter(); +} + +void vehicles_enter() +{ + // Remove this when bots know how to use vehicles + if (clienttype(other) != CLIENTTYPE_REAL) + return; + + if(self.phase > time) + return; + - if(teams_matter) ++ if(teamplay) + if(self.team) + if(self.team != other.team) + return; + + self.vehicle_ammo1 = 0; + self.vehicle_ammo2 = 0; + self.vehicle_reload1 = 0; + self.vehicle_reload2 = 0; + self.vehicle_energy = 0; + + self.owner = other; + self.switchweapon = other.switchweapon; + + // .viewmodelforclient works better. + //self.vehicle_hudmodel.drawonlytoclient = self.owner; + + self.vehicle_hudmodel.viewmodelforclient = self.owner; + + self.event_damage = vehicles_damage; + self.nextthink = 0; + self.owner.angles = self.angles; + self.owner.takedamage = DAMAGE_NO; + self.owner.solid = SOLID_NOT; + self.owner.movetype = MOVETYPE_NOCLIP; + self.owner.alpha = -1; + self.owner.vehicle = self; + self.owner.event_damage = SUB_Null; + self.owner.view_ofs = '0 0 0'; + self.colormap = self.owner.colormap; + if(self.tur_head) + self.tur_head.colormap = self.owner.colormap; + + self.owner.hud = self.hud; + self.owner.PlayerPhysplug = self.PlayerPhysplug; + + self.owner.vehicle_ammo1 = self.vehicle_ammo1; + self.owner.vehicle_ammo2 = self.vehicle_ammo2; + self.owner.vehicle_reload1 = self.vehicle_reload1; + self.owner.vehicle_reload2 = self.vehicle_reload2; + + // Cant do this, hides attached objects too. + //self.exteriormodeltoclient = self.owner; + //self.tur_head.exteriormodeltoclient = self.owner; + + other.flags &~= FL_ONGROUND; + self.flags &~= FL_ONGROUND; + + self.team = self.owner.team; + self.flags -= FL_NOTARGET; + + 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 + { + WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + 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); + + self.vehicle_enter(); +} + +/** vehicles_findgoodexit + Locates a valid location for the player to exit the vehicle. + Will first try prefer_spot, then up 100 random spots arround the vehicle + wich are in direct line of sight and empty enougth to hold a players bbox +**/ +vector vehicles_findgoodexit(vector prefer_spot) +{ + vector exitspot; + float mysize; + + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, prefer_spot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return prefer_spot; + + mysize = vlen(self.maxs - self.mins); + float i; + vector v, v2; + v2 = 0.5 * (self.absmin + self.absmax); + for(i = 0; i < 100; ++i) + { + v = randomvec(); + v_z = 0; + v = v2 + normalize(v) * mysize; + tracebox(v2, PL_MIN, PL_MAX, v, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return v; + } + + /* + exitspot = (self.origin + '0 0 48') + v_forward * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') - v_forward * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') + v_right * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + + exitspot = (self.origin + '0 0 48') - v_right * mysize; + tracebox(self.origin + '0 0 32', PL_MIN, PL_MAX, exitspot, MOVE_NORMAL, self.owner); + if(trace_fraction == 1.0 && !trace_startsolid && !trace_allsolid) + return exitspot; + */ + + return self.origin; +} + +/** vehicles_exit + Standarrd vehicle release fucntion. + custom code goes in self.vehicle_exit +**/ +void vehicles_exit(float eject) +{ + self.flags |= FL_NOTARGET; + + if (self.owner) + { + 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(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(!teams_matter) ++ if(!teamplay) + self.team = 0; + + self.vehicle_exit(eject); + self.owner = world; +} + + +void vehicles_regen(.float timer, .float regen_field, float field_max, float rpause, float regen, float delta_time) +{ + if(self.regen_field < field_max) + if(self.timer + rpause < time) + { + self.regen_field = min(self.regen_field + regen * delta_time, field_max); if(self.owner) - self.owner.vehicle_energy = self.vehicle_energy / rmax; + self.owner.regen_field = (self.regen_field / field_max) * 100; } } @@@ -675,292 -109,12 +675,292 @@@ void vehicles_damage(entity inflictor, { if(self.owner) if(self.vehicle_flags & VHF_DEATHEJECT) - self.vehicle_exit(VHEF_EJECT); + vehicles_exit(VHEF_EJECT); + else + vehicles_exit(VHEF_RELESE); self.vehicle_die(); + vehicles_setreturn(); + } +} + +void vehicles_clearrturn() +{ + entity ret; + // Remove "return helper", if any. + ret = findchain(classname, "vehicle_return"); + while(ret) + { + if(ret.enemy == self) + { + ret.classname = ""; + ret.think = SUB_Remove; + ret.nextthink = time + 0.1; + + if(ret.waypointsprite_attached) + WaypointSprite_Kill(ret.waypointsprite_attached); + + return; + } + ret = ret.chain; + } +} + +void vehicles_return() +{ + pointparticles(particleeffectnum("teleport"), self.enemy.origin + '0 0 64', '0 0 0', 1); + + self.enemy.think = vehicles_spawn; + self.enemy.nextthink = time; + + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); + + remove(self); +} + +void vehicles_showwp_goaway() +{ + if(self.waypointsprite_attached) + WaypointSprite_Kill(self.waypointsprite_attached); + + remove(self); + +} + +void vehicles_showwp() +{ + entity oldself; + + 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.nextthink = time + 5; + self.think = vehicles_showwp_goaway; + } + + WaypointSprite_Spawn("vehicle", 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE); + if(self.waypointsprite_attached) + { + - if(teams_matter && self.team) ++ if(teamplay && self.team) + WaypointSprite_UpdateTeamRadar(self.waypointsprite_attached, RADARICON_POWERUP, TeamColor(self.team)); + else + WaypointSprite_UpdateTeamRadar(self.waypointsprite_attached, RADARICON_POWERUP, '1 1 1'); + + WaypointSprite_UpdateRule(self.waypointsprite_attached, self.enemy.team, SPRITERULE_DEFAULT); + if(oldself == world) + { + WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, self.nextthink); + dprint("Oldies is goldies\n"); + } + + WaypointSprite_Ping(self.waypointsprite_attached); + } + + if(oldself != world) + self = oldself; +} + +void vehicles_setreturn() +{ + entity ret; + + vehicles_clearrturn(); + + ret = spawn(); + ret.classname = "vehicle_return"; + ret.enemy = 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); + } + else + { + 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() +{ + entity e; + float _effects, _colormap; + vector _glowmod, _colormod; + + if(autocvar_g_nodepthtestplayers) + _effects = EF_NODEPTHTEST; + + if(autocvar_g_fullbrightplayers) + _effects |= EF_FULLBRIGHT; + + if(self.team) + _colormap = 1024 + (self.team - 1) * 17; + else + _colormap = 1024; + + _glowmod = '0 0 0'; + _colormod = '0 0 0'; + + // Find all ents attacked to main model and setup effects, colormod etc. + e = findchainentity(tag_entity, self); + while(e) + { + if(e != self.vehicle_shieldent) + { + e.effects = _effects | EF_LOWPRECISION; + e.colormod = _colormod; + e.colormap = _colormap; + e.alpha = 1; + } + e = e.chain; + } + + self.vehicle_hudmodel.effects = self.effects = _effects | EF_LOWPRECISION; + self.vehicle_hudmodel.colormod = self.colormod = _colormod; + self.vehicle_hudmodel.colormap = self.colormap = _colormap; + self.vehicle_viewport.effects = (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT); + + self.alpha = 1; + self.avelocity = '0 0 0'; + self.velocity = '0 0 0'; + self.effects = _effects; +} + +float vehicle_initialize(string net_name, + string bodymodel, + string topmodel, + string hudmodel, + string toptag, + string hudtag, + string viewtag, + float vhud, + vector min_s, + vector max_s, + float nodrop, + void() spawnproc, + float _respawntime, + float() physproc, + void() enterproc, + void(float extflag) exitfunc, + void() dieproc, + void() thinkproc, + float use_csqc) +{ + addstat(STAT_HUD, AS_INT, hud); + addstat(STAT_VEHICLESTAT_HEALTH, AS_INT, vehicle_health); + addstat(STAT_VEHICLESTAT_SHIELD, AS_INT, vehicle_shield); + addstat(STAT_VEHICLESTAT_ENERGY, AS_INT, vehicle_energy); + + addstat(STAT_VEHICLESTAT_AMMO1, AS_INT, vehicle_ammo1); + addstat(STAT_VEHICLESTAT_RELOAD1, AS_INT, vehicle_reload1); + + addstat(STAT_VEHICLESTAT_AMMO2, AS_INT, vehicle_ammo2); + addstat(STAT_VEHICLESTAT_RELOAD2, AS_INT, vehicle_reload2); + + if(bodymodel == "") + error("vehicles: missing bodymodel!"); + + if(hudmodel == "") + error("vehicles: missing hudmodel!"); + + if(net_name == "") + self.netname = self.classname; + else + self.netname = net_name; + - if(self.team && !teams_matter) ++ if(self.team && !teamplay) + self.team = 0; + + self.vehicle_flags |= VHF_ISVEHICLE; + + setmodel(self, bodymodel); + + self.vehicle_viewport = spawn(); + self.vehicle_hudmodel = spawn(); + self.tur_head = spawn(); + self.tur_head.owner = self; + self.takedamage = DAMAGE_AIM; + self.bot_attack = TRUE; + self.iscreature = TRUE; + self.hud = vhud; + + 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.vehicle_respawntime = _respawntime; + self.vehicle_spawn = spawnproc; + + if(autocvar_g_nodepthtestplayers) + self.effects = self.effects | EF_NODEPTHTEST; + + if(autocvar_g_fullbrightplayers) + self.effects = self.effects | EF_FULLBRIGHT; + + setmodel(self.vehicle_hudmodel, hudmodel); + setmodel(self.vehicle_viewport, "null"); + + + if(topmodel != "") + { + setmodel(self.tur_head, topmodel); + setattachment(self.tur_head, self, toptag); + setattachment(self.vehicle_hudmodel, self.tur_head, hudtag); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); + } + else + { + setattachment(self.tur_head, self, ""); + setattachment(self.vehicle_hudmodel, self, hudtag); + setattachment(self.vehicle_viewport, self.vehicle_hudmodel, viewtag); + } + + setsize(self, min_s, max_s); + if not (nodrop) + { + setorigin(self, self.origin); + tracebox(self.origin + '0 0 100', min_s, max_s, self.origin - '0 0 10000', MOVE_WORLDONLY, self); + setorigin(self, trace_endpos); } + self.pos1 = self.origin; + self.pos2 = self.angles; + return TRUE; } void bugmenot()