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