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