1
2 /**
3 *
4 * @file jj1event.cpp
5 *
6 * Part of the OpenJazz project
7 *
8 * @par History:
9 * - 23rd August 2005: Created level.c
10 * - 1st January 2006: Created events.c from parts of level.c
11 * - 3rd February 2009: Renamed events.c to events.cpp
12 * - 5th February 2009: Added parts of events.cpp and level.cpp to player.cpp
13 * - 11th February 2009: Created bullet.cpp from parts of events.cpp
14 * - 1st March 2009: Created bird.cpp from parts of events.cpp
15 * - 19th March 2009: Created sprite.cpp from parts of event.cpp and player.cpp
16 * - 19th July 2009: Created eventframe.cpp from parts of events.cpp
17 * - 19th July 2009: Renamed events.cpp to event.cpp
18 * - 2nd March 2010: Created guardians.cpp from parts of event.cpp and
19 * eventframe.cpp
20 * - 2nd March 2010: Created bridge.cpp from parts of event.cpp and eventframe.cpp
21 * - 5th February 2011: Moved parts of eventframe.cpp to event.cpp
22 * - 1st August 2012: Renamed event.cpp to jj1event.cpp
23 *
24 * @par Licence:
25 * Copyright (c) 2005-2013 Alister Thomson
26 *
27 * OpenJazz is distributed under the terms of
28 * the GNU General Public License, version 2.0
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 *
34 * @par Description:
35 * Deals with events in ordinary levels.
36 *
37 */
38
39
40 #include "../jj1level.h"
41 #include "jj1event.h"
42
43 #include "io/gfx/video.h"
44 #include "io/sound.h"
45 #include "util.h"
46
47
48 /**
49 * Create event
50 *
51 * @param gX X-coordinate
52 * @param gY Y-coordinate
53 */
JJ1Event(unsigned char gX,unsigned char gY)54 JJ1Event::JJ1Event (unsigned char gX, unsigned char gY) {
55
56 set = level->getEvent(gX, gY);
57
58 x = TTOF(gX);
59 y = TTOF(gY + 1);
60 dx = 0;
61 dy = 0;
62
63 next = level->getEvents();
64 gridX = gX;
65 gridY = gY;
66 flashTime = 0;
67
68 animType = E_NOANIM;
69 anim = NULL;
70 noAnimOffset = false;
71
72 drawnX = x;
73 drawnY = y;
74 width = F32;
75 height = F32;
76
77 return;
78
79 }
80
81
82 /**
83 * Delete all events
84 */
~JJ1Event()85 JJ1Event::~JJ1Event () {
86
87 if (next) delete next;
88
89 return;
90
91 }
92
93
94 /**
95 * Delete this event
96 *
97 * @param permanently Whether or not to delete the event from the level
98 *
99 * @return The next event
100 */
remove(bool permanently)101 JJ1Event* JJ1Event::remove (bool permanently) {
102
103 JJ1Event *oldNext;
104
105 if (permanently) level->clearEvent(gridX, gridY);
106
107 oldNext = next;
108 next = NULL;
109 delete this;
110
111 return oldNext;
112
113 }
114
115
116 /**
117 * Get the next event
118 *
119 * @return The next event
120 */
getNext()121 JJ1Event * JJ1Event::getNext () {
122
123 return next;
124
125 }
126
127
128 /**
129 * Initiate the destruction of the event
130 *
131 * @param ticks Time
132 */
destroy(unsigned int ticks)133 void JJ1Event::destroy (unsigned int ticks) {
134
135 setAnimType(E_LFINISHANIM | (animType & 1));
136
137 level->setEventTime(gridX, gridY, ticks);
138
139 playSound(set->sound);
140
141 return;
142
143 }
144
145
146 /**
147 * Deal with bullet collisions
148 *
149 * @param source Source of the hit(s)
150 * @param hits Number of hits to inflict
151 * @param ticks Current time
152 *
153 * @return Whether or not the hit was successful
154 */
hit(JJ1LevelPlayer * source,int hits,unsigned int ticks)155 bool JJ1Event::hit (JJ1LevelPlayer *source, int hits, unsigned int ticks) {
156
157 int hitsRemaining;
158
159 // Check if event has already been destroyed
160 if (((animType & ~1) == E_LFINISHANIM) || (ticks < flashTime)) return false;
161
162 hitsRemaining = level->hitEvent(gridX, gridY, hits, source, ticks);
163
164 // If the event cannot be hit, do not register hit
165 if (hitsRemaining < 0) return false;
166
167 // Check if the hit has destroyed the event
168 if (hitsRemaining == 0) destroy(ticks);
169
170 // The event has been hit, so it should flash
171 flashTime = ticks + T_FLASH;
172
173 // Register hit
174 return true;
175
176 }
177
178
179 /**
180 * Determine whether or not the event is an enemy
181 *
182 * @return Whether or not the event is an enemy
183 */
isEnemy()184 bool JJ1Event::isEnemy () {
185
186 return set->strength && (set->modifier == 0);
187
188 }
189
190
191 /**
192 * Determine whether or not the event is from the given position
193 *
194 * @return Whether or not the event is from the given position
195 */
isFrom(unsigned char gX,unsigned char gY)196 bool JJ1Event::isFrom (unsigned char gX, unsigned char gY) {
197
198 return (gX == gridX) && (gY == gridY);
199
200 }
201
202
203 /**
204 * Calculate the width and height of the event
205 */
calcDimensions()206 void JJ1Event::calcDimensions () {
207
208 if (animType == E_NOANIM) {
209
210 width = F32;
211 height = F32;
212
213 } else {
214
215 width = ITOF(anim->getWidth());
216 height = ITOF(anim->getHeight());
217
218 // Blank sprites for e.g. invisible springs
219 if ((width == F1) && (height == F1)) {
220
221 width = F32;
222 height = F32;
223
224 }
225
226 }
227
228 return;
229
230 }
231
232
233 /**
234 * Determine whether or not the event is overlapping the given area
235 *
236 * @param areaX The x-coordinate of the left of the area
237 * @param areaY The y-coordinate of the top of the area
238 * @param areaWidth The width of the area
239 * @param areaHeight The height of the area
240 *
241 * @return Whether or not there is an overlap
242 */
overlap(fixed areaX,fixed areaY,fixed areaWidth,fixed areaHeight)243 bool JJ1Event::overlap (fixed areaX, fixed areaY, fixed areaWidth, fixed areaHeight) {
244
245 return (drawnX + width >= areaX) &&
246 (drawnX < areaX + areaWidth) &&
247 (drawnY + height >= areaY) &&
248 (drawnY < areaY + areaHeight);
249
250 }
251
252
253 /**
254 * Sets the animation type and updates the current animation and dimensions
255 *
256 * @param type The new animation type
257 */
setAnimType(unsigned char type)258 void JJ1Event::setAnimType(unsigned char type) {
259
260 if (type == animType) return;
261
262 animType = type;
263
264 if (animType == E_NOANIM) anim = NULL;
265
266 // If there is no shooting animation, use the normal animation instead
267 else if (((animType & ~1) == E_LSHOOTANIM) && (set->anims[animType] == 0))
268 anim = level->getAnim(set->anims[animType & 1] & 0x7F);
269
270 else anim = level->getAnim(set->anims[animType] & 0x7F);
271
272 calcDimensions();
273
274 return;
275
276 }
277
278
279 /**
280 * Sets the animation frame and updates the current dimensions
281 */
setAnimFrame(int frame,bool looping)282 void JJ1Event::setAnimFrame (int frame, bool looping) {
283
284 if (!anim) return;
285
286 anim->setFrame(frame, looping);
287 calcDimensions();
288
289 return;
290
291 }
292
293
294 /**
295 * Functionality required by all event types on each iteration
296 *
297 * @param ticks Time
298 *
299 * @return Animation
300 */
prepareStep(unsigned int ticks)301 JJ1EventType* JJ1Event::prepareStep (unsigned int ticks) {
302
303 // Process the next event
304 if (next) next = next->step(ticks);
305
306 // If the event has been removed from the grid, destroy it
307 if (!set) return NULL;
308
309 // If the event and its origin are off-screen, the event is not in the
310 // process of self-destruction, remove it
311 if (((animType & ~1) != E_LFINISHANIM) &&
312 ((x < viewX - F192) || (x > viewX + ITOF(canvasW) + F192) ||
313 (y < viewY - F160) || (y > viewY + ITOF(canvasH) + F160)) &&
314 ((gridX < FTOT(viewX) - 1) ||
315 (gridX > ITOT(FTOI(viewX) + canvasW) + 1) ||
316 (gridY < FTOT(viewY) - 1) ||
317 (gridY > ITOT(FTOI(viewY) + canvasH) + 1))) return NULL;
318
319 return set;
320
321 }
322
323
324 /**
325 * Draw the event's energy bar
326 *
327 * @param ticks Time
328 */
drawEnergy(unsigned int ticks)329 void JJ1Event::drawEnergy (unsigned int ticks) {
330
331 Anim* miscAnim;
332 int hits;
333
334 if (!set || set->modifier != 8) {
335
336 if (next) next->drawEnergy(ticks);
337
338 return;
339
340 } else if (set->strength) {
341
342 // Draw boss energy bar
343
344 hits = level->getEventHits(gridX, gridY) * 100 / set->strength;
345
346
347 // Devan head
348
349 miscAnim = level->getMiscAnim(MA_DEVHEAD);
350 miscAnim->setFrame(0, true);
351
352 if (ticks < flashTime) miscAnim->flashPalette(0);
353
354 miscAnim->draw(ITOF(canvasW - 44), ITOF(hits + 48));
355
356 if (ticks < flashTime) miscAnim->restorePalette();
357
358
359 // Bar
360 drawRect(canvasW - 40, hits + 40, 12, 100 - hits, (ticks < flashTime)? 0: 32);
361
362 }
363
364 return;
365
366 }
367
368