1 /*************************************************************************
2 
3                          "I Have No Tomatoes"
4                   Copyright (c) 2004, Mika Halttunen
5 
6  This software is provided 'as-is', without any express or implied
7  warranty. In no event will the authors be held liable for any damages
8  arising from the use of this software.
9 
10  Permission is granted to anyone to use this software for any purpose,
11  including commercial applications, and to alter it and redistribute
12  it freely, subject to the following restrictions:
13 
14     1. The origin of this software must not be misrepresented; you must
15     not claim that you wrote the original software. If you use this
16     software in a product, an acknowledgment in the product documentation
17     would be appreciated but is not required.
18 
19     2. Altered source versions must be plainly marked as such, and must
20     not be misrepresented as being the original software.
21 
22     3. This notice may not be removed or altered from any source
23     distribution.
24 
25 
26  Mika Halttunen <lsoft@mbnet.fi>
27 
28 *************************************************************************/
29 
30 #include <stdio.h>
31 #include "SDL.h"
32 #include "SDL_opengl.h"
33 #include "SDL_image.h"
34 #include "mymath.h"
35 #include "tilemap.h"
36 #include "particle.h"
37 #include "texture.h"
38 #include "effects.h"
39 
40 
41 // Create the teleport effect
create_teleport_effect(int x,int y)42 void create_teleport_effect(int x, int y) {
43 
44 	// Add the big glow particle
45 	VECT pos(x + 0.5f, 0.5f, y + 0.5f);
46 	VECT dir = 0.0f;
47 	float c1[4] = { 1.0f, 1.0f, 0.3f, 1.0f };
48 	float c2[4] = { 1, 1, 0, 0 };
49 //	float c1[4] = { 0.3f, 0.8f, 1.0f, 1.0f };
50 //	float c2[4] = { 0, 0, 1, 0 };
51 	add_particle(pos, dir, 60, 2.0f, 1.0f, c1, c2, part_glow);
52 
53 	// Create those "fire lines"
54 	for(int f=0; f < RAND(5,6); f++) {
55 	    // Choose the direction
56 		VECT dir;
57 		dir.x = RANDF(-0.5f, 0.5f);
58 		dir.y = RANDF(0.05f, 0.5f);
59 		dir.z = RANDF(-0.5f, 0.5f);
60 		normalize(dir);
61 
62 		// Create the particles
63 		int max = RAND(25, 50);
64 		for(int i=0; i < max; i++) {
65 			VECT p(x + 0.5f, 0.0f, y + 0.5f);
66 			p += (dir * (float)i * 0.1f);
67 			VECT d = 0.0f;
68 			float s = (float)i / (float)max;
69 			add_particle(p, d, RAND(40,80), 0.5f * (1.0f-s), 0.00f, c1, c2, part_glow);
70 		}
71 
72 	}
73 
74 }
75 
76 
77 // Create some particle fire
create_fire(VECT pos)78 void create_fire(VECT pos) {
79 	VECT ppos = pos;
80 
81 	// Create some particle fire
82 	for(int i=0; i<RAND(3,7); i++) {
83 		ppos = pos;
84 		ppos.x += RANDF(-0.4f, 0.4f);
85 		ppos.y += RANDF(-0.3f, 0.3f);
86 		ppos.z += RANDF(-0.4f, 0.4f);
87 		VECT dir(RANDF(-0.01f,0.01f), RANDF(0.05f,0.15f), RANDF(-0.01f,0.01f));
88 		float c1[4] = { 1, 0.5f, 0.1f, 1 };
89 		float c2[4] = { 1, 0.1f, 0.1f, 0.1f };
90 		add_particle(ppos, dir, RAND(20,35), 0.3f, 0.1f, c1, c2, part_fire);
91 	}
92 
93 	// Create smoke
94 	if(RAND(0,100) > 50) {
95 		pos.y += 0.2f;
96 		pos.x += RANDF(-0.3f, 0.3f);
97 		pos.y += RANDF(0.1f, 0.5f);
98 		pos.z += RANDF(-0.3f, 0.3f);
99 		VECT dir(RANDF(-0.01f,0.01f), RANDF(0.05f,0.1f), RANDF(-0.01f,0.01f));
100 		float c1[4] = { 0.5f, 0.1f, 0.1f, 1 };
101 		float c2[4] = { 0.1f, 0.1f, 0.1f, 0 };
102 		add_particle(pos, dir, RAND(20,35), 0.2f, 0.4f, c1, c2, part_smoke, true);
103 	}
104 }
105 
106 
107 // Helper function for the lightning effect.
108 // Creates an recursive lightning bolt
light_bolt(VECT pos1,VECT pos2,int points,float noise,float thickness,int level,float color[4])109 void light_bolt(VECT pos1, VECT pos2, int points, float noise, float thickness, int level, float color[4]) {
110 	if(level > 6)
111 		return;			// Don't recurse too deeply
112 
113 	// Create the points array
114 	VECT *point = new VECT[points];
115 	if(!point)
116 		return;
117 
118 	// Define the end points
119 	point[0] = pos1;
120 	point[points-1] = pos2;
121 
122 	// Compute the direction from pos1 to pos2
123 	VECT dir = pos2 - pos1;
124 	float dist = vector_length(dir);
125 	float step = dist / points;
126 	normalize(dir);
127 
128 	// Make a straight line between pos1 and pos2, and randomize it a bit
129 	for(int f=1; f < points-1; f++) {
130 		point[f] = point[f-1] + step * dir;
131 
132 		point[f].x += RANDF(-noise, noise);
133 		point[f].y += RANDF(-noise, noise);
134 		point[f].z += RANDF(-noise, noise);
135 
136 		// Create some recursive bolts
137 		if(RAND(0,100) > 45) {
138 			// Choose a destination which isn't too close to the original point
139 			VECT dest;
140 			dest.x = RANDF(-noise,noise);
141 			dest.y = RANDF(-noise,noise);
142 			dest.z = RANDF(-noise,noise);
143 			bool ok = false;
144 			while(!ok) {
145 				float bdist = vector_length(VECT(dest - point[f]));
146 				float rad = noise * 0.5f;
147 				if(bdist > rad) {
148 					// Also try to steer the bolts towards the ground
149 					if((point[f].y + dest.y) < point[f].y)
150 						ok = true;
151 					else
152 						ok = false;
153 				}
154 				if(!ok) {
155 					dest.x = RANDF(-noise,noise);
156 					dest.y = RANDF(-noise,noise);
157 					dest.z = RANDF(-noise,noise);
158 				}
159 			}
160 
161 			dest *= RANDF(3.0f, 7.0f);
162 			light_bolt(point[f], point[f] + dest, int(points * 0.65f), noise * 0.5f, thickness * 0.5f, level + 1, color);
163 		}
164 	}
165 
166 	glColor4fv(color);
167 	glLineWidth(thickness);
168 	glBegin(GL_LINE_STRIP);
169 	for(int f=0; f<points; f++) {
170 	//for(int f=0; f<points-1; f++) {
171 		glVertex3f(point[f].x, point[f].y, point[f].z);
172 		//glVertex3f(point[f+1].x, point[f+1].y, point[f+1].z);
173 	}
174 	glEnd();
175 
176 	// Draw some glows
177 	if(level == 0) {
178 		BIND_TEXTURE(part_glow);
179 		glColor4f(.4f, .8f, 1, RANDF(.15f,.25f));
180 		for(int f=0; f<points; f++) {
181 			glPushMatrix();
182 			glTranslatef(point[f].x, point[f].y, point[f].z);
183 			// Negate the camera rotation
184 			glRotatef(45.0f, 0,1,0);
185 			glRotatef(-30.0f, 1,0,0);
186 			glBegin(GL_TRIANGLE_STRIP);
187 				glTexCoord2f(1,1); glVertex3f( 1,  1,  1);
188 				glTexCoord2f(0,1); glVertex3f(-1,  1,  1);
189 				glTexCoord2f(1,0); glVertex3f( 1, -1, -1);
190 				glTexCoord2f(0,0); glVertex3f(-1, -1, -1);
191 			glEnd();
192 			glPopMatrix();
193 		}
194 		BIND_TEXTURE(0);
195 	}
196 
197 	delete [] point;
198 }
199 
200 
201 // The lightning effect
draw_lightning(VECT pos1,VECT pos2,float noise1,float noise2)202 void draw_lightning(VECT pos1, VECT pos2, float noise1, float noise2) {
203 
204 	glDisable(GL_DEPTH_TEST);
205 	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
206 	BIND_TEXTURE(0);
207 
208 	// Draw two bolts
209 	float color[4] = { .5f, .8f, 1, 1 };
210 	light_bolt(pos1, pos2, 15, noise1, 5, 0, color);		// noise: 0.35f
211 
212 	float color2[4] = { .2f, .6f, 1, 1 };
213 	light_bolt(pos1, pos2, 10, noise2, 3, 1, color2);		// noise: 0.20f
214 
215 	// Draw the end point glows
216 	BIND_TEXTURE(part_glow);
217 	glColor4f(.4f, .8f, 1, RANDF(.5f,1));
218 	glPushMatrix();
219 	glTranslatef(pos1.x, pos1.y, pos1.z);
220 	// Negate the camera rotation
221 	glRotatef(45.0f, 0,1,0);
222 	glRotatef(-30.0f, 1,0,0);
223 	glBegin(GL_TRIANGLE_STRIP);
224 		glTexCoord2f(1,1); glVertex3f( 1.2f,  1.2f,  1.2f);
225 		glTexCoord2f(0,1); glVertex3f(-1.2f,  1.2f,  1.2f);
226 		glTexCoord2f(1,0); glVertex3f( 1.2f, -1.2f, -1.2f);
227 		glTexCoord2f(0,0); glVertex3f(-1.2f, -1.2f, -1.2f);
228 	glEnd();
229 	glPopMatrix();
230 
231 /*	glPushMatrix();
232 	glTranslatef(pos2.x, pos2.y, pos2.z);
233 	// Negate the camera rotation
234 	glRotatef(45.0f, 0,1,0);
235 	glRotatef(-30.0f, 1,0,0);
236 	glBegin(GL_TRIANGLE_STRIP);
237 		glTexCoord2f(1,1); glVertex3f( 1.2f,  1.2f,  1.2f);
238 		glTexCoord2f(0,1); glVertex3f(-1.2f,  1.2f,  1.2f);
239 		glTexCoord2f(1,0); glVertex3f( 1.2f, -1.2f, -1.2f);
240 		glTexCoord2f(0,0); glVertex3f(-1.2f, -1.2f, -1.2f);
241 	glEnd();
242 	glPopMatrix();
243 */
244 	glEnable(GL_DEPTH_TEST);
245 }
246 
247 
248 // Create an explosion to a tile
create_explosion(int x,int y,int type)249 void create_explosion(int x, int y, int type) {
250 	int p;
251 	if(type == EXP_BOMB_NORMAL) {
252 		for(p = 0; p < RAND(20,40); p++) {
253 			// Add the explosion flames
254 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
255 			VECT dir;
256 			dir.x = RANDF(-0.01f, 0.01f);
257 			dir.y = RANDF(0.0f, 0.1f);
258 			dir.z = RANDF(-0.01f, 0.01f);
259 			float c1[4] = { 1, 0.3f, 0.2f, 1 };
260 			float c2[4] = { 1, 0, 0, 0 };
261 			add_particle(pos, dir, RAND(10,60), 0.2f, 0.8f, c1, c2, part_explo);
262 		}
263 		for(p = 0; p < RAND(10,30); p++) {
264 			// Add the sparks
265 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
266 			VECT dir;
267 			dir.x = RANDF(-0.05f, 0.05f);
268 			dir.y = RANDF(0.0f, 0.1f);
269 			dir.z = RANDF(-0.05f, 0.05f);
270 			float c1[4] = { 1, 0.7f, 0.3f, 1 };
271 			float c2[4] = { 0, 0, 1, 0 };
272 			add_particle(pos, dir, RAND(20,70), 0.05f, 0.01f, c1, c2, part_spark);
273 		}
274 	}
275 
276 	if(type == EXP_BOMB_FLOWER) {
277 		for(p = 0; p < RAND(10,30); p++) {
278 			// Add the explosion flames
279 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
280 			VECT dir;
281 			dir.x = RANDF(-0.01f, 0.01f);
282 			dir.y = RANDF(0.0f, 0.1f);
283 			dir.z = RANDF(-0.01f, 0.01f);
284 			float c1[4] = { 0.5f, 0, 1, 1 };
285 			float c2[4] = { 0.2f, 1, 0.2f, 0 };
286 			add_particle(pos, dir, RAND(10,60), 0.2f, 0.8f, c1, c2, part_explo);
287 		}
288 		for(p = 0; p < RAND(1,5); p++) {
289 			// Add the flowers
290 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
291 			VECT dir;
292 			dir.x = RANDF(-0.05f, 0.05f);
293 			dir.y = RANDF(0.0f, 0.1f);
294 			dir.z = RANDF(-0.05f, 0.05f);
295 			float c1[4] = { 1, 1, 1, 1 };
296 			float c2[4] = { 1, 1, 1, 0 };
297 			add_particle(pos, dir, RAND(50,100), 0.5f, 0.1f, c1, c2, part_flower, true);
298 		}
299 	}
300 
301 	else if(type == EXP_BOMB_CENTER) {
302 		for(p = 0; p < RAND(30,70); p++) {
303 			// Add the explosion flames
304 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
305 			VECT dir;
306 			dir.x = RANDF(-0.01f, 0.01f);
307 			dir.y = RANDF(0.0f, 0.1f);
308 			dir.z = RANDF(-0.01f, 0.01f);
309 			float c1[4] = { 1, 0.7f, 0.3f, 1 };
310 			float c2[4] = { 1, 0, 0, 0 };
311 			add_particle(pos, dir, RAND(10,60), 0.2f, 0.8f, c1, c2, part_explo);
312 		}
313 		for(p = 0; p < RAND(10,40); p++) {
314 			// Add the sparks
315 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
316 			VECT dir;
317 			dir.x = RANDF(-0.05f, 0.05f);
318 			dir.y = RANDF(0.0f, 0.1f);
319 			dir.z = RANDF(-0.05f, 0.05f);
320 			float c1[4] = { 1, 0.7f, 0.3f, 1 };
321 			float c2[4] = { 0, 0, 1, 0 };
322 			add_particle(pos, dir, RAND(20,70), 0.05f, 0.01f, c1, c2, part_spark);
323 		}
324 	}
325 
326 	else if(type == EXP_BOMB_CENTER_FLOWER) {
327 		for(p = 0; p < RAND(20,30); p++) {
328 			// Add the explosion flames
329 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
330 			VECT dir;
331 			dir.x = RANDF(-0.01f, 0.01f);
332 			dir.y = RANDF(0.0f, 0.1f);
333 			dir.z = RANDF(-0.01f, 0.01f);
334 			float c1[4] = { 0.3f, 1, 0.3f, 1 };
335 			float c2[4] = { .5f, 0, 1, 0 };
336 			add_particle(pos, dir, RAND(10,60), 0.2f, 0.8f, c1, c2, part_explo);
337 		}
338 		for(p = 0; p < RAND(1,5); p++) {
339 			// Add the flowers
340 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
341 			VECT dir;
342 			dir.x = RANDF(-0.05f, 0.05f);
343 			dir.y = RANDF(0.0f, 0.1f);
344 			dir.z = RANDF(-0.05f, 0.05f);
345 			float c1[4] = { 1, 1, 1, 1 };
346 			float c2[4] = { 1, 1, 1, 0 };
347 			add_particle(pos, dir, RAND(50,100), 0.5f, 0.1f, c1, c2, part_flower, true);
348 		}
349 	}
350 
351 	else if(type == EXP_NAPALM) {
352 		for(p = 0; p < RAND(20,50); p++) {
353 			// Add the explosion flames
354 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
355 			VECT dir;
356 			dir.x = RANDF(-0.01f, 0.01f);
357 			dir.y = RANDF(0.0f, 0.1f);
358 			dir.z = RANDF(-0.01f, 0.01f);
359 			float c1[4] = { 1, 0.3f, 0.2f, 1 };
360 			float c2[4] = { 1, 0, 0, 0 };
361 			add_particle(pos, dir, RAND(10,60), 0.2f, 0.8f, c1, c2, part_explo);
362 		}
363 		for(p = 0; p < RAND(10,30); p++) {
364 			// Add the sparks
365 			VECT pos(x + 0.5f, 0.0f, y + 0.5f);
366 			VECT dir;
367 			dir.x = RANDF(-0.05f, 0.05f);
368 			dir.y = RANDF(0.0f, 0.1f);
369 			dir.z = RANDF(-0.05f, 0.05f);
370 			float c1[4] = { 1, 0.7f, 0.3f, 1 };
371 			float c2[4] = { 0, 0, 1, 0 };
372 			add_particle(pos, dir, RAND(20,70), 0.05f, 0.01f, c1, c2, part_spark);
373 		}
374 	}
375 }
376