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 "canvas.h"
22 
23 #include <stdio.h>
24 #include "input.h"
25 #include "random.h"
26 #include "bloc.h"
27 #include "quadra.h"
28 #include "image_png.h"
29 #include "cfgfile.h"
30 #include "res.h"
31 #include "zone.h"
32 #include "game.h"
33 #include "global.h"
34 #include "sons.h"
35 #include "recording.h"
36 #include "chat_text.h"
37 #include "nglog.h"
38 #include "net_server.h"
39 #include "packets.h"
40 
41 using std::max;
42 using std::min;
43 using std::vector;
44 
Canvas(int qplayer,int game_seed,Palette * p)45 Canvas::Canvas(int qplayer, int game_seed, Palette *p):
46   bit(NULL), //Somebody somewhere will set that. Sucks.
47   rnd(game_seed),
48   sprlevel_up(NULL) {
49 // constructs a local Canvas
50 	snapshot[0]=0;
51 	best_move=best_clean=best_recurse=0;
52 	memset(player_hash, 0, sizeof(player_hash));
53 	memset(team_hash, 0, sizeof(team_hash));
54 	collide_side_only=false;
55 	should_remove_bonus=false;
56 	wait_download=false;
57 	z_lines=z_potatolines=z_linestot=z_potatolinestot=NULL;
58 	team_potato_lines=team_potato_linestot=0;
59 	send_for_clean=false;
60 	handicap_crowd=0;
61 	potato_team_on_last_stamp=255;
62 	potato_lines=0;
63 	gone_time=0;
64 	inter=NULL;
65 	h_repeat = v_repeat = 0;
66 	smooth = shadow = false;
67 	moves=NULL;
68   pal = p;
69   player = qplayer;
70 	if(playback) {
71 		color = playback->player[player].color;
72 		strcpy(name, playback->player[player].name);
73 		continuous=1;
74 	} else {
75 		handicap = config.player2[player].handicap;
76 		color = config.player[player].color;
77 		strcpy(name, config.player[player].name);
78 		strcpy(team_name, config.player2[player].ngTeam);
79 		continuous=config.player2[player].continuous;
80 	}
81   remote_adr=NULL;
82 	local_player = true;
83 	hide();
84   init();
85 }
86 
Canvas(int game_seed,Byte team,const char * nam,int ph_repeat,int pv_repeat,bool psmooth,bool pshadow,int phandicap,Net_connection * adr,int qplayer,bool wait_down)87 Canvas::Canvas(int game_seed, Byte team, const char *nam, int ph_repeat,
88                int pv_repeat, bool psmooth, bool pshadow, int phandicap,
89                Net_connection *adr, int qplayer, bool wait_down):
90   bit(NULL),
91   rnd(game_seed),
92   sprlevel_up(NULL) {
93 // constructs a remote Canvas
94 	snapshot[0]=0;
95 	best_move=best_clean=best_recurse=0;
96 	memset(player_hash, 0, sizeof(player_hash));
97 	memset(team_hash, 0, sizeof(team_hash));
98 	collide_side_only=false;
99 	should_remove_bonus=false;
100 	wait_download=wait_down;
101 	z_lines=z_potatolines=z_linestot=z_potatolinestot=NULL;
102 	team_potato_lines=team_potato_linestot=0;
103 	send_for_clean=false;
104 	handicap_crowd=0;
105 	potato_team_on_last_stamp=255;
106 	potato_lines=0;
107 	gone_time=0;
108 	inter=NULL;
109 	handicap = phandicap;
110 	h_repeat = ph_repeat;
111 	v_repeat = pv_repeat;
112 	continuous=1; //Doesn't matter for remote canvas
113 	smooth = psmooth;
114 	shadow = pshadow;
115 	moves=NULL;
116   pal = NULL;
117   player = qplayer;
118   color = team;
119 	strncpy(name, nam, sizeof(name));
120 	name[sizeof(name)-1]=0;
121   remote_adr=adr;
122 	local_player = false;
123   hide();
124   init();
125 }
126 
~Canvas()127 Canvas::~Canvas() {
128   delete over;
129   delete myself;
130 	if(moves)
131 		delete moves;
132   delete_bloc();
133   if (sprlevel_up)
134     SDL_FreeSurface(sprlevel_up);
135 	while (!watchers.empty()) {
136 		delete watchers.back();
137 		watchers.pop_back();
138 	}
139 }
140 
long_name(bool handi,bool gone)141 char *Canvas::long_name(bool handi, bool gone) {
142 	static char ret[64];
143 	strcpy(ret, name);
144 	if(handi) {
145 		const char *h="";
146 		switch(handicap) {
147 			case 0: h=" (-)"; break;
148 			case 1: h=" (A)"; break;
149 			case 3: h=" (M)"; break;
150 			case 4: h=" (+)"; break;
151 		}
152 		strcat(ret, h);
153 	}
154 	if(gone)
155 		if(idle==3)
156 			strcat(ret, " *");
157 	return ret;
158 }
159 
delete_bloc()160 void Canvas::delete_bloc() {
161   if(bloc)
162     delete bloc;
163   if(next)
164     delete next;
165   if(next2)
166     delete next2;
167   if(next3)
168     delete next3;
169   if(bloc_shadow)
170     delete bloc_shadow;
171   bloc = next = next2 = next3 = bloc_shadow = NULL;
172 }
173 
init()174 void Canvas::init() {
175 	trying_to_drop=false;
176   {
177     Res_doze res("gamelvup.png");
178     Png raw(res);
179     sprlevel_up = raw.new_surface();
180     SDL_SetColorKey(sprlevel_up, SDL_SRCCOLORKEY, 0);
181   }
182   over = new Overmind();
183   bloc = next = next2 = next3 = bloc_shadow = NULL;
184 	reinit();
185   myself = new Executor();
186   myself->add(new Player_init(this));
187   over->start(myself);
188 }
189 
reinit()190 void Canvas::reinit() {
191 	set_message("", "");
192   int i,j;
193   watch_date = 0;
194   for(j=0; j<36; j++)
195     for(i=0; i<18; i++) {
196 			occupied[j][i] = false;
197       block[j][i] = 0;
198 			blinded[j][i] = 0;
199 			bflash[j][i] = 0;
200 		}
201   for(i=0; i<20; i++)
202     flash[i] = 0;
203   if(islocal()) {
204 		if(playback) {
205 			//playback->multi_mode is certainly false since this canvas
206 			//  is local. Thus, we don't care about handicap
207 			h_repeat = v_repeat = playback->player[player].repeat;
208 			continuous = 1;
209 			smooth = playback->player[player].smooth ? true:false;
210 			shadow = playback->player[player].shadow ? true:false;
211 		} else {
212 			handicap = config.player2[player].handicap;
213 			h_repeat = config.player2[player].h_repeat;
214 			v_repeat = config.player2[player].v_repeat;
215 			continuous = config.player2[player].continuous;
216 			smooth = config.player[player].smooth ? true:false;
217 			shadow = config.player[player].shadow ? true:false;
218 		}
219   }
220 	if(game->normal_attack.type==ATTACK_BLIND || game->normal_attack.type==ATTACK_FULLBLIND)
221 		shadow=true;
222 	if(game->potato_normal_attack.type==ATTACK_BLIND || game->potato_normal_attack.type==ATTACK_FULLBLIND)
223 		shadow=true;
224   switch(h_repeat) {
225     case 0:
226       h_repeat_delay = 11;
227       break;
228     case 1:
229       h_repeat_delay = 6;
230       break;
231     case 2:
232       h_repeat_delay = 3;
233       break;
234     case 3:
235       h_repeat_delay = 1;
236       break;
237   }
238   side_speed = (18<<4)/h_repeat_delay;
239   switch(v_repeat) {
240     case 0:
241       v_repeat_delay = 11;
242       break;
243     case 1:
244       v_repeat_delay = 6;
245       break;
246     case 2:
247       v_repeat_delay = 3;
248       break;
249     case 3:
250       v_repeat_delay = 1;
251       break;
252   }
253   down_speed = (340)/v_repeat_delay;
254   if(down_speed > 180)
255     down_speed = 180;
256   level = game->level_start;
257   depth = complexity = bonus = 0;
258 	stats[LINESCUR].set_value(0);
259   level_up = color_flash = 0;
260   over->framecount = 0; // initialize the counter when the player starts
261 	if(game->net_version()>=23 && game->survivor)
262 		idle = 2;
263 	else
264 		idle = 1;
265 	dying = false;
266 	state = PLAYING;
267 	handicap_crowd=0;
268 	potato_team_on_last_stamp=255;
269 	send_for_clean=false;
270 	should_remove_bonus=false;
271 }
272 
restart()273 void Canvas::restart() {
274   if(islocal())
275     clear_key_all();
276   init_block();
277   clear_tmp();
278   delete_bloc();
279   set_next();
280   last_attacker = 255;
281   for(int i=0; i<MAXPLAYERS; i++) {
282     attacks[i] = 0;
283 		handicaps[i] = 0;
284 	}
285   level = game->level_start;
286   depth = complexity = bonus = 0;
287 	stats[LINESCUR].set_value(0);
288   level_up = color_flash = 0;
289   calc_speed();
290   idle = 1; // starts 'idle' to allow joins if the game is on pause and the player just started
291 	state = PLAYING;
292 	dying=false;
293 	handicap_crowd=0;
294 	potato_team_on_last_stamp=255;
295 	send_for_clean=false;
296 	should_remove_bonus=false;
297 	set_message("", "");
298 }
299 
clear_key_all()300 void Canvas::clear_key_all() {
301   for(int i=0; i<7; i++) // clears the key states of the player
302     clear_key(i);
303 }
304 
calc_shadow()305 void Canvas::calc_shadow() {
306   if(!bloc_shadow)
307     bloc_shadow = new Bloc(bloc->type, 8, 0, 0);
308   bloc_shadow->rot = bloc->rot;
309   bloc_shadow->bx = bloc->bx;
310   bloc_shadow->by = bloc->by;
311   while(!check_collide(bloc_shadow, bloc_shadow->bx, bloc_shadow->by+1, bloc_shadow->rot))
312     bloc_shadow->by++;
313   bloc_shadow->calc_xy();
314   //bloc_shadow->x = bloc->x;
315 }
316 
init_block()317 void Canvas::init_block() {
318   int x, y;
319   for(y=32; y < 36; y++)
320     for(x = 0; x < 18; x++)
321       occupied[y][x] = true;
322   for(y = 0; y < 32; y++) {
323     for(x = 0; x < 4; x++) {
324       occupied[y][x] = true;
325       occupied[y][x+14] = true;
326     }
327     for(x = 4; x < 14; x++) {
328       block[y][x] = 0;
329 			occupied[y][x] = false;
330 		}
331   }
332   for(x = 0; x < 18; x++)
333     tmp[32][x] = 1;
334   for(y = 0; y < 32; y++) {
335     for(x = 0; x < 4; x++)
336       tmp[y][x] = 1;
337     for(x = 14; x < 18; x++)
338       tmp[y][x] = 1;
339   }
340   for(y = 0; y < 36; y++)
341     for(x = 0; x < 14; x++)
342       dirted[y][x]=2;
343 	for(y = 0; y < 36; y++)
344 		for(x = 0; x < 18; x++) {
345 			blinded[y][x] = 0;
346 			bflash[y][x] = 0;
347 		}
348 }
349 
draw_block(int j,int i) const350 void Canvas::draw_block(int j, int i) const {
351   Byte side, col, to[4];
352   side = block[j][i]&15;
353   col = block[j][i]>>4;
354   to[0] = block[j][i-1];
355   to[1] = block[j-1][i];
356   to[2] = block[j][i+1];
357   to[3] = block[j+1][i];
358   raw_draw_bloc_corner(*screen, (i-4)*18, (j-12)*18, side, ::color[col],to);
359 }
360 
calc_speed()361 void Canvas::calc_speed() {
362   //speed = level * 4;
363   if(level<=10)
364     speed = 4 + (level-1)*5;
365   else
366     speed = 50 + (level-10)*3;
367 }
368 
set_next()369 void Canvas::set_next() {
370   if(znext) {
371     znext->set_next(next);
372     znext2->set_next(next2);
373     znext3->set_next(next3);
374   }
375 }
376 
set_message(const char * m1,const char * m2)377 void Canvas::set_message(const char *m1, const char *m2) {
378 	strncpy(msg1, m1, sizeof(msg1));
379 	msg1[sizeof(msg1)-1]=0;
380 	strncpy(msg2, m2, sizeof(msg2));
381 	msg2[sizeof(msg2)-1]=0;
382 }
383 
add_text_scroller(const char * st,int xoffset,int yoffset)384 void Canvas::add_text_scroller(const char *st, int xoffset, int yoffset) {
385 	if(inter && !small_watch) { // if the canvas is currently visible
386 		Executor *tmp2 = new Executor(true);
387 		tmp2->add(new Player_text_scroll(this, st, xoffset, yoffset));
388 		over->start(tmp2);
389 	}
390 }
391 
blind_all(Byte time)392 void Canvas::blind_all(Byte time) {
393 	if(idle<2 && !dying) {
394 		int x, y;
395 		for(y = 0; y < 36; y++)
396 			for(x = 0; x < 18; x++) {
397 				int tmp = blinded[y][x];
398 				if(occupied[y][x]) {
399 					if(!tmp && time) {
400 						bflash[y][x]=32;
401 						dirted[y][x]=2;
402 					}
403 					tmp=min(255, tmp+time);
404 					blinded[y][x] = tmp;
405 				}
406 			}
407 	}
408 }
409 
add_packet(Canvas * sender,Byte nb,Byte nc,Byte lx,Attack attack,Word hole_pos[])410 void Canvas::add_packet(Canvas *sender, Byte nb, Byte nc, Byte lx, Attack attack, Word hole_pos[]) {
411 	int x, qui;
412 	if(!sender)
413 		return;
414 
415 	Packet_serverlog log("player_attacked");
416 	log.add(Packet_serverlog::Var("id", id()));
417 	log.add(Packet_serverlog::Var("attacker_id", sender->id()));
418 	log.add(Packet_serverlog::Var("type", attack.log_type()));
419 	log.add(Packet_serverlog::Var("size", attack.type==ATTACK_FULLBLIND? nb*nc:nb));
420 	if(game->net_server)
421 		game->net_server->record_packet(&log);
422 
423 	//Nothing further to do if attack is none.
424 	if(attack.type==ATTACK_NONE)
425 		return;
426 
427 	//Update last_attacker and attacks array
428 	qui = game->net_list.canvas2player(sender);
429 	int temp = attacks[qui] + nb*2;
430 	if(temp > 255)
431 		temp = 255;
432 	attacks[qui] = temp;
433 	if(last_attacker != 255) { // if there is a last attacker
434 		if(attacks[qui] >= attacks[last_attacker]) // if larger or equal to the last best
435 			last_attacker = qui; // it's the one that becomes the best
436 	} else
437 		last_attacker = qui;
438 
439 	//If full-blind attack, blind canvas and return
440 	if(attack.type==ATTACK_FULLBLIND) {
441 		blind_all(nb*nc*attack.param);
442 		return;
443 	}
444 
445 	//Attack type is either blind or lines, add bonuses
446 	if(bonus < 20) {
447 		if(nb+bonus > 20)
448 			nb = 20-bonus;
449 		nc--;
450 		int normal = max(nb - nc, 0);
451 		int fucked = nb - normal;
452 		if(game->net_version()>=23) {
453 			for(x=0; x<nb; x++) {
454 				bon[x+bonus].x = 127;
455 				bon[x+bonus].color = sender->color;
456 				bon[x+bonus].blind_time = attack.type==ATTACK_BLIND? attack.param:0;
457 				bon[x+bonus].hole_pos=hole_pos[x];
458 				if(x==nb-1)
459 					bon[x+bonus].final=true;
460 				else
461 					bon[x+bonus].final=false;
462 			}
463 			bonus += nb;
464 		}
465 
466 		if(game->net_version()<23) {
467 			for(x=0; x<normal; x++) {
468 				bon[x+bonus].x = lx;
469 				bon[x+bonus].color = sender->color;
470 				bon[x+bonus].blind_time = attack.type==ATTACK_BLIND? attack.param:0;
471 			}
472 			bonus += normal;
473 
474 			for(x=0; x<fucked; x++) {
475 				lx += nc;
476 				while(lx > 13)
477 					lx -= 10;
478 				bon[x+bonus].x = lx;
479 				bon[x+bonus].color = sender->color;
480 				bon[x+bonus].blind_time = attack.type==ATTACK_BLIND? attack.param:0;
481 			}
482 			bonus += fucked;
483 		}
484 	}
485 }
486 
give_line()487 void Canvas::give_line() {
488 	if(!depth)
489 		return;
490   int i, score_add;
491 	int clean_bonus=0;
492 	bool log_it=false;
493 	Word move_value=(depth<<8)+complexity;
494 	if(send_for_clean) {
495 		clean_bonus=(1+depth)/2;
496 		if(move_value>best_clean) {
497 			log_it=true;
498 			best_clean=move_value;
499 		}
500 	}
501 	if(move_value>best_move) {
502 		log_it=true;
503 		best_move=move_value;
504 	}
505 	move_value=(complexity<<8)+depth;
506 	if(move_value>best_recurse) {
507 		log_it=true;
508 		best_recurse=move_value;
509 	}
510 	if(log_it) {
511 		Packet_serverlog log("player_snapshot");
512 		log.add(Packet_serverlog::Var("id", id()));
513 		log.add(Packet_serverlog::Var("lines", depth));
514 		log.add(Packet_serverlog::Var("clean", send_for_clean? "true":"false"));
515 		log.add(Packet_serverlog::Var("combo", complexity));
516 		log.add(Packet_serverlog::Var("snapshot", snapshot));
517 		if(game->net_server)
518 			game->net_server->record_packet(&log);
519 	}
520   switch(depth) {
521     case 1: score_add = 250; break;
522     case 2: score_add = 500; break;
523     case 3: score_add = 1000; break;
524     case 4: score_add = 2000; break;
525     default: score_add = 200 * depth * depth; break;
526   }
527 	int complexity_points=1000*(complexity-1);
528 	if(game->net_version()>=23)
529 		complexity_points=200*(complexity-1)*(complexity-1);
530   score_add += complexity_points;
531 	//0 clean_points for net_version<23 cause it was added in check_clean
532 	if(send_for_clean && game->net_version()>=23) {
533 		int clean_points;
534 		if(depth<=4)
535 			clean_points=depth*1250;
536 		else
537 			clean_points=depth*depth*500;
538 		score_add += clean_points;
539 	}
540   score_add += (score_add/10)*level;
541   stats[SCORE].add(score_add);
542   i = depth-1;
543 	bool enough=(depth >= game->combo_min);
544 	if(game->net_version()==23) {
545 		int alive_count=0;
546 		for(i=0; i<MAXPLAYERS; i++) {
547 			Canvas *c=game->net_list.get(i);
548 			if(c && c->idle<2)
549 				alive_count++;
550 		}
551 		//alive_count adjustment only if there's at least 5 alive
552 		if(alive_count>4)
553 			alive_count-=4;
554 		else
555 			alive_count=0;
556 		i = max(0, depth-1-alive_count);
557 		// this is a bug, it should have been done like net_version >= 24 (below)
558 		//   but it must remain as is for network compatibility
559 		enough=i? true:false;
560 	}
561 	if(game->net_version()>=24) {
562 		if(!send_for_clean && !game->boring_rules)
563 			while(i && handicap_crowd >= stamp_per_handicap) {
564 				handicap_crowd -= stamp_per_handicap;
565 				--i;
566 			}
567 		if(!i)
568 			enough = false;
569 	}
570 
571 	Packet_serverlog log("player_lines_cleared");
572 	log.add(Packet_serverlog::Var("id", id()));
573 	log.add(Packet_serverlog::Var("lines", depth));
574 	log.add(Packet_serverlog::Var("clean", send_for_clean? "true":"false"));
575 	log.add(Packet_serverlog::Var("attack_size", clean_bonus+(enough? i:0)));
576 	log.add(Packet_serverlog::Var("combo", complexity));
577 	log.add(Packet_serverlog::Var("points", score_add));
578 	if(game->net_server)
579 		game->net_server->record_packet(&log);
580 
581 	Attack clean_att, normal_att;
582 	normal_att=game->normal_attack;
583 	clean_att=game->clean_attack;
584 	if(game->hot_potato && color==game->potato_team) {
585 		normal_att=game->potato_normal_attack;
586 		clean_att=game->potato_clean_attack;
587 	}
588 	if(color==game->potato_team && enough)
589 		potato_lines += (i+clean_bonus);
590 	if(send_for_clean) {
591 		game->net_list.send(this, clean_bonus, complexity, last_x, clean_att, true);
592 		if(chat_text) {
593 			char st[256];
594 			int num;
595 			if(normal_att.type==ATTACK_NONE) {
596 				num=depth;
597 				if(num>1)
598 					sprintf(st, "Clean canvas: %s clears %i lines!", name, num);
599 				else
600 					sprintf(st, "Clean canvas: %s clears 1 line!", name);
601 			}
602 			else {
603 				num=clean_bonus;
604 				if(enough)
605 					num+=i;
606 				if(num>1)
607 					sprintf(st, "Clean canvas: %s sends %i lines!", name, num);
608 				else
609 					sprintf(st, "Clean canvas: %s sends 1 line!", name);
610 			}
611 			message(color, st);
612 		}
613 	}
614   if(i && enough) { // sends nothing if depth < combo_min
615 		if(i>=3 && chat_text && !send_for_clean) {
616 			// if does a 'quad' minimally and not clean
617 			char st[256];
618 			if(normal_att.type == ATTACK_NONE)
619 				sprintf(st, "%s clears %i line%s.", name, depth, depth!=1? "s":"");
620 			else
621 				sprintf(st, "%s sends %i line%s.", name, i, i != 1 ? "s" : "");
622 			message(color, st);
623 		}
624     game->net_list.send(this, i, complexity, last_x, normal_att, false);
625     if(inter && !small_watch) { // if the canvas is currently visible
626 			char st[256];
627 			if(depth == 2)
628 				sprintf(st, "Double! %i pts", score_add);
629 			if(depth == 3)
630 				sprintf(st, "Triple! %i pts", score_add);
631 			if(depth == 4)
632 				sprintf(st, "Quad! %i pts", score_add);
633 			if(depth > 4)
634 				sprintf(st, "%i-lines! %i pts", depth, score_add);
635 			add_text_scroller(st, 20);
636     }
637   }
638 	i=depth-1; //For stats accounting, use old numbers
639   if(i >= 14) {
640 		stats[CLEAR14+i-14].add(1);
641 		i = 14; //Add in CLEARMORE
642 	}
643 	stats[CLEAR00+i].add(1);
644 	stats[COMBO00+complexity-1].add(1);
645 
646   stats[LINESCUR].add(depth);
647   stats[LINESTOT].add(depth);
648   if(game->level_up && stats[LINESCUR].get_value() >= level*15) {
649     level++;
650     calc_speed();
651     Executor *tmp = new Executor(true);
652     tmp->add(new Player_level_up(this));
653     over->start(tmp);
654   }
655   depth = 0;
656   complexity=0;
657   send_for_clean=false;
658 }
659 
change_level_single()660 void Canvas::change_level_single() {
661   change_level(level, pal, bit);
662   //video->setpal(*pal);
663   if(level <= 10 && (level-1) > config.info.unlock_theme && !playback) {
664     config.info.unlock_theme = level-1;
665     config.write();
666   }
667 }
668 
change_level(const int level,Palette * pal,Bitmap * bit)669 void Canvas::change_level(const int level, Palette *pal, Bitmap *bit) {
670   int num, i;
671   num = (level-1)%10;
672 //	if(level>5)
673 //		num=config.info.multi_level-1;
674   sprintf(st, "fond%i.png", num);
675 	if(level==-1)
676 		strcpy(st, "black.png");
677   Res_doze *res = new Res_doze(st);
678   Png img(*res);
679   bit->reload(img);
680   Palette pal2(img);
681   for(i=0; i<256; i++) // was 184
682     pal->setcolor(i, pal2.r(i), pal2.g(i), pal2.b(i));
683 
684   for(i=0; i<MAXTEAMS-1; i++)
685 		fteam[i]->colorize(*pal, pal2.r(i*8+184), pal2.g(i*8+184), pal2.b(i*8+184));
686 	fteam[MAXTEAMS-1]->colorize(*pal, 170, 170, 170);
687 
688   video->need_paint = 2;
689   delete res;
690 
691   delete sons.flash;
692   delete sons.depose3;
693   delete sons.depose2;
694   delete sons.depose;
695   delete sons.drip;
696 
697   sons.flash = sons.depose3 = sons.depose2 = sons.depose = sons.drip = NULL;
698   const char *foo0, *foo1, *foo2, *foo3, *foo4;
699   switch(num) {
700     case 1:
701       foo0="Pwap2.wav";
702       foo1=foo2=foo3="Knock.wav";
703       foo4="click_3.wav";
704       break;
705     case 2:
706       foo0="Blip1.wav";
707       foo1="metal3.wav";
708       foo2="Metal1.wav";
709       foo3="Metal6.wav";
710       foo4="click_1.wav";
711       break;
712     case 3:
713       foo0="Whistle1.wav";
714       foo1="Tapdrip.wav";
715       foo2="Click01.wav";
716       foo3="click_3.wav";
717       foo4="Click01.wav";
718       break;
719     case 4:
720       foo0="Spring.wav";
721       foo1="Pop1.wav";
722       foo2="bloop.wav";
723       foo3="Pwap2.wav";
724       foo4="corkpop.wav";
725       break;
726     case 5:
727       foo0="Whistle2.wav";
728       foo1="Knock.wav";
729       foo2="Splodge.wav";
730       foo3="Pop1.wav";
731       foo4="Tapdrip.wav";
732       break;
733     case 6:
734       foo0="Glass04.wav";
735       foo1="Glass01.wav";
736       foo2="Glass03.wav";
737       foo3="Glass03.wav";
738       foo4="Click01.wav";
739       break;
740     case 7:
741       foo0="Bubble2.wav";
742       foo1="Water05_1.wav";
743       foo2="water05_2.wav";
744       foo3="water05_3.wav";
745       foo4="Click01.wav";
746       break;
747     case 8:
748       foo0="Ceramic3.wav";
749       foo1="Explod03.wav";
750       foo2="Explod05.wav";
751       foo3="Explod06.wav";
752       foo4="Tapdrip.wav";
753       break;
754     case 9:
755       foo0="Smash2.wav";
756       foo1="Knock.wav";
757       foo2="bloop.wav";
758       foo3="click_1.wav";
759       foo4="Pop1.wav";
760       break;
761     default:
762       foo0="Pwap2.wav";
763       foo1="Hitwood1.wav";
764       foo2="Chop2.wav";
765       foo3="metal3.wav";
766       foo4="Tapdrip.wav";
767       break;
768   }
769   sons.flash = new Sample(Res_doze(foo0)); // when we do a ligne (flash)
770   sons.depose3 = new Sample(Res_doze(foo1)); // drop
771   sons.depose2 = new Sample(Res_doze(foo2)); // drop
772   sons.depose = new Sample(Res_doze(foo3)); // drop
773   sons.drip = new Sample(Res_doze(foo4)); // rotate
774 }
775 
clear_tmp()776 void Canvas::clear_tmp() {
777   int i, j;
778   for(j = 0; j < 32; j++)
779     for(i = 4; i < 14; i++)
780       tmp[j][i] = 0;
781 	for(j=0; j<36; j++)
782 		for(i=0; i<18; i++)
783 			moved[j][i]=false;
784 }
785 
set_canvas_pos(int px,int py,Bitmap * fo,Video_bitmap * s,Zone_next * z,Zone_next * z2,Zone_next * z3,Inter * in)786 void Canvas::set_canvas_pos(int px, int py, Bitmap *fo, Video_bitmap *s, Zone_next *z, Zone_next *z2, Zone_next *z3, Inter *in) {
787   x = px;
788   y = py;
789   fond = fo;
790   screen = s;
791   znext = z;
792   znext2 = z2;
793   znext3 = z3;
794   set_next();
795   inter = in;
796   small_watch = false;
797 }
798 
hide()799 void Canvas::hide() {
800   x = 0;
801   y = 0;
802   fond = NULL;
803   screen = NULL;
804   znext = NULL;
805   znext2 = NULL;
806   znext3 = NULL;
807   inter = NULL;
808 	z_lines=z_potatolines=z_linestot=z_potatolinestot=NULL;
809 }
810 
check_key(int i)811 Byte Canvas::check_key(int i) {
812   if(ecran && ecran->focus) {  // prevents controlling while inputting
813                                // into a zone_text_input that has the
814                                // focus
815     clear_key(i); // prevents rotating from happening after an input
816                   // (because bit 'was released!')
817     input->allow_key_repeat(true);
818     return 0;
819   } else {
820 		input->allow_key_repeat(false);
821 		if(i < 5)
822 			return input->keys[config.player[player].key[i]];
823 		else
824 			return input->keys[config.player2[player].key[i - 5]];
825   }
826 }
827 
clear_key(int i)828 void Canvas::clear_key(int i) {
829 	if(i < 5)
830 		input->keys[config.player[player].key[i]] = 0;
831 	else
832 		input->keys[config.player2[player].key[i - 5]] = 0;
833 }
834 
unrelease_key(int i)835 void Canvas::unrelease_key(int i) {
836 	if(i<5)
837 		input->keys[config.player[player].key[i]] &= ~RELEASED;
838 	else
839 		input->keys[config.player2[player].key[i-5]] &= ~RELEASED;
840 }
841 
blit_level_up()842 void Canvas::blit_level_up() {
843   screen->put_surface(sprlevel_up, 10, level_up - 30);
844   dirt_rect(10, level_up - 30, sprlevel_up->w, sprlevel_up->h);
845 }
846 
blit_flash()847 void Canvas::blit_flash() {
848   int i, j, pj;
849   for(j = 0; j < 20; j++) {
850     pj = flash[j];
851     if(pj) {
852       for(i=0; i<18; i++)
853         screen->hline((pj-12)*18+i, 0, 10*18-1, color_flash);
854       dirt_rect(0, (pj-12)*18, 10*18, 18);
855     }
856   }
857 }
858 
dirt_rect(int x1,int y1,int w1,int h1)859 void Canvas::dirt_rect(int x1, int y1, int w1, int h1) {
860   int i,j;
861   w1 = (x1+w1+17)/18;
862   h1 = (y1+h1+17)/18;
863   x1 = x1/18;
864   y1 = y1/18;
865   x1 = max(0,x1);
866   y1 = max(0,y1);
867   w1 = min(10,w1);
868   h1 = min(20,h1);
869   for(j=y1; j<h1; j++)
870     for(i=x1; i<w1; i++)
871       dirted[j+12][i+4]=2;
872 }
873 
collide(Byte px,Byte py,Byte rot)874 bool Canvas::collide(Byte px, Byte py, Byte rot) {
875   return check_collide(bloc, px, py, rot);
876 }
877 
check_collide(Bloc * blo,Byte px,Byte py,Byte rot)878 bool Canvas::check_collide(Bloc *blo, Byte px, Byte py, Byte rot) {
879 	collide_side_only=true;
880 	bool ret=false;
881   int i,j;
882   for(j = 0; j < 4; j++)
883     for(i = 0; i < 4; i++) {
884       if(blo->bloc[bloc->type][rot][j][i])
885         if(occupied[py + j][px + i]) {
886 					if(px+i>=4 && px+i<14)
887 						collide_side_only=false;
888           ret=true;
889 				}
890     }
891 	if(ret) {
892 		return ret;
893 	}
894 	else {
895 		collide_side_only=false;
896 		return false;
897 	}
898 }
899 
step_bflash()900 void Canvas::step_bflash() {
901   int j, i;
902   for(j = 12; j < 32; j++)
903     for(i = 4; i < 14; i++) {
904 			if(occupied[j][i] && bflash[j][i]) {
905 				if(!(bflash[j][i]&3))
906 					dirted[j][i] = 2;
907 				bflash[j][i]--;
908 				if(!bflash[j][i])
909 					dirted[j][i] = 2;
910 			}
911 		}
912 }
913 
blit_back()914 void Canvas::blit_back() {
915 	step_bflash();
916 	video->clone_palette(fond->surface);
917   int j, i, x2, y2;
918   for(j = 12; j < 32; j++)
919     for(i = 4; i < 14; i++) {
920       if(dirted[j][i]) {
921 				bool blitbloc=true;
922 				if(!occupied[j][i])
923 					blitbloc=false;
924 				if(bflash[j][i])
925 					if(bflash[j][i]&4)
926 						blitbloc=false;
927 				if(!bflash[j][i] && blinded[j][i])
928 					blitbloc=false;
929         if(blitbloc) {
930           draw_block(j,i);
931         } else {
932           x2=(i-4)*18;
933           y2=(j-12)*18;
934           SDL_Rect rect;
935           rect.x = x2;
936           rect.y = y2;
937           rect.w = rect.h = 18;
938           screen->put_surface(fond->surface, rect, x2, y2);
939         }
940         dirted[j][i]--;
941       }
942 		}
943 	if(msg1[0] && inter)
944 		inter->font->draw(msg1, video->vb, x+5, y+40);
945 	if(msg2[0] && inter)
946 		inter->font->draw(msg2, video->vb, x+5, y+60);
947 }
948 
blit_bloc(Bloc * blo)949 void Canvas::blit_bloc(Bloc *blo) {
950   int j,i,bx,by,tx,ty;
951   if(!blo)
952     return;
953   if(smooth) {
954     blo->draw(*screen);
955   } else {
956     blo->draw(*screen, (blo->bx-4)*18, (blo->by-12)*18);
957   }
958   for(j=0; j<4; j++)
959     for(i=0; i<4; i++) {
960       if(blo->bloc[blo->type][blo->rot][j][i]) {
961         if(smooth) {
962           tx=(blo->x>>4)+4*18;
963           ty=(blo->y>>4)+12*18;
964         } else {
965           tx=blo->bx*18;
966           ty=blo->by*18;
967         }
968         tx += i*18;
969         ty += j*18;
970         bx=tx/18;
971         by=ty/18;
972         if(by>=0)
973           dirted[by][bx]=2;
974         bx=(tx+17)/18;
975         if(by>=0)
976           dirted[by][bx]=2;
977         by=(ty+17)/18;
978         if(by>=0)
979           dirted[by][bx]=2;
980         bx=tx/18;
981         if(by>=0)
982           dirted[by][bx]=2;
983       }
984     }
985 }
986 
small_draw_block(int j,int i) const987 void Canvas::small_draw_block(int j, int i) const {
988   Byte side, col;
989   side = block[j][i]&15;
990   col = block[j][i]>>4;
991   raw_small_draw_bloc(*screen, (i-4)*6, (j-12)*6, side, ::color[col]);
992 }
993 
small_blit_back()994 void Canvas::small_blit_back() {
995 	step_bflash();
996 	video->clone_palette(fond->surface);
997   int j, i, x2, y2;
998   for(j = 12; j < 32; j++)
999     for(i = 4; i < 14; i++)
1000       if(dirted[j][i]) {
1001 				bool blitbloc=true;
1002 				if(!occupied[j][i])
1003 					blitbloc=false;
1004 				if(bflash[j][i])
1005 					if(bflash[j][i]&4)
1006 						blitbloc=false;
1007 				if(!bflash[j][i] && blinded[j][i])
1008 					blitbloc=false;
1009         if(blitbloc) {
1010           small_draw_block(j,i);
1011         } else {
1012           x2=(i-4)*6;
1013           y2=(j-12)*6;
1014           SDL_Rect rect;
1015           rect.x = x2;
1016           rect.y = y2;
1017           rect.w = rect.h = 6;
1018           screen->put_surface(fond->surface, rect, x2, y2);
1019         }
1020         dirted[j][i]--;
1021       }
1022 }
1023 
small_blit_bloc(Bloc * blo)1024 void Canvas::small_blit_bloc(Bloc *blo) {
1025   int j,i,bx,by,tx,ty;
1026   if(!blo)
1027     return;
1028   blo->small_draw(*screen, (blo->bx-4)*6, (blo->by-12)*6);
1029   for(j=0; j<4; j++)
1030     for(i=0; i<4; i++) {
1031       if(blo->bloc[blo->type][blo->rot][j][i]) {
1032         tx=blo->bx*6;
1033         ty=blo->by*6;
1034         tx += i*6;
1035         ty += j*6;
1036         bx=tx/6;
1037         by=ty/6;
1038         if(by>=0)
1039           dirted[by][bx]=2;
1040         bx=(tx+5)/6;
1041         if(by>=0)
1042           dirted[by][bx]=2;
1043         by=(ty+5)/6;
1044         if(by>=0)
1045           dirted[by][bx]=2;
1046         bx=tx/6;
1047         if(by>=0)
1048           dirted[by][bx]=2;
1049       }
1050     }
1051 }
1052 
small_blit_flash()1053 void Canvas::small_blit_flash() {
1054   int i, j, pj;
1055   for(j = 0; j < 20; j++) {
1056     pj = flash[j];
1057     if(pj) {
1058       for(i=0; i<6; i++)
1059         screen->hline((pj-12)*6+i, 0, 10*6-1, color_flash);
1060       dirt_rect(0, (pj-12)*18, 10*18, 18);
1061     }
1062   }
1063 }
1064 
add_watcher(Watcher * w)1065 void Canvas::add_watcher(Watcher *w) {
1066   watchers.push_back(w);
1067 }
1068 
remove_watcher(Net_connection * nc)1069 void Canvas::remove_watcher(Net_connection *nc) {
1070 	vector<Watcher*>::iterator it = watchers.begin();
1071 
1072 	while (it != watchers.end()) {
1073 		if ((*it)->nc == nc) {
1074 			delete *it;
1075 			watchers.erase(it);
1076 			it = watchers.begin();
1077 		} else
1078 			++it;
1079 	}
1080 }
1081 
islocal() const1082 bool Canvas::islocal() const {
1083 	return local_player;
1084 }
1085 
start_moves()1086 void Canvas::start_moves() {
1087 	if(game->wants_moves) {
1088 		if(moves)
1089 			delete moves;
1090 		moves=new Packet_clientmoves();
1091 		moves->player = num_player;
1092 	}
1093 }
1094 
send_p_moves()1095 void Canvas::send_p_moves() {
1096 	if(game->wants_moves) {
1097 		if(moves) {
1098 			net->sendtcp(moves);
1099 			delete moves;
1100 			moves=NULL;
1101 		}
1102 	}
1103 }
1104 
start_byte()1105 void Canvas::start_byte() {
1106 	if(game->wants_moves) {
1107 		if(!moves)
1108 			start_moves();
1109 		if(moves->size>=50) {
1110 			send_p_moves();
1111 			start_moves();
1112 		}
1113 		moves->start_byte();
1114 	}
1115 }
1116 
set_bit(int v)1117 void Canvas::set_bit(int v) {
1118 	if(moves)
1119 		moves->set_bit(v);
1120 }
1121 
write_byte()1122 void Canvas::write_byte() {
1123 	if(moves)
1124 		moves->write_byte();
1125 }
1126