// for all entities
.vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles;
.float warpzone_teleport_time;
+.float warpzone_teleport_finishtime;
.entity warpzone_teleport_zone;
void WarpZone_StoreProjectileData(entity e)
}
#define WARPZONE_TELEPORT_FIXSOLID(ret) \
+ do \
{ \
setorigin(player, o1 - player.view_ofs); \
if(WarpZoneLib_MoveOutOfSolid(player)) \
setorigin(player, o0 - player.view_ofs); \
return (ret); \
} \
- }
+ } \
+ while(0)
#define WARPZONE_TELEPORT_DOTELEPORT() \
+ do \
{ \
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_finishtime = time; \
player.warpzone_teleport_zone = wz; \
- }
+ } \
+ while(0)
float WarpZone_Teleport(entity wz, entity player, float f0, float f1)
{
- vector o0, a0, v0, o1, a1, v1;
+ vector o0, a0, v0, o1, a1, v1, o10;
o0 = player.origin + player.view_ofs;
v0 = player.velocity;
a0 = player.angles;
- o1 = WarpZone_TransformOrigin(wz, o0);
+ o10 = o1 = WarpZone_TransformOrigin(wz, o0);
v1 = WarpZone_TransformVelocity(wz, v0);
if(clienttype(player) != CLIENTTYPE_NOTACLIENT)
a1 = WarpZone_TransformVAngles(wz, player.v_angle);
else
a1 = WarpZone_TransformAngles(wz, a0);
- // 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!
- print(sprintf("%v ", o1));
- tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
+ if(f0 != 0 || f1 != 0)
{
- 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;
- print(sprintf("-> %v\n", o1));
-
+ // 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!
+
+ tracebox(o1 - player.view_ofs + v1 * frametime * f1, player.mins, player.maxs, o1 - player.view_ofs + v1 * frametime * f0, MOVE_WORLDONLY, player);
+ {
+ 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;
+
+ float d, dv, md;
+ md = max(vlen(player.mins), vlen(player.maxs));
+ d = WarpZone_TargetPlaneDist(wz, o1);
+ dv = WarpZone_TargetPlaneDist(wz, v1);
+ if(d < 0)
+ o1 = o1 - v1 * (d / dv);
+ }
+
// 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_DOTELEPORT();
+ // prevent further teleports back
+ float dt = (o1 - o10) * v1 * (1 / (v1 * v1));
+ if(dt < sys_frametime)
+ player.warpzone_teleport_finishtime += sys_frametime - dt;
+
#ifndef WARPZONE_USE_FIXANGLE
if(player.classname == "player")
{
void WarpZone_Touch (void)
{
- entity oldself, e;
+ entity oldself;
if(other.classname == "trigger_warpzone")
return;
+ if(time <= other.warpzone_teleport_finishtime) // 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 || other.movetype == MOVETYPE_FOLLOW)
+ if(other.movetype == MOVETYPE_NONE || other.movetype == MOVETYPE_FOLLOW || other.tag_entity)
return;
if(WarpZoneLib_ExactTrigger_Touch())
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))
+ float f;
+ // number of frames we need to go back:
+ // dist = 16*sqrt(2) qu
+ // dist ~ 24 qu
+ // 24 qu = v*t
+ // 24 qu = v*frametime*n
+ // n = 24 qu/(v*frametime)
+ // for clients go only one frame though, may be too irritating otherwise
+ // but max 0.25 sec = 0.25/frametime frames
+ // 24/(0.25/frametime)
+ // 96*frametime
+ float d;
+ d = 24 + max(vlen(other.mins), vlen(other.maxs));
+ if(clienttype(other) == CLIENTTYPE_NOTACLIENT)
+ f = -d / bound(frametime * d * 1, frametime * vlen(other.velocity), d);
+ else
+ f = -1;
+ if(WarpZone_Teleport(self, other, f, 0))
{
string save1, save2;
activator = other;
return TRUE;
}
-float WarpZone_CheckProjectileImpact()
+float WarpZone_CheckProjectileImpact(entity player)
{
- entity player;
- player = self;
- vector o0, a0, v0, o1, a1, v1;
+ vector o0, v0;
o0 = player.origin + player.view_ofs;
v0 = player.velocity;
- a0 = player.angles;
+
+ // if we teleported shortly before, abort
+ if(time <= player.warpzone_teleport_finishtime + 0.1)
+ return 0;
// if player hit a warpzone, abort
- float mpd, pd, dpd;
entity wz;
wz = WarpZone_Find(o0 + player.mins, o0 + player.maxs);
if(!wz)
return 0;
- if(player.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;
- }
+ print("impactfilter found something - and it even gets handled correctly - please tell divVerent that this code apparently gets triggered again\n");
+
+ // retry previous move
setorigin(player, player.warpzone_oldorigin);
player.velocity = player.warpzone_oldvelocity;
if(WarpZone_Teleport(wz, player, 0, 1))
{
+ entity oldself;
+ string save1, save2;
+
+ oldself = self;
+ self = wz;
+ other = player;
+ activator = player;
+
+ save1 = self.target; self.target = string_null;
+ save2 = self.target3; self.target3 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target3) self.target3 = save2;
+
+ self = self.enemy;
+ save1 = self.target; self.target = string_null;
+ save2 = self.target2; self.target2 = string_null;
+ SUB_UseTargets();
+ if not(self.target) self.target = save1;
+ if not(self.target2) self.target2 = save2;
+ self = oldself;
}
else
{
- setorigin(player, o0);
+ setorigin(player, o0 - player.view_ofs);
player.velocity = v0;
}
return TRUE;
// no further impacts if we teleported this frame!
- if(self.warpzone_teleport_time == time)
+ if(time == self.warpzone_teleport_time)
return TRUE;
+ // this SEEMS to not happen at the moment, but if it did, it would be more reliable
{
float save_dpstartcontents;
float save_dphitcontents;
save_ent = trace_ent;
save_inopen = trace_inopen;
save_inwater = trace_inwater;
- if((f = WarpZone_CheckProjectileImpact()) != 0)
+ if((f = WarpZone_CheckProjectileImpact(self)) != 0)
return (f > 0);
trace_dpstartcontents = save_dpstartcontents;
trace_dphitcontents = save_dphitcontents;
if(WarpZone_Projectile_Touch_ImpactFilter_Callback())
return TRUE;
- 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;
- }
return FALSE;
}
WarpZone_InitStep_UpdateTransform();
self = e;
WarpZones_Reconnect();
+ WarpZone_PostInitialize_Callback();
}
- if(warpzone_warpzones_exist)
+ entity oldself, oldother;
+ oldself = self;
+ oldother = other;
+ for(e = world; (e = nextent(e)); )
{
- entity oldself, oldother;
- oldself = self;
- oldother = other;
- for(e = world; (e = nextent(e)); )
+ if(warpzone_warpzones_exist) { WarpZone_StoreProjectileData(e); }
+
+ float f = clienttype(e);
+ if(f == CLIENTTYPE_REAL)
{
- WarpZone_StoreProjectileData(e);
- float f;
- f = clienttype(e);
- if(f == CLIENTTYPE_REAL)
+ if(e.solid == SOLID_NOT) // not spectating?
+ if(e.movetype == MOVETYPE_NOCLIP || e.movetype == MOVETYPE_FLY || e.movetype == MOVETYPE_FLY_WORLDONLY) // not spectating? (this is to catch observers)
{
- if(e.solid != SOLID_NOT) // not spectating?
- continue;
- if(e.movetype != MOVETYPE_NOCLIP && e.movetype != MOVETYPE_FLY) // not spectating? (this is to catch observers)
- continue;
- self = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
- if(!self)
- continue;
- other = e;
- if(WarpZoneLib_ExactTrigger_Touch())
- continue;
- if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) >= 0)
- WarpZone_Teleport(self, e); // NOT triggering targets by this!
+ other = e; // player
+
+ // warpzones
+ if(warpzone_warpzones_exist) {
+ self = WarpZone_Find(e.origin + e.mins, e.origin + e.maxs);
+ if(self)
+ if(!WarpZoneLib_ExactTrigger_Touch())
+ if(WarpZone_PlaneDist(self, e.origin + e.view_ofs) <= 0)
+ WarpZone_Teleport(self, e, -1, 0); } // NOT triggering targets by this!
+
+ // teleporters
+ self = Teleport_Find(e.origin + e.mins, e.origin + e.maxs);
+ if(self)
+ if(!WarpZoneLib_ExactTrigger_Touch())
+ Simple_TeleportPlayer(self, other); // NOT triggering targets by this!
}
- if(f == CLIENTTYPE_NOTACLIENT)
- {
+ }
+
+ if(f == CLIENTTYPE_NOTACLIENT)
+ {
+ if(warpzone_warpzones_exist)
for(; (e = nextent(e)); )
WarpZone_StoreProjectileData(e);
- break;
- }
+ break;
}
- self = oldself;
- other = oldother;
}
+ self = oldself;
+ other = oldother;
}
.float warpzone_reconnecting;