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 | * Inferno High Scores and Statistics System |
||
| 23 | * |
||
| 24 | */ |
||
| 25 | |||
| 26 | #include <stdio.h> |
||
| 27 | #include <stdlib.h> |
||
| 28 | #include <string.h> |
||
| 29 | #include <ctype.h> |
||
| 30 | |||
| 31 | #include "scores.h" |
||
| 32 | #include "dxxerror.h" |
||
| 33 | #include "pstypes.h" |
||
| 34 | #include "window.h" |
||
| 35 | #include "gr.h" |
||
| 36 | #include "key.h" |
||
| 37 | #include "mouse.h" |
||
| 38 | #include "palette.h" |
||
| 39 | #include "game.h" |
||
| 40 | #include "gamefont.h" |
||
| 41 | #include "u_mem.h" |
||
| 42 | #include "newmenu.h" |
||
| 43 | #include "menu.h" |
||
| 44 | #include "player.h" |
||
| 45 | #include "object.h" |
||
| 46 | #include "screens.h" |
||
| 47 | #include "gamefont.h" |
||
| 48 | #include "mouse.h" |
||
| 49 | #include "joy.h" |
||
| 50 | #include "timer.h" |
||
| 51 | #include "text.h" |
||
| 52 | #include "strutil.h" |
||
| 53 | #include "rbaudio.h" |
||
| 54 | #include "physfsx.h" |
||
| 55 | #include "compiler-range_for.h" |
||
| 56 | #include "d_range.h" |
||
| 57 | |||
| 58 | #if DXX_USE_OGL |
||
| 59 | #include "ogl_init.h" |
||
| 60 | #endif |
||
| 61 | |||
| 62 | #define VERSION_NUMBER 1 |
||
| 63 | #define SCORES_FILENAME "descent.hi" |
||
| 64 | #define COOL_MESSAGE_LEN 50 |
||
| 65 | namespace dcx { |
||
| 66 | constexpr std::integral_constant<unsigned, 10> MAX_HIGH_SCORES{}; |
||
| 67 | } |
||
| 68 | |||
| 69 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 70 | #define DXX_SCORE_STRUCT_PACK __pack__ |
||
| 71 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 72 | #define DXX_SCORE_STRUCT_PACK |
||
| 73 | #endif |
||
| 74 | |||
| 75 | struct stats_info |
||
| 76 | { |
||
| 77 | callsign_t name; |
||
| 78 | int score; |
||
| 79 | sbyte starting_level; |
||
| 80 | sbyte ending_level; |
||
| 81 | sbyte diff_level; |
||
| 82 | short kill_ratio; // 0-100 |
||
| 83 | short hostage_ratio; // |
||
| 84 | int seconds; // How long it took in seconds... |
||
| 85 | } DXX_SCORE_STRUCT_PACK; |
||
| 86 | |||
| 87 | struct all_scores |
||
| 88 | { |
||
| 89 | char signature[3]; // DHS |
||
| 90 | sbyte version; // version |
||
| 91 | char cool_saying[COOL_MESSAGE_LEN]; |
||
| 92 | stats_info stats[MAX_HIGH_SCORES]; |
||
| 93 | } DXX_SCORE_STRUCT_PACK; |
||
| 94 | #if defined(DXX_BUILD_DESCENT_I) |
||
| 95 | static_assert(sizeof(all_scores) == 294, "high score size wrong"); |
||
| 96 | #elif defined(DXX_BUILD_DESCENT_II) |
||
| 97 | static_assert(sizeof(all_scores) == 336, "high score size wrong"); |
||
| 98 | #endif |
||
| 99 | |||
| 100 | static void scores_read(all_scores *scores) |
||
| 101 | { |
||
| 102 | int fsize; |
||
| 103 | |||
| 104 | // clear score array... |
||
| 105 | *scores = {}; |
||
| 106 | |||
| 107 | RAIIPHYSFS_File fp{PHYSFS_openRead(SCORES_FILENAME)}; |
||
| 108 | if (!fp) |
||
| 109 | { |
||
| 110 | // No error message needed, code will work without a scores file |
||
| 111 | strcpy(scores->cool_saying, TXT_REGISTER_DESCENT); |
||
| 112 | scores->stats[0].name = "Parallax"; |
||
| 113 | scores->stats[1].name = "Matt"; |
||
| 114 | scores->stats[2].name = "Mike"; |
||
| 115 | scores->stats[3].name = "Adam"; |
||
| 116 | scores->stats[4].name = "Mark"; |
||
| 117 | scores->stats[5].name = "Jasen"; |
||
| 118 | scores->stats[6].name = "Samir"; |
||
| 119 | scores->stats[7].name = "Doug"; |
||
| 120 | scores->stats[8].name = "Dan"; |
||
| 121 | scores->stats[9].name = "Jason"; |
||
| 122 | |||
| 123 | range_for (const int i, xrange(10u)) |
||
| 124 | scores->stats[i].score = (10-i)*1000; |
||
| 125 | return; |
||
| 126 | } |
||
| 127 | |||
| 128 | fsize = PHYSFS_fileLength(fp); |
||
| 129 | |||
| 130 | if ( fsize != sizeof(all_scores) ) { |
||
| 131 | return; |
||
| 132 | } |
||
| 133 | // Read 'em in... |
||
| 134 | PHYSFS_read(fp, scores, sizeof(all_scores), 1); |
||
| 135 | if ( (scores->version!=VERSION_NUMBER)||(scores->signature[0]!='D')||(scores->signature[1]!='H')||(scores->signature[2]!='S') ) { |
||
| 136 | *scores = {}; |
||
| 137 | return; |
||
| 138 | } |
||
| 139 | } |
||
| 140 | |||
| 141 | static void scores_write(all_scores *scores) |
||
| 142 | { |
||
| 143 | RAIIPHYSFS_File fp{PHYSFS_openWrite(SCORES_FILENAME)}; |
||
| 144 | if (!fp) |
||
| 145 | { |
||
| 146 | nm_messagebox( TXT_WARNING, 1, TXT_OK, "%s\n'%s'", TXT_UNABLE_TO_OPEN, SCORES_FILENAME ); |
||
| 147 | return; |
||
| 148 | } |
||
| 149 | |||
| 150 | scores->signature[0]='D'; |
||
| 151 | scores->signature[1]='H'; |
||
| 152 | scores->signature[2]='S'; |
||
| 153 | scores->version = VERSION_NUMBER; |
||
| 154 | PHYSFS_write(fp, scores,sizeof(all_scores), 1); |
||
| 155 | } |
||
| 156 | |||
| 157 | static void int_to_string( int number, char *dest ) |
||
| 158 | { |
||
| 159 | int c; |
||
| 160 | char buffer[20],*p; |
||
| 161 | |||
| 162 | const auto l = snprintf(buffer, sizeof(buffer), "%d", number); |
||
| 163 | if (l<=3) { |
||
| 164 | // Don't bother with less than 3 digits |
||
| 165 | memcpy(dest, buffer, 4); |
||
| 166 | return; |
||
| 167 | } |
||
| 168 | |||
| 169 | c = 0; |
||
| 170 | p=dest; |
||
| 171 | for (int i=l-1; i>=0; i-- ) { |
||
| 172 | if (c==3) { |
||
| 173 | *p++=','; |
||
| 174 | c = 0; |
||
| 175 | } |
||
| 176 | c++; |
||
| 177 | *p++ = buffer[i]; |
||
| 178 | } |
||
| 179 | *p++ = '\0'; |
||
| 180 | d_strrev(dest); |
||
| 181 | } |
||
| 182 | |||
| 183 | static void scores_fill_struct(stats_info * stats) |
||
| 184 | { |
||
| 185 | auto &Objects = LevelUniqueObjectState.Objects; |
||
| 186 | auto &vmobjptr = Objects.vmptr; |
||
| 187 | auto &plr = get_local_player(); |
||
| 188 | stats->name = plr.callsign; |
||
| 189 | auto &player_info = get_local_plrobj().ctype.player_info; |
||
| 190 | stats->score = player_info.mission.score; |
||
| 191 | stats->ending_level = plr.level; |
||
| 192 | if (const auto robots_total = GameUniqueState.accumulated_robots) |
||
| 193 | stats->kill_ratio = (plr.num_kills_total * 100) / robots_total; |
||
| 194 | else |
||
| 195 | stats->kill_ratio = 0; |
||
| 196 | |||
| 197 | if (const auto hostages_total = GameUniqueState.total_hostages) |
||
| 198 | stats->hostage_ratio = (player_info.mission.hostages_rescued_total * 100) / hostages_total; |
||
| 199 | else |
||
| 200 | stats->hostage_ratio = 0; |
||
| 201 | |||
| 202 | stats->seconds = f2i(plr.time_total) + (plr.hours_total * 3600); |
||
| 203 | |||
| 204 | stats->diff_level = GameUniqueState.Difficulty_level; |
||
| 205 | stats->starting_level = plr.starting_level; |
||
| 206 | } |
||
| 207 | |||
| 208 | static inline const char *get_placement_slot_string(const unsigned position) |
||
| 209 | { |
||
| 210 | switch(position) |
||
| 211 | { |
||
| 212 | default: |
||
| 213 | Int3(); |
||
| 214 | DXX_BOOST_FALLTHROUGH; |
||
| 215 | case 0: return TXT_1ST; |
||
| 216 | case 1: return TXT_2ND; |
||
| 217 | case 2: return TXT_3RD; |
||
| 218 | case 3: return TXT_4TH; |
||
| 219 | case 4: return TXT_5TH; |
||
| 220 | case 5: return TXT_6TH; |
||
| 221 | case 6: return TXT_7TH; |
||
| 222 | case 7: return TXT_8TH; |
||
| 223 | case 8: return TXT_9TH; |
||
| 224 | case 9: return TXT_10TH; |
||
| 225 | } |
||
| 226 | } |
||
| 227 | |||
| 228 | void scores_maybe_add_player() |
||
| 229 | { |
||
| 230 | auto &Objects = LevelUniqueObjectState.Objects; |
||
| 231 | auto &vmobjptr = Objects.vmptr; |
||
| 232 | int position; |
||
| 233 | all_scores scores; |
||
| 234 | stats_info last_game; |
||
| 235 | |||
| 236 | if ((Game_mode & GM_MULTI) && !(Game_mode & GM_MULTI_COOP)) |
||
| 237 | return; |
||
| 238 | |||
| 239 | scores_read(&scores); |
||
| 240 | |||
| 241 | position = MAX_HIGH_SCORES; |
||
| 242 | auto &player_info = get_local_plrobj().ctype.player_info; |
||
| 243 | for (int i=0; i<MAX_HIGH_SCORES; i++ ) { |
||
| 244 | if (player_info.mission.score > scores.stats[i].score) |
||
| 245 | { |
||
| 246 | position = i; |
||
| 247 | break; |
||
| 248 | } |
||
| 249 | } |
||
| 250 | |||
| 251 | if ( position == MAX_HIGH_SCORES ) { |
||
| 252 | scores_fill_struct( &last_game ); |
||
| 253 | } else { |
||
| 254 | if ( position==0 ) { |
||
| 255 | std::array<char, sizeof(scores.cool_saying)> text1{}; |
||
| 256 | std::array<newmenu_item, 2> m{{ |
||
| 257 | nm_item_text(TXT_COOL_SAYING), |
||
| 258 | nm_item_input(text1), |
||
| 259 | }}; |
||
| 260 | newmenu_do( TXT_HIGH_SCORE, TXT_YOU_PLACED_1ST, m, unused_newmenu_subfunction, unused_newmenu_userdata ); |
||
| 261 | strcpy(scores.cool_saying, text1[0] ? text1.data() : "No comment"); |
||
| 262 | } else { |
||
| 263 | nm_messagebox( TXT_HIGH_SCORE, 1, TXT_OK, "%s %s!", TXT_YOU_PLACED, get_placement_slot_string(position)); |
||
| 264 | } |
||
| 265 | |||
| 266 | // move everyone down... |
||
| 267 | for ( int i=MAX_HIGH_SCORES-1; i>position; i-- ) { |
||
| 268 | scores.stats[i] = scores.stats[i-1]; |
||
| 269 | } |
||
| 270 | |||
| 271 | scores_fill_struct( &scores.stats[position] ); |
||
| 272 | |||
| 273 | scores_write(&scores); |
||
| 274 | |||
| 275 | } |
||
| 276 | scores_view(&last_game, position); |
||
| 277 | } |
||
| 278 | |||
| 279 | __attribute_nonnull() |
||
| 280 | static void scores_rputs(grs_canvas &canvas, const grs_font &cv_font, const int x, const int y, char *const buffer) |
||
| 281 | { |
||
| 282 | char *p; |
||
| 283 | |||
| 284 | //replace the digit '1' with special wider 1 |
||
| 285 | for (p=buffer;*p;p++) |
||
| 286 | if (*p=='1') *p=(char)132; // Pierre-Marie Baty -- missing cast |
||
| 287 | |||
| 288 | int w, h; |
||
| 289 | gr_get_string_size(cv_font, buffer, &w, &h, nullptr); |
||
| 290 | gr_string(canvas, cv_font, FSPACX(x) - w, FSPACY(y), buffer, w, h); |
||
| 291 | } |
||
| 292 | |||
| 293 | __attribute_format_printf(5, 6) |
||
| 294 | static void scores_rprintf(grs_canvas &canvas, const grs_font &cv_font, const int x, const int y, const char *const format, ...) |
||
| 295 | { |
||
| 296 | va_list args; |
||
| 297 | char buffer[128]; |
||
| 298 | |||
| 299 | va_start(args, format ); |
||
| 300 | vsnprintf(buffer,sizeof(buffer),format,args); |
||
| 301 | va_end(args); |
||
| 302 | scores_rputs(canvas, cv_font, x, y, buffer); |
||
| 303 | } |
||
| 304 | |||
| 305 | static void scores_draw_item(grs_canvas &canvas, const grs_font &cv_font, const unsigned i, stats_info *const stats) |
||
| 306 | { |
||
| 307 | char buffer[20]; |
||
| 308 | |||
| 309 | int y; |
||
| 310 | |||
| 311 | y = 77+i*9; |
||
| 312 | |||
| 313 | if (i==0) |
||
| 314 | y -= 8; |
||
| 315 | |||
| 316 | if ( i==MAX_HIGH_SCORES ) |
||
| 317 | y += 8; |
||
| 318 | else |
||
| 319 | scores_rprintf(canvas, cv_font, 57, y - 3, "%d.", i + 1); |
||
| 320 | |||
| 321 | y -= 3; |
||
| 322 | |||
| 323 | const auto &&fspacx = FSPACX(); |
||
| 324 | const auto &&fspacx66 = fspacx(66); |
||
| 325 | const auto &&fspacy_y = FSPACY(y); |
||
| 326 | if (!stats->name[0u]) |
||
| 327 | { |
||
| 328 | gr_string(canvas, cv_font, fspacx66, fspacy_y, TXT_EMPTY); |
||
| 329 | return; |
||
| 330 | } |
||
| 331 | gr_string(canvas, cv_font, fspacx66, fspacy_y, stats->name); |
||
| 332 | int_to_string(stats->score, buffer); |
||
| 333 | scores_rputs(canvas, cv_font, 149, y, buffer); |
||
| 334 | |||
| 335 | gr_string(canvas, cv_font, fspacx(166), fspacy_y, MENU_DIFFICULTY_TEXT(stats->diff_level)); |
||
| 336 | |||
| 337 | if ( (stats->starting_level > 0 ) && (stats->ending_level > 0 )) |
||
| 338 | scores_rprintf(canvas, cv_font, 232, y, "%d-%d", stats->starting_level, stats->ending_level); |
||
| 339 | else if ( (stats->starting_level < 0 ) && (stats->ending_level > 0 )) |
||
| 340 | scores_rprintf(canvas, cv_font, 232, y, "S%d-%d", -stats->starting_level, stats->ending_level); |
||
| 341 | else if ( (stats->starting_level < 0 ) && (stats->ending_level < 0 )) |
||
| 342 | scores_rprintf(canvas, cv_font, 232, y, "S%d-S%d", -stats->starting_level, -stats->ending_level); |
||
| 343 | else if ( (stats->starting_level > 0 ) && (stats->ending_level < 0 )) |
||
| 344 | scores_rprintf(canvas, cv_font, 232, y, "%d-S%d", stats->starting_level, -stats->ending_level); |
||
| 345 | |||
| 346 | { |
||
| 347 | int h, m, s; |
||
| 348 | h = stats->seconds/3600; |
||
| 349 | s = stats->seconds%3600; |
||
| 350 | m = s / 60; |
||
| 351 | s = s % 60; |
||
| 352 | scores_rprintf(canvas, cv_font, 276, y, "%d:%02d:%02d", h, m, s); |
||
| 353 | } |
||
| 354 | } |
||
| 355 | |||
| 356 | struct scores_menu : ignore_window_pointer_t |
||
| 357 | { |
||
| 358 | int citem; |
||
| 359 | fix64 t1; |
||
| 360 | int looper; |
||
| 361 | all_scores scores; |
||
| 362 | stats_info last_game; |
||
| 363 | }; |
||
| 364 | |||
| 365 | static window_event_result scores_handler(window *wind,const d_event &event, scores_menu *menu) |
||
| 366 | { |
||
| 367 | int k; |
||
| 368 | static const std::array<int8_t, 64> fades{{ |
||
| 369 | 1,1,1,2,2,3,4,4,5,6,8,9,10,12,13,15,16,17,19,20,22,23,24,26,27,28,28,29,30,30,31,31,31,31,31,30,30,29,28,28,27,26,24,23,22,20,19,17,16,15,13,12,10,9,8,6,5,4,4,3,2,2,1,1 |
||
| 370 | }}; |
||
| 371 | const auto &&fspacx = FSPACX(); |
||
| 372 | const auto &&fspacy = FSPACY(); |
||
| 373 | int w = fspacx(290), h = fspacy(170); |
||
| 374 | |||
| 375 | switch (event.type) |
||
| 376 | { |
||
| 377 | case EVENT_WINDOW_ACTIVATED: |
||
| 378 | game_flush_inputs(); |
||
| 379 | break; |
||
| 380 | |||
| 381 | case EVENT_KEY_COMMAND: |
||
| 382 | k = event_key_get(event); |
||
| 383 | switch( k ) { |
||
| 384 | case KEY_CTRLED+KEY_R: |
||
| 385 | if ( menu->citem < 0 ) { |
||
| 386 | // Reset scores... |
||
| 387 | if ( nm_messagebox( NULL, 2, TXT_NO, TXT_YES, TXT_RESET_HIGH_SCORES )==1 ) { |
||
| 388 | PHYSFS_delete(SCORES_FILENAME); |
||
| 389 | scores_view(&menu->last_game, menu->citem); // create new scores window |
||
| 390 | return window_event_result::close; |
||
| 391 | } |
||
| 392 | } |
||
| 393 | return window_event_result::handled; |
||
| 394 | case KEY_ENTER: |
||
| 395 | case KEY_SPACEBAR: |
||
| 396 | case KEY_ESC: |
||
| 397 | return window_event_result::close; |
||
| 398 | } |
||
| 399 | break; |
||
| 400 | |||
| 401 | case EVENT_MOUSE_BUTTON_DOWN: |
||
| 402 | case EVENT_MOUSE_BUTTON_UP: |
||
| 403 | if (event_mouse_get_button(event) == MBTN_LEFT || event_mouse_get_button(event) == MBTN_RIGHT) |
||
| 404 | { |
||
| 405 | return window_event_result::close; |
||
| 406 | } |
||
| 407 | break; |
||
| 408 | |||
| 409 | case EVENT_JOYSTICK_BUTTON_DOWN: |
||
| 410 | return window_event_result::close; |
||
| 411 | |||
| 412 | case EVENT_IDLE: |
||
| 413 | timer_delay2(50); |
||
| 414 | break; |
||
| 415 | |||
| 416 | case EVENT_WINDOW_DRAW: |
||
| 417 | gr_set_default_canvas(); |
||
| 418 | |||
| 419 | nm_draw_background(*grd_curcanv, ((SWIDTH - w) / 2) - BORDERX, ((SHEIGHT - h) / 2) - BORDERY, ((SWIDTH - w) / 2) + w + BORDERX, ((SHEIGHT - h) / 2) + h + BORDERY); |
||
| 420 | |||
| 421 | { |
||
| 422 | auto &canvas = window_get_canvas(*wind); |
||
| 423 | auto &medium3_font = *MEDIUM3_FONT; |
||
| 424 | gr_string(canvas, medium3_font, 0x8000, fspacy(15), TXT_HIGH_SCORES); |
||
| 425 | gr_set_fontcolor(canvas, BM_XRGB(31, 26, 5), -1); |
||
| 426 | auto &game_font = *GAME_FONT; |
||
| 427 | gr_string(canvas, game_font, fspacx( 71), fspacy(50), TXT_NAME); |
||
| 428 | gr_string(canvas, game_font, fspacx(122), fspacy(50), TXT_SCORE); |
||
| 429 | gr_string(canvas, game_font, fspacx(167), fspacy(50), TXT_SKILL); |
||
| 430 | gr_string(canvas, game_font, fspacx(210), fspacy(50), TXT_LEVELS); |
||
| 431 | gr_string(canvas, game_font, fspacx(253), fspacy(50), TXT_TIME); |
||
| 432 | |||
| 433 | if ( menu->citem < 0 ) |
||
| 434 | gr_string(canvas, game_font, 0x8000, fspacy(175), TXT_PRESS_CTRL_R); |
||
| 435 | |||
| 436 | gr_set_fontcolor(canvas, BM_XRGB(28, 28, 28), -1); |
||
| 437 | |||
| 438 | gr_printf(canvas, game_font, 0x8000, fspacy(31), "%c%s%c - %s", 34, menu->scores.cool_saying, 34, static_cast<const char *>(menu->scores.stats[0].name)); |
||
| 439 | |||
| 440 | for (int i=0; i<MAX_HIGH_SCORES; i++ ) { |
||
| 441 | gr_set_fontcolor(canvas, BM_XRGB(28 - i * 2, 28 - i * 2, 28 - i * 2), -1); |
||
| 442 | scores_draw_item(canvas, game_font, i, &menu->scores.stats[i]); |
||
| 443 | } |
||
| 444 | |||
| 445 | if ( menu->citem > -1 ) { |
||
| 446 | |||
| 447 | gr_set_fontcolor(canvas, BM_XRGB(7 + fades[menu->looper], 7 + fades[menu->looper], 7 + fades[menu->looper]), -1); |
||
| 448 | if (timer_query() >= menu->t1+F1_0/128) |
||
| 449 | { |
||
| 450 | menu->t1 = timer_query(); |
||
| 451 | menu->looper++; |
||
| 452 | if (menu->looper>63) menu->looper=0; |
||
| 453 | } |
||
| 454 | |||
| 455 | scores_draw_item(canvas, game_font, menu->citem, menu->citem == MAX_HIGH_SCORES |
||
| 456 | ? &menu->last_game |
||
| 457 | : &menu->scores.stats[menu->citem]); |
||
| 458 | } |
||
| 459 | } |
||
| 460 | break; |
||
| 461 | case EVENT_WINDOW_CLOSE: |
||
| 462 | d_free(menu); |
||
| 463 | break; |
||
| 464 | |||
| 465 | default: |
||
| 466 | break; |
||
| 467 | } |
||
| 468 | return window_event_result::ignored; |
||
| 469 | } |
||
| 470 | |||
| 471 | void scores_view(stats_info *last_game, int citem) |
||
| 472 | { |
||
| 473 | scores_menu *menu; |
||
| 474 | |||
| 475 | MALLOC(menu, scores_menu, 1); |
||
| 476 | if (!menu) |
||
| 477 | return; |
||
| 478 | |||
| 479 | menu->citem = citem; |
||
| 480 | menu->t1 = timer_query(); |
||
| 481 | menu->looper = 0; |
||
| 482 | if (last_game) |
||
| 483 | menu->last_game = *last_game; |
||
| 484 | |||
| 485 | newmenu_free_background(); |
||
| 486 | |||
| 487 | scores_read(&menu->scores); |
||
| 488 | |||
| 489 | set_screen_mode(SCREEN_MENU); |
||
| 490 | show_menus(); |
||
| 491 | |||
| 492 | const auto &&fspacx320 = FSPACX(320); |
||
| 493 | const auto &&fspacy200 = FSPACY(200); |
||
| 494 | window_create(grd_curscreen->sc_canvas, (SWIDTH - fspacx320) / 2, (SHEIGHT - fspacy200) / 2, fspacx320, fspacy200, |
||
| 495 | scores_handler, menu); |
||
| 496 | } |