Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 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 | } |