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