1 /***************************************************************************
2                           fall.cpp  -  description
3                              -------------------
4     begin                : Sat Aug 18 2001
5     copyright            : (C) 2001 by Immi
6     email                : cuyo@karimmi.de
7 
8 Modified 2001-2003,2005,2006,2008,2010,2011,2014 by the cuyo developers
9 
10  ***************************************************************************/
11 
12 /***************************************************************************
13  *                                                                         *
14  *   This program is free software; you can redistribute it and/or modify  *
15  *   it under the terms of the GNU General Public License as published by  *
16  *   the Free Software Foundation; either version 2 of the License, or     *
17  *   (at your option) any later version.                                   *
18  *                                                                         *
19  ***************************************************************************/
20 
21 #include "fall.h"
22 #include "spielfeld.h"
23 #include "aufnahme.h"
24 #include "fehler.h"
25 #include "sound.h"
26 #include "layout.h"
27 
28 
29 /* Anzahl der Pixel: Verschiebung einen Blops beim drehen... */
30 #define am_drehen_schieb_gross 28 /* gric * cos(30 Grad) */
31 #define am_drehen_schieb_klein 16 /* gric * sin(30 Grad) */
32 /* Anz. d. angezeigten Zwischenbildchen beim Drehen. (Das erste
33    Zwischenbild sieht man allerdings nicht...) */
34 #define am_drehen_start 3
35 
36 /* Animation des naechsten Falls, wenn es frisch erzeugt wird. */
37 #define am_erzeugen_start (-3 * (gric / 4))
38 #define am_erzeugen_dy (gric / 4)
39 
40 
41 /* Anzahl der Pixel: Verschiebung des Falls beim verschieben... */
42 #define am_schieben_diff 8
43 /* Restverschiebung direkt nach dem Tastendruck. (Das erste
44    Zwischenbild sieht man allerdings nicht...) */
45 #define am_schieben_start 16
46 
47 
48 
49 /* Return-Werte f�r testBelegt() */
50 #define belegt_keins 0
51 #define belegt_0 1
52 #define belegt_1 2
53 #define belegt_beide (belegt_0 | belegt_1)
54 
55 
56 /***************************************************************************/
57 
58 
59 /** Liefert die Anzahl der Blops vom Fall zur�ck. */
getAnz() const60 int FallPos::getAnz() const {
61   switch (r) {
62     case richtung_keins: return 0;
63     case richtung_einzel: return 1;
64     default: return 2;  // waag / senk / unplatziert
65   }
66 }
67 
getX(int a) const68 int FallPos::getX(int a) const {
69   return x + a * (r == richtung_waag || r == richtung_unplatziert);
70 }
71 
72 
getY(int a,const Spielfeld * spf) const73 int FallPos::getY(int a, const Spielfeld * spf) const {
74   int y0 = yy + gric - 1 + spf->getHochVerschiebung();
75 
76   /* Bei unplatzierten blops ist yy die Koord relativ zur ins-Spiel-Komm-Position */
77   if (r == richtung_unplatziert)
78     y0 += spf->getHetzrandYPix() - gric;
79 
80   /* Korrektur bei jeder zweiten Spalte im Sechseck-Modus... */
81   if (spf->getHexShift(getX(a)))
82     y0 += gric / 2;
83 
84   return y0 / gric + a * (r == richtung_senk);
85 }
86 
87 
88 /***************************************************************************/
89 
90 
91 /** Konstruktor... */
Fall(Spielfeld * sp,bool re)92 Fall::Fall(Spielfeld * sp, bool re): BlopBesitzer(sp), mRechterSpieler(re),
93        mRectW(0), mRectH(0) {
94   mBlop[0].setBesitzer(this, ort_absolut(absort_fall, re, 0));
95   mBlop[1].setBesitzer(this, ort_absolut(absort_fall, re, 1));
96 }
97 
98 /**  Mu� einmal aufgerufen werden */
initialisiere()99 void Fall::initialisiere() {
100   /* Initialisiert werden m�ssen sie schon, bevor sich jemand bequemt,
101      erzeug() aufzurufen:
102      Mit @0 und @1 kann drauf zugegriffen werden.
103      Nur halt noch nicht sinnvoll */
104   mBlop[0] = Blop(blopart_keins);
105   mBlop[1] = Blop(blopart_keins);
106   mPos.r = richtung_keins;
107 }
108 
109 /** Erzeugt ein neues Fall, der sich noch nicht im Spielfeld befindet.
110     Bei reinkommen = true kommt das Fall ins Preview-Feld reingerutscht.
111     Sonst ist es sofort da (f�r Spielanfang) */
erzeug(bool reinkommen)112 void Fall::erzeug(bool reinkommen /* = true*/) {
113   mBlop[0].setBesitzer(this, ort_absolut(absort_fall, mRechterSpieler, 0, 1));
114   mBlop[1].setBesitzer(this, ort_absolut(absort_fall, mRechterSpieler, 1, 1));
115   CASSERT(mPos.r == richtung_keins);
116   for (int i=0; i<2; i++)
117     mBlop[i]=ld->zufallsSorte(wv_farbe);
118   mPos.r = richtung_unplatziert;
119   mExtraDreh = 0;
120   mExtraX = 0;
121   mSchnell = false;
122   if (ld->mFallPosZufaellig)
123     mPos.x = Aufnahme::rnd(grx-1);
124   else
125     mPos.x = grx / 2 - 1;
126   mPos.yy = reinkommen ? am_erzeugen_start : 0;
127 }
128 
129 
130 
131 /** Bringt ein Fall ins Spiel, d.h. setzt die Koordinaten. Liefert false, wenn daf�r kein Platz ist */
insSpiel()132 bool Fall::insSpiel() {
133   mBlop[0].setBesitzer(this, ort_absolut(absort_fall, mRechterSpieler, 0, 0));
134   mBlop[1].setBesitzer(this, ort_absolut(absort_fall, mRechterSpieler, 1, 0));
135   CASSERT(mPos.r == richtung_unplatziert);
136   /* mPos.x wurde schon beim erzeugen festgelegt */
137   mPos.yy = mSpf->getHetzrandYPix() - gric;
138   mPos.r = richtung_waag;
139 
140   /* Platz? */
141   if (testBelegt(mPos)) {
142     /* Kein Platz, also wieder zerst�ren */
143     mPos.r = richtung_keins;
144     return false;
145   }
146 
147   /* Ich hab die folgende Zeile mal hier eingef�gt. Ich denke, es war ein Bug, dass
148      die da nicht war. -Immi (2014) */
149   calcFallRect();
150 
151   return true;
152 }
153 
154 
155 /** Liefert true, wenn das Fallende senkrecht ist */
istSenkrecht() const156 bool Fall::istSenkrecht() const {
157   CASSERT(mPos.r == richtung_waag || mPos.r == richtung_senk);
158   return mPos.r == richtung_senk;
159 }
160 
161 
162 /** L�sst nur noch Blop a �brig */
halbiere(int a)163 void Fall::halbiere(int a) {
164   CASSERT(mPos.r == richtung_waag);
165   CASSERT(a == 0 || a == 1);
166   mPos.x += a;
167   mPos.r = richtung_einzel;
168   mExtraDreh = 0;
169   mExtraX = 0;
170 }
171 
172 /** Entfernt das Fall ganz */
zerstoere()173 void Fall::zerstoere() {
174   mPos.r = richtung_keins;
175 }
176 
177 
178 /** Fuer platzierte Falls: Macht alles von spielSchritt ausser Grafik-Update markieren */
spielSchrittPlatziertIntern()179 void Fall::spielSchrittPlatziertIntern() {
180 
181   /* Wenn der Stein von einem fr�heren Tastendruck noch nicht fertig
182      gedreht ist, dann weiterdrehen */
183   if (mExtraDreh > 0)
184     mExtraDreh--;
185   /* Wenn der Stein noch nicht fertig X-verschoben ist, dann jetzt fertig
186      X-verschieben */
187   if (mExtraX > 0) mExtraX -= am_schieben_diff;
188   if (mExtraX < 0) mExtraX += am_schieben_diff;
189 
190 
191 
192   /* Wenn am Platzen, dann nicht mehr nach unten bewegen */
193   if (getAmPlatzen())
194     return;
195 
196   /* Neue y-Koordinate... */
197   FallPos fp2 = mPos;
198   if (mSchnell || mPos.r == richtung_einzel)
199     fp2.yy += mSpf->getSemiglobal().getVariable(spezvar_falling_fast_speed);
200   else
201     fp2.yy += mSpf->getSemiglobal().getVariable(spezvar_falling_speed);
202   /* Geschwindigkeit k�nnte ja negativ sein. Also clippen. */
203   if (fp2.yy < mSpf->getHetzrandYPix() - gric)
204     fp2.yy = mSpf->getHetzrandYPix() - gric;
205 
206   /* Gibt's Platz um weiterzufallen? */
207   int beleg = testBelegt(fp2);
208   if (!beleg) {
209     mPos = fp2;
210     return;
211   }
212 
213   /* OK, wir kommen irgendwo auf. */
214   playSample(sample_land);
215 
216   /* Einzelblop? */
217   if (mPos.r == richtung_einzel) {
218     Blop * b1 = festige(0);
219     if (b1) b1->scheduleEvent(event_land);
220     zerstoere();
221     return;
222   }
223 
224   /* Senkrecht? */
225   if (istSenkrecht()) {
226     /* Wichtig: Erst den unteren Blop festigen; es k�nnte sein, dass die Blops
227        weiter oben gefestigt werden m�ssen, als geplant (wg. Hochverschiebung
228        oder sogar wegen richtiger Spielfeld�nderung am Ende von einer Zeilen-
229        �bergabe)... */
230     Blop * b1 = festige(1);
231     Blop * b0 = festige(0);
232     if (b1) b1->scheduleEvent(event_land);
233     if (b0) b0->scheduleEvent(event_land);
234     zerstoere();
235     return;
236   }
237 
238   /* OK, waagrecht. Welche Teile? */
239   //Blop::beginGleichzeitig();
240   Blop * b0 = 0, * b1 = 0;
241   if (beleg & belegt_0) b0 = festige(0);
242   if (beleg & belegt_1) b1 = festige(1);
243   if (b0) b0->scheduleEvent(event_land);
244   if (b1) b1->scheduleEvent(event_land);
245   //Blop::endGleichzeitig();
246 
247 
248   /* Beide H�lften aufgekommen? */
249   if (beleg == belegt_beide) {
250     zerstoere();
251     return;
252   }
253 
254   /* Nur eine H�lfte aufgekommen. */
255   mPos = fp2;
256   if (beleg == belegt_0) {
257     // linke H�lfte aufgekommen =>
258     // �briges rechtes nach links schieben
259     mBlop[0] = mBlop[1];
260   }
261   /* Nur noch die H�lfte vom Fall ist �brig; wenn das linke fest ist,
262      dann die rechte H�lfte. */
263   halbiere(beleg == belegt_0);
264 }  // spielSchrittIntern
265 
266 
267 
268 
269 /** Bewegt das Fall ggf. nach unten und animiert es ggf.
270  */
spielSchritt()271 void Fall::spielSchritt() {
272 
273   if (mPos.r == richtung_keins) {
274     /* Bei nicht-Existenz nichts tun. */
275 
276   } else if (mPos.r == richtung_unplatziert) {
277     if (mPos.yy < 0) {
278       mPos.yy += am_erzeugen_dy;
279       CASSERT(mPos.yy <= 0);
280       mSpf->setUpdateNaechstesFall();
281     }
282 
283   } else {
284 
285     /* Das meiste passiert hier */
286     spielSchrittPlatziertIntern();
287 
288     /* Altes Rechteck zum updaten markieren,
289       neues Rechteck bestimmen,
290       neues Rechteck zum updaten markieren.
291 
292       Achtung: Altes Rechteck haette auch vor spielSchrittPlatziertIntern()
293       nicht mehr berechnet werden, da Tastendruecke das Fall verschoben
294       haben koennen.
295       */
296     setUpdateFallRect();
297     calcFallRect();
298     setUpdateFallRect();
299   }
300 
301 
302 }  // spielSchritt
303 
304 
305 
306 
307 /** F�hrt die Animationen durch. Innerhalb einer Gleichzeit aufrufen. */
animiere()308 void Fall::animiere() {
309   //CASSERT(gGleichZeit);
310   for (int i = 0; i < getAnz(); i++)
311     mBlop[i].animiere();
312 }
313 
314 
315 /** kopiert einen fallenden Blop nach mDaten und liefert den
316     Zielblop in mDaten zur�ck (als Referenz), damit man einen
317     land-Event senden kann. Sendet den land-Event nicht selbst,
318     weil Cual-Code erwarten k�nnte, dass erst beide Blops
319     gefestigt werden und dann erst die Events kommen.
320     Kann 0 zur�ckliefern (wenn der Blop keinen Platz auf
321     dem Bildschirm hat). */
festige(int n)322 Blop * Fall::festige(int n) {
323   int x = getX(n);
324   int y = getY(n);
325 
326   /* Evtl. ist dieses Feld schon belegt. Dann so lange weiter oben probieren,
327      bis wir ein freies Feld finden. */
328   while (mSpf->getDatenPtr()->getFeldArt(x, y) != blopart_keins) {
329     y--;
330     /* Sollte tats�chlich (auf welche Art auch immer) pl�tzlich die ganze Spalte
331        voll sein, dann verschwindet der Blop halt. */
332     if (y < 0)
333       return 0;
334   }
335   Blop & dst = mSpf->getDatenPtr()->getFeld(x, y);
336   dst = mBlop[n];
337   return &dst;
338 }
339 
340 
341 
342 /** Bewegt das Fall eins nach links */
tasteLinks()343 void Fall::tasteLinks() {
344   mBlop[0].execEvent(event_keyleft);
345   mBlop[1].execEvent(event_keyleft);
346   if (steuerbar()) {
347     FallPos fp2 = mPos;
348     fp2.x--;
349     if (!testBelegt(fp2)) {
350       mPos = fp2;
351       /* Auf dem Bildschirm soll der Fall noch nicht fertigverschoben
352 	 erscheinen */
353       mExtraX = am_schieben_start;
354     }
355   }
356 }
357 
358 /** Bewegt das Fall eins nach rechts */
tasteRechts()359 void Fall::tasteRechts(){
360   mBlop[0].execEvent(event_keyright);
361   mBlop[1].execEvent(event_keyright);
362   if (steuerbar()) {
363     FallPos fp2 = mPos;
364     fp2.x++;
365     if (!testBelegt(fp2)) {
366       mPos = fp2;
367       /* Auf dem Bildschirm soll der Fall noch nicht fertigverschoben
368 	 erscheinen */
369       mExtraX = -am_schieben_start;
370     }
371   }
372 }
373 
374 /** Dreht das Fall */
tasteDreh1()375 void Fall::tasteDreh1(){
376   mBlop[0].execEvent(event_keyturn);
377   mBlop[1].execEvent(event_keyturn);
378 }
379 
380 /** Dreht das Fall */
tasteDreh2()381 void Fall::tasteDreh2(){
382   if (steuerbar()) {
383     FallPos fp2 = mPos;
384     fp2.r = fp2.r == richtung_waag ? richtung_senk : richtung_waag;
385     if (!testBelegt(fp2)) {
386       mPos = fp2;
387       /* Drehrichtung bei senkrecht gespiegeltem Level andersrum, damit
388 	 es f�r den Spieler gleich erscheint */
389       if (ld->mSpiegeln ? fp2.r == richtung_senk : fp2.r == richtung_waag) {
390 	Blop b = mBlop[0];
391 	mBlop[0] = mBlop[1];
392 	mBlop[1] = b;
393       }
394       /* F�r Level, bei denen sich die Teile beim Drehen ver�ndern... */
395       Blop::beginGleichzeitig();
396       mBlop[0].execEvent(event_turn);
397       mBlop[1].execEvent(event_turn);
398       Blop::endGleichzeitig();
399 
400       /* Auf dem Bildschirm soll der Fall noch nicht fertiggedreht
401 	 erscheinen */
402       mExtraDreh = am_drehen_start;
403     }
404   }
405 }
406 
407 /** �ndert die Fallgeschwindigkeit vom Fall */
tasteFall()408 void Fall::tasteFall(){
409   mBlop[0].execEvent(event_keyfall);
410   mBlop[1].execEvent(event_keyfall);
411   if (steuerbar()) {
412     mSchnell = !mSchnell;
413   }
414 }
415 
416 
417 /** Liefert true, wenn das Fall (noch) am Platzen ist
418     (wg. Spielende) */
getAmPlatzen() const419 bool Fall::getAmPlatzen() const {
420   if (mPos.r == richtung_keins)
421     return false;
422 
423   /* Wenn einer platzt, dann beide. */
424   CASSERT(mPos.r == richtung_einzel ||
425          mBlop[0].getAmPlatzen() == mBlop[1].getAmPlatzen());
426 
427   return mBlop[0].getAmPlatzen();
428 }
429 
430 /** L�sst alle Blops vom Fall platzen (Spielende). */
lassPlatzen()431 void Fall::lassPlatzen() {
432   CASSERT(mPos.r != richtung_keins);
433   for (int i = 0; i < getAnz(); i++)
434     mBlop[i].lassPlatzen();
435 }
436 
437 /** Liefert einen Pointer auf die Blops zur�ck. Wird vom
438     KIPlayer und von @0 und @1 ben�tigt. */
getBlop() const439 const Blop * Fall::getBlop() const {
440   return mBlop;
441 }
442 
getBlop()443 Blop * Fall::getBlop() {
444   return mBlop;
445 }
446 
447 
448 /** Malt das Fall. */
malen() const449 void Fall::malen() const {
450   /* Wenn kein Fallendes unterwegs ist, liefert getAnz() 0 */
451   for (int i = 0; i < getAnz(); i++) {
452     int xx, yy;
453 
454     if (mPos.r == richtung_unplatziert) {
455       /* Unplatzierte Blops kommen nicht an die von getXX(), getYY() angegebene Stelle...
456        * (da die R�ckgabewerte dieser Funktionen die Werte sind, die cual zu sehen bekommt) */
457 
458       xx = L_naechstesfall_x + i * gric;
459       yy = mPos.yy;
460 
461       /* H�ssliches Workaround: mBlop[i].malen spiegelt die Position. Das soll aber
462        * fuer den unplazierten Fall nicht passieren; deshalb hier nochmal spiegeln.
463        * (Das "+ yy" sorgt jedoch daf�r, dass das Preview in der gew�nschten Richtung reinkommt.) */
464       if (ld->mSpiegeln) yy = gry * gric + yy - gric;
465 
466     } else {
467       xx = getXX(i);
468       yy = getYY(i);
469     }
470 
471     mBlop[i].malen(xx, yy);
472   }
473 }
474 
475 
testBelegt(FallPos p) const476 int Fall::testBelegt(FallPos p) const {
477   int i = 0;
478   int ret = belegt_keins;
479 
480   for (; i < p.getAnz(); i++)
481     if (!mSpf->getDatenPtr()->testPlatzSpalte(p.getX(i), p.getY(i, mSpf)))
482       ret |= (i == 0 ? belegt_0 : belegt_1);
483 
484   /* Sonderfall: Wenn im Senkrecht-Modus Blop 1 belegt ist,
485      dann per Definition auch Blop 0.
486      (Das wird zwar (im Moment) nirgends verwendet, macht aber Sinn.) */
487   if (mPos.r == richtung_senk && ret) ret = belegt_beide;
488 
489   return ret;
490 }
491 /** Liefert true, wenn das Fall existiert.
492     Mit Argument: Wenn diese H�lfte existiert. */
existiert(int a) const493 bool Fall::existiert(int a/*=0*/) const {
494   return mPos.r != richtung_keins && !(mPos.r == richtung_einzel && a == 1);
495 }
496 
497 
498 
499 /** Liefert loc_x */
getX(int a) const500 int Fall::getX(int a) const {
501   if (!existiert(a)) return blop_pos_nix;
502   return mPos.getX(a);
503 }
504 
505 /** Liefert loc_y */
getY(int a) const506 int Fall::getY(int a) const {
507   if (!existiert(a)) return blop_pos_nix;
508   return mPos.getY(a, mSpf);
509 }
510 
511 
512 
513 /** Liefert loc_xx */
getXX(int a) const514 int Fall::getXX(int a) const {
515   if (!existiert(a)) return blop_pos_nix;
516 
517   /*           Gedreht              Ungedreht */
518   /*           Normal    Spiegel              */
519   /*           Waag Senk Waag Senk            */
520   int drehx = "2215 2243 2215 4322  2"[getDrehIndex(a)] - '1';
521   /*           1*>01>0* 0*>01 10>0*           */
522   /*           0  *  1  1  *  *  1            */
523 
524   /* 1: -1 + sin   2: 0   3: sin  4: cos  5: -1 + cos   (bei 30 Grad) */
525   int wandel[] = {-gric + am_drehen_schieb_klein, 0,
526     am_drehen_schieb_klein, am_drehen_schieb_gross,
527     -gric + am_drehen_schieb_gross};
528 
529   return (mPos.x + a*(mPos.r==richtung_waag || mPos.r==richtung_unplatziert))*gric + mExtraX + wandel[drehx];
530 }
531 
532 /** Liefert loc_yy */
getYY(int a) const533 int Fall::getYY(int a) const {
534   if (!existiert(a)) return blop_pos_nix;
535 
536   if (mPos.r == richtung_unplatziert)
537     return mSpf->getHetzrandYPix() - gric + mPos.yy;
538 
539   /*           Gedreht              Ungedreht */
540   /*           Normal    Spiegel              */
541   /*           Waag Senk Waag Senk            */
542   int drehy = "4322 2215 2243 2215  2"[getDrehIndex(a)] - '1';
543   /*           1*>01>0* 0*>01 10>0*           */
544   /*           0  *  1  1  *  *  1            */
545 
546   /* 1: -1 + sin   2: 0   3: sin  4: cos  5: -1 + cos   (bei 30 Grad) */
547   int wandel[] = {-gric + am_drehen_schieb_klein, 0,
548     am_drehen_schieb_klein, am_drehen_schieb_gross,
549     -gric + am_drehen_schieb_gross};
550 
551   return mPos.yy + a*(mPos.r==richtung_senk)*gric + wandel[drehy];
552 }
553 
554 /** Kodiert alle Informationen des Drehens in eine Zahl.
555     Ist f�r getXX und getYY da */
getDrehIndex(int a) const556 int Fall::getDrehIndex(int a) const {
557 /* Bit 21: gar nicht gedreht | */
558 /* Bit 10: Spiegel? | Bit 5: wirdSenk? | */
559 /* Bit 2: Blob1? | Bit 1: Schritt1? */
560 
561   if (mExtraDreh != 0) {
562 
563     /* 3 bedeutet eigentlich: Noch gar nicht gedreht. Normalerweise wird
564        nach einem Tastendruck erst mal ein spielSchritt() aufgerufen (mit
565        mExtraDreh--) und dann das Fall erst neu gemalt. Bei einem au�er-
566        ordentlichen Update k�nnte allerdings auch schon fr�her neu gemalt
567        werden. Der Einfachheit halber malen wir da schon angedreht. */
568     int ed = mExtraDreh;
569     if (ed == 3) ed = 2;
570 
571     return 10 * ld->mSpiegeln + 5 * istSenkrecht() + 2 * a + (ed == 1);
572   }
573   else return 21;
574 }
575 
576 
577 /** Bestimm mFallRect neu (Fall-ueberdeckendes Rechteck) */
calcFallRect()578 void Fall::calcFallRect() {
579   if (mPos.r == richtung_keins || mPos.r == richtung_unplatziert)
580     mRectW = mRectH = 0;
581   else {
582     /* Faule Variante... ohne Beachtung der Drehposition und der genauen
583        y-Position */
584     int li = mPos.x;
585     int re = mPos.x + 2;
586     if (mExtraX < 0) li--;
587     if (mExtraX > 0) re++;
588     mRectX = li * gric;
589     mRectW = (re - li) * gric;
590     mRectY = mPos.yy;
591     mRectH = 3 * gric;
592   }
593 }
594 
595 
596 /** Setzt den Bereich, der durch mRect* angegeben ist, auf
597     upzudaten */
setUpdateFallRect()598 void Fall::setUpdateFallRect() {
599   if (mRectW != 0) {
600     mSpf->setUpdateRect(mRectX, mRectY, mRectW, mRectH);
601   }
602 }
603 
604 
605 
606 /** Liefert true, wenn das Fall aus grade am zerfallen ist
607     (d. h. existiert, aber aus nur noch einem Blop besteht).
608     In dieser Zeit darf n�mlich keine Explosion gez�ndet
609     werden. (Erst warten, bis der andere Blop auch angekommen
610     ist.) */
istEinzel() const611 bool Fall::istEinzel() const {
612   return mPos.r == richtung_einzel;
613 }
614 
615 
playSample(int nr) const616 void Fall::playSample(int nr) const {
617   Sound::playSample(nr, mRechterSpieler ? so_rfeld : so_lfeld,
618 		    2*mPos.x+1+(mPos.r==richtung_waag), 2*grx);
619 }
620 
621 
getSpezConst(int vnr,const Blop * wer) const622 int Fall::getSpezConst(int vnr, const Blop * wer) const {
623   /* Wie nett: Man hat uns mitgeteilt, welcher der beiden
624      Blops anfragt. */
625   bool bin_1 = wer->getOrt().x == 1;
626 
627   switch (vnr) {
628   case spezconst_loc_x:
629     return getX(bin_1);
630   case spezconst_loc_y:
631     return getY(bin_1);
632   case spezconst_loc_xx:
633     return getXX(bin_1);
634   case spezconst_loc_yy:
635     return getYY(bin_1);
636   case spezconst_turn:
637     /* Potentieller Bug:
638        Hier stand mal < 3 statt < 4 (und "021" statt "0211").
639        Jene assertion wurde nichtreproduzierbar verletzt.
640        Die Verletzung war schon beim ersten Bildaufbau (vorm Spiel),
641        aber nicht im ersten Spiel. Sollte man mal bei Gelegenheit verfolgen. */
642     CASSERT(mExtraDreh < 4);
643     return "0211"[mExtraDreh] - '0';
644   case spezconst_falling:
645     return 1;
646   case spezconst_falling_fast:
647     return mSchnell;
648   }
649 
650   /* Wir wissen von nix; Blop::getSpezConst() soll den Default-Wert
651      zur�ckliefern. */
652   return spezconst_defaultwert;
653 }
654 
655