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