From c460befa5dd2aee5f9d3dab015980253559e49bd Mon Sep 17 00:00:00 2001 From: Juhu <5894800-Juhu_@users.noreply.gitlab.com> Date: Tue, 16 May 2023 14:13:02 +0200 Subject: [PATCH] improve dropping from dropship try harder to get the dropship to the top of the map ensure that players are never spawned at invalid positions abort a player's drop when crashing into an object place squad members evenly on both sides of the leader disconnect squad members from drop leader if they are too far away make sure dropping squad properly stays in a line formation with the correct orientation --- qcsrc/common/gamemodes/gamemode/br/sv_br.qc | 79 +++++++++++++++---- .../gamemodes/gamemode/br/sv_dropship.qc | 46 +++++++++-- 2 files changed, 101 insertions(+), 24 deletions(-) diff --git a/qcsrc/common/gamemodes/gamemode/br/sv_br.qc b/qcsrc/common/gamemodes/gamemode/br/sv_br.qc index 0f4163766..825866027 100644 --- a/qcsrc/common/gamemodes/gamemode/br/sv_br.qc +++ b/qcsrc/common/gamemodes/gamemode/br/sv_br.qc @@ -12,6 +12,7 @@ || DEATH_ISWEAPON(dt, WEP_VAPORIZER)) float br_CalculatePlayerDropAngle(entity this); +bool br_PositionDropMember(entity this, entity leader, int position, float disconnect_range); void br_LastPlayerForSquad_Notify(entity squad); void br_RemovePlayer(entity player); void br_Revive(entity player); @@ -25,12 +26,15 @@ bool squads_colored = false; const float br_drop_time_secs = 1; const float drop_speed_vertical_max = 0.9; +const float drop_distance_disconnect = 32; +const float drop_speed_crash = 0.9; bool br_started = false; .bool br_ring_warned; .float br_drop_time; .float br_force_drop_distance; .int br_drop_launch; .int br_drop_detached; +.float br_drop_position; .bool br_drop_instructions; .float br_ring_damage_time; @@ -399,15 +403,13 @@ MUTATOR_HOOKFUNCTION(br, PlayerPreThink, CBC_ORDER_FIRST) { player.br_squad.br_squad_drop_leader = player; - vector drop_base_offset; - drop_base_offset.x = cos((player.angles.y + 90) * DEG2RAD); - drop_base_offset.y = sin((player.angles.y + 90) * DEG2RAD); - drop_base_offset.z = 0; - drop_base_offset = drop_base_offset * vlen(vec2(player.maxs - player.mins)) + drop_base_offset * 32; // I hope individual players never get different mins/maxs + bool other_side = false; + int drop_position = 1; - vector drop_offset = drop_base_offset; + if(random() < 0.5) + drop_position *= -1; - FOREACH_CLIENT(IS_PLAYER(it) && (it != player) && SAME_SQUAD(it, player) && (STAT(DROP, it) == DROP_TRANSPORT), { + FOREACH_CLIENT_RANDOM(IS_PLAYER(it) && (it != player) && SAME_SQUAD(it, player) && (STAT(DROP, it) == DROP_TRANSPORT), { it.effects &= ~EF_NODRAW; it.takedamage = DAMAGE_AIM; it.solid = SOLID_SLIDEBOX; @@ -418,8 +420,13 @@ MUTATOR_HOOKFUNCTION(br, PlayerPreThink, CBC_ORDER_FIRST) it.br_drop_detached = 0; Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_BR_DROP_DETACH); - setorigin(it, player.origin + drop_offset); // FIXME: this can teleport players into brushes/void - drop_offset += drop_base_offset; + it.br_drop_position = drop_position; + if(other_side) + drop_position += copysign(1, drop_position); + drop_position *= -1; + other_side = !other_side; + + br_PositionDropMember(it, player, it.br_drop_position, -1); it.velocity = player.velocity; it.angles = player.angles; @@ -542,21 +549,23 @@ MUTATOR_HOOKFUNCTION(br, PM_Physics) // TODO: improve dropping physics if(STAT(DROP, player) == DROP_FALLING){ - if(!IS_ONGROUND(player) && (player.waterlevel < WATERLEVEL_SWIMMING) && ((tracebox(player.origin, player.mins, player.maxs, player.origin - '0 0 1', MOVE_NOMONSTERS, player), trace_fraction) >= 1)) // IS_ONGROUND doesn't work if jump is held (jump is theoretically blocked until landed) + float maxairspeed = PHYS_MAXAIRSPEED(player) * max(maxspeed_mod, 1); + float mindropspeed = maxairspeed * max(autocvar_g_br_drop_speed_min, 0); + float dropspeed = vlen(vec2(player.velocity) + eZ * min(player.velocity.z, 0)); + if(player.velocity.z > 0) + dropspeed -= vlen(player.velocity) - dropspeed; + if(!IS_ONGROUND(player) && (player.waterlevel < WATERLEVEL_SWIMMING) && (dropspeed >= (mindropspeed * drop_speed_crash)) && ((tracebox(player.origin, player.mins, player.maxs, player.origin - '0 0 1', MOVE_NOMONSTERS, player), trace_fraction) >= 1)) // IS_ONGROUND doesn't work if jump is held (jump is theoretically blocked until landed) { ITEMS_STAT(player) |= IT_USING_JETPACK; bool has_drop_leader = IN_SQUAD(player) && (player.br_drop_detached != 2) && (player.br_squad.br_squad_drop_leader && (STAT(DROP, player.br_squad.br_squad_drop_leader) == DROP_FALLING)); bool player_is_drop_leader = has_drop_leader && (player == player.br_squad.br_squad_drop_leader); if(player_is_drop_leader || !has_drop_leader) { - float maxairspeed = PHYS_MAXAIRSPEED(player) * max(maxspeed_mod, 1); float maxdropspeed = maxairspeed * max(autocvar_g_br_drop_speed_max, 0); - float mindropspeed = maxairspeed * max(autocvar_g_br_drop_speed_min, 0); float maxdropspeed_ratio = drop_speed_vertical_max; // moving straight down is glitchy float mindropspeed_ratio = bound(0, autocvar_g_br_drop_speed_vertical_min, drop_speed_vertical_max); float accel_dive = max(autocvar_g_br_drop_accel_dive, 0); float accel_turn = max(autocvar_g_br_drop_accel_turn, 0); - float dropspeed = vlen(player.velocity); float dropspeed_xy = vlen(vec2(player.velocity)); float pitch_current = br_CalculatePlayerDropAngle(player); float pitch_view = max(player.v_angle.x, 0); @@ -582,9 +591,7 @@ MUTATOR_HOOKFUNCTION(br, PM_Physics) // vertical wishvel using forward movement and the previously calculated ratio wishvel.z = pitch_ratio_wish * bound(0, CS(player).movement.x / maxairspeed, 1); // apply turn acceleration to wishvel - wishvel.x *= accel_turn; - wishvel.y *= accel_turn; - wishvel.z *= accel_turn; + wishvel *= accel_turn; player.velocity += wishvel * dt; player.velocity = normalize(eZ * player.velocity.z + normalize(vec2(player.velocity)) * dropspeed_xy); @@ -618,6 +625,13 @@ MUTATOR_HOOKFUNCTION(br, PM_Physics) if(player_is_drop_leader) { FOREACH_CLIENT(IS_PLAYER(it) && (it != player) && SAME_SQUAD(it, player) && (it.br_drop_detached != 2) && (STAT(DROP, it) == DROP_FALLING), { + if(!br_PositionDropMember(it, player, it.br_drop_position, drop_distance_disconnect)) + { + it.br_drop_detached = 2; + Kill_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CPID_BR_DROP); + continue; + } + it.velocity = player.velocity; it.angles = player.angles; }); @@ -630,6 +644,12 @@ MUTATOR_HOOKFUNCTION(br, PM_Physics) } else { + if(!br_PositionDropMember(player, player.br_squad.br_squad_drop_leader, player.br_drop_position, drop_distance_disconnect)) + { + player.br_drop_detached = 2; + Kill_Notification(NOTIF_ONE_ONLY, player, MSG_CENTER, CPID_BR_DROP); + } + player.velocity = player.br_squad.br_squad_drop_leader.velocity; player.angles = player.br_squad.br_squad_drop_leader.angles; // no fixangles, only moves the player model not the player view } @@ -997,6 +1017,31 @@ float br_CalculatePlayerDropAngle(entity this) return 0; } +bool br_PositionDropMember(entity this, entity leader, int position, float disconnect_range) { + float pl_mins = min(leader.mins.x, leader.mins.y); + float pl_maxs = max(leader.maxs.x, leader.maxs.y); + + vector member_offset; + member_offset.x = cos((leader.angles.y + 90) * DEG2RAD); + member_offset.y = sin((leader.angles.y + 90) * DEG2RAD); + member_offset.z = 0; + member_offset *= pl_maxs - pl_mins + 32; // I hope individual players never get different mins/maxs + member_offset *= position; + + vector member_destination = leader.origin + member_offset; + + tracebox(this.origin, this.mins, this.maxs, member_destination, MOVE_NORMAL, this); + + if((trace_fraction < 1) && (disconnect_range >= 0)) + { + if(vlen(member_destination - trace_endpos) > disconnect_range) + return false; + } + + setorigin(this, trace_endpos); + return true; +} + void br_LastPlayerForSquad_Notify(entity squad) { entity player = br_SquadFindLastAlive(squad, false); @@ -1152,7 +1197,7 @@ void br_Start(){ br_SquadMember_Add(current_squad, it); GameRules_scoring_add(it, BR_SQUAD, current_squad.br_squad_id); - setorigin(it, dropship.origin + eZ * (dropship.mins.z - it.maxs.z - 64)); // FIXME: this can teleport players into brushes/void + setorigin(it, dropship.origin + eZ * (dropship.mins.z - it.maxs.z - 64)); it.angles = vectoangles(dropship_path_direction) + '45 0 0'; it.fixangle = true; it.velocity = '0 0 0'; diff --git a/qcsrc/common/gamemodes/gamemode/br/sv_dropship.qc b/qcsrc/common/gamemodes/gamemode/br/sv_dropship.qc index 01ce3bd8e..df06720fb 100644 --- a/qcsrc/common/gamemodes/gamemode/br/sv_dropship.qc +++ b/qcsrc/common/gamemodes/gamemode/br/sv_dropship.qc @@ -13,6 +13,33 @@ entity dropship_initialize() { entity this = dropship_spawn(VEH_RACER, autocvar_g_br_dropship_scale, autocvar_g_br_dropship_color); + vector pl_mins = '0 0 0'; + vector pl_maxs = '0 0 0'; + + FOREACH_CLIENT(IS_PLAYER(it), + { + pl_mins = STAT(PL_MIN, it); + pl_maxs = STAT(PL_MAX, it); + break; + }); + + vector path_mins; + vector path_maxs; + + path_mins.x = min(pl_mins.x, this.mins.x); + path_maxs.x = max(pl_maxs.x, this.maxs.x); + + path_mins.y = min(pl_mins.y, this.mins.y); + path_maxs.y = max(pl_maxs.y, this.maxs.y); + + float z_ofs = this.mins.z - pl_maxs.z - 64; + path_mins.z = min(pl_mins.z + z_ofs, this.mins.z); + path_maxs.z = max(pl_maxs.z + z_ofs, this.maxs.z); + + vector saved_mins = this.mins; + vector saved_maxs = this.maxs; + setsize(this, path_mins, path_maxs); + for(int i = 0; i < 100; ++i) // try to find a dropship path multiple times { if(!MoveToRandomLocationWithinBounds(this, world.mins, world.maxs, this.dphitcontentsmask, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 100, 8192, 1024, false)) @@ -20,10 +47,13 @@ entity dropship_initialize() vector mult; - vector startorigin; - startorigin = dropship_seekPoint(this, this.origin, 2, 2, 1); - startorigin = dropship_seekPoint(this, startorigin, 0, 0, 1); - startorigin = dropship_seekPoint(this, startorigin, 1, 0, 1); + vector startorigin = this.origin; + do { + startorigin = dropship_seekPoint(this, startorigin, 2, 2, 1); + startorigin = dropship_seekPoint(this, startorigin, 0, 0, 1); + startorigin = dropship_seekPoint(this, startorigin, 1, 0, 1); + } while((tracebox(startorigin, this.mins, this.maxs, startorigin + '0 0 1', MOVE_NORMAL, this), trace_fraction) >= 1); + mult = dropship_getMultipliers(); startorigin = dropship_seekPoint(this, startorigin, 0, 1, mult.x); startorigin = dropship_seekPoint(this, startorigin, 1, 1, mult.y); @@ -33,7 +63,7 @@ entity dropship_initialize() endorigin = dropship_seekPoint(this, startorigin, 0, 1, 1 - mult.x); endorigin = dropship_seekPoint(this, endorigin, 1, 1, 1 - mult.y); - endorigin = startorigin + normalize(endorigin - startorigin) * vlen(vec2(world.maxs - world.mins)); + endorigin = startorigin + normalize(endorigin - startorigin) * 65536; tracebox(startorigin, this.mins, this.maxs, endorigin, MOVE_NORMAL, this); dropship_path_length = trace_fraction * vlen(endorigin - startorigin); @@ -42,6 +72,8 @@ entity dropship_initialize() endorigin = trace_endpos; dropship_path_direction = normalize(endorigin - startorigin); + setsize(this, saved_mins, saved_maxs); + setorigin(this, startorigin); this.angles = vectoangles(dropship_path_direction); this.velocity = '0 0 0'; @@ -147,13 +179,13 @@ vector dropship_seekPoint(entity this, vector orig, int axis, int direction, flo vector second_end = '0 0 0'; first_end = orig; - first_end = first_end - first_end * vec_axis * vec_axis + world.maxs * vec_axis * vec_axis; + first_end = first_end - first_end * vec_axis * vec_axis + 65536 * vec_axis; first_fraction = (tracebox(orig, this.mins, this.maxs, first_end, MOVE_NORMAL, this), trace_fraction); if(direction != 2) { second_end = orig; - second_end = second_end - second_end * vec_axis * vec_axis + world.mins * vec_axis * vec_axis; + second_end = second_end - second_end * vec_axis * vec_axis + -65536 * vec_axis; second_fraction = (tracebox(orig, this.mins, this.maxs, second_end, MOVE_NORMAL, this), trace_fraction); } -- 2.39.2