]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
improve dropping from dropship
authorJuhu <5894800-Juhu_@users.noreply.gitlab.com>
Tue, 16 May 2023 12:13:02 +0000 (14:13 +0200)
committerJuhu <5894800-Juhu_@users.noreply.gitlab.com>
Tue, 16 May 2023 15:54:19 +0000 (17:54 +0200)
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
qcsrc/common/gamemodes/gamemode/br/sv_dropship.qc

index 0f416376668b142df0b546267928448464a0233e..82586602765c561d150ada309de2ca5c76b20317 100644 (file)
@@ -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';
index 01ce3bd8ef8746d37f9e3069b69e84474e62ed48..df06720fb82477e7a81a9413e9dc6d77af885ac9 100644 (file)
@@ -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);
     }