X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fwarpzonelib%2Fserver.qc;h=cb7cde2e45a9b9a01cc45668fc99c68a1f596d18;hb=437473c799ae8f8f33640163650825e3155b886b;hp=3892b329d991cb1337a31acf613992053750f9ff;hpb=ea73bfe85e356df9b6c705882a5077f48ab03de0;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/warpzonelib/server.qc b/qcsrc/warpzonelib/server.qc index 3892b329d..cb7cde2e4 100644 --- a/qcsrc/warpzonelib/server.qc +++ b/qcsrc/warpzonelib/server.qc @@ -18,11 +18,6 @@ void WarpZone_StoreProjectileData(entity e) void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity) { - vector from; - - makevectors (to_angles); - - from = player.origin; setorigin (player, to); player.oldorigin = to; // for DP's unsticking player.angles = to_angles; @@ -46,7 +41,31 @@ float WarpZone_Teleported_Send(entity to, float sf) return TRUE; } -float WarpZone_Teleport(entity player) +#define WARPZONE_TELEPORT_FIXSOLID(ret) \ + { \ + setorigin(player, o1 - player.view_ofs); \ + if(WarpZoneLib_MoveOutOfSolid(player)) \ + { \ + o1 = player.origin + player.view_ofs; \ + setorigin(player, o0 - player.view_ofs); \ + } \ + else \ + { \ + print("would have to put player in solid, won't do that\n"); \ + setorigin(player, o0 - player.view_ofs); \ + return (ret); \ + } \ + } +#define WARPZONE_TELEPORT_DOTELEPORT() \ + { \ + WarpZone_RefSys_Add(player, wz); \ + WarpZone_TeleportPlayer(wz, player, o1 - player.view_ofs, a1, v1); \ + WarpZone_StoreProjectileData(player); \ + player.warpzone_teleport_time = time; \ + player.warpzone_teleport_zone = wz; \ + } + +float WarpZone_Teleport(entity wz, entity player, float f0, float f1) { vector o0, a0, v0, o1, a1, v1; @@ -54,73 +73,67 @@ float WarpZone_Teleport(entity player) v0 = player.velocity; a0 = player.angles; - if(WarpZone_PlaneDist(self, o0) >= 0) // wrong side of the trigger_warpzone - return 2; - // no failure, we simply don't want to teleport yet; TODO in - // this situation we may want to create a temporary clone - // entity of the player to fix graphics glitch - - o1 = WarpZone_TransformOrigin(self, o0); - v1 = WarpZone_TransformVelocity(self, v0); + o1 = WarpZone_TransformOrigin(wz, o0); + v1 = WarpZone_TransformVelocity(wz, v0); if(clienttype(player) != CLIENTTYPE_NOTACLIENT) - a1 = WarpZone_TransformVAngles(self, player.v_angle); + a1 = WarpZone_TransformVAngles(wz, player.v_angle); else - a1 = WarpZone_TransformAngles(self, a0); + a1 = WarpZone_TransformAngles(wz, a0); - // put him inside solid - tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player); - if(trace_startsolid) + if(f0 != 0 || f1 != 0) { - vector mi, ma; - mi = player.mins; - ma = player.maxs; - setsize(player, mi - player.view_ofs, ma - player.view_ofs); - setorigin(player, o1); - if(WarpZoneLib_MoveOutOfSolid(player)) - { - o1 = player.origin; - setsize(player, mi, ma); - setorigin(player, o0); - } - else + // retry last move but behind the warpzone! + // we must first go back as far as we can, then forward again, to not cause double touch events! + + float d0; + d0 = WarpZone_TargetPlaneDist(wz, o1); + if(d0 < 0) + dprint("warpzone: target is not outside warp!\n"); + + tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player); { - print("would have to put player in solid, won't do that\n"); - setsize(player, mi, ma); - setorigin(player, o0 - player.view_ofs); - return 0; // cannot fix + entity own; + own = player.owner; + player.owner = world; + tracebox(trace_endpos, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f1, MOVE_NORMAL, player); // this should get us through the warpzone + player.owner = own; } - } + o1 = trace_endpos + player.view_ofs; - if(WarpZone_TargetPlaneDist(self, o1) <= 0) - { - print("inconsistent warp zones or evil roundoff error\n"); - return 0; + float d, dv; + d = WarpZone_TargetPlaneDist(wz, o1); + dv = WarpZone_TargetPlaneDist(wz, v1); + if(d0 >= 0) + if(d < 0) + o1 = o1 - v1 * (d / dv); } - //print(sprintf("warpzone: %f %f %f -> %f %f %f\n", o0_x, o0_y, o0_z, o1_x, o1_y, o1_z)); + // put him inside solid + tracebox(o1 - player.view_ofs, player.mins, player.maxs, o1 - player.view_ofs, MOVE_NOMONSTERS, player); + if(trace_startsolid) + WARPZONE_TELEPORT_FIXSOLID(0); + + WARPZONE_TELEPORT_DOTELEPORT(); - //o1 = trace_endpos; - WarpZone_RefSys_Add(player, self); - WarpZone_TeleportPlayer(self, player, o1 - player.view_ofs, a1, v1); - WarpZone_StoreProjectileData(player); - player.warpzone_teleport_time = time; - player.warpzone_teleport_zone = self; #ifndef WARPZONE_USE_FIXANGLE - // instead of fixangle, send the transform to the client for smoother operation - player.fixangle = FALSE; - - entity ts = spawn(); - setmodel(ts, "null"); - ts.SendEntity = WarpZone_Teleported_Send; - ts.SendFlags = 0xFFFFFF; - ts.drawonlytoclient = player; - ts.think = SUB_Remove; - ts.nextthink = time + 1; - ts.owner = player; - ts.enemy = self; - ts.effects = EF_NODEPTHTEST; - ts.classname = "warpzone_teleported"; - ts.angles = self.warpzone_transform; + if(player.classname == "player") + { + // instead of fixangle, send the transform to the client for smoother operation + player.fixangle = FALSE; + + entity ts = spawn(); + setmodel(ts, "null"); + ts.SendEntity = WarpZone_Teleported_Send; + ts.SendFlags = 0xFFFFFF; + ts.drawonlytoclient = player; + ts.think = SUB_Remove; + ts.nextthink = time + 1; + ts.owner = player; + ts.enemy = wz; + ts.effects = EF_NODEPTHTEST; + ts.classname = "warpzone_teleported"; + ts.angles = wz.warpzone_transform; + } #endif return 1; @@ -128,20 +141,25 @@ float WarpZone_Teleport(entity player) void WarpZone_Touch (void) { - entity oldself, e; + entity oldself; if(other.classname == "trigger_warpzone") return; + if(other.warpzone_teleport_time == time) // already teleported this frame + return; + // FIXME needs a better check to know what is safe to teleport and what not - if(other.movetype == MOVETYPE_NONE) + if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW) return; if(WarpZoneLib_ExactTrigger_Touch()) return; - e = self.enemy; - if(WarpZone_Teleport(other)) + if(WarpZone_PlaneDist(self, other.origin + other.view_ofs) >= 0) // wrong side of the trigger_warpzone (don't teleport yet) + return; + + if(WarpZone_Teleport(self, other, -1, 0)) { string save1, save2; activator = other; @@ -267,73 +285,18 @@ float WarpZone_Camera_Send(entity to, float sendflags) return TRUE; } -float WarpZone_CheckProjectileImpact() -{ - // if self hit a warpzone, abort - vector o0, v0, a0; - float mpd, pd, dpd; - entity wz; - wz = WarpZone_Find(self.origin + self.mins, self.origin + self.maxs); - if(!wz) - return 0; - if(self.warpzone_teleport_time == time) - { - // just ignore if we got teleported this frame already and now hit a wall and are in a warpzone again (this will cause a detonation) - // print("2 warps 1 frame\n"); - return -1; - } - o0 = self.origin; - v0 = self.velocity; - a0 = self.angles; - - // this approach transports the projectile at its full speed, but does - // not properly retain the projectile trail (but we can't retain it - // easily anyway without delaying the projectile by two frames, so who - // cares) - WarpZone_TraceBox_ThroughZone(self.warpzone_oldorigin, self.mins, self.maxs, self.warpzone_oldorigin + self.warpzone_oldvelocity * frametime, MOVE_NORMAL, self, wz, WarpZone_trace_callback_t_null); // this will get us through the warpzone - setorigin(self, trace_endpos); - self.angles = WarpZone_TransformAngles(WarpZone_trace_transform, self.angles); - self.velocity = WarpZone_TransformVelocity(WarpZone_trace_transform, self.warpzone_oldvelocity); - - // in case we are in our warp zone post-teleport, shift the projectile forward a bit - mpd = max(vlen(self.mins), vlen(self.maxs)); - pd = WarpZone_TargetPlaneDist(wz, self.origin); - if(pd < mpd) - { - dpd = normalize(self.velocity) * wz.warpzone_targetforward; - setorigin(self, self.origin + normalize(self.velocity) * ((mpd - pd) / dpd)); - if(!WarpZoneLib_MoveOutOfSolid(self)) - { - setorigin(self, o0); - self.angles = a0; - self.velocity = v0; - return 0; - } - } - WarpZone_RefSys_Add(self, wz); - WarpZone_StoreProjectileData(self); - self.warpzone_teleport_time = time; - - return +1; -} float WarpZone_Projectile_Touch() { - float f; if(other.classname == "trigger_warpzone") return TRUE; - if(WarpZone_Projectile_Touch_ImpactFilter_Callback()) - return TRUE; - if((f = WarpZone_CheckProjectileImpact()) != 0) - return (f > 0); + + // no further impacts if we teleported this frame! if(self.warpzone_teleport_time == time) - { - // sequence: hit warpzone, get teleported, hit wall - // print("2 hits 1 frame\n"); - setorigin(self, self.warpzone_oldorigin); - self.velocity = self.warpzone_oldvelocity; - self.angles = self.warpzone_oldangles; return TRUE; - } + + if(WarpZone_Projectile_Touch_ImpactFilter_Callback()) + return TRUE; + return FALSE; } @@ -410,7 +373,7 @@ void WarpZoneCamera_InitStep_FindTarget() warpzone_cameras_exist = 1; WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles); self.SendFlags = 0xFFFFFF; - if(self.spawnflags & 2) + if(self.spawnflags & 1) { self.think = WarpZoneCamera_Think; self.nextthink = time; @@ -554,7 +517,7 @@ void WarpZone_InitStep_FinalizeTransform() WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles); self.touch = WarpZone_Touch; self.SendFlags = 0xFFFFFF; - if(self.spawnflags & 2) + if(self.spawnflags & 1) { self.think = WarpZone_Think; self.nextthink = time; @@ -588,6 +551,11 @@ void spawnfunc_trigger_warpzone(void) // the map, with another killtarget to designate its // orientation +#ifndef WARPZONE_USE_FIXANGLE + // used when teleporting + precache_model("null"); +#endif + if(!self.scale) self.scale = self.modelscale; if(!self.scale) @@ -715,7 +683,8 @@ void WarpZone_StartFrame() other = e; if(WarpZoneLib_ExactTrigger_Touch()) continue; - WarpZone_Teleport(e); // NOT triggering targets by this! + if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0) + WarpZone_Teleport(self, e); // NOT triggering targets by this! } if(f == CLIENTTYPE_NOTACLIENT) {