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