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