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