X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fwarpzonelib%2Fserver.qc;h=921b2ed58289df9fadff0acb3d409feca06d498f;hb=b3499b8b8d3cf35c151aa14f362fa9e777c27d97;hp=8879d6f425a7a9aa4178d941501a6e0043407792;hpb=5fe51fc3c89d42df0ea80e7a60059c0f270f4f4b;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/warpzonelib/server.qc b/qcsrc/warpzonelib/server.qc index 8879d6f42..921b2ed58 100644 --- a/qcsrc/warpzonelib/server.qc +++ b/qcsrc/warpzonelib/server.qc @@ -1,5 +1,6 @@ .vector warpzone_oldorigin, warpzone_oldvelocity, warpzone_oldangles; .float warpzone_teleport_time; +.entity warpzone_teleport_zone; void WarpZone_StoreProjectileData(entity e) { @@ -21,17 +22,23 @@ void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector player.fixangle = TRUE; player.velocity = to_velocity; - if(player.effects & EF_TELEPORT_BIT) - player.effects &~= EF_TELEPORT_BIT; - else - player.effects |= EF_TELEPORT_BIT; + BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT); if(player.classname == "player") - player.flags &~= FL_ONGROUND; + BITCLR_ASSIGN(player.flags, FL_ONGROUND); WarpZone_PostTeleportPlayer_Callback(player); } +float WarpZone_Teleported_Send(entity to, float sf) +{ + WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED); + WriteCoord(MSG_ENTITY, self.angles_x); + WriteCoord(MSG_ENTITY, self.angles_y); + WriteCoord(MSG_ENTITY, self.angles_z); + return TRUE; +} + float WarpZone_Teleport(entity player) { vector o0, a0, v0, o1, a1, v1; @@ -48,7 +55,7 @@ float WarpZone_Teleport(entity player) o1 = WarpZone_TransformOrigin(self, o0); v1 = WarpZone_TransformVelocity(self, v0); - if(player.classname == "player") + if(clienttype(player) != CLIENTTYPE_NOTACLIENT) a1 = WarpZone_TransformVAngles(self, player.v_angle); else a1 = WarpZone_TransformAngles(self, a0); @@ -90,6 +97,24 @@ float WarpZone_Teleport(entity player) 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; +#endif return 1; } @@ -143,15 +168,20 @@ float WarpZone_Send(entity to, float sendflags) // we must send this flag for clientside to match properly too f = 0; if(self.warpzone_isboxy) - f |= 1; + BITSET_ASSIGN(f, 1); if(self.warpzone_fadestart) - f |= 2; + BITSET_ASSIGN(f, 2); + if(self.origin != '0 0 0') + BITSET_ASSIGN(f, 4); WriteByte(MSG_ENTITY, f); // we need THESE to render the warpzone (and cull properly)... - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); + if(f & 4) + { + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + } WriteShort(MSG_ENTITY, self.modelindex); WriteCoord(MSG_ENTITY, self.mins_x); @@ -191,13 +221,18 @@ float WarpZone_Camera_Send(entity to, float sendflags) WriteByte(MSG_ENTITY, ENT_CLIENT_WARPZONE_CAMERA); if(self.warpzone_fadestart) - f |= 2; + BITSET_ASSIGN(f, 2); + if(self.origin != '0 0 0') + BITSET_ASSIGN(f, 4); WriteByte(MSG_ENTITY, f); // we need THESE to render the warpzone (and cull properly)... - WriteCoord(MSG_ENTITY, self.origin_x); - WriteCoord(MSG_ENTITY, self.origin_y); - WriteCoord(MSG_ENTITY, self.origin_z); + if(f & 4) + { + WriteCoord(MSG_ENTITY, self.origin_x); + WriteCoord(MSG_ENTITY, self.origin_y); + WriteCoord(MSG_ENTITY, self.origin_z); + } WriteShort(MSG_ENTITY, self.modelindex); WriteCoord(MSG_ENTITY, self.mins_x); @@ -233,7 +268,13 @@ float WarpZone_CheckProjectileImpact() entity wz; wz = WarpZone_Find(self.origin + self.mins, self.origin + self.maxs); if(!wz) - return FALSE; + 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; @@ -245,45 +286,47 @@ float WarpZone_CheckProjectileImpact() 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.velocity); + 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) * self.warpzone_targetforward; + 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 FALSE; + return 0; } } WarpZone_RefSys_Add(self, wz); WarpZone_StoreProjectileData(self); self.warpzone_teleport_time = time; - return TRUE; + return +1; } float WarpZone_Projectile_Touch() { + float f; if(other.classname == "trigger_warpzone") return TRUE; if(WarpZone_Projectile_Touch_ImpactFilter_Callback()) return TRUE; - if(WarpZone_CheckProjectileImpact()) - return TRUE; - if(self.warpzone_teleport_time == time) // already got teleported this frame? no collision then please + if((f = WarpZone_CheckProjectileImpact()) != 0) + return (f > 0); + 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; } @@ -325,19 +368,25 @@ void WarpZonePosition_InitStep_FindTarget() void WarpZoneCamera_InitStep_FindTarget() { + entity e; + float i; if(self.target == "") { error("Camera with no target"); return; } - self.enemy = find(world, targetname, self.target); + self.enemy = world; + for(e = world, i = 0; (e = find(e, targetname, self.target)); ) + if(random() * ++i < 1) + self.enemy = e; if(self.enemy == world) { error("Camera with nonexisting target"); return; } - ++warpzone_cameras_exist; + warpzone_cameras_exist = 1; WarpZone_Camera_SetUp(self, self.enemy.origin, self.enemy.angles); + self.SendFlags = 0xFFFFFF; } void WarpZone_InitStep_UpdateTransform() @@ -359,7 +408,7 @@ void WarpZone_InitStep_UpdateTransform() tex = getsurfacetexture(self, i_s); if not(tex) break; // this is beyond the last one - if(tex == "textures/common/trigger") + if(tex == "textures/common/trigger" || tex == "trigger") continue; n_t = getsurfacenumtriangles(self, i_s); for(i_t = 0; i_t < n_t; ++i_t) @@ -470,7 +519,7 @@ void WarpZone_InitStep_FinalizeTransform() return; } - ++warpzone_warpzones_exist; + warpzone_warpzones_exist = 1; WarpZone_SetUp(self, self.warpzone_origin, self.warpzone_angles, self.enemy.warpzone_origin, self.enemy.warpzone_angles); self.touch = WarpZone_Touch; self.SendFlags = 0xFFFFFF; @@ -520,7 +569,7 @@ void spawnfunc_trigger_warpzone(void) setsize(self, self.mins, self.maxs); self.SendEntity = WarpZone_Send; self.SendFlags = 0xFFFFFF; - self.effects |= EF_NODEPTHTEST; + BITSET_ASSIGN(self.effects, EF_NODEPTHTEST); self.warpzone_next = warpzone_first; warpzone_first = self; } @@ -557,6 +606,8 @@ void WarpZones_Reconnect() WarpZone_InitStep_ClearTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_FindTarget(); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_FinalizeTransform(); self = e; @@ -573,17 +624,58 @@ void WarpZone_StartFrame() WarpZone_InitStep_FindOriginTarget(); for(self = warpzone_position_first; self; self = self.warpzone_next) WarpZonePosition_InitStep_FindTarget(); - for(self = warpzone_camera_first; self; self = self.warpzone_next) - WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) WarpZone_InitStep_UpdateTransform(); self = e; WarpZones_Reconnect(); } - for(e = world; (e = nextent(e)); ) - WarpZone_StoreProjectileData(e); + + if(warpzone_warpzones_exist) + { + entity oldself, oldother; + oldself = self; + oldother = other; + for(e = world; (e = nextent(e)); ) + { + WarpZone_StoreProjectileData(e); + float f; + f = clienttype(e); + if(f == CLIENTTYPE_REAL) + { + 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; + WarpZone_Teleport(e); // NOT triggering targets by this! + } + if(f == CLIENTTYPE_NOTACLIENT) + { + for(; (e = nextent(e)); ) + WarpZone_StoreProjectileData(e); + break; + } + } + self = oldself; + other = oldother; + } } +.float warpzone_reconnecting; +float visible_to_some_client(entity ent) +{ + entity e; + for(e = nextent(world); clienttype(e) != CLIENTTYPE_NOTACLIENT; e = nextent(e)) + if(e.classname == "player" && clienttype(e) == CLIENTTYPE_REAL) + if(checkpvs(e.origin + e.view_ofs, ent)) + return 1; + return 0; +} void trigger_warpzone_reconnect_use() { entity e; @@ -591,13 +683,20 @@ void trigger_warpzone_reconnect_use() // NOTE: this matches for target, not targetname, but of course // targetname must be set too on the other entities for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target) + self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && (visible_to_some_client(self) || visible_to_some_client(self.enemy)))); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + self.warpzone_reconnecting = ((e.target == "" || self.target == e.target) && !((e.spawnflags & 1) && visible_to_some_client(self))); + for(self = warpzone_first; self; self = self.warpzone_next) + if(self.warpzone_reconnecting) WarpZone_InitStep_ClearTarget(); for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target) + if(self.warpzone_reconnecting) WarpZone_InitStep_FindTarget(); + for(self = warpzone_camera_first; self; self = self.warpzone_next) + if(self.warpzone_reconnecting) + WarpZoneCamera_InitStep_FindTarget(); for(self = warpzone_first; self; self = self.warpzone_next) - if(e.target == "" || self.target == e.target || self.enemy.target == e.target) + if(self.warpzone_reconnecting || self.enemy.warpzone_reconnecting) WarpZone_InitStep_FinalizeTransform(); self = e; } @@ -611,3 +710,16 @@ void spawnfunc_target_warpzone_reconnect() { spawnfunc_trigger_warpzone_reconnect(); // both names make sense here :( } + +void WarpZone_PlayerPhysics_FixVAngle(void) +{ +#ifndef WARPZONE_DONT_FIX_VANGLE + if(clienttype(self) == CLIENTTYPE_REAL) + if(self.v_angle_z <= 360) // if not already adjusted + if(time - self.ping * 0.001 < self.warpzone_teleport_time) + { + self.v_angle = WarpZone_TransformVAngles(self.warpzone_teleport_zone, self.v_angle); + self.v_angle_z += 720; // mark as adjusted + } +#endif +}