1 // Untahris (Common Playground)
2 // copyright (C) 2006 longuens@users.sourceforge.net
3 // Released under GNU General Public License (see the file COPYING)
4 // --------------------------------------------------------------
5 // UTetris.
6 
7 #include <math.h>
8 
9 struct OTetris : TPlayObject {
10   public:
11   int32 ix;
12   int32 iy;
13   int32 bx;
14   int32 by;
15   bool brick[4][4];
16   int32 n; // blocks in brick
17 
tBlockingTypeOTetris18   int tBlockingType(int x, int y) {
19     if(g.map[y][x] == cFree) return 2;
20     if(g.map[y][x] == cXunux) return 2;
21     CellType m = bigType(x, y);
22     if(isBonus(m)) return 2;
23     if(isSnakePart(g.map[y][x]) || g.map[y][x] == cTetris) return 1;
24     return 0;
25     }
26 
tLiningTypeOTetris27   int tLiningType(int x, int y) {
28     // 0: not forming lines, falling yes
29     // 1: not forming lines, falling no
30     // 2: limit for forming lines
31     // 3: forms lines
32     CellType m = g.map[y][x];
33     if(m == cFree) return 0;
34     if(isSnakePart(m) || m == cPermaWall)
35       return 2;
36     if(m == cTetrisDown || m == cSnakeTRON || m == cBreakWall)
37       return 3;
38     return 1;
39     }
40 
blockFitsOTetris41   int blockFits() {
42     int bf = 2;
43     for(int py=0; py<4; py++) for(int px=0; px<4; px++) if(brick[py][px]) {
44       int bf2 = tBlockingType(bx+px, by+py);
45       if(bf2 < bf) bf = bf2;
46       }
47     return bf;
48     }
49 
putBlockOTetris50   void putBlock(CellType ct, int x, int y) {
51     CellType m = bigType(x, y);
52     if(isBonus(m)) {
53       switch(m) {
54         case cBonusLevel:
55           d.playSoundAt(d.sndBlue, x, y);
56           ow()->score += scoreGain() * 10;
57           ow()->level += 10;
58           break;
59         case cBonusScore:
60           d.playSoundAt(d.sndGreen, x, y);
61           ow()->score += scoreGain() * 2;
62           break;
63         case cBonusAmmo:
64           d.playSoundAt(d.sndRed, x, y);
65           ow()->score += scoreGain();
66           ow()->gainAmmo();
67           break;
68         }
69 
70       if(gc.regenerate(m))
71         placeBigRandomly(m, 0);
72       clearBig(x, y, cFree, 0);
73       }
74 
75     if(g.map[y][x] == cXunux)
76       destroyAt(x, y, owner, 0);
77 
78     g.mapSet(x,y, ct, owner);
79     }
80 
tryLinesOTetris81   void tryLines(int x, int y) {
82     int x0 = x, x1 = x;
83     int t0 = 3, t1 = 3;
84     while(t0 == 3) {x0--; t0 = tLiningType(x0, y);}
85     while(t1 == 3) {x1++; t1 = tLiningType(x1, y);}
86     if((t0 == 2 && t1 == 2) || (x1-x0 > gc.utetrisMinLength + 1)) {
87       int len = x1-x0-1;
88       ow()->level += len;
89       ow()->score += scoreGain() * len;
90       for(int x2=x0+1; x2<x1; x2++) {
91         int y2 = y;
92         while(1) {
93           int t = tLiningType(x2, y2-1);
94           if(t == 1 || t == 2) {
95             g.mapSet(x2,y2, cFree, 0);
96             break;
97             }
98           else {
99             g.mapSet(x2,y2, g.map[y2-1][x2], g.owner[y2-1][x2]);
100             y2--;
101             }
102           }
103         }
104       }
105     }
106 
putBlockOTetris107   void putBlock(CellType ct) {
108     for(int py=0; py<4; py++) for(int px=0; px<4; px++) if(brick[py][px])
109       putBlock(ct, bx+px, by+py);
110     }
111 
tryLinesOTetris112   void tryLines() {
113     for(int py=0; py<4; py++) for(int px=0; px<4; px++) if(brick[py][px])
114       tryLines(bx+px, by+py);
115     }
116 
takeBlockOTetris117   void takeBlock() {
118     n = 0;
119     for(int py=0; py<4; py++) for(int px=0; px<4; px++) if(brick[py][px]) {
120       int y = by+py, x = bx+px;
121       if(g.map[by+py][bx+px] == cTetris && g.owner[by+py][bx+px] == owner) {
122         g.mapSet(bx+px, by+py, cFree, 0);
123         n++;
124         }
125       else brick[py][px] = false;
126       }
127     }
128 
createNewBrickOTetris129   bool createNewBrick() {
130     char* bricks[7] = {
131       "..#...#...#...#.",
132       ".....##..##.....",
133       ".....#...##..#..",
134       "......#..##..#..",
135       ".....#...##...#.",
136       ".....##..#...#..",
137       ".....##...#...#."
138       };
139     bx = ix;
140     by = iy;
141     int btype = g.rand() % 7;
142     for(int b=0; b<16; b++) brick[b/4][b%4] = bricks[btype][b] == '#';
143     int bf = blockFits();
144     switch(bf) {
145       case 2:
146         putBlock(cTetris);
147         n = 4;
148         break;
149       case 0:
150         g.deleteObject(this);
151         ow()->typeval = -1;
152         break;
153       // just wait in case of 1
154       }
155     }
156 
OTetrisOTetris157   OTetris(int _owner, int _x, int _y) : ix(_x), iy(_y) {
158     owner = _owner;
159     time = g.time;
160     g.objects.push_back(this);
161     n = 0;
162     }
163 
OTetrisOTetris164   OTetris(TBuffer &b) {
165     b.get(owner);
166     b.get(ix); b.get(iy);
167     b.get(bx); b.get(by);
168     b.get(time); b.get(n);
169     for(int ky=0; ky<4; ky++)
170     for(int kx=0; kx<4; kx++) b.get(brick[ky][kx]);
171     }
saveOTetris172   void save(TBuffer &b) {
173     b.putChar(4);
174     b.put(owner);
175     b.put(ix); b.put(iy);
176     b.put(bx); b.put(by);
177     b.put(time); b.put(n);
178     for(int ky=0; ky<4; ky++)
179     for(int kx=0; kx<4; kx++) b.put(brick[ky][kx]);
180     }
181 
goOTetris182   void go() {
183     if(n) takeBlock();
184     if(n) {
185       by++;
186       int bf = blockFits();
187       if(bf == 2)
188         putBlock(cTetris);
189       else if(bf == 1) {
190         by--;
191         putBlock(cTetris);
192         }
193       else {
194         by--;
195         d.playSoundAt(d.sndPlace, bx+1, by+1);
196         putBlock(cTetrisDown);
197         tryLines();
198         n = 0;
199         }
200       }
201     else {
202       createNewBrick();
203       }
204     time += spd() * 5;
205     }
206 
ref1OTetris207   void ref1() {
208     for(int x=0; x<4; x++) for(int y=0; y<2; y++)
209       swap(brick[y][x], brick[3-y][x]);
210     }
211 
ref2OTetris212   void ref2() {
213     for(int x=0; x<4; x++) for(int y=0; y<x; y++)
214       swap(brick[y][x], brick[x][y]);
215     }
216 
reactToKeyOTetris217   void reactToKey(PlayerKey pk, bool pressed) {
218     if(!pressed) return;
219     if(n) switch(pk) {
220       case keyLeft:
221         takeBlock();
222         bx--;
223         if(blockFits() != 2) bx++;
224         putBlock(cTetris);
225         break;
226       case keyRight:
227         takeBlock();
228         bx++;
229         if(blockFits() != 2) bx--;
230         putBlock(cTetris);
231         break;
232       case keyDown:
233         takeBlock();
234         by++;
235         if(blockFits() != 2) by--;
236         putBlock(cTetris);
237         break;
238       case keyFire: case keyWater:
239         takeBlock();
240         while(blockFits()) by++;
241         by--;
242         putBlock(cTetris);
243         break;
244       case keyUp:
245         takeBlock();
246         ref1(); ref2();
247         if(blockFits() != 2) {ref2(); ref1();}
248         putBlock(cTetris);
249         break;
250       case keyEarth:
251         if(ow()->ammo >= ec().ammoPerShoot)
252           d.playSoundAt(d.sndShoot, bx+1, by+1);
253         for(int py=0; py<4; py++) for(int px=0; px<4; px++)
254           if(brick[py][px] && (py == 3 || !brick[py+1][px]) && ow()->useAmmo())
255             new OBullet(owner, Ctr(bx+px), Ctr(by+py) + 2048, 0, bulletSpeed());
256         break;
257       case keyAir:
258         if(ow()->ammo >= ec().ammoPerShoot)
259           d.playSoundAt(d.sndShoot, bx+1, by+1);
260         for(int py=0; py<4; py++) for(int px=0; px<4; px++) if(brick[py][px]) {
261           if((px == 3 || !brick[py][px+1]) && ow()->useAmmo((ec().ammoPerShoot+1)/2))
262             new OBullet(owner, Ctr(bx+px) + 2048, Ctr(by+py), bulletSpeed(), 0);
263           if((px == 0 || !brick[py][px-1]) && ow()->useAmmo((ec().ammoPerShoot+1)/2))
264             new OBullet(owner, Ctr(bx+px) - 2048, Ctr(by+py), -bulletSpeed(), 0);
265           }
266         break;
267       }
268     }
269   };
270