1 /*
2 etc.cpp - contains everything not contained in some other file
3 Copyright (C) 2006 Mark boyd
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be fun to play,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <algorithm> /* For std::min and std::max (which aren't algorithms IMO) (and which don't appear in this file either!) */
21 #include <sstream>
22
23 #include <SDL_inc.h>
24
25 #include "game.h"
26 #include "text.h"
27 #include "etc.h"
28
29
30 //These 2 functions are right out of the SDL manual.
31
32 /*
33 * Return the pixel value at (x, y)
34 * NOTE: The surface must be locked before calling this!
35 */
getpixel(SDL_Surface * surface,int x,int y)36 Uint32 getpixel(SDL_Surface *surface, int x, int y)
37 {
38 int bpp = surface->format->BytesPerPixel;
39 /* Here p is the address to the pixel we want to retrieve */
40 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
41
42 switch(bpp) {
43 case 1:
44 return *p;
45
46 case 2:
47 return *(Uint16 *)p;
48
49 case 3:
50 if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
51 return p[0] << 16 | p[1] << 8 | p[2];
52 else
53 return p[0] | p[1] << 8 | p[2] << 16;
54
55 case 4:
56 return *(Uint32 *)p;
57
58 default:
59 return 0; /* shouldn't happen, but avoids warnings */
60 }
61 }
62
63
64
65 /*
66 * Set the pixel at (x, y) to the given value
67 * NOTE: The surface must be locked before calling this!
68 */
putpixel(SDL_Surface * surface,int x,int y,Uint32 pixel)69 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
70 {
71 int bpp = surface->format->BytesPerPixel;
72 /* Here p is the address to the pixel we want to set */
73 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
74
75 switch(bpp) {
76 case 1:
77 *p = pixel;
78 break;
79
80 case 2:
81 *(Uint16 *)p = pixel;
82 break;
83
84 case 3:
85 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
86 p[0] = (pixel >> 16) & 0xff;
87 p[1] = (pixel >> 8) & 0xff;
88 p[2] = pixel & 0xff;
89 } else {
90 p[0] = pixel & 0xff;
91 p[1] = (pixel >> 8) & 0xff;
92 p[2] = (pixel >> 16) & 0xff;
93 }
94 break;
95
96 case 4:
97 *(Uint32 *)p = pixel;
98 break;
99 }
100 }
101
dist(float x,float y)102 float dist(float x, float y)
103 {
104 return std::sqrt(x*x+y*y);
105 }
106
create_surface(int w,int h,alphanity al)107 SDL_Surface *create_surface(int w, int h, alphanity al)
108 {
109 Uint32 rmask, gmask, bmask, amask;
110 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
111 rmask = 0xff000000;
112 gmask = 0x00ff0000;
113 bmask = 0x0000ff00;
114 amask = 0x000000ff;
115 #else
116 rmask = 0x000000ff;
117 gmask = 0x0000ff00;
118 bmask = 0x00ff0000;
119 amask = 0xff000000;
120 #endif
121 if (al==no_alpha_channel) amask=0;
122
123 SDL_Surface *sur=SDL_CreateRGBSurface(SDL_HWSURFACE, w, h, 32, rmask, gmask, bmask, amask);
124 SDL_SetColorKey(sur, SDL_RLEACCEL, 0);
125 return sur;
126 }
127
dfloor(float f)128 inline int dfloor(float f)
129 {
130 return f>=0?int(f):int(f-1);
131 }
132
rotate(SDL_Surface * from,SDL_Surface * to,double angle)133 void rotate(SDL_Surface *from, SDL_Surface *to, double angle)
134 {
135 SDL_LockSurface(from);
136 SDL_LockSurface(to);
137 for (int x=0; x<to->w; ++x) for(int y=0;y<to->h;++y)
138 {
139 //centre of the pixel
140 double x_cen=(float(x)-float(to->w)/2.0+0.5);
141 double y_cen=(float(y)-float(to->h)/2.0+0.5);
142
143 double s=std::sin(angle),c=std::cos(angle);
144 double r_x_cen=x_cen* c+y_cen*s;
145 double r_y_cen=x_cen*-s+y_cen*c;
146
147 int irx_cen=dfloor(r_x_cen+float(from->w)/2.0);
148 int iry_cen=dfloor(r_y_cen+float(from->h)/2.0);
149
150 if (irx_cen>=0 && irx_cen<from->w && iry_cen>=0&&iry_cen<from->h)
151 {
152 Uint8 r,g,b,a;
153 SDL_GetRGBA(getpixel(from,irx_cen,iry_cen), from->format, &r, &g, &b, &a);
154
155 putpixel(to,x,y,SDL_MapRGBA(to->format,r,g,b,a));
156 }
157 }
158 SDL_UnlockSurface(to);
159 SDL_UnlockSurface(from);
160 }
161
162
randint(int i)163 int randint(int i)
164 {
165 return minmax(0, int(1.0*i*randu()), i-1);
166 }
167
randn()168 float randn()
169 {
170 //box-muller method.
171 int r;
172 double d=RAND_MAX;
173 while(!(r=rand()));
174 return cos(2.0*M_PI*rand()/d) * sqrt(2.0*log(d/r));
175 }
176
int2str(int i)177 std::string int2str(int i)
178 {
179 std::stringstream ss; ss<<i;
180 return ss.str();
181 }
182
fade_out(SDL_Surface * screen,SDL_Rect rect)183 void fade_out(SDL_Surface *screen, SDL_Rect rect)
184 {
185 const Uint32 black=SDL_MapRGB(screen->format, 0,0,0);
186 const int frames=30;
187 const int delay=30;
188
189 SDL_Surface *fade=create_surface(rect.w, rect.h, no_alpha_channel);
190 SDL_BlitSurface(screen, &rect, fade, 0);
191
192 for(int i=0; i<frames;++i)
193 {
194
195 SDL_FillRect(screen, &rect, black);
196
197 SDL_SetAlpha(fade, SDL_SRCALPHA, (SDL_ALPHA_TRANSPARENT*i+SDL_ALPHA_OPAQUE*(frames-i))/frames);
198 SDL_BlitSurface(fade, 0, screen, &rect);
199 SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h);
200
201 SDL_Delay(delay);
202 }
203
204
205 }
206
207
update_player_status(SDL_Surface * screen)208 void update_player_status(SDL_Surface *screen)
209 {
210 Uint32 black=SDL_MapRGB(screen->format, 0,0,0);
211 Uint32 white=SDL_MapRGB(screen->format, 255,255,255);
212 int top=screen->h-TILE_SIZE;
213
214 const int bars_left=screen->w/2-70;
215
216 SDL_Rect statusrect={0, top, screen->w, TILE_SIZE};
217 SDL_FillRect(screen, &statusrect, black);
218
219 SDL_Rect sep={0, top, screen->w, 1};
220 SDL_FillRect(screen, &sep, white);
221
222 player_status &ps=game::the_game->m_player_status;
223
224 text::draw("Lives: "+int2str(ps.lives), screen, 20, top+5, white);
225 text::draw("Score: "+int2str(ps.score), screen, 20, top+20, white);
226
227 text::draw("Shield:", screen, bars_left-60, top+3, white);
228 SDL_Rect sh={screen->w/2-70,top+3,202,12};
229 SDL_FillRect(screen, &sh, white);
230 sh.x++;sh.y++;sh.h-=2;sh.w-=2;
231 SDL_FillRect(screen, &sh, black);
232 float shield_frac = 1.0*minmax(0, ps.shield, MAX_SHIELD)/MAX_SHIELD;
233 sh.w=int(shield_frac*sh.w);
234 SDL_FillRect(screen, &sh, SDL_MapRGB(screen->format, int((1.0-shield_frac)*255), int((shield_frac)*255),0));
235 if (ps.invulnerability>0)
236 {
237 SDL_Rect iv={bars_left,top+3,202,12};
238 float inv_frac = 1.0*minmax<float>(0, ps.invulnerability, MAX_INVULNERABILITY)/MAX_INVULNERABILITY;
239 iv.w=int(inv_frac*iv.w);
240 SDL_FillRect(screen, &iv, white);
241 }
242
243
244 text::draw("Energy:", screen, bars_left-60, top+18, white);
245 SDL_Rect en={bars_left,top+18,202,12};
246 SDL_FillRect(screen, &en, white);
247 en.x++;en.y++;en.h-=2;en.w-=2;
248 SDL_FillRect(screen, &en, black);
249 float energy_frac=1.0*minmax<float>(0, ps.energy, ps.max_energy)/ps.max_energy;
250 en.w=int(energy_frac*en.w);
251 SDL_FillRect(screen, &en, SDL_MapRGB(screen->format, int((1.0-energy_frac)*255), int((energy_frac)*255),0));
252 text::draw("/"+int2str(int(ps.max_energy+0.5)), screen, bars_left+202+5,top+18, white);
253
254 text::draw("Money: "+int2str(ps.money), screen, screen->w-110, top+5, white);
255 }
256
calc_ship_mass()257 int calc_ship_mass()
258 {
259 int total_mass=ship_empty_mass;
260
261 //Weapons
262 for(int i=0; i<game::the_game->m_weapon_mounts.size(); ++i)
263 total_mass+=weapon_types()[game::the_game->m_weapon_mounts[i].type].mass;
264
265 //Engine
266 total_mass += engine_types()[game::the_game->m_engine].mass;
267
268 //Todo: other equipment
269 for(int i=0; i<game::the_game->m_systems.size(); ++i)
270 total_mass+=system_types()[game::the_game->m_systems[i]].mass;
271
272 return total_mass;
273 }
274
calc_ship_battery()275 float calc_ship_battery()
276 {
277 float total=ship_base_battery;
278
279 for(int i=0; i<game::the_game->m_systems.size(); ++i)
280 if(game::the_game->m_systems[i] == ST_BATTERY)
281 total+=15;
282
283 return total;
284 }
285
calc_ship_generate()286 float calc_ship_generate()
287 {
288 float total=ship_base_generate;
289
290 for(int i=0; i<game::the_game->m_systems.size(); ++i)
291 if(game::the_game->m_systems[i] == ST_GENERATOR)
292 total+=0.2;
293 else if(game::the_game->m_systems[i] == ST_SUPERGENERATOR)
294 total+=0.6;
295 return total;
296 }
297