Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Kill matrix displayed at end of level.
  23.  *
  24.  */
  25.  
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include <stdarg.h>
  31.  
  32. #include "dxxerror.h"
  33. #include "pstypes.h"
  34. #include "gr.h"
  35. #include "window.h"
  36. #include "key.h"
  37. #include "palette.h"
  38. #include "game.h"
  39. #include "gameseq.h"
  40. #include "window.h"
  41. #include "physfsx.h"
  42. #include "gamefont.h"
  43. #include "u_mem.h"
  44. #include "newmenu.h"
  45. #include "menu.h"
  46. #include "player.h"
  47. #include "screens.h"
  48. #include "cntrlcen.h"
  49. #include "mouse.h"
  50. #include "joy.h"
  51. #include "timer.h"
  52. #include "text.h"
  53. #include "rbaudio.h"
  54. #include "multi.h"
  55. #include "kmatrix.h"
  56. #include "gauges.h"
  57. #include "pcx.h"
  58. #include "object.h"
  59. #include "args.h"
  60.  
  61. #include "compiler-range_for.h"
  62.  
  63. #if DXX_USE_OGL
  64. #include "ogl_init.h"
  65. #endif
  66.  
  67. #define CENTERING_OFFSET(x) ((300 - (70 + (x)*25 ))/2)
  68. #define CENTERSCREEN (SWIDTH/2)
  69. #define KMATRIX_VIEW_SEC 7 // Time after reactor explosion until new level - in seconds
  70. static void kmatrix_redraw_coop(fvcobjptr &vcobjptr);
  71.  
  72. static void kmatrix_draw_item(fvcobjptr &vcobjptr, grs_canvas &canvas, const grs_font &cv_font, const int i, const playernum_array_t &sorted)
  73. {
  74.         int x, y;
  75.  
  76.         y = FSPACY(50+i*9);
  77.         const auto &&fspacx = FSPACX();
  78.         auto &p = *vcplayerptr(sorted[i]);
  79.         gr_string(canvas, cv_font, fspacx(CENTERING_OFFSET(N_players)), y, static_cast<const char *>(p.callsign));
  80.  
  81.         const auto &&rgb10 = BM_XRGB(10, 10, 10);
  82.         const auto &&rgb25 = BM_XRGB(25, 25, 25);
  83.         for (int j=0; j<N_players; j++)
  84.         {
  85.                 x = fspacx(70 + CENTERING_OFFSET(N_players) + j * 25);
  86.  
  87.                 const auto kmij = kill_matrix[sorted[i]][sorted[j]];
  88.                 if (sorted[i]==sorted[j])
  89.                 {
  90.                         if (kmij == 0)
  91.                         {
  92.                                 gr_set_fontcolor(canvas, rgb10, -1);
  93.                                 gr_string(canvas, cv_font, x, y, "0");
  94.                         }
  95.                         else
  96.                         {
  97.                                 gr_set_fontcolor(canvas, rgb25, -1);
  98.                                 gr_printf(canvas, cv_font, x, y, "-%hu", kmij);
  99.                         }
  100.                 }
  101.                 else
  102.                 {
  103.                         gr_set_fontcolor(canvas, kmij <= 0 ? rgb10 : rgb25, -1);
  104.                         gr_printf(canvas, cv_font, x, y, "%hu", kmij);
  105.                 }
  106.         }
  107.  
  108.                 auto &player_info = vcobjptr(p.objnum)->ctype.player_info;
  109.                 const int eff = (player_info.net_killed_total + player_info.net_kills_total <= 0)
  110.                         ? 0
  111.                         : static_cast<int>(
  112.                                 static_cast<float>(player_info.net_kills_total) / (
  113.                                         static_cast<float>(player_info.net_killed_total) + static_cast<float>(player_info.net_kills_total)
  114.                                 ) * 100.0
  115.                         );
  116.  
  117.         x = fspacx(60 + CENTERING_OFFSET(N_players) + N_players * 25);
  118.         gr_set_fontcolor(canvas, rgb25, -1);
  119.         gr_printf(canvas, cv_font, x, y, "%4d/%i%%", player_info.net_kills_total, eff <= 0 ? 0 : eff);
  120. }
  121.  
  122. static void kmatrix_draw_names(grs_canvas &canvas, const grs_font &cv_font, const playernum_array_t &sorted)
  123. {
  124.         int x;
  125.  
  126.         const auto &&fspacx = FSPACX();
  127.         const auto &&fspacy = FSPACY();
  128.         const auto &&rgb31 = BM_XRGB(31, 31, 31);
  129.         for (int j=0; j<N_players; j++)
  130.         {
  131.                 x = fspacx(70 + CENTERING_OFFSET(N_players) + j * 25);
  132.  
  133.                 color_t c;
  134.                 auto &p = *vcplayerptr(sorted[j]);
  135.                 if (p.connected==CONNECT_DISCONNECTED)
  136.                         c = rgb31;
  137.                 else
  138.                 {
  139.                         const auto color = get_player_or_team_color(sorted[j]);
  140.                         const auto &rgb = player_rgb[color];
  141.                         c = BM_XRGB(rgb.r, rgb.g, rgb.b);
  142.                 }
  143.                 gr_set_fontcolor(canvas, c, -1);
  144.                 gr_printf(canvas, cv_font, x, fspacy(40), "%c", p.callsign[0u]);
  145.         }
  146.  
  147.         x = fspacx(72 + CENTERING_OFFSET(N_players) + N_players * 25);
  148.         gr_set_fontcolor(canvas, rgb31, -1);
  149.         gr_string(canvas, cv_font, x, fspacy(40), "K/E");
  150. }
  151.  
  152. static void kmatrix_draw_coop_names(grs_canvas &canvas, const grs_font &cv_font)
  153. {
  154.         gr_set_fontcolor(canvas, BM_XRGB(63, 31, 31),-1);
  155.         const auto &&fspacy40 = FSPACY(40);
  156.         const auto centerscreen = CENTERSCREEN;
  157.         gr_string(canvas, cv_font, centerscreen, fspacy40, "SCORE");
  158.         gr_string(canvas, cv_font, centerscreen + FSPACX(50), fspacy40, "DEATHS");
  159. }
  160.  
  161. static void kmatrix_status_msg(grs_canvas &canvas, const fix time, const int reactor)
  162. {
  163.         gr_set_fontcolor(canvas, gr_find_closest_color(255, 255, 255),-1);
  164.         auto &game_font = *GAME_FONT;
  165.         gr_printf(canvas, game_font, 0x8000, SHEIGHT - LINE_SPACING(game_font, game_font), reactor
  166.                 ? "Waiting for players to finish level. Reactor time: T-%d"
  167.                 : "Level finished. Wait (%d) to proceed or ESC to Quit."
  168.         , time);
  169. }
  170.  
  171. namespace {
  172.  
  173. struct kmatrix_screen : ignore_window_pointer_t
  174. {
  175.         grs_main_bitmap background;
  176.         int network;
  177.         fix64 end_time;
  178.         int playing;
  179.         int aborted;
  180. };
  181.  
  182. }
  183.  
  184. namespace dsx {
  185. static void kmatrix_redraw(kmatrix_screen *km)
  186. {
  187.         auto &Objects = LevelUniqueObjectState.Objects;
  188.         auto &vcobjptr = Objects.vcptr;
  189.         playernum_array_t sorted;
  190.  
  191.         gr_set_default_canvas();
  192.         auto &canvas = *grd_curcanv;
  193.         show_fullscr(canvas, km->background);
  194.        
  195.         if (Game_mode & GM_MULTI_COOP)
  196.         {
  197.                 kmatrix_redraw_coop(vcobjptr);
  198.         }
  199.         else
  200.         {
  201.                 multi_sort_kill_list();
  202.                 const auto title =
  203. #if defined(DXX_BUILD_DESCENT_II)
  204.                         game_mode_capture_flag()
  205.                         ? "CAPTURE THE FLAG SUMMARY"
  206.                         : game_mode_hoard()
  207.                                 ? "HOARD SUMMARY"
  208.                                 :
  209. #endif
  210.                                 TXT_KILL_MATRIX_TITLE;
  211.                 auto &medium3_font = *MEDIUM3_FONT;
  212.                 gr_string(canvas, medium3_font, 0x8000, FSPACY(10), title);
  213.  
  214.                 auto &game_font = *GAME_FONT;
  215.                 multi_get_kill_list(sorted);
  216.                 kmatrix_draw_names(canvas, game_font, sorted);
  217.  
  218.                 for (int i=0; i<N_players; i++ )
  219.                 {
  220.                         if (vcplayerptr(sorted[i])->connected == CONNECT_DISCONNECTED)
  221.                                 gr_set_fontcolor(canvas, gr_find_closest_color(31, 31, 31),-1);
  222.                         else
  223.                         {
  224.                                 const auto color = get_player_or_team_color(sorted[i]);
  225.                                 gr_set_fontcolor(canvas, BM_XRGB(player_rgb[color].r, player_rgb[color].g, player_rgb[color].b),-1);
  226.                         }
  227.                         kmatrix_draw_item(vcobjptr, canvas, game_font, i, sorted);
  228.                 }
  229.         }
  230.  
  231.         gr_palette_load(gr_palette);
  232. }
  233. }
  234.  
  235. static void kmatrix_redraw_coop(fvcobjptr &vcobjptr)
  236. {
  237.         playernum_array_t sorted;
  238.  
  239.         multi_sort_kill_list();
  240.         auto &canvas = *grd_curcanv;
  241.         auto &medium3_font = *MEDIUM3_FONT;
  242.         gr_string(canvas, medium3_font,  0x8000, FSPACY(10), "COOPERATIVE SUMMARY");
  243.         multi_get_kill_list(sorted);
  244.         auto &game_font = *GAME_FONT;
  245.         kmatrix_draw_coop_names(canvas, game_font);
  246.         const auto &&fspacx = FSPACX();
  247.         const auto &&fspacy = FSPACY();
  248.         const auto x_callsign = fspacx(CENTERING_OFFSET(N_players));
  249.         const auto x_centerscreen = CENTERSCREEN;
  250.         const auto &&fspacx50 = fspacx(50);
  251.         const auto rgb60_40_10 = BM_XRGB(60, 40, 10);
  252.  
  253.         for (playernum_t i = 0; i < N_players; ++i)
  254.         {
  255.                 auto &plr = *vcplayerptr(sorted[i]);
  256.                 int r, g, b;
  257.                 if (plr.connected == CONNECT_DISCONNECTED)
  258.                         r = g = b = 31;
  259.                 else
  260.                 {
  261.                         auto &color = player_rgb_normal[get_player_color(sorted[i])];
  262.                         r = color.r * 2;
  263.                         g = color.g * 2;
  264.                         b = color.b * 2;
  265.                 }
  266.                 gr_set_fontcolor(canvas, gr_find_closest_color(r, g, b), -1);
  267.  
  268.                 const auto &&y = fspacy(50 + i * 9);
  269.                 gr_string(canvas, game_font, x_callsign, y, static_cast<const char *>(plr.callsign));
  270.                 gr_set_fontcolor(canvas, rgb60_40_10, -1);
  271.                 auto &player_info = vcobjptr(plr.objnum)->ctype.player_info;
  272.                 gr_printf(canvas, game_font, x_centerscreen, y, "%d", player_info.mission.score);
  273.                 gr_printf(canvas, game_font, x_centerscreen + fspacx50, y, "%d", player_info.net_killed_total);
  274.         }
  275.  
  276.         gr_palette_load(gr_palette);
  277. }
  278.  
  279. namespace dsx {
  280. static window_event_result kmatrix_handler(window *, const d_event &event, kmatrix_screen *km)
  281. {
  282.         auto &LevelUniqueControlCenterState = LevelUniqueObjectState.ControlCenterState;
  283.         int k = 0, choice = 0;
  284.        
  285.         switch (event.type)
  286.         {
  287.                 case EVENT_KEY_COMMAND:
  288.                         k = event_key_get(event);
  289.                         switch( k )
  290.                         {
  291.                                 case KEY_ESC:
  292.                                         {
  293.                                                 std::array<newmenu_item, 2> nm_message_items{{
  294.                                                         nm_item_menu(TXT_YES),
  295.                                                         nm_item_menu(TXT_NO),
  296.                                                 }};
  297.                                                 choice = newmenu_do(nullptr, TXT_ABORT_GAME, nm_message_items, km->network ? get_multi_endlevel_poll2() : unused_newmenu_subfunction, unused_newmenu_userdata);
  298.                                         }
  299.                                        
  300.                                         if (choice==0)
  301.                                         {
  302.                                                 get_local_player().connected=CONNECT_DISCONNECTED;
  303.                                                
  304.                                                 if (km->network)
  305.                                                         multi_send_endlevel_packet();
  306.                                                
  307.                                                 multi_leave_game();
  308.                                                 km->aborted = 1;
  309.  
  310.                                                 return window_event_result::close;
  311.                                         }
  312.                                         return window_event_result::handled;
  313.                                        
  314.                                 default:
  315.                                         break;
  316.                         }
  317.                         break;
  318.                        
  319.                 case EVENT_WINDOW_DRAW:
  320.                         {
  321.                         timer_delay2(50);
  322.  
  323.                         if (km->network)
  324.                                 multi_do_protocol_frame(0, 1);
  325.                        
  326.                         km->playing = 0;
  327.  
  328.                         // Check if all connected players are also looking at this screen ...
  329.                         range_for (auto &i, Players)
  330.                                 if (i.connected)
  331.                                         if (i.connected != CONNECT_END_MENU && i.connected != CONNECT_DIED_IN_MINE)
  332.                                         {
  333.                                                 km->playing = 1;
  334.                                                 break;
  335.                                         }
  336.                        
  337.                         // ... and let the reactor blow sky high!
  338.                         if (!km->playing)
  339.                                 LevelUniqueControlCenterState.Countdown_seconds_left = -1;
  340.                        
  341.                         // If Reactor is finished and end_time not inited, set the time when we will exit this loop
  342.                         const auto Countdown_seconds_left = LevelUniqueControlCenterState.Countdown_seconds_left;
  343.                         if (km->end_time == -1 && Countdown_seconds_left < 0 && !km->playing)
  344.                                 km->end_time = timer_query() + (KMATRIX_VIEW_SEC * F1_0);
  345.                        
  346.                         // Check if end_time has been reached and exit loop
  347.                         if (timer_query() >= km->end_time && km->end_time != -1)
  348.                         {
  349.                                 if (km->network)
  350.                                         multi_send_endlevel_packet();  // make sure
  351.                                
  352. #if defined(DXX_BUILD_DESCENT_II)
  353.                                 if (is_D2_OEM)
  354.                                 {
  355.                                         if (Current_level_num==8)
  356.                                         {
  357.                                                 get_local_player().connected=CONNECT_DISCONNECTED;
  358.                                                
  359.                                                 if (km->network)
  360.                                                         multi_send_endlevel_packet();
  361.                                                
  362.                                                 multi_leave_game();
  363.                                                 km->aborted = 1;
  364.                                         }
  365.                                 }
  366. #endif
  367.                                 return window_event_result::close;
  368.                         }
  369.  
  370.                         kmatrix_redraw(km);
  371.                         kmatrix_status_msg(*grd_curcanv, km->playing ? Countdown_seconds_left : f2i(timer_query() - km->end_time), km->playing);
  372.                         break;
  373.                         }
  374.                        
  375.                 case EVENT_WINDOW_CLOSE:
  376.                         game_flush_inputs();
  377.                         newmenu_free_background();
  378.                         break;
  379.                        
  380.                 default:
  381.                         break;
  382.         }
  383.         return window_event_result::ignored;
  384. }
  385. }
  386.  
  387. kmatrix_result kmatrix_view(int network)
  388. {
  389.         auto &Objects = LevelUniqueObjectState.Objects;
  390.         auto &vcobjptridx = Objects.vcptridx;
  391.         kmatrix_screen km;
  392.         if (pcx_read_bitmap(STARS_BACKGROUND, km.background, gr_palette) != pcx_result::SUCCESS)
  393.         {
  394.                 return kmatrix_result::abort;
  395.         }
  396.         gr_palette_load(gr_palette);
  397.        
  398.         km.network = network;
  399.         km.end_time = -1;
  400.         km.playing = 0;
  401.         km.aborted = 0;
  402.        
  403.         set_screen_mode( SCREEN_MENU );
  404.         game_flush_inputs();
  405.  
  406.         range_for (auto &i, Players)
  407.                 if (i.objnum != object_none)
  408.                         digi_kill_sound_linked_to_object(vcobjptridx(i.objnum));
  409.  
  410.         const auto wind = window_create(grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT, kmatrix_handler, &km);
  411.         if (!wind)
  412.         {
  413.                 return kmatrix_result::abort;
  414.         }
  415.        
  416.         event_process_all();
  417.  
  418.         return (km.aborted ? kmatrix_result::abort : kmatrix_result::proceed);
  419. }
  420.