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 // Bomber & Bomb.
6 
7 struct OBomb : TPlayObject {
8   public:
9   int32 x;
10   int32 y;
11   int32 xtime;
12   int32 range;
13 
OBombOBomb14   OBomb(int _owner, int _x, int _y, int _xtime, int _range) : x(_x), y(_y) {
15     owner = _owner;
16     range = _range;
17     time = g.time;
18     xtime = g.time + _xtime;
19     g.mapSet(x,y, cBomb1, owner);
20     g.objects.push_back(this);
21     }
OBombOBomb22   OBomb(TBuffer &b) {
23     b.get(owner);
24     b.get(x); b.get(y); b.get(time); b.get(xtime); b.get(range);
25     }
saveOBomb26   void save(TBuffer &b) {
27     b.putChar(11);
28     b.put(owner); b.put(x); b.put(y); b.put(time); b.put(xtime); b.put(range);
29     }
goOBomb30   void go() {
31     if(time < xtime && g.map[y][x] != cExplosion) {
32       int phase = (2500 / (xtime-time));
33       g.mapSet(x, y, phase&1 ? cBomb1 : cBomb2, owner);
34       time += 25;
35       if(time > xtime) time = xtime;
36       }
37     else if(time <= xtime) {
38       g.mapSet(x,y, cExplosion, owner);
39       d.playSoundAt(d.sndShoot, x, y);
40       for(int k=0; k<4; k++)
41       for(int r=1; r<=range; r++) {
42         int ax = x+kx[k]*r, ay = y+ky[k]*r;
43         CellType m = bigType(ax, ay);
44         if(isBonus(m)) {
45           clearBig(ax, ay, cFree, 0);
46           if(gc.regenerate(m) && gc.regenerateDestroyed)
47             placeBigRandomly(m, 0);
48           }
49         if(isCannon(m)) {
50           clearBig(ax, ay, cFree, 0);
51           g.mapSet(ax,ay, cExplosion, owner);
52           r=range;
53           }
54         switch(g.map[ay][ax]) {
55           case cExplosion:
56             // might be someone else's
57             break;
58           case cXunux:
59             destroyAt(ax, ay, owner, 0);
60             /* fallthrough */
61           case cFree:
62           case cBomb1:
63           case cBomb2:
64             g.mapSet(ax,ay, cExplosion, owner);
65             break;
66           case cBreakWall:
67           case cSnakeTRON:
68           case cTetrisDown:
69           case cTetris:
70           case cCastleWall:
71           case cXunuxStable:
72             g.mapSet(ax,ay, cExplosion, owner);
73             r=range;
74             break;
75           case cSnakeHead:
76             g.mapSet(ax,ay, cSnakeDead, owner);
77             r=range;
78             break;
79           default:
80             r=range;
81             break;
82           }
83         }
84       xtime = time; // if it exploded due to another's explosion
85       time += 750;
86       ow()->ammo += ec().ammoPerShoot;
87       }
88     else if(time > xtime) {
89       g.mapSet(x,y, cFree, 0);
90       for(int k=0; k<4; k++)
91       for(int r=1; r<=range; r++) {
92         int ax = x+kx[k]*r, ay = y+ky[k]*r;
93         if(ax == 0 || ay == 0 || ax == g.sizeX-1 || ay == g.sizeY-1) continue;
94         if(g.map[ay][ax] == cExplosion)
95           g.mapSet(ax,ay, cFree, 0);
96         }
97       g.deleteObject(this);
98       }
99     }
100   };
101 
102 struct OBomber : TPlayObject {
103   public:
104   int x;
105   int y;
OBomberOBomber106   OBomber(int _owner, int _x, int _y) :
107     x(_x), y(_y) {
108     owner = _owner;
109     time = g.time;
110     g.objects.push_back(this);
111     }
112 
OBomberOBomber113   OBomber(TBuffer &b) {
114     b.get(owner);
115     b.get(x); b.get(y);
116     b.get(time);
117     }
saveOBomber118   void save(TBuffer &b) {
119     b.putChar(10);
120     b.put(owner);
121     b.put(x); b.put(y);
122     b.put(time);
123     }
124 
checkGoOBomber125   bool checkGo(int cx, int cy) {
126     cx = DeCtr(cx);
127     cy = DeCtr(cy);
128     // cannot block self with bomb
129     if(cx == DeCtr(x) && cy == DeCtr(y)) return true;
130     if(g.map[cy][cx] == cFree) return true;
131     if(g.map[cy][cx] == cExplosion) return true;
132     CellType m = bigType(cx, cy);
133     if(isBonus(m)) return true;
134     return false;
135     }
136 
tryToGoOBomber137   void tryToGo(int k) {
138     int rx = x + kx[k] * (384 + 128);
139     int ry = y + ky[k] * (384 + 128);
140     bool u0 = checkGo(rx - ky[k] * 384, ry + kx[k] * 384);
141     bool u1 = checkGo(rx + ky[k] * 384, ry - kx[k] * 384);
142     if(u0 && u1) {
143       x += kx[k] * 128;
144       y += ky[k] * 128;
145       }
146     }
147 
goOBomber148   void go() {
149     for(int k=0; k<4; k++) if(g.pl[owner]->key[k]) tryToGo(k);
150     time += spd()/2;
151     int nx = DeCtr(x);
152     int ny = DeCtr(y);
153     CellType m = bigType(nx, ny);
154     if(isBonus(m)) {
155       switch(m) {
156         case cBonusAmmo:
157           d.playSoundAt(d.sndRed, nx, ny);
158           ow()->score += scoreGain();
159           ow()->gainAmmo();
160           break;
161         case cBonusLevel:
162           d.playSoundAt(d.sndBlue, nx, ny);
163           ow()->score += scoreGain() * 10;
164           ow()->level++;
165           break;
166         case cBonusScore:
167           d.playSoundAt(d.sndGreen, nx, ny);
168           ow()->score += scoreGain();
169           ow()->typeval += gc.bombBonusRange;
170           break;
171         }
172       if(gc.regenerate(m)) placeBigRandomly(m, 0);
173       clearBig(nx, ny, cFree, 0);
174       }
175     if(g.map[ny][nx] != cFree && g.map[ny][nx] != cBomb1 && g.map[ny][nx] != cBomb2) {
176       d.playSoundAt(d.sndDeath, nx, ny);
177       killedBy(g.owner[ny][nx]);
178       return;
179       }
180     }
181 
drawOBomber182   void draw() {
183     DIc(icBomber).drawAtCentered(CTG(x), CTG(y));
184     }
reactToKeyOBomber185   void reactToKey(PlayerKey pk, bool pressed) {
186     if(!pressed) return;
187     int nx = DeCtr(x);
188     int ny = DeCtr(y);
189     if(pk == keyFire && g.map[ny][nx] == cFree && ow()->useAmmo()) {
190       d.playSoundAt(d.sndPlace, nx, ny);
191       new OBomb(owner, nx, ny, 50 * spd(), ow()->typeval);
192       }
193     }
reactToBulletOBomber194   bool reactToBullet(OBullet *bullet) {
195     if(calcDistance(x-bullet->x, y-bullet->y) < 512) {
196       d.playSoundAt(d.sndDeath, x, y);
197       killedBy(bullet->owner);
198       return true;
199       }
200     return false;
201     }
reactToCannonOBomber202   void reactToCannon(OCannonball *ball) {
203     if(calcDistance(x-ball->tx, y-ball->ty) < 512 + 512) {
204       d.playSoundAt(d.sndDeath, x, y);
205       killedBy(ball->owner);
206       }
207     }
reactToThrusterOBomber208   bool reactToThruster(OThruster *enemy) {
209     if(calcDistance(x-enemy->x, y-enemy->y) < 512 + 1024) {
210       d.playSoundAt(d.sndDeath, x, y);
211       killedBy(enemy->owner);
212       // thruster is larger... it survives
213       }
214     return false;
215     }
smashedByBallOBomber216   bool smashedByBall(OBall *enemy) {
217     if(calcDistance(x-enemy->x, y-enemy->y) < 512 + 512) {
218       d.playSoundAt(d.sndDeath, x, y);
219       killedBy(enemy->owner);
220       return true;
221       }
222     return false;
223     }
catchesRopeOBomber224   bool catchesRope(int rx, int ry) {
225     if(calcDistance(x-rx, y-ry) < 512) {
226       return true;
227       }
228     return false;
229     }
230   void pullRope(OWorm *worm, int ddx, int ddy);
231   };
232