1 /* $Id: comShakeCut.cpp,v 1.19 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 "comShakeCut.h"
21 #include "Control.h"
22 #include "Ball.h"
23 #include "Player.h"
24 #include "PlayGame.h"
25 #include "RCFile.h"
26
27 extern RCFile *theRC;
28
29 extern Ball theBall;
30
ComShakeCut()31 ComShakeCut::ComShakeCut() : ShakeCut(), ComPlayer() {
32 }
33
ComShakeCut(long side)34 ComShakeCut::ComShakeCut(long side) : ShakeCut(side), ComPlayer() {
35 }
36
ComShakeCut(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)37 ComShakeCut::ComShakeCut( long playerType, long side,
38 double x, double y, double z,
39 double vx, double vy, double vz,
40 long status, long swing,
41 long swingType, bool swingSide,
42 long afterSwing, long swingError,
43 double targetX, double targetY,
44 double eyeX, double eyeY, double eyeZ,
45 long pow, double spin, double stamina,
46 long statusMax ) :
47 ShakeCut( playerType, side, x, y, z, vx, vy, vz, status, swing, swingType,
48 swingSide, afterSwing, swingError, targetX, targetY,
49 eyeX, eyeY, eyeZ, pow, spin, stamina, statusMax ), ComPlayer() {
50 }
51
~ComShakeCut()52 ComShakeCut::~ComShakeCut() {
53 }
54
55 bool
Move(SDL_keysym * KeyHistory,long * MouseXHistory,long * MouseYHistory,unsigned long * MouseBHistory,int Histptr)56 ComShakeCut::Move( SDL_keysym *KeyHistory, long *MouseXHistory,
57 long *MouseYHistory, unsigned long *MouseBHistory,
58 int Histptr ) {
59 double prevVx = m_vx;
60 double prevVy = m_vy;
61
62 ShakeCut::Move( KeyHistory, MouseXHistory, MouseYHistory, MouseBHistory,
63 Histptr );
64 Think();
65
66 // Calc status
67 if ( hypot( m_vx-prevVx, m_vy-prevVy ) > 0.8-theRC->gameLevel*0.1 ) {
68 AddStatus(-1);
69 }
70
71 return true;
72 }
73
74 bool
Think()75 ComShakeCut::Think() {
76 double hitT; // estimation time until ball reaches _hitX, _hitY
77 double mx;
78
79 // If the ball status changes, change _hitX, _hitY
80 if ( _prevBallstatus != theBall.GetStatus() && theBall.GetStatus() >= 0 ){
81 Hitarea( _hitX, _hitY );
82
83 _prevBallstatus = theBall.GetStatus();
84 }
85
86 if ( theBall.GetVY() != 0.0 )
87 hitT = (_hitY - theBall.GetY())/theBall.GetVY()-TICK;
88 else
89 hitT = -1.0;
90
91 if ( fabs( _hitX-(m_x+m_side*0.3) ) < fabs( _hitX-(m_x-m_side*0.3) ) ||
92 theBall.GetStatus() == 8 || _hitX*m_side > 0 )
93 mx = m_x+m_side*0.3;
94 else
95 mx = m_x-m_side*0.3;
96
97 if ( m_swing > 10 && m_swing <= 20 ) {
98 } else {
99 if ( hitT > 0.0 ) {
100 double vx = (_hitX-mx)/hitT;
101 if ( vx > m_vx+0.1 )
102 m_vx += 0.1;
103 else if ( vx < m_vx-0.1 )
104 m_vx -= 0.1;
105 else
106 m_vx = vx;
107 } else {
108 if ( m_vx*fabs(m_vx*0.1)/2 < _hitX - mx )
109 m_vx += 0.1;
110 else
111 m_vx -= 0.1;
112 }
113 }
114
115 if ( m_swing > 10 && m_swing <= 20 ) {
116 } else {
117 if ( hitT > 0.0 ) {
118 double vy = (_hitY-m_y)/hitT;
119 if ( vy > m_vy+0.1 )
120 m_vy += 0.1;
121 else if ( vy < m_vy-0.1 )
122 m_vy -= 0.1;
123 else
124 m_vy = vy;
125 } else {
126 if ( m_vy*fabs(m_vy*0.1)/2 < _hitY - m_y )
127 m_vy += 0.1;
128 else
129 m_vy -= 0.1;
130 }
131 }
132
133 if ( m_swing == 19 ) {
134 Player *opponent;
135 if ( m_side == -1 )
136 opponent = Control::TheControl()->GetThePlayer();
137 else
138 opponent = Control::TheControl()->GetComPlayer();
139
140 SetTargetX( opponent );
141 }
142
143 if ( (theBall.GetStatus() == 0 && m_side == -1) ||
144 (theBall.GetStatus() == 1 && m_side == -1) ||
145 (theBall.GetStatus() == 2 && m_side == 1) ||
146 (theBall.GetStatus() == 3 && m_side == 1) ||
147 (theBall.GetStatus() == 4 && m_side == -1) ||
148 (theBall.GetStatus() == 5 && m_side == 1) ) {
149 if ( m_vx > 5.0 )
150 m_vx = 5.0;
151 else if ( m_vx < -5.0 )
152 m_vx = -5.0;
153 if ( m_vy > 5.0 )
154 m_vy = 5.0;
155 else if ( m_vy < -5.0 )
156 m_vy = -5.0;
157 } else {
158 if ( hypot( m_vx, m_vy ) >= 2.0 ) {
159 double v = hypot( m_vx, m_vy );
160 m_vx = m_vx/v*1.99;
161 m_vy = m_vy/v*1.99;
162 }
163 }
164
165 // Toss
166 if ( theBall.GetStatus() == 8 &&
167 ( (Control::TheControl()->IsPlaying() &&
168 ((PlayGame *)Control::TheControl())->GetService() == GetSide()) ||
169 (!Control::TheControl()->IsPlaying() && GetSide() == 1) ) &&
170 fabs(m_vx) < 0.1 && fabs(m_vy) < 0.1 &&
171 fabs(m_x+m_side*0.3-_hitX) < 0.1 && fabs(m_y-_hitY) < 0.1 &&
172 m_swing == 0 ) {
173 theBall.Toss( this, 2 );
174 StartSwing( 3 );
175 m_targetY = TABLELENGTH/6*m_side;
176
177 return true;
178 }
179
180 if ( fabs( theBall.GetY()+theBall.GetVY()*0.1 - _hitY ) < 0.2 /*&&
181 m_swing == 0*/ ){
182 // Calc the ball location of 0.1 second later.
183 // This part seems to be the same as Swing(). Consider again.
184 Ball *tmpBall;
185 double tmpBallX, tmpBallY, tmpBallZ;
186 double tmpX, tmpY;
187
188 tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
189 theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
190 theBall.GetSpin(), theBall.GetStatus() );
191
192 for ( int i = 0 ; i < 9 ; i++ )
193 tmpBall->Move();
194 tmpX = m_x+m_vx*0.08;
195 tmpY = m_y+m_vy*0.08;
196
197 if ( ((tmpBall->GetStatus() == 3 && m_side == 1) ||
198 (tmpBall->GetStatus() == 1 && m_side == -1)) &&
199 (tmpY-tmpBall->GetY())*m_side < 0.3 &&
200 (tmpY-tmpBall->GetY())*m_side > -0.6 &&
201 m_swing <= 10 ) {
202 tmpBallX = tmpBall->GetX();
203 tmpBallY = tmpBall->GetY();
204 tmpBallZ = tmpBall->GetZ();
205
206 // If the ball location becomes better at 1/100 second later, wait.
207 tmpBall->Move();
208 if ( fabs(tmpY+m_vy*0.01-tmpBall->GetY()) < fabs(tmpY-tmpBallY) &&
209 fabs(tmpY-tmpBallY) > LEVELMARGIN ) {
210 delete tmpBall;
211 return true;
212 }
213
214 _hitX = tmpBallX;
215 _hitY = tmpBallY;
216
217 if ( (tmpBallZ-TABLEHEIGHT)/fabs(m_y - m_targetY) < 0.0 )
218 m_targetY = TABLELENGTH/4*m_side;
219 else if ( (tmpBallZ-TABLEHEIGHT)/fabs(m_y-m_targetY) < 0.1 )
220 m_targetY = TABLELENGTH/3*m_side;
221 else
222 m_targetY = TABLELENGTH/16*6*m_side;
223
224 if ( (m_x-tmpBallX)*m_side < 0 )
225 Swing(3);
226 else
227 Swing(1);
228
229 m_pow = 7 + theRC->gameLevel;
230 }
231 delete tmpBall;
232 }
233
234 return true;
235 }
236
237 // Calc hit point
238 // (1) If the ball haven't bound, calc bound point
239 // (2) Calc hit point from current ball location or bound location
240 bool
Hitarea(double & hitX,double & hitY)241 ComShakeCut::Hitarea( double &hitX, double &hitY ) {
242 Ball *tmpBall;
243 double max = -1.0; /* highest point of the ball */
244 double bestX = AREAXSIZE, bestY = AREAYSIZE;
245
246 if ( (theBall.GetStatus() == 3 && m_side == 1) ||
247 (theBall.GetStatus() == 2 && m_side == 1) ||
248 (theBall.GetStatus() == 0 && m_side == -1) ||
249 (theBall.GetStatus() == 1 && m_side == -1) ||
250 (theBall.GetStatus() == 4 && m_side == -1) ||
251 (theBall.GetStatus() == 5 && m_side == 1) ) {
252 tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
253 theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
254 theBall.GetSpin(), theBall.GetStatus() );
255
256 while ( tmpBall->GetStatus() != -1 ) {
257 if ( (tmpBall->GetStatus() == 3 && m_side == 1) ||
258 (tmpBall->GetStatus() == 1 && m_side == -1) ) {
259 if ( tmpBall->GetZ() > max ) {
260 max = tmpBall->GetZ();
261 if ( tmpBall->GetY() < TABLELENGTH/2 ) {
262 bestX = tmpBall->GetX();
263 bestY = tmpBall->GetY();
264 }
265 }
266 if ( tmpBall->GetVZ() < 0.0 && tmpBall->GetY() > TABLELENGTH/2 &&
267 tmpBall->GetZ() > TABLEHEIGHT ) {
268 bestX = tmpBall->GetX();
269 bestY = tmpBall->GetY();
270 }
271 }
272 tmpBall->Move();
273 }
274
275 delete tmpBall;
276
277 if ( bestX != AREAXSIZE && bestY != AREAYSIZE ) {
278 hitX = bestX;
279 hitY = bestY;
280 }
281 } else if ( theBall.GetStatus() == 8 ) {
282 if ( (Control::TheControl()->IsPlaying() &&
283 ((PlayGame *)Control::TheControl())->GetService() == GetSide()) ||
284 GetSide() == 1 ) {
285 if ( RAND(2) )
286 hitX = m_targetX;
287 else
288 hitX = -m_targetX;
289 } else
290 hitX = 0.0;
291 hitY = -(TABLELENGTH/2+0.2)*m_side;
292 } else if ( theBall.GetStatus() < 6 ) {
293 hitX = 0.0;
294 hitY = -(TABLELENGTH/2+1.0)*m_side;
295 }
296
297 return true;
298 }
299
300 bool
SetTargetX(Player * opponent)301 ComShakeCut::SetTargetX( Player *opponent ) {
302 double width;
303
304 switch ( theRC->gameLevel ) {
305 case LEVEL_EASY:
306 width = TABLEWIDTH/4;
307 break;
308 case LEVEL_NORMAL:
309 width = TABLEWIDTH/2;
310 break;
311 case LEVEL_HARD:
312 case LEVEL_TSUBORISH:
313 width = TABLEWIDTH;
314 break;
315 default:
316 return false;
317 }
318
319 if ( opponent->GetPlayerType() == PLAYER_PENDRIVE ) {
320 switch ( RAND(4) ) {
321 case 0:
322 m_targetX = -width*7/16;
323 break;
324 case 1:
325 m_targetX = -width*5/16;
326 break;
327 case 2:
328 m_targetX = -width*3/16;
329 break;
330 case 3:
331 m_targetX = -width*1/16;
332 break;
333 }
334 } else {
335 switch ( RAND(8) ) {
336 case 0:
337 m_targetX = -width*7/16;
338 break;
339 case 1:
340 m_targetX = width*5/16;
341 break;
342 case 2:
343 m_targetX = -width*3/16;
344 break;
345 case 3:
346 m_targetX = -width*1/16;
347 break;
348 case 4:
349 m_targetX = width*1/16;
350 break;
351 case 5:
352 m_targetX = width*3/16;
353 break;
354 case 6:
355 m_targetX = width*5/16;
356 break;
357 case 7:
358 m_targetX = width*7/16;
359 break;
360 }
361 }
362
363 if ( theRC->gameLevel == LEVEL_TSUBORISH ) {
364 if ( opponent->GetX()+opponent->GetVX()*0.5 < 0.0 ) {
365 m_targetX = width*7/16;
366 } else {
367 m_targetX = -width*7/16;
368 }
369
370 if ( RAND(4) == 0 ) {
371 m_targetX = -m_targetX;
372 }
373 }
374
375 if ( m_vx > 1.5 ) {
376 m_targetX += TABLEWIDTH/2;
377 } else if ( m_vx > 0.5 ) {
378 m_targetX += TABLEWIDTH/4;
379 } else if ( m_vx < -1.5 ) {
380 m_targetX -= TABLEWIDTH/2;
381 } else if ( m_vx < -0.5 ) {
382 m_targetX -= TABLEWIDTH/4;
383 }
384
385 if ( m_targetX > TABLEWIDTH/2 )
386 m_targetX = TABLEWIDTH*7/16;
387 if ( m_targetX < -TABLEWIDTH/2 )
388 m_targetX = -TABLEWIDTH*7/16;
389
390 return true;
391 }
392