JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
engine dots push rocks
[vor.git] / rocks.c
1 #include <SDL_image.h>
2 #include <math.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "common.h"
7 #include "config.h"
8 #include "file.h"
9 #include "globals.h"
10 #include "mt.h"
11 #include "rocks.h"
12 #include "sprite.h"
13
14 static struct rock rocks[MAXROCKS];
15 static struct rock prototypes[NROCKS];
16
17 // timers for rock generation.
18 static float rtimers[4];
19
20 uint32_t nrocks = I_ROCKS;
21 float nrocks_timer = 0;
22 float nrocks_inc_ticks = 2*60*20/(F_ROCKS-I_ROCKS);
23
24 // constants for rock generation.
25 #define KH (32*20)  // 32 s for a speed=1 rock to cross the screen horizontally.
26 #define KV (24*20)  // 24 s for a speed=1 rock to cross the screen vertically.
27 #define RDX 2.5  // range for rock dx values (+/-)
28 #define RDY 2.5  // range for rock dy values (+/-)
29
30 void
31 reset_rocks(void)
32 {
33         nrocks = I_ROCKS;
34         nrocks_timer = 0;
35 }
36
37 #define ROCK_LEN sizeof("sprites/rockXX.png")
38
39 void
40 load_rocks(void)
41 {
42         int i;
43         char a[ROCK_LEN];
44
45         for(i=0; i<NROCKS; i++) {
46                 snprintf(a, ROCK_LEN, "sprites/rock%02d.png", i);
47                 load_sprite(SPRITE(&prototypes[i]), a);
48                 prototypes[i].sprite_type = ROCK;
49                 prototypes[i].flags = MOVE|DRAW|COLLIDE;
50         }
51
52         memset(rocks, 0, MAXROCKS*sizeof(struct rock));
53
54         for(i=1; i<MAXROCKS; i++) rocks[i].next = &rocks[i-1];
55         free_sprites[ROCK] = SPRITE(&rocks[MAXROCKS-1]);
56
57         reset_rocks();
58 }
59
60 enum { LEFT, RIGHT, TOP, BOTTOM };
61
62
63 // compute the number of rocks/tick that should be coming from each side,
64 // and the speed ranges of rocks coming from each side
65 void
66 rock_sides(float *ti, float *speed_min, float *speed_max)
67 {
68         float dx0,dx1, dy0,dy1;
69         float hfactor, vfactor;
70         int i;
71
72         for(i=0; i<4; i++) ti[i] = 0;
73         for(i=0; i<4; i++) speed_min[i] = 0;
74         for(i=0; i<4; i++) speed_max[i] = 0;
75         hfactor = (float)nrocks/KH; vfactor = (float)nrocks/KV;
76
77         dx0 = -RDX - screendx; dx1 = RDX - screendx;
78         dy0 = -RDY - screendy; dy1 = RDY - screendy;
79
80         if(dx0 < 0) {
81                 speed_max[RIGHT] = -dx0;
82                 if(dx1 < 0) {
83                         // Rocks moving left only. So the RIGHT side of the screen
84                         speed_min[RIGHT] = -dx1;
85                         ti[RIGHT] = -(dx0+dx1)/2;
86                 } else {
87                         // Rocks moving left and right
88                         speed_max[LEFT] = dx1;
89                         ti[RIGHT] = -dx0/2;
90                         ti[LEFT] = dx1/2;
91                 }
92         } else {
93                 // Rocks moving right only. So the LEFT side of the screen
94                 speed_min[LEFT] = dx0;
95                 speed_max[LEFT] = dx1;
96                 ti[LEFT] = (dx0+dx1)/2;
97         }
98         ti[LEFT] *= hfactor;
99         ti[RIGHT] *= hfactor;
100
101         if(dy0 < 0) {
102                 speed_max[BOTTOM] = -dy0;
103                 if(dy1 < 0) {
104                         // Rocks moving up only. So the BOTTOM of the screen
105                         speed_min[BOTTOM] = -dy1;
106                         ti[BOTTOM] = -(dy0+dy1)/2;
107                 } else {
108                         // Rocks moving up and down
109                         speed_max[TOP] = dy1;
110                         ti[BOTTOM] = -dy0/2;
111                         ti[TOP] = dy1/2;
112                 }
113         } else {
114                 // Rocks moving down only. so the TOP of the screen
115                 speed_min[TOP] = dy0;
116                 speed_max[TOP] = dy1;
117                 ti[TOP] = (dy0+dy1)/2;
118         }
119         ti[TOP] *= vfactor;
120         ti[BOTTOM] *= vfactor;
121 }
122
123 float
124 weighted_rnd_range(float min, float max) {
125         return sqrt(min * min + frnd() * (max * max - min * min));
126 }
127
128 void
129 new_rocks(void)
130 {
131         int i, type;
132         struct rock *r;
133         float ti[4];
134         float rmin[4];
135         float rmax[4];
136
137         if(nrocks < F_ROCKS) {
138                 nrocks_timer += t_frame;
139                 if(nrocks_timer >= nrocks_inc_ticks) {
140                         nrocks_timer -= nrocks_inc_ticks;
141                         nrocks++;
142                 }
143         }
144
145         rock_sides(ti, rmin, rmax);
146
147         // increment timers
148         for(i=0; i<4; i++) rtimers[i] += ti[i]*t_frame;
149
150         // generate rocks
151         for(i=0; i<4; i++) {
152                 while(rtimers[i] >= 1) {
153                         rtimers[i] -= 1;
154                         if(!free_sprites[ROCK]) return;  // sorry, we ran out of rocks!
155                         r = (struct rock *) remove_sprite(&free_sprites[ROCK]);
156                         type = urnd() % NROCKS;
157                         *r = prototypes[type];
158                         r->type = type;
159                         switch(i) {
160                                 case RIGHT:
161                                         r->x = XSIZE;
162                                         r->y = frnd()*(YSIZE + r->image->h);
163
164                                         r->dx = -weighted_rnd_range(rmin[i], rmax[i]) + screendx;
165                                         r->dy = RDY*crnd();
166                                         break;
167                                 case LEFT:
168                                         r->x = -r->image->w;
169                                         r->y = frnd()*(YSIZE + r->image->h);
170
171                                         r->dx = weighted_rnd_range(rmin[i], rmax[i]) + screendx;
172                                         r->dy = RDY*crnd();
173                                         break;
174                                 case BOTTOM:
175                                         r->x = frnd()*(XSIZE + r->image->w);
176                                         r->y = YSIZE;
177
178                                         r->dx = RDX*crnd();
179                                         r->dy = -weighted_rnd_range(rmin[i], rmax[i]) + screendy;
180                                         break;
181                                 case TOP:
182                                         r->x = frnd()*(XSIZE + r->image->w);
183                                         r->y = -r->image->h;
184
185                                         r->dx = RDX*crnd();
186                                         r->dy = weighted_rnd_range(rmin[i], rmax[i]) + screendy;
187                                         break;
188                         }
189                         add_sprite(SPRITE(r));
190                 }
191         }
192 }
193
194
195 void
196 draw_rocks(void)
197 {
198         int i;
199         for(i=0; i<MAXROCKS; i++) draw_sprite(SPRITE(&rocks[i]));
200 }
201
202 void
203 blast_rocks(float x, float y, float radius)
204 {
205         int i;
206         Sprite *r;
207         float dx, dy, n;
208
209         for(i=0; i<MAXROCKS; i++) {
210                 if(!rocks[i].flags) continue;
211                 r = SPRITE(&rocks[i]);
212                 if(r->x <= 0) continue;
213
214                 dx = r->x - x;
215                 dy = r->y - y;
216
217                 n = sqrt(dx*dx + dy*dy);
218                 if(n < radius) {
219                         n *= 15;
220                         r->dx += 54.0*dx/n;
221                         r->dy += 54.0*dy/n;
222                 }
223         }
224 }