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 | } |