]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'TimePath/cleanup'
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 08:40:25 +0000 (19:40 +1100)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 11 Oct 2015 08:40:25 +0000 (19:40 +1100)
34 files changed:
defaultXonotic.cfg
physics.cfg
physicsCPMA.cfg
physicsFruit.cfg
physicsHavoc.cfg
physicsLeeStricklin-ModdedFruit.cfg
physicsLeeStricklin.cfg
physicsLeeStricklinOld.cfg
physicsLzd.cfg
physicsNexuiz10.cfg
physicsNexuiz11.cfg
physicsNexuiz151.cfg
physicsNexuiz151b.cfg
physicsNexuiz16rc1.cfg
physicsNexuiz20.cfg
physicsNexuiz25.cfg
physicsNexuiz26.cfg
physicsNoQWBunny-nexbased.cfg
physicsQ.cfg
physicsQ2.cfg
physicsQ2a.cfg
physicsQ3.cfg
physicsQBF.cfg
physicsQBFplus.cfg
physicsSamual.cfg
physicsWarsow.cfg
physicsWarsowClassicBunny.cfg
physicsWarsowDev.cfg
qcsrc/common/minigames/minigame/c4.qc
qcsrc/common/minigames/minigame/snake.qc
qcsrc/common/minigames/sv_minigames.qc
qcsrc/common/physics.qc
qcsrc/common/physics.qh
qcsrc/common/stats.qh

index 0afdb7af70254056edf38c1153d4bc057fa55993..3735e55349da0713a11e59317ead64ebe0d13610 100644 (file)
@@ -305,6 +305,7 @@ set sv_doublejump 0 "allow Quake 2-style double jumps"
 set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
 set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
 set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
+set sv_track_canjump 0 "track if the player released the jump key between 2 jumps to decide if they are able to jump or not"
 
 seta sv_precacheplayermodels 1
 seta sv_precacheweapons 0
index 58d1b1f81d058263aa59c1ddd779f758c72b7e21..e9fe5628940d9597fd5843533b54bced13066ae0 100644 (file)
@@ -38,6 +38,7 @@ set g_physics_xonotic_accelerate 15
 set g_physics_xonotic_stopspeed 100
 set g_physics_xonotic_airaccelerate 2
 set g_physics_xonotic_airstopaccelerate 3
+set g_physics_xonotic_track_canjump 0
 
 // ========
 //  Nexuiz
@@ -65,6 +66,7 @@ set g_physics_nexuiz_accelerate 8
 set g_physics_nexuiz_stopspeed 100
 set g_physics_nexuiz_airaccelerate 5.5
 set g_physics_nexuiz_airstopaccelerate 0
+set g_physics_nexuiz_track_canjump 0
 
 // =======
 //  Quake
@@ -92,6 +94,7 @@ set g_physics_quake_accelerate 10
 set g_physics_quake_stopspeed 100
 set g_physics_quake_airaccelerate 106.66666666666666666666
 set g_physics_quake_airstopaccelerate 0
+set g_physics_quake_track_canjump 1
 
 // ========
 //  Warsow
@@ -119,6 +122,7 @@ set g_physics_warsow_accelerate 15
 set g_physics_warsow_stopspeed 100
 set g_physics_warsow_airaccelerate 1
 set g_physics_warsow_airstopaccelerate 2.5
+set g_physics_warsow_track_canjump 0
 
 // ========
 //  DeFrag
@@ -146,6 +150,7 @@ set g_physics_defrag_accelerate 15
 set g_physics_defrag_stopspeed 100
 set g_physics_defrag_airaccelerate 1
 set g_physics_defrag_airstopaccelerate 2.5
+set g_physics_defrag_track_canjump 0
 
 // =========
 //  Quake 3
@@ -173,6 +178,7 @@ set g_physics_quake3_accelerate 10
 set g_physics_quake3_stopspeed 100
 set g_physics_quake3_airaccelerate 1
 set g_physics_quake3_airstopaccelerate 0
+set g_physics_quake3_track_canjump 1
 
 // ========
 //  Vecxis
@@ -200,6 +206,7 @@ set g_physics_vecxis_accelerate 5.5
 set g_physics_vecxis_stopspeed 100
 set g_physics_vecxis_airaccelerate 5.5
 set g_physics_vecxis_airstopaccelerate 0
+set g_physics_vecxis_track_canjump 0
 
 // =========
 //  Quake 2
@@ -227,6 +234,7 @@ set g_physics_quake2_accelerate 10
 set g_physics_quake2_stopspeed 100
 set g_physics_quake2_airaccelerate 1
 set g_physics_quake2_airstopaccelerate 0
+set g_physics_quake2_track_canjump 1
 
 // =======
 //  Bones
@@ -254,3 +262,4 @@ set g_physics_bones_accelerate 15
 set g_physics_bones_stopspeed 100
 set g_physics_bones_airaccelerate 1
 set g_physics_bones_airstopaccelerate 2.5
+set g_physics_bones_track_canjump 0
index 9734cfc6f6ccc1180a9925105814321f1d5ed69f..e4bbad3d48630aa95c9f3463fdd1d327c7323a12 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 400
+sv_track_canjump 0
index 5f65d66d8ab36e6b6e2349174c15431ea20e6e3f..ee44b5547a052717cde7f28fb0f52063e638c65f 100644 (file)
@@ -33,3 +33,4 @@ sv_jumpspeedcap_min 0 // need predicting? (it should already be in CSQC predicti
 sv_jumpspeedcap_max 0.35
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+sv_track_canjump 0
index f107158720dc50d26d0dcc014a5a4eb23ae8ddbe..6aac341780e7573cbe580b714e62b747d61e6612 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 3553a94a7e587a415a24613aaf735392622e6a53..90eaa49c1223cd4bacf7aa7e228dc4670f88240b 100644 (file)
@@ -42,3 +42,4 @@ sv_jumpspeedcap_min 0 // need predicting? (it should already be in CSQC predicti
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+sv_track_canjump 0
index e4aef4440d6b5b173e141962d3e429077216ab31..03081fdab7554b9c5118b795ac8b86987ff966a6 100644 (file)
@@ -42,3 +42,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+sv_track_canjump 0
index eda92ac6930431893efd7865b83f26d45efecffc..ef213a70f9d356226b401c0779752d85d69c7157 100644 (file)
@@ -37,3 +37,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max 0.38
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index cd76c2fe39f557fd6bb50133fddc8dad880dc1e6..51c49d7832dbf0197ca6a2ab5d456389ce675ebf 100644 (file)
@@ -35,3 +35,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 6c99b307f00f74d41e90e6d95b5db96dcacb2e20..0ce33aa95132362f57bb28eeec904c6549bed91e 100644 (file)
@@ -35,3 +35,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 65a6a4b6fc40b9a67fc91d4936cee4095e32ebd2..08711fd5b0f6905b33ff2688261f0e0543611922 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 833a67dce383f608a8051938cdffa905d55f3d4d..092985cae51a00a87a76cf26a78519c9f5d3f127 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 31380c973828580dc2fe523cac5715e59e8ab020..c6d9bef4b912d82e5200691d82a3fb55627b4d88 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index f3a85e50b7cf4d03556fd315f7b731b5d4125ec6..5e0ee6ae0c6f265690c3783be05c3d10f35a1d19 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 60071e1844026fb1bb9fb04e695d19247295f33b..d129a2db05ebada4a9698aeafcfedbb9456ac2d9 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index dd984bb310c1a8c2299df157edc8b751e20d05d5..8a52299763d537423fb2012f6a9ed304c969ef0e 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 827bbc55c16501e6ee64e509b4313f8612a0d3c4..4df3f211ebe490134394e21d60a35a0b739fae6b 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index f8d43c4f2ece249c7fe52776ce6bae5c7577a535..3e905428f76d52f1183cde4fc116ccabc0268afa 100644 (file)
@@ -43,3 +43,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 1
 g_teleport_maxspeed 0
+sv_track_canjump 0
index c26745629677cf209b65c223eb60d5abfd6a9436..448e087f46f20c1d0287dfd29c9a605a93266fcc 100644 (file)
@@ -35,3 +35,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 05e2f1456cdd5152935fe084e730f717069dc4cd..124c50660a1046ca8bf9ce7245a4d9579a0ff71c 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 9b953e32e8b78b8852f663ed4e55668da55a1b1a..580f6257fa65f2bde52c74983f72492e45456f2f 100644 (file)
@@ -35,3 +35,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index eed1c7409008447be660d6b84b73e57da536d11f..6f00896b671b4b542115d6270c96b4bac7d08c20 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 320
+sv_track_canjump 0
index 8dff0edd9df5d208440a721a04fce1e236a5722a..31963e9feee4dc1dc6691514a081bde9d3765c7f 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 634b6083ee6c910a69442de8430c8251e2781bb7..82463859835480526e90bbae65db204238344fd7 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 8019089bf216f7eb5749c8d12064a494ca0f7edd..6858892e3b3ad27b1c8a8e8d4257c7a650e269c6 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 7d66b3716d987f96d48687973d7c09cfc7f1011d..50101d73d43165843ecf32f08b55fb33aff8fb2d 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 1dbb14a90fb4f87d31359ee48ee84ea32ae11231..c4c3535a7f9ac1c74d3daa7a7c7645f4daaa9e27 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index f2f989d7580295a9ea237701d240ab7084dc7bb0..331723ec9317539cbc2b2e4bdc139a99b52abb94 100644 (file)
@@ -34,3 +34,4 @@ sv_jumpspeedcap_min ""
 sv_jumpspeedcap_max ""
 sv_jumpspeedcap_max_disable_on_ramps 0
 g_teleport_maxspeed 0
+sv_track_canjump 0
index 98020972a742ee5a59e4eef24e69a7a483f6e69c..a7ba05068ac85e929d607a43e7d0028c4385edac 100644 (file)
@@ -3,7 +3,6 @@ REGISTER_MINIGAME(c4, "Connect Four");
 const float C4_TURN_PLACE = 0x0100; // player has to place a piece on the board
 const float C4_TURN_WIN   = 0x0200; // player has won
 const float C4_TURN_DRAW  = 0x0400; // no moves are possible
-const float C4_TURN_TYPE  = 0x0f00; // turn type mask
 
 const float C4_TURN_TEAM1 = 0x0001;
 const float C4_TURN_TEAM2 = 0x0002;
index bef26caaa53cbc8ad2489b5604081470e47a384b..cbb13420fb1573ad76e31e2b7eb6a1057e0fa51c 100644 (file)
@@ -1,10 +1,12 @@
-REGISTER_MINIGAME(snake, "Snake");
+REGISTER_MINIGAME(snake, "Snake"); // SNAAAAKE
 
 const float SNAKE_TURN_MOVE  = 0x0100; // the snake is moving, player must control it
-const float SNAKE_TURN_LOSS  = 0x0200; // they did it?!
-const float SNAKE_TURN_WAIT  = 0x0400; // the snake is waiting for the player to make their first move and begin the game
+const float SNAKE_TURN_WIN   = 0x0200; // multiplayer victory
+const float SNAKE_TURN_LOSS  = 0x0400; // they did it?!
 const float SNAKE_TURN_TYPE  = 0x0f00; // turn type mask
 
+const int SNAKE_TURN_TEAM  = 0x000f; // turn team mask
+
 const int SNAKE_SF_PLAYERSCORE = MINIG_SF_CUSTOM;
 
 const int SNAKE_LET_CNT = 15;
@@ -12,18 +14,38 @@ const int SNAKE_NUM_CNT = 15;
 
 const int SNAKE_TILE_SIZE = 15;
 
+const int SNAKE_TEAMS = 6;
+
 bool autocvar_sv_minigames_snake_wrap = false;
 float autocvar_sv_minigames_snake_delay_initial = 0.7;
 float autocvar_sv_minigames_snake_delay_multiplier = 50;
 float autocvar_sv_minigames_snake_delay_min = 0.1;
+int autocvar_sv_minigames_snake_lives = 3;
 
 .int snake_score;
-.entity snake_head;
 
 .float snake_delay;
-.float snake_nextmove;
 .vector snake_dir;
 
+.entity snake_next, snake_last, snake_prev;
+
+.bool snake_tail;
+
+.int snake_lives[SNAKE_TEAMS + 1];
+
+.int snake_lost_teams;
+
+bool snake_alone(entity minig)
+{
+       int headcount = 0;
+       entity e = world;
+       while ( ( e = findentity(e,owner,minig) ) )
+               if ( e.classname == "minigame_board_piece" && e.cnt == 1 )
+                       ++headcount;
+
+       return headcount <= 1;
+}
+
 // find same game piece given its tile name
 entity snake_find_piece(entity minig, string tile)
 {
@@ -35,11 +57,11 @@ entity snake_find_piece(entity minig, string tile)
 }
 
 // find same game piece given its cnt
-entity snake_find_cnt(entity minig, int tile)
+entity snake_find_cnt(entity minig, int steam, int tile)
 {
        entity e = world;
        while ( ( e = findentity(e,owner,minig) ) )
-               if ( e.classname == "minigame_board_piece" && e.cnt == tile )
+               if ( e.classname == "minigame_board_piece" && e.cnt == tile && e.team == steam )
                        return e;
        return world;
 }
@@ -54,6 +76,15 @@ bool snake_valid_tile(string tile)
        return 0 <= number && number < SNAKE_NUM_CNT && 0 <= letter && letter < SNAKE_LET_CNT;
 }
 
+entity snake_find_head(entity minig, int steam)
+{
+       entity e = world;
+       while ( ( e = findentity(e,owner,minig) ) )
+               if ( e.classname == "minigame_board_piece" && e.cnt == 1 && e.team == steam )
+                       return e;
+       return world;
+}
+
 void snake_new_mouse(entity minigame)
 {
        RandomSelection_Init();
@@ -67,184 +98,297 @@ void snake_new_mouse(entity minigame)
        }
 
        entity piece = msle_spawn(minigame,"minigame_board_piece");
-       piece.team = 1;
+       piece.team = 0;
        piece.netname = strzone(RandomSelection_chosen_string);
        minigame_server_sendflags(piece,MINIG_SF_ALL);
 
        minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
 }
 
-void snake_move_head(entity minigame);
+entity snake_get_player(entity minigame, int pteam);
+int snake_winning_team(entity minigame)
+{
+       int winning_team = 0;
+       for(int i = 1; i <= SNAKE_TEAMS; ++i)
+       {
+               entity pl = snake_get_player(minigame, i);
+               if(pl && minigame.snake_lives[i] > 0)
+               {
+                       if(winning_team)
+                               return 0;
+                       winning_team = i;
+               }
+       }
+
+       return winning_team;
+}
+
+void snake_check_winner(entity minigame)
+{
+       if(snake_alone(minigame) && !minigame.snake_lost_teams)
+               return;
+
+       int winner = snake_winning_team(minigame);
+
+       int alivecnt = 0;
+       for(int i = 1; i <= SNAKE_TEAMS; ++i)
+       {
+               entity pl = snake_get_player(minigame, i);
+               if(pl && minigame.snake_lives[i] > 0)
+                       ++alivecnt;
+       }
+
+       if(!alivecnt)
+       {
+               minigame.minigame_flags = SNAKE_TURN_LOSS;
+               minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+               return;
+       }
+
+       if(winner)
+       {
+               minigame.minigame_flags = SNAKE_TURN_WIN | winner;
+               minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+       }
+}
+
+void snake_move_head(entity minigame, entity head);
 void snake_head_think()
 {
        entity minigame = self.owner;
 
        if(minigame.minigame_flags & SNAKE_TURN_MOVE)
-               snake_move_head(minigame);
+               snake_move_head(minigame, self);
 
-       self.nextthink = time + minigame.snake_delay;
+       snake_check_winner(minigame);
+
+       self.nextthink = time + self.snake_delay;
 }
 
-void snake_setup_pieces(entity minigame)
+void minigame_setup_snake(entity minigame, int pteam)
 {
-       int targnum = bound(1, floor(random() * SNAKE_NUM_CNT), SNAKE_NUM_CNT - 1);
-       int targlet = bound(1, floor(random() * SNAKE_LET_CNT), SNAKE_LET_CNT - 1);
+       RandomSelection_Init();
+       int i, j;
+       for(i = 1; i < SNAKE_LET_CNT - 1; ++i)
+       for(j = 1; j < SNAKE_NUM_CNT - 1; ++j)
+       {
+               string pos = minigame_tile_buildname(i, j);
+               if(!snake_find_piece(minigame, pos))
+                       RandomSelection_Add(world, 0, pos, 1, 1);
+       }
 
        entity piece = msle_spawn(minigame,"minigame_board_piece");
-       piece.team = 1; // init default team?
-       piece.netname = strzone(minigame_tile_buildname(targlet,targnum));
+       piece.team = pteam;
+       piece.netname = strzone(RandomSelection_chosen_string);
        piece.cnt = 1;
+       piece.snake_next = world;
+       piece.snake_prev = world;
+       piece.snake_last = piece;
        piece.think = snake_head_think;
+       piece.snake_delay = autocvar_sv_minigames_snake_delay_initial;
        piece.nextthink = time + 0.1;
        minigame_server_sendflags(piece,MINIG_SF_ALL);
+}
 
-       minigame.snake_head = piece;
-
+void snake_setup_pieces(entity minigame)
+{
        snake_new_mouse(minigame);
 
        minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
 }
 
-void snake_add_score(entity minigame, int thescore)
+entity snake_get_player(entity minigame, int pteam)
+{
+       entity e;
+#ifdef SVQC
+       for(e = minigame.minigame_players; e; e = e.list_next)
+#elif defined(CSQC)
+       e = world;
+       while( (e = findentity(e,owner,minigame)) )
+               if ( e.classname == "minigame_player" )
+#endif
+       if(e.team == pteam)
+               return e;
+       return world;
+}
+
+void snake_add_score(entity minigame, int pteam, int thescore)
 {
 #ifdef SVQC
        if(!minigame)
                return;
-       if(minigame.minigame_players)
+       entity pl = snake_get_player(minigame, pteam);
+       if(pl)
        {
-               minigame.minigame_players.snake_score += thescore;
-               minigame.minigame_players.SendFlags |= SNAKE_SF_PLAYERSCORE;
+               pl.snake_score += thescore;
+               pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
        }
 #endif
 }
 
-void snake_move_body(entity minigame, bool ate_mouse)
+void snake_move_body(entity minigame, entity head, bool ate_mouse)
 {
-       entity tail = world;
-       string tailpos = string_null;
-       vector taildir = '0 0 0';
-
-       int i, pieces = 0;
-       for(i = (SNAKE_NUM_CNT * SNAKE_LET_CNT); i >= 2; --i)
+       for(entity e = head.snake_last; e; e = e.snake_prev)
        {
-               entity piece = snake_find_cnt(minigame, i);
-               entity nextpiece = snake_find_cnt(minigame, i - 1);
-               if(!piece)
-                       continue;
+               if(!e || e == head) { break; }
 
-               pieces++;
+               entity nextpiece = e.snake_prev; // can be head
 
-               if(!tail)
-               {
-                       tail = piece;
-                       tailpos = piece.netname;
-                       taildir = piece.snake_dir;
-               }
-
-               if(piece.netname) { strunzone(piece.netname); }
-               piece.netname = strzone(nextpiece.netname);
-               piece.snake_dir = nextpiece.snake_dir;
-               minigame_server_sendflags(piece, MINIG_SF_ALL);
+               if(e.netname) { strunzone(e.netname); }
+               e.netname = strzone(nextpiece.netname);
+               e.snake_dir = nextpiece.snake_dir;
+               minigame_server_sendflags(e, MINIG_SF_UPDATE);
        }
 
-       // just a head
-       if(!pieces)
+       if(ate_mouse)
        {
-               tail = minigame.snake_head;
-               tailpos = minigame.snake_head.netname;
-               taildir = minigame.snake_head.snake_dir;
-       }
+               entity tail = head.snake_last;
+
+               tail.snake_tail = false;
 
-       if(tail && ate_mouse)
-       {
                int newcnt = tail.cnt + 1;
-               minigame.snake_delay = max(autocvar_sv_minigames_snake_delay_min, autocvar_sv_minigames_snake_delay_initial - (newcnt / autocvar_sv_minigames_snake_delay_multiplier));
-               snake_add_score(minigame, 1);
+               head.snake_delay = max(autocvar_sv_minigames_snake_delay_min, autocvar_sv_minigames_snake_delay_initial - (newcnt / autocvar_sv_minigames_snake_delay_multiplier));
+               snake_add_score(minigame, head.team, 1);
 
                entity piece = msle_spawn(minigame,"minigame_board_piece");
                piece.cnt = newcnt;
-               piece.team = 1;
-               piece.snake_dir = taildir;
-               piece.netname = strzone(tailpos);
-               minigame_server_sendflags(piece,MINIG_SF_ALL);
+               piece.team = head.team;
+               piece.snake_prev = tail;
+               piece.snake_dir = tail.snake_dir;
+               piece.snake_next = world;
+               piece.snake_tail = true;
+               piece.netname = strzone(tail.netname);
 
-               minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+               tail.snake_next = piece;
+               head.snake_last = piece;
+
+               minigame_server_sendflags(piece,MINIG_SF_UPDATE);
+
+               //minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
        }
 }
 
-void snake_move_head(entity minigame)
+void snake_eat_team(entity minigame, int pteam)
 {
-       entity head = minigame.snake_head;
+       entity head = snake_find_head(minigame, pteam);
+       if(!head) { return; }
+
+       minigame.snake_lives[pteam] -= 1;
+
+       entity pl = snake_get_player(minigame, pteam);
+#ifdef SVQC
+       pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
+#endif
+
+       head.nextthink = time + 1; // make sure they don't to eat us somehow
+
+       entity e = world;
+       while ( ( e = findentity(e,owner,minigame) ) )
+               if ( e.classname == "minigame_board_piece" && e.cnt && e.team == pteam )
+               {
+                       if(e.netname) { strunzone(e.netname); }
+                       remove(e);
+               }
+
+       if(minigame.snake_lives[pteam] <= 0)
+               minigame.snake_lost_teams |= BIT(pteam);
+
+       if(pl && minigame.snake_lives[pteam] > 0)
+               minigame_setup_snake(minigame, pteam);  
+}
+
+void snake_move_head(entity minigame, entity head)
+{
+       if(!head.snake_dir_x && !head.snake_dir_y)
+               return; // nope!
+
        string newpos;
 
        if(autocvar_sv_minigames_snake_wrap)
-               newpos = minigame_relative_tile(head.netname, minigame.snake_dir_x, minigame.snake_dir_y, SNAKE_NUM_CNT, SNAKE_LET_CNT);
+               newpos = minigame_relative_tile(head.netname, head.snake_dir_x, head.snake_dir_y, SNAKE_NUM_CNT, SNAKE_LET_CNT);
        else
        {
                int myx = minigame_tile_letter(head.netname);
                int myy = minigame_tile_number(head.netname);
 
-               myx += minigame.snake_dir_x;
-               myy += minigame.snake_dir_y;
+               myx += head.snake_dir_x;
+               myy += head.snake_dir_y;
 
                newpos = minigame_tile_buildname(myx, myy);
        }
 
-       if(!snake_valid_tile(newpos) || (snake_find_piece(minigame, newpos)).cnt)
+       entity hit = snake_find_piece(minigame, newpos);
+
+       if(!snake_valid_tile(newpos) || (hit && hit.cnt && hit.team == head.team))
        {
-               minigame.minigame_flags = SNAKE_TURN_LOSS;
-               minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+               if(snake_alone(minigame))
+               {
+                       minigame.minigame_flags = SNAKE_TURN_LOSS;
+                       minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
+               }
+               else
+               {
+                       snake_add_score(minigame, head.team, -1);
+                       snake_eat_team(minigame, head.team);
+               }
+
                return;
        }
 
-       bool ate_mouse = false;
-       entity piece = snake_find_piece(minigame, newpos);
-       if(piece && !piece.cnt)
-               ate_mouse = true;
+       bool ate_mouse = (hit && !hit.cnt);
 
        // move the body first, then set the new head position?
-       snake_move_body(minigame, ate_mouse);
+       snake_move_body(minigame, head, ate_mouse);
+
+       if(head.netname) { strunzone(head.netname); }
+       head.netname = strzone(newpos);
+       minigame_server_sendflags(head,MINIG_SF_UPDATE);
+
+       // above check makes sure it's not our team
+       if(hit.cnt)
+       {
+               snake_eat_team(minigame, hit.team);
+               snake_add_score(minigame, head.team, 1);
+       }
 
        if(ate_mouse)
        {
-               if(piece.netname) { strunzone(piece.netname); }
-               remove(piece);
+               if(hit.netname) { strunzone(hit.netname); }
+               remove(hit);
 
                snake_new_mouse(minigame);
        }
-
-       if(head.netname) { strunzone(head.netname); }
-       head.netname = strzone(newpos);
-       minigame_server_sendflags(head,MINIG_SF_ALL);
 }
 
 // make a move
 void snake_move(entity minigame, entity player, string dxs, string dys )
 {
-       if ( (minigame.minigame_flags & SNAKE_TURN_MOVE) || (minigame.minigame_flags & SNAKE_TURN_WAIT) )
+       if ( minigame.minigame_flags & SNAKE_TURN_MOVE )
        if ( dxs || dys )
        {
                //if ( snake_valid_tile(pos) )
                //if ( snake_find_piece(minigame, pos) )
                {
+                       entity head = snake_find_head(minigame, player.team);
+                       if(!head)
+                               return; // their head is already dead
+
                        int dx = ((dxs) ? bound(-1, stof(dxs), 1) : 0);
                        int dy = ((dys) ? bound(-1, stof(dys), 1) : 0);
 
-                       int myl = minigame_tile_letter(minigame.snake_head.netname);
-                       int myn = minigame_tile_number(minigame.snake_head.netname);
+                       int myl = minigame_tile_letter(head.netname);
+                       int myn = minigame_tile_number(head.netname);
 
-                       entity head = snake_find_piece(minigame, minigame_tile_buildname(myl + dx, myn + dy));
-                       if(head && head.cnt == 2)
+                       entity check_piece = snake_find_piece(minigame, minigame_tile_buildname(myl + dx, myn + dy));
+                       if(check_piece && check_piece.cnt == 2)
                                return; // nope!
 
-                       if(minigame.minigame_flags & SNAKE_TURN_WAIT)
-                               minigame.snake_nextmove = time;
-                       minigame.minigame_flags = SNAKE_TURN_MOVE;
-                       minigame.snake_dir_x = dx;
-                       minigame.snake_dir_y = dy;
-                       minigame.snake_dir_z = 0;
-                       minigame.snake_head.snake_dir = minigame.snake_dir;
-                       minigame_server_sendflags(minigame.snake_head,MINIG_SF_UPDATE);
+                       if(head.snake_dir == '0 0 0')
+                               head.nextthink = time; // TODO: make sure this can't be exploited!
+                       head.snake_dir_x = dx;
+                       head.snake_dir_y = dy;
+                       head.snake_dir_z = 0;
+                       minigame_server_sendflags(head,MINIG_SF_UPDATE);
                        minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
                }
        }
@@ -261,8 +405,17 @@ int snake_server_event(entity minigame, string event, ...)
                case "start":
                {
                        snake_setup_pieces(minigame);
-                       minigame.snake_delay = autocvar_sv_minigames_snake_delay_initial;
-                       minigame.minigame_flags = SNAKE_TURN_WAIT;
+                       minigame.minigame_flags = SNAKE_TURN_MOVE;
+                       minigame.snake_lost_teams = 0;
+
+                       if(SNAKE_TEAMS > 1)
+                       {
+                               for(int i = 1; i <= SNAKE_TEAMS; ++i)
+                                       minigame.snake_lives[i] = autocvar_sv_minigames_snake_lives;
+                       }
+                       else
+                               minigame.snake_lives[1] = 1;
+                       
                        return true;
                }
                case "end":
@@ -274,19 +427,39 @@ int snake_server_event(entity minigame, string event, ...)
                                if(e.netname) { strunzone(e.netname); }
                                remove(e);
                        }
-                       minigame.snake_head = world;
                        return false;
                }
                case "join":
                {
                        int pl_num = minigame_count_players(minigame);
 
-                       // Don't allow more than 1 player
-                       // not sure if this should be a multiplayer game (might get crazy)
-                       if(pl_num >= 1) { return false; }
+                       if(pl_num >= SNAKE_TEAMS) { return false; }
 
-                       // Team 1 by default
-                       return 1;
+                       int t = 1; // Team 1 by default
+
+                       for(int i = 1; i <= SNAKE_TEAMS; ++i)
+                       {
+                               entity e = snake_get_player(minigame, i);
+                               if(!e)
+                               {
+                                       t = i;
+                                       break;
+                               }
+                       }
+
+                       if(!snake_find_head(minigame, t) && !(minigame.snake_lost_teams & BIT(t)))
+                       {
+                               entity pl = ...(1,entity);
+                               if(pl)
+                               {
+                                       //pl.snake_lives = ((SNAKE_TEAMS > 1) ? autocvar_sv_minigames_snake_lives : 1);
+                                       // send score anyway, lives are set
+                                       pl.SendFlags |= SNAKE_SF_PLAYERSCORE;
+                               }
+                               minigame_setup_snake(minigame, t);
+                       }
+
+                       return t;
                }
                case "cmd":
                {
@@ -305,13 +478,26 @@ int snake_server_event(entity minigame, string event, ...)
                        int sf = ...(1,int);
                        if ( sent.classname == "minigame_board_piece" && (sf & MINIG_SF_UPDATE) )
                        {
+                               int letter = minigame_tile_letter(sent.netname);
+                               int number = minigame_tile_number(sent.netname);
+
+                               WriteByte(MSG_ENTITY,letter);
+                               WriteByte(MSG_ENTITY,number);
+
                                WriteByte(MSG_ENTITY,sent.cnt);
-                               WriteCoord(MSG_ENTITY,sent.snake_dir_x);
-                               WriteCoord(MSG_ENTITY,sent.snake_dir_y);
+                               WriteByte(MSG_ENTITY,sent.snake_tail);
+
+                               int dx = sent.snake_dir_x;
+                               int dy = sent.snake_dir_y;
+                               if(dx == -1) dx = 2;
+                               if(dy == -1) dy = 2;
+                               WriteByte(MSG_ENTITY,dx);
+                               WriteByte(MSG_ENTITY,dy);
                        }
                        else if ( sent.classname == "minigame_player" && (sf & SNAKE_SF_PLAYERSCORE ) )
                        {
                                WriteLong(MSG_ENTITY,sent.snake_score);
+                               WriteByte(MSG_ENTITY,max(0, minigame.snake_lives[sent.team]));
                        }
                        else if ( sent.classname == "minigame" && (sf & MINIG_SF_UPDATE ) )
                        {
@@ -332,6 +518,21 @@ vector snake_boardsize;// HUD board size
 
 bool snake_wrap;
 
+vector snake_teamcolor(int steam)
+{
+       switch(steam)
+       {
+               case 1: return '1 0 0';
+               case 2: return '0 0 1';
+               case 3: return '1 1 0';
+               case 4: return '1 0 1';
+               case 5: return '0 1 0';
+               case 6: return '0 1 1';
+       }
+
+       return '1 1 1';
+}
+
 // Required function, draw the game board
 void snake_hud_board(vector pos, vector mySize)
 {
@@ -344,18 +545,6 @@ void snake_hud_board(vector pos, vector mySize)
        vector tile_size = minigame_hud_denormalize_size('1 1 0' / SNAKE_TILE_SIZE,pos,mySize);
        vector tile_pos;
 
-       entity tail = world;
-       int i;
-       for(i = (SNAKE_NUM_CNT * SNAKE_LET_CNT); i >= 2; --i)
-       {
-               entity piece = snake_find_cnt(active_minigame, i);
-               if(piece)
-               {
-                       tail = piece;
-                       break;
-               }
-       }
-
        entity e;
        FOREACH_MINIGAME_ENTITY(e)
        {
@@ -363,10 +552,13 @@ void snake_hud_board(vector pos, vector mySize)
                {
                        tile_pos = minigame_tile_pos(e.netname,SNAKE_NUM_CNT,SNAKE_LET_CNT);
                        tile_pos = minigame_hud_denormalize(tile_pos,pos,mySize);
+
+                       vector tile_color = snake_teamcolor(e.team);
+
                        string thepiece = "snake/mouse";
                        if(e.cnt)
                                thepiece = "snake/body";
-                       if(tail && e.cnt == tail.cnt)
+                       if(e.snake_tail)
                                thepiece = "snake/tail";
                        if(e.cnt == 1)
                        {
@@ -374,7 +566,7 @@ void snake_hud_board(vector pos, vector mySize)
                                int dy = minigame_tile_number(e.netname) + e.snake_dir_y * 2;
                                entity mouse = snake_find_piece(active_minigame, minigame_tile_buildname(dx, dy));
                                thepiece = "snake/head";
-                               if(mouse && !mouse.cnt)
+                               if(mouse && mouse.team != e.team)
                                {
                                        float myang = 0;
                                        int myx = minigame_tile_letter(e.netname);
@@ -394,20 +586,20 @@ void snake_hud_board(vector pos, vector mySize)
                                        my_pos = minigame_hud_denormalize(my_pos,pos,mySize);
 
                                        drawrotpic(my_pos, myang, minigame_texture("snake/tongue"),
-                                                       tile_size, tile_size/2, '1 1 1',
+                                                       tile_size, tile_size/2, tile_color,
                                                        panel_fg_alpha, DRAWFLAG_NORMAL );
                                }
                        }
 
-                       if(e.cnt == 1 || e.cnt == tail.cnt)
+                       if(e.cnt == 1 || e.snake_tail)
                        {
                                vector thedir = e.snake_dir;
                                float theang = 0;
-                               if(e.cnt == tail.cnt)
+                               if(e.snake_tail)
                                {
                                        int thex = minigame_tile_letter(e.netname);
                                        int they = minigame_tile_number(e.netname);
-                                       entity t = snake_find_cnt(active_minigame, e.cnt - 1);
+                                       entity t = snake_find_cnt(active_minigame, e.team, e.cnt - 1);
                                        int tx = minigame_tile_letter(t.netname);
                                        int ty = minigame_tile_number(t.netname);
 
@@ -436,39 +628,43 @@ void snake_hud_board(vector pos, vector mySize)
                                        theang = M_PI*3/2;
 
                                drawrotpic(tile_pos, theang, minigame_texture(thepiece),
-                                                       tile_size, tile_size/2, '1 1 1',
+                                                       tile_size, tile_size/2, tile_color,
                                                        panel_fg_alpha, DRAWFLAG_NORMAL );
                        }
                        else
                        {
                                minigame_drawpic_centered( tile_pos,  
                                                minigame_texture(thepiece),
-                                               tile_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
+                                               tile_size, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
                        }
                }
        }
 
-       if ( active_minigame.minigame_flags & SNAKE_TURN_LOSS )
+       if ( (active_minigame.minigame_flags & SNAKE_TURN_LOSS) || (active_minigame.minigame_flags & SNAKE_TURN_WIN) || (active_minigame.snake_lives[minigame_self.team] <= 0) )
        {
-               int scores = 0;
-               FOREACH_MINIGAME_ENTITY(e)
-                       if(e.classname == "minigame_player")
-                               scores = e.snake_score;
+               int scores = minigame_self.snake_score;
 
                vector winfs = hud_fontsize*2;
-               string scores_text;
+               string scores_text, victory_text;
+               victory_text = "Game over!";
                scores_text = strcat("Score: ", ftos(scores));
+
+               if(active_minigame.minigame_flags & SNAKE_TURN_WIN)
+               if((active_minigame.minigame_flags & SNAKE_TURN_TEAM) == minigame_self.team)
+                       victory_text = "You win!";
+               if(active_minigame.snake_lives[minigame_self.team] <= 0)
+                       victory_text = "You ran out of lives!";
                
                vector win_pos = pos+eY*(mySize_y-winfs_y)/2;
                vector win_sz;
                win_sz = minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
-                       sprintf("Game over! %s", scores_text), 
+                       sprintf("%s %s", victory_text, scores_text), 
                        winfs, 0, DRAWFLAG_NORMAL, 0.5);
                
                drawfill(win_pos-eY*hud_fontsize_y,win_sz+2*eY*hud_fontsize_y,'0.3 0.3 1',0.8,DRAWFLAG_ADDITIVE);
                
                minigame_drawcolorcodedstring_wrapped(mySize_x,win_pos,
-                       sprintf("Game over! %s", scores_text), 
+                       sprintf("%s %s", victory_text, scores_text), 
                        winfs, panel_fg_alpha, DRAWFLAG_NORMAL, 0.5);
        }
 }
@@ -481,17 +677,19 @@ void snake_hud_status(vector pos, vector mySize)
        vector ts;
        ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
                hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
-       
+
        pos_y += ts_y;
        mySize_y -= ts_y;
-       
+
        vector player_fontsize = hud_fontsize * 1.75;
-       ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
+       ts_y = ( mySize_y - 2*player_fontsize_y ) / SNAKE_TEAMS;
        ts_x = mySize_x;
        vector mypos;
        vector tile_size = '48 48 0';
 
        mypos = pos;
+       if ( minigame_self.team > 1 )
+               mypos_y  += player_fontsize_y + (ts_y * (minigame_self.team - 1));
        drawfill(mypos,eX*mySize_x+eY*player_fontsize_y,'1 1 1',0.5,DRAWFLAG_ADDITIVE);
        mypos_y += player_fontsize_y;
        drawfill(mypos,eX*mySize_x+eY*tile_size_y,'1 1 1',0.25,DRAWFLAG_ADDITIVE);
@@ -502,19 +700,28 @@ void snake_hud_status(vector pos, vector mySize)
                if ( e.classname == "minigame_player" )
                {
                        mypos = pos;
+                       if ( e.team > 1 )
+                               mypos_y  += player_fontsize_y + (ts_y * (e.team - 1));
                        minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
                                GetPlayerName(e.minigame_playerslot-1),
                                player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       
+
+                       vector tile_color = snake_teamcolor(e.team);
+
                        mypos_y += player_fontsize_y;
-                       //drawpic( mypos,  
-                       //              minigame_texture("snake/piece"),
-                       //              tile_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
-                       
-                       //mypos_x += tile_size_x;
+                       drawpic( mypos,
+                                       minigame_texture("snake/head"),
+                                       tile_size * 0.7, tile_color, panel_fg_alpha, DRAWFLAG_NORMAL );
+
+                       mypos_x += tile_size_x;
 
                        drawstring(mypos,ftos(e.snake_score),tile_size,
                                           '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+
+                       mypos_x += tile_size_x;
+
+                       drawstring(mypos,strcat("1UP: ", ftos(active_minigame.snake_lives[e.team])),tile_size * 0.6,
+                                                        '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                }
        }
 }
@@ -524,8 +731,18 @@ string snake_turn_to_string(int turnflags)
 {
        if ( turnflags & SNAKE_TURN_LOSS )
                return _("Game over!");
+
+       if ( turnflags & SNAKE_TURN_WIN )
+       {
+               if ( (turnflags&SNAKE_TURN_TEAM) != minigame_self.team )
+                       return _("You ran out of lives!");
+               return _("You win!");
+       }
+
+       if(active_minigame.snake_lives[minigame_self.team] <= 0)
+               return _("You ran out of lives!");
        
-       if ( turnflags & SNAKE_TURN_WAIT )
+       if ( (snake_find_head(active_minigame, minigame_self.team)).snake_dir == '0 0 0' )
                return _("Press an arrow key to begin the game");
 
        if ( turnflags & SNAKE_TURN_MOVE )
@@ -601,17 +818,29 @@ int snake_client_event(entity minigame, string event, ...)
                        {
                                if(sf & MINIG_SF_UPDATE)
                                {
+                                       int letter = ReadByte();
+                                       int number = ReadByte();
+                                       if(sent.netname) { strunzone(sent.netname); }
+                                       sent.netname = strzone(minigame_tile_buildname(letter, number));
+
                                        sent.cnt = ReadByte();
-                                       sent.snake_dir_x = ReadCoord();
-                                       sent.snake_dir_y = ReadCoord();
+                                       sent.snake_tail = ReadByte();
+
+                                       int dx = ReadByte();
+                                       int dy = ReadByte();
+
+                                       if(dx == 2) dx = -1;
+                                       if(dy == 2) dy = -1;
+
+                                       sent.snake_dir_x = dx;
+                                       sent.snake_dir_y = dy;
                                        sent.snake_dir_z = 0;
-                                       if(sent.cnt == 1)
-                                               minigame.snake_head = sent; // hax
                                }
                        }
                        else if ( sent.classname == "minigame_player" && (sf & SNAKE_SF_PLAYERSCORE ) )
                        {
                                sent.snake_score = ReadLong();
+                               minigame.snake_lives[sent.team] = ReadByte();
                        }
 
                        return false;
index 0f02e2b5819407d14f3b705df99a8aa2f86d8704..56d0ece1a2a3c944812642e0c0f9dc889b276ab0 100644 (file)
@@ -131,12 +131,11 @@ int minigame_addplayer(entity minigame_session, entity player)
                        return 0;
                minigame_rmplayer(player.active_minigame,player);
        }
-
-       int mgteam = minigame_session.minigame_event(minigame_session,"join",player);
+       entity player_pointer = spawn();
+       int mgteam = minigame_session.minigame_event(minigame_session,"join",player,player_pointer);
 
        if ( mgteam )
        {
-               entity player_pointer = spawn();
                player_pointer.classname = "minigame_player";
                player_pointer.owner = minigame_session;
                player_pointer.minigame_players = player;
@@ -157,6 +156,7 @@ int minigame_addplayer(entity minigame_session, entity player)
 
                minigame_resend(minigame_session);
        }
+       else { remove(player_pointer); }
        GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
                ftos(num_for_edict(player)),":",player.netname));
 
index 731cba8ed45c912bb35b409be792f2ffe15f77bb..54a7002056f9b681e4a741034ec24656911a6742 100644 (file)
@@ -70,7 +70,8 @@ void Physics_AddStats()
        addstat(STAT_JETPACK_MAXSPEED_SIDE, AS_FLOAT, stat_jetpack_maxspeed_side);
 
        // hack to fix track_canjump
-       addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
+       addstat(STAT_MOVEVARS_CL_TRACK_CANJUMP, AS_INT, cvar_cl_movement_track_canjump);
+       addstat(STAT_MOVEVARS_TRACK_CANJUMP, AS_INT, stat_sv_track_canjump);
 
        // double jump
        addstat(STAT_DOUBLEJUMP, AS_INT, stat_doublejump);
@@ -167,6 +168,8 @@ void Physics_UpdateStats(float maxspd_mod)
        self.stat_sv_airstopaccelerate = Physics_ClientOption(self, "airstopaccelerate");
        self.stat_sv_jumpvelocity = Physics_ClientOption(self, "jumpvelocity");
 
+       self.stat_sv_track_canjump = Physics_ClientOption(self, "track_canjump");
+
        self.stat_gameplayfix_upvelocityclearsonground = UPWARD_VELOCITY_CLEARS_ONGROUND;
 }
 #endif
@@ -583,7 +586,11 @@ bool PlayerJump (void)
                if (!IS_ONGROUND(self))
                        return IS_JUMP_HELD(self);
 
-       if (PHYS_TRACK_CANJUMP(self))
+       bool track_jump = PHYS_CL_TRACK_CANJUMP(self);
+       if(PHYS_TRACK_CANJUMP(self))
+               track_jump = true;
+
+       if (track_jump)
                if (IS_JUMP_HELD(self))
                        return true;
 
index a249b238d7bf197650833c3e3d1badad89135478..d1f82991cd3308f4e5f45c70043e3f2ad076b0a9 100644 (file)
@@ -123,6 +123,7 @@ bool IsFlying(entity a);
        #define PHYS_JUMPSPEEDCAP_MAX                           cvar_string("cl_jumpspeedcap_max")
        #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS       getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
 
+       #define PHYS_CL_TRACK_CANJUMP(s)                        getstati(STAT_MOVEVARS_CL_TRACK_CANJUMP)
        #define PHYS_TRACK_CANJUMP(s)                           getstati(STAT_MOVEVARS_TRACK_CANJUMP)
        #define PHYS_ACCELERATE                                         getstatf(STAT_MOVEVARS_ACCELERATE)
        #define PHYS_AIRACCEL_QW(s)                                     getstatf(STAT_MOVEVARS_AIRACCEL_QW)
@@ -247,6 +248,8 @@ bool IsFlying(entity a);
        .float stat_nostep;
        .float stat_jumpstep;
 
+       .bool stat_sv_track_canjump;
+
        #define PHYS_INPUT_ANGLES(s)                            s.v_angle
        #define PHYS_WORLD_ANGLES(s)                            s.angles
 
@@ -323,7 +326,8 @@ bool IsFlying(entity a);
        #define PHYS_JUMPSPEEDCAP_MAX                           autocvar_sv_jumpspeedcap_max
        #define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS       autocvar_sv_jumpspeedcap_max_disable_on_ramps
 
-       #define PHYS_TRACK_CANJUMP(s)                           s.cvar_cl_movement_track_canjump
+       #define PHYS_CL_TRACK_CANJUMP(s)                        s.cvar_cl_movement_track_canjump
+       #define PHYS_TRACK_CANJUMP(s)                           s.stat_sv_track_canjump
        #define PHYS_ACCELERATE                                         self.stat_sv_accelerate
        #define PHYS_AIRACCEL_QW(s)                                     s.stat_sv_airaccel_qw
        #define PHYS_AIRACCEL_QW_STRETCHFACTOR(s)       self.stat_sv_airaccel_qw_stretchfactor
index eff0eff804ef1f07621f138f78f03266e8096a62..9bdcb5773a5e4bcff57fe8079b53542babfa2bef 100644 (file)
@@ -245,10 +245,10 @@ const int STAT_GAMEPLAYFIX_EASIERWATERJUMP            = 190;
 const int STAT_MOVEVARS_FRICTION_SLICK                = 191;
 const int STAT_MOVEVARS_FRICTION_ONLAND               = 192;
 const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS  = 193;
-// 194 empty?
+const int STAT_MOVEVARS_TRACK_CANJUMP                 = 194;
 // 195 empty?
 const int STAT_DOUBLEJUMP                             = 196;
-const int STAT_MOVEVARS_TRACK_CANJUMP                 = 197;
+const int STAT_MOVEVARS_CL_TRACK_CANJUMP              = 197;
 const int STAT_MULTIJUMP_ADD                          = 198;
 const int STAT_MULTIJUMP_SPEED                        = 199;
 const int STAT_MULTIJUMP                              = 200;