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 "quadra.h"
22 
23 #include "config.h"
24 #include "SDL.h"
25 #ifdef UGS_LINUX
26 #include <pwd.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #endif
30 #ifdef WIN32
31 #include <shlobj.h>
32 #endif
33 #include <stdlib.h>
34 #include <exception>
35 #include "packets.h"
36 #include "types.h"
37 #include "net.h"
38 #include "video.h"
39 #include "cursor.h"
40 #include "image_png.h"
41 #include "palette.h"
42 #include "input.h"
43 #include "sound.h"
44 #include "sprite.h"
45 #include "bitmap.h"
46 #include "inter.h"
47 #include "random.h"
48 #include "game.h"
49 #include "bloc.h"
50 #include "color.h"
51 #include "menu.h"
52 #include "main.h"
53 #include "overmind.h"
54 #include "command.h"
55 #include "multi_player.h"
56 #include "stringtable.h"
57 #include "net_stuff.h"
58 #include "chat_text.h"
59 #include "recording.h"
60 #include "canvas.h"
61 #include "global.h"
62 #include "sons.h"
63 #include "cfgfile.h"
64 #include "fonts.h"
65 #include "res_compress.h"
66 #include "highscores.h"
67 #include "crypt.h"
68 #include "unicode.h"
69 #include "nglog.h"
70 #include "clock.h"
71 #include "net_server.h"
72 #include "update.h"
73 
74 using std::max;
75 using std::min;
76 
77 Color *color[9];
78 Font *fteam[8];
79 bool video_is_dumb = false;
80 
set_fteam_color(const Palette & pal)81 void set_fteam_color(const Palette& pal) {
82 	fteam[0]->colorize(pal, 255,125,0);
83 	fteam[1]->colorize(pal, 0,225,255);
84 	fteam[2]->colorize(pal, 255,0,0);
85 	fteam[3]->colorize(pal, 255,0,255);
86 	fteam[4]->colorize(pal, 255,255,0);
87 	fteam[5]->colorize(pal, 0,255,0);
88 	fteam[6]->colorize(pal, 40,40,255);
89 	fteam[7]->colorize(pal, 170,170,170);
90 }
91 
raw_draw_bloc_corner(const Video_bitmap & bit,int x,int y,Byte side,Color * col,Byte to[4])92 void raw_draw_bloc_corner(const Video_bitmap& bit, int x, int y, Byte side, Color* col, Byte to[4]) {
93 	raw_draw_bloc(bit, x, y, side, col);
94 	if(!(side&1) && !(side&2) && to[0]&2 && to[1]&1) {
95 		bit.put_pel(x, y, col->shade(7));
96 		bit.put_pel(x+1, y, col->shade(6));
97 		bit.put_pel(x, y+1, col->shade(6));
98 		bit.put_pel(x+2, y, col->shade(5));
99 		bit.put_pel(x+1, y+1, col->shade(5));
100 		bit.put_pel(x, y+2, col->shade(5));
101 	}
102 	if(!(side&4) && !(side&2) && to[2]&2 && to[1]&4) {
103 		bit.put_pel(x+17, y, col->shade(1+2));
104 		bit.put_pel(x+16, y, col->shade(2+1));
105 		bit.put_pel(x+17, y+1, col->shade(2+2));
106 		bit.put_pel(x+15, y, col->shade(3));
107 		bit.put_pel(x+16, y+1, col->shade(3+1));
108 		bit.put_pel(x+17, y+2, col->shade(3+2));
109 	}
110 	if(!(side&1) && !(side&8) && to[0]&8 && to[3]&1) {
111 		bit.put_pel(x, y+17, col->shade(7));
112 		bit.put_pel(x+1, y+17, col->shade(6));
113 		bit.put_pel(x, y+16, col->shade(6));
114 		bit.put_pel(x+2, y+17, col->shade(5));
115 		bit.put_pel(x+1, y+16, col->shade(5));
116 		bit.put_pel(x, y+15, col->shade(5));
117 	}
118 	if(!(side&4) && !(side&8) && to[2]&8 && to[3]&4) {
119 		bit.put_pel(x+17, y+17, col->shade(1));
120 		bit.put_pel(x+16, y+17, col->shade(2));
121 		bit.put_pel(x+17, y+16, col->shade(2));
122 		bit.put_pel(x+15, y+17, col->shade(3));
123 		bit.put_pel(x+16, y+16, col->shade(3));
124 		bit.put_pel(x+17, y+15, col->shade(3));
125 	}
126 }
127 
raw_draw_bloc(const Video_bitmap & bit,int x,int y,Byte side,Color * col)128 void raw_draw_bloc(const Video_bitmap& bit, int x, int y, Byte side, Color* col) {
129 	int tx,tl,rx=0,ry=0,rw=18,rh=18;
130 	if(side&1) {
131 		bit.vline(x, y, 18, col->shade(7));
132 		bit.vline(x+1, y, 18, col->shade(6));
133 		bit.vline(x+2, y, 18, col->shade(5));
134 		rx=3; rw-=3;
135 	}
136 	if(side&2) {
137 		bit.hline(y, x, 18, col->shade(7));
138 		if(side&1)
139 			tx = x+1;
140 		else
141 			tx = x;
142 		bit.hline(y+1, tx, x-tx+18, col->shade(6));
143 		if(side&1)
144 			tx = x+2;
145 		else
146 			tx = x;
147 		bit.hline(y+2, tx, x-tx+18, col->shade(5));
148 		ry=3; rh-=3;
149 	}
150 	if(side&4) {
151 		bit.vline(x+17, y, 18, col->shade(1));
152 		if(side&2)
153 			tx = y+1;
154 		else
155 			tx = y;
156 		bit.vline(x+16, tx, y-tx+18, col->shade(2));
157 		if(side&2)
158 			tx = y+2;
159 		else
160 			tx = y;
161 		bit.vline(x+15, tx, y-tx+18, col->shade(3));
162 		rw-=3;
163 	}
164 	if(side&8) {
165 		bit.hline(y+17, x, 18, col->shade(1));
166 		if(side&1)
167 			tx = x+1;
168 		else
169 			tx = x;
170 		tl = x-tx+18;
171 		if(side&4)
172 			tl--;
173 		bit.hline(y+16, tx, tl, col->shade(2));
174 		if(side&1)
175 			tx = x+2;
176 		else
177 			tx = x;
178 		tl = x-tx+18;
179 		if(side&4)
180 			tl -= 2;
181 		bit.hline(y+15, tx, tl, col->shade(3));
182 		rh-=3;
183 	}
184 	Byte main_color=col->shade(4);
185 	for(int i=0; i<rh; i++)
186 		bit.hline(y+ry+i, x+rx, rw, main_color);
187 }
188 
raw_small_draw_bloc(const Video_bitmap & bit,int x,int y,Byte side,Color * col)189 void raw_small_draw_bloc(const Video_bitmap& bit, int x, int y, Byte side, Color* col) {
190 	int i,rx=0,ry=0,rw=6,rh=6;
191 	if(side&1) {
192 		bit.vline(x, y, 6, col->shade(7));
193 		rx++; rw--;
194 	}
195 	if(side&2) {
196 		bit.hline(y, x, 6, col->shade(7));
197 		ry++; rh--;
198 	}
199 	if(side&4) {
200 		bit.vline(x+5, y, 6, col->shade(1));
201 		rw--;
202 	}
203 	if(side&8) {
204 		bit.hline(y+5, x, 6, col->shade(1));
205 		rh--;
206 	}
207 	for(i=0; i<rh; i++)
208 		bit.hline(y+ry+i, x+rx, rw, col->shade(4));
209 }
210 
Player_check_link(Canvas * c)211 Player_check_link::Player_check_link(Canvas *c): Player_base(c) {
212 	anim = 0;
213 	tombe = 0;
214 	//Reset Canvas::moved
215 	int i, j;
216 	for(j=0; j<36; j++)
217 		for(i=0; i<18; i++)
218 			canvas->moved[j][i]=false;
219 }
220 
step()221 void Player_check_link::step() {
222 	Player_base::step();
223 	int i, j, k = 1;
224 	if(anim == 0) {
225 		while(k) {												 // rescan plusieurs pass
226 			k = 0;
227 			for(j = 31; j >= 0; j--) {						 // pour chaque rangee :
228 				for(i = 4; i < 14; i++) 						 // scan gauche a droite ->
229 					if((canvas->block[j][i]&8) && (!canvas->tmp[j][i]) && canvas->tmp[j+1][i]) {
230 						fill_bloc(i,j);
231 						k = 1;
232 					}
233 			}
234 		}
235 		anim++;
236 	} else {
237 		anim = 0;
238 		k = 0;
239 		//Temp move array
240 		bool moved[36][18];
241 		for(j=0; j<36; j++)
242 			for(i=0; i<18; i++)
243 				moved[j][i]=false;
244 		for(j = 31; j >= 0; j--)
245 			for(i = 4; i < 14; i++)
246 				if(canvas->occupied[j][i] && (!canvas->tmp[j][i])) {
247 					k = 1;
248 					canvas->block[j+1][i] = canvas->block[j][i];
249 					canvas->occupied[j+1][i] = canvas->occupied[j][i];
250 					moved[j+1][i] = true;
251 					canvas->blinded[j+1][i] = canvas->blinded[j][i];
252 					canvas->bflash[j+1][i] = canvas->bflash[j][i];
253 					canvas->dirted[j+1][i] = 2;
254 					canvas->block[j][i] = 0;
255 					canvas->occupied[j][i] = false;
256 					canvas->blinded[j][i] = 0;
257 					canvas->bflash[j][i] = 0;
258 					canvas->dirted[j][i] = 2;
259 				}
260 		if(k) {
261 			tombe++;
262 			//Some blocks moved, overwrite Canvas::moved
263 			for(j=0; j<36; j++) {
264 				bool movement_in_line=false;
265 				for(i=0; i<18; i++)
266 					if(moved[j][i])
267 						movement_in_line=true;
268 				if(movement_in_line)
269 					for(i=0; i<18; i++)
270 						canvas->moved[j][i]=moved[j][i];
271 			}
272 		}
273 		if(!k) {
274 			if(tombe) {
275 				i = -500 + tombe * 50;
276 				if(!canvas->islocal())
277 					i -= 1000;
278 				if(i>0)
279 					i=0;
280 				if(canvas->inter) {
281 					play_sound(sons.depose4, i, -1, 11000+ugs_random.rnd(127) - (canvas->complexity<<8));
282 				}
283 			}
284 			ret();//exec(new Player_check_line(canvas));
285 		}
286 	}
287 }
288 
fill_bloc(Byte x,Byte y)289 void Player_check_link::fill_bloc(Byte x, Byte y) {
290 	canvas->tmp[y][x] = 1;
291 	if((!(canvas->block[y][x]&8)) && (!canvas->tmp[y+1][x]))
292 		fill_bloc(x, y+1);
293 	if((!(canvas->block[y][x]&1)) && (!canvas->tmp[y][x-1]))
294 		fill_bloc(x-1, y);
295 	if((!(canvas->block[y][x]&4)) && (!canvas->tmp[y][x+1]))
296 		fill_bloc(x+1, y);
297 	if((!(canvas->block[y][x]&2)) && (!canvas->tmp[y-1][x]))
298 		fill_bloc(x, y-1);
299 }
300 
Player_flash_lines(Canvas * c)301 Player_flash_lines::Player_flash_lines(Canvas *c): Player_base(c) {
302 	anim = 0;
303 	canvas->color_flash = 255;
304 	if(canvas->inter) {
305 		int vo = -300 - ugs_random.rnd(255);
306 		if(!canvas->islocal())
307 			vo -= 1000;
308 		play_sound(sons.flash, vo, -1, 11000+ugs_random.rnd(127) - (canvas->complexity<<8));
309 	}
310 }
311 
step()312 void Player_flash_lines::step() {
313 	Player_base::step();
314 	int i;
315 	if(anim < 16) {
316 		if((anim>>1)&1)
317 			canvas->color_flash = 200;
318 		else
319 			canvas->color_flash = 255;
320 		anim++;
321 	} else {
322 		canvas->color_flash = 0;
323 		canvas->clear_tmp();
324 		anim = 0;
325 		for(i = 0; i < 20; i++)
326 			canvas->flash[i] = 0;
327 		exec(new Player_check_link(canvas));
328 	}
329 }
330 
step()331 void Player_base::step() {
332 	if(canvas->idle<3)
333 		canvas->gone_time=0;
334 	if(game && game->net_version()<23 && !game->paused && (canvas->idle==0 || canvas->idle==1))
335 		canvas->stats[CS::PLAYING_TIME].add(1);
336 	if(!((overmind.framecount+1)&127)) {
337 		int pm=0;
338 		int time=canvas->stats[CS::PLAYING_TIME].get_value();
339 		if(time)
340 			pm=(int)(canvas->stats[CS::SCORE].get_value()*6000.0/time);
341 		canvas->stats[CS::PPM].set_value(pm);
342 		pm=0;
343 		if(time)
344 			pm=(int)(canvas->stats[CS::COMPTETOT].get_value()*6000.0/time);
345 		canvas->stats[CS::BPM].set_value(pm);
346 	}
347 	if(game && !game->paused && !(overmind.framecount&15)) {
348 		int i, j;
349 		for(j=0; j<36; j++)
350 			for(i=0; i<18; i++)
351 				if(canvas->blinded[j][i]) {
352 					if(!--canvas->blinded[j][i]) {
353 						canvas->bflash[j][i]=24;
354 						canvas->dirted[j][i]=2;
355 					}
356 				}
357 	}
358 }
359 
calc_by(int py) const360 Byte Player_base::calc_by(int py) const {
361 	return (((py+15+(12*18<<4))>>4)+17)/18;
362 }
363 
check_gone()364 bool Player_base::check_gone() {
365 	{
366 		Packet_gone *p=(Packet_gone *) game->peekpacket(P_GONE);
367 		if(p && p->player==canvas->num_player) {
368 			bool chat_msg=p->chat_msg;
369 			game->removepacket();
370 			msgbox("Player_base::check_gone: Player %i is gone\n", canvas->num_player);
371 			exec(new Player_gone(canvas, chat_msg));
372 			ret();
373 			return true;
374 		}
375 	}
376 	if(game->abort || game->terminated) {
377 		if(canvas->islocal()) {
378 			msgbox("Player_base::check_gone: local player %i gone\n", canvas->num_player);
379 			Player_base *pb;
380 			if(game->terminated || game->server || canvas->idle==2 || canvas->dying || game->delay_start==500) {
381 				Packet_clientgone p;
382 				p.player=canvas->num_player;
383 				p.chat_msg=!game->terminated;
384 				net->sendtcp(&p);
385 				pb = new Player_gone(canvas, !game->terminated);
386 			}
387 			else {
388 				//Player_dead::Player_dead sends the packet
389 				pb = new Player_dead(canvas, true);
390 			}
391 			exec(pb);
392 			ret();
393 			return true;
394 		}
395 	}
396 	return false;
397 }
398 
check_state()399 void Player_base::check_state() {
400 	Packet_state *p=(Packet_state *) game->peekpacket(P_STATE);
401 	if(p && p->player==canvas->num_player) {
402 		msgbox("Player_base::check_state: player=%i, state=%i\n", p->player, p->state);
403 		canvas->state=(Canvas::State) p->state;
404 		game->removepacket();
405 	}
406 }
407 
remove_bonus()408 void Player_base::remove_bonus() {
409 	canvas->should_remove_bonus=false;
410 	canvas->bonus=0;
411 	if(canvas->islocal()) {
412 		Packet_clientremovebonus p;
413 		p.player=canvas->num_player;
414 		net->sendtcp(&p);
415 	}
416 }
417 
check_bonus()418 void Player_base::check_bonus() {
419 	Packet_removebonus *p=(Packet_removebonus *) game->peekpacket(P_REMOVEBONUS);
420 	if(p && p->player==canvas->num_player) {
421 		remove_bonus();
422 		game->removepacket();
423 	}
424 }
425 
play_sound(Sample * s,int vol,int pan,int freq)426 void Player_base::play_sound(Sample *s, int vol, int pan, int freq) {
427 	if(time_control == TIME_SLOW)
428 		freq = freq*2/3;
429 	if(time_control == TIME_FAST)
430 		freq = freq*3/2;
431   s->play(vol, pan, freq);
432 }
433 
Player_text_scroll(Canvas * c,const char * texte,int xoffset,int yoffset)434 Player_text_scroll::Player_text_scroll(Canvas *c, const char *texte, int xoffset, int yoffset): Player_base(c) {
435 	(void)new Zone_combo(&combo, canvas, texte, canvas->x + xoffset, canvas->y + 330 + yoffset);
436 	if(game)
437 		game->net_list.add_watch(this);
438 }
439 
~Player_text_scroll()440 Player_text_scroll::~Player_text_scroll() {
441 	if(game) // if ALT-F4: game is destroyed before this module... grr...
442 		game->net_list.remove_watch(this);
443 }
444 
notify()445 void Player_text_scroll::notify() {
446 	if(!game->net_list.get(canvas->num_player)) {
447 		stop();
448 	}
449 }
450 
step()451 void Player_text_scroll::step() {
452 	if(combo) {
453 		combo->y-=2;
454 		if(combo->y < canvas->y || canvas->inter==NULL || canvas->small_watch) {
455 			stop();
456 		}
457 	}
458 }
459 
stop()460 void Player_text_scroll::stop() {
461 	if(combo) {
462 		delete combo;
463 		combo=NULL;
464 	}
465 	ret();
466 }
467 
Player_add_bonus(Canvas * c)468 Player_add_bonus::Player_add_bonus(Canvas *c): Player_base(c) {
469 	anim = 0;
470 	first_done=false;
471 	if(canvas->inter) {
472 		int vo = -600;
473 		if(!canvas->islocal())
474 			vo -= 1000;
475 		play_sound(sons.bonus1, vo, -1, 11000+ugs_random.rnd(511));
476 	}
477 	nb=canvas->bonus;
478 }
479 
~Player_add_bonus()480 Player_add_bonus::~Player_add_bonus() {
481 }
482 
step()483 void Player_add_bonus::step() {
484 	Player_base::step();
485 	int y, i, j;
486 	bool old_net_version=false;
487 	if(game->net_version()<23)
488 		old_net_version=true;
489 	if(nb && canvas->bonus) {
490 		if(anim == 0) {
491 			for(j = 0; j < 31; j++)
492 				for(i = 4; i < 14; i++) {
493 					canvas->block[j][i] = canvas->block[j+1][i];
494 					canvas->occupied[j][i] = canvas->occupied[j+1][i];
495 					canvas->blinded[j][i] = canvas->blinded[j+1][i];
496 					canvas->bflash[j][i] = canvas->bflash[j+1][i];
497 					canvas->dirted[j+1][i] = 2;
498 				}
499 			Word hole_pos=canvas->bon[0].hole_pos;
500 			if(old_net_version)
501 				hole_pos=(1 << (9-(canvas->bon[0].x-4)));
502 			Byte top_bottom_add=0;
503 			if(!first_done || old_net_version)
504 				top_bottom_add |= 2; //Add top
505 			if(canvas->bon[0].final || old_net_version)
506 				top_bottom_add |= 8; //Add bottom
507 			for(i = 4; i < 14; i++) {
508 				canvas->block[31][i] = top_bottom_add + (canvas->bon[0].color<<4);
509 				canvas->occupied[31][i] = true;
510 			}
511 			for(i = 4; i < 14; i++) {
512 				if(hole_pos&512) {
513 					canvas->block[31][i] = 0;
514 					canvas->occupied[31][i] = false;
515 					if(first_done && canvas->occupied[30][i]) {
516 						//First line done in this packet and corresponding
517 						//  unit block above is not a hole: add bottom
518 						canvas->block[30][i] |= 8;
519 					}
520 					if(i > 4) {
521 						if(canvas->occupied[31][i-1])
522 							canvas->block[31][i-1] |= 4;
523 						if(canvas->occupied[31][4])
524 							canvas->block[31][4] |= 1;
525 					}
526 					if(i < 14) {
527 						canvas->block[31][i+1] |= 1;
528 						canvas->block[31][14] |= 4;
529 					}
530 				}
531 				else {
532 					if(first_done && !canvas->occupied[30][i]) {
533 						//First line done in this packet and corresponding
534 						//  unit block above is a hole: add top
535 						canvas->block[31][i] |= 2;
536 					}
537 				}
538 				canvas->blinded[31][i] = 0;
539 				canvas->bflash[31][i] = 0;
540 				hole_pos <<= 1;
541 			}
542 			first_done=true;
543 			if(canvas->bon[0].final)
544 				first_done=false;
545 		}
546 		anim++;
547 		if(anim == 7) {
548 			for(y = 1; y < canvas->bonus; y++)
549 				canvas->bon[y-1] = canvas->bon[y];
550 			canvas->bonus--;
551 			nb--;
552 			anim=0;
553 		}
554 	} else {
555 		for(i = 4; i < 14; i++)
556 			if(canvas->occupied[0][i])
557 				canvas->block[0][i] |= 2; 		// clip top
558 		canvas->clear_tmp();
559 		call(new Player_check_link(canvas));
560 		ret();
561 	}
562 }
563 
Player_change_level(Canvas * c)564 Player_change_level::Player_change_level(Canvas *c): Player_base(c) {
565 	canvas->myself->pause();
566 }
567 
~Player_change_level()568 Player_change_level::~Player_change_level() {
569 	canvas->myself->unpause();
570 }
571 
init()572 void Player_change_level::init() {
573 	Player_base::init();
574 	canvas->change_level_single();
575 	if(canvas->inter) {
576 		canvas->inter->font->colorize(*canvas->pal, 255, 255, 255);
577 		video->need_paint = 2;
578 	}
579 	int nframe=16;
580 	if(time_control == TIME_SLOW)
581 		nframe = nframe*3/2;
582 	if(time_control == TIME_FAST)
583 		nframe = 3;
584 	call(new Fade_to(*canvas->pal, noir, nframe));
585 	call(new Wait_time(14)); // so that the 'level up' doesn't jerk
586 	ret();
587 }
588 
Player_level_up(Canvas * c)589 Player_level_up::Player_level_up(Canvas *c): Player_base(c) {
590 	canvas->level_up = 220;
591 	if(canvas->islocal() || (canvas->inter && !canvas->small_watch))
592 		Player_base::play_sound(sons.levelup, -200-ugs_random.rnd(127), 0, 11000);
593 }
594 
init()595 void Player_level_up::init() {
596 	Player_base::init();
597 	if(game->single) {  // && (canvas->level-1<=9 || game->net_version()<23)) {
598 		call(new Player_change_level(canvas));
599 		int nframe=16;
600 		if(time_control == TIME_SLOW)
601 			nframe = nframe*3/2;
602 		if(time_control == TIME_FAST)
603 			nframe = 3;
604 		call(new Fade_to(noir, *canvas->pal, nframe));
605 	}
606 }
607 
step()608 void Player_level_up::step() {
609 	Player_base::step();
610 	canvas->level_up--;
611 	if(canvas->level_up < 0) {
612 		canvas->level_up = 0;
613 		ret();
614 	}
615 }
616 
Player_check_line(Canvas * c)617 Player_check_line::Player_check_line(Canvas *c): Player_base(c) {
618 }
619 
step()620 void Player_check_line::step() {
621 	Player_base::step();
622 	int co = check_nb_line();
623 	if(co) {
624 		canvas->depth += co;
625 		canvas->complexity++;
626 		check_clean();
627 		call(new Player_flash_lines(canvas));
628 	} else {
629 		if(canvas->idle < 2) { // if alive
630 			//Copy hole positions into moved array so that give_line
631 			//  and Net_list::send can use them
632 			int i, j;
633 			for(j=0; j<36; j++)
634 				for(i=0; i<18; i++)
635 					canvas->moved[j][i]=hole_pos[j][i];
636 			canvas->give_line();
637 		} else { // if dead, useless
638 			canvas->depth = 0;
639 			canvas->complexity=0;
640 			canvas->send_for_clean=0;
641 		}
642 		ret();
643 	}
644 }
645 
check_nb_line()646 int Player_check_line::check_nb_line() {
647 	int co = 0, i, j;
648 	for(j = 12; j < 32; j++) {
649 		for(i = 4; i < 14; i++)
650 			if(!canvas->occupied[j][i])
651 				break;
652 		if(i == 14) {
653 			if(co < 20)
654 				canvas->flash[co] = j;
655 			for(i = 4; i < 14; i++) {
656 				if(canvas->occupied[j-1][i] && !(canvas->block[j-1][i]&8)) {
657 					canvas->block[j-1][i] |= 8;
658 					canvas->dirted[j-1][i] = 2;
659 				}
660 				hole_pos[canvas->depth+co][i]=canvas->moved[j][i];
661 				canvas->block[j][i] = 0;
662 				canvas->occupied[j][i] = false;
663 				canvas->blinded[j][i] = 0;
664 				canvas->bflash[j][i] = 0;
665 				canvas->dirted[j][i] = 2;
666 				if(canvas->occupied[j+1][i] && !(canvas->block[j+1][i]&2)) {
667 					canvas->block[j+1][i] |= 2;
668 					canvas->dirted[j+1][i] = 2;
669 				}
670 			}
671 			co++;
672 		}
673 	}
674 	return co;
675 }
676 
check_clean()677 void Player_check_line::check_clean() {
678 	int i, j;
679 	for(j = 12; j < 32; j++)
680 		for(i = 4; i < 14; i++)
681 			if(canvas->occupied[j][i])
682 				return;
683 	canvas->add_text_scroller("Clean Canvas!!");
684 	if(game->net_version()<23)
685 		canvas->stats[CS::SCORE].add(5000);
686 	canvas->send_for_clean=true;
687 }
688 
Player_process_key(Canvas * c)689 Player_process_key::Player_process_key(Canvas *c): Player_base(c) {
690 	hold_left = hold_right = 0;
691 	last_video_frame = last_overmind_frame = 0;
692 	canvas->idle = 1;
693 	canvas->state = Canvas::PLAYING;
694 	block_rotated=0;
695 	time_held=0;
696 }
697 
rotate_left()698 bool Player_base::rotate_left() {
699 	bool ret=false;
700 	int t, i;
701 	t = (canvas->bloc->rot-1)&3;
702 	if(!canvas->collide(canvas->bloc->bx, canvas->bloc->by, t)) {
703 		ret=true;
704 		canvas->bloc->rot = t;
705 		if(canvas->inter) {
706 			i = (canvas->bloc->bx-9) * 300;
707 			play_sound(sons.drip, -200-ugs_random.rnd(127), i, 10500+ugs_random.rnd(1023));
708 		}
709 	}
710 	canvas->set_bit(8);
711 	return ret;
712 }
713 
rotate_right(bool twice)714 bool Player_base::rotate_right(bool twice) {
715 	bool ret=false;
716 	int t, i;
717 	int inc=1;
718 	if(twice)
719 		inc=2;
720 	t = (canvas->bloc->rot+inc)&3;
721 	if(!canvas->collide(canvas->bloc->bx, canvas->bloc->by, t)) {
722 		ret=true;
723 		canvas->bloc->rot = t;
724 		if(canvas->inter) {
725 			i = (canvas->bloc->bx-9) * 300;
726 			play_sound(sons.drip, -200-ugs_random.rnd(127), i, 10500+ugs_random.rnd(1023));
727 		}
728 	}
729 	if(twice)
730 		canvas->set_bit(32);
731 	else
732 		canvas->set_bit(16);
733 	return ret;
734 }
735 
move_down()736 void Player_base::move_down() {
737 	int t;
738 	t = calc_by(canvas->bloc->y+canvas->down_speed);
739 	if(!canvas->collide(canvas->bloc->bx, t, canvas->bloc->rot)) {
740 		canvas->bloc->y += canvas->down_speed;
741 		canvas->bloc->by = calc_by(canvas->bloc->y);
742 	} else { // is used to "settle" the block so that it drops
743 		canvas->bloc->y = ((canvas->bloc->by-12)*18<<4)-1;
744 	}
745 	canvas->set_bit(1);
746 }
747 
drop_down()748 void Player_base::drop_down() {
749 	while(!canvas->check_collide(canvas->bloc, canvas->bloc->bx, canvas->bloc->by+1, canvas->bloc->rot))
750 		canvas->bloc->by++;
751 	canvas->bloc->calc_xy();
752 	canvas->set_bit(64);
753 }
754 
move_left()755 bool Player_base::move_left() {
756 	bool ret=false;
757 	if(!canvas->collide(canvas->bloc->bx-1, canvas->bloc->by, canvas->bloc->rot)) {
758 		ret=true;
759 		canvas->bloc->bx--;
760 	}
761 	canvas->set_bit(2);
762 	return ret;
763 }
764 
move_right()765 bool Player_base::move_right() {
766 	bool ret=false;
767 	if(!canvas->collide(canvas->bloc->bx+1, canvas->bloc->by, canvas->bloc->rot)) {
768 		ret=true;
769 		canvas->bloc->bx++;
770 	}
771 	canvas->set_bit(4);
772 	return ret;
773 }
774 
playback_control()775 void Player_process_key::playback_control() {
776 	Byte r = playback->get_byte();
777 	if(r & 8)
778 		rotate_left();
779 	if(r & 16)
780 		rotate_right();
781 	if(r & 1)
782 		move_down();
783 	if(r & 2)
784 		move_left();
785 	if(r & 4)
786 		move_right();
787 }
788 
keyboard_control()789 void Player_process_key::keyboard_control() {
790 	if(last_video_frame == video->framecount && overmind.framecount - last_overmind_frame > 3)
791 		return;
792 	if(last_video_frame != video->framecount) {
793 		last_video_frame = video->framecount;
794 		last_overmind_frame = overmind.framecount;
795 	}
796 
797 	bool bouge_left = false;
798 	bool bouge_right = false;
799 	bool auto_bouge = false;
800 	if(canvas->check_key(2) & RELEASED) {
801 		if(rotate_left())
802 			block_rotated++;
803 		else {
804 			if(canvas->collide_side_only) {
805 				int inc;
806 				if(canvas->bloc->bx<5)
807 					inc=1;
808 				else
809 					inc = -1;
810 				if(!canvas->collide(canvas->bloc->bx+inc, canvas->bloc->by, canvas->bloc->rot)) {
811 					canvas->bloc->bx+=inc;
812 					if(rotate_left()) {
813 						auto_bouge=true;
814 						block_rotated++;
815 					}
816 					else
817 						canvas->bloc->bx-=inc;
818 				}
819 			}
820 		}
821 		canvas->clear_key(2);
822 	}
823 	if(canvas->check_key(4) & RELEASED) {
824 		if(rotate_right())
825 			block_rotated++;
826 		else {
827 			if(canvas->collide_side_only) {
828 				int inc;
829 				if(canvas->bloc->bx<5)
830 					inc=1;
831 				else
832 					inc = -1;
833 				if(!canvas->collide(canvas->bloc->bx+inc, canvas->bloc->by, canvas->bloc->rot)) {
834 					canvas->bloc->bx+=inc;
835 					if(rotate_right()) {
836 						auto_bouge=true;
837 						block_rotated++;
838 					}
839 					else
840 						canvas->bloc->bx-=inc;
841 				}
842 			}
843 		}
844 		canvas->clear_key(4);
845 	}
846 	if(canvas->check_key(5) & RELEASED) {
847 		if(rotate_right(true))
848 			block_rotated++;
849 		else {
850 			if(canvas->collide_side_only) {
851 				int inc;
852 				if(canvas->bloc->bx<5)
853 					inc=1;
854 				else
855 					inc = -1;
856 				if(!canvas->collide(canvas->bloc->bx+inc, canvas->bloc->by, canvas->bloc->rot)) {
857 					canvas->bloc->bx+=inc;
858 					if(rotate_right(true)) {
859 						auto_bouge=true;
860 						block_rotated++;
861 					}
862 					else
863 						canvas->bloc->bx-=inc;
864 				}
865 			}
866 		}
867 		canvas->clear_key(5);
868 	}
869 	if(canvas->check_key(3) & PRESSED || canvas->check_key(3) & RELEASED) {
870 		move_down();
871 		canvas->unrelease_key(3);
872 	}
873 	if(canvas->check_key(6) & PRESSED) {
874 		drop_down();
875 		canvas->clear_key(6);
876 	}
877 	if(canvas->check_key(0) & PRESSED || canvas->check_key(0) & RELEASED) {
878 		if(!bouge_left) {
879 			bouge_left = true;
880 			canvas->unrelease_key(0);
881 		}
882 	}
883 	if(canvas->check_key(1) & PRESSED || canvas->check_key(1) & RELEASED) {
884 		if(!bouge_right) {
885 			bouge_right = true;
886 			canvas->unrelease_key(1);
887 		}
888 	}
889 	if(bouge_left && !bouge_right && !auto_bouge) {
890 		if(hold_left < 2) {
891 			if(hold_left == 0)
892 				hold_left = canvas->h_repeat_delay+10;	// initial repeating delay
893 			else
894 				hold_left = canvas->h_repeat_delay;
895 			if(!move_left())
896 				hold_left=1;
897 		} else
898 			hold_left--;
899 	} else
900 		hold_left = 0;
901 	if(bouge_right && !bouge_left && !auto_bouge) {
902 		if(hold_right < 2) {
903 			if(hold_right == 0)
904 				hold_right = canvas->h_repeat_delay+10;
905 			else
906 				hold_right = canvas->h_repeat_delay;
907 			if(!move_right())
908 				hold_right=1;
909 		} else
910 			hold_right--;
911 	} else
912 		hold_right = 0;
913 }
914 
init()915 void Player_process_key::init() {
916 	Player_base::init();
917 //	canvas->clear_key(2);
918 //	canvas->clear_key(4);
919 //	canvas->clear_key(5);
920 	canvas->clear_key(6);
921 	if(!canvas->continuous)
922 		canvas->clear_key(3);
923 	canvas->start_moves();
924 }
925 
step()926 void Player_process_key::step() {
927 	Player_base::step();
928 	if(check_gone())
929 		return;
930 
931 	if(canvas->should_remove_bonus)
932 		remove_bonus();
933 
934 	int t, i;
935 	if(game->survivor)
936 		if(check_first_frag())
937 			return;
938 	if(game->paused)
939 		return;
940 
941 	time_held++;
942 	canvas->start_byte();
943 
944 	if(playback)
945 		playback_control();
946 	else {
947 		if(canvas->inter) // if the canvas is hidden, don't listen to keys
948 			keyboard_control();
949 	}
950 
951 	canvas->write_byte();
952 
953 	t = ((canvas->bloc->bx-4)<<4)*18; // compute the position where the block should be
954 	int nx = canvas->bloc->x; // new position 'x' to obtain
955 	if(nx < t) {
956 		nx += canvas->side_speed;
957 		if(nx > t) // if past the position
958 			nx = t;
959 	}
960 	if(nx > t) {
961 		nx -= canvas->side_speed;
962 		if(nx < t) // if past the position
963 			nx = t;
964 	}
965 	t = calc_by(canvas->bloc->y-(17<<4)-15);
966 	if(!canvas->collide(canvas->bloc->bx, t, canvas->bloc->rot))
967 		canvas->bloc->x = nx; // accepte le deplacement 'smooth' seulement s'il ne passe pas par-dessus un bloc
968 	t = calc_by(canvas->bloc->y+canvas->speed);
969 	if(canvas->collide(canvas->bloc->bx, t, canvas->bloc->rot)) {
970 		canvas->send_p_moves();
971 		Packet_clientstampblock p;
972 		p.rotate=canvas->bloc->rot;
973 		p.x=canvas->bloc->bx;
974 		p.y=canvas->bloc->by;
975 		p.player=canvas->num_player;
976 		if(game->net_version()<23) {
977 			i = max(overmind.framecount - canvas->frame_start - 50, static_cast<unsigned int>(0));
978 			p.score=max(0, 100 - i) >> 1;
979 		}
980 		else
981 			p.score=0;
982 		p.date = canvas->watch_date++;
983 		if(block_rotated>255)
984 			block_rotated=255;
985 		p.block_rotated=block_rotated;
986 		if(time_held>65535)
987 			time_held=65535;
988 		p.time_held=time_held;
989 		net->sendtcp(&p);
990 		exec(new Player_stamp(canvas, &p));
991 		return;
992 	}
993 	else {
994 		canvas->bloc->y+=canvas->speed;
995 		canvas->bloc->by = calc_by(canvas->bloc->y);
996 		if(canvas->shadow)
997 			canvas->calc_shadow();
998 	}
999 }
1000 
check_first_frag()1001 bool Player_process_key::check_first_frag() {
1002 	if(game->net_list.syncpoint==Canvas::PLAYING)
1003 		return false;
1004 	if(game->net_list.syncpoint==Canvas::LAST)
1005 		return false;
1006 	//If syncing toward WAITFORWINNER or WAITFORRESTART,
1007 	//	go to first_frag state
1008 	canvas->send_p_moves();
1009 	Packet_clientfirst_frag pf;
1010 	pf.player = canvas->num_player;
1011 	net->sendtcp(&pf);
1012 	exec(new Player_first_frag(canvas));
1013 	return true;
1014 }
1015 
step()1016 void Player_get_next::step() {
1017 	Player_base::step();
1018 	while(!canvas->bloc)
1019 		shift_next();
1020 
1021 	canvas->set_next();
1022 	canvas->frame_start = overmind.framecount;
1023 	ret();
1024 }
1025 
shift_next()1026 void Player_get_next::shift_next() {
1027 	canvas->bloc = canvas->next3;
1028 	canvas->next3 = canvas->next2;
1029 	canvas->next2 = canvas->next;
1030 	Byte the_next;
1031 	if(game->net_version()>=23)
1032 		the_next=canvas->rnd.rnd()%7;
1033 	else
1034 		the_next=canvas->rnd.crap_rnd()%7;
1035 	canvas->next = new Bloc(the_next, -1, 7, 10);
1036 }
1037 
Player_normal(Canvas * c)1038 Player_normal::Player_normal(Canvas *c): Player_base(c) {
1039 	canvas->idle = 1;
1040 	canvas->state = Canvas::PLAYING;
1041 }
1042 
step()1043 void Player_normal::step() {
1044 	Player_base::step();
1045 
1046 	if(!canvas->bloc)
1047 		call(new Player_get_next(canvas));
1048 	else {
1049 		//If this is a local player, check death condition
1050 		if(canvas->islocal()) {
1051 			if(canvas->collide(canvas->bloc->bx, canvas->bloc->by, canvas->bloc->rot)) {
1052 				bool tg=false;
1053 				if(game->single)
1054 					tg=true;
1055 				call(new Player_dead(canvas));
1056 			}
1057 			else {
1058 				call(new Player_process_key(canvas));
1059 			}
1060 		}
1061 		else {
1062 			//Not local, wait for next block or death
1063 			call(new Player_wait_block(canvas));
1064 		}
1065 	}
1066 }
1067 
Player_dead(Canvas * c,bool tg)1068 Player_dead::Player_dead(Canvas *c, bool tg): Player_base(c), then_gone(tg) {
1069 	canvas->dying=true;
1070   for(j=0; j<36; j++)
1071     for(i=0; i<18; i++) {
1072 			if(canvas->blinded[j][i]) {
1073 				canvas->bflash[j][i] = 24;
1074 				canvas->dirted[j][i] = 2;
1075 			}
1076 			canvas->blinded[j][i] = 0;
1077 		}
1078 	if(canvas->islocal()) {
1079 		//If local, tell server that we died
1080 		Packet_clientdead p;
1081 		p.player=canvas->num_player;
1082 		p.then_gone=then_gone;
1083 		net->sendtcp(&p);
1084 	}
1085 	Canvas* fragger = NULL;
1086 	if(canvas->last_attacker != 255)
1087 		fragger = game->net_list.get(canvas->last_attacker);
1088 	if(fragger)
1089 		msgbox("Player_dead::Player_dead: %s a ete fragger par %s. attacks[]=", canvas->name, fragger->name);
1090 	else
1091 		msgbox("Player_dead::Player_dead: %s est mort sans frag. attacks[]=", canvas->name);
1092 	for(int i2=0; i2<MAXPLAYERS; i2++)
1093 		msgbox("%i,", canvas->attacks[i2]);
1094 	msgbox("\n");
1095 	if(fragger) {
1096 		fragger->stats[CS::FRAG].add(1);
1097 		sprintf(st, "%s fragged %s!", fragger->name, c->name);
1098 		message(fragger->color, st);
1099 
1100 		couleur = fragger->color<<4; // couleur du 'fragger'
1101 		sprintf(st, "Fragged %s!", c->name);
1102 		fragger->add_text_scroller(st);
1103 	} else {
1104 		sprintf(st, "%s died.", c->name);
1105 		message(-1, st);
1106 		couleur = 8<<4; // gris pour mort naturelle
1107 	}
1108 	canvas->stats[CS::DEATH].add(1);
1109 	const char *death_type="normal";
1110 	//Suicide: less than 9 unit blocks in the 2 lines right
1111 	//  below the top
1112 	int num_units=0;
1113 	for(i=14; i<16; i++)
1114 		for(j=4; j<14; j++)
1115 			if(canvas->occupied[i][j])
1116 				num_units++;
1117 	bool suicide=false;
1118 	if(num_units<9)
1119 		suicide=true;
1120 	if(then_gone) {
1121 		death_type="left";
1122 		suicide=false;
1123 	}
1124 	//Overkill and maximum overkill
1125 	for(i=0; i<12; i++) {
1126 		num_units=0;
1127 		for(j=4; j<14; j++)
1128 			if(canvas->occupied[i][j])
1129 				num_units++;
1130 		if(num_units>=8)
1131 			break;
1132 	}
1133 	if(i<10 && i>=7) {
1134 		death_type="overkill";
1135 		if(fragger)
1136 			fragger->stats[CS::OVERKILLER].add(1);
1137 		canvas->stats[CS::OVERKILLEE].add(1);
1138 		suicide=false;
1139 	}
1140 	if(i<7) {
1141 		death_type="maximum_overkill";
1142 		if(fragger)
1143 			fragger->stats[CS::MAXOVERKILLER].add(1);
1144 		canvas->stats[CS::MAXOVERKILLEE].add(1);
1145 		suicide=false;
1146 	}
1147 	if(suicide) {
1148 		death_type="suicide";
1149 		canvas->stats[CS::SUICIDES].add(1);
1150 	}
1151 	Packet_serverlog log("player_dead");
1152 	log.add(Packet_serverlog::Var("id", canvas->id()));
1153 	log.add(Packet_serverlog::Var("fragger_id", fragger? fragger->id():0));
1154 	log.add(Packet_serverlog::Var("type", death_type));
1155 	if(game && game->net_server)
1156 		game->net_server->record_packet(&log);
1157 	i = 11;
1158 	j = 4;
1159 	Player_dead::c = 0;
1160 	canvas->delete_bloc();
1161 	canvas->set_next();
1162 }
1163 
step()1164 void Player_dead::step() {
1165 	Player_base::step();
1166 
1167 	if(c++&1)
1168 		return;
1169 	if(j < 9) {
1170 		if(canvas->occupied[i][j]) {
1171 			canvas->block[i][j] = (canvas->block[i][j] & 15) + couleur;
1172 			canvas->dirted[i][j] = 2;
1173 		}
1174 		if(canvas->occupied[42-i][j]) {
1175 			canvas->block[42-i][j] = (canvas->block[42-i][j] & 15) + couleur;
1176 			canvas->dirted[42-i][j] = 2;
1177 		}
1178 		if(canvas->occupied[i][17-j]) {
1179 			canvas->block[i][17-j] = (canvas->block[i][17-j] & 15) + couleur;
1180 			canvas->dirted[i][17-j] = 2;
1181 		}
1182 		if(canvas->occupied[42-i][17-j]) {
1183 			canvas->block[42-i][17-j] = (canvas->block[42-i][17-j] & 15) + couleur;
1184 			canvas->dirted[42-i][17-j] = 2;
1185 		}
1186 		int vo = -600;
1187 		if(!canvas->islocal())
1188 			vo -= 1000;
1189 
1190 		i++;
1191 		if(i == 22) {
1192 			j++;
1193 			i = 11;
1194 			if(canvas->inter)
1195 				play_sound(sons.flash, vo, -1, 22500+ugs_random.rnd(1023));
1196 		}
1197 	}
1198 	else {
1199 		canvas->dying=false;
1200 		if(then_gone)
1201 			exec(new Player_gone(canvas, true));
1202 		else
1203 			if(canvas->islocal())
1204 				exec(new Player_dead_wait(canvas));
1205 			else
1206 				exec(new Player_wait_respawn(canvas));
1207 	}
1208 }
1209 
Player_dead_wait(Canvas * c,bool ab)1210 Player_dead_wait::Player_dead_wait(Canvas *c, bool ab): Player_base(c), add_bonus(ab) {
1211 	if(canvas->inter)
1212 		canvas->clear_key_all();
1213 	canvas->idle = 2;
1214 	canvas->state = Canvas::WAITFORWINNER;
1215 }
1216 
init()1217 void Player_dead_wait::init() {
1218 	Player_base::init();
1219 	if(game->single || game->delay_start)
1220 		return;
1221 	if(game->survivor)
1222 		canvas->set_message("Waiting for the", "        next round...");
1223 	else
1224 		canvas->set_message("Press a key to", "        restart.");
1225 }
1226 
step()1227 void Player_dead_wait::step() {
1228 	Player_base::step();
1229 	if(check_gone())
1230 		return;
1231 
1232 	if(canvas->should_remove_bonus)
1233 		remove_bonus();
1234 
1235 	bool restart=false;
1236 
1237 	if(playback && playback->old_mode) {
1238 		if(playback->get_byte())
1239 			restart = true;
1240 	}
1241 	else {
1242 		if(canvas->inter) {// si canvas invisible, ecoute pas les touches!
1243 			for(int i=0; i<7; i++)
1244 				if(canvas->check_key(i))
1245 					restart = true;
1246 		}
1247 	}
1248 
1249 	if(game->survivor) {
1250 		restart = check_first_frag();
1251 	}
1252 	else
1253 		if(game->hot_potato && canvas->color==game->potato_team) {
1254 			//Sorry mister, your buddies are still juggling the hot
1255 			//  potato, you can't go help them yet! :)
1256 			restart=false;
1257 		}
1258 	//Never restart in single-player games
1259 	if(game->single)
1260 		restart=false;
1261 	if(restart) {
1262 		Packet_clientrespawn p;
1263 		p.player=canvas->num_player;
1264 		net->sendtcp(&p);
1265 		canvas->restart();
1266 		ret();
1267 		Packet_serverlog log("player_respawn");
1268 		log.add(Packet_serverlog::Var("id", canvas->id()));
1269 		if(game && game->net_server)
1270 			game->net_server->record_packet(&log);
1271 	}
1272 	else {
1273 		if(canvas->bonus && !canvas->bon[0].blind_time && add_bonus)
1274 			call(new Player_add_bonus(canvas));
1275 	}
1276 }
1277 
check_first_frag()1278 bool Player_dead_wait::check_first_frag() {
1279 	switch(canvas->state) {
1280 		case Canvas::WAITFORWINNER:
1281 			if(game->net_list.syncpoint==Canvas::WAITFORRESTART) {
1282 				canvas->state = Canvas::WAITFORRESTART;
1283 				Packet_clientstate p;
1284 				p.player = canvas->num_player;
1285 				p.state = canvas->state;
1286 				net->sendtcp(&p);
1287 			}
1288 			break;
1289 		case Canvas::WAITFORRESTART:
1290 			if(game->net_list.syncpoint==Canvas::PLAYING)
1291 				return true;
1292 		case Canvas::PLAYING:
1293 		case Canvas::LAST:
1294 			break;
1295 	}
1296 	return false;
1297 }
1298 
Player_first_frag(Canvas * c)1299 Player_first_frag::Player_first_frag(Canvas *c): Player_base(c) {
1300 	canvas->dying=true;
1301   for(j=0; j<36; j++)
1302     for(i=0; i<18; i++) {
1303 			if(canvas->blinded[j][i]) {
1304 				canvas->bflash[j][i] = 24;
1305 				canvas->dirted[j][i] = 2;
1306 			}
1307 			canvas->blinded[j][i] = 0;
1308 		}
1309 	couleur = 8<<4;
1310 	i = 11;
1311 	j = 4;
1312 	this->c = 0;
1313 	canvas->delete_bloc();
1314 	canvas->set_next();
1315 	canvas->stats[CS::ROUND_WINS].add(1);
1316 	Packet_serverlog log("player_survived");
1317 	log.add(Packet_serverlog::Var("id", canvas->id()));
1318 	if(game && game->net_server)
1319 		game->net_server->record_packet(&log);
1320 }
1321 
step()1322 void Player_first_frag::step() {
1323 	Player_base::step();
1324 
1325 	if(c++&1)
1326 		return;
1327 	if(j < 9) {
1328 		canvas->block[i][j] = 15 + couleur;
1329 		canvas->occupied[i][j] = true;
1330 		canvas->dirted[i][j] = 2;
1331 		canvas->block[42-i][j] = 15 + couleur;
1332 		canvas->occupied[42-i][j] = true;
1333 		canvas->dirted[42-i][j] = 2;
1334 		canvas->block[i][17-j] = 15 + couleur;
1335 		canvas->occupied[i][17-j] = true;
1336 		canvas->dirted[i][17-j] = 2;
1337 		canvas->block[42-i][17-j] = 15 + couleur;
1338 		canvas->occupied[42-i][17-j] = true;
1339 		canvas->dirted[42-i][17-j] = 2;
1340 		int vo = -600;
1341 		if(!canvas->islocal())
1342 			vo -= 1000;
1343 
1344 		i++;
1345 		if(i == 22) {
1346 			j++;
1347 			i = 11;
1348 			if(canvas->inter)
1349 				play_sound(sons.flash, vo, 1000, 32500+ugs_random.rnd(1023));
1350 		}
1351 	} else {
1352 		canvas->dying=false;
1353 		Player_base *pb;
1354 		if(canvas->islocal()) {
1355 			pb=new Player_dead_wait(canvas, false);
1356 		}
1357 		else {
1358 			pb=new Player_wait_respawn(canvas, false);
1359 		}
1360 		exec(pb);
1361 	}
1362 }
1363 
Player_gone(Canvas * c,bool chat_msg)1364 Player_gone::Player_gone(Canvas *c, bool chat_msg): Player_base(c) {
1365 	canvas->local_player = false; // enleve le statut de 'local' a un joueur gone
1366 	canvas->idle = 3;
1367 	canvas->state = Canvas::LAST;
1368 
1369 	canvas->delete_bloc();
1370 	canvas->set_next();
1371 	if(chat_msg) {
1372 		sprintf(st, "%s has left the game.", canvas->name);
1373 		message(-1, st);
1374 	}
1375 	Packet_serverlog log("player_gone");
1376 	log.add(Packet_serverlog::Var("id", canvas->id()));
1377 	if(game && game->net_server)
1378 		game->net_server->record_packet(&log);
1379 }
1380 
step()1381 void Player_gone::step() {
1382 	Player_base::step();
1383 	if(canvas->islocal()) {
1384 		if(canvas->should_remove_bonus)
1385 			remove_bonus();
1386 	}
1387 	else {
1388 		check_bonus();
1389 	}
1390 	canvas->gone_time++;
1391 
1392 	{
1393 		Packet_dead *p=(Packet_dead *) game->peekpacket(P_DEAD);
1394 		if(p && p->player==canvas->num_player && p->then_gone)
1395 			game->removepacket(); //Remove superfluous gone packet sent by server if client disconnects too fast
1396 	}
1397 
1398 	{
1399 		Packet_gone *p=(Packet_gone *) game->peekpacket(P_GONE);
1400 		if(p && p->player==canvas->num_player)
1401 			game->removepacket(); //Remove superfluous gone packet sent by server if client disconnects too fast
1402 	}
1403 
1404 	Packet_rejoin *p=(Packet_rejoin *) game->peekpacket(P_REJOIN);
1405 	if(p && p->player==canvas->num_player) {
1406 		canvas->h_repeat = p->h_repeat;
1407 		canvas->v_repeat = p->v_repeat;
1408 		canvas->smooth = p->smooth? true:false;
1409 		canvas->shadow = p->shadow? true:false;
1410 		canvas->handicap = p->handicap;
1411 		sprintf(st, "%s has joined back!", canvas->long_name(true, false));
1412 		message(-1, st);
1413 		msgbox("Player_gone::step: player %i is no longer a goner! Rejoining.\n", p->player);
1414 		game->removepacket();
1415 
1416 		game->net_list.rejoin_player(canvas);
1417 		canvas->delete_bloc();
1418 		canvas->reinit();
1419 		canvas->restart();
1420 		game->net_list.notify_all();
1421 		if(game->net_version()>=23 && game->survivor) {
1422 			if(canvas->islocal())
1423 				exec(new Player_dead_wait(canvas));
1424 			else
1425 				exec(new Player_wait_respawn(canvas));
1426 		}
1427 		ret();
1428 	}
1429 }
1430 
Player_wait_block(Canvas * c)1431 Player_wait_block::Player_wait_block(Canvas *c): Player_base(c) {
1432 	canvas->idle = 1;
1433 	canvas->state = Canvas::PLAYING;
1434 	move_index=0;
1435 }
1436 
~Player_wait_block()1437 Player_wait_block::~Player_wait_block() {
1438 	int total_left=0;
1439 	if(move_index<canvas->da_moves.size())
1440 		total_left+=canvas->da_moves.size()-move_index;
1441 	if(total_left)
1442 		msgbox("Player_wait_block::deletemoves: moves not exhausted, %i left\n", total_left);
1443 	canvas->da_moves.resize(0);
1444 }
1445 
init()1446 void Player_wait_block::init() {
1447 	Player_base::init();
1448 }
1449 
step()1450 void Player_wait_block::step() {
1451 	Player_base::step();
1452 	bool wait_more=false;
1453 	if(playback && !playback->old_mode) {
1454 		int remain=canvas->da_moves.size()-move_index;
1455 		if(remain && remain<=50)
1456 			wait_more=true;
1457 	}
1458 
1459 	if(!wait_more)
1460 		if(check_gone())
1461 			return;
1462 
1463 	check_bonus();
1464 
1465 	if(!wait_more)
1466 		if(game->survivor)
1467 			if(check_first_frag())
1468 				return;
1469 
1470 	if(!(playback && playback->old_mode)) {
1471 		{
1472 			Packet_moves *p=(Packet_moves *) game->peekpacket(P_MOVES);
1473 			if(p && p->player==canvas->num_player) {
1474 				if(canvas->da_moves.size()+p->size<4000)
1475 					canvas->da_moves.append(p->moves, p->size);
1476 				game->removepacket();
1477 			}
1478 		}
1479 		if(move_index<canvas->da_moves.size() && !game->paused) {
1480 			Byte r = canvas->da_moves[move_index++];
1481 			if(r & 8)
1482 				rotate_left();
1483 			if(r & 16)
1484 				rotate_right();
1485 			if(r & 32)
1486 				rotate_right(true);
1487 			if(r & 1)
1488 				move_down();
1489 			if(r & 64)
1490 				drop_down();
1491 			if(r & 2)
1492 				move_left();
1493 			if(r & 4)
1494 				move_right();
1495 
1496 			int t;
1497 			t = ((canvas->bloc->bx-4)<<4)*18; // calcul la position ou le bloc devrait etre
1498 			int nx = canvas->bloc->x; // nouvelle position 'x' a obtenir
1499 			if(nx < t) {
1500 				nx += canvas->side_speed;
1501 				if(nx > t) // si depasse la position
1502 					nx = t;
1503 			}
1504 			if(nx > t) {
1505 				nx -= canvas->side_speed;
1506 				if(nx < t) // si depasse la position
1507 					nx = t;
1508 			}
1509 			t = calc_by(canvas->bloc->y-(17<<4)-15);
1510 			if(!canvas->collide(canvas->bloc->bx, t, canvas->bloc->rot))
1511 				canvas->bloc->x = nx; // accepte le deplacement 'smooth' seulement s'il ne passe pas par-dessus un bloc
1512 			t = calc_by(canvas->bloc->y+canvas->speed);
1513 			if(!canvas->collide(canvas->bloc->bx, t, canvas->bloc->rot)) {
1514 				canvas->bloc->y+=canvas->speed;
1515 				canvas->bloc->by = calc_by(canvas->bloc->y);
1516 			}
1517 			if(canvas->shadow)
1518 				canvas->calc_shadow();
1519 		}
1520 	}
1521 
1522 	if(wait_more)
1523 		return;
1524 
1525 	//Check whether this player placed a block
1526 	Packet_stampblock *p=(Packet_stampblock *) game->peekpacket(P_STAMPBLOCK);
1527 	if(p && p->player==canvas->num_player) {
1528 		exec(new Player_stamp(canvas, p));
1529 		game->removepacket();
1530 		return;
1531 	}
1532 
1533 	//Check whether this player died
1534 	Packet_dead *pd=(Packet_dead *) game->peekpacket(P_DEAD);
1535 	if(pd && pd->player==canvas->num_player) {
1536 		exec(new Player_dead(canvas, pd->then_gone));
1537 		game->removepacket();
1538 		return;
1539 	}
1540 }
1541 
check_first_frag()1542 bool Player_wait_block::check_first_frag() {
1543 	Packet_first_frag *p=(Packet_first_frag *) game->peekpacket(P_FIRST_FRAG);
1544 	if(p && p->player==canvas->num_player) {
1545 		msgbox("Player_wait_block::check_first_frag: recu P_FIRST_FRAG: %s gagnant!\n", canvas->name);
1546 		exec(new Player_first_frag(canvas));
1547 		game->removepacket();
1548 		return true;
1549 	}
1550 	return false;
1551 }
1552 
Player_stamp(Canvas * c,Packet_stampblock * p)1553 Player_stamp::Player_stamp(Canvas *c, Packet_stampblock *p): Player_base(c) {
1554 	/* Flash blinded blocks when stamping
1555 	int i, j;
1556   for(j=0; j<36; j++)
1557     for(i=0; i<18; i++)
1558 			if(canvas->blinded[j][i]) {
1559 				canvas->bflash[j][i] = 8;
1560 			}
1561 	*/
1562 	int i, j;
1563 	//Reset Canvas::moved
1564 	for(j=0; j<36; j++)
1565 		for(i=0; i<18; i++)
1566 			canvas->moved[j][i]=false;
1567 	canvas->idle = 0;
1568 	canvas->potato_team_on_last_stamp=game->potato_team;
1569 	canvas->bloc->rot=p->rotate;
1570 	canvas->bloc->bx=p->x;
1571 	canvas->bloc->by=p->y;
1572 	if(canvas->collide(p->x, p->y, p->rotate) || !canvas->collide(p->x, p->y+1, p->rotate)) {
1573 		char st[256];
1574 		sprintf(st, "*** %s dropped an invalid block! ***", canvas->name);
1575 		if(game->server) {
1576 			message(-1, st, true, false, true);
1577 			game->net_list.server_drop_player(canvas->num_player, DROP_INVALID_BLOCK);
1578 			Net_connection *nc=canvas->remote_adr;
1579 			send_msg(nc, "You have been dropped because you placed an invalid block. This may be due to a bug in the game or a network failure.");
1580 			send_msg(nc, "Quitting and rejoining the game should fix the problem. If not, please contact support@ludusdesign.com.");
1581 		}
1582 		msgbox("%s\n", st);
1583 	}
1584 	canvas->stats[CS::COMPTE0+canvas->bloc->type].add(1);
1585 	canvas->stats[CS::COMPTETOT].add(1);
1586 	canvas->stats[CS::ROTATED0+canvas->bloc->type].add(p->block_rotated);
1587 	canvas->stats[CS::ROTATEDTOT].add(p->block_rotated);
1588 	canvas->stats[CS::SCORE].add(p->score);
1589 	if(game->net_version()>=23)
1590 		canvas->stats[CS::PLAYING_TIME].add(p->time_held);
1591 
1592 	Packet_serverlog log("player_stampblock");
1593 	log.add(Packet_serverlog::Var("id", canvas->id()));
1594 	log.add(Packet_serverlog::Var("block", canvas->bloc->type));
1595 	log.add(Packet_serverlog::Var("times_rotated", p->block_rotated));
1596 	log.add(Packet_serverlog::Var("time_held", p->time_held));
1597 	log.add(Packet_serverlog::Var("points", p->score));
1598 	if(game && game->net_server)
1599 		game->net_server->record_packet(&log);
1600 
1601 	canvas->watch_date = p->date;
1602 	stamp_bloc();
1603 	if(canvas->bonus && !canvas->bon[0].blind_time)
1604 		addbonus=new Player_add_bonus(canvas);
1605 	else
1606 		addbonus=NULL;
1607 
1608 	for(i=0; i<MAXPLAYERS; i++) {
1609 		if(canvas->attacks[i] > 0) {
1610 			canvas->attacks[i]--;
1611 			if(canvas->attacks[i] == 0 && canvas->last_attacker == i) // si c'etait lui le last_attacker,
1612 				if(!game->survivor)
1613 					canvas->last_attacker = 255; // on l'oublie.
1614 		}
1615 
1616 		// new handicap code for net_version >= 24
1617 		Canvas* other_canvas = game->net_list.get(i);
1618 		if(other_canvas) {
1619 			int diff=0;
1620 			if(canvas->handicap>other_canvas->handicap)
1621 				diff=canvas->handicap-other_canvas->handicap;
1622 			if(canvas->handicaps[i] < diff*Canvas::stamp_per_handicap)
1623 				canvas->handicaps[i]++;
1624 		}
1625 	}
1626 
1627 	// adjust handicap_crowd considering crowdedness of the game (i.e. number of players alive)
1628 	int max_handicap_crowd = max(0, int(game->net_list.count_alive())-4);
1629 	max_handicap_crowd *= Canvas::stamp_per_handicap;
1630 	if(canvas->handicap_crowd < max_handicap_crowd)
1631 		++canvas->handicap_crowd;
1632 	else
1633 		canvas->handicap_crowd = max_handicap_crowd;
1634 }
1635 
init()1636 void Player_stamp::init() {
1637 	if(addbonus) {
1638 		call(new Player_check_line(canvas));
1639 		call(addbonus);
1640 	}
1641 	call(new Player_check_line(canvas));
1642 	ret();
1643 }
1644 
stamp_bloc()1645 void Player_stamp::stamp_bloc() {
1646 	int i,j;
1647 	Byte t;
1648 	Byte blindness=0;
1649 	if(canvas->bonus && canvas->bon[0].blind_time) {
1650 		blindness=canvas->bon[0].blind_time;
1651 		int y;
1652 		for(y = 1; y < canvas->bonus; y++)
1653 			canvas->bon[y-1] = canvas->bon[y];
1654 		canvas->bonus--;
1655 	}
1656 	for(j = 0; j < 4; j++)
1657 		for(i = 0; i < 4; i++) {
1658 			t = canvas->bloc->bloc[canvas->bloc->type][canvas->bloc->rot][j][i];
1659 			if(t) {
1660 				canvas->block[canvas->bloc->by+j][canvas->bloc->bx+i] = t + (canvas->bloc->type<<4);
1661 				canvas->occupied[canvas->bloc->by+j][canvas->bloc->bx+i] = true;
1662 				canvas->blinded[canvas->bloc->by+j][canvas->bloc->bx+i] = blindness;
1663 				canvas->bflash[canvas->bloc->by+j][canvas->bloc->bx+i] = blindness? 16:0;
1664 				canvas->dirted[canvas->bloc->by+j][canvas->bloc->bx+i] = 2;
1665 				canvas->last_x = i;
1666 				canvas->moved[canvas->bloc->by+j][canvas->bloc->bx+i] = true;
1667 			}
1668 		}
1669 	canvas->last_x += canvas->bloc->bx;
1670 	int startline=0;
1671 	for(j = 0; j < 32; ++j)
1672 		for(i = 4; i < 14; ++i)
1673 			if(canvas->occupied[j][i]) {
1674 				startline = j;
1675 				// break out of both loops
1676 				j=32;
1677 				break;
1678 			}
1679 	canvas->snapshot[0]=0;
1680 	for(j = startline; j < 32; j++)
1681 		for(i = 4; i < 14; i++) {
1682 			if(canvas->occupied[j][i]) {
1683 				char bl[3];
1684 				Byte color;
1685 				if(canvas->moved[j][i])
1686 					color=8;
1687 				else
1688 					color=canvas->block[j][i]>>4;
1689 				Byte side=canvas->block[j][i]&15;
1690 				sprintf(bl, "%c%c", '0'+color, 'a'+side);
1691 				strcat(canvas->snapshot, bl);
1692 			}
1693 			else
1694 				strcat(canvas->snapshot, "e0");
1695 		}
1696 	i = (canvas->bloc->bx-9) * 300;
1697 	Sample *dep;
1698 	switch(ugs_random.rnd()%3) {
1699 		case 0: dep = sons.depose;
1700 			break;
1701 		case 1: dep = sons.depose2;
1702 			break;
1703 		default: dep = sons.depose3;
1704 			break;
1705 	}
1706 	if(canvas->inter) {
1707 		int vo = -200 - ugs_random.rnd(255);
1708 		if(!canvas->islocal())
1709 			vo -= 1000;
1710 		play_sound(dep, vo, i, 10500+ugs_random.rnd(1023));
1711 	}
1712 
1713 	delete canvas->bloc;
1714 	canvas->bloc = NULL;
1715 	if(canvas->bloc_shadow) {
1716 		delete canvas->bloc_shadow;
1717 		canvas->bloc_shadow = NULL;
1718 	}
1719 }
1720 
Player_wait_respawn(Canvas * c,bool ab)1721 Player_wait_respawn::Player_wait_respawn(Canvas *c, bool ab): Player_base(c), add_bonus(ab) {
1722 	canvas->idle = 2;
1723 	canvas->state = Canvas::WAITFORWINNER;
1724 }
1725 
step()1726 void Player_wait_respawn::step() {
1727 	Player_base::step();
1728 	if(check_gone())
1729 		return;
1730 
1731 	check_bonus();
1732 
1733 	check_state();
1734 
1735 	Packet_respawn *p=(Packet_respawn *) game->peekpacket(P_RESPAWN);
1736 	if(p && p->player==canvas->num_player) {
1737 		canvas->restart();
1738 		ret();
1739 		game->removepacket();
1740 		Packet_serverlog log("player_respawn");
1741 		log.add(Packet_serverlog::Var("id", canvas->id()));
1742 		if(game && game->net_server)
1743 			game->net_server->record_packet(&log);
1744 	} else {
1745 		if(canvas->bonus && !canvas->bon[0].blind_time && add_bonus)
1746 			call(new Player_add_bonus(canvas));
1747 	}
1748 }
1749 
Player_init(Canvas * canvas)1750 Player_init::Player_init(Canvas *canvas): Player_base(canvas) {
1751 	canvas->restart();
1752 	if(game->net_version()>=23 && game->survivor)
1753 		canvas->idle = 2;
1754 	else
1755 		canvas->idle = 1;
1756 	canvas->state = Canvas::PLAYING;
1757 	if(canvas->wait_download)
1758 		net->addwatch(P_DOWNLOAD, this);
1759 }
1760 
step()1761 void Player_init::step() {
1762 	Player_base::step();
1763 	//Don't start until we got our download packet
1764 	if(canvas->wait_download)
1765 		return;
1766 	Byte idle=canvas->idle; //Cause Player_normal::Player_normal sets it
1767 	exec(new Player_normal(canvas));
1768 	if(idle == 2) {
1769 		if(canvas->islocal())
1770 			call(new Player_dead_wait(canvas));
1771 		else
1772 			call(new Player_wait_respawn(canvas));
1773 	}
1774 	if(idle == 3) {
1775 		call(new Player_gone(canvas, false));
1776 		canvas->remote_adr = NULL; // empeche de watcher un joueur qui est 'gone' lorsqu'on join
1777 	}
1778 }
1779 
net_call(Packet * p2)1780 void Player_init::net_call(Packet *p2) {
1781 	Packet_download *p=(Packet_download *) p2;
1782 	{
1783 		Canvas *c = game->net_list.get(p->player);
1784 		if(!c || c!=canvas) {
1785 			msgbox("Player_init::net_call: got a P_DOWNLOAD but canvas does not exist or not even mine, something screwy is going on\n");
1786 			delete p2;
1787 			return;
1788 		}
1789 	}
1790 	for(int y=0; y<32; y++)
1791 		for(int x=0; x<10; x++) {
1792 			canvas->block[y][x+4] = p->can[y][x];
1793 			canvas->occupied[y][x+4] = p->occ[y][x];
1794 			canvas->blinded[y][x+4] = p->blinded[y][x];
1795 		}
1796 	canvas->rnd.set_seed(p->seed);
1797 	if(p->bloc != 255) {
1798 		canvas->bloc = new Bloc(p->bloc, -1, 7, 10);
1799 		canvas->next = new Bloc(p->next, -1, 7, 10);
1800 		canvas->next2 = new Bloc(p->next2, -1, 7, 10);
1801 		canvas->next3 = new Bloc(p->next3, -1, 7, 10);
1802 	}
1803 	canvas->bonus = p->bonus;
1804 	int i;
1805 	for(i=0; i<20; i++) {
1806 		canvas->bon[i].x = p->bon[i].x;
1807 		canvas->bon[i].color = p->bon[i].color;
1808 		canvas->bon[i].blind_time = p->bon[i].blind_time;
1809 		canvas->bon[i].hole_pos = p->bon[i].hole_pos;
1810 		canvas->bon[i].final = p->bon[i].final;
1811 	}
1812 	for(i=0; i<MAXPLAYERS; i++)
1813 		canvas->attacks[i] = p->attacks[i];
1814 	canvas->last_attacker = p->last_attacker;
1815 	canvas->idle = p->idle;
1816 	canvas->state = (Canvas::State) p->state;
1817 	msgbox("Player_init::net_call: name=%s, idle=%i, bonus=%i, bloc=%i\n", canvas->name, canvas->idle, canvas->bonus, p->bloc);
1818 	delete p2;
1819 	canvas->wait_download=false;
1820 	net->removewatch(P_DOWNLOAD, this);
1821 }
1822 
init_directory()1823 void init_directory() {
1824 	strcpy(quadradir, exe_directory);
1825 #ifdef WIN32
1826 	if(SHGetFolderPath(0, CSIDL_APPDATA|CSIDL_FLAG_CREATE, 0, SHGFP_TYPE_CURRENT, quadradir) < 0) {
1827 		msgbox("SHGetFolderPath failed, using exe_directory");
1828 	}
1829 	else {
1830 		strcat(quadradir, "\\Quadra");
1831 		CreateDirectory(quadradir, 0);
1832 	}
1833 #endif
1834 #ifdef UGS_LINUX
1835 	struct passwd *pw = NULL;
1836 
1837 	pw = getpwuid(getuid());
1838 	if(pw) {
1839 		strcpy(quadradir, pw->pw_dir);
1840 		strcat(quadradir, "/.quadra");
1841 		mkdir(quadradir, 0777);
1842 		chown(quadradir, pw->pw_uid, pw->pw_gid);
1843 	}
1844 #endif
1845 }
1846 
init_stuff(bool need_sound,bool need_video)1847 static void init_stuff(bool need_sound, bool need_video) {
1848 	int i;
1849 
1850 	if (!need_video) {
1851 		video_is_dumb = true;
1852 		char value[] = "SDL_VIDEODRIVER=dummy";
1853 		SDL_putenv(value);
1854 	}
1855 
1856   if(SDL_Init(SDL_INIT_VIDEO) == -1) {
1857     fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
1858     exit(1);
1859   }
1860 
1861 	video = new Video;
1862 
1863 	if(!video)
1864 		fatal_msgbox("Could not initialize video subsystem");
1865 
1866 	fonts.init();
1867 	//If we init a dumb video, we need a dumb input too
1868 	input = Input::New(!need_video);
1869   // don't need sound if no video
1870 	if(need_sound && need_video)
1871 		sound = Sound::New();
1872 	else
1873 		sound = NULL;
1874 
1875 	for(i=0; i<256; i++)
1876 		noir.setcolor(i, 40, 40, 40);
1877 
1878 	chat_text = new Chat_text(fonts.normal, 212);
1879 	net_starter = new Net_starter();
1880   sons.pause = new Sample(Res_doze("cuckoo.wav"));
1881   sons.start = new Sample(Res_doze("hooter03.wav"));
1882   sons.bonus1 = new Sample(Res_doze("Whizz1.wav"));
1883   sons.levelup = new Sample(Res_doze("glissup.wav"));
1884   // when the canvas 'flows'
1885   sons.depose4 = new Sample(Res_doze("Clang3.wav"));
1886 	sons.flash = NULL;
1887 	sons.depose3 = NULL;
1888 	sons.depose2 = NULL;
1889 	sons.depose = NULL;
1890 	sons.drip = NULL;
1891   sons.glass = new Sample(Res_doze("Glass01.wav"));
1892   sons.enter = new Sample(Res_doze("Tapdrip.wav"));
1893   sons.fadein = new Sample(Res_doze("W_BAYO_0.wav"));
1894   sons.fadeout = new Sample(Res_doze("fadeout.wav"));
1895   sons.point = new Sample(Res_doze("click_1.wav"));
1896   sons.click = new Sample(Res_doze("Blip1.wav"));
1897   sons.msg = new Sample(Res_doze("handbell.wav"));
1898   sons.potato_get = new Sample(Res_doze("potato_get.wav"));
1899   sons.potato_rid = new Sample(Res_doze("zingle.wav"));
1900   sons.minute = new Sample(Res_doze("t1min.wav"));
1901   sons.thirty = new Sample(Res_doze("t30sec.wav"));
1902   sons.twenty = new Sample(Res_doze("t20sec.wav"));
1903   sons.ten = new Sample(Res_doze("t10sec.wav"));
1904   sons.five = new Sample(Res_doze("t5sec.wav"));
1905   sons.four = new Sample(Res_doze("t4sec.wav"));
1906   sons.three = new Sample(Res_doze("t3sec.wav"));
1907   sons.two = new Sample(Res_doze("t2sec.wav"));
1908   sons.one = new Sample(Res_doze("t1sec.wav"));
1909 	cursor = new Cursor;
1910 	for(i=0; i<8; i++)
1911 		fteam[i] = new Font(*fonts.normal);
1912 }
1913 
deinit_stuff()1914 void deinit_stuff() {
1915 	for(int i=0; i<8; i++)
1916 		if(fteam[i]) {
1917 			delete fteam[i];
1918 			fteam[i] = NULL;
1919 		}
1920 
1921 	delete sons.click; sons.click = NULL;
1922 	delete sons.point; sons.point = NULL;
1923 	delete sons.fadeout; sons.fadeout = NULL;
1924 	delete sons.fadein; sons.fadein = NULL;
1925 	delete sons.drip; sons.drip = NULL;
1926 	delete sons.glass; sons.glass = NULL;
1927 	delete sons.depose; sons.depose = NULL;
1928 	delete sons.depose2; sons.depose2 = NULL;
1929 	delete sons.depose3; sons.depose3 = NULL;
1930 	delete sons.depose4; sons.depose4 = NULL;
1931 	delete sons.flash; sons.flash = NULL;
1932 	delete sons.enter; sons.enter = NULL;
1933 	delete sons.levelup; sons.levelup = NULL;
1934 	delete sons.bonus1; sons.bonus1 = NULL;
1935 	delete sons.start; sons.start = NULL;
1936 	delete sons.pause; sons.pause = NULL;
1937 	delete sons.msg; sons.msg = NULL;
1938 	delete sons.potato_get; sons.potato_get = NULL;
1939 	delete sons.potato_rid; sons.potato_rid = NULL;
1940 	delete sons.minute; sons.minute = NULL;
1941 	delete sons.thirty; sons.thirty = NULL;
1942 	delete sons.twenty; sons.twenty = NULL;
1943 	delete sons.ten; sons.ten = NULL;
1944 	delete sons.five; sons.five = NULL;
1945 	delete sons.four; sons.four = NULL;
1946 	delete sons.three; sons.three = NULL;
1947 	delete sons.two; sons.two = NULL;
1948 	delete sons.one; sons.one = NULL;
1949 
1950 	delete net_starter; net_starter=NULL;
1951 	delete chat_text; chat_text=NULL;
1952 
1953 	config.write();
1954 	Highscores::freemem();
1955 
1956 	delete cursor; cursor = NULL;
1957 
1958 	fonts.deinit();
1959 }
1960 
command_get_param(const char * t,const char * def=NULL)1961 const char *command_get_param(const char *t, const char *def=NULL) {
1962 	const char *temp = command.get_param();
1963 	if(!temp)
1964 		temp=def;
1965 	if(!temp)
1966 		fatal_msgbox("Command line parameter not found for '%s'", t);
1967 	return temp;
1968 }
1969 
read_attack_param(const char * s)1970 Attack read_attack_param(const char *s) {
1971 	Attack ret;
1972 	char temp[1024];
1973 	strncpy(temp, s, sizeof(temp));
1974 	temp[sizeof(temp)-1]=0;
1975 	char *param=strchr(temp, ' ');
1976 	if(param) {
1977 		*param=0;
1978 		param++;
1979 	}
1980 	if(!strcmp(temp, "lines"))
1981 		ret.type=ATTACK_LINES;
1982 	if(!strcmp(temp, "none"))
1983 		ret.type=ATTACK_NONE;
1984 	if(!strcmp(temp, "blind") || !strcmp(temp, "fullblind")) {
1985 		if(param) {
1986 			int p=atoi(param);
1987 			p=min(max(1, p), 255);
1988 			ret.param=p;
1989 		}
1990 	}
1991 	if(!strcmp(temp, "blind")) {
1992 		ret.type=ATTACK_BLIND;
1993 		if(!param)
1994 			ret.param=30;
1995 	}
1996 	if(!strcmp(temp, "fullblind")) {
1997 		ret.type=ATTACK_FULLBLIND;
1998 		if(!param)
1999 			ret.param=12;
2000 	}
2001 	return ret;
2002 }
2003 
display_command_line_help()2004 void display_command_line_help() {
2005 	char st[4096];
2006 	Res_doze cmdline("help_en.txt");
2007 	Dword size = min(static_cast<Dword>(sizeof(st)-1), cmdline.size());
2008 	strncpy(st, (char *)cmdline.buf(), size);
2009 	st[size] = 0;
2010 	if(video)
2011 		delete video;
2012 	user_output("Quadra - Command line", st);
2013 }
2014 
read_script(const char * fn,bool second=false)2015 void read_script(const char *fn, bool second=false) {
2016 	char st[32768];
2017 	Res_dos script(fn);
2018 	if(script.exist) {
2019 		//-2 because Stringtable is strange
2020 		Dword size = min(static_cast<Dword>(sizeof(st)-2), script.size());
2021 		strncpy(st, (char *)script.buf(), size);
2022 		st[size] = 0;
2023 		Stringtable str((Byte *)st, size);
2024 		int i;
2025 		for(i=0; i<str.size(); i++) {
2026 			if(second) {
2027 				if(game && str.get(i)[0]=='/')
2028 					game->net_list.got_admin_line(str.get(i), NULL);
2029 			}
2030 			else {
2031 				if(str.get(i)[0]=='-')
2032 					command.add(str.get(i));
2033 			}
2034 		}
2035 	}
2036 	else
2037 		msgbox("Can't find script %s, ignoring.\n", fn);
2038 }
2039 
start_game()2040 void start_game() {
2041 	if(command.token("113"))
2042 		Config::net_version = 20;
2043 	if(command.token("debug")) {
2044 		_debug = true;
2045 		msgbox("Debug mode enabled\n");
2046 	}
2047 
2048 	bool no_video = false;
2049 	bool no_sound = false;
2050 	bool demo_play = false;
2051 	bool demo_verif = false;
2052 	bool demo_verified_and_valid = false;
2053 	char buf[512];
2054   /* FIXME: rather than using 1024 MAXPATHLEN should be used.  To do
2055      so requires all other filename lengths be MAXPATHLEN as well. */
2056 	char fn[1024];
2057 
2058 	init_directory();
2059 
2060 	const char *dir=quadradir;
2061 #ifdef WIN32
2062 	dir = exe_directory;
2063 #else
2064 #ifdef UGS_XCODE
2065 	dir = ".";
2066 #else
2067 	dir = getenv("QUADRADIR");
2068 	if(!dir)
2069 		dir = DATAGAMESDIR;
2070 #endif
2071 #endif
2072 	resmanager=new Resmanager();
2073 	snprintf(fn, sizeof(fn) - 1, "%s/quadra.res", dir);
2074 	resmanager->loadresfile(fn);
2075 	snprintf(fn, sizeof(fn) - 1, "%s/quadra%i%i%i.res", dir, Config::major, Config::minor, Config::patchlevel);
2076 	resmanager->loadresfile(fn);
2077 	if(command.token("patch") || command.token("theme")) {
2078 		const char *temp=command_get_param("patch <filename>");
2079 		if(temp[0] != '/' && temp[0] != '\\')
2080 			snprintf(fn, sizeof(fn) - 1, "%s/%s", dir, temp);
2081 		else
2082 			snprintf(fn, sizeof(fn) - 1, "%s", temp);
2083 		resmanager->loadresfile(fn);
2084 	}
2085 	msgbox("Reading config: ");
2086 	config.read();
2087 	msgbox("Ok\n");
2088 	//Read script and add to command line options if applicable
2089 	if(command.token("exec")) {
2090 		const char *temp=command_get_param("exec <filename>");
2091 		msgbox("Reading script %s: ", temp);
2092 		read_script(temp);
2093 		msgbox("Ok\n");
2094 	}
2095 	bool dedicated=command.token("dedicated");
2096 	int i;
2097 	for(i=0; i<MAXTEAMS; i++)
2098 		set_team_name(i, NULL);
2099 
2100 	if(command.token("h help ?")) {
2101 		display_command_line_help();
2102 		delete resmanager;
2103 		return;
2104 	}
2105 	if(_debug && command.token("verify")) {
2106 		const char *temp = command_get_param("verify <filename>");
2107 		strncpy(buf, temp, sizeof(buf) - 1);
2108 		demo_play = true;
2109 		demo_verif = true;
2110 		demo_verified_and_valid = false;
2111 		no_video = true;
2112 		no_sound = true;
2113 	}
2114 	if(command.token("play")) {
2115 		const char *temp = command_get_param("play <filename>");
2116 		strncpy(buf, temp, sizeof(buf) - 1);
2117 		demo_play = true;
2118 		demo_verif = false;
2119 	}
2120 	if(!demo_play && dedicated)
2121 		no_video=true;
2122 	if(command.token("novideo")) {
2123 		no_video=true;
2124 		no_sound=true;
2125 	}
2126 	if(command.token("nosound")) {
2127 		no_sound=true;
2128 	}
2129 	msgbox("Calling init_stuff: ");
2130 	init_stuff(!no_sound, !no_video); //No sound when checking demos
2131   msgbox("Ok\n");
2132 
2133   // Start auto-updater, but only if we have video enabled.
2134   if(!no_video)
2135     AutoUpdater::start();
2136 
2137 	Dword last=0;
2138 	Dword acc=0;
2139 	Executor *menu = new Executor();
2140 	//Add Menu_intro so we get back there after -connect, -server or -play
2141 	//  unless -thenquit option si specified
2142 	if(!command.token("thenquit") && !demo_verif)
2143 			menu->add(new Menu_intro());
2144 
2145 	if(!demo_play) {
2146 		if(command.token("server") || dedicated) {
2147 			if(!net->active)
2148 				fatal_msgbox("Network failed to initialize or not present\nCan't start server.\n");
2149 			buf[0] = 0;
2150 			if(command.token("port")) {
2151 				const char *temp = command_get_param("port <TCP/IP port>");
2152 				int port = atoi(temp);
2153 				if(port<=0 || port>=65535)
2154 					fatal_msgbox("Illegal port number.\n");
2155 				config.info.port_number = port;
2156 			}
2157 			Game_params p;
2158 			if(command.token("ffa"))
2159 				p.set_preset(PRESET_FFA);
2160 			if(command.token("survivor"))
2161 				p.set_preset(PRESET_SURVIVOR);
2162 			if(command.token("hotpotato"))
2163 				p.set_preset(PRESET_HOT_POTATO);
2164 			if(command.token("peace"))
2165 				p.set_preset(PRESET_PEACE);
2166 			if(command.token("blind")) {
2167 				p.set_preset(PRESET_BLIND);
2168 				const char *temp = command_get_param("blind <n>", "30");
2169 				Dword time=atoi(temp);
2170 				time=min(max(time, static_cast<Dword>(0)), static_cast<Dword>(255));
2171 				p.normal_attack.param=time;
2172 				p.clean_attack.param=time;
2173 			}
2174 			if(command.token("fullblind")) {
2175 				p.set_preset(PRESET_FULLBLIND);
2176 				const char *temp = command_get_param("fullblind <n>", "12");
2177 				Dword time=atoi(temp);
2178 				time=min(max(time, static_cast<Dword>(0)), static_cast<Dword>(255));
2179 				p.normal_attack.param=time;
2180 				p.clean_attack.param=time;
2181 			}
2182 			if(command.token("attack")) {
2183 				const char *temp=command_get_param("attack <type> [strength]");
2184 				p.normal_attack=read_attack_param(temp);
2185 			}
2186 			if(command.token("attackclean")) {
2187 				const char *temp=command_get_param("attackclean <type> [strength]");
2188 				p.clean_attack=read_attack_param(temp);
2189 			}
2190 			if(command.token("attack2")) {
2191 				const char *temp=command_get_param("attack2 <type> [strength]");
2192 				p.potato_normal_attack=read_attack_param(temp);
2193 			}
2194 			if(command.token("attack2clean")) {
2195 				const char *temp=command_get_param("attack2clean <type> [strength]");
2196 				p.potato_clean_attack=read_attack_param(temp);
2197 			}
2198 			if(command.token("boringrules"))
2199 				p.boring_rules = true;
2200 			if(command.token("nolevelup"))
2201 				p.level_up = false;
2202 			if(command.token("levelup"))
2203 				p.level_up = true;
2204 			if(command.token("level")) {
2205 				const char *temp = command_get_param("level <level number>");
2206 				p.level_start = atoi(temp);
2207 				p.level_start = min(max(p.level_start, 1), 40);
2208 			}
2209 			if(command.token("name")) {
2210 				const char *temp = command_get_param("name <game name>");
2211 				strncpy(buf, temp, sizeof(buf) - 1);
2212 				p.name=buf;
2213 			}
2214 			if(command.token("nohandicap"))
2215 				p.allow_handicap=false;
2216 			if(command.token("endfrag"))
2217 				p.game_end = END_FRAG;
2218 			if(command.token("endfrags"))
2219 				p.game_end = END_FRAG;
2220 			if(command.token("endtime"))
2221 				p.game_end = END_TIME;
2222 			if(command.token("endpoints"))
2223 				p.game_end = END_POINTS;
2224 			if(command.token("endscore"))
2225 				p.game_end = END_POINTS;
2226 			if(p.game_end != END_NEVER) {
2227 				const char *temp = command_get_param("endfrag/endtime/endpoints <number>");
2228 				p.game_end_value = atoi(temp);
2229 				p.game_end_value = min(max(p.game_end_value, 1), p.game_end<=END_TIME? 9999:99999);
2230 			}
2231 			if(command.token("public"))
2232 				p.game_public = true;
2233 			menu->add(new Menu_startserver());
2234 			(void)new Game(&p);
2235 			if(dedicated && !command.token("once"))
2236 				game->auto_restart = true;
2237 			if(command.token("nomoves"))
2238 				game->wants_moves = false;
2239 			//Read script a second time, now that game is created
2240 			if(command.token("exec")) {
2241 				const char *temp=command_get_param("exec <filename>");
2242 				read_script(temp, true);
2243 			}
2244 			if(command.token("admin")) {
2245 				const char *temp = command_get_param("admin <password>");
2246 				char line[1024];
2247 				snprintf(line, sizeof(line) - 1, "/setpasswd %s", temp);
2248 				game->net_list.got_admin_line(line, NULL);
2249 			}
2250 			if(command.token("record")) {
2251 				const char *temp = command_get_param("record <filename>", Clock::absolute_time());
2252 				game->prepare_recording(temp);
2253 				game->prepare_logging();
2254 			}
2255 		}
2256 		else {
2257 			if(command.token("connectfile")) {
2258 				const char *temp = command_get_param("connectfile <filename>");
2259 				char st[1024];
2260 				Res_dos file(temp);
2261 				if(file.exist) {
2262 					snprintf(st, sizeof(st), "-connect %*.*s", file.size(), file.size(), (char *)file.buf());
2263 					st[sizeof(st) - 1] = 0;
2264 					command.add(st);
2265 				}
2266 				else
2267 					msgbox("Can't find connectfile %s, ignoring.\n", temp);
2268 
2269 			}
2270 			if(command.token("connect")) {
2271 				if(!net->active)
2272 					fatal_msgbox("Network failed to initialize or not present\nCan't connect.\n");
2273 				const char *temp = command_get_param("connect <TCP/IP address>");
2274 				strncpy(buf, temp, sizeof(buf) - 1);
2275 				buf[sizeof(buf)-1] = 0;
2276 				menu->add(new Menu_startconnect(buf, false));
2277 				if(config.warning)
2278 					menu->add(new Menu_setup());
2279 			}
2280 		}
2281 	}
2282 	else {
2283 		Res_compress *res = new Res_compress(buf, RES_TRY);
2284 		if(res->exist) {
2285 			menu->add(new Demo_multi_player(res));
2286 			// le 'delete res' est fait par ~Demo_multi_player
2287 			if(playback)
2288 				playback->set_verification_flag(&demo_verified_and_valid);
2289 		}
2290 		else {
2291 			msgbox("Unable to open demo '%s'\n", buf);
2292 			delete res;
2293 		}
2294 	}
2295 
2296 	overmind.start(menu);
2297 	bool reset_time=false;
2298 	while(!menu->done) {
2299 		last=getmsec();
2300 		if(demo_verif) {
2301 			acc=500;
2302 			while(acc--)
2303 				overmind.step();
2304 		}
2305 		else {
2306 			while(acc>=10) {
2307 				if(reset_time) { // remet 'normal' seulement si au moins 1 frame s'est ecoule
2308 					time_control = TIME_NORMAL;
2309 					reset_time = false;
2310 				}
2311 				acc-=10;
2312 				try {
2313 					overmind.step();
2314 				}
2315 				catch(std::exception *e) {
2316 					msgbox("Exception caught from overmind.step(): %s\n", e->what());
2317 				}
2318 				reset_time=true;
2319 				if(time_control == TIME_FREEZE)
2320 					break;
2321 			}
2322 		}
2323 		start_frame();
2324 		if(ecran && !video_is_dumb) {
2325 			try {
2326 				ecran->draw_zone();
2327 			}
2328 			catch(std::exception *e) {
2329 				msgbox("Exception caught from ecran->draw_zone(): %s\n", e->what());
2330 			}
2331 
2332 #ifdef FRAMECOUNTER
2333 			static Dword lastvideoframe=0, lastoverframe=0;
2334 			if(ecran->font) {
2335 				if(overmind.framecount-lastoverframe > 500) {
2336 					lastoverframe = overmind.framecount;
2337 					lastvideoframe = video->framecount;
2338 				}
2339 				int up = 999;
2340 				if(overmind.framecount-lastoverframe > 0)
2341 					up = ((video->framecount-lastvideoframe) * 100) / (overmind.framecount-lastoverframe);
2342 				video->vb->rect(0,0,50,20,0);
2343 				char st[80];
2344 				sprintf(st, "%i", up);
2345 				ecran->font->draw(st, video->vb, 0, 0);
2346 			}
2347 #endif /* FRAMECOUNTER */
2348 		}
2349 		end_frame();
2350 
2351 #ifndef NDEBUG
2352     Uint8 *keystate = SDL_GetKeyState(NULL);
2353     if(keystate[SDLK_F8]) // F8 = buckage
2354 			for(int j=0; j<8000000; j++)
2355 				;
2356     if(keystate[SDLK_F9]) // F8 = slow motion mode
2357 			time_control = TIME_SLOW;
2358     if(keystate[SDLK_F10]) // F8 = turbo mode
2359 			time_control = TIME_FAST;
2360 #endif
2361 
2362 		switch(time_control) {
2363 		case TIME_FREEZE: acc = 10; break;
2364 		case TIME_SLOW: acc += 1; break;
2365 		case TIME_FAST: acc += 80; break;
2366 		default: acc+=getmsec()-last;
2367 		}
2368 		if(acc > 300 && !video_is_dumb) {
2369 			overmind.framecount+=acc-300;
2370 			acc = 300; // pour eviter trop de depassement
2371 		}
2372 		if(acc > 10000) {
2373 			msgbox("Not enough CPU time to be server!\n");
2374 			overmind.framecount+=acc-10;
2375 			acc=10;
2376 		}
2377 	}
2378 	delete menu;
2379 
2380 	deinit_stuff();
2381 	delete resmanager;
2382 
2383 	// FIXME: This is not the smoothest exit ever, a better way?
2384 	if(demo_verif)
2385 		exit(demo_verified_and_valid? 0 : 1);
2386 }
2387