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 // Castle & Cannonball. 6 7 #include <math.h> 8 9 bool flags[128][128]; 10 11 int qs, qe; 12 int qx[20000], qy[20000]; 13 14 int bre; 15 int brx[20000], bry[20000]; 16 17 struct OCannonball : TPlayObject { 18 public: 19 int32 fx, fy, tx, ty, stime; 20 getOxOCannonball21 int getOx() { 22 return Ctr(fx)+512; 23 } 24 getOyOCannonball25 int getOy() { 26 return Ctr(fy)+512; 27 } 28 OCannonballOCannonball29 OCannonball(int _owner, int _fx, int _fy, int _tx, int _ty) : 30 fx(_fx), fy(_fy), tx(_tx), ty(_ty) { 31 owner = _owner; 32 stime = g.time; 33 time = stime + (calcDistance(getOx()-tx, getOy()-ty)*spd()) / 500; 34 g.objects.push_back(this); 35 } OCannonballOCannonball36 OCannonball(TBuffer &b) { 37 b.get(owner); b.get(time); b.get(stime); 38 b.get(fx); b.get(fy); b.get(tx); b.get(ty); 39 } saveOCannonball40 void save(TBuffer &b) { 41 b.putChar(7); 42 b.put(owner); b.put(time); b.put(stime); 43 b.put(fx); b.put(fy); b.put(tx); b.put(ty); 44 } goOCannonball45 void go() { 46 if(g.map[fy][fx] == cCannonA) 47 g.mapSet(fx,fy, cCannonF, g.owner[fy][fx]); 48 49 for(int o=0; o<size(g.objects); o++) if(g.objects[o]) 50 g.objects[o]->reactToCannon(this); 51 52 destroyAt(DeCtr(tx), DeCtr(ty), owner); 53 g.deleteObject(this); 54 } drawOCannonball55 void draw() { 56 int x = getOx(); 57 int y = getOy(); 58 x = x + ((tx-x) * (g.time-stime)) / (time-stime); 59 y = y + ((ty-y) * (g.time-stime)) / (time-stime); 60 DIc(icBall).drawAtCentered(CTG(x), CTG(y)); 61 } 62 }; 63 64 struct OCastle : TPlayObject { 65 public: 66 int32 bx, by; // brick coordinates 67 int32 cx, cy; // cannon coordinates 68 int32 tx, ty; // target coordinates 69 int32 fx, fy; // cannon-to-fire coordinates 70 bool brick[3][3]; 71 int32 utime; 72 int32 mode; 73 ref1OCastle74 void ref1() { 75 for(int x=0; x<3; x++) swap(brick[0][x], brick[2][x]); 76 } 77 ref2OCastle78 void ref2() { 79 for(int x=0; x<3; x++) for(int y=0; y<x; y++) 80 swap(brick[y][x], brick[x][y]); 81 } 82 createNewBrickOCastle83 bool createNewBrick() { 84 char* bricks[11] = { 85 ".#..#..##", 86 ".#..#..##", 87 ".#..#.##.", 88 ".#.##....", 89 ".#.##....", 90 ".#.##....", 91 ".#..#..#.", 92 ".#..#..#.", 93 "##..#.##.", 94 "##..#.##.", 95 "....#...."}; 96 97 int r = g.rand() % 11; 98 for(int y=0; y<3; y++) for(int x=0; x<3; x++) 99 brick[y][x] = bricks[r][y*3+x] == '#'; 100 for(int u=g.rand() % 4; u<4; u++) ref1(), ref2(); 101 } 102 OCastleOCastle103 OCastle(int _owner, int _x, int _y) { 104 owner = _owner; 105 time = g.time; 106 utime= g.time; 107 fx = 0; 108 fy = 0; 109 cx = _x; 110 cy = _y; 111 bx = _x-1; 112 by = _y-1; 113 tx = Ctr(_x); 114 ty = Ctr(_y); 115 mode = 0; 116 createNewBrick(); 117 g.objects.push_back(this); 118 } 119 OCastleOCastle120 OCastle(TBuffer &b) { 121 b.get(owner); b.get(time); b.get(mode); 122 b.get(bx); b.get(by); b.get(cx); b.get(cy); b.get(tx); b.get(ty); 123 b.get(fx); b.get(fy); b.get(utime); 124 for(int ky=0; ky<3; ky++) 125 for(int kx=0; kx<3; kx++) b.get(brick[ky][kx]); 126 } saveOCastle127 void save(TBuffer &b) { 128 b.putChar(6); 129 b.put(owner); b.put(time); b.put(mode); 130 b.put(bx); b.put(by); b.put(cx); b.put(cy); b.put(tx); b.put(ty); 131 b.put(fx); b.put(fy); b.put(utime); 132 for(int ky=0; ky<3; ky++) 133 for(int kx=0; kx<3; kx++) b.put(brick[ky][kx]); 134 } 135 checkEnclosedOCastle136 void checkEnclosed(int rx, int ry) { 137 if(!isCastlable(g.map[ry][rx])) return; 138 if(g.owner[ry][rx] == owner) return; // already ours... 139 qs = 0; 140 qe = 1; 141 qx[0] = rx; qy[0] = ry; 142 bool ok = true; 143 while(qs<qe) { 144 int rx = qx[qs]; 145 int ry = qy[qs]; 146 qs++; 147 if(g.map[ry][rx] == cPermaWall) {ok = false; break;} 148 if(isCastlable(g.map[ry][rx])) { 149 for(int lx=rx-1; lx<=rx+1; lx++) 150 for(int ly=ry-1; ly<=ry+1; ly++) { 151 if(flags[ly][lx]) continue; 152 flags[ly][lx] = true; 153 qx[qe] = lx; qy[qe] = ly; 154 qe++; 155 } 156 } 157 } 158 if(ok) { 159 for(int q=0; q<qe; q++) { 160 rx = qx[q]; ry = qy[q]; 161 if(isCastlable(g.map[ry][rx])) g.mapSet(rx,ry, g.map[ry][rx], owner); 162 flags[ry][rx] = false; 163 } 164 } 165 else for(int q=0; q<qe; q++) flags[qy[q]][qx[q]] = false; 166 } 167 placeBrickOCastle168 void placeBrick() { 169 bool ok = false; 170 for(int ky=0; ky<3; ky++) 171 for(int kx=0; kx<3; kx++) if(brick[ky][kx]) { 172 if(g.map[by+ky][bx+kx] != cFree) return; 173 for(int ly=-2; ly<3; ly++) 174 for(int lx=-2; lx<3; lx++) 175 if(by+ky+ly >= 0 && by+ky+ly < g.sizeY && 176 bx+kx+lx >= 0 && bx+kx+lx < g.sizeX && 177 g.owner[by+ky+ly][bx+kx+lx] == owner 178 ) 179 ok = true; 180 } 181 if(ok) { 182 d.playSoundAt(d.sndPlace, bx+1, by+1); 183 for(int ky=0; ky<3; ky++) 184 for(int kx=0; kx<3; kx++) if(brick[ky][kx]) { 185 g.mapSet(bx+kx, by+ky, cCastleWall, owner); 186 for(int tx=0; tx<3; tx++) 187 for(int ty=0; ty<3; ty++) 188 checkEnclosed(bx+kx+tx-1, by+ky+ty-1); 189 } 190 } 191 createNewBrick(); 192 } 193 placeCannonOCastle194 void placeCannon() { 195 for(int ky=0; ky<2; ky++) 196 for(int kx=0; kx<2; kx++) 197 if(g.map[cy+ky][cx+kx] != cFree || g.owner[cy+ky][cx+kx] != owner) 198 return; 199 if(ow()->useAmmo(gc.ammoPerCannon)) { 200 d.playSoundAt(d.sndPlace, fx, fy); 201 placeBig(cx, cy, cCannonF, owner); 202 } 203 } 204 fireCannonOCastle205 void fireCannon() { 206 if(fx == 999 || fy == 999) return; 207 if(g.map[fy][fx] != cCannonF) return; 208 if(g.owner[fy][fx] != owner) return; 209 if(ow()->useAmmo()) { 210 g.mapSet(fx,fy, cCannonA, owner); 211 d.playSoundAt(d.sndShoot, fx, fy); 212 new OCannonball(owner, fx, fy, tx, ty); 213 } 214 } 215 reactToKeyOCastle216 void reactToKey(PlayerKey pk, bool pressed) { 217 if(!pressed) return; 218 if(pk == keyEarth) { 219 mode++; 220 mode %= 3; 221 } 222 else switch(mode) { 223 case 0: 224 switch(pk) { 225 case keyLeft: 226 if(bx>0) bx--; 227 break; 228 case keyRight: 229 if(bx<g.sizeX-3) bx++; 230 break; 231 case keyDown: 232 if(by<g.sizeY-3) by++; 233 break; 234 case keyUp: 235 if(by>0) by--; 236 break; 237 case keyFire: 238 placeBrick(); 239 break; 240 case keyAir: 241 ref1(); ref2(); 242 break; 243 case keyWater: 244 ref2(); ref1(); 245 break; 246 } 247 break; 248 case 1: 249 switch(pk) { 250 case keyLeft: 251 if(cx>1) cx--; 252 break; 253 case keyRight: 254 if(cx<g.sizeX-2) cx++; 255 break; 256 case keyDown: 257 if(cy<g.sizeY-2) cy++; 258 break; 259 case keyUp: 260 if(cy>1) cy--; 261 break; 262 case keyFire: 263 case keyAir: 264 case keyWater: 265 placeCannon(); 266 break; 267 } 268 break; 269 case 2: 270 switch(pk) { 271 case keyFire: 272 fireCannon(); 273 break; 274 } 275 break; 276 } 277 } 278 cannonDistanceOCastle279 int cannonDistance(int x, int y) { 280 return calcDistance(tx-Ctr(x)-512, ty-Ctr(y)-512); 281 } 282 manageCastleOCastle283 void manageCastle() { 284 int levels=0, scores=0, ammos=0; 285 bre = 0; 286 fx = 999, fy = 999; 287 for(int y=1; y<g.sizeY-1; y++) 288 for(int x=1; x<g.sizeX-1; x++) 289 if(g.owner[y][x] == owner && isCastlable(g.map[y][x])) { 290 if(g.map[y][x] == cBonusLevel) levels++; 291 if(g.map[y][x] == cBonusScore) scores++; 292 if(g.map[y][x] == cBonusAmmo) ammos++; 293 if(g.map[y][x] == cCannonF) { 294 if(cannonDistance(x,y) < cannonDistance(fx, fy)) 295 fx=x, fy=y; 296 } 297 for(int ay=y-1; ay<=y+1; ay++) 298 for(int ax=x-1; ax<=x+1; ax++) { 299 if(isCastlable(g.map[ay][ax]) && g.owner[ay][ax] == 0) { 300 // maybe everything is OK... 301 checkEnclosed(ax, ay); 302 // ... or maybe not 303 if(g.owner[ay][ax] == 0) { 304 brx[bre] = x; bry[bre] = y; bre++; 305 } 306 } 307 } 308 } 309 for(int t=0; t<bre; t++) { 310 int ax = brx[t], ay = bry[t]; 311 g.mapSet(ax, ay, g.map[ay][ax], 0); 312 } 313 ow()->level = levels; 314 int32& tv (ow()->typeval); 315 if(scores == 0) { 316 tv -= gc.castleRotSpeed; 317 if(tv <= 0) { 318 // dies without sound 319 killedBy(0); 320 ow()->ammo = 0; 321 return; 322 } 323 } 324 scores *= gc.castlePowerBase; 325 if(tv < scores) { 326 tv += gc.castleRegenSpeed; 327 if(tv > scores) tv = scores; 328 } 329 ow()->ammo += ammos * ec().bonusAmmo; 330 } 331 goOCastle332 void go() { 333 if(time >= utime) { manageCastle(); utime = time + 200; } 334 if(mode == 2) { 335 int spd = 128; 336 if(ow()->key[keyAir]) spd *= 2; 337 if(ow()->key[keyWater]) spd *= 2; 338 if(ow()->key[keyRight] && tx < g.sizeX*1024 - 2048) 339 tx += spd; 340 if(ow()->key[keyDown] && ty < g.sizeY*1024 - 2048) 341 ty += spd; 342 if(ow()->key[keyLeft] && tx >= 2048) 343 tx -= spd; 344 if(ow()->key[keyUp] && ty >= 2048) 345 ty -= spd; 346 } 347 time += 10; 348 } 349 drawOCastle350 void draw() { 351 switch(mode) { 352 case 0: 353 for(int y=0; y<3; y++) 354 for(int x=0; x<3; x++) 355 if(brick[y][x]) { 356 DIc(icCastle).drawAtCentered( 357 d.Res * (x+bx) + d.Res/2, 358 d.Res * (y+by) + d.Res/2 359 ); 360 } 361 break; 362 case 1: 363 DIc(icCannonP).drawAtCentered( 364 d.Res * cx + d.Res, 365 d.Res * cy + d.Res 366 ); 367 break; 368 case 2: 369 DIc(icTarget).drawAtCentered(CTG(tx), CTG(ty)); 370 break; 371 } 372 } 373 }; 374