1 #ifndef _global_h
2 # include "global.h"
3 #endif
4
5 #ifndef _carrom_h
6 # include "carrom.h"
7 #endif
8 #ifndef _wall_h
9 # include "wall.h"
10 #endif
11 #ifndef _graph_h
12 # include "graph.h"
13 #endif
14 #ifndef _mover_h
15 # include "mover.h"
16 #endif
17 #ifndef _arcs_h
18 # include "arcs.h"
19 #endif
20 #ifndef _pocket_h
21 # include "pocket.h"
22 #endif
23
24
25
InitArea(double wx,double wy)26 void Carrom::InitArea( double wx, double wy ) {
27 area_width = wx;
28 area_height = wy;
29 area_off_x = (MaxX()-ToPocket-PocketWidth-area_width)/2.0;
30 area_off_y = (MaxY()-area_height)/2.0;
31 }
32
33
Carrom(double wx,double wy)34 Carrom::Carrom(double wx, double wy) :
35 Game(wx+2.0*FrameOffset+PocketWidth+ToPocket,wy+2.0*FrameOffset)
36 {
37 InitArea(wx,wy);
38
39 table_col = SetMainBgColor( "Tan" ); // GlobalBackground
40
41 table_black = AddBgColor( "black" );
42 table_red = AddBgColor( "Brown" );
43 table_green = AddBgColor( "DarkGreen" );
44 pocket_col = CreateColorMix( table_col, table_green );
45
46 #ifndef __TURBOC__
47 white_col = AddBallColor( "DarkGoldenrod" );
48 black_col = AddBallColor( "black" );
49 queen_col = AddBallColor( "red" );
50 striker_col = AddBallColor( "DeepSkyBlue" );
51 #else
52 white_col = AddBallColor( "DarkGoldenrod" );
53 floor = CreateColorMix( table_green, table_black );
54
55 black_col = AddBallColor( "black" );
56 queen_col = AddBallColor( "red" );
57 striker_col = CreateColorMix( white_col, black_col );
58 #endif
59
60 AddShadeColor( "grey", 1, 2 );
61 SetCursorColor( "White" );
62 striker = 0;
63 striker_in_pocket = 0;
64 queen_in_pocket = 0;
65 whites_in_pocket = 0;
66 blacks_in_pocket = 0;
67
68 keeper = new StackKeeper(PocketWidth,PocketFrame,table_black);
69 }
70
~Carrom()71 Carrom::~Carrom() {
72 if (striker) {
73 delete queen;
74 delete striker;
75 for (int i=0;i<9;i++) {
76 delete white[i];
77 delete black[i];
78 }
79 striker=0;
80 }
81
82 for (int i=0;i<4;i++) {
83 if (e[i][0]) delete e[i][0];
84 if (e[i][1]) delete e[i][1];
85 if (p[i]) delete p[i];
86 if (w[i]) delete w[i];
87 }
88
89 if (mstone) delete mstone;
90 if (mstriker) delete mstriker;
91 }
92
GetPresetA()93 const Real & Carrom::GetPresetA() const { return PresetA; }
GetPresetHaft()94 const Real & Carrom::GetPresetHaft() const { return PresetHaft; }
GetSlowGranularity()95 const Real & Carrom::GetSlowGranularity() const { return SlowGranularity; }
96
GetNormalBallSize()97 const Real & Carrom::GetNormalBallSize() const { return StoneRadius; }
98
GetChargeGranularity()99 const Real & Carrom::GetChargeGranularity() const { return ChargeGranularity; }
GetChargeSpeed()100 const Real & Carrom::GetChargeSpeed() const { return ChargeSpeed; }
GetMaxCharge()101 const Real & Carrom::GetMaxCharge() const { return MaxCharge; }
GetShootTime()102 const Real & Carrom::GetShootTime() const { return ShootTime; }
103
AreaOffX()104 const Real Carrom::AreaOffX() const { return area_off_x; }
AreaOffY()105 const Real Carrom::AreaOffY() const { return area_off_y; }
AreaWidth()106 const Real Carrom::AreaWidth() const { return area_width; }
AreaHeight()107 const Real Carrom::AreaHeight() const { return area_height; }
108
TAreaOffX()109 const Real Carrom::TAreaOffX() const { return area_off_x-Cushion; }
TAreaOffY()110 const Real Carrom::TAreaOffY() const { return area_off_y-Cushion; }
TAreaWidth()111 const Real Carrom::TAreaWidth() const { return area_width+2.0*Cushion; }
TAreaHeight()112 const Real Carrom::TAreaHeight() const { return area_height+2.0*Cushion; }
113
Setup(double x,double y)114 void Carrom::Setup( double x, double y )
115 {
116 static int nc[5] = { 3, 4, 5, 4, 3 }; // Steine pro Spalte
117 static int t[19] = { -1, 1, -2, // Steinverteilung
118 2, -3, 3, 4,
119 -4, 5, 0, -5, -6,
120 6, -7, 7, 8,
121 -8, 9, -9 };
122
123 const int count = 5;
124 int c=0;
125 double cdist = sqrt( 3.*(GetNormalBallSize()+Offset)*(GetNormalBallSize()+Offset) );
126 Ball *r;
127
128 x-=(cdist*(count-1)/2.0);
129 for( int col=0; col<count; col++ ) {
130 for( int row=0; row<nc[col]; row++ ) {
131 r=new Ball( x+col*cdist, y+(row-nc[col]/2.0+0.5)*2.0*(GetNormalBallSize()+Offset), 0.0, 0.0, GetNormalBallSize(), StoneWeight );
132 if (t[c]>0) {
133 r->state = new BallState( mstone, white_col, r->P() );
134 white[t[c]-1] = r;
135 }
136 else if (t[c]<0) {
137 r->state = new BallState( mstone, black_col, r->P() );
138 black[-t[c]-1] = r;
139 }
140 else {
141 r->state = new BallState( mstone, queen_col, r->P() );
142 queen = r;
143 }
144 c++;
145 }
146 }
147 }
148
149
150
151
InitPlayground()152 void Carrom::InitPlayground() {
153 int i;
154
155 mstone = new DiscMover( GetNormalBallSize() );
156 mstone->Init();
157 DBG2(UnixTrace, "Carrom: Stone-Radius set back from %g to %g\n",
158 (double)StoneRadius, (double)mstone->GetActRadius() );
159 StoneRadius = mstone->GetActRadius();
160
161 mstriker = new BallMover( StrikerRadius );
162 mstriker->Init();
163 DBG2(UnixTrace, "Carrom: Striker-Radius set back from %g to %g\n",
164 (double)StrikerRadius, (double)mstriker->GetActRadius() );
165 StrikerRadius = mstriker->GetActRadius();
166
167 Game::InitPlayground();
168 #if (0)
169 #ifdef DEBUG
170 if (debug&ShowLight) {
171 mstone->CreateLightWindow();
172 }
173 #endif
174 #endif
175
176 p[0] = new Pocket( AreaOffX(), AreaOffY(), PocketRadius );
177 p[1] = new Pocket( AreaOffX()+AreaWidth(), AreaOffY(), PocketRadius );
178 p[2] = new Pocket( AreaOffX()+AreaWidth(), AreaOffY()+AreaHeight(), PocketRadius );
179 p[3] = new Pocket( AreaOffX(), AreaOffY()+AreaHeight(), PocketRadius );
180
181 for (i=0;i<4;i++) {
182 e[i][0] = new StaticBall( p[i]->P()+PocketRadius*Vec2(1.0,RealZero).TurnAngleDeg(-90.*i), 0.0 );
183 e[i][1] = new StaticBall( p[i]->P()+PocketRadius*Vec2(1.0,RealZero).TurnAngleDeg(-90.*i-90.),0.0 );
184 }
185 for (i=0;i<4;i++) {
186 w[i] = new Wall( e[i][0]->P(), e[(i+1)%4][1]->P() );
187 }
188
189 mid = Vec2( AreaOffX()+AreaWidth()/2.0, AreaOffY()+AreaHeight()/2.0 );
190 Vec2 d(1.0,0.0);
191 for (i=0;i<4;i++) {
192 base[i][0] = mid+25.*d.TurnAngleDeg(-90.*i)+22.*d.TurnAngleDeg(90.*(i+1));
193 base[i][1] = mid+25.*d.TurnAngleDeg(-90.*i)+22.*d.TurnAngleDeg(90.*(i-1));
194 }
195 Setup(AreaOffX()+AreaWidth()/2.0, AreaOffY()+AreaHeight()/2.0);
196
197 striker = new Ball( (base[1][0]+base[1][1])/2.0, StrikerRadius, StrikerWeight );
198 striker->state = new BallState( mstriker, striker_col, striker->P() );
199 }
200
201
202
203
DrawBackground()204 void Carrom::DrawBackground() const {
205 int i;
206 int j;
207
208 const Real w8 = 45.0;
209 const Real w16 = w8/2.0;
210 const Real w32 = w16/2.;
211 const Real w64 = w32/2.;
212
213 Vec2 d(1.0,0.0);
214 Vec2 p1,p2,p3,p4;
215
216 Game::DrawBackground();
217
218 // normales Spielfeld
219 SetBgColor( table_black );
220 FillRectangle( TAreaOffX(), TAreaOffY(), TAreaWidth(), TAreaHeight() );
221 SetBgColor(0);
222 FillRectangle( AreaOffX(), AreaOffY(), AreaWidth(), AreaHeight() );
223
224 //
225 // Randelemente und Taschen aufbauen (4er-Schleife)
226 //
227 for (i=0;i<4;i++) {
228 SetBgColor(pocket_col);
229 FillCircle( p[i]->P(), p[i]->R() );
230 Real ang = w8*Real(2*i+1);
231 SetBgColor(table_black);
232 DrawLine( mid+16.0*d.TurnAngleDeg(ang), mid+42.0*d.TurnAngleDeg(ang) );
233 DrawArc( mid+19.5*d.TurnAngleDeg(ang), 3.5, ang+30.0, 300. );
234
235 SetBgColor( table_black );
236 p1 = base[i][0] + 1.8*d.TurnAngleDeg(90.*i);
237 p2 = base[i][0] + 1.3*d.TurnAngleDeg(90.*i);
238 p3 = base[i][1] + 1.3*d.TurnAngleDeg(90.*i);
239 p4 = base[i][1] + 1.8*d.TurnAngleDeg(90.*i);
240 FillPoly( 4, &p1, &p2, &p3, &p4 );
241 p1 = base[i][0] - 1.8*d.TurnAngleDeg(90.*i);
242 p2 = base[i][0] - 1.6*d.TurnAngleDeg(90.*i);
243 p3 = base[i][1] - 1.6*d.TurnAngleDeg(90.*i);
244 p4 = base[i][1] - 1.8*d.TurnAngleDeg(90.*i);
245 FillPoly( 4, &p1, &p2, &p3, &p4 );
246
247 for (j=0;j<2;j++) {
248 SetBgColor( table_black ); FillCircle( base[i][j], 3.6/2 );
249 SetBgColor( table_col ); FillCircle( base[i][j], 3.3/2 );
250 SetBgColor( table_red ); FillCircle( base[i][j], 3.5/2 );
251 }
252 }
253
254 //
255 // Kreise in der Mitte ziehen
256 //
257 SetBgColor( table_black ); FillCircle( mid, 21.5 / 2 );
258 SetBgColor( table_red ); FillCircle( mid, 21.2 / 2 );
259 SetBgColor( table_black ); FillCircle( mid, 20.8 / 2 );
260 SetBgColor( table_col ); FillCircle( mid, 20.5 / 2 );
261
262 SetBgColor( table_black ); FillCircle( mid, 16.1 / 2 );
263 SetBgColor( table_col ); FillCircle( mid, 15.9 / 2 );
264
265 SetBgColor( table_black ); FillCircle( mid, 15.6 / 2 );
266 SetBgColor( table_red ); FillCircle( mid, 15.5 / 2 );
267 SetBgColor( table_black ); FillCircle( mid, 15.1 / 2 );
268 SetBgColor( table_col ); FillCircle( mid, 15.0 / 2 );
269
270 SetBgColor( table_black ); FillCircle( mid, 14.60 / 2 );
271 SetBgColor( table_col ); FillCircle( mid, 14.35 / 2 );
272
273 //
274 // mittleren Kreis in 8 Segmenten aufbauen
275 //
276 for (i=0;i<8;i++) {
277 d = Vec2(1.0,RealZero).TurnAngleDeg( w8 * (double)i );
278
279 SetBgColor(table_black);
280 for (double r=0.;r<4.;r++) {
281 p1 = mid+8.0*d.TurnAngleDeg(r*w32);
282 p2 = mid+8.7*d.TurnAngleDeg(r*w32+5.0);
283 p3 = mid+8.7*d.TurnAngleDeg(r*w32-5.0);
284 FillPoly(3, &p1, &p2, &p3 );
285 Real ang=w8*Real(i)+w32*r+w64;
286 DrawArc(mid+9.*Vec2(1.0,RealZero).TurnAngleDeg(ang),0.95,ang-90.,180.);
287 }
288
289 SetBgColor(table_red);
290 FillCircle( mid+3.0*d.TurnAngleDeg(w16), 0.7 );
291 for (j=1;j<8;j+=4) FillCircle(mid+9.0*d.TurnAngleDeg(w64*j),0.6);
292 SetBgColor(table_green);
293 for (j=3;j<8;j+=4) FillCircle(mid+9.0*d.TurnAngleDeg(w64*j),0.6);
294
295 p1=mid+3.0*d;
296 p2=mid+4.0*d.TurnAngleDeg( 10.0);
297 p3=mid+8.5*d;
298 p4=mid+4.0*d.TurnAngleDeg(-10.0);
299 FillPoly( 4, &p1, &p2, &p3, &p4 );
300 p2 = mid+1.5*d.TurnAngleDeg( 5.0*w16);
301 p3 = mid+1.5*d.TurnAngleDeg(-5.0*w16);
302 FillPoly( 3, &p1, &p2, &p3 );
303
304 Vec2 s[10]; // Stern
305 s[0] = mid+4.7*d.TurnAngleDeg(w16);
306 s[1] = mid+4.3*d.TurnAngleDeg(w16+12.);
307 s[2] = mid+5.2*d.TurnAngleDeg(w16+9.);
308 s[3] = mid+6.2*d.TurnAngleDeg(w16+13.);
309 s[4] = mid+6.2*d.TurnAngleDeg(w16+5.);
310
311 s[5] = mid+7.2*d.TurnAngleDeg(w16);
312 s[6] = mid+6.2*d.TurnAngleDeg(w16-5.);
313 s[7] = mid+6.2*d.TurnAngleDeg(w16-13.);
314 s[8] = mid+5.2*d.TurnAngleDeg(w16-9.);
315 s[9] = mid+4.3*d.TurnAngleDeg(w16-12.);
316 FillPoly( 10, s );
317 }
318
319 SetBgColor(table_red);
320 FillCircle(mid,1.2);
321 }
322
323 //////////////////////////////////////////////////////////////////////////////
324
InPocket(Ball * b)325 void Carrom::InPocket( Ball *b ) {
326 Game::InPocket(b);
327 if (b==striker) { striker_in_pocket = 1; return; }
328 if (b==queen) { queen_in_pocket = 1; return; }
329 for (int i=0;i<9;i++) {
330 if (b==white[i]) { whites_in_pocket |= (1<<i); return; }
331 if (b==black[i]) { blacks_in_pocket |= (1<<i); return; }
332 }
333 }
334
AllBallsStopped()335 void Carrom::AllBallsStopped() {
336 Game::AllBallsStopped();
337 (void)IsSelectable(striker); // back on the table
338 }
339
ResetToCenter(Ball * b)340 void Carrom::ResetToCenter(Ball *b) {
341 Vec2 center(AreaOffX()+AreaWidth()/2.0, AreaOffY()+AreaHeight()/2.0);
342
343 Vec2 newpos;
344 b->FitsNextTo(center,Vec2(1.0,RealZero),&newpos);
345 b->SetP(newpos); // closer to right wall
346
347 b->ChgV(Vec2Zero);
348 }
349
IsSelectable(Ball * b)350 int Carrom::IsSelectable(Ball *b) {
351 if (b==striker) {
352 if (striker_in_pocket) {
353 Vec2 inspos(AreaOffX()+AreaWidth()-2.0*StrikerRadius-EPS,
354 AreaOffY()+AreaHeight()/2.0);
355 Vec2 newpos;
356
357 b->FitsNextTo(inspos,Vec2(-1.0,RealZero),&newpos);
358 striker_in_pocket = 0;
359 b->SetP(newpos);
360 b->ChgV(Vec2Zero);
361
362 return 0;
363 }
364 else {
365 return 1;
366 }
367 }
368 for (int i=0;i<9;i++) {
369 if ( b==white[i] ) {
370 if (whites_in_pocket&(1<<i)) {
371 ResetToCenter(b);
372 whites_in_pocket &= ~(1U<<i);
373 return 0;
374 }
375 else return 1;
376 }
377 if ( b==black[i] ) {
378 if (blacks_in_pocket&(1<<i)) {
379 ResetToCenter(b);
380 blacks_in_pocket &= ~(1U<<i);
381 return 0;
382 }
383 else return 1;
384 }
385 }
386 if ( b==queen ) {
387 if (queen_in_pocket) {
388 ResetToCenter(b);
389 queen_in_pocket = 0;
390 return 0;
391 }
392 else return 1;
393 }
394
395 return Game::IsSelectable(b);
396 }
397
398 // -------------------------------------------------------------------------
399
~CarromDemo()400 CarromDemo::~CarromDemo() {}
401
GetPresetA()402 const Real &CarromDemo::GetPresetA() const { return PresetA; }
GetSlowGranularity()403 const Real &CarromDemo::GetSlowGranularity() const { return SlowGranularity; }
404
InitPlayground()405 void CarromDemo::InitPlayground() {
406 Carrom::InitPlayground();
407 for (int i=0;i<4;i++) {
408 delete e[i][0]; e[i][0]=0L;
409 delete e[i][1]; e[i][1]=0L;
410 Vec2 pos( p[i]->P() );
411 delete p[i];
412 p[i] = new StaticBall( pos, PocketRadius );
413 }
414
415 striker->v = Vec2(1.0,-shot_speed);
416 }
417
DrawBackground()418 void CarromDemo::DrawBackground() const {
419 Carrom::DrawBackground();
420 SetBgColor(table_black);
421 for (int i=0;i<4;i++) {
422 FillCircle( p[i]->P(), p[i]->R() );
423 }
424 }
425
426