1 /* $Id: PenAttack.cpp,v 1.27 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 "PenAttack.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
PenAttack()33 PenAttack::PenAttack() {
34 m_playerType = PLAYER_PENATTACK;
35 }
36
PenAttack(long side)37 PenAttack::PenAttack(long side) : Player(side) {
38 m_playerType = PLAYER_PENATTACK;
39 }
40
PenAttack(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 PenAttack::PenAttack( 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
~PenAttack()53 PenAttack::~PenAttack() {
54 }
55
56 bool
AddStatus(long diff)57 PenAttack::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 PenAttack::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 ) < 1.0 ) {
74 AddStatus( 1 );
75 }
76 if ( hypot( m_vx-prevVx, m_vy-prevVy ) > 0.8-theRC->gameLevel*0.1 ) {
77 AddStatus(-1);
78 }
79
80 return true;
81 }
82
83 bool
Swing(long spin)84 PenAttack::Swing( long spin ) {
85 Ball *tmpBall;
86
87 if ( theBall.GetStatus() == 6 || theBall.GetStatus() == 7 )
88 return false;
89
90 if ( m_swing > 10 && m_swing < 30 )
91 return false;
92
93 if ( m_swing >= 30 )
94 AddStatus( -(50-m_swing)*2 );
95
96 m_swing = 11;
97 m_pow = 8;
98
99 // Decide SwingType by the hit point and spin, etc.
100 // Calc the ball location of 0.1 second later
101 tmpBall = new Ball( theBall.GetX(), theBall.GetY(), theBall.GetZ(),
102 theBall.GetVX(), theBall.GetVY(), theBall.GetVZ(),
103 theBall.GetSpin(), theBall.GetStatus() );
104
105 for ( int i = 0 ; i < 10 ; i++ )
106 tmpBall->Move();
107
108 if ( spin < 3 )
109 m_swingSide = false;
110 else
111 m_swingSide = true;
112
113 SwingType( tmpBall, spin );
114
115 delete tmpBall;
116
117 if (Control::TheControl()->GetThePlayer() == this && mode == MODE_MULTIPLAY)
118 ::SendSwing( this );
119
120 return true;
121 }
122
123 bool
StartSwing(long spin)124 PenAttack::StartSwing( long spin ) { // Argument is valid only on serve
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 = -0.6;
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 PenAttack::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.3F)*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 double targetX, targetY;
216
217 GetModifiedTarget( targetX, targetY );
218
219 double maxVy;
220 CalcLevel( &theBall, diff, level, maxVy );
221
222 theBall.TargetToV( targetX, targetY, level, m_spin, vx, vy, vz,
223 0.1, maxVy );
224
225 // If your target is near the edge of the table, much more status point
226 // is necessary.
227
228 if ((m_status-StatusBorder())*3/2000.0 <
229 fabs(fabs(m_x-theBall.GetX())-0.3))
230 AddError( vx, vy, vz );
231
232 // Reduce status
233 m_afterSwing = (long)
234 (hypot( theBall.GetVX()*0.8-vx, theBall.GetVY()*0.8+vy )
235 * (1.0+diff*10.0) + fabs(m_spin)*5.0 + fabs(theBall.GetSpin())*4.0);
236
237 if ( ForeOrBack() || m_swingType == SWING_POKE )
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 PenAttack::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)*0.5 ){ // low ball on the table
264 if ( ball->GetSpin() < 0 ){
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 = spin*0.2;
271 m_spin = 0.4;
272 }
273 } else if ( ball->GetZ() < TABLEHEIGHT+NETHEIGHT ) { // under the net
274 if ( ForeOrBack() ) {
275 m_swingType = SWING_DRIVE;
276 //m_spin = spin*0.2+0.4;
277 m_spin = 0.8;
278 } else {
279 if ( ball->GetSpin() < 0 ) {
280 m_swingType = SWING_POKE;
281 //m_spin = -spin*0.2-0.4;
282 m_spin = -0.8;
283 } else {
284 m_swingType = SWING_NORMAL;
285 //m_spin = spin*0.2;
286 m_spin = 0.4;
287 }
288 }
289 } else if ( fabs(ball->GetY()) < TABLELENGTH/2+1.0 &&
290 ball->GetZ() > TABLEHEIGHT+NETHEIGHT ){
291 m_swingType = SWING_SMASH;
292 m_spin = 0.2;
293 } else {
294 m_swingType = SWING_NORMAL;
295 //m_spin = spin*0.2;
296 m_spin = 0.4;
297 }
298 } else{
299 m_swingType = SWING_NORMAL;
300 //m_spin = spin*0.2;
301 m_spin = 0.4;
302 }
303
304 return true;
305 }
306
307 // Target will be modified by the spin
308 // (now invalid)
309 #if 0
310 bool
311 PenAttack::GetModifiedTarget( double &targetX, double &targetY ) {
312 targetX = m_targetX;
313 targetY = m_targetY + theBall.GetSpin()*m_side*0.5;
314
315 return true;
316 }
317 #else
318 bool
GetModifiedTarget(double & targetX,double & targetY)319 PenAttack::GetModifiedTarget( double &targetX, double &targetY ) {
320 targetX = m_targetX;
321 targetY = m_targetY;
322
323 return true;
324 }
325 #endif
326
327 void
CalcLevel(Ball * ball,double & diff,double & level,double & maxVy)328 PenAttack::CalcLevel(Ball *ball, double &diff, double &level, double &maxVy) {
329 double targetX, targetY;
330
331 GetModifiedTarget( targetX, targetY );
332
333 if ( (m_y-ball->GetY())*m_side < 0 )
334 diff = fabs( m_y-ball->GetY() )*0.1;
335 else
336 diff = fabs( m_y-ball->GetY() )*0.15;
337
338 diff *= fabs(ball->GetSpin())+1;
339
340 SwingError();
341
342 level = 1 - fabs(targetY)/(TABLELENGTH/16)/40 -
343 diff*fabs(targetY)/(TABLELENGTH/16);
344
345 level *= (double)m_pow/20.0 + 0.5;
346
347 if ( ForeOrBack() ) {
348 switch ( m_swingType ) {
349 case SWING_CUT:
350 case SWING_POKE:
351 case SWING_NORMAL:
352 case SWING_DRIVE:
353 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 15.0 -
354 (fabs(m_spin)+fabs(ball->GetSpin()))*3.0;
355 break;
356 case SWING_SMASH:
357 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 25.0 -
358 (fabs(m_spin)+fabs(ball->GetSpin()))*3.0;
359 break;
360 default:
361 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 15.0 -
362 (fabs(m_spin)+fabs(ball->GetSpin()))*3.0;
363 }
364 } else {
365 switch ( m_swingType ) {
366 case SWING_CUT:
367 case SWING_POKE:
368 case SWING_NORMAL:
369 case SWING_DRIVE:
370 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 12.0 -
371 (fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
372 break;
373 case SWING_SMASH:
374 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 18.0 -
375 (fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
376 break;
377 default:
378 maxVy = hypot(ball->GetVX(), ball->GetVY())*0.6 + 12.0 -
379 (fabs(m_spin)+fabs(ball->GetSpin()))*4.0;
380 }
381 }
382
383 if ( level > 1.0 )
384 level = 1.0;
385 }
386