1 /* $Id: ShakeCut.cpp,v 1.22 2003/07/25 17:28:27 nan Exp $ */
2 
3 // Copyright (C) 2000-2003  $B?@Fn(B $B5H9((B(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 "ShakeCut.h"
21 #include "Ball.h"
22 #include "Event.h"
23 #include "Network.h"
24 #include "Control.h"
25 #include "RCFile.h"
26 
27 extern RCFile *theRC;
28 
29 extern Ball   theBall;
30 
31 extern long mode;
32 
ShakeCut()33 ShakeCut::ShakeCut() {
34   m_playerType = PLAYER_SHAKECUT;
35 }
36 
ShakeCut(long side)37 ShakeCut::ShakeCut(long side) : Player(side) {
38   m_playerType = PLAYER_SHAKECUT;
39 }
40 
ShakeCut(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)41 ShakeCut::ShakeCut( long playerType, long side, double x, double y, double z,
42 		    double vx, double vy, double vz,long status, long swing,
43 		    long swingType, bool swingSide, long afterSwing,
44 		    long swingError,
45 		    double targetX, double targetY, double eyeX, double eyeY,
46 		    double eyeZ, long pow, double spin, double stamina,
47 		    long statusMax ) :
48   Player( playerType, side, x, y, z, vx, vy, vz, status, swing, swingType,
49 	  swingSide, afterSwing, swingError, targetX, targetY,
50 	  eyeX, eyeY, eyeZ, pow, spin, stamina, statusMax ) {
51 }
52 
~ShakeCut()53 ShakeCut::~ShakeCut() {
54 }
55 
56 bool
AddStatus(long diff)57 ShakeCut::AddStatus( long diff ) {
58   // Add something in the future
59   return Player::AddStatus( diff );
60 }
61 
62 bool
Move(SDL_keysym * KeyHistory,long * MouseXHistory,long * MouseYHistory,unsigned long * MouseBHistory,int Histptr)63 ShakeCut::Move( SDL_keysym *KeyHistory, long *MouseXHistory,
64 	      long *MouseYHistory, unsigned long *MouseBHistory,
65 	      int Histptr ) {
66   double prevVx = m_vx;
67   double prevVy = m_vy;
68 
69   Player::Move( KeyHistory, MouseXHistory, MouseYHistory,MouseBHistory,
70 		Histptr );
71 
72 // Calc status
73   if ( hypot( m_vx, m_vy ) < 2.0 )
74     AddStatus( 1 );
75   if ( hypot( m_vx-prevVx, m_vy-prevVy ) > 0.8-theRC->gameLevel*0.1 ) {
76     AddStatus(-1);
77   }
78 
79   return true;
80 }
81 
82 bool
Swing(long spin)83 ShakeCut::Swing( long spin ) {
84   Ball *tmpBall;
85 
86   if ( theBall.GetStatus() == 6 || theBall.GetStatus() == 7 )
87     return false;
88 
89   if ( m_swing > 10 && m_swing < 30 )
90     return false;
91 
92   if ( m_swing >= 30 )
93     AddStatus( -(50-m_swing)*2 );
94 
95   m_swing = 11;
96   m_pow = 8;
97 
98   // Decide SwingType by the hit point and spin, etc.
99   // Calc the ball location of 0.1 second later
100   tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
101 		      theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
102 		      theBall.GetSpin(), theBall.GetStatus() );
103 
104   for ( int i = 0 ; i < 10 ; i++ )
105     tmpBall->Move();
106 
107   if ( spin < 3 )
108     m_swingSide = false;
109   else
110     m_swingSide = true;
111 
112   SwingType( tmpBall, spin );
113 
114   delete tmpBall;
115 
116   if ( Control::TheControl()->GetThePlayer() == this &&
117        mode == MODE_MULTIPLAY )
118     ::SendSwing( this );
119 
120   return true;
121 }
122 
123 bool
StartSwing(long spin)124 ShakeCut::StartSwing( long spin ) {
125   Ball *tmpBall;
126 
127   if ( m_swing > 10 )
128     return false;
129 
130   if ( m_swing == 0 ){
131     m_swing = 1;
132     m_pow = 0;
133 
134     // Decide SwingType by the hit point and spin, etc.
135     // Calc the ball location of 0.2 second later
136     tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
137 			theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
138 			theBall.GetSpin(), theBall.GetStatus() );
139 
140     for ( int i = 0 ; i < 20 ; i++ )
141       tmpBall->Move();
142 
143     if ( (theBall.GetStatus() == 6 && m_side == 1) ||
144 	(theBall.GetStatus() == 7 && m_side == -1) ){	// Serve
145       switch ( spin-1 ) {
146       case 0:
147 	m_spin = 0.2;	// straight
148 	m_swingType = SWING_NORMAL;
149 	break;
150       case 1:
151 	m_spin = -0.1;	// knuckle
152 	m_swingType = SWING_POKE;
153 	break;
154       case 2:
155 	m_spin = -1.0;
156 	m_swingType = SWING_POKE;
157 	break;
158       }
159 
160       m_swingSide = true;
161 
162       if ( Control::TheControl()->GetThePlayer() == this &&
163 	   mode == MODE_MULTIPLAY )
164 	::SendSwing( this );
165     } else {
166       if ( (m_x-tmpBall->GetX())*m_side > 0 )
167 	m_swingSide = false;
168       else
169 	m_swingSide = true;
170 
171       SwingType( tmpBall, spin );
172     }
173 
174     delete tmpBall;
175   }
176 
177   return true;
178 }
179 
180 bool
HitBall()181 ShakeCut::HitBall() {
182   double vx, vy, vz;
183   double diff;
184   double level;
185 
186   // Serve
187   if ( ( (m_side == 1 && theBall.GetStatus() == 6) ||
188          (m_side ==-1 && theBall.GetStatus() == 7) ) &&
189        fabs( m_x-theBall.GetX() ) < 0.6 && fabs( m_y-theBall.GetY() ) < 0.3 ){
190     AddStatus( (long)-fabs(fabs(m_x-theBall.GetX())-0.3)*100 );
191     diff = fabs( m_y-theBall.GetY() )*0.3;
192 
193     SwingError();
194 
195     if ( fabs(m_targetY) < TABLELENGTH/16*2 )
196       level = 0.95 - diff*1.0;
197     else if ( fabs(m_targetY) < TABLELENGTH/16*4 )
198       level = 0.93-diff*1.5;
199     else if ( fabs(m_targetY) < TABLELENGTH/16*6 )
200       level = 0.90-diff*2.0;
201     else
202       level = 0.90-diff*2.0;
203 
204     theBall.TargetToVS( m_targetX, m_targetY, level, m_spin, vx, vy, vz );
205 
206     theBall.Hit( vx, vy, vz, m_spin, this );
207   } else if ( ((m_side == 1 && theBall.GetStatus() == 3) ||
208 	       (m_side ==-1 && theBall.GetStatus() == 1)) &&
209 	      fabs(m_x-theBall.GetX()) < 0.6 &&
210 	      ((GetSwingSide() && (m_x-theBall.GetX())*m_side < 0 ) ||
211 	       (!GetSwingSide() && (m_x-theBall.GetX())*m_side > 0 )) &&
212 	      (m_y-theBall.GetY())*m_side < 0.3 &&
213 	      (m_y-theBall.GetY())*m_side > -0.6 ) {
214 
215     //AddStatus( -fabs(fabs(m_x-theBall.GetX())-0.3)*100 );
216     double targetX, targetY;
217 
218     GetModifiedTarget( targetX, targetY );
219 
220     double maxVy;
221     CalcLevel( &theBall, diff, level, maxVy );
222 
223     theBall.TargetToV( targetX, targetY, level, m_spin, vx, vy, vz,
224 		       0.1, maxVy );
225 
226     if ((m_status-StatusBorder())*3/2000.0 <
227 	fabs(fabs(m_x-theBall.GetX())-0.3))
228       AddError( vx, vy, vz );
229 
230     // Reduce status
231     m_afterSwing = (long)
232       (hypot( theBall.GetVX()*0.8-vx, theBall.GetVY()*0.8+vy )
233        * (1.0+diff*10.0) + fabs(m_spin)*3.0 + fabs(theBall.GetSpin())*2.0);
234 
235     if ( m_swingType == SWING_POKE || m_swingType == SWING_CUT )
236       AddStatus( -m_afterSwing );
237     else if ( ForeOrBack() )
238       AddStatus( -m_afterSwing*2 );
239     else
240       AddStatus( -m_afterSwing*3 );
241 
242     if ( m_status == 1 )
243       m_afterSwing *= 3;
244 
245     theBall.Hit( vx, vy, vz, m_spin, this );
246   } else {
247     m_swingError = SWING_MISS;
248     if ( Control::TheControl()->GetThePlayer() == this &&
249 	 mode == MODE_MULTIPLAY )
250       Event::TheEvent()->SendBall();
251   }
252 
253   return true;
254 }
255 
256 bool
SwingType(Ball * ball,long spin)257 ShakeCut::SwingType( Ball *ball, long spin ) {
258   if ( (ball->GetStatus() == 3 && m_side == 1) ||
259        (ball->GetStatus() == 1 && m_side == -1) ) {
260     if ( fabs(ball->GetX()) < TABLEWIDTH/2 &&
261 	 fabs(ball->GetY()) < TABLELENGTH/2 &&
262 	 (ball->GetZ()-TABLEHEIGHT-NETHEIGHT)/fabs(ball->GetY()) <
263 	 NETHEIGHT/(TABLELENGTH/2) ){	// low ball on the table
264       if ( ball->GetSpin() <= -0.2 ) {
265 	m_swingType = SWING_POKE;
266 	//m_spin = -spin*0.2-0.4;
267 	m_spin = -0.8;
268       } else {
269 	m_swingType = SWING_NORMAL;
270 	m_spin = 0.2;
271       }
272     } else if ( fabs(ball->GetY()) > TABLELENGTH/2 &&
273 		ball->GetZ() < TABLEHEIGHT+NETHEIGHT*2 ){ // middle height
274       if ( ball->GetVZ() < 0 ) {
275 	m_swingType = SWING_CUT;
276 	//m_spin = -spin*0.3-0.4;
277 	m_spin = -1.0;
278       } else {
279 	m_swingType = SWING_DRIVE;
280 	//m_spin = spin*0.2+0.2;
281 	m_spin = 0.6;
282       }
283     } else {	// high ball
284       m_swingType = SWING_SMASH;
285       m_spin = 0.2;
286     }
287   }
288   else{
289     m_swingType = SWING_NORMAL;
290     m_spin = 0.2;
291   }
292 
293   return true;
294 }
295 
296 // Target will be modified by the spin
297 // (now invalid)
298 #if 0
299 bool
300 ShakeCut::GetModifiedTarget( double &targetX, double &targetY ) {
301   targetX = m_targetX;
302   targetY = m_targetY + theBall.GetSpin()*m_side*0.2;
303 
304   return true;
305 }
306 #else
307 bool
GetModifiedTarget(double & targetX,double & targetY)308 ShakeCut::GetModifiedTarget( double &targetX, double &targetY ) {
309   targetX = m_targetX;
310   targetY = m_targetY;
311 
312   return true;
313 }
314 #endif
315 
316 void
CalcLevel(Ball * ball,double & diff,double & level,double & maxVy)317 ShakeCut::CalcLevel( Ball *ball, double &diff, double &level, double &maxVy ) {
318   double targetX, targetY;
319 
320   GetModifiedTarget( targetX, targetY );
321 
322   if ( (m_y-ball->GetY())*m_side < 0 )
323     diff = fabs( m_y-ball->GetY() )*0.1;
324   else
325     diff = fabs( m_y-ball->GetY() )*0.15;
326 
327   diff *= fabs(ball->GetSpin())+1;
328 
329   SwingError();
330 
331   if ( m_swingType == SWING_CUT || m_swingType == SWING_POKE )
332     level = 1 - fabs(targetY)/(TABLELENGTH/16)/40/2 -
333       diff*fabs(targetY)/(TABLELENGTH/16)*0.5;
334   else
335     level = 1 - fabs(targetY)/(TABLELENGTH/16)/40 -
336       diff*fabs(targetY)/(TABLELENGTH/16)*1.2;
337 
338   level *= (double)m_pow/20.0 + 0.5;
339 
340   if ( ForeOrBack() ) {
341     switch ( m_swingType ) {
342     case SWING_CUT:
343     case SWING_POKE:
344       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 8.0 -
345 	(fabs(m_spin)+fabs(ball->GetSpin())/3)*2.0;
346       break;
347     case SWING_NORMAL:
348     case SWING_DRIVE:
349       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 10.0 -
350 	(fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
351       break;
352     case SWING_SMASH:
353       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 15.0 -
354 	(fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
355       break;
356     default:
357       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 10.0 -
358 	(fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
359     }
360   } else {
361     switch ( m_swingType ) {
362     case SWING_CUT:
363     case SWING_POKE:
364       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 7.0 -
365 	(fabs(m_spin)+fabs(ball->GetSpin())/3)*3.0;
366       break;
367     case SWING_NORMAL:
368     case SWING_DRIVE:
369       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 8.0 -
370 	(fabs(m_spin)+fabs(ball->GetSpin()))*5.0;
371       break;
372     case SWING_SMASH:
373       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 12.0 -
374 	(fabs(m_spin)+fabs(ball->GetSpin()))*5.0;
375       break;
376     default:
377       maxVy = hypot(ball->GetVX(), ball->GetVY())*0.4 + 8.0 -
378 	(fabs(m_spin)+fabs(ball->GetSpin()))*5.0;
379     }
380   }
381 
382   if ( level > 1.0 )
383     level = 1.0;
384 }
385