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 #include "packets.h"
21 
22 #include "net_buf.h"
23 #include "error.h"
24 #include "net_stuff.h"
25 #include "stats.h"
26 #include "cfgfile.h"
27 #include "canvas.h"
28 
29 using std::vector;
30 
write(Net_buf * p)31 void Packet_wantjoin::write(Net_buf *p) {
32 	Packet_ping::write(p);
33 	p->write_byte(1);
34 	p->write_byte(net_version);
35 	p->write_byte(language);
36 	p->write_byte(os);
37 	p->write_bool(true);
38 }
39 
read(Net_buf * p)40 bool Packet_wantjoin::read(Net_buf *p) {
41 	if(!Packet_ping::read(p))
42 		return false;
43 	if(!p->read_byte())
44 		return false; // completely ignore 1.1.0 clients
45 	net_version=p->read_byte();
46 	language=p->read_byte();
47 	os=p->read_byte();
48 	p->read_bool();
49 	return true;
50 }
51 
read_attack(Attack * a,Net_buf * p)52 bool read_attack(Attack *a, Net_buf *p) {
53 	a->type=(Attack_type) p->read_byte();
54 	if(a->type>=ATTACK_LAST)
55 		return false;
56 	a->param=p->read_dword();
57 	return true;
58 }
59 
write_attack(Attack * a,Net_buf * p)60 void write_attack(Attack *a, Net_buf *p) {
61 	p->write_byte(a->type);
62 	p->write_dword(a->param);
63 }
64 
Packet_gameinfo()65 Packet_gameinfo::Packet_gameinfo() {
66 	packet_id = P_GAMEINFO;
67 	name[0] = 0;
68 	version = 0;
69 	port = 0;
70 	game_end_value = 0;
71 	nolevel_up = 0;
72 	delay_start = false;
73 	terminated = false;
74 	level_start = 0;
75 	combo_min = 0;
76 	allow_handicap = true;
77 	survivor = false;
78 	hot_potato = false;
79 	game_end = 0;
80 }
81 
~Packet_gameinfo()82 Packet_gameinfo::~Packet_gameinfo() {
83 	while (!players.empty()) {
84 		delete players.back();
85 		players.pop_back();
86 	}
87 }
88 
write(Net_buf * p)89 void Packet_gameinfo::write(Net_buf *p) {
90 	Packet_udp::write(p);
91 	p->write_string(name);
92 	p->write_byte(version);
93 	p->write_dword(port);
94 	p->write_byte(players.size());
95 	vector<Net_player*>::const_iterator it;
96 	for (it = players.begin(); it != players.end(); ++it) {
97 		p->write_byte((*it)->team);
98 		p->write_string((*it)->name);
99 	}
100 	p->write_dword(game_end_value);
101 	p->write_bool(nolevel_up);
102 	p->write_bool(delay_start);
103 	p->write_bool(terminated);
104 	p->write_byte(level_start);
105 	p->write_byte(combo_min);
106 	p->write_bool(survivor);
107 	p->write_byte(game_end);
108 	for (it = players.begin(); it != players.end(); ++it)
109 		p->write_dword((*it)->handicap);
110 	//allow_handicap is reversed because the default should be true
111 	//  but 1.1.1 and older will not supply it (thus we'll read a
112 	//  0 from those).
113 	p->write_bool(!allow_handicap);
114 	p->write_bool(hot_potato);
115 	if(version>=22) {
116 		write_attack(&normal_attack, p);
117 		write_attack(&clean_attack, p);
118 		write_attack(&potato_normal_attack, p);
119 		write_attack(&potato_clean_attack, p);
120 	}
121 }
122 
read(Net_buf * p)123 bool Packet_gameinfo::read(Net_buf *p) {
124 	if(!Packet_udp::read(p))
125 		return false;
126 	if(!p->read_string(name, sizeof(name)))
127 		return false;
128 	version = p->read_byte();
129 	port = p->read_dword();
130 	Byte num_player = p->read_byte();
131 	if(num_player>MAXPLAYERS)
132 		return false;
133 	int i;
134 	for(i=0; i<num_player; i++) {
135 		char tmp[40];
136 		Byte t=p->read_byte();
137 		if(t>=MAXTEAMS)
138 			return false;
139 		if(!p->read_string(tmp, sizeof(tmp)))
140 			return false;
141 		add_player(0, t, tmp, -1, 0);
142 	}
143 	game_end_value = p->read_dword();
144 	nolevel_up = p->read_bool();
145 	delay_start = p->read_bool();
146 	terminated = p->read_bool();
147 	level_start = p->read_byte();
148 	if(level_start > 10)
149 		return false;
150 	combo_min = p->read_byte();
151 	if(combo_min > 10)
152 		return false;
153 	survivor = p->read_bool();
154 	game_end = p->read_byte();
155 	if(game_end > 4)
156 		return false;
157 	for(i=0; i<num_player; i++) {
158 		int handicap;
159 		handicap = p->read_dword();
160 		if(handicap<0 || handicap>4)
161 			return false;
162 		players[i]->handicap=handicap;
163 	}
164 	//allow_handicap is reversed because the default should be true
165 	//  but 1.1.1 and older will not supply it (thus we'll read a
166 	//  0 from those).
167 	allow_handicap=!p->read_bool();
168 	hot_potato=p->read_bool();
169 	if(version>=22) {
170 		if(!read_attack(&normal_attack, p))
171 			return false;
172 		if(!read_attack(&clean_attack, p))
173 			return false;
174 		if(!read_attack(&potato_normal_attack, p))
175 			return false;
176 		if(!read_attack(&potato_clean_attack, p))
177 			return false;
178 	}
179 	return true;
180 }
181 
~Packet_gameserver()182 Packet_gameserver::~Packet_gameserver() {
183 	while (!players.empty()) {
184 		delete players.back();
185 		players.pop_back();
186 	}
187 }
188 
write(Net_buf * p)189 void Packet_gameserver::write(Net_buf *p) {
190 	Packet_ping::write(p);
191 	p->write_byte(version);
192 	p->write_string(name);
193 	p->write_bool(accepted);
194 	p->write_dword(game_seed);
195 	p->write_bool(paused);
196 	p->write_byte(players.size());
197 	p->write_bool(nolevel_up);
198 	p->write_byte(level_start);
199 	p->write_bool(survivor);
200 	p->write_byte(combo_min);
201 	p->write_word(delay_start);
202 	p->write_byte(game_end);
203 	p->write_dword(game_end_value);
204 	vector<Net_player*>::const_iterator it;
205 	for (it = players.begin(); it != players.end(); ++it) {
206 		p->write_byte((*it)->quel);
207 		p->write_byte((*it)->team);
208 		p->write_string((*it)->name);
209 	}
210 	p->write_bool(wants_moves);
211 	p->write_byte(syncpoint);
212 	p->write_byte(potato_team);
213 	for (it = players.begin(); it != players.end(); ++it)
214 		p->write_dword((*it)->handicap);
215 	//allow_handicap is reversed because the default should be true
216 	//  but 1.1.1 and older will not supply it (thus we'll read a
217 	//  0 from those).
218 	p->write_bool(!allow_handicap);
219 	p->write_bool(hot_potato);
220 	if(version>=22) {
221 		write_attack(&normal_attack, p);
222 		write_attack(&clean_attack, p);
223 		write_attack(&potato_normal_attack, p);
224 		write_attack(&potato_clean_attack, p);
225 	}
226 	p->write_bool(single);
227 	p->write_bool(terminated);
228 	for (it = players.begin(); it != players.end(); ++it)
229 		p->write_dword((*it)->player_id);
230 	p->write_bool(boring_rules);
231 }
232 
read(Net_buf * p)233 bool Packet_gameserver::read(Net_buf *p) {
234 	if(!Packet_ping::read(p))
235 		return false;
236 	version = p->read_byte();
237 	if(!p->read_string(name, sizeof(name)))
238 		return false;
239 	accepted=p->read_bool();
240 	game_seed=p->read_dword();
241 	paused=p->read_bool();
242 	Byte num_player = p->read_byte();
243 	if(num_player>MAXPLAYERS)
244 		return false;
245 	nolevel_up=p->read_bool();
246 	level_start=p->read_byte();
247 	survivor=p->read_bool();
248 	combo_min=p->read_byte();
249 	delay_start=p->read_word();
250 	game_end=p->read_byte();
251 	if(game_end>=END_LAST)
252 		return false;
253 	game_end_value=p->read_dword();
254 	int i;
255 	for(i=0; i<num_player; i++) {
256 		char tmp[40];
257 		Byte quel=p->read_byte();
258 		if(quel>=MAXPLAYERS)
259 			return false;
260 		Byte t=p->read_byte();
261 		if(t>=MAXTEAMS)
262 			return false;
263 		if(!p->read_string(tmp, sizeof(tmp)))
264 			return false;
265 		add_player(quel, t, tmp, 0, 0);
266 	}
267 	wants_moves=p->read_bool();
268 	syncpoint=p->read_byte();
269 	if(syncpoint>Canvas::LAST)
270 		return false;
271 	potato_team=p->read_byte();
272 	if(potato_team>=MAXTEAMS && potato_team!=255)
273 		return false;
274 	//Adjust player handicaps (they are at the end to maintain
275 	//  net compatibility with net_version <= 20
276 	for(i=0; i<num_player; i++) {
277 		int handicap=p->read_dword();
278 		if(handicap<0 || handicap>4)
279 			return false;
280 		players[i]->handicap = handicap;
281 	}
282 	//allow_handicap is reversed because the default should be true
283 	//  but 1.1.1 and older will not supply it (thus we'll read a
284 	//  0 from those).
285 	allow_handicap=!p->read_bool();
286 	hot_potato=p->read_bool();
287 	if(version>=22) {
288 		if(!read_attack(&normal_attack, p))
289 			return false;
290 		if(!read_attack(&clean_attack, p))
291 			return false;
292 		if(!read_attack(&potato_normal_attack, p))
293 			return false;
294 		if(!read_attack(&potato_clean_attack, p))
295 			return false;
296 	}
297 	single=p->read_bool();
298 	terminated=p->read_bool();
299 	for (i = 0; i < num_player; ++i)
300 		players[i]->player_id = p->read_dword();
301 	boring_rules=p->read_bool();
302 	return true;
303 }
304 
any_attack()305 bool Packet_gameserver::any_attack() {
306 	if(normal_attack.type!=ATTACK_NONE || clean_attack.type!=ATTACK_NONE)
307 		return true;
308 	if(hot_potato && (potato_normal_attack.type!=ATTACK_NONE || potato_clean_attack.type!=ATTACK_NONE))
309 		return true;
310 	return false;
311 }
312 
read(Net_buf * p)313 bool Packet_chat::read(Net_buf *p) {
314 	if(!Packet_tcp::read(p))
315 		return false;
316 	team = p->read_byte();
317 	if(team>=MAXTEAMS || team<-1)
318 		return false;
319 	if(!p->read_string(text, sizeof(text)))
320 		return false;
321 	to_team = p->read_byte();
322 	if(to_team>=MAXTEAMS || to_team<-1)
323 		return false;
324 	return true;
325 }
326 
write(Net_buf * p)327 void Packet_chat::write(Net_buf *p) {
328 	Packet_tcp::write(p);
329 	p->write_byte(team);
330 	p->write_string(text);
331 	p->write_byte(to_team);
332 }
333 
read(Net_buf * p)334 bool Packet_playerwantjoin::read(Net_buf *p) {
335 	if(!Packet_ping::read(p))
336 		return false;
337 	team = p->read_byte();
338 	if(team>=MAXTEAMS)
339 		return false;
340 	if(!p->read_string(name, sizeof(name)))
341 		return false;
342 	player = p->read_byte();
343 	if(player>2)
344 		return false;
345 	int repeat = p->read_dword();
346 	if(repeat<-1 || repeat>3)
347 		return false;
348 	smooth = p->read_dword();
349 	if(smooth<0 || smooth>1)
350 		return false;
351 	shadow = p->read_dword();
352 	if(shadow<0 || shadow>1)
353 		return false;
354 	handicap = p->read_dword();
355 	if(handicap<0 || handicap>4)
356 		return false;
357 	p->read_mem(player_hash, sizeof(player_hash));
358 	if(!p->read_string(team_name, sizeof(team_name)))
359 		return false;
360 	p->read_mem(team_hash, sizeof(team_hash));
361 	h_repeat = p->read_dword();
362 	if(h_repeat<0 || h_repeat>3)
363 		return false;
364 	v_repeat = p->read_dword();
365 	if(v_repeat<0 || v_repeat>3)
366 		return false;
367 	return true;
368 }
369 
write(Net_buf * p)370 void Packet_playerwantjoin::write(Net_buf *p) {
371 	Packet_ping::write(p);
372 	p->write_byte(team);
373 	p->write_string(name);
374 	p->write_byte(player);
375 	if(game->net_version()>=23)
376 		p->write_dword(static_cast<Dword>(-1));
377 	else
378 		p->write_dword(h_repeat);
379 	p->write_dword(smooth);
380 	p->write_dword(shadow);
381 	p->write_dword(handicap);
382 	p->write_mem(player_hash, sizeof(player_hash));
383 	p->write_string(team_name);
384 	p->write_mem(team_hash, sizeof(team_hash));
385 	p->write_dword(h_repeat);
386 	p->write_dword(v_repeat);
387 }
388 
read(Net_buf * p)389 bool Packet_player::read(Net_buf *p) {
390 	if(!Packet_ping::read(p))
391 		return false;
392 	team = p->read_byte();
393 	if(team>=MAXTEAMS)
394 		return false;
395 	if(!p->read_string(name, sizeof(name)))
396 		return false;
397 	player = p->read_byte();
398 	if(player>2)
399 		return false;
400 	int repeat = p->read_dword();
401 	if(repeat<-1 || repeat>3)
402 		return false;
403 	if(repeat!=-1)
404 		h_repeat = v_repeat = repeat;
405 	smooth = p->read_dword();
406 	if(smooth<0 || smooth>1)
407 		return false;
408 	shadow = p->read_dword();
409 	if(shadow<0 || shadow>1)
410 		return false;
411 	pos = p->read_byte();
412 	if(pos>=MAXPLAYERS)
413 		return false;
414 	handicap = p->read_dword();
415 	if(handicap<0 || handicap>4)
416 		return false;
417 	int h_repeat = p->read_dword();
418 	if(h_repeat<0 || h_repeat>3)
419 		return false;
420 	if(repeat==-1 || h_repeat)
421 		this->h_repeat = h_repeat;
422 	int v_repeat = p->read_dword();
423 	if(v_repeat<0 || v_repeat>3)
424 		return false;
425 	if(repeat==-1 || v_repeat)
426 		this->v_repeat = v_repeat;
427 	player_id = p->read_dword();
428 	return true;
429 }
430 
write(Net_buf * p)431 void Packet_player::write(Net_buf *p) {
432 	Packet_ping::write(p);
433 	p->write_byte(team);
434 	p->write_string(name);
435 	p->write_byte(player);
436 	if(game->net_version()>=23)
437 		p->write_dword(static_cast<Dword>(-1));
438 	else
439 		p->write_dword(h_repeat);
440 	p->write_dword(smooth);
441 	p->write_dword(shadow);
442 	p->write_byte(pos);
443 	p->write_dword(handicap);
444 	p->write_dword(h_repeat);
445 	p->write_dword(v_repeat);
446 	p->write_dword(player_id);
447 }
448 
read(Net_buf * p)449 bool Packet_playeraccepted::read(Net_buf *p) {
450 	if(!Packet_ping::read(p))
451 		return false;
452 	pos = p->read_byte();
453 	if(pos>=MAXPLAYERS)
454 		return false;
455 	accepted = p->read_byte();
456 	return true;
457 }
458 
write(Net_buf * p)459 void Packet_playeraccepted::write(Net_buf *p) {
460 	Packet_ping::write(p);
461 	p->write_byte(pos);
462 	p->write_byte(accepted);
463 }
464 
read(Net_buf * p)465 bool Packet_pause::read(Net_buf *p) {
466 	if(!Packet_tcp::read(p))
467 		return false;
468 	player=p->read_byte();
469 	return true;
470 }
471 
write(Net_buf * p)472 void Packet_pause::write(Net_buf *p) {
473 	Packet_tcp::write(p);
474 	p->write_byte(player);
475 }
476 
~Packet_stat()477 Packet_stat::~Packet_stat() {
478 	while (!net_stats.empty()) {
479 		delete net_stats.back();
480 		net_stats.pop_back();
481 	}
482 }
483 
add_stat(Byte s,int v)484 void Packet_stat::add_stat(Byte s, int v) {
485 	net_stats.push_back(new Net_stat(s, v));
486 }
487 
read(Net_buf * p)488 bool Packet_stat::read(Net_buf *p) {
489 	if(!Packet_playerbase::read(p))
490 		return false;
491 	num_stat=p->read_byte();
492 	for(int i=0; i<num_stat; i++) {
493 		Byte st=p->read_byte();
494 		int val=p->read_dword();
495 		if(st>=CS::LAST)
496 			continue; //Ignore stats we don't know about
497 		add_stat(st, val);
498 	}
499 	return true;
500 }
501 
write(Net_buf * p)502 void Packet_stat::write(Net_buf *p) {
503 	Packet_playerbase::write(p);
504 	p->write_byte(net_stats.size());
505 	vector<Net_stat*>::const_iterator it;
506 	for (it = net_stats.begin(); it != net_stats.end(); ++it) {
507 		p->write_byte((*it)->st);
508 		p->write_dword((*it)->value);
509 	}
510 }
511 
~Packet_gamestat()512 Packet_gamestat::~Packet_gamestat() {
513 	while (!net_stats.empty()) {
514 		delete net_stats.back();
515 		net_stats.pop_back();
516 	}
517 }
518 
add_stat(Byte s,int v)519 void Packet_gamestat::add_stat(Byte s, int v) {
520 	net_stats.push_back(new Net_stat(s, v));
521 }
522 
read(Net_buf * p)523 bool Packet_gamestat::read(Net_buf *p) {
524 	if(!Packet_tcp::read(p))
525 		return false;
526 	num_stat=p->read_byte();
527 	for(int i=0; i<num_stat; i++) {
528 		Byte st=p->read_byte();
529 		int val=p->read_dword();
530 		if(st>=GS::LAST)
531 			continue; //Ignore stats we don't know about
532 		add_stat(st, val);
533 	}
534 	return true;
535 }
536 
write(Net_buf * p)537 void Packet_gamestat::write(Net_buf *p) {
538 	Packet_tcp::write(p);
539 	p->write_byte(net_stats.size());
540 	vector<Net_stat*>::const_iterator it;
541 	for (it = net_stats.begin(); it != net_stats.end(); ++it) {
542 		p->write_byte((*it)->st);
543 		p->write_dword((*it)->value);
544 	}
545 }
546 
read(Net_buf * p)547 bool Packet_dropplayer::read(Net_buf *p) {
548 	if(!Packet_playerbase::read(p))
549 		return false;
550 	Byte r=p->read_byte();
551 	if(r>=DROP_LAST)
552 		return false;
553 	reason=(Drop_reason) r;
554 	return true;
555 }
556 
write(Net_buf * p)557 void Packet_dropplayer::write(Net_buf *p) {
558 	Packet_playerbase::write(p);
559 	p->write_byte(reason);
560 }
561 
read(Net_buf * p)562 bool Packet_playerbase::read(Net_buf *p) {
563 	if(!Packet_tcp::read(p))
564 		return false;
565 	player=p->read_byte();
566 	if(player>=MAXPLAYERS)
567 		return false;
568 	return true;
569 }
570 
write(Net_buf * p)571 void Packet_playerbase::write(Net_buf *p) {
572 	Packet_tcp::write(p);
573 	p->write_byte(player);
574 }
575 
read(Net_buf * p)576 bool Packet_stampblock::read(Net_buf *p) {
577 	if(!Packet_playerbase::read(p))
578 		return false;
579 	x=p->read_byte();
580 	y=p->read_byte();
581 	rotate=p->read_byte();
582 	score=p->read_byte();
583 	date=p->read_word();
584 	block_rotated=p->read_byte();
585 	time_held=p->read_word();
586 	return true;
587 }
588 
write(Net_buf * p)589 void Packet_stampblock::write(Net_buf *p) {
590 	Packet_playerbase::write(p);
591 	p->write_byte(x);
592 	p->write_byte(y);
593 	p->write_byte(rotate);
594 	p->write_byte(score);
595 	p->write_word(date);
596 	p->write_byte(block_rotated);
597 	p->write_word(time_held);
598 }
599 
read(Net_buf * p)600 bool Packet_dead::read(Net_buf *p) {
601 	if(!Packet_playerbase::read(p))
602 		return false;
603 	then_gone=p->read_bool();
604 	return true;
605 }
606 
write(Net_buf * p)607 void Packet_dead::write(Net_buf *p) {
608 	Packet_playerbase::write(p);
609 	p->write_bool(then_gone);
610 }
611 
read(Net_buf * p)612 bool Packet_startwatch::read(Net_buf *p) {
613 	if(!Packet_playerbase::read(p))
614 		return false;
615 	address=p->read_dword();
616 	stop=p->read_bool();
617 	update=p->read_byte();
618 	return true;
619 }
620 
write(Net_buf * p)621 void Packet_startwatch::write(Net_buf *p) {
622 	Packet_playerbase::write(p);
623 	p->write_dword(address);
624 	p->write_bool(stop);
625 	p->write_byte(update);
626 }
627 
read(Net_buf * p)628 bool Packet_download::read(Net_buf *p) {
629 	if(!Packet_playerbase::read(p))
630 		return false;
631 	p->read_mem(can, sizeof(can));
632 	int i, j;
633 	for(j=0; j<32; j++)
634 		for(i=0; i<10; i++) {
635 			occ[j][i]=can[j][i]? true:false;
636 			can[j][i] &= 0x7F;
637 		}
638 	seed = p->read_dword();
639 	idle = p->read_byte();
640 	if(idle>3)
641 		return false;
642 	state = p->read_byte();
643 	if(state>Canvas::LAST)
644 		return false;
645 	bloc = p->read_byte();
646 	if(bloc>6 && bloc!=255)
647 		return false;
648 	next = p->read_byte();
649 	if(next>6 && bloc!=255)
650 		return false;
651 	next2 = p->read_byte();
652 	if(next2>6 && bloc!=255)
653 		return false;
654 	next3 = p->read_byte();
655 	if(next3>6 && bloc!=255)
656 		return false;
657 	bonus = p->read_byte();
658 	if(bonus>20)
659 		return false;
660 	for(i=0; i<20; i++) {
661 		if(i<bonus) {
662 			bon[i].x=p->read_byte();
663 			bon[i].color=p->read_byte();
664 			bon[i].blind_time=0; //Will be fixed below
665 			bon[i].hole_pos=0;
666 			bon[i].final=false;
667 		}
668 		else {
669 			p->read_byte();
670 			p->read_byte();
671 			bon[i].x=0;
672 			bon[i].color=0;
673 			bon[i].blind_time=0;
674 			bon[i].hole_pos=0;
675 			bon[i].final=false;
676 		}
677 	}
678 	for(i=0; i<MAXPLAYERS; i++)
679 		attacks[i] = p->read_byte();
680 	last_attacker = p->read_byte();
681 	if(last_attacker>=MAXPLAYERS && last_attacker!=255)
682 		return false;
683 	p->read_mem(blinded, sizeof(blinded));
684 	for(i=0; i<20; i++)
685 		if(i<bonus)
686 			bon[i].blind_time=p->read_byte();
687 		else
688 			p->read_byte();
689 	for(i=0; i<bonus; i++) {
690 		Word tmp=p->read_word();
691 		bon[i].hole_pos=tmp & 0x3FF;
692 		bon[i].final=tmp&0x8000? true:false;
693 	}
694 	return true;
695 }
696 
write(Net_buf * p)697 void Packet_download::write(Net_buf *p) {
698 	Packet_playerbase::write(p);
699 	Byte tmp[32][10];
700 	memcpy(tmp, can, sizeof(can));
701 	int i, j;
702 	if(game->net_version()>=23)
703 		for(j=0; j<32; j++)
704 			for(i=0; i<10; i++)
705 				if(occ[j][i])
706 					tmp[j][i] |= 0x80;
707 	p->write_mem(tmp, sizeof(can));
708 	p->write_dword(seed);
709 	p->write_byte(idle);
710 	p->write_byte(state);
711 	p->write_byte(bloc);
712 	p->write_byte(next);
713 	p->write_byte(next2);
714 	p->write_byte(next3);
715 	p->write_byte(bonus);
716 	for(i=0; i<20; i++)
717 		if(i<bonus) {
718 			p->write_byte(bon[i].x);
719 			p->write_byte(bon[i].color);
720 		}
721 		else {
722 			p->write_byte(0);
723 			p->write_byte(0);
724 		}
725 	for(i=0; i<MAXPLAYERS; i++)
726 		p->write_byte(attacks[i]);
727 	p->write_byte(last_attacker);
728 	p->write_mem(blinded, sizeof(blinded));
729 	for(i=0; i<20; i++)
730 		if(i<bonus)
731 			p->write_byte(bon[i].blind_time);
732 		else
733 			p->write_byte(0);
734 	for(i=0; i<bonus; i++) {
735 		Word tmp=bon[i].hole_pos;
736 		if(bon[i].final)
737 			tmp |= 0x8000;
738 		p->write_word(tmp);
739 	}
740 }
741 
read(Net_buf * p)742 bool Packet_lines::read(Net_buf *p) {
743 	if(!Packet_playerbase::read(p))
744 		return false;
745 	nb=p->read_byte();
746 	if(nb>36)
747 		return false;
748 	nc=p->read_byte();
749 	lx=p->read_byte();
750 	//127 is magical code for new complexity stuff
751 	if((lx<4 || lx>=14) && lx!=127)
752 		return false;
753 	sender=p->read_byte();
754 	if(sender>=MAXPLAYERS && sender!=255)
755 		return false;
756 	attack.type=(Attack_type) p->read_byte();
757 	if(attack.type>=ATTACK_LAST)
758 		return false;
759 	attack.param=p->read_dword();
760 	for(int i=0; i<nb; i++)
761 		hole_pos[i]=p->read_word();
762 	return true;
763 }
764 
write(Net_buf * p)765 void Packet_lines::write(Net_buf *p) {
766 	Packet_playerbase::write(p);
767 	p->write_byte(nb);
768 	p->write_byte(nc);
769 	p->write_byte(lx);
770 	p->write_byte(sender);
771 	p->write_byte(attack.type);
772 	p->write_dword(attack.param);
773 	for(int i=0; i<nb; i++)
774 		p->write_word(hole_pos[i]);
775 }
776 
read(Net_buf * p)777 bool Packet_testping::read(Net_buf *p) {
778 	if(!Packet_tcp::read(p))
779 		return false;
780 	frame=p->read_dword();
781 	return true;
782 }
783 
write(Net_buf * p)784 void Packet_testping::write(Net_buf *p) {
785 	Packet_tcp::write(p);
786 	p->write_dword(frame);
787 }
788 
read(Net_buf * p)789 bool Packet_gone::read(Net_buf *p) {
790 	if(!Packet_playerbase::read(p))
791 		return false;
792 	chat_msg=!p->read_bool();
793 	return true;
794 }
795 
write(Net_buf * p)796 void Packet_gone::write(Net_buf *p) {
797 	Packet_playerbase::write(p);
798 	p->write_bool(!chat_msg);
799 }
800 
read(Net_buf * p)801 bool Packet_endgame::read(Net_buf *p) {
802 	if(!Packet_tcp::read(p))
803 		return false;
804 	auto_end=p->read_bool();
805 	return true;
806 }
807 
write(Net_buf * p)808 void Packet_endgame::write(Net_buf *p) {
809 	Packet_tcp::write(p);
810 	p->write_bool(auto_end);
811 }
812 
read(Net_buf * p)813 bool Packet_rejoin::read(Net_buf *p) {
814 	if(!Packet_playerbase::read(p))
815 		return false;
816 	int repeat = p->read_dword();
817 	if(repeat<-1 || repeat>3)
818 		return false;
819 	smooth = p->read_dword();
820 	if(smooth<0 || smooth>1)
821 		return false;
822 	shadow = p->read_dword();
823 	if(shadow<0 || shadow>1)
824 		return false;
825 	handicap = p->read_dword();
826 	if(handicap<0 || handicap>4)
827 		return false;
828 	h_repeat = p->read_dword();
829 	if(h_repeat<0 || h_repeat>3)
830 		return false;
831 	v_repeat = p->read_dword();
832 	if(v_repeat<0 || v_repeat>3)
833 		return false;
834 	return true;
835 }
836 
write(Net_buf * p)837 void Packet_rejoin::write(Net_buf *p) {
838 	Packet_playerbase::write(p);
839 	if(game->net_version()>=23)
840 		p->write_dword(static_cast<Dword>(-1));
841 	else
842 		p->write_dword(h_repeat);
843 	p->write_dword(smooth);
844 	p->write_dword(shadow);
845 	p->write_dword(handicap);
846 	p->write_dword(h_repeat);
847 	p->write_dword(v_repeat);
848 }
849 
850 
start_byte()851 void Packet_moves::start_byte() {
852 	if(size==255)
853 		fatal_msgbox("Packet_moves too big!");
854 	moves[size]=0;
855 }
856 
set_bit(int v)857 void Packet_moves::set_bit(int v) {
858 	moves[size] |= v;
859 }
860 
write_byte()861 void Packet_moves::write_byte() {
862 	size++;
863 }
864 
read(Net_buf * p)865 bool Packet_moves::read(Net_buf *p) {
866 	if(!Packet_playerbase::read(p))
867 		return false;
868 	size=p->read_byte();
869 	p->read_mem(moves, size);
870 	return true;
871 }
872 
write(Net_buf * p)873 void Packet_moves::write(Net_buf *p) {
874 	Packet_playerbase::write(p);
875 	p->write_byte(size);
876 	p->write_mem(moves, size);
877 }
878 
read(Net_buf * p)879 bool Packet_state::read(Net_buf *p) {
880 	if(!Packet_playerbase::read(p))
881 		return false;
882 	state=p->read_byte();
883 	if(state>Canvas::LAST)
884 		return false;
885 	return true;
886 }
887 
write(Net_buf * p)888 void Packet_state::write(Net_buf *p) {
889 	Packet_playerbase::write(p);
890 	p->write_byte(state);
891 }
892 
write(Net_buf * p)893 void Packet_serverrandom::write(Net_buf *p) {
894 	Packet_tcp::write(p);
895 	p->write_dword(seed);
896 }
897 
read(Net_buf * p)898 bool Packet_serverrandom::read(Net_buf *p) {
899 	if(!Packet_tcp::read(p))
900 		return false;
901 	seed=p->read_dword();
902 	return true;
903 }
904 
read(Net_buf * p)905 bool Packet_serverpotato::read(Net_buf *p) {
906 	if(!Packet_tcp::read(p))
907 		return false;
908 	team=p->read_byte();
909 	if(team>=MAXTEAMS && team!=255)
910 		return false;
911 	potato_lines=p->read_dword();
912 	return true;
913 }
914 
write(Net_buf * p)915 void Packet_serverpotato::write(Net_buf *p) {
916 	Packet_tcp::write(p);
917 	p->write_byte(team);
918 	p->write_dword(potato_lines);
919 }
920 
write(Net_buf * p)921 void Packet_servernameteam::write(Net_buf *p) {
922 	Packet_tcp::write(p);
923 	p->write_byte(team);
924 	p->write_string(name);
925 }
926 
read(Net_buf * p)927 bool Packet_servernameteam::read(Net_buf *p) {
928 	if(!Packet_tcp::read(p))
929 		return false;
930 	team=p->read_byte();
931 	if(team>=MAXTEAMS)
932 		return false;
933 	if(!p->read_string(name, sizeof(name)))
934 		return false;
935 	return true;
936 }
937 
Var()938 Packet_serverlog::Var::Var() {
939 	name[0]=0;
940 	value[0]=0;
941 }
942 
Var(const char * n,const char * val)943 Packet_serverlog::Var::Var(const char* n, const char* val) {
944 	strncpy(name, n, sizeof(name));
945 	name[sizeof(name)-1]=0;
946 	strncpy(value, val, sizeof(value));
947 	value[sizeof(value)-1]=0;
948 }
949 
Var(const char * n,unsigned i)950 Packet_serverlog::Var::Var(const char* n, unsigned i) {
951 	strncpy(name, n, sizeof(name));
952 	name[sizeof(name)-1]=0;
953 	sprintf(value, "%u", i);
954 }
955 
Var(const char * n,int i)956 Packet_serverlog::Var::Var(const char* n, int i) {
957 	strncpy(name, n, sizeof(name));
958 	name[sizeof(name)-1]=0;
959 	sprintf(value, "%i", i);
960 }
961 
Var(const char * n,float f)962 Packet_serverlog::Var::Var(const char* n, float f) {
963 	strncpy(name, n, sizeof(name));
964 	name[sizeof(name)-1]=0;
965 	sprintf(value, "%f", f);
966 }
967 
Packet_serverlog(const char * type)968 Packet_serverlog::Packet_serverlog(const char* type) {
969 	packet_id = P_SERVERLOG;
970 	strncpy(event_type, type, sizeof(event_type));
971 	event_type[sizeof(event_type)-1]=0;
972 }
973 
read(Net_buf * p)974 bool Packet_serverlog::Var::read(Net_buf* p) {
975 	if(!p->read_string(name, sizeof(name)))
976 		return false;
977 	if(!p->read_string(value, sizeof(value)))
978 		return false;
979 	return true;
980 }
981 
write(Net_buf * p)982 void Packet_serverlog::Var::write(Net_buf* p) {
983 	p->write_string(name);
984 	p->write_string(value);
985 }
986 
write(Net_buf * p)987 void Packet_serverlog::write(Net_buf* p) {
988 	Packet_tcp::write(p);
989 	p->write_string(event_type);
990 	p->write_dword(vars.size());
991 	vector<Var>::iterator it;
992 	for (it = vars.begin(); it != vars.end(); ++it)
993 		it->write(p);
994 }
995 
read(Net_buf * p)996 bool Packet_serverlog::read(Net_buf* p) {
997 	if(!Packet_tcp::read(p))
998 		return false;
999 	if(!p->read_string(event_type, sizeof(event_type)))
1000 		return false;
1001 	vars.clear();
1002 	unsigned size = p->read_dword();
1003 	if(size > 100)
1004 		return false;
1005 	for(unsigned i=0; i<size; i++) {
1006 		Var v;
1007 		if(!v.read(p))
1008 			return false;
1009 		vars.push_back(v);
1010 	}
1011 	return true;
1012 }
1013 
add(const Var & var)1014 void Packet_serverlog::add(const Var& var)
1015 {
1016 	vars.push_back(var);
1017 }
1018