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