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