1 /* $Id: Player.cpp,v 1.55 2003/11/19 16:49:31 nan Exp $ */
2 
3 // Copyright (C) 2000-2003  ���� �ȹ�(Kanna Yoshihiro)
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 
19 #include "ttinc.h"
20 #include "Player.h"
21 #include "Ball.h"
22 #include "BaseView.h"
23 #include "Control.h"
24 #include "Event.h"
25 #include "PenAttack.h"
26 #include "PenDrive.h"
27 #include "ShakeCut.h"
28 #include "comPenAttack.h"
29 #include "comPenDrive.h"
30 #include "comShakeCut.h"
31 #include "TrainingPenAttack.h"
32 #include "TrainingPenDrive.h"
33 #include "ComTrainingPenAttack.h"
34 #include "ComTrainingPenDrive.h"
35 #include "HitMark.h"
36 #include "PlayGame.h"
37 #include "Network.h"
38 #include "RCFile.h"
39 #ifdef LOGGING
40 #include "Logging.h"
41 #endif
42 
43 extern RCFile *theRC;
44 
45 extern Ball   theBall;
46 
47 extern long mode;
48 
Player()49 Player::Player() {
50   m_side = 1;
51   m_playerType = PLAYER_PROTO;
52 
53   m_x = 0;
54   m_y = -TABLELENGTH/2-0.2;
55   m_z = 1.4;
56   m_vx = m_vy = m_vz = 0.0;
57 
58   m_status = 200;
59   m_swing = 0;
60   m_afterSwing = 0;
61   m_swingType = SWING_NORMAL;
62   m_swingError = SWING_PERFECT;
63   m_targetX = 0.0;
64   m_targetY = TABLELENGTH/16*5;
65 
66   m_eyeX = 0.0;
67   m_eyeY = -1.0;
68   m_eyeZ = 0.2;
69 
70   m_pow = 0;
71   m_spin = 0.0;
72 
73   m_stamina = 80.0;
74 
75   m_statusMax = 200;
76 
77   m_lookAtX = 0.0;
78   m_lookAtY = TABLELENGTH/2*m_side;
79   m_lookAtZ = TABLEHEIGHT;
80 
81   m_View = NULL;
82 
83   m_lastSendX = m_lastSendY = m_lastSendZ = 0.0;
84   m_lastSendVX = m_lastSendVY = m_lastSendVZ = 0.0;
85   m_lastSendCount = 0;
86 }
87 
Player(long side)88 Player::Player( long side ) {
89   m_playerType = PLAYER_PROTO;
90 
91   m_x = 0;
92   m_y = -TABLELENGTH/2-0.2;
93   m_z = 1.4;
94   m_vx = m_vy = m_vz = 0.0;
95 
96   m_status = 200;
97   m_swing = 0;
98   m_afterSwing = 0;
99   m_swingType = SWING_NORMAL;
100   m_swingError = SWING_PERFECT;
101   m_targetX = 0.0;
102   m_targetY = TABLELENGTH/16*5;
103 
104   m_eyeX = 0.0;
105   m_eyeY = -1.0;
106   m_eyeZ = 0.2;
107 
108   m_pow = 0;
109   m_spin = 0.0;
110 
111   m_stamina = 80.0;
112 
113   m_View = NULL;
114 
115   m_side = side;
116   if ( side < 0 ) {
117     m_y = -m_y;
118     m_targetY = -m_targetY;
119     m_eyeY = -m_eyeY;
120   }
121 
122   m_lookAtX = 0.0;
123   m_lookAtY = TABLELENGTH/2*m_side;
124   m_lookAtZ = TABLEHEIGHT;
125 
126   m_lastSendX = m_lastSendY = m_lastSendZ = 0.0;
127   m_lastSendVX = m_lastSendVY = m_lastSendVZ = 0.0;
128   m_lastSendCount = 0;
129 }
130 
Player(long playerType,long side,double x,double y,double z,double vx,double vy,double vz,long status,long swing,long swingType,bool swingSide,long afterSwing,long swingError,double targetX,double targetY,double eyeX,double eyeY,double eyeZ,long pow,double spin,double stamina,long statusMax)131 Player::Player( long playerType, long side, double x, double y, double z,
132 		double vx, double vy, double vz,long status, long swing,
133 		long swingType, bool swingSide, long afterSwing,
134 		long swingError,
135 		double targetX, double targetY, double eyeX, double eyeY,
136 		double eyeZ, long pow, double spin, double stamina,
137 		long statusMax ) {
138   m_side = side;
139   m_playerType = playerType;
140 
141   m_x = x;
142   m_y = y;
143   m_z = z;
144   m_vx = vx;
145   m_vy = vy;
146   m_vz = vz;
147 
148   m_status = status;
149   m_swing = swing;
150   m_afterSwing = afterSwing;
151   m_swingType = swingType;
152   m_swingSide = swingSide;
153   m_swingError = swingError;
154   m_targetX = targetX;
155   m_targetY = targetY;
156 
157   m_eyeX = eyeX;
158   m_eyeY = eyeY;
159   m_eyeZ = eyeZ;
160 
161   m_pow = pow;
162   m_spin = spin;
163 
164   m_stamina = stamina;
165   m_statusMax = statusMax;
166 
167   m_lookAtX = 0.0;
168   m_lookAtY = TABLELENGTH/2*m_side;
169   m_lookAtZ = TABLEHEIGHT;
170 
171   m_View = NULL;
172 
173   m_lastSendX = m_lastSendY = m_lastSendZ = 0.0;
174   m_lastSendVX = m_lastSendVY = m_lastSendVZ = 0.0;
175   m_lastSendCount = 0;
176 }
177 
~Player()178 Player::~Player() {
179   if ( m_View ){
180     BaseView::TheView()->RemoveView( m_View );
181     delete m_View;
182   }
183 }
184 
185 void
operator =(Player & p)186 Player::operator=(Player& p) {
187   m_playerType = p.m_playerType;
188   m_side = p.m_side;
189 
190   m_x = p.m_x;
191   m_y = p.m_y;
192   m_z = p.m_z;
193   m_vx = p.m_vx;
194   m_vy = p.m_vy;
195   m_vz = p.m_vz;
196 
197   m_status = p.m_status;
198   m_swing = p.m_swing;
199   m_swingType = p.m_swingType;
200   m_swingSide = p.m_swingSide;
201   m_afterSwing = p.m_afterSwing;
202   m_swingError = p.m_swingError;
203   m_targetX = p.m_targetX;
204   m_targetY = p.m_targetY;
205 
206   m_eyeX = p.m_eyeX;
207   m_eyeY = p.m_eyeY;
208   m_eyeZ = p.m_eyeZ;
209 
210   m_lookAtX = p.m_lookAtX;
211   m_lookAtY = p.m_lookAtY;
212   m_lookAtZ = p.m_lookAtZ;
213 
214   m_pow = p.m_pow;
215   m_spin = p.m_spin;
216 
217   m_stamina = p.m_stamina;
218 
219   m_dragX = p.m_dragX;
220   m_dragY = p.m_dragY;
221 
222   m_View = NULL;
223 }
224 
225 Player*
Create(long player,long side,long type)226 Player::Create( long player, long side, long type ) {
227   switch (type) {
228   case 0:	// normal
229     switch (player) {
230     case 0:
231       return new PenAttack(side);
232     case 1:
233       return new ShakeCut(side);
234     case 2:
235       return new PenDrive(side);
236     }
237     break;
238   case 1:	// Com
239     switch (player) {
240     case 0:
241       return new ComPenAttack(side);
242     case 1:
243       return new ComShakeCut(side);
244     case 2:
245       return new ComPenDrive(side);
246     }
247     break;
248   case 2:	// Training
249     switch (player) {
250     case 0:
251       return new TrainingPenAttack(side);
252     case 1:
253       return new TrainingPenDrive(side);
254     }
255     break;
256   case 3:	// ComTraining
257     switch (player) {
258     case 0:
259       return new ComTrainingPenAttack(side);
260     case 1:
261       return new ComTrainingPenDrive(side);
262     }
263     break;
264   }
265 
266   printf( _("no player %ld\n"), player );
267   exit(1);
268 }
269 
270 bool
Init()271 Player::Init() {
272   m_View = (PlayerView *)View::CreateView( VIEW_PLAYER );
273 
274   m_View->Init( this );
275 
276   BaseView::TheView()->AddView( m_View );
277 
278   if ( theRC->gmode != GMODE_2D )
279     HitMark::Init();
280 
281   return true;
282 }
283 
284 bool
Reset(Player * p)285 Player::Reset( Player *p ) {
286   *this = *p;
287 
288   return true;
289 }
290 
291 bool
Move(SDL_keysym * KeyHistory,long * MouseXHistory,long * MouseYHistory,unsigned long * MouseBHistory,int Histptr)292 Player::Move( SDL_keysym *KeyHistory, long *MouseXHistory,
293 	      long *MouseYHistory, unsigned long *MouseBHistory,
294 	      int Histptr ) {
295   //static double  lastSendX = 0,  lastSendY = 0,  lastSendZ = 0;
296   //static double lastSendVX = 0, lastSendVY = 0, lastSendVZ = 0;
297   //static long lastSendCount = 0;
298 
299 // swing
300   if ( m_swing > 0 ){
301     if ( m_swing > 30 && m_afterSwing > 0 ) {
302       m_afterSwing--;
303     } else {
304       if ( theBall.GetStatus() == 6 || theBall.GetStatus() == 7 ) {
305 	if ( theBall.GetVZ() < 0 )
306 	  m_swing++;
307       } else {
308 	if ( m_swing == 10 ) {
309 	  if ( theBall.GetStatus() == -1 )
310 	    m_swing = 0;
311 	  else if ( ( m_side > 0 && theBall.GetStatus() == 0) ||
312 		    ( m_side < 0 && theBall.GetStatus() == 2) ) {
313 	    m_swing++;
314 	  }
315 	} else
316 	  m_swing++;
317       }
318     }
319   }
320 
321   // If the ball goes out of sight, look at the ball direction
322   double x, y, z;
323   double tx, ty, tz;
324   double vx1, vy1, vz1;
325   double vxt, vyt, vzt;
326   double vx2, vy2, vz2;
327   double vl;
328   double p, q;
329   double sinP, cosP;
330 
331   tx = 0.0;
332   ty = TABLELENGTH/2*m_side;
333   tz = TABLEHEIGHT;
334 
335   x = m_x + m_eyeX;
336   y = m_y + m_eyeY;
337   z = m_z + m_eyeZ;
338 
339   vx1 = tx-x;
340   vy1 = ty-y;
341   vz1 = tz-z;
342   vl = sqrt(vx1*vx1+vy1*vy1+vz1*vz1);
343   vx1 /= vl;
344   vy1 /= vl;
345   vz1 /= vl;
346 
347   vxt = theBall.GetX()-x;
348   vyt = theBall.GetY()-y;
349   if ( theBall.GetStatus() == 6 || theBall.GetStatus() == 7 )
350     vzt = TABLEHEIGHT + 0.15-z;
351   else
352     vzt = theBall.GetZ()-z;
353   vl = sqrt(vxt*vxt+vyt*vyt+vzt*vzt);
354   vxt /= vl;
355   vyt /= vl;
356   vzt /= vl;
357 
358   if ( (cosP = vx1*vxt+vy1*vyt+vz1*vzt) < cos(3.141592/180.0*15) &&
359        fabs(theBall.GetY()) > fabs(y) ) {
360     sinP = sqrt(1-cosP*cosP);
361     p = cos(3.141592/180.0*15) - sin(3.141592/180.0*15)*cosP/sinP;
362     q = sin(3.141592/180.0*15)/sinP;
363 
364     vx2 = p*vxt+q*vx1;
365     vy2 = p*vyt+q*vy1;
366     vz2 = p*vzt+q*vz1;
367 
368     m_lookAtX = x+vx2;
369     m_lookAtY = y+vy2;
370     m_lookAtZ = z+vz2;
371   } else if ( (cosP = (vy1*vyt+vz1*vzt)/(hypot(vy1, vz1)*hypot(vyt, vzt)))
372 	      < cos(3.141592/180.0*15) && theBall.GetZ() > z &&
373 	      (theBall.GetStatus() == 0 || theBall.GetStatus() == 2) ) {
374     sinP = sqrt(1-cosP*cosP);
375     p = cos(3.141592/180.0*15) - sin(3.141592/180.0*15)*cosP/sinP;
376     q = sin(3.141592/180.0*15)/sinP;
377 
378     vx2 = p*vxt+q*vx1;
379     vy2 = p*vyt+q*vy1;
380     vz2 = p*vzt+q*vz1;
381 
382     m_lookAtX = x+vx2;
383     m_lookAtY = y+vy2;
384     m_lookAtZ = z+vz2;
385   } else {
386     m_lookAtX = tx;
387     m_lookAtY = ty;
388     m_lookAtZ = tz;
389   }
390 
391 // backswing and inpact
392   if ( m_swing == 20 ){
393     HitBall();
394 
395     if ( Control::TheControl()->GetThePlayer() == this &&
396 	 theRC->gmode != GMODE_2D ) {
397       HitMark *hit;
398 
399       hit = new HitMark();
400       hit->Hit( theBall.GetX(), m_y, theBall.GetZ(),
401 		theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
402 		GetSwingError() );
403 
404       BaseView::TheView()->AddView( hit );
405     }
406     m_spin = 0.0;
407   }
408   else if ( m_swing == 50 ){
409     m_swing = 0;
410     m_swingType = SWING_NORMAL;
411   }
412 
413   // Automatically move towards the ball
414   // Only for human.
415   if ( (mode == MODE_SOLOPLAY || mode == MODE_MULTIPLAY ||
416 	mode == MODE_PRACTICE) && KeyHistory &&
417        theRC->gameLevel != LEVEL_TSUBORISH ) {
418     if ( m_swing > 10 && m_swing < 20 ) {
419       Ball *tmpBall;
420 
421       tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
422 			  theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
423 			  theBall.GetSpin(), theBall.GetStatus() );
424 
425       for ( int i = 0 ; i < 20-m_swing ; i++ )
426 	tmpBall->Move();
427 
428       if ( ((tmpBall->GetStatus() == 3 && m_side == 1) ||
429 	    (tmpBall->GetStatus() == 1 && m_side == -1)) ) {
430 	double hitpointX = m_swingSide ? m_x+0.3*m_side : m_x-0.3*m_side;
431 	double xdiff = tmpBall->GetX() - (hitpointX+m_vx*(20-m_swing)*TICK);
432 	double ydiff = tmpBall->GetY() - (m_y+m_vy*(20-m_swing)*TICK);
433 
434 	double vxdiff, vydiff;
435 	vxdiff = xdiff/TICK/(20-m_swing);
436 
437 	if ( vxdiff > 2.0 )
438 	  vxdiff = 2.0;
439 	else if ( vxdiff < -2.0 )
440 	  vxdiff = -2.0;
441 
442 	vxdiff /= theRC->gameLevel+1;
443 
444 	m_vx += vxdiff;
445 
446 	if ( fabs(ydiff) > 0.3 ) {
447 	  vydiff = ydiff/TICK/(20-m_swing);
448 	  if ( vydiff > 2.0 )
449 	    vydiff = 2.0;
450 	  else if ( vydiff < -2.0 )
451 	    vydiff = -2.0;
452 
453 	  vydiff /= theRC->gameLevel+1;
454 
455 	  m_vy += vydiff;
456 	}
457       }
458       delete tmpBall;
459     }
460   }
461 
462 // move player
463   if ( m_x+m_vx*TICK < -AREAXSIZE/2 ){
464     m_x = -AREAXSIZE/2;
465     m_vx = 0.0;
466   }
467   else if ( m_x+m_vx*TICK > AREAXSIZE/2 ){
468     m_x = AREAXSIZE/2;
469     m_vx = 0.0;
470   }
471   else if ( m_x <= -TABLEWIDTH/2 && m_x+m_vx*TICK >= -TABLEWIDTH/2 &&
472 	    m_y > -TABLELENGTH/2+0.5 && m_y < TABLELENGTH/2-0.5 ){
473     m_x = -TABLEWIDTH/2;
474     m_vx = 0.0;
475   }
476   else if ( m_x >= TABLEWIDTH/2 && m_x+m_vx*TICK <= TABLEWIDTH/2 &&
477 	    m_y > -TABLELENGTH/2+0.5 && m_y < TABLELENGTH/2-0.5 ){
478     m_x = TABLEWIDTH/2;
479     m_vx = 0.0;
480   }
481   else
482     m_x += m_vx*TICK;
483 
484   if ( m_y+m_vy*TICK < -AREAYSIZE/2 ) {
485     m_y = -AREAYSIZE/2;
486     m_vy = 0.0;
487   } else if ( m_y+m_vy*TICK > AREAYSIZE/2 ) {
488     m_y = AREAYSIZE/2;
489     m_vy = 0.0;
490   } else if ( m_y <= -TABLELENGTH/2+0.5 && m_y+m_vy*TICK >= -TABLELENGTH/2+0.5
491 	      && m_x > -TABLEWIDTH/2 && m_x < TABLEWIDTH/2 ) {
492     m_y = -TABLELENGTH/2+0.5;
493     m_vy = 0.0;
494   } else if ( m_y >= TABLELENGTH/2-0.5 && m_y+m_vy*TICK <= TABLELENGTH/2-0.5
495 	      && m_x > -TABLEWIDTH/2 && m_x < TABLEWIDTH/2 ) {
496     m_y = TABLELENGTH/2-0.5;
497     m_vy = 0.0;
498   } else
499     m_y += m_vy*TICK;
500 
501 // Go back to the endline before serve
502   if ( Control::TheControl()->IsPlaying() && theBall.GetStatus() == 8 &&
503        ((PlayGame *)Control::TheControl())->GetService() == GetSide() ) {
504     if ( m_side > 0 && m_y > -TABLELENGTH/2 )
505       m_y = -TABLELENGTH/2;
506     else if ( m_side < 0 && m_y < TABLELENGTH/2 )
507       m_y = TABLELENGTH/2;
508   }
509 
510   // Auto backswing
511   if ( m_swing == 0 ) {
512     Ball *tmpBall;
513 
514     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
515 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
516 			theBall.GetSpin(), theBall.GetStatus() );
517 
518     for ( int i = 0 ; i < 30 ; i++ ) {	/* A bit earlier */
519       tmpBall->Move();
520 
521       if ( ((tmpBall->GetStatus() == 3 && m_side == 1) ||
522 	    (tmpBall->GetStatus() == 1 && m_side == -1)) &&
523 	   (m_y-tmpBall->GetY())*m_side < 0.3 &&
524 	   (m_y-tmpBall->GetY())*m_side > -0.05 ){
525 	StartSwing( 3 );
526 	break;
527       }
528     }
529     delete tmpBall;
530   }
531 
532 // calc status
533   if ( hypot( m_vx, m_vy ) > 2.0 )
534     AddStatus( -1 );
535 
536   if ( m_swing > 10 )
537     AddStatus( -1 );
538 
539   if ( theBall.GetStatus() == 8 || theBall.GetStatus() == -1 )
540     AddStatus( 200 );
541 
542   if ( SDL_WM_GrabInput( SDL_GRAB_QUERY ) == SDL_GRAB_ON )
543     KeyCheck( KeyHistory, MouseXHistory, MouseYHistory, MouseBHistory,Histptr );
544 
545   if ( Control::TheControl()->GetThePlayer() == this &&
546        mode == MODE_MULTIPLAY ) {
547     m_lastSendCount++;
548 
549     m_lastSendX += m_lastSendVX*TICK;
550     m_lastSendY += m_lastSendVY*TICK;
551     m_lastSendZ += m_lastSendVZ*TICK;
552 
553     if ( m_lastSendCount >= 100 ||
554 	 fabs(m_lastSendVX-m_vx) >= 0.25 ||
555 	 fabs(m_lastSendVY-m_vy) >= 0.25 || fabs(m_lastSendVZ-m_vz) >= 0.25 ) {
556       Event::TheEvent()->SendPlayer( this );
557     }
558 
559     // theBall goes out of hitting area.
560     if ( ((theBall.GetStatus() == 1 && m_side == -1) ||
561 	  (theBall.GetStatus() == 3 && m_side == 1 ) ) &&
562 	 m_swing <= 10 &&
563 	 (m_y-theBall.GetY())*m_side > 0.3 &&
564 	 (m_y+m_vy*TICK-(theBall.GetY()+theBall.GetVY()*TICK))*m_side > 0.3 )
565       Event::TheEvent()->SendBall();
566   }
567 
568   return true;
569 }
570 
571 bool
KeyCheck(SDL_keysym * KeyHistory,long * MouseXHistory,long * MouseYHistory,unsigned long * MouseBHistory,int Histptr)572 Player::KeyCheck( SDL_keysym *KeyHistory, long *MouseXHistory,
573 		  long *MouseYHistory, unsigned long *MouseBHistory,
574 		  int Histptr ) {
575   long mouse, lastmouse;
576 
577 const char keytable[][5] = {
578   {'\0', '\0', '\0', '\0', '\0'},
579   {'\0', '\0', '\0', '\0', '\0'},
580   {'1', '1', '1', '[', '\0'},
581   {'2', '2', '2', '7', '\0'},
582   {'3', '3', '3', '5', '\0'},
583   {'4', '4', '4', '3', '\0'},
584   {'5', '5', '5', '1', '\0'},
585   {'6', '6', '6', '9', '\0'},
586   {'7', '7', '7', '0', '\0'},
587   {'8', '8', '8', '2', '\0'},
588   {'9', '9', '9', '6', '\0'},
589   {'0', '0', '0', '8', '\0'},
590   {'\0', '\0', '\0', '\0', '\0'},
591   {'\0', '\0', '\0', '\0', '\0'},
592   {'\0', '\0', '\0', '\0', '\0'},
593   {'\0', '\0', '\0', '\0', '\0'},
594   {'q', 'q', 'a', '/', '\0'},
595   {'w', 'w', 'z', ',', '\0'},
596   {'e', 'e', 'e', '.', '\0'},
597   {'r', 'r', 'r', 'p', '\0'},
598   {'t', 't', 't', 'y', '\0'},
599   {'y', 'z', 'y', 'f', '\0'},
600   {'u', 'u', 'u', 'g', '\0'},
601   {'i', 'i', 'i', 'c', '\0'},
602   {'o', 'o', 'o', 'r', '\0'},
603   {'p', 'p', 'p', 'l', '\0'},
604   {'\0', '\0', '\0', '\0', '\0'},
605   {'\0', '\0', '\0', '\0', '\0'},
606   {'\0', '\0', '\0', '\0', '\0'},
607   {'\0', '\0', '\0', '\0', '\0'},
608   {'a', 'a', 'q', 'a', '\0'},
609   {'s', 's', 's', 'o', '\0'},
610   {'d', 'd', 'd', 'e', '\0'},
611   {'f', 'f', 'f', 'u', '\0'},
612   {'g', 'g', 'g', 'i', '\0'},
613   {'h', 'h', 'h', 'd', '\0'},
614   {'j', 'j', 'j', 'h', '\0'},
615   {'k', 'k', 'k', 't', '\0'},
616   {'l', 'l', 'l', 'n', '\0'},
617   {'\0', '\0', '\0', '\0', '\0'},	// {          'm', 's', '\0'},
618   {'\0', '\0', '\0', '\0', '\0'},
619   {'\0', '\0', '\0', '\0', '\0'},
620   {'\0', '\0', '\0', '\0', '\0'},
621   {'\0', '\0', '\0', '\0', '\0'},
622   {'z', 'y', 'w', ';', '\0'},
623   {'x', 'x', 'x', 'q', '\0'},
624   {'c', 'c', 'c', 'j', '\0'},
625   {'v', 'v', 'v', 'k', '\0'},
626   {'b', 'b', 'b', 'x', '\0'},
627   {'n', 'n', 'n', 'b', '\0'},
628   {'m', 'm'     , 'm', '\0', '\0'},
629   {'\0', '\0', '\0', '\0', '\0'},	// {               'w', '\0'},
630   {'\0', '\0', '\0', '\0', '\0'},	// {               'v', '\0'},
631   {'\0', '\0', '\0', '\0', '\0'}	// {               'z', '\0'}
632 };
633 
634 // COM
635   if ( !KeyHistory || !MouseXHistory || !MouseYHistory || !MouseBHistory )
636     return true;
637 
638 // key input
639   // Check keyboard type and modify keycode.
640   int code = -1;
641 
642   if ( KeyHistory[Histptr].scancode < 54 ) {
643     int i = 0;
644     while (keytable[KeyHistory[Histptr].scancode][i]) {
645       if ( keytable[KeyHistory[Histptr].scancode][i]
646 	   == KeyHistory[Histptr].unicode ) {
647 	code = keytable[KeyHistory[Histptr].scancode][0];
648 	break;
649       }
650       i++;
651     }
652   }
653 
654   if ( KeyHistory[Histptr].scancode >= 8 &&
655        KeyHistory[Histptr].scancode < 62 &&
656        code < 0 ) {	// for X11
657     int i = 0;
658     while (keytable[KeyHistory[Histptr].scancode-8][i]) {
659       if ( keytable[KeyHistory[Histptr].scancode-8][i]
660 	   == KeyHistory[Histptr].unicode ) {
661 	code = keytable[KeyHistory[Histptr].scancode-8][0];
662 	break;
663       }
664       i++;
665     }
666   }
667 
668   if ( code < 0 )
669     code = KeyHistory[Histptr].unicode;
670 
671 
672   switch ( code ) {
673   case '1':  case 'q':  case 'a':  case 'z':
674   case '2':  case 'w':  case 's':  case 'x':
675   case '3':
676     m_targetX = -TABLEWIDTH/2*0.9*GetSide();
677     break;
678   case 'e':
679     m_targetX = -TABLEWIDTH/2*0.75*GetSide();
680     break;
681   case 'd':
682     m_targetX = -TABLEWIDTH/2*0.6*GetSide();
683     break;
684   case '4':  case 'c':
685     m_targetX = -TABLEWIDTH/2*0.45*GetSide();
686     break;
687   case 'r':
688     m_targetX = -TABLEWIDTH/2*0.3*GetSide();
689     break;
690   case 'f':
691     m_targetX = -TABLEWIDTH/2*0.15*GetSide();
692     break;
693   case '5':  case 'v':
694     m_targetX = 0;
695     break;
696   case 't':
697     m_targetX = TABLEWIDTH/2*0.15*GetSide();
698     break;
699   case 'g':
700     m_targetX = TABLEWIDTH/2*0.3*GetSide();
701     break;
702   case '6':  case 'b':
703     m_targetX = TABLEWIDTH/2*0.45*GetSide();
704     break;
705   case 'y':
706     m_targetX = TABLEWIDTH/2*0.6*GetSide();
707     break;
708   case 'h':
709     m_targetX = TABLEWIDTH/2*0.75*GetSide();
710     break;
711   case '7':  case 'n':  case 'u':  case 'j':
712   case '8':  case 'm':  case 'i':  case 'k':
713   case '9':  case ',':  case 'o':  case 'l':
714   case '0':  case '.':  case 'p':  case ';':
715     m_targetX = TABLEWIDTH/2*0.9*GetSide();
716     break;
717   }
718 
719   switch ( code ){
720   case '1':  case '2':  case '3':  case '4':  case '5':  case '6':
721   case '7':  case '8':  case '9':  case '0':  case '-':  case '^':
722     m_targetY = TABLELENGTH/12*5*GetSide();
723     break;
724   case 'q':  case 'w':  case 'e':  case 'r':  case 't':  case 'y':
725   case 'u':  case 'i':  case 'o':  case 'p':  case '@':  case '[':
726     m_targetY = TABLELENGTH/12*4*GetSide();
727     break;
728   case 'a':  case 's':  case 'd':  case 'f':  case 'g':  case 'h':
729   case 'j':  case 'k':  case 'l':  case ';':  case ':':  case ']':
730     m_targetY = TABLELENGTH/12*3*GetSide();
731     break;
732   case 'z':  case 'x': case 'c':  case 'v':  case 'b':  case 'n':
733   case 'm':  case ',':  case '.':  case '/':  case '\\':
734     m_targetY = TABLELENGTH/12*2*GetSide();
735     break;
736   }
737 
738 
739   if ( (Histptr == 0 &&
740 	KeyHistory[Histptr].unicode != KeyHistory[MAX_HISTORY-1].unicode) ||
741        (Histptr != 0 &&
742 	KeyHistory[Histptr].unicode != KeyHistory[Histptr-1].unicode) ) {
743     switch ( KeyHistory[Histptr].unicode ) {
744     case 'H':
745       m_eyeX -= 0.05;
746       break;
747     case 'J':
748       m_eyeZ -= 0.05;
749       break;
750     case 'K':
751       m_eyeZ += 0.05;
752       break;
753     case 'L':
754       m_eyeX += 0.05;
755       break;
756     case '<':
757       m_eyeY -= 0.05;
758       break;
759     case '>':
760       m_eyeY += 0.05;
761       break;
762 
763     case 'A':
764       m_lookAtX -= 0.05;
765       break;
766     case 'S':
767       m_lookAtZ -= 0.05;
768       break;
769     case 'D':
770       m_lookAtZ += 0.05;
771       break;
772     case 'F':
773       m_lookAtX += 0.05;
774       break;
775     case 'C':
776       m_lookAtY -= 0.05;
777       break;
778     case 'V':
779       m_lookAtY += 0.05;
780       break;
781 
782     }
783   }
784 
785   // Sorry in Japanese...
786   // ���������®�٤��Ѥ��ʤ��褦�ˤ���. �������뤳�Ȥ�
787   // MultiPlay ���ˤ��Ʊ����Ȥ�䤹���ʤ�.
788   // ������ͳ��, ���������Ϥ��������� Player �Υ���ѥ���
789   // �ޤǤι�ư�����ꤵ��뤿��, ���������ϻ��˾���������
790   // Ʊ�����Ȥ��褦�ˤʤ뤿��Ǥ���. ����ޤǤ�, ����ѥ��Ȼ���
791   // ���������Ƥ����Τ�, 0.1���᤯Ʊ�����Ȥ�뤳�Ȥˤʤ�.
792 
793   // ���ʤߤ�, ��������Υޥ����Υɥ�å��ˤ�äƥܡ���β�ž��
794   // ���椹����, ������ˡ�ϻȤ��ʤ������Τ�ʤ�.
795 
796   if ( SDL_WM_GrabInput( SDL_GRAB_QUERY ) == SDL_GRAB_OFF )
797     return true;
798 
799   if ( m_swing > 10 && m_swing <= 20 ) {
800     long hptr = Histptr-(m_swing-11);
801     if ( hptr < 0 )
802       hptr += MAX_HISTORY;
803 
804     m_dragX = MouseXHistory[Histptr]-MouseXHistory[hptr];
805     m_dragY = MouseYHistory[Histptr]-MouseYHistory[hptr];
806   } else {
807     m_vx = (MouseXHistory[Histptr] - BaseView::GetWinWidth()/2) /
808       (BaseView::GetWinWidth()/40)*GetSide();
809     m_vy = -(MouseYHistory[Histptr] - BaseView::GetWinHeight()/2) /
810       (BaseView::GetWinHeight()/40)*GetSide();
811     m_vx /= 4;
812     m_vy /= 4;
813   }
814 
815   mouse = MouseBHistory[Histptr];
816   if ( Histptr-1 < 0 )
817     lastmouse = MouseBHistory[MAX_HISTORY-1];
818   else
819     lastmouse = MouseBHistory[Histptr-1];
820 
821   if ( (mouse & BUTTON_RIGHT) && !(lastmouse & BUTTON_RIGHT) ){
822     if ( theBall.GetStatus() == 8 &&
823 	 ((PlayGame *)Control::TheControl())->GetService() == GetSide() ) {
824       theBall.Toss( this, 3 );
825       StartSwing( 3 );
826     } else {
827       AddStatus( (m_swing-10)*10 );
828       Swing( 3 );
829     }
830   }
831   else if ( (mouse & BUTTON_MIDDLE) && !(lastmouse & BUTTON_MIDDLE) ){
832     if ( theBall.GetStatus() == 8 &&
833 	 ((PlayGame *)Control::TheControl())->GetService() == GetSide() ) {
834       theBall.Toss( this, 2 );
835       StartSwing( 2 );
836     } else {
837       AddStatus( (m_swing-10)*10 );
838       Swing( 2 );
839     }
840   }
841   else if ( (mouse & BUTTON_LEFT) && !(lastmouse & BUTTON_LEFT) ){
842     if ( theBall.GetStatus() == 8 &&
843 	 ((PlayGame *)Control::TheControl())->GetService() == GetSide() ) {
844       theBall.Toss( this, 1 );
845       StartSwing( 1 );
846     } else {
847       AddStatus( (m_swing-10)*10 );
848       Swing( 1 );
849     }
850   }
851 
852   return true;
853 }
854 
855 bool
AddStatus(long diff)856 Player::AddStatus( long diff ) {
857   if ( diff == 200 ) {	// Not good...
858     m_statusMax = 200;
859     m_status = 200;
860   } else {
861     m_status += diff;
862 
863     if ( m_status > m_statusMax )
864       m_status = m_statusMax;
865 
866     if ( m_status < 1 ) {
867       m_stamina += (m_status-1) / 10.0;
868       m_status = 1;
869     }
870 
871     if ( diff < -3 ) {	// Not good... When status decreased without moving...
872       if ( Control::TheControl()->GetThePlayer() == this ) {
873 	switch (theRC->gameLevel) {
874 	case LEVEL_EASY:
875 	  m_statusMax += diff/4;
876 	  break;
877 	case LEVEL_NORMAL:
878 	  m_statusMax += diff/3;
879 	  break;
880 	case LEVEL_HARD:
881 	  m_statusMax += diff/2;
882 	  break;
883 	case LEVEL_TSUBORISH:
884 	  m_statusMax += diff/2;
885 	  break;
886 	}
887       } else {
888 	m_statusMax += diff/4;	/* �ǵ���֤ǤΥڥʥ�ƥ����껦 */
889       }
890     }
891   }
892 
893   return true;
894 }
895 
896 // Calc the shoulder location
897 // x   --- x
898 // y   --- y
899 // deg --- rotation degree around z axis
900 bool
GetShoulder(double & x,double & y,double & deg)901 Player::GetShoulder( double &x, double &y, double &deg ) {
902   double px, py, bx, by, bvx, bvy;
903   double t, btx;
904 
905   // rotate 180 when the player is in the opposite side
906   if ( m_side < 0 ){
907     px = -m_x;
908     py = -m_y;
909     bx = -theBall.GetX();
910     by = -theBall.GetY();
911     bvx = -theBall.GetVX();
912     bvy = -theBall.GetVY();
913   }
914   else{
915     px = m_x;
916     py = m_y;
917     bx = theBall.GetX();
918     by = theBall.GetY();
919     bvx = theBall.GetVX();
920     bvy = theBall.GetVY();
921   }
922 
923   // target
924   if ( bvy == 0.0 || m_swing == 0 ){
925     btx = bx;
926     t = -1;
927   }
928   else{
929     t = (py - by) / bvy;
930     btx = bx + bvx*t;
931   }
932 
933   // Forehand or backhand?
934   if ( btx - px > 0 ){	// Forehand
935     switch ( m_swingType ){
936     case SWING_NORMAL:
937     case SWING_DRIVE:
938       if ( m_swing < 10 )
939 	deg = -(double)m_swing/10*15-30;
940       else if ( m_swing < 30 )
941 	deg = -45+(double)(m_swing-10)/20*45;
942       else
943 	deg = -(double)(m_swing-30)/20*30;
944       break;
945     case SWING_POKE:
946       if ( m_swing < 10 )
947 	deg = -(double)m_swing/10*10-30;
948       else if ( m_swing < 30 )
949 	deg = -40+(double)(m_swing-10)/20*20;
950       else
951 	deg = -20-(double)(m_swing-30)/20*10;
952       break;
953     case SWING_CUT:
954       if ( m_swing < 10 )
955 	deg = -(double)m_swing/10*60-30;
956       else if ( m_swing < 30 )
957 	deg = -60+(double)(m_swing-10)/20*60;
958       else
959 	deg = -(double)(m_swing-30)/20*30;
960       break;
961     case SWING_SMASH:
962       if ( m_swing < 10 )
963 	deg = -(double)m_swing/10*30-30;
964       else if ( m_swing < 30 )
965 	deg = -60+(double)(m_swing-10)/20*90;
966       else
967 	deg = 30-(double)(m_swing-30)/20*60;
968       break;
969     }
970 
971     if ( m_swing == 0 ){
972       x = y = 0.0;
973       return true;
974     }
975 
976     // The distance from the ideal location for hitting
977     if ( btx - px < 0.6 ){
978       x = btx - px - 0.3;
979       y = 0.0;
980     }
981     else {
982       x = 0.3;
983       y = 0.0;
984     }
985   }
986   else{		// Backhand
987     switch ( m_swingType ){
988     case SWING_NORMAL:
989     case SWING_SMASH:
990     case SWING_DRIVE:
991       if ( m_swing < 10 )
992 	deg = (double)m_swing/10*30-30;
993       else if ( m_swing < 30 )
994 	deg = -(double)(m_swing-10)/20*45;
995       else
996 	deg = -45+(double)(m_swing-30)/20*15;
997       break;
998     case SWING_POKE:
999       if ( m_swing < 30 )
1000 	deg = (double)m_swing/30*60-30;
1001       else
1002 	deg = 30-(double)(m_swing-30)/20*60;
1003       break;
1004     case SWING_CUT:
1005       if ( m_swing < 10 )
1006 	deg = (double)m_swing/10*120-30;
1007       else if ( m_swing < 30 )
1008 	deg = 90-(double)(m_swing-10)/20*90;
1009       else
1010 	deg = -(double)(m_swing-30)/20*30;
1011       break;
1012     }
1013 
1014     if ( m_swing == 0 ){
1015       x = y = 0.0;
1016       return true;
1017     }
1018 
1019     // The distance from the ideal location for hitting
1020     if ( btx - px > -0.6 ){
1021       x = btx - px + 0.3;
1022       y = 0.0;
1023     }
1024     else{
1025       x = -0.3;
1026       y = 0.0;
1027     }
1028   }
1029 
1030   if ( m_swing < 30 ) {
1031     x *= (double)m_swing / 30.0;
1032     y *= (double)m_swing / 30.0;
1033   } else {
1034     x *= (double)(50-m_swing) / 20.0;
1035     y *= (double)(50-m_swing) / 20.0;
1036   }
1037 
1038   return true;
1039 }
1040 
1041 // Calc the elbow location
1042 // degx --- rotation degree around x axis
1043 // degy --- rotation degree around y axis. default=-15
1044 bool
GetElbow(double & degx,double & degy)1045 Player::GetElbow( double &degx, double &degy ) {
1046   if ( ForeOrBack() ){
1047     switch ( m_swingType ){
1048     case SWING_NORMAL:
1049     case SWING_SMASH:
1050       if ( m_swing < 10 )
1051 	degx = 0.0;
1052       else if ( m_swing < 30 )
1053 	degx = (double)(m_swing-10)/20*15;
1054       else
1055 	degx = 15-(double)(m_swing-30)/20*15;
1056       degy = -15.0;
1057       break;
1058     case SWING_POKE:
1059       degx = 0.0;
1060       degy = -15.0;
1061       break;
1062     case SWING_CUT:
1063       if ( m_swing < 10 ){
1064 	degx = 0.0;
1065 	degy = -15-(double)m_swing/10*75;
1066       } else if ( m_swing < 30 ){
1067 	degx = 0.0;
1068 	degy = -90+(double)(m_swing-10)/20*90;
1069       } else {
1070 	degx = 0.0;
1071 	degy = -(double)(m_swing-30)/20*15;
1072       }
1073       break;
1074     case SWING_DRIVE:
1075       if ( m_swing < 10 ){
1076 	degx = -(double)m_swing/10*10;
1077 	degy = -15.0;
1078       } else if ( m_swing < 30 ){
1079 	degx = -10+(double)(m_swing-10)/20*160;
1080 	degy = -15+(double)(m_swing-10)/20*45;
1081       } else{
1082 	degx = 150-(double)(m_swing-30)/20*150;
1083 	degy = 30-(double)(m_swing-30)/20*45;
1084       }
1085       break;
1086     }
1087   }
1088   else{
1089     switch ( m_swingType ){
1090     case SWING_NORMAL:
1091     case SWING_SMASH:
1092     case SWING_DRIVE:
1093       degx = 0.0;
1094       degy = -15.0;
1095       break;
1096     case SWING_POKE:
1097       if ( m_swing < 10 ){
1098 	degx = (double)m_swing/10*15;
1099 	degy = -15.0;
1100       }
1101       else if ( m_swing < 30 ){
1102 	degx = 15 - (double)(m_swing-10)/20*15;
1103 	degy = -15.0;
1104       } else{
1105 	degx = 0.0;
1106 	degy = -15.0;
1107       }
1108       break;
1109     case SWING_CUT:
1110       if ( m_swing < 10 ){
1111 	degx = (double)m_swing/10*10;
1112 	degy = (double)m_swing/10*45;
1113       } else if ( m_swing < 30 ){
1114 	degx = 10-(double)(m_swing-10)/20*10;
1115 	degy = 45-(double)(m_swing-10)/20*45;
1116       } else{
1117 	degx = 0.0;
1118 	degy = -(double)(m_swing-30)/20*15;
1119       }
1120       break;
1121     }
1122   }
1123   return true;
1124 }
1125 
1126 // Calc the hand location
1127 // degx --- rotation degree around x axis
1128 // degy --- rotation degree around y axis
1129 // degz --- rotation degree around z axis
1130 bool
GetHand(double & degx,double & degy,double & degz)1131 Player::GetHand( double &degx, double &degy, double &degz ) {
1132 
1133   if ( ForeOrBack() ){
1134     switch ( m_swingType ){
1135     case SWING_NORMAL:
1136     case SWING_SMASH:
1137       if ( m_swing < 10 ){
1138 	degz = -(double)m_swing/10*90;
1139 	degx = degy = 0.0;
1140       }
1141       else if ( m_swing < 30 ){
1142 	degz = -90+(double)(m_swing-10)/20*120;
1143 	degx = (double)(m_swing-10)/20*75;
1144 	degy = 0.0;
1145       }
1146       else{
1147 	degz = 30-(double)(m_swing-30)/20*30;
1148 	degx = 75-(double)(m_swing-30)/20*75;
1149 	degy = 0.0;
1150       }
1151       break;
1152     case SWING_POKE:
1153       if ( m_swing < 10 ){
1154 	degz = -(double)m_swing/10*90;
1155 	degx = (double)m_swing/10*45;
1156 	degy = (double)m_swing/10*45;
1157       }
1158       else if ( m_swing < 30 ){
1159 	degz = -90+(double)(m_swing-10)/20*150;
1160 	degx = 45 - (double)(m_swing-10)/20*45;
1161 	degy = 45.0;
1162       }
1163       else{
1164 	degz = 60-(double)(m_swing-30)/20*30;
1165 	degx = 0.0;
1166 	degy = 45.0 - (double)(m_swing-30)/20*45;
1167       }
1168       break;
1169     case SWING_CUT:
1170       if ( m_swing < 10 ){
1171 	degz = -(double)m_swing/10*90;
1172 	degx = 0.0;
1173 	degy = (double)m_swing/10*45;
1174       }
1175       else if ( m_swing < 30 ){
1176 	degz = -90+(double)(m_swing-10)/20*150;
1177 	degx = -(double)(m_swing-10)/20*60;
1178 	degy = 45.0;
1179       }
1180       else{
1181 	degz = 60-(double)(m_swing-30)/20*30;
1182 	degx = -60+(double)(m_swing-30)/20*60;
1183 	degy = 45.0 - (double)(m_swing-30)/20*45;
1184       }
1185       break;
1186     case SWING_DRIVE:
1187       if ( m_swing < 10 ){
1188 	degz = -(double)m_swing/10*90;
1189 	degx = -(double)m_swing/10*90;
1190 	degy = 0.0;
1191       }
1192       else if ( m_swing < 30 ){
1193 	degz = -90+(double)(m_swing-10)/20*120;
1194 	degx = -90;
1195 	degy = 0.0;
1196       }
1197       else{
1198 	degz = 30-(double)(m_swing-30)/20*30;
1199 	degx = -90+(double)(m_swing-30)/20*90;
1200 	degy = 0.0;
1201       }
1202       break;
1203     }
1204   }
1205   else{
1206     switch ( m_swingType ){
1207     case SWING_NORMAL:
1208     case SWING_SMASH:
1209     case SWING_DRIVE:
1210       if ( m_swing < 10 ){
1211 	degz = (double)m_swing/10*90;
1212 	degx = degy = 0.0;
1213       }
1214       else if ( m_swing < 30 ){
1215 	degz = 90-(double)(m_swing-10)/20*120;
1216 	degx = (double)(m_swing-10)/20*75;
1217 	degy = 0.0;
1218       }
1219       else{
1220 	degz = -30+(double)(m_swing-30)/20*30;
1221 	degx = 75-(double)(m_swing-30)/20*75;
1222 	degy = 0.0;
1223       }
1224       break;
1225     case SWING_POKE:
1226       if ( m_swing < 10 ){
1227 	degz = (double)m_swing/10*90;
1228 	degx = 0.0;
1229 	degy = -(double)m_swing/10*45;
1230       }
1231       else if ( m_swing < 30 ){
1232 	degz = 90-(double)(m_swing-10)/20*120;
1233 	degx = 0.0;
1234 	degy = -45.0;
1235       }
1236       else{
1237 	degz = -30+(double)(m_swing-30)/20*30;
1238 	degx = 0.0;
1239 	degy = -45.0 + (double)(m_swing-30)/20*45;
1240       }
1241       break;
1242     case SWING_CUT:
1243       if ( m_swing < 10 ){
1244 	degz = (double)m_swing/10*90;
1245 	degx = (double)m_swing/10*30;
1246 	degy = -(double)m_swing/10*45;
1247       }
1248       else if ( m_swing < 30 ){
1249 	degz = 90-(double)(m_swing-10)/20*120;
1250 	degx = 30-(double)(m_swing-10)/20*90;
1251 	degy = -45.0;
1252       }
1253       else{
1254 	degz = -30+(double)(m_swing-30)/20*30;
1255 	degx = -60+(double)(m_swing-30)/20*60;
1256 	degy = -45.0 + (double)(m_swing-30)/20*45;
1257       }
1258       break;
1259     }
1260   }
1261 
1262   return true;
1263 }
1264 
1265 bool
ForeOrBack()1266 Player::ForeOrBack() {
1267   return GetSwingSide();
1268 }
1269 
1270 bool
SwingError()1271 Player::SwingError() {
1272   double diff;
1273 
1274   if ( (m_y-theBall.GetY())*m_side < 0 )
1275     diff = fabs(m_y-theBall.GetY())/2;
1276   else
1277     diff = fabs(m_y-theBall.GetY());
1278 
1279   if ( diff < 0.03 )
1280     m_swingError = SWING_PERFECT;
1281   else if ( diff < 0.1 )
1282     m_swingError = SWING_GREAT;
1283   else if ( diff < 0.2 )
1284     m_swingError = SWING_GOOD;
1285   else
1286     m_swingError = SWING_BOO;
1287 
1288   return true;
1289 }
1290 
1291 bool
Warp(double x,double y,double z,double vx,double vy,double vz)1292 Player::Warp( double x, double y, double z, double vx, double vy, double vz ) {
1293   m_x = x;
1294   m_y = y;
1295   m_z = z;
1296   m_vx = vx;
1297   m_vy = vy;
1298   m_vz = vz;
1299 
1300   return true;
1301 }
1302 
1303 bool
Warp(char * buf)1304 Player::Warp( char *buf ) {
1305   char *b = buf;
1306   b = ReadDouble( b, m_x );
1307   b = ReadDouble( b, m_y );
1308   b = ReadDouble( b, m_z );
1309   b = ReadDouble( b, m_vx );
1310   b = ReadDouble( b, m_vy );
1311   b = ReadDouble( b, m_vz );
1312 
1313   return true;
1314 }
1315 
1316 bool
ExternalSwing(long pow,double spin,long swingType,long swing)1317 Player::ExternalSwing( long pow, double spin, long swingType, long swing ) {
1318   m_swing = swing;
1319   m_pow = pow;
1320   m_spin = spin;
1321   m_swingType =swingType;
1322 
1323   return true;
1324 }
1325 
1326 bool
ExternalSwing(char * buf)1327 Player::ExternalSwing( char *buf ) {
1328   char *b = buf;
1329   long swingSide;
1330   b = ReadLong( b, m_pow );
1331   b = ReadDouble( b, m_spin );
1332   b = ReadLong( b, m_swingType );
1333   b = ReadLong( b, swingSide );
1334   b = ReadLong( b, m_swing );
1335 
1336   m_swingSide = (bool)(swingSide != 0);
1337 
1338   return true;
1339 }
1340 
1341 char *
SendSwing(char * buf)1342 Player::SendSwing( char *buf ) {
1343   long l;
1344   double d;
1345 
1346   l = SwapLong(m_pow);
1347   memcpy( buf, (char *)&l, 4 );
1348   d = SwapDbl(m_spin);
1349   memcpy( &(buf[4]), (char *)&d, 8 );
1350   l = SwapLong(m_swingType);
1351   memcpy( &(buf[12]), (char *)&l, 4 );
1352   l = SwapLong((long)m_swingSide);
1353   memcpy( &(buf[16]), (char *)&l, 4 );
1354   l = SwapLong(m_swing);
1355   memcpy( &(buf[20]), (char *)&l, 4 );
1356 
1357 #ifdef LOGGING
1358   Logging::GetLogging()->LogSendPSMessage( this );
1359 #endif
1360 
1361   return buf;
1362 }
1363 
1364 char *
SendLocation(char * buf)1365 Player::SendLocation( char *buf ) {
1366   double d;
1367 
1368   d = SwapDbl(m_x);
1369   memcpy( buf, (char *)&d, 8 );
1370   d = SwapDbl(m_y);
1371   memcpy( &(buf[8]), (char *)&d, 8 );
1372   d = SwapDbl(m_z);
1373   memcpy( &(buf[16]), (char *)&d, 8 );
1374   d = SwapDbl(m_vx);
1375   memcpy( &(buf[24]), (char *)&d, 8 );
1376   d = SwapDbl(m_vy);
1377   memcpy( &(buf[32]), (char *)&d, 8 );
1378   d = SwapDbl(m_vz);
1379   memcpy( &(buf[40]), (char *)&d, 8 );
1380 
1381   UpdateLastSend();
1382 
1383 #ifdef LOGGING
1384   Logging::GetLogging()->LogSendPVMessage( this );
1385 #endif
1386 
1387   return buf;
1388 }
1389 
1390 bool
SendAll(int sd)1391 Player::SendAll( int sd ) {
1392   SendLong( sd, m_playerType );
1393   SendLong( sd, m_side );
1394 
1395   SendDouble( sd, m_x );
1396   SendDouble( sd, m_y );
1397   SendDouble( sd, m_z );
1398   SendDouble( sd, m_vx );
1399   SendDouble( sd, m_vy );
1400   SendDouble( sd, m_vz );
1401 
1402   SendLong( sd, m_status );
1403   SendLong( sd, m_swing );
1404   SendLong( sd, m_swingType );
1405   SendLong( sd, (long)m_swingSide );
1406   SendLong( sd, m_afterSwing );
1407   SendLong( sd, m_swingError );
1408 
1409   SendDouble( sd, m_targetX );
1410   SendDouble( sd, m_targetY );
1411   SendDouble( sd, m_eyeX );
1412   SendDouble( sd, m_eyeY );
1413   SendDouble( sd, m_eyeZ );
1414 
1415   SendLong( sd, m_pow );
1416 
1417   SendDouble( sd, m_spin );
1418   SendDouble( sd, m_stamina );
1419 
1420   SendLong( sd, m_statusMax );
1421 
1422   return true;
1423 }
1424 
1425 // Must be overridden
1426 bool
GetModifiedTarget(double & targetX,double & targetY)1427 Player::GetModifiedTarget( double &targetX, double &targetY ) {
1428   return false;
1429 }
1430 
1431 void
CalcLevel(Ball * ball,double & diff,double & level,double & maxVy)1432 Player::CalcLevel( Ball *ball, double &diff, double &level, double &maxVy ) {
1433 }
1434 
1435 bool
Swing(long power)1436 Player::Swing( long power ) {
1437   return false;
1438 }
1439 
1440 bool
StartSwing(long power)1441 Player::StartSwing( long power ) {
1442   return false;
1443 }
1444 
1445 bool
HitBall()1446 Player::HitBall() {
1447   return false;
1448 }
1449 
1450 void
UpdateLastSend()1451 Player::UpdateLastSend() {
1452   m_lastSendCount = 0;
1453 
1454   m_lastSendX = m_x;
1455   m_lastSendY = m_y;
1456   m_lastSendZ = m_z;
1457   m_lastSendVX = m_vx;
1458   m_lastSendVY = m_vy;
1459   m_lastSendVZ = m_vz;
1460 }
1461 
1462 void
AddError(double & vx,double & vy,double & vz)1463 Player::AddError( double &vx, double &vy, double &vz ) {
1464   double v;
1465   double n1x, n1y, n1z, n2x, n2y, n2z;
1466   double radDiff, radRand;
1467 
1468 #if 0
1469   radDiff = hypot( fabs(fabs(m_x-theBall.GetX())-0.3)/0.3,
1470 		   fabs(m_y-theBall.GetY())/0.3 );
1471   radDiff = sqrt( radDiff );
1472   radDiff *= (double)(200-m_status)/200*3.141592/12;
1473 #else
1474   radDiff = (double)(200-m_status)/200*3.141592/12;
1475 #endif
1476 
1477   v = sqrt(vx*vx+vy*vy+vz*vz);
1478   n1x = vy/hypot(vx, vy) * v*tan(radDiff);
1479   n1y = -vx/hypot(vx, vy) * v*tan(radDiff);
1480   n1z = 0;
1481   n2x = vx*vz/(v*hypot(vx, vy)) * v*tan(radDiff);
1482   n2y = vy*vz/(v*hypot(vx, vy)) * v*tan(radDiff);
1483   n2z = (vx*vx+vy*vy)/(v*hypot(vx, vy)) * v*tan(radDiff);
1484 
1485   // Hit the ball too fast --- net miss
1486   // Hit the ball too slow --- over miss
1487   if ( (m_y-theBall.GetY())*m_side < 0 )
1488     radRand = (RAND(180)+180)*3.141592/180.0;
1489   else
1490     radRand = RAND(180)*3.141592/180.0;
1491 
1492   vx += n1x*cos(radRand)+n2x*sin(radRand);
1493   vy += n1y*cos(radRand)+n2y*sin(radRand);
1494   vz += n1z*cos(radRand)+n2z*sin(radRand);
1495 }
1496 
1497 // If status point is less than this value, player will miss.
1498 long
StatusBorder()1499 Player::StatusBorder() {
1500   double nearEdge = TABLEWIDTH/2-fabs(m_targetX);
1501   if ( TABLELENGTH/4-fabs(fabs(m_targetY)-TABLELENGTH/4) < nearEdge )
1502     nearEdge = TABLELENGTH/4-fabs(fabs(m_targetY)-TABLELENGTH/4);
1503 
1504   return 50+(TABLELENGTH/4-nearEdge)*40;
1505 
1506 }
1507