1 /* -*- Mode: C++; c-basic-offset: 2; tab-width: 2; indent-tabs-mode: nil -*-
2 *
3 * Quadra, an action puzzle game
4 * Copyright (C) 1998-2000 Ludus Design
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "menu_demo_central.h"
22
23 #include "inter.h"
24 #include "bitmap.h"
25 #include "dict.h"
26 #include "clock.h"
27 #include "res_compress.h"
28 #include "find_file.h"
29 #include "fonts.h"
30 #include "zone.h"
31 #include "global.h"
32 #include "quadra.h"
33 #include "image_png.h"
34 #include "recording.h"
35 #include "game.h"
36 #include "multi_player.h"
37 #include "packets.h"
38 #include "config.h"
39
40 class Zone_change_dir: public Zone_text_input {
41 Menu_demo_central *menu_demo_central;
42 public:
43 Zone_change_dir(Inter *in, const Palette &p, char *s, int max, int x, int y, int w, Menu_demo_central *m);
44 virtual void lost_focus(int cancel);
45 };
46
Zone_change_dir(Inter * in,const Palette & p,char * s,int max,int x,int y,int w,Menu_demo_central * m)47 Zone_change_dir::Zone_change_dir(Inter *in, const Palette &p, char *s, int max, int x, int y, int w, Menu_demo_central *m):
48 Zone_text_input(in, p, s, max, x, y, w) {
49 menu_demo_central = m;
50 }
51
lost_focus(int cancel)52 void Zone_change_dir::lost_focus(int cancel) {
53 Zone_text_input::lost_focus(cancel);
54 if(cancel == 0)
55 menu_demo_central->reload();
56 }
57
Listitem(const char * n,Font * f)58 Menu_demo_central::Listitem::Listitem(const char *n, Font *f):
59 Listable(n, f) {
60 file_date[0] = 0;
61 file_size = 0;
62 }
63
~Listitem()64 Menu_demo_central::Listitem::~Listitem() {
65 }
66
Player_infos(int pplayer)67 Menu_demo_central::Player_infos::Player_infos(int pplayer) {
68 name[0]=0;
69 player=pplayer;
70 team=255;
71 }
72
Menu_demo_central()73 Menu_demo_central::Menu_demo_central() {
74 quel = -1;
75 {
76 Res_doze res("multi.png");
77 Png img(res);
78 bit = new Bitmap(img);
79 pal.load(img);
80 }
81 pal.set_size(256);
82 set_fteam_color(pal);
83
84 fcourrier[0] = new Font(*fonts.courrier, pal, 255,125,0);
85 fcourrier[1] = new Font(*fonts.courrier, pal, 0,225,255);
86 fcourrier[2] = new Font(*fonts.courrier, pal, 255,0,0);
87 fcourrier[3] = new Font(*fonts.courrier, pal, 255,0,255);
88 fcourrier[4] = new Font(*fonts.courrier, pal, 255,255,0);
89 fcourrier[5] = new Font(*fonts.courrier, pal, 0,255,0);
90 fcourrier[6] = new Font(*fonts.courrier, pal, 0,0,255);
91 fcourrier[7] = new Font(*fonts.courrier, pal, 170,170,170);
92
93 inter->set_font(new Font(*fonts.normal, pal, 255,255,255));
94 (void)new Zone_bitmap(inter, bit, 0, 0, true);
95 (void)new Zone_text(inter, "The Demo Central", 20);
96 (void)new Zone_text(fteam[7], inter, "Current directory:", 10, 50);
97 Find_file::get_current_directory(find_directory);
98 z_dir = new Zone_change_dir(inter, pal, find_directory, 900, 170, 50, 460, this);
99 z_list = new Zone_listbox2(inter, bit, fteam[4], &quel, 10, 90, 180, 300);
100 z_status = new Zone_text_field(inter, "", 0, 460, 640);
101 z_play = new Zone_text_button2(inter, bit, fteam[4], "�2 Start playback",
102 30, 400);
103 z_delete = new Zone_text_button2(inter, bit, fteam[4], "Delete demo",
104 30, 430);
105 cancel = new Zone_text_button2(inter, bit, fteam[4], "Back �0", 560, 430);
106 int y=90,ys=21;
107 (void)new Zone_text(fteam[7], inter, "Game name:", 210, y);
108 z_name = new Zone_text_field(inter, (char *) NULL, 335, y, 295,
109 fteam[1]); y+=ys;
110 (void)new Zone_text(fteam[7], inter, "Date & time:", 210, y);
111 z_date = new Zone_text_field(inter, (char *) NULL, 335, y, 295,
112 fteam[1]); y+=ys;
113 (void)new Zone_text(fteam[7], inter, "Version:", 210, y);
114 z_version = new Zone_text_field(inter, (char *) NULL, 335, y, 70,
115 fteam[1]); y+=ys;
116 (void)new Zone_text(fteam[7], inter, "Duration:", 210, y);
117 z_duration = new Zone_text_field(inter, (char *) NULL, 335, y, 295,
118 fteam[1]); y+=ys;
119 (void)new Zone_text(fteam[7], inter, "Game type:", 210, y);
120 z_type = new Zone_text_field(inter, (char *) NULL, 335, y, 295,
121 fteam[1]); y+=ys;
122 (void)new Zone_text(fteam[7], inter, "Game end:", 210, y);
123 z_end = new Zone_text_field(inter, (char *) NULL, 335, y, 295,
124 fteam[1]); y+=ys;
125
126 play = NULL;
127 reload();
128 }
129
~Menu_demo_central()130 Menu_demo_central::~Menu_demo_central() {
131 for(int i=0; i<MAXTEAMS; i++)
132 delete fcourrier[i];
133 if(play)
134 delete play;
135 while (!pinfos.empty()) {
136 delete pinfos.back();
137 pinfos.pop_back();
138 }
139 }
140
clear_detail()141 void Menu_demo_central::clear_detail() {
142 s_date[0] = 0;
143 s_name[0] = 0;
144 s_version[0] = 0;
145 s_duration[0] = 0;
146 s_type[0] = 0;
147 s_end[0] = 0;
148 if(play) {
149 delete play;
150 play = NULL;
151 }
152 list.deleteall();
153 while (!pinfos.empty()) {
154 delete pinfos.back();
155 pinfos.pop_back();
156 }
157 video->need_paint = 2;
158 }
159
refresh_detail()160 void Menu_demo_central::refresh_detail() {
161 z_date->set_val(s_date);
162 z_name->set_val(s_name);
163 z_version->set_val(s_version);
164 z_duration->set_val(s_duration);
165 z_type->set_val(s_type);
166 z_end->set_val(s_end);
167 }
168
drive_playback(const char * n)169 void Menu_demo_central::drive_playback(const char *n) {
170 char temp[1024];
171 snprintf(temp, sizeof(temp) - 1, "%s/%s", find_directory, n);
172 Res_compress *res = new Res_compress(temp, RES_TRY);
173 if(res->exist) {
174 play = new Playback(res);
175 if(play->completed || !play->valid) {
176 sprintf(st, "File '%s' is not a Quadra demo file", temp);
177 z_status->set_val(st);
178 delete play;
179 play = NULL;
180 }
181 else {
182 z_status->set_val("");
183 strcpy(s_version, "1.0.1");
184 strcpy(s_name, "-");
185 strcpy(s_duration, "-");
186 strcpy(s_date, "-");
187 if(play->packet_gameserver) {
188 strcpy(s_type, "Free for all");
189 if(play->packet_gameserver->survivor)
190 strcpy(s_type, "Survivor");
191 Attack_type nat=play->packet_gameserver->normal_attack.type;
192 Attack_type cat=play->packet_gameserver->clean_attack.type;
193 if(nat==ATTACK_NONE && cat==ATTACK_NONE)
194 strcpy(s_type, "Peace");
195 if(nat==ATTACK_BLIND || nat==ATTACK_FULLBLIND)
196 strcpy(s_type, "Blind");
197 if(play->packet_gameserver->hot_potato)
198 strcpy(s_type, "Hot potato");
199 switch(play->packet_gameserver->game_end) {
200 case END_NEVER:
201 strcpy(s_end, "Never");
202 break;
203 case END_FRAG:
204 sprintf(s_end, "After %i frags",
205 play->packet_gameserver->game_end_value);
206 break;
207 case END_TIME:
208 sprintf(s_end, "After %i minutes", play->packet_gameserver->game_end_value/6000);
209 if(play->single())
210 strcpy(s_type, "Sprint");
211 break;
212 case END_POINTS:
213 sprintf(s_end, "After %i points", play->packet_gameserver->game_end_value);
214 break;
215 case END_LINES:
216 sprintf(s_end, "After %i lines", play->packet_gameserver->game_end_value);
217 break;
218 default:
219 strcpy(s_end, "Unknown");
220 break;
221 }
222 }
223 if(play->single())
224 strcpy(s_type, "Single player");
225 populate_dict(play->sum);
226 }
227 }
228 else {
229 sprintf(st, "File '%s' is not a Quadra demo file", temp);
230 z_status->set_val(st);
231 }
232 delete res;
233 }
234
populate_dict(Dict * d)235 void Menu_demo_central::populate_dict(Dict *d) {
236 if(!d)
237 return;
238 const char *temp;
239 temp = d->find("name");
240 if(temp)
241 strcpy(s_name, temp);
242 temp = d->find("quadra_version");
243 if(temp)
244 strcpy(s_version, temp);
245 temp = d->find("duration");
246 if(temp) {
247 int dur = atoi(temp);
248 int min=dur/6000;
249 int sec=(dur%6000)/100;
250 if(min)
251 sprintf(s_duration, "%i minutes", min);
252 else
253 s_duration[0]=0;
254 if(sec) {
255 char st[100];
256 sprintf(st, "%i seconds", sec);
257 if(min)
258 strcat(s_duration, " ");
259 strcat(s_duration, st);
260 }
261 }
262 temp = d->find("time");
263 if(temp) {
264 int dur = atoi(temp);
265 temp = Clock::time2char(dur);
266 if(temp)
267 strcpy(s_date, temp);
268 }
269 int cx[5], cw[5];
270 cx[0] = 210;
271 cw[0] = 120;
272 cx[1] = cx[0] + cw[0] + 5;
273 cw[1] = 60;
274 cx[2] = cx[1] + cw[1] + 5;
275 cw[2] = 60;
276 cx[3] = cx[2] + cw[2] + 5;
277 cw[3] = 90;
278 cx[4] = cx[3] + cw[3] + 5;
279 cw[4] = 80;
280 int y=220, ys=21, i, j;
281 list.zones.push_back(new Zone_text(fteam[7], inter, "Players", cx[0], y));
282 if(!play->single()) {
283 list.zones.push_back(new Zone_text(fteam[7], inter, "Frags", cx[1], y));
284 list.zones.push_back(new Zone_text(fteam[7], inter, "Deaths", cx[2], y));
285 }
286 list.zones.push_back(new Zone_text(fteam[7], inter, "Score", cx[3], y));
287 list.zones.push_back(new Zone_text(fteam[7], inter, "Lines", cx[4], y)); y+=ys;
288 while (!pinfos.empty()) {
289 delete pinfos.back();
290 pinfos.pop_back();
291 }
292 Dict *players = d->find_sub("players");
293 if(players && players->size()<=MAXPLAYERS) {
294 for(i = 0; i < (int)players->size(); i++) {
295 const Dict *d2 = players->get_sub(i);
296 Player_infos *pi=new Player_infos(i);
297 pinfos.push_back(pi);
298 const char *name = d2->find("name");
299 if(name)
300 strcpy(pi->name, name);
301 temp = d2->find("team");
302 if(temp)
303 pi->team = atoi(temp);
304 }
305 //Reset score with freshly constructed Score object
306 Score score2;
307 score=score2;
308 score.updateFromDict(players);
309 Byte team_pos, team;
310 for(team_pos=0; team_pos<MAXTEAMS; team_pos++) {
311 team=score.team_order[team_pos];
312 for(j=0; j<MAXPLAYERS; j++) {
313 for(i=0; i<MAXPLAYERS; i++)
314 if(score.order[j]==i && score.player_team[i]==team)
315 break;
316 if (i < static_cast<int>(pinfos.size())) {
317 Player_infos* pi = pinfos[i];
318 Font *f=inter->font;
319 if(pi->team<=6)
320 f=fteam[pi->team];
321 list.zones.push_back(new Zone_text(f, inter, pi->name, cx[0], y));
322 int *statp;
323 if(!play->single()) {
324 statp=score.stats[i].stats[CS::FRAG].get_address();
325 list.zones.push_back(new Zone_text_field(inter, statp, cx[1], y, cw[1], fcourrier[pi->team], false));
326 statp=score.stats[i].stats[CS::DEATH].get_address();
327 list.zones.push_back(new Zone_text_field(inter, statp, cx[2], y, cw[2], fcourrier[pi->team], false));
328 }
329 statp=score.stats[i].stats[CS::SCORE].get_address();
330 list.zones.push_back(new Zone_text_field(inter, statp, cx[3], y, cw[3], fcourrier[pi->team], false));
331 statp=score.stats[i].stats[CS::LINESTOT].get_address();
332 list.zones.push_back(new Zone_text_field(inter, statp, cx[4], y, cw[4], fcourrier[pi->team], false));
333 y+=ys;
334 }
335 }
336 }
337 }
338 }
339
step()340 void Menu_demo_central::step() {
341 Menu_standard::step();
342 if(!result)
343 return;
344 if(result == cancel)
345 quit=true;
346 if(z_list->in_listbox(result)) {
347 Listitem *e = (Listitem *) z_list->get_selected();
348 if(e && !e->isfolder) {
349 clear_detail();
350 drive_playback(e->list_name);
351 refresh_detail();
352 } else {
353 clear_detail();
354 }
355 }
356 Zone *dbl = inter->double_clicked;
357 if(dbl && z_list->in_listbox(dbl)) {
358 Listitem *e = (Listitem *) z_list->get_selected();
359 if(e && e->isfolder) {
360 if(!strcmp(e->list_name, "..")) {
361 // treat the .. differently
362 char *t = strrchr(find_directory, '/');
363 if(t)
364 *t = 0;
365 }
366 else {
367 strcat(find_directory, "/");
368 strcat(find_directory, e->list_name);
369 }
370 z_dir->set_val(find_directory);
371 reload();
372 }
373 }
374 if((dbl && z_list->in_listbox(dbl)) || result == z_play) {
375 Listitem *e = (Listitem *) z_list->get_selected();
376 if(e && !e->isfolder) {
377 if(!play) {
378 clear_detail();
379 drive_playback(e->list_name);
380 refresh_detail();
381 }
382 if(play) {
383 play->shit_skipper2000(false);
384 call(new Fade_in(pal));
385 call(new Call_setfont(pal, new Demo_multi_player(play)));
386 call(new Fade_out(pal));
387 // the 'delete play' is done by ~Demo_multi_player
388 play = NULL;
389 }
390 }
391 }
392 if(result == z_delete) {
393 Listitem *e = (Listitem *) z_list->get_selected();
394 if(e && !e->isfolder) {
395 char temp[1024];
396 snprintf(temp, sizeof(temp) - 1, "%s/%s", find_directory, e->list_name);
397 remove(temp);
398 z_list->remove_item(e);
399 }
400 }
401 }
402
reload()403 void Menu_demo_central::reload() {
404 quel = -1;
405 #ifdef UGS_DIRECTX
406 do {
407 char *t = strchr(find_directory, '\\');
408 if(t)
409 *t = '/';
410 else
411 break;
412 } while(1);
413 #endif
414
415 z_list->clear();
416 clear_detail();
417 refresh_detail();
418 z_status->set_val("");
419
420 //Remove slashes from the end
421 char *temp=find_directory+strlen(find_directory)-1;
422 while(temp>=find_directory) {
423 if(*temp == '/')
424 *temp=0;
425 else
426 break;
427 temp--;
428 }
429 z_dir->set_val(find_directory);
430 char temp_search[1024];
431 snprintf(temp_search, sizeof(temp_search) - 1, "%s/*", find_directory);
432
433 msgbox("Menu_demo_central::find_all: Finding directories in [%s]...\n", temp_search);
434 {
435 Find_file *find_file = Find_file::New(temp_search);
436 if(find_file->has_error())
437 {
438 z_status->set_val("Warning: Invalid path.");
439 delete find_file;
440 return;
441 }
442 z_list->init_sort();
443 while(!find_file->eof()) {
444 Find_file_entry ff = find_file->get_next_entry();
445 if(ff.is_folder) {
446 if(ff.name[0] == '.' && ff.name[1] == 0) // ignore the "." directory
447 continue;
448 Listitem *e = new Listitem(ff.name, fteam[1]);
449 e->isfolder = true;
450 z_list->add_sort(e);
451 }
452 }
453 z_list->end_sort();
454 delete find_file;
455 }
456
457 snprintf(temp_search, sizeof(temp_search) - 1, "%s/*.rec", find_directory);
458
459 msgbox("Menu_demo_central::find_all: Finding files in [%s]...\n", find_directory);
460 {
461 Find_file *find_file = Find_file::New(temp_search);
462 z_list->init_sort();
463 while(!find_file->eof()) {
464 Find_file_entry ff = find_file->get_next_entry();
465 if(!ff.is_folder) {
466 Listitem *e = new Listitem(ff.name, fteam[5]);
467 e->file_size = ff.size;
468 strcpy(e->file_date, ff.date);
469 e->isfolder = false;
470 z_list->add_sort(e);
471 }
472 }
473 delete find_file;
474
475 snprintf(temp_search, sizeof(temp_search) - 1, "%s/*.qrec", find_directory);
476 find_file = Find_file::New(temp_search);
477 while(!find_file->eof()) {
478 Find_file_entry ff = find_file->get_next_entry();
479 if(!ff.is_folder) {
480 Listitem *e = new Listitem(ff.name, fteam[5]);
481 e->file_size = ff.size;
482 strcpy(e->file_date, ff.date);
483 e->isfolder = false;
484 z_list->add_sort(e);
485 }
486 }
487 delete find_file;
488
489 z_list->end_sort();
490 }
491 }
492