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